kill d_instantiate_no_diralias()
authorAl Viro <viro@zeniv.linux.org.uk>
Mon, 28 May 2018 22:27:19 +0000 (18:27 -0400)
committerAl Viro <viro@zeniv.linux.org.uk>
Thu, 2 Aug 2018 03:18:53 +0000 (23:18 -0400)
The only user is fuse_create_new_entry(), and there it's used to
mitigate the same mkdir/open-by-handle race as in nfs_mkdir().
The same solution applies - unhash the mkdir argument, then
call d_splice_alias() and if that returns a reference to preexisting
alias, dput() and report success.  ->mkdir() argument left unhashed
negative with the preexisting alias moved in the right place is just
fine from the ->mkdir() callers point of view.

Cc: Miklos Szeredi <miklos@szeredi.hu>
Signed-off-by: Al Viro <viro@zeniv.linux.org.uk>
fs/dcache.c
fs/fuse/dir.c
include/linux/dcache.h

index 0e8e5de..a7d9e7a 100644 (file)
@@ -1899,33 +1899,6 @@ void d_instantiate_new(struct dentry *entry, struct inode *inode)
 }
 EXPORT_SYMBOL(d_instantiate_new);
 
-/**
- * d_instantiate_no_diralias - instantiate a non-aliased dentry
- * @entry: dentry to complete
- * @inode: inode to attach to this dentry
- *
- * Fill in inode information in the entry.  If a directory alias is found, then
- * return an error (and drop inode).  Together with d_materialise_unique() this
- * guarantees that a directory inode may never have more than one alias.
- */
-int d_instantiate_no_diralias(struct dentry *entry, struct inode *inode)
-{
-       BUG_ON(!hlist_unhashed(&entry->d_u.d_alias));
-
-       security_d_instantiate(entry, inode);
-       spin_lock(&inode->i_lock);
-       if (S_ISDIR(inode->i_mode) && !hlist_empty(&inode->i_dentry)) {
-               spin_unlock(&inode->i_lock);
-               iput(inode);
-               return -EBUSY;
-       }
-       __d_instantiate(entry, inode);
-       spin_unlock(&inode->i_lock);
-
-       return 0;
-}
-EXPORT_SYMBOL(d_instantiate_no_diralias);
-
 struct dentry *d_make_root(struct inode *root_inode)
 {
        struct dentry *res = NULL;
index 56231b3..4bbae6a 100644 (file)
@@ -539,6 +539,7 @@ static int create_new_entry(struct fuse_conn *fc, struct fuse_args *args,
 {
        struct fuse_entry_out outarg;
        struct inode *inode;
+       struct dentry *d;
        int err;
        struct fuse_forget_link *forget;
 
@@ -570,11 +571,17 @@ static int create_new_entry(struct fuse_conn *fc, struct fuse_args *args,
        }
        kfree(forget);
 
-       err = d_instantiate_no_diralias(entry, inode);
-       if (err)
-               return err;
+       d_drop(entry);
+       d = d_splice_alias(inode, entry);
+       if (IS_ERR(d))
+               return PTR_ERR(d);
 
-       fuse_change_entry_timeout(entry, &outarg);
+       if (d) {
+               fuse_change_entry_timeout(d, &outarg);
+               dput(d);
+       } else {
+               fuse_change_entry_timeout(entry, &outarg);
+       }
        fuse_invalidate_attr(dir);
        return 0;
 
index 66c6e17..0b83629 100644 (file)
@@ -227,7 +227,6 @@ extern void d_instantiate(struct dentry *, struct inode *);
 extern void d_instantiate_new(struct dentry *, struct inode *);
 extern struct dentry * d_instantiate_unique(struct dentry *, struct inode *);
 extern struct dentry * d_instantiate_anon(struct dentry *, struct inode *);
-extern int d_instantiate_no_diralias(struct dentry *, struct inode *);
 extern void __d_drop(struct dentry *dentry);
 extern void d_drop(struct dentry *dentry);
 extern void d_delete(struct dentry *);