ceph: consider inode's last read/write when calculating wanted caps
Add i_last_rd and i_last_wr to ceph_inode_info. These fields are used to track the last time the client acquired read/write caps for the inode. If there is no read/write on an inode for 'caps_wanted_delay_max' seconds, __ceph_caps_file_wanted() does not request caps for read/write even there are open files. Call __ceph_touch_fmode() for dir operations. __ceph_caps_file_wanted() calculates dir's wanted caps according to last dir read/modification. If there is recent dir read, dir inode wants CEPH_CAP_ANY_SHARED caps. If there is recent dir modification, also wants CEPH_CAP_FILE_EXCL. Readdir is a special case. Dir inode wants CEPH_CAP_FILE_EXCL after readdir, as with that, modifications do not need to release CEPH_CAP_FILE_SHARED or invalidate all dentry leases issued by readdir. Signed-off-by: "Yan, Zheng" <zyan@redhat.com> Reviewed-by: Jeff Layton <jlayton@kernel.org> Signed-off-by: Ilya Dryomov <idryomov@gmail.com>
This commit is contained in:
@@ -213,7 +213,7 @@ static int ceph_init_file_info(struct inode *inode, struct file *file,
|
||||
struct ceph_dir_file_info *dfi =
|
||||
kmem_cache_zalloc(ceph_dir_file_cachep, GFP_KERNEL);
|
||||
if (!dfi) {
|
||||
ceph_put_fmode(ci, fmode); /* clean up */
|
||||
ceph_put_fmode(ci, fmode, 1); /* clean up */
|
||||
return -ENOMEM;
|
||||
}
|
||||
|
||||
@@ -224,7 +224,7 @@ static int ceph_init_file_info(struct inode *inode, struct file *file,
|
||||
} else {
|
||||
fi = kmem_cache_zalloc(ceph_file_cachep, GFP_KERNEL);
|
||||
if (!fi) {
|
||||
ceph_put_fmode(ci, fmode); /* clean up */
|
||||
ceph_put_fmode(ci, fmode, 1); /* clean up */
|
||||
return -ENOMEM;
|
||||
}
|
||||
|
||||
@@ -263,7 +263,7 @@ static int ceph_init_file(struct inode *inode, struct file *file, int fmode)
|
||||
case S_IFLNK:
|
||||
dout("init_file %p %p 0%o (symlink)\n", inode, file,
|
||||
inode->i_mode);
|
||||
ceph_put_fmode(ceph_inode(inode), fmode); /* clean up */
|
||||
ceph_put_fmode(ceph_inode(inode), fmode, 1); /* clean up */
|
||||
break;
|
||||
|
||||
default:
|
||||
@@ -273,7 +273,7 @@ static int ceph_init_file(struct inode *inode, struct file *file, int fmode)
|
||||
* we need to drop the open ref now, since we don't
|
||||
* have .release set to ceph_release.
|
||||
*/
|
||||
ceph_put_fmode(ceph_inode(inode), fmode); /* clean up */
|
||||
ceph_put_fmode(ceph_inode(inode), fmode, 1); /* clean up */
|
||||
BUG_ON(inode->i_fop->release == ceph_release);
|
||||
|
||||
/* call the proper open fop */
|
||||
@@ -285,14 +285,15 @@ static int ceph_init_file(struct inode *inode, struct file *file, int fmode)
|
||||
/*
|
||||
* try renew caps after session gets killed.
|
||||
*/
|
||||
int ceph_renew_caps(struct inode *inode)
|
||||
int ceph_renew_caps(struct inode *inode, int fmode)
|
||||
{
|
||||
struct ceph_mds_client *mdsc = ceph_sb_to_client(inode->i_sb)->mdsc;
|
||||
struct ceph_mds_client *mdsc = ceph_inode_to_client(inode)->mdsc;
|
||||
struct ceph_inode_info *ci = ceph_inode(inode);
|
||||
struct ceph_mds_request *req;
|
||||
int err, flags, wanted;
|
||||
|
||||
spin_lock(&ci->i_ceph_lock);
|
||||
__ceph_touch_fmode(ci, mdsc, fmode);
|
||||
wanted = __ceph_caps_file_wanted(ci);
|
||||
if (__ceph_is_any_real_caps(ci) &&
|
||||
(!(wanted & CEPH_CAP_ANY_WR) || ci->i_auth_cap)) {
|
||||
@@ -405,6 +406,7 @@ int ceph_open(struct inode *inode, struct file *file)
|
||||
} else if (ceph_snap(inode) != CEPH_NOSNAP &&
|
||||
(ci->i_snap_caps & wanted) == wanted) {
|
||||
__ceph_get_fmode(ci, fmode);
|
||||
__ceph_touch_fmode(ci, mdsc, fmode);
|
||||
spin_unlock(&ci->i_ceph_lock);
|
||||
return ceph_init_file(inode, file, fmode);
|
||||
}
|
||||
@@ -781,7 +783,7 @@ retry:
|
||||
}
|
||||
out_req:
|
||||
if (!req->r_err && req->r_target_inode)
|
||||
ceph_put_fmode(ceph_inode(req->r_target_inode), req->r_fmode);
|
||||
ceph_put_fmode(ceph_inode(req->r_target_inode), req->r_fmode, 1);
|
||||
ceph_mdsc_put_request(req);
|
||||
out_ctx:
|
||||
ceph_release_acl_sec_ctx(&as_ctx);
|
||||
@@ -798,7 +800,7 @@ int ceph_release(struct inode *inode, struct file *file)
|
||||
dout("release inode %p dir file %p\n", inode, file);
|
||||
WARN_ON(!list_empty(&dfi->file_info.rw_contexts));
|
||||
|
||||
ceph_put_fmode(ci, dfi->file_info.fmode);
|
||||
ceph_put_fmode(ci, dfi->file_info.fmode, 1);
|
||||
|
||||
if (dfi->last_readdir)
|
||||
ceph_mdsc_put_request(dfi->last_readdir);
|
||||
@@ -810,7 +812,8 @@ int ceph_release(struct inode *inode, struct file *file)
|
||||
dout("release inode %p regular file %p\n", inode, file);
|
||||
WARN_ON(!list_empty(&fi->rw_contexts));
|
||||
|
||||
ceph_put_fmode(ci, fi->fmode);
|
||||
ceph_put_fmode(ci, fi->fmode, 1);
|
||||
|
||||
kmem_cache_free(ceph_file_cachep, fi);
|
||||
}
|
||||
|
||||
|
Reference in New Issue
Block a user