| From: "Yan, Zheng" <zyan@redhat.com> |
| Date: Thu, 17 Mar 2016 14:41:59 +0800 |
| Subject: ceph: use lookup request to revalidate dentry |
| |
| commit 200fd27c8fa2ba8bb4529033967b69a7cbfa2c2e upstream. |
| |
| If dentry has no lease, ceph_d_revalidate() previously return 0. |
| This causes VFS to invalidate the dentry and create a new dentry |
| for later lookup. Invalidating a dentry also detach any underneath |
| mount points. So mount point inside cephfs can disapear mystically |
| (even the mount point is not modified by other hosts). |
| |
| The fix is using lookup request to revalidate dentry without lease. |
| This can partly solve the mount points disapear issue (as long as |
| the mount point is not modified by other hosts) |
| |
| Signed-off-by: Yan, Zheng <zyan@redhat.com> |
| Cc: Bryan Henderson <bryanh@giraffe-data.com> |
| [bwh: Backported to 3.16: Add the ceph_security_xattr_wanted() function] |
| Signed-off-by: Ben Hutchings <ben@decadent.org.uk> |
| --- |
| fs/ceph/dir.c | 34 ++++++++++++++++++++++++++++++++++ |
| fs/ceph/inode.c | 1 + |
| 2 files changed, 35 insertions(+) |
| |
| --- a/fs/ceph/dir.c |
| +++ b/fs/ceph/dir.c |
| @@ -1064,6 +1064,40 @@ static int ceph_d_revalidate(struct dent |
| valid = 1; |
| } |
| |
| + if (!valid) { |
| + struct ceph_mds_client *mdsc = |
| + ceph_sb_to_client(dir->i_sb)->mdsc; |
| + struct ceph_mds_request *req; |
| + int op, mask, err; |
| + |
| + op = ceph_snap(dir) == CEPH_SNAPDIR ? |
| + CEPH_MDS_OP_LOOKUPSNAP : CEPH_MDS_OP_LOOKUP; |
| + req = ceph_mdsc_create_request(mdsc, op, USE_ANY_MDS); |
| + if (!IS_ERR(req)) { |
| + req->r_dentry = dget(dentry); |
| + req->r_num_caps = 2; |
| + |
| + mask = CEPH_STAT_CAP_INODE | CEPH_CAP_AUTH_SHARED; |
| + if (ceph_security_xattr_wanted(dir)) |
| + mask |= CEPH_CAP_XATTR_SHARED; |
| + req->r_args.getattr.mask = mask; |
| + |
| + req->r_locked_dir = dir; |
| + err = ceph_mdsc_do_request(mdsc, NULL, req); |
| + if (err == 0 || err == -ENOENT) { |
| + if (dentry == req->r_dentry) { |
| + valid = !d_unhashed(dentry); |
| + } else { |
| + d_invalidate(req->r_dentry); |
| + err = -EAGAIN; |
| + } |
| + } |
| + ceph_mdsc_put_request(req); |
| + dout("d_revalidate %p lookup result=%d\n", |
| + dentry, err); |
| + } |
| + } |
| + |
| dout("d_revalidate %p %s\n", dentry, valid ? "valid" : "invalid"); |
| if (valid) { |
| ceph_dentry_lru_touch(dentry); |
| --- a/fs/ceph/inode.c |
| +++ b/fs/ceph/inode.c |
| @@ -1251,6 +1251,7 @@ retry_lookup: |
| dout(" %p links to %p %llx.%llx, not %llx.%llx\n", |
| dn, dn->d_inode, ceph_vinop(dn->d_inode), |
| ceph_vinop(in)); |
| + d_invalidate(dn); |
| have_lease = false; |
| } |
| |
| --- a/fs/ceph/super.h |
| +++ b/fs/ceph/super.h |
| @@ -736,6 +736,15 @@ extern void __ceph_destroy_xattrs(struct |
| extern void __init ceph_xattr_init(void); |
| extern void ceph_xattr_exit(void); |
| |
| +#ifdef CONFIG_SECURITY |
| +extern bool ceph_security_xattr_wanted(struct inode *in); |
| +#else |
| +static inline bool ceph_security_xattr_wanted(struct inode *in) |
| +{ |
| + return false; |
| +} |
| +#endif |
| + |
| /* acl.c */ |
| extern const struct xattr_handler *ceph_xattr_handlers[]; |
| |
| --- a/fs/ceph/xattr.c |
| +++ b/fs/ceph/xattr.c |
| @@ -1128,3 +1128,10 @@ int ceph_removexattr(struct dentry *dent |
| |
| return __ceph_removexattr(dentry, name); |
| } |
| + |
| +#ifdef CONFIG_SECURITY |
| +bool ceph_security_xattr_wanted(struct inode *in) |
| +{ |
| + return in->i_security != NULL; |
| +} |
| +#endif |