dcache: d_obtain_alias callers don't all want DISCONNECTED
authorJ. Bruce Fields <bfields@redhat.com>
Fri, 14 Feb 2014 22:35:37 +0000 (17:35 -0500)
committerAl Viro <viro@zeniv.linux.org.uk>
Thu, 7 Aug 2014 18:40:10 +0000 (14:40 -0400)
There are a few d_obtain_alias callers that are using it to get the
root of a filesystem which may already have an alias somewhere else.

This is not the same as the filehandle-lookup case, and none of them
actually need DCACHE_DISCONNECTED set.

It isn't really a serious problem, but it would really be clearer if we
reserved DCACHE_DISCONNECTED for those cases where it's actually needed.

In the btrfs case this was causing a spurious printk from
nfsd/nfsfh.c:fh_verify when it found an unexpected DCACHE_DISCONNECTED
dentry.  Josef worked around this by unsetting DCACHE_DISCONNECTED
manually in 3a0dfa6a12e "Btrfs: unset DCACHE_DISCONNECTED when mounting
default subvol", and this replaces that workaround.

Cc: Josef Bacik <jbacik@fb.com>
Signed-off-by: J. Bruce Fields <bfields@redhat.com>
Signed-off-by: Al Viro <viro@zeniv.linux.org.uk>
fs/btrfs/super.c
fs/ceph/super.c
fs/dcache.c
fs/nfs/getroot.c
fs/nilfs2/super.c
include/linux/dcache.h

index 8e16bca69c56de7fa54c1680698b60d7319a03a9..67b48b9a03e044eb2d83ab28447c8ead9db5192b 100644 (file)
@@ -851,7 +851,6 @@ static struct dentry *get_default_root(struct super_block *sb,
        struct btrfs_path *path;
        struct btrfs_key location;
        struct inode *inode;
-       struct dentry *dentry;
        u64 dir_id;
        int new = 0;
 
@@ -922,13 +921,7 @@ setup_root:
                return dget(sb->s_root);
        }
 
-       dentry = d_obtain_alias(inode);
-       if (!IS_ERR(dentry)) {
-               spin_lock(&dentry->d_lock);
-               dentry->d_flags &= ~DCACHE_DISCONNECTED;
-               spin_unlock(&dentry->d_lock);
-       }
-       return dentry;
+       return d_obtain_root(inode);
 }
 
 static int btrfs_fill_super(struct super_block *sb,
index 06150fd745ac65d72c456b1fe57f537336f1064a..f6e12377335c1a2aa030e86f1d903daa365792b1 100644 (file)
@@ -755,7 +755,7 @@ static struct dentry *open_root_dentry(struct ceph_fs_client *fsc,
                                goto out;
                        }
                } else {
-                       root = d_obtain_alias(inode);
+                       root = d_obtain_root(inode);
                }
                ceph_init_dentry(root);
                dout("open_root_inode success, root dentry is %p\n", root);
index 3ed09536399735528f0992b4be98a2610651b61c..63d556c0e698556b1bc1094480a5386f71928555 100644 (file)
@@ -1781,25 +1781,7 @@ struct dentry *d_find_any_alias(struct inode *inode)
 }
 EXPORT_SYMBOL(d_find_any_alias);
 
-/**
- * d_obtain_alias - find or allocate a dentry for a given inode
- * @inode: inode to allocate the dentry for
- *
- * Obtain a dentry for an inode resulting from NFS filehandle conversion or
- * similar open by handle operations.  The returned dentry may be anonymous,
- * or may have a full name (if the inode was already in the cache).
- *
- * When called on a directory inode, we must ensure that the inode only ever
- * has one dentry.  If a dentry is found, that is returned instead of
- * allocating a new one.
- *
- * On successful return, the reference to the inode has been transferred
- * to the dentry.  In case of an error the reference on the inode is released.
- * To make it easier to use in export operations a %NULL or IS_ERR inode may
- * be passed in and will be the error will be propagate to the return value,
- * with a %NULL @inode replaced by ERR_PTR(-ESTALE).
- */
-struct dentry *d_obtain_alias(struct inode *inode)
+struct dentry *__d_obtain_alias(struct inode *inode, int disconnected)
 {
        static const struct qstr anonstring = QSTR_INIT("/", 1);
        struct dentry *tmp;
@@ -1830,7 +1812,10 @@ struct dentry *d_obtain_alias(struct inode *inode)
        }
 
        /* attach a disconnected dentry */
