From: Al Viro Date: Tue, 20 Feb 2024 04:32:22 +0000 (-0500) Subject: rpc_populate(): lift cleanup into callers X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=8be22c49646e47452e74aa0b97ea50fb04c271ed;p=thirdparty%2Fkernel%2Fstable.git rpc_populate(): lift cleanup into callers 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 Signed-off-by: Al Viro --- diff --git a/net/sunrpc/rpc_pipe.c b/net/sunrpc/rpc_pipe.c index 67621a94f67b2..46fa00ac5e0e7 100644 --- a/net/sunrpc/rpc_pipe.c +++ b/net/sunrpc/rpc_pipe.c @@ -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;