]> git.ipfire.org Git - thirdparty/kernel/stable.git/commitdiff
rpc_populate(): lift cleanup into callers
authorAl Viro <viro@zeniv.linux.org.uk>
Tue, 20 Feb 2024 04:32:22 +0000 (23:32 -0500)
committerAl Viro <viro@zeniv.linux.org.uk>
Thu, 3 Jul 2025 02:44:55 +0000 (22:44 -0400)
rpc_populate() is called either from fill_super (where we don't
need to remove any files on failure - rpc_kill_sb() will take
them all out anyway) or from rpc_mkdir_populate(), where we need
to remove the directory we'd been trying to populate along with
whatever we'd put into it before we failed.  Simpler to combine
that into simple_recursive_removal() there.

Note that rpc_pipe is overlocking directories quite a bit -
locked parent is no obstacle to finding a child in dcache, so
keeping it locked won't prevent userland observing a partially
built subtree.

All we need is to follow minimal VFS requirements; it's not
as if clients used directory locking for exclusion - tree
changes are serialized, but that's done on ->pipefs_sb_lock.

Reviewed-by: Jeff Layton <jlayton@kernel.org>
Signed-off-by: Al Viro <viro@zeniv.linux.org.uk>
net/sunrpc/rpc_pipe.c

index 67621a94f67b23a0146ccf177f058b854c867d6b..46fa00ac5e0e7667104b1bd8ba4f64194913a419 100644 (file)
@@ -594,32 +594,6 @@ static int __rpc_mkpipe_dentry(struct inode *dir, struct dentry *dentry,
        return 0;
 }
 
-static int __rpc_rmdir(struct inode *dir, struct dentry *dentry)
-{
-       int ret;
-
-       dget(dentry);
-       ret = simple_rmdir(dir, dentry);
-       d_drop(dentry);
-       if (!ret)
-               fsnotify_rmdir(dir, dentry);
-       dput(dentry);
-       return ret;
-}
-
-static int __rpc_unlink(struct inode *dir, struct dentry *dentry)
-{
-       int ret;
-
-       dget(dentry);
-       ret = simple_unlink(dir, dentry);
-       d_drop(dentry);
-       if (!ret)
-               fsnotify_unlink(dir, dentry);
-       dput(dentry);
-       return ret;
-}
-
 static struct dentry *__rpc_lookup_create_exclusive(struct dentry *parent,
                                          const char *name)
 {
@@ -636,41 +610,6 @@ static struct dentry *__rpc_lookup_create_exclusive(struct dentry *parent,
        return ERR_PTR(-EEXIST);
 }
 
-/*
- * FIXME: This probably has races.
- */
-static void __rpc_depopulate(struct dentry *parent,
-                            const struct rpc_filelist *files,
-                            int start, int eof)
-{
-       struct inode *dir = d_inode(parent);
-       struct dentry *dentry;
-       struct qstr name;
-       int i;
-
-       for (i = start; i < eof; i++) {
-               name.name = files[i].name;
-               name.len = strlen(files[i].name);
-               dentry = try_lookup_noperm(&name, parent);
-
-               if (dentry == NULL)
-                       continue;
-               if (d_really_is_negative(dentry))
-                       goto next;
-               switch (d_inode(dentry)->i_mode & S_IFMT) {
-                       default:
-                               BUG();
-                       case S_IFREG:
-                               __rpc_unlink(dir, dentry);
-                               break;
-                       case S_IFDIR:
-                               __rpc_rmdir(dir, dentry);
-               }
-next:
-               dput(dentry);
-       }
-}
-
 static int rpc_populate(struct dentry *parent,
                        const struct rpc_filelist *files,
                        int start, int eof,
@@ -707,7 +646,6 @@ static int rpc_populate(struct dentry *parent,
        inode_unlock(dir);
        return 0;
 out_bad:
-       __rpc_depopulate(parent, files, start, eof);
        inode_unlock(dir);
        printk(KERN_WARNING "%s: %s failed to populate directory %pd\n",
                        __FILE__, __func__, parent);
@@ -731,14 +669,15 @@ static struct dentry *rpc_mkdir_populate(struct dentry *parent,
                goto out_err;
        if (populate != NULL) {
                error = populate(dentry, args_populate);
-               if (error)
-                       goto err_rmdir;
+               if (error) {
+                       inode_unlock(dir);
+                       simple_recursive_removal(dentry, NULL);
+                       return ERR_PTR(error);
+               }
        }
 out:
        inode_unlock(dir);
        return dentry;
-err_rmdir:
-       __rpc_rmdir(dir, dentry);
 out_err:
        dentry = ERR_PTR(error);
        goto out;