-       add_flags = d_flags_for_inode(inode) | DCACHE_DISCONNECTED;
+       add_flags = d_flags_for_inode(inode);
+
+       if (disconnected)
+               add_flags |= DCACHE_DISCONNECTED;
 
        spin_lock(&tmp->d_lock);
        tmp->d_inode = inode;
@@ -1851,8 +1836,52 @@ struct dentry *d_obtain_alias(struct inode *inode)
        iput(inode);
        return res;
 }
+
+/**
+ * d_obtain_alias - find or allocate a DISCONNECTED dentry for a given inode
+ * @inode: inode to allocate the dentry for
+ *
+ * Obtain a dentry for an inode resulting from NFS filehandle conversion or
+ * similar open by handle operations.  The returned dentry may be anonymous,
+ * or may have a full name (if the inode was already in the cache).
+ *
+ * When called on a directory inode, we must ensure that the inode only ever
+ * has one dentry.  If a dentry is found, that is returned instead of
+ * allocating a new one.
+ *
+ * On successful return, the reference to the inode has been transferred
+ * to the dentry.  In case of an error the reference on the inode is released.
+ * To make it easier to use in export operations a %NULL or IS_ERR inode may
+ * be passed in and the error will be propagated to the return value,
+ * with a %NULL @inode replaced by ERR_PTR(-ESTALE).
+ */
+struct dentry *d_obtain_alias(struct inode *inode)
+{
+       return __d_obtain_alias(inode, 1);
+}
 EXPORT_SYMBOL(d_obtain_alias);
 
+/**
+ * d_obtain_root - find or allocate a dentry for a given inode
+ * @inode: inode to allocate the dentry for
+ *
+ * Obtain an IS_ROOT dentry for the root of a filesystem.
+ *
+ * We must ensure that directory inodes only ever have one dentry.  If a
+ * dentry is found, that is returned instead of allocating a new one.
+ *
+ * On successful return, the reference to the inode has been transferred
+ * to the dentry.  In case of an error the reference on the inode is
+ * released.  A %NULL or IS_ERR inode may be passed in and will be the
+ * error will be propagate to the return value, with a %NULL @inode
+ * replaced by ERR_PTR(-ESTALE).
+ */
+struct dentry *d_obtain_root(struct inode *inode)
+{
+       return __d_obtain_alias(inode, 0);
+}
+EXPORT_SYMBOL(d_obtain_root);
+
 /**
  * d_add_ci - lookup or allocate new dentry with case-exact name
  * @inode:  the inode case-insensitive lookup has found
index b94f80420a584e596789fd048489463728a58789..880618a8b0489da1580e7cea0058de74ae2ceece 100644 (file)
@@ -112,7 +112,7 @@ struct dentry *nfs_get_root(struct super_block *sb, struct nfs_fh *mntfh,
         * if the dentry tree reaches them; however if the dentry already
         * exists, we'll pick it up at this point and use it as the root
         */
-       ret = d_obtain_alias(inode);
+       ret = d_obtain_root(inode);
        if (IS_ERR(ret)) {
                dprintk("nfs_get_root: get root dentry failed\n");
                goto out;
index 8c532b2ca3aba1c1a4c6e162641e3eb7d009f91c..ac914994dfedf0f6cd1d48b153d3a6ab9cb9689a 100644 (file)
@@ -942,7 +942,7 @@ static int nilfs_get_root_dentry(struct super_block *sb,
                        iput(inode);
                }
        } else {
-               dentry = d_obtain_alias(inode);
+               dentry = d_obtain_root(inode);
                if (IS_ERR(dentry)) {
                        ret = PTR_ERR(dentry);
                        goto failed_dentry;
index 3c7ec327ebd2eecc2fb63ac4f742ca0d75c56ec8..e4ae2ad48d072efcd78e3905c3f1e212130c88cc 100644 (file)
@@ -249,6 +249,7 @@ extern struct dentry * d_splice_alias(struct inode *, struct dentry *);
 extern struct dentry * d_add_ci(struct dentry *, struct inode *, struct qstr *);
 extern struct dentry *d_find_any_alias(struct inode *inode);
 extern struct dentry * d_obtain_alias(struct inode *);
+extern struct dentry * d_obtain_root(struct inode *);
 extern void shrink_dcache_sb(struct super_block *);
 extern void shrink_dcache_parent(struct dentry *);
 extern void shrink_dcache_for_umount(struct super_block *);