ceph: use lookup request to revalidate dentry
authorYan, Zheng <zyan@redhat.com>
Thu, 17 Mar 2016 06:41:59 +0000 (14:41 +0800)
committerBen Hutchings <ben@decadent.org.uk>
Tue, 20 Nov 2018 18:05:57 +0000 (18:05 +0000)
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
fs/ceph/inode.c
fs/ceph/super.h
fs/ceph/xattr.c

index 51ea03313df96e25c0e9e55f829158c36854fb7d..efe397452d77f080ffd9c4a677bc26b360179947 100644 (file)
@@ -1064,6 +1064,40 @@ static int ceph_d_revalidate(struct dentry *dentry, unsigned int flags)
                        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);
index bf29a9972e5bc7ab61a60662c2496ddc6d884a28..20e488053793699ecdd1f7cbf76ab8218d3dd093 100644 (file)
@@ -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;
                }
 
index b5b324a94cca846ded581b66b5f58903cbdbc70e..6e17dc6520bd7b1409e06808337f25e820d0c46a 100644 (file)
@@ -736,6 +736,15 @@ extern void __ceph_destroy_xattrs(struct ceph_inode_info *ci);
 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[];
 
index 4f88efa3f70e96dd9fee2d8435d3e9bc4aacfd69..ddfc1a6cd9697ab324bd892f60c7eaaf313ce3f8 100644 (file)
@@ -1128,3 +1128,10 @@ int ceph_removexattr(struct dentry *dentry, const char *name)
 
        return __ceph_removexattr(dentry, name);
 }
+
+#ifdef CONFIG_SECURITY
+bool ceph_security_xattr_wanted(struct inode *in)
+{
+       return in->i_security != NULL;
+}
+#endif