]> www.infradead.org Git - users/jedix/linux-maple.git/commitdiff
NFS: Refactor nfs_instantiate() for dentry referencing callers
authorBenjamin Coddington <bcodding@redhat.com>
Fri, 13 Sep 2019 12:29:02 +0000 (08:29 -0400)
committerAnna Schumaker <Anna.Schumaker@Netapp.com>
Fri, 20 Sep 2019 19:15:24 +0000 (15:15 -0400)
Since commit b0c6108ecf64 ("nfs_instantiate(): prevent multiple aliases for
directory inode"), nfs_instantiate() may succeed without actually
instantiating the dentry that was passed in.  That can be problematic for
some callers in NFSv3, so this patch breaks things up so we can get the
actual dentry obtained.

Signed-off-by: Benjamin Coddington <bcodding@redhat.com>
Signed-off-by: Anna Schumaker <Anna.Schumaker@Netapp.com>
fs/nfs/dir.c
include/linux/nfs_fs.h

index 8d501093660f4a052a781d61c46a507fa4c7c1ca..d1bbf2fb6ac7a4864f90e7288aacf697116f3daf 100644 (file)
@@ -1669,24 +1669,23 @@ static int nfs4_lookup_revalidate(struct dentry *dentry, unsigned int flags)
 
 #endif /* CONFIG_NFSV4 */
 
-/*
- * Code common to create, mkdir, and mknod.
- */
-int nfs_instantiate(struct dentry *dentry, struct nfs_fh *fhandle,
+struct dentry *
+nfs_add_or_obtain(struct dentry *dentry, struct nfs_fh *fhandle,
                                struct nfs_fattr *fattr,
                                struct nfs4_label *label)
 {
        struct dentry *parent = dget_parent(dentry);
        struct inode *dir = d_inode(parent);
        struct inode *inode;
-       struct dentry *d;
-       int error = -EACCES;
+       struct dentry *d = NULL;
+       int error;
 
        d_drop(dentry);
 
        /* We may have been initialized further down */
        if (d_really_is_positive(dentry))
                goto out;
+
        if (fhandle->size == 0) {
                error = NFS_PROTO(dir)->lookup(dir, &dentry->d_name, fhandle, fattr, NULL);
                if (error)
@@ -1702,18 +1701,32 @@ int nfs_instantiate(struct dentry *dentry, struct nfs_fh *fhandle,
        }
        inode = nfs_fhget(dentry->d_sb, fhandle, fattr, label);
        d = d_splice_alias(inode, dentry);
-       if (IS_ERR(d)) {
-               error = PTR_ERR(d);
-               goto out_error;
-       }
-       dput(d);
 out:
        dput(parent);
-       return 0;
+       return d;
 out_error:
        nfs_mark_for_revalidate(dir);
-       dput(parent);
-       return error;
+       d = ERR_PTR(error);
+       goto out;
+}
+EXPORT_SYMBOL_GPL(nfs_add_or_obtain);
+
+/*
+ * Code common to create, mkdir, and mknod.
+ */
+int nfs_instantiate(struct dentry *dentry, struct nfs_fh *fhandle,
+                               struct nfs_fattr *fattr,
+                               struct nfs4_label *label)
+{
+       struct dentry *d;
+
+       d = nfs_add_or_obtain(dentry, fhandle, fattr, label);
+       if (IS_ERR(d))
+               return PTR_ERR(d);
+
+       /* Callers don't care */
+       dput(d);
+       return 0;
 }
 EXPORT_SYMBOL_GPL(nfs_instantiate);
 
index 0a11712a80e37cfe18a108f43a58cbf3842b63c7..570a60c2f4f48316c8d78aa2887ee79908382d92 100644 (file)
@@ -490,6 +490,9 @@ extern const struct file_operations nfs_dir_operations;
 extern const struct dentry_operations nfs_dentry_operations;
 
 extern void nfs_force_lookup_revalidate(struct inode *dir);
+extern struct dentry *nfs_add_or_obtain(struct dentry *dentry,
+                       struct nfs_fh *fh, struct nfs_fattr *fattr,
+                       struct nfs4_label *label);
 extern int nfs_instantiate(struct dentry *dentry, struct nfs_fh *fh,
                        struct nfs_fattr *fattr, struct nfs4_label *label);
 extern int nfs_may_open(struct inode *inode, const struct cred *cred, int openflags);