linux-fsdevel.vger.kernel.org archive mirror
 help / color / mirror / Atom feed
* [PATCHES][RFC][CFT] rpc_pipefs cleanups
@ 2025-06-13  7:31 Al Viro
  2025-06-13  7:34 ` [PATCH 01/17] simple_recursive_removal(): saner interaction with fsnotify Al Viro
  2025-06-13 19:32 ` [PATCHES][RFC][CFT] rpc_pipefs cleanups Jeff Layton
  0 siblings, 2 replies; 25+ messages in thread
From: Al Viro @ 2025-06-13  7:31 UTC (permalink / raw)
  To: linux-fsdevel
  Cc: linux-nfs, Chuck Lever, Jeff Layton, NeilBrown, Trond Myklebust,
	Linus Torvalds

	Another series pulled out of tree-in-dcache pile; it massages
rpc_pipefs to use saner primitives.  Lives in
git://git.kernel.org/pub/scm/linux/kernel/git/viro/vfs.git #work.rpc_pipe
6.16-rc1-based, 17 commits, -314 lines of code...

Individual patches in followups.

Folks, please test and review.  In various forms this has sat in my tree
for more than a year and I'd rather get that logjam dealt with.

Overview:

	Prep/infrastructure (#1 is shared with #work.simple_recursive_removal)

1) simple_recursive_removal(): saner interaction with fsnotify
	fsnotify events are triggered before the callback, unlike in real
unlink(2)/rmdir(2) syscalls.  Obviously matters only in case when callback
is non-empty, which excludes most of the current users in the kernel.

2) new helper: simple_start_creating()
	Set the things up for kernel-initiated creation of object in a
tree-in-dcache filesystem.  With respect to locking it's an equivalent of
filename_create() - we either get a negative dentry with locked parent,
or ERR_PTR() and no locks taken.
	tracefs and debugfs had that open-coded as part of their object
creation machinery; switched to calling new helper.

      rpc_pipefs proper:

3) rpc_pipe: clean failure exits in fill_super
	->kill_sb() will be called immediately after a failure
return anyway, so we don't need to bother with notifier chain and
rpc_gssd_dummy_depopulate().  What's more, rpc_gssd_dummy_populate()
failure exits do not need to bother with __rpc_depopulate() - anything
added to the tree will be taken out by ->kill_sb().

4) rpc_{rmdir_,}depopulate(): use simple_recursive_removal() instead
	no need to give an exact list of objects to be remove when it's
simply every child of the victim directory.

5) rpc_unlink(): use simple_recursive_removal()
	Previous commit was dealing with directories; this one is for
named pipes (i.e. the thing rpc_pipefs is used for).  Note that the
callback of simple_recursive_removal() is called with the parent locked;
the victim isn't locked by the caller.

6) 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.

7) rpc_unlink(): saner calling conventions
	* pass it pipe instead of pipe->dentry
	* zero pipe->dentry afterwards
	* it always returns 0; why bother?
	
8) rpc_mkpipe_dentry(): saner calling conventions
	Instead of returning a dentry or ERR_PTR(-E...), return 0 and
store dentry into pipe->dentry on success and return -E... on failure.
Callers are happier that way...

9) rpc_pipe: don't overdo directory locking
	Don't try to hold directories locked more than VFS requires;
lock just before getting a child to be made positive (using
simple_start_creating()) and unlock as soon as the child is created.
There's no benefit in keeping the parent locked while populating the
child - it won't stop dcache lookups anyway.

10) rpc_pipe: saner primitive for creating subdirectories
	All users of __rpc_mkdir() have the same form - start_creating(),
followed, in case of success, by __rpc_mkdir() and unlocking parent.
Combine that into a single helper, expanding __rpc_mkdir() into it, along
with the call of __rpc_create_common() in it.
	Don't mess with d_drop() + d_add() - just d_instantiate()
and be done with that.	The reason __rpc_create_common() goes for that
dance is that dentry it gets might or might not be hashed; here we know
it's hashed.

11) rpc_pipe: saner primitive for creating regular files
	rpc_new_file(); similar to rpc_new_dir(), except that here we
pass file_operations as well.  Callers don't care about dentry, just
return 0 or -E...

12) rpc_mkpipe_dentry(): switch to start_creating()
	... and make sure we set the rpc_pipe-private part of inode up
before attaching it to dentry.

13) rpc_gssd_dummy_populate(): don't bother with rpc_populate()
	Just have it create gssd (in root), clntXX in gssd, then info
and gssd in clntXX - all with explicit
rpc_new_dir()/rpc_new_file()/rpc_mkpipe_dentry().

14) rpc_pipe: expand the calls of rpc_mkdir_populate()
	... and get rid of convoluted callbacks.

15) rpc_new_dir(): the last argument is always NULL
	All callers except the one in rpc_populate() pass explicit NULL
there; rpc_populate() passes its last argument ('private') instead,
but in the only call of rpc_populate() that creates any subdirectories
(when creating fixed subdirectories of root) private itself is NULL.

16) rpc_create_client_dir(): don't bother with rpc_populate()
	not for a single file...

17) rpc_create_client_dir(): return 0 or -E...
	Callers couldn't care less which dentry did we get - anything
valid is treated as success.

^ permalink raw reply	[flat|nested] 25+ messages in thread

* [PATCH 01/17] simple_recursive_removal(): saner interaction with fsnotify
  2025-06-13  7:31 [PATCHES][RFC][CFT] rpc_pipefs cleanups Al Viro
@ 2025-06-13  7:34 ` Al Viro
  2025-06-13  7:34   ` [PATCH 02/17] new helper: simple_start_creating() Al Viro
                     ` (16 more replies)
  2025-06-13 19:32 ` [PATCHES][RFC][CFT] rpc_pipefs cleanups Jeff Layton
  1 sibling, 17 replies; 25+ messages in thread
From: Al Viro @ 2025-06-13  7:34 UTC (permalink / raw)
  To: linux-fsdevel; +Cc: chuck.lever, jlayton, linux-nfs, neil, torvalds, trondmy

Make it match the real unlink(2)/rmdir(2) - notify *after* the
operation.  And use fsnotify_delete() instead of messing with
fsnotify_unlink()/fsnotify_rmdir().

Currently the only caller that cares is the one in debugfs, and
there the order matching the normal syscalls makes more sense;
it'll get more serious for users introduced later in the series.

Signed-off-by: Al Viro <viro@zeniv.linux.org.uk>
---
 fs/libfs.c | 5 +----
 1 file changed, 1 insertion(+), 4 deletions(-)

diff --git a/fs/libfs.c b/fs/libfs.c
index 9ea0ecc325a8..42e226af6095 100644
--- a/fs/libfs.c
+++ b/fs/libfs.c
@@ -628,12 +628,9 @@ void simple_recursive_removal(struct dentry *dentry,
 			inode_lock(inode);
 			if (simple_positive(victim)) {
 				d_invalidate(victim);	// avoid lost mounts
-				if (d_is_dir(victim))
-					fsnotify_rmdir(inode, victim);
-				else
-					fsnotify_unlink(inode, victim);
 				if (callback)
 					callback(victim);
+				fsnotify_delete(inode, d_inode(victim), victim);
 				dput(victim);		// unpin it
 			}
 			if (victim == dentry) {
-- 
2.39.5


^ permalink raw reply related	[flat|nested] 25+ messages in thread

* [PATCH 02/17] new helper: simple_start_creating()
  2025-06-13  7:34 ` [PATCH 01/17] simple_recursive_removal(): saner interaction with fsnotify Al Viro
@ 2025-06-13  7:34   ` Al Viro
  2025-06-13 18:31     ` Jeff Layton
  2025-06-13  7:34   ` [PATCH 03/17] rpc_pipe: clean failure exits in fill_super Al Viro
                     ` (15 subsequent siblings)
  16 siblings, 1 reply; 25+ messages in thread
From: Al Viro @ 2025-06-13  7:34 UTC (permalink / raw)
  To: linux-fsdevel; +Cc: chuck.lever, jlayton, linux-nfs, neil, torvalds, trondmy

Set the things up for kernel-initiated creation of object in
a tree-in-dcache filesystem.  With respect to locking it's
an equivalent of filename_create() - we either get a negative
dentry with locked parent, or ERR_PTR() and no locks taken.

tracefs and debugfs had that open-coded as part of their
object creation machinery; switched to calling new helper.

Signed-off-by: Al Viro <viro@zeniv.linux.org.uk>
---
 fs/debugfs/inode.c | 21 ++-------------------
 fs/libfs.c         | 25 +++++++++++++++++++++++++
 fs/tracefs/inode.c | 15 ++-------------
 include/linux/fs.h |  1 +
 4 files changed, 30 insertions(+), 32 deletions(-)

diff --git a/fs/debugfs/inode.c b/fs/debugfs/inode.c
index 30c4944e1862..08638e39bd12 100644
--- a/fs/debugfs/inode.c
+++ b/fs/debugfs/inode.c
@@ -384,26 +384,9 @@ static struct dentry *start_creating(const char *name, struct dentry *parent)
 	if (!parent)
 		parent = debugfs_mount->mnt_root;
 
-	inode_lock(d_inode(parent));
-	if (unlikely(IS_DEADDIR(d_inode(parent))))
-		dentry = ERR_PTR(-ENOENT);
-	else
-		dentry = lookup_noperm(&QSTR(name), parent);
-	if (!IS_ERR(dentry) && d_really_is_positive(dentry)) {
-		if (d_is_dir(dentry))
-			pr_err("Directory '%s' with parent '%s' already present!\n",
-			       name, parent->d_name.name);
-		else
-			pr_err("File '%s' in directory '%s' already present!\n",
-			       name, parent->d_name.name);
-		dput(dentry);
-		dentry = ERR_PTR(-EEXIST);
-	}
-
-	if (IS_ERR(dentry)) {
-		inode_unlock(d_inode(parent));
+	dentry = simple_start_creating(parent, name);
+	if (IS_ERR(dentry))
 		simple_release_fs(&debugfs_mount, &debugfs_mount_count);
-	}
 
 	return dentry;
 }
diff --git a/fs/libfs.c b/fs/libfs.c
index 42e226af6095..833ad5ed10f5 100644
--- a/fs/libfs.c
+++ b/fs/libfs.c
@@ -2260,3 +2260,28 @@ void stashed_dentry_prune(struct dentry *dentry)
 	 */
 	cmpxchg(stashed, dentry, NULL);
 }
+
+/* parent must be held exclusive */
+struct dentry *simple_start_creating(struct dentry *parent, const char *name)
+{
+	struct dentry *dentry;
+	struct inode *dir = d_inode(parent);
+
+	inode_lock(dir);
+	if (unlikely(IS_DEADDIR(dir))) {
+		inode_unlock(dir);
+		return ERR_PTR(-ENOENT);
+	}
+	dentry = lookup_noperm(&QSTR(name), parent);
+	if (IS_ERR(dentry)) {
+		inode_unlock(dir);
+		return dentry;
+	}
+	if (dentry->d_inode) {
+		dput(dentry);
+		inode_unlock(dir);
+		return ERR_PTR(-EEXIST);
+	}
+	return dentry;
+}
+EXPORT_SYMBOL(simple_start_creating);
diff --git a/fs/tracefs/inode.c b/fs/tracefs/inode.c
index a3fd3cc591bd..4e5d091e9263 100644
--- a/fs/tracefs/inode.c
+++ b/fs/tracefs/inode.c
@@ -551,20 +551,9 @@ struct dentry *tracefs_start_creating(const char *name, struct dentry *parent)
 	if (!parent)
 		parent = tracefs_mount->mnt_root;
 
-	inode_lock(d_inode(parent));
-	if (unlikely(IS_DEADDIR(d_inode(parent))))
-		dentry = ERR_PTR(-ENOENT);
-	else
-		dentry = lookup_noperm(&QSTR(name), parent);
-	if (!IS_ERR(dentry) && d_inode(dentry)) {
-		dput(dentry);
-		dentry = ERR_PTR(-EEXIST);
-	}
-
-	if (IS_ERR(dentry)) {
-		inode_unlock(d_inode(parent));
+	dentry = simple_start_creating(parent, name);
+	if (IS_ERR(dentry))
 		simple_release_fs(&tracefs_mount, &tracefs_mount_count);
-	}
 
 	return dentry;
 }
diff --git a/include/linux/fs.h b/include/linux/fs.h
index 96c7925a6551..9f75f8836bbd 100644
--- a/include/linux/fs.h
+++ b/include/linux/fs.h
@@ -3619,6 +3619,7 @@ extern int simple_fill_super(struct super_block *, unsigned long,
 			     const struct tree_descr *);
 extern int simple_pin_fs(struct file_system_type *, struct vfsmount **mount, int *count);
 extern void simple_release_fs(struct vfsmount **mount, int *count);
+struct dentry *simple_start_creating(struct dentry *, const char *);
 
 extern ssize_t simple_read_from_buffer(void __user *to, size_t count,
 			loff_t *ppos, const void *from, size_t available);
-- 
2.39.5


^ permalink raw reply related	[flat|nested] 25+ messages in thread

* [PATCH 03/17] rpc_pipe: clean failure exits in fill_super
  2025-06-13  7:34 ` [PATCH 01/17] simple_recursive_removal(): saner interaction with fsnotify Al Viro
  2025-06-13  7:34   ` [PATCH 02/17] new helper: simple_start_creating() Al Viro
@ 2025-06-13  7:34   ` Al Viro
  2025-06-13  7:34   ` [PATCH 04/17] rpc_{rmdir_,}depopulate(): use simple_recursive_removal() instead Al Viro
                     ` (14 subsequent siblings)
  16 siblings, 0 replies; 25+ messages in thread
From: Al Viro @ 2025-06-13  7:34 UTC (permalink / raw)
  To: linux-fsdevel; +Cc: chuck.lever, jlayton, linux-nfs, neil, torvalds, trondmy

->kill_sb() will be called immediately after a failure return
anyway, so we don't need to bother with notifier chain and
rpc_gssd_dummy_depopulate().  What's more, rpc_gssd_dummy_populate()
failure exits do not need to bother with __rpc_depopulate() -
anything added to the tree will be taken out by ->kill_sb().

Signed-off-by: Al Viro <viro@zeniv.linux.org.uk>
---
 net/sunrpc/rpc_pipe.c | 67 +++++++++++--------------------------------
 1 file changed, 16 insertions(+), 51 deletions(-)

diff --git a/net/sunrpc/rpc_pipe.c b/net/sunrpc/rpc_pipe.c
index 98f78cd55905..580e078e49a3 100644
--- a/net/sunrpc/rpc_pipe.c
+++ b/net/sunrpc/rpc_pipe.c
@@ -1292,7 +1292,7 @@ static const struct rpc_filelist gssd_dummy_info_file[] = {
  * Create a dummy set of directories and a pipe that gssd can hold open to
  * indicate that it is up and running.
  */
-static struct dentry *
+static int
 rpc_gssd_dummy_populate(struct dentry *root, struct rpc_pipe *pipe_data)
 {
 	int ret = 0;
@@ -1303,58 +1303,37 @@ rpc_gssd_dummy_populate(struct dentry *root, struct rpc_pipe *pipe_data)
 	/* We should never get this far if "gssd" doesn't exist */
 	gssd_dentry = try_lookup_noperm(&QSTR(files[RPCAUTH_gssd].name), root);
 	if (!gssd_dentry)
-		return ERR_PTR(-ENOENT);
+		return -ENOENT;
 
 	ret = rpc_populate(gssd_dentry, gssd_dummy_clnt_dir, 0, 1, NULL);
 	if (ret) {
-		pipe_dentry = ERR_PTR(ret);
-		goto out;
+		dput(gssd_dentry);
+		return ret;
 	}
 
 	clnt_dentry = try_lookup_noperm(&QSTR(gssd_dummy_clnt_dir[0].name),
 					  gssd_dentry);
-	if (!clnt_dentry) {
-		__rpc_depopulate(gssd_dentry, gssd_dummy_clnt_dir, 0, 1);
-		pipe_dentry = ERR_PTR(-ENOENT);
-		goto out;
-	}
+	dput(gssd_dentry);
+	if (!clnt_dentry)
+		return -ENOENT;
 
 	ret = rpc_populate(clnt_dentry, gssd_dummy_info_file, 0, 1, NULL);
 	if (ret) {
-		__rpc_depopulate(gssd_dentry, gssd_dummy_clnt_dir, 0, 1);
-		pipe_dentry = ERR_PTR(ret);
-		goto out;
+		dput(clnt_dentry);
+		return ret;
 	}
-
 	pipe_dentry = rpc_mkpipe_dentry(clnt_dentry, "gssd", NULL, pipe_data);
-	if (IS_ERR(pipe_dentry)) {
-		__rpc_depopulate(clnt_dentry, gssd_dummy_info_file, 0, 1);
-		__rpc_depopulate(gssd_dentry, gssd_dummy_clnt_dir, 0, 1);
-	}
-out:
 	dput(clnt_dentry);
-	dput(gssd_dentry);
-	return pipe_dentry;
-}
-
-static void
-rpc_gssd_dummy_depopulate(struct dentry *pipe_dentry)
-{
-	struct dentry *clnt_dir = pipe_dentry->d_parent;
-	struct dentry *gssd_dir = clnt_dir->d_parent;
-
-	dget(pipe_dentry);
-	__rpc_rmpipe(d_inode(clnt_dir), pipe_dentry);
-	__rpc_depopulate(clnt_dir, gssd_dummy_info_file, 0, 1);
-	__rpc_depopulate(gssd_dir, gssd_dummy_clnt_dir, 0, 1);
-	dput(pipe_dentry);
+	if (IS_ERR(pipe_dentry))
+		ret = PTR_ERR(pipe_dentry);
+	return ret;
 }
 
 static int
 rpc_fill_super(struct super_block *sb, struct fs_context *fc)
 {
 	struct inode *inode;
-	struct dentry *root, *gssd_dentry;
+	struct dentry *root;
 	struct net *net = sb->s_fs_info;
 	struct sunrpc_net *sn = net_generic(net, sunrpc_net_id);
 	int err;
@@ -1373,11 +1352,9 @@ rpc_fill_super(struct super_block *sb, struct fs_context *fc)
 	if (rpc_populate(root, files, RPCAUTH_lockd, RPCAUTH_RootEOF, NULL))
 		return -ENOMEM;
 
-	gssd_dentry = rpc_gssd_dummy_populate(root, sn->gssd_dummy);
-	if (IS_ERR(gssd_dentry)) {
-		__rpc_depopulate(root, files, RPCAUTH_lockd, RPCAUTH_RootEOF);
-		return PTR_ERR(gssd_dentry);
-	}
+	err = rpc_gssd_dummy_populate(root, sn->gssd_dummy);
+	if (err)
+		return err;
 
 	dprintk("RPC:       sending pipefs MOUNT notification for net %x%s\n",
 		net->ns.inum, NET_NAME(net));
@@ -1386,18 +1363,6 @@ rpc_fill_super(struct super_block *sb, struct fs_context *fc)
 	err = blocking_notifier_call_chain(&rpc_pipefs_notifier_list,
 					   RPC_PIPEFS_MOUNT,
 					   sb);
-	if (err)
-		goto err_depopulate;
-	mutex_unlock(&sn->pipefs_sb_lock);
-	return 0;
-
-err_depopulate:
-	rpc_gssd_dummy_depopulate(gssd_dentry);
-	blocking_notifier_call_chain(&rpc_pipefs_notifier_list,
-					   RPC_PIPEFS_UMOUNT,
-					   sb);
-	sn->pipefs_sb = NULL;
-	__rpc_depopulate(root, files, RPCAUTH_lockd, RPCAUTH_RootEOF);
 	mutex_unlock(&sn->pipefs_sb_lock);
 	return err;
 }
-- 
2.39.5


^ permalink raw reply related	[flat|nested] 25+ messages in thread

* [PATCH 04/17] rpc_{rmdir_,}depopulate(): use simple_recursive_removal() instead
  2025-06-13  7:34 ` [PATCH 01/17] simple_recursive_removal(): saner interaction with fsnotify Al Viro
  2025-06-13  7:34   ` [PATCH 02/17] new helper: simple_start_creating() Al Viro
  2025-06-13  7:34   ` [PATCH 03/17] rpc_pipe: clean failure exits in fill_super Al Viro
@ 2025-06-13  7:34   ` Al Viro
  2025-06-13  7:34   ` [PATCH 05/17] rpc_unlink(): use simple_recursive_removal() Al Viro
                     ` (13 subsequent siblings)
  16 siblings, 0 replies; 25+ messages in thread
From: Al Viro @ 2025-06-13  7:34 UTC (permalink / raw)
  To: linux-fsdevel; +Cc: chuck.lever, jlayton, linux-nfs, neil, torvalds, trondmy

no need to give an exact list of objects to be remove when it's
simply every child of the victim directory.

Signed-off-by: Al Viro <viro@zeniv.linux.org.uk>
---
 net/sunrpc/rpc_pipe.c | 44 +++----------------------------------------
 1 file changed, 3 insertions(+), 41 deletions(-)

diff --git a/net/sunrpc/rpc_pipe.c b/net/sunrpc/rpc_pipe.c
index 580e078e49a3..9571cbd91305 100644
--- a/net/sunrpc/rpc_pipe.c
+++ b/net/sunrpc/rpc_pipe.c
@@ -678,17 +678,6 @@ static void __rpc_depopulate(struct dentry *parent,
 	}
 }
 
-static void rpc_depopulate(struct dentry *parent,
-			   const struct rpc_filelist *files,
-			   int start, int eof)
-{
-	struct inode *dir = d_inode(parent);
-
-	inode_lock_nested(dir, I_MUTEX_CHILD);
-	__rpc_depopulate(parent, files, start, eof);
-	inode_unlock(dir);
-}
-
 static int rpc_populate(struct dentry *parent,
 			const struct rpc_filelist *files,
 			int start, int eof,
@@ -762,24 +751,6 @@ static struct dentry *rpc_mkdir_populate(struct dentry *parent,
 	goto out;
 }
 
-static int rpc_rmdir_depopulate(struct dentry *dentry,
-		void (*depopulate)(struct dentry *))
-{
-	struct dentry *parent;
-	struct inode *dir;
-	int error;
-
-	parent = dget_parent(dentry);
-	dir = d_inode(parent);
-	inode_lock_nested(dir, I_MUTEX_PARENT);
-	if (depopulate != NULL)
-		depopulate(dentry);
-	error = __rpc_rmdir(dir, dentry);
-	inode_unlock(dir);
-	dput(parent);
-	return error;
-}
-
 /**
  * rpc_mkpipe_dentry - make an rpc_pipefs file for kernel<->userspace
  *		       communication
@@ -1030,11 +1001,6 @@ static int rpc_clntdir_populate(struct dentry *dentry, void *private)
 			    private);
 }
 
-static void rpc_clntdir_depopulate(struct dentry *dentry)
-{
-	rpc_depopulate(dentry, authfiles, RPCAUTH_info, RPCAUTH_EOF);
-}
-
 /**
  * rpc_create_client_dir - Create a new rpc_client directory in rpc_pipefs
  * @dentry: the parent of new directory
@@ -1073,7 +1039,8 @@ int rpc_remove_client_dir(struct rpc_clnt *rpc_client)
 		return 0;
 	rpc_destroy_pipe_dir_objects(&rpc_client->cl_pipedir_objects);
 	rpc_client->cl_pipedir_objects.pdh_dentry = NULL;
-	return rpc_rmdir_depopulate(dentry, rpc_clntdir_depopulate);
+	simple_recursive_removal(dentry, NULL);
+	return 0;
 }
 
 static const struct rpc_filelist cache_pipefs_files[3] = {
@@ -1101,11 +1068,6 @@ static int rpc_cachedir_populate(struct dentry *dentry, void *private)
 			    private);
 }
 
-static void rpc_cachedir_depopulate(struct dentry *dentry)
-{
-	rpc_depopulate(dentry, cache_pipefs_files, 0, 3);
-}
-
 struct dentry *rpc_create_cache_dir(struct dentry *parent, const char *name,
 				    umode_t umode, struct cache_detail *cd)
 {
@@ -1115,7 +1077,7 @@ struct dentry *rpc_create_cache_dir(struct dentry *parent, const char *name,
 
 void rpc_remove_cache_dir(struct dentry *dentry)
 {
-	rpc_rmdir_depopulate(dentry, rpc_cachedir_depopulate);
+	simple_recursive_removal(dentry, NULL);
 }
 
 /*
-- 
2.39.5


^ permalink raw reply related	[flat|nested] 25+ messages in thread

* [PATCH 05/17] rpc_unlink(): use simple_recursive_removal()
  2025-06-13  7:34 ` [PATCH 01/17] simple_recursive_removal(): saner interaction with fsnotify Al Viro
                     ` (2 preceding siblings ...)
  2025-06-13  7:34   ` [PATCH 04/17] rpc_{rmdir_,}depopulate(): use simple_recursive_removal() instead Al Viro
@ 2025-06-13  7:34   ` Al Viro
  2025-06-13  7:34   ` [PATCH 06/17] rpc_populate(): lift cleanup into callers Al Viro
                     ` (12 subsequent siblings)
  16 siblings, 0 replies; 25+ messages in thread
From: Al Viro @ 2025-06-13  7:34 UTC (permalink / raw)
  To: linux-fsdevel; +Cc: chuck.lever, jlayton, linux-nfs, neil, torvalds, trondmy

note that the callback of simple_recursive_removal() is called with
the parent locked; the victim isn't locked by the caller.

Signed-off-by: Al Viro <viro@zeniv.linux.org.uk>
---
 net/sunrpc/rpc_pipe.c | 24 ++++--------------------
 1 file changed, 4 insertions(+), 20 deletions(-)

diff --git a/net/sunrpc/rpc_pipe.c b/net/sunrpc/rpc_pipe.c
index 9571cbd91305..67621a94f67b 100644
--- a/net/sunrpc/rpc_pipe.c
+++ b/net/sunrpc/rpc_pipe.c
@@ -168,8 +168,9 @@ rpc_inode_setowner(struct inode *inode, void *private)
 }
 
 static void
-rpc_close_pipes(struct inode *inode)
+rpc_close_pipes(struct dentry *dentry)
 {
+	struct inode *inode = dentry->d_inode;
 	struct rpc_pipe *pipe = RPC_I(inode)->pipe;
 	int need_release;
 	LIST_HEAD(free_list);
@@ -619,14 +620,6 @@ static int __rpc_unlink(struct inode *dir, struct dentry *dentry)
 	return ret;
 }
 
-static int __rpc_rmpipe(struct inode *dir, struct dentry *dentry)
-{
-	struct inode *inode = d_inode(dentry);
-
-	rpc_close_pipes(inode);
-	return __rpc_unlink(dir, dentry);
-}
-
 static struct dentry *__rpc_lookup_create_exclusive(struct dentry *parent,
 					  const char *name)
 {
@@ -814,17 +807,8 @@ EXPORT_SYMBOL_GPL(rpc_mkpipe_dentry);
 int
 rpc_unlink(struct dentry *dentry)
 {
-	struct dentry *parent;
-	struct inode *dir;
-	int error = 0;
-
-	parent = dget_parent(dentry);
-	dir = d_inode(parent);
-	inode_lock_nested(dir, I_MUTEX_PARENT);
-	error = __rpc_rmpipe(dir, dentry);
-	inode_unlock(dir);
-	dput(parent);
-	return error;
+	simple_recursive_removal(dentry, rpc_close_pipes);
+	return 0;
 }
 EXPORT_SYMBOL_GPL(rpc_unlink);
 
-- 
2.39.5


^ permalink raw reply related	[flat|nested] 25+ messages in thread

* [PATCH 06/17] rpc_populate(): lift cleanup into callers
  2025-06-13  7:34 ` [PATCH 01/17] simple_recursive_removal(): saner interaction with fsnotify Al Viro
                     ` (3 preceding siblings ...)
  2025-06-13  7:34   ` [PATCH 05/17] rpc_unlink(): use simple_recursive_removal() Al Viro
@ 2025-06-13  7:34   ` Al Viro
  2025-06-13  7:34   ` [PATCH 07/17] rpc_unlink(): saner calling conventions Al Viro
                     ` (11 subsequent siblings)
  16 siblings, 0 replies; 25+ messages in thread
From: Al Viro @ 2025-06-13  7:34 UTC (permalink / raw)
  To: linux-fsdevel; +Cc: chuck.lever, jlayton, linux-nfs, neil, torvalds, trondmy

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.

Signed-off-by: Al Viro <viro@zeniv.linux.org.uk>
---
 net/sunrpc/rpc_pipe.c | 71 +++----------------------------------------
 1 file changed, 5 insertions(+), 66 deletions(-)

diff --git a/net/sunrpc/rpc_pipe.c b/net/sunrpc/rpc_pipe.c
index 67621a94f67b..46fa00ac5e0e 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;
-- 
2.39.5


^ permalink raw reply related	[flat|nested] 25+ messages in thread

* [PATCH 07/17] rpc_unlink(): saner calling conventions
  2025-06-13  7:34 ` [PATCH 01/17] simple_recursive_removal(): saner interaction with fsnotify Al Viro
                     ` (4 preceding siblings ...)
  2025-06-13  7:34   ` [PATCH 06/17] rpc_populate(): lift cleanup into callers Al Viro
@ 2025-06-13  7:34   ` Al Viro
  2025-06-13  7:34   ` [PATCH 08/17] rpc_mkpipe_dentry(): " Al Viro
                     ` (10 subsequent siblings)
  16 siblings, 0 replies; 25+ messages in thread
From: Al Viro @ 2025-06-13  7:34 UTC (permalink / raw)
  To: linux-fsdevel; +Cc: chuck.lever, jlayton, linux-nfs, neil, torvalds, trondmy

1) pass it pipe instead of pipe->dentry
2) zero pipe->dentry afterwards
3) it always returns 0; why bother?

Signed-off-by: Al Viro <viro@zeniv.linux.org.uk>
---
 fs/nfs/blocklayout/rpc_pipefs.c    | 12 ++----------
 fs/nfs/nfs4idmap.c                 |  6 +-----
 fs/nfsd/nfs4recover.c              | 12 ++----------
 include/linux/sunrpc/rpc_pipe_fs.h |  2 +-
 net/sunrpc/auth_gss/auth_gss.c     |  6 +-----
 net/sunrpc/rpc_pipe.c              | 12 +++++++-----
 6 files changed, 14 insertions(+), 36 deletions(-)

diff --git a/fs/nfs/blocklayout/rpc_pipefs.c b/fs/nfs/blocklayout/rpc_pipefs.c
index d8d50a88de04..25d429e44eb4 100644
--- a/fs/nfs/blocklayout/rpc_pipefs.c
+++ b/fs/nfs/blocklayout/rpc_pipefs.c
@@ -154,13 +154,6 @@ static struct dentry *nfs4blocklayout_register_sb(struct super_block *sb,
 	return dentry;
 }
 
-static void nfs4blocklayout_unregister_sb(struct super_block *sb,
-					  struct rpc_pipe *pipe)
-{
-	if (pipe->dentry)
-		rpc_unlink(pipe->dentry);
-}
-
 static int rpc_pipefs_event(struct notifier_block *nb, unsigned long event,
 			   void *ptr)
 {
@@ -188,8 +181,7 @@ static int rpc_pipefs_event(struct notifier_block *nb, unsigned long event,
 		nn->bl_device_pipe->dentry = dentry;
 		break;
 	case RPC_PIPEFS_UMOUNT:
-		if (nn->bl_device_pipe->dentry)
-			nfs4blocklayout_unregister_sb(sb, nn->bl_device_pipe);
+		rpc_unlink(nn->bl_device_pipe);
 		break;
 	default:
 		ret = -ENOTSUPP;
@@ -224,7 +216,7 @@ static void nfs4blocklayout_unregister_net(struct net *net,
 
 	pipefs_sb = rpc_get_sb_net(net);
 	if (pipefs_sb) {
-		nfs4blocklayout_unregister_sb(pipefs_sb, pipe);
+		rpc_unlink(pipe);
 		rpc_put_sb_net(net);
 	}
 }
diff --git a/fs/nfs/nfs4idmap.c b/fs/nfs/nfs4idmap.c
index 25a7c771cfd8..adc03232b851 100644
--- a/fs/nfs/nfs4idmap.c
+++ b/fs/nfs/nfs4idmap.c
@@ -424,12 +424,8 @@ static void nfs_idmap_pipe_destroy(struct dentry *dir,
 		struct rpc_pipe_dir_object *pdo)
 {
 	struct idmap *idmap = pdo->pdo_data;
-	struct rpc_pipe *pipe = idmap->idmap_pipe;
 
-	if (pipe->dentry) {
-		rpc_unlink(pipe->dentry);
-		pipe->dentry = NULL;
-	}
+	rpc_unlink(idmap->idmap_pipe);
 }
 
 static int nfs_idmap_pipe_create(struct dentry *dir,
diff --git a/fs/nfsd/nfs4recover.c b/fs/nfsd/nfs4recover.c
index 82785db730d9..bbd29b3b573f 100644
--- a/fs/nfsd/nfs4recover.c
+++ b/fs/nfsd/nfs4recover.c
@@ -963,13 +963,6 @@ nfsd4_cld_register_sb(struct super_block *sb, struct rpc_pipe *pipe)
 	return dentry;
 }
 
-static void
-nfsd4_cld_unregister_sb(struct rpc_pipe *pipe)
-{
-	if (pipe->dentry)
-		rpc_unlink(pipe->dentry);
-}
-
 static struct dentry *
 nfsd4_cld_register_net(struct net *net, struct rpc_pipe *pipe)
 {
@@ -991,7 +984,7 @@ nfsd4_cld_unregister_net(struct net *net, struct rpc_pipe *pipe)
 
 	sb = rpc_get_sb_net(net);
 	if (sb) {
-		nfsd4_cld_unregister_sb(pipe);
+		rpc_unlink(pipe);
 		rpc_put_sb_net(net);
 	}
 }
@@ -2142,8 +2135,7 @@ rpc_pipefs_event(struct notifier_block *nb, unsigned long event, void *ptr)
 		cn->cn_pipe->dentry = dentry;
 		break;
 	case RPC_PIPEFS_UMOUNT:
-		if (cn->cn_pipe->dentry)
-			nfsd4_cld_unregister_sb(cn->cn_pipe);
+		rpc_unlink(cn->cn_pipe);
 		break;
 	default:
 		ret = -ENOTSUPP;
diff --git a/include/linux/sunrpc/rpc_pipe_fs.h b/include/linux/sunrpc/rpc_pipe_fs.h
index 3b35b6f6533a..a8c0a500d55c 100644
--- a/include/linux/sunrpc/rpc_pipe_fs.h
+++ b/include/linux/sunrpc/rpc_pipe_fs.h
@@ -129,7 +129,7 @@ struct rpc_pipe *rpc_mkpipe_data(const struct rpc_pipe_ops *ops, int flags);
 void rpc_destroy_pipe_data(struct rpc_pipe *pipe);
 extern struct dentry *rpc_mkpipe_dentry(struct dentry *, const char *, void *,
 					struct rpc_pipe *);
-extern int rpc_unlink(struct dentry *);
+extern void rpc_unlink(struct rpc_pipe *);
 extern int register_rpc_pipefs(void);
 extern void unregister_rpc_pipefs(void);
 
diff --git a/net/sunrpc/auth_gss/auth_gss.c b/net/sunrpc/auth_gss/auth_gss.c
index 0fa244f16876..f2a44d589cfb 100644
--- a/net/sunrpc/auth_gss/auth_gss.c
+++ b/net/sunrpc/auth_gss/auth_gss.c
@@ -887,12 +887,8 @@ static void gss_pipe_dentry_destroy(struct dentry *dir,
 		struct rpc_pipe_dir_object *pdo)
 {
 	struct gss_pipe *gss_pipe = pdo->pdo_data;
-	struct rpc_pipe *pipe = gss_pipe->pipe;
 
-	if (pipe->dentry != NULL) {
-		rpc_unlink(pipe->dentry);
-		pipe->dentry = NULL;
-	}
+	rpc_unlink(gss_pipe->pipe);
 }
 
 static int gss_pipe_dentry_create(struct dentry *dir,
diff --git a/net/sunrpc/rpc_pipe.c b/net/sunrpc/rpc_pipe.c
index 46fa00ac5e0e..2046582c4f35 100644
--- a/net/sunrpc/rpc_pipe.c
+++ b/net/sunrpc/rpc_pipe.c
@@ -737,17 +737,19 @@ EXPORT_SYMBOL_GPL(rpc_mkpipe_dentry);
 
 /**
  * rpc_unlink - remove a pipe
- * @dentry: dentry for the pipe, as returned from rpc_mkpipe
+ * @pipe: the pipe to be removed
  *
  * After this call, lookups will no longer find the pipe, and any
  * attempts to read or write using preexisting opens of the pipe will
  * return -EPIPE.
  */
-int
-rpc_unlink(struct dentry *dentry)
+void
+rpc_unlink(struct rpc_pipe *pipe)
 {
-	simple_recursive_removal(dentry, rpc_close_pipes);
-	return 0;
+	if (pipe->dentry) {
+		simple_recursive_removal(pipe->dentry, rpc_close_pipes);
+		pipe->dentry = NULL;
+	}
 }
 EXPORT_SYMBOL_GPL(rpc_unlink);
 
-- 
2.39.5


^ permalink raw reply related	[flat|nested] 25+ messages in thread

* [PATCH 08/17] rpc_mkpipe_dentry(): saner calling conventions
  2025-06-13  7:34 ` [PATCH 01/17] simple_recursive_removal(): saner interaction with fsnotify Al Viro
                     ` (5 preceding siblings ...)
  2025-06-13  7:34   ` [PATCH 07/17] rpc_unlink(): saner calling conventions Al Viro
@ 2025-06-13  7:34   ` Al Viro
  2025-06-13  7:34   ` [PATCH 09/17] rpc_pipe: don't overdo directory locking Al Viro
                     ` (9 subsequent siblings)
  16 siblings, 0 replies; 25+ messages in thread
From: Al Viro @ 2025-06-13  7:34 UTC (permalink / raw)
  To: linux-fsdevel; +Cc: chuck.lever, jlayton, linux-nfs, neil, torvalds, trondmy

Instead of returning a dentry or ERR_PTR(-E...), return 0 and store
dentry into pipe->dentry on success and return -E... on failure.

Callers are happier that way...

NOTE: dummy rpc_pipe is getting ->dentry set; we never access that,
since we
	1) never call rpc_unlink() for it (dentry is taken out by
->kill_sb())
	2) never call rpc_queue_upcall() for it (writing to that
sucker fails; no downcalls are ever submitted, so no replies are
going to arrive)
IOW, having that ->dentry set (and left dangling) is harmless,
if ugly; cleaner solution will take more massage.

Signed-off-by: Al Viro <viro@zeniv.linux.org.uk>
---
 fs/nfs/blocklayout/rpc_pipefs.c    | 41 ++++++++++++------------------
 fs/nfs/nfs4idmap.c                 |  8 +-----
 fs/nfsd/nfs4recover.c              | 37 ++++++++++-----------------
 include/linux/sunrpc/rpc_pipe_fs.h |  2 +-
 net/sunrpc/auth_gss/auth_gss.c     |  7 +----
 net/sunrpc/rpc_pipe.c              | 29 +++++++++------------
 6 files changed, 45 insertions(+), 79 deletions(-)

diff --git a/fs/nfs/blocklayout/rpc_pipefs.c b/fs/nfs/blocklayout/rpc_pipefs.c
index 25d429e44eb4..d526f5ba7887 100644
--- a/fs/nfs/blocklayout/rpc_pipefs.c
+++ b/fs/nfs/blocklayout/rpc_pipefs.c
@@ -141,17 +141,18 @@ static const struct rpc_pipe_ops bl_upcall_ops = {
 	.destroy_msg	= bl_pipe_destroy_msg,
 };
 
-static struct dentry *nfs4blocklayout_register_sb(struct super_block *sb,
+static int nfs4blocklayout_register_sb(struct super_block *sb,
 					    struct rpc_pipe *pipe)
 {
-	struct dentry *dir, *dentry;
+	struct dentry *dir;
+	int err;
 
 	dir = rpc_d_lookup_sb(sb, NFS_PIPE_DIRNAME);
 	if (dir == NULL)
-		return ERR_PTR(-ENOENT);
-	dentry = rpc_mkpipe_dentry(dir, "blocklayout", NULL, pipe);
+		return -ENOENT;
+	err = rpc_mkpipe_dentry(dir, "blocklayout", NULL, pipe);
 	dput(dir);
-	return dentry;
+	return err;
 }
 
 static int rpc_pipefs_event(struct notifier_block *nb, unsigned long event,
@@ -160,7 +161,6 @@ static int rpc_pipefs_event(struct notifier_block *nb, unsigned long event,
 	struct super_block *sb = ptr;
 	struct net *net = sb->s_fs_info;
 	struct nfs_net *nn = net_generic(net, nfs_net_id);
-	struct dentry *dentry;
 	int ret = 0;
 
 	if (!try_module_get(THIS_MODULE))
@@ -173,12 +173,7 @@ static int rpc_pipefs_event(struct notifier_block *nb, unsigned long event,
 
 	switch (event) {
 	case RPC_PIPEFS_MOUNT:
-		dentry = nfs4blocklayout_register_sb(sb, nn->bl_device_pipe);
-		if (IS_ERR(dentry)) {
-			ret = PTR_ERR(dentry);
-			break;
-		}
-		nn->bl_device_pipe->dentry = dentry;
+		ret = nfs4blocklayout_register_sb(sb, nn->bl_device_pipe);
 		break;
 	case RPC_PIPEFS_UMOUNT:
 		rpc_unlink(nn->bl_device_pipe);
@@ -195,18 +190,17 @@ static struct notifier_block nfs4blocklayout_block = {
 	.notifier_call = rpc_pipefs_event,
 };
 
-static struct dentry *nfs4blocklayout_register_net(struct net *net,
-						   struct rpc_pipe *pipe)
+static int nfs4blocklayout_register_net(struct net *net, struct rpc_pipe *pipe)
 {
 	struct super_block *pipefs_sb;
-	struct dentry *dentry;
+	int ret;
 
 	pipefs_sb = rpc_get_sb_net(net);
 	if (!pipefs_sb)
-		return NULL;
-	dentry = nfs4blocklayout_register_sb(pipefs_sb, pipe);
+		return 0;
+	ret = nfs4blocklayout_register_sb(pipefs_sb, pipe);
 	rpc_put_sb_net(net);
-	return dentry;
+	return ret;
 }
 
 static void nfs4blocklayout_unregister_net(struct net *net,
@@ -224,20 +218,17 @@ static void nfs4blocklayout_unregister_net(struct net *net,
 static int nfs4blocklayout_net_init(struct net *net)
 {
 	struct nfs_net *nn = net_generic(net, nfs_net_id);
-	struct dentry *dentry;
+	int err;
 
 	mutex_init(&nn->bl_mutex);
 	init_waitqueue_head(&nn->bl_wq);
 	nn->bl_device_pipe = rpc_mkpipe_data(&bl_upcall_ops, 0);
 	if (IS_ERR(nn->bl_device_pipe))
 		return PTR_ERR(nn->bl_device_pipe);
-	dentry = nfs4blocklayout_register_net(net, nn->bl_device_pipe);
-	if (IS_ERR(dentry)) {
+	err = nfs4blocklayout_register_net(net, nn->bl_device_pipe);
+	if (unlikely(err))
 		rpc_destroy_pipe_data(nn->bl_device_pipe);
-		return PTR_ERR(dentry);
-	}
-	nn->bl_device_pipe->dentry = dentry;
-	return 0;
+	return err;
 }
 
 static void nfs4blocklayout_net_exit(struct net *net)
diff --git a/fs/nfs/nfs4idmap.c b/fs/nfs/nfs4idmap.c
index adc03232b851..00932500fce4 100644
--- a/fs/nfs/nfs4idmap.c
+++ b/fs/nfs/nfs4idmap.c
@@ -432,14 +432,8 @@ static int nfs_idmap_pipe_create(struct dentry *dir,
 		struct rpc_pipe_dir_object *pdo)
 {
 	struct idmap *idmap = pdo->pdo_data;
-	struct rpc_pipe *pipe = idmap->idmap_pipe;
-	struct dentry *dentry;
 
-	dentry = rpc_mkpipe_dentry(dir, "idmap", idmap, pipe);
-	if (IS_ERR(dentry))
-		return PTR_ERR(dentry);
-	pipe->dentry = dentry;
-	return 0;
+	return rpc_mkpipe_dentry(dir, "idmap", idmap, idmap->idmap_pipe);
 }
 
 static const struct rpc_pipe_dir_object_ops nfs_idmap_pipe_dir_object_ops = {
diff --git a/fs/nfsd/nfs4recover.c b/fs/nfsd/nfs4recover.c
index bbd29b3b573f..2231192ec33f 100644
--- a/fs/nfsd/nfs4recover.c
+++ b/fs/nfsd/nfs4recover.c
@@ -950,31 +950,32 @@ static const struct rpc_pipe_ops cld_upcall_ops = {
 	.destroy_msg	= cld_pipe_destroy_msg,
 };
 
-static struct dentry *
+static int
 nfsd4_cld_register_sb(struct super_block *sb, struct rpc_pipe *pipe)
 {
-	struct dentry *dir, *dentry;
+	struct dentry *dir;
+	int err;
 
 	dir = rpc_d_lookup_sb(sb, NFSD_PIPE_DIR);
 	if (dir == NULL)
-		return ERR_PTR(-ENOENT);
-	dentry = rpc_mkpipe_dentry(dir, NFSD_CLD_PIPE, NULL, pipe);
+		return -ENOENT;
+	err = rpc_mkpipe_dentry(dir, NFSD_CLD_PIPE, NULL, pipe);
 	dput(dir);
-	return dentry;
+	return err;
 }
 
-static struct dentry *
+static int
 nfsd4_cld_register_net(struct net *net, struct rpc_pipe *pipe)
 {
 	struct super_block *sb;
-	struct dentry *dentry;
+	int err;
 
 	sb = rpc_get_sb_net(net);
 	if (!sb)
-		return NULL;
-	dentry = nfsd4_cld_register_sb(sb, pipe);
+		return 0;
+	err = nfsd4_cld_register_sb(sb, pipe);
 	rpc_put_sb_net(net);
-	return dentry;
+	return err;
 }
 
 static void
@@ -994,7 +995,6 @@ static int
 __nfsd4_init_cld_pipe(struct net *net)
 {
 	int ret;
-	struct dentry *dentry;
 	struct nfsd_net *nn = net_generic(net, nfsd_net_id);
 	struct cld_net *cn;
 
@@ -1015,13 +1015,10 @@ __nfsd4_init_cld_pipe(struct net *net)
 	spin_lock_init(&cn->cn_lock);
 	INIT_LIST_HEAD(&cn->cn_list);
 
-	dentry = nfsd4_cld_register_net(net, cn->cn_pipe);
-	if (IS_ERR(dentry)) {
-		ret = PTR_ERR(dentry);
+	ret = nfsd4_cld_register_net(net, cn->cn_pipe);
+	if (unlikely(ret))
 		goto err_destroy_data;
-	}
 
-	cn->cn_pipe->dentry = dentry;
 #ifdef CONFIG_NFSD_LEGACY_CLIENT_TRACKING
 	cn->cn_has_legacy = false;
 #endif
@@ -2114,7 +2111,6 @@ rpc_pipefs_event(struct notifier_block *nb, unsigned long event, void *ptr)
 	struct net *net = sb->s_fs_info;
 	struct nfsd_net *nn = net_generic(net, nfsd_net_id);
 	struct cld_net *cn = nn->cld_net;
-	struct dentry *dentry;
 	int ret = 0;
 
 	if (!try_module_get(THIS_MODULE))
@@ -2127,12 +2123,7 @@ rpc_pipefs_event(struct notifier_block *nb, unsigned long event, void *ptr)
 
 	switch (event) {
 	case RPC_PIPEFS_MOUNT:
-		dentry = nfsd4_cld_register_sb(sb, cn->cn_pipe);
-		if (IS_ERR(dentry)) {
-			ret = PTR_ERR(dentry);
-			break;
-		}
-		cn->cn_pipe->dentry = dentry;
+		ret = nfsd4_cld_register_sb(sb, cn->cn_pipe);
 		break;
 	case RPC_PIPEFS_UMOUNT:
 		rpc_unlink(cn->cn_pipe);
diff --git a/include/linux/sunrpc/rpc_pipe_fs.h b/include/linux/sunrpc/rpc_pipe_fs.h
index a8c0a500d55c..8cc3a5df9801 100644
--- a/include/linux/sunrpc/rpc_pipe_fs.h
+++ b/include/linux/sunrpc/rpc_pipe_fs.h
@@ -127,7 +127,7 @@ extern void rpc_remove_cache_dir(struct dentry *);
 
 struct rpc_pipe *rpc_mkpipe_data(const struct rpc_pipe_ops *ops, int flags);
 void rpc_destroy_pipe_data(struct rpc_pipe *pipe);
-extern struct dentry *rpc_mkpipe_dentry(struct dentry *, const char *, void *,
+extern int rpc_mkpipe_dentry(struct dentry *, const char *, void *,
 					struct rpc_pipe *);
 extern void rpc_unlink(struct rpc_pipe *);
 extern int register_rpc_pipefs(void);
diff --git a/net/sunrpc/auth_gss/auth_gss.c b/net/sunrpc/auth_gss/auth_gss.c
index f2a44d589cfb..6c23d46a1dcc 100644
--- a/net/sunrpc/auth_gss/auth_gss.c
+++ b/net/sunrpc/auth_gss/auth_gss.c
@@ -895,13 +895,8 @@ static int gss_pipe_dentry_create(struct dentry *dir,
 		struct rpc_pipe_dir_object *pdo)
 {
 	struct gss_pipe *p = pdo->pdo_data;
-	struct dentry *dentry;
 
-	dentry = rpc_mkpipe_dentry(dir, p->name, p->clnt, p->pipe);
-	if (IS_ERR(dentry))
-		return PTR_ERR(dentry);
-	p->pipe->dentry = dentry;
-	return 0;
+	return rpc_mkpipe_dentry(dir, p->name, p->clnt, p->pipe);
 }
 
 static const struct rpc_pipe_dir_object_ops gss_pipe_dir_object_ops = {
diff --git a/net/sunrpc/rpc_pipe.c b/net/sunrpc/rpc_pipe.c
index 2046582c4f35..dac1c35a642f 100644
--- a/net/sunrpc/rpc_pipe.c
+++ b/net/sunrpc/rpc_pipe.c
@@ -702,7 +702,7 @@ static struct dentry *rpc_mkdir_populate(struct dentry *parent,
  * The @private argument passed here will be available to all these methods
  * from the file pointer, via RPC_I(file_inode(file))->private.
  */
-struct dentry *rpc_mkpipe_dentry(struct dentry *parent, const char *name,
+int rpc_mkpipe_dentry(struct dentry *parent, const char *name,
 				 void *private, struct rpc_pipe *pipe)
 {
 	struct dentry *dentry;
@@ -717,21 +717,19 @@ struct dentry *rpc_mkpipe_dentry(struct dentry *parent, const char *name,
 
 	inode_lock_nested(dir, I_MUTEX_PARENT);
 	dentry = __rpc_lookup_create_exclusive(parent, name);
-	if (IS_ERR(dentry))
-		goto out;
+	if (IS_ERR(dentry)) {
+		inode_unlock(dir);
+		return PTR_ERR(dentry);
+	}
 	err = __rpc_mkpipe_dentry(dir, dentry, umode, &rpc_pipe_fops,
 				  private, pipe);
-	if (err)
-		goto out_err;
-out:
+	if (unlikely(err))
+		pr_warn("%s() failed to create pipe %pd/%s (errno = %d)\n",
+			__func__, parent, name, err);
+	else
+		pipe->dentry = dentry;
 	inode_unlock(dir);
-	return dentry;
-out_err:
-	dentry = ERR_PTR(err);
-	printk(KERN_WARNING "%s: %s() failed to create pipe %pd/%s (errno = %d)\n",
-			__FILE__, __func__, parent, name,
-			err);
-	goto out;
+	return err;
 }
 EXPORT_SYMBOL_GPL(rpc_mkpipe_dentry);
 
@@ -1185,7 +1183,6 @@ rpc_gssd_dummy_populate(struct dentry *root, struct rpc_pipe *pipe_data)
 	int ret = 0;
 	struct dentry *gssd_dentry;
 	struct dentry *clnt_dentry = NULL;
-	struct dentry *pipe_dentry = NULL;
 
 	/* We should never get this far if "gssd" doesn't exist */
 	gssd_dentry = try_lookup_noperm(&QSTR(files[RPCAUTH_gssd].name), root);
@@ -1209,10 +1206,8 @@ rpc_gssd_dummy_populate(struct dentry *root, struct rpc_pipe *pipe_data)
 		dput(clnt_dentry);
 		return ret;
 	}
-	pipe_dentry = rpc_mkpipe_dentry(clnt_dentry, "gssd", NULL, pipe_data);
+	ret = rpc_mkpipe_dentry(clnt_dentry, "gssd", NULL, pipe_data);
 	dput(clnt_dentry);
-	if (IS_ERR(pipe_dentry))
-		ret = PTR_ERR(pipe_dentry);
 	return ret;
 }
 
-- 
2.39.5


^ permalink raw reply related	[flat|nested] 25+ messages in thread

* [PATCH 09/17] rpc_pipe: don't overdo directory locking
  2025-06-13  7:34 ` [PATCH 01/17] simple_recursive_removal(): saner interaction with fsnotify Al Viro
                     ` (6 preceding siblings ...)
  2025-06-13  7:34   ` [PATCH 08/17] rpc_mkpipe_dentry(): " Al Viro
@ 2025-06-13  7:34   ` Al Viro
  2025-06-13  7:34   ` [PATCH 10/17] rpc_pipe: saner primitive for creating subdirectories Al Viro
                     ` (8 subsequent siblings)
  16 siblings, 0 replies; 25+ messages in thread
From: Al Viro @ 2025-06-13  7:34 UTC (permalink / raw)
  To: linux-fsdevel; +Cc: chuck.lever, jlayton, linux-nfs, neil, torvalds, trondmy

Don't try to hold directories locked more than VFS requires;
lock just before getting a child to be made positive (using
simple_start_creating()) and unlock as soon as the child is
created.  There's no benefit in keeping the parent locked
while populating the child - it won't stop dcache lookups anyway.

Signed-off-by: Al Viro <viro@zeniv.linux.org.uk>
---
 net/sunrpc/rpc_pipe.c | 44 +++++++++----------------------------------
 1 file changed, 9 insertions(+), 35 deletions(-)

diff --git a/net/sunrpc/rpc_pipe.c b/net/sunrpc/rpc_pipe.c
index dac1c35a642f..a61c1173738c 100644
--- a/net/sunrpc/rpc_pipe.c
+++ b/net/sunrpc/rpc_pipe.c
@@ -594,22 +594,6 @@ static int __rpc_mkpipe_dentry(struct inode *dir, struct dentry *dentry,
 	return 0;
 }
 
-static struct dentry *__rpc_lookup_create_exclusive(struct dentry *parent,
-					  const char *name)
-{
-	struct qstr q = QSTR(name);
-	struct dentry *dentry = try_lookup_noperm(&q, parent);
-	if (!dentry) {
-		dentry = d_alloc(parent, &q);
-		if (!dentry)
-			return ERR_PTR(-ENOMEM);
-	}
-	if (d_really_is_negative(dentry))
-		return dentry;
-	dput(dentry);
-	return ERR_PTR(-EEXIST);
-}
-
 static int rpc_populate(struct dentry *parent,
 			const struct rpc_filelist *files,
 			int start, int eof,
@@ -619,9 +603,8 @@ static int rpc_populate(struct dentry *parent,
 	struct dentry *dentry;
 	int i, err;
 
-	inode_lock(dir);
 	for (i = start; i < eof; i++) {
-		dentry = __rpc_lookup_create_exclusive(parent, files[i].name);
+		dentry = simple_start_creating(parent, files[i].name);
 		err = PTR_ERR(dentry);
 		if (IS_ERR(dentry))
 			goto out_bad;
@@ -633,20 +616,20 @@ static int rpc_populate(struct dentry *parent,
 						files[i].mode,
 						files[i].i_fop,
 						private);
+				inode_unlock(dir);
 				break;
 			case S_IFDIR:
 				err = __rpc_mkdir(dir, dentry,
 						files[i].mode,
 						NULL,
 						private);
+				inode_unlock(dir);
 		}
 		if (err != 0)
 			goto out_bad;
 	}
-	inode_unlock(dir);
 	return 0;
 out_bad:
-	inode_unlock(dir);
 	printk(KERN_WARNING "%s: %s failed to populate directory %pd\n",
 			__FILE__, __func__, parent);
 	return err;
@@ -660,27 +643,21 @@ static struct dentry *rpc_mkdir_populate(struct dentry *parent,
 	struct inode *dir = d_inode(parent);
 	int error;
 
-	inode_lock_nested(dir, I_MUTEX_PARENT);
-	dentry = __rpc_lookup_create_exclusive(parent, name);
+	dentry = simple_start_creating(parent, name);
 	if (IS_ERR(dentry))
-		goto out;
+		return dentry;
 	error = __rpc_mkdir(dir, dentry, mode, NULL, private);
+	inode_unlock(dir);
 	if (error != 0)
-		goto out_err;
+		return ERR_PTR(error);
 	if (populate != NULL) {
 		error = populate(dentry, args_populate);
 		if (error) {
-			inode_unlock(dir);
 			simple_recursive_removal(dentry, NULL);
 			return ERR_PTR(error);
 		}
 	}
-out:
-	inode_unlock(dir);
 	return dentry;
-out_err:
-	dentry = ERR_PTR(error);
-	goto out;
 }
 
 /**
@@ -715,12 +692,9 @@ int rpc_mkpipe_dentry(struct dentry *parent, const char *name,
 	if (pipe->ops->downcall == NULL)
 		umode &= ~0222;
 
-	inode_lock_nested(dir, I_MUTEX_PARENT);
-	dentry = __rpc_lookup_create_exclusive(parent, name);
-	if (IS_ERR(dentry)) {
-		inode_unlock(dir);
+	dentry = simple_start_creating(parent, name);
+	if (IS_ERR(dentry))
 		return PTR_ERR(dentry);
-	}
 	err = __rpc_mkpipe_dentry(dir, dentry, umode, &rpc_pipe_fops,
 				  private, pipe);
 	if (unlikely(err))
-- 
2.39.5


^ permalink raw reply related	[flat|nested] 25+ messages in thread

* [PATCH 10/17] rpc_pipe: saner primitive for creating subdirectories
  2025-06-13  7:34 ` [PATCH 01/17] simple_recursive_removal(): saner interaction with fsnotify Al Viro
                     ` (7 preceding siblings ...)
  2025-06-13  7:34   ` [PATCH 09/17] rpc_pipe: don't overdo directory locking Al Viro
@ 2025-06-13  7:34   ` Al Viro
  2025-06-13  7:34   ` [PATCH 11/17] rpc_pipe: saner primitive for creating regular files Al Viro
                     ` (7 subsequent siblings)
  16 siblings, 0 replies; 25+ messages in thread
From: Al Viro @ 2025-06-13  7:34 UTC (permalink / raw)
  To: linux-fsdevel; +Cc: chuck.lever, jlayton, linux-nfs, neil, torvalds, trondmy

All users of __rpc_mkdir() have the same form - start_creating(),
followed, in case of success, by __rpc_mkdir() and unlocking parent.

Combine that into a single helper, expanding __rpc_mkdir() into it,
along with the call of __rpc_create_common() in it.

Don't mess with d_drop() + d_add() - just d_instantiate() and be
done with that.  The reason __rpc_create_common() goes for that
dance is that dentry it gets might or might not be hashed; here
we know it's hashed.

Signed-off-by: Al Viro <viro@zeniv.linux.org.uk>
---
 net/sunrpc/rpc_pipe.c | 67 +++++++++++++++++++++++++------------------
 1 file changed, 39 insertions(+), 28 deletions(-)

diff --git a/net/sunrpc/rpc_pipe.c b/net/sunrpc/rpc_pipe.c
index a61c1173738c..c3f269aadcaf 100644
--- a/net/sunrpc/rpc_pipe.c
+++ b/net/sunrpc/rpc_pipe.c
@@ -524,21 +524,6 @@ static int __rpc_create(struct inode *dir, struct dentry *dentry,
 	return 0;
 }
 
-static int __rpc_mkdir(struct inode *dir, struct dentry *dentry,
-		       umode_t mode,
-		       const struct file_operations *i_fop,
-		       void *private)
-{
-	int err;
-
-	err = __rpc_create_common(dir, dentry, S_IFDIR | mode, i_fop, private);
-	if (err)
-		return err;
-	inc_nlink(dir);
-	fsnotify_mkdir(dir, dentry);
-	return 0;
-}
-
 static void
 init_pipe(struct rpc_pipe *pipe)
 {
@@ -594,6 +579,35 @@ static int __rpc_mkpipe_dentry(struct inode *dir, struct dentry *dentry,
 	return 0;
 }
 
+static struct dentry *rpc_new_dir(struct dentry *parent,
+				  const char *name,
+				  umode_t mode,
+				  void *private)
+{
+	struct dentry *dentry = simple_start_creating(parent, name);
+	struct inode *dir = parent->d_inode;
+	struct inode *inode;
+
+	if (IS_ERR(dentry))
+		return dentry;
+
+	inode = rpc_get_inode(dir->i_sb, S_IFDIR | mode);
+	if (unlikely(!inode)) {
+		dput(dentry);
+		inode_unlock(dir);
+		return ERR_PTR(-ENOMEM);
+	}
+
+	inode->i_ino = iunique(dir->i_sb, 100);
+	rpc_inode_setowner(inode, private);
+	inc_nlink(dir);
+	d_instantiate(dentry, inode);
+	fsnotify_mkdir(dir, dentry);
+	inode_unlock(dir);
+
+	return dentry;
+}
+
 static int rpc_populate(struct dentry *parent,
 			const struct rpc_filelist *files,
 			int start, int eof,
@@ -604,14 +618,14 @@ static int rpc_populate(struct dentry *parent,
 	int i, err;
 
 	for (i = start; i < eof; i++) {
-		dentry = simple_start_creating(parent, files[i].name);
-		err = PTR_ERR(dentry);
-		if (IS_ERR(dentry))
-			goto out_bad;
 		switch (files[i].mode & S_IFMT) {
 			default:
 				BUG();
 			case S_IFREG:
+				dentry = simple_start_creating(parent, files[i].name);
+				err = PTR_ERR(dentry);
+				if (IS_ERR(dentry))
+					goto out_bad;
 				err = __rpc_create(dir, dentry,
 						files[i].mode,
 						files[i].i_fop,
@@ -619,11 +633,13 @@ static int rpc_populate(struct dentry *parent,
 				inode_unlock(dir);
 				break;
 			case S_IFDIR:
-				err = __rpc_mkdir(dir, dentry,
+				dentry = rpc_new_dir(parent,
+						files[i].name,
 						files[i].mode,
-						NULL,
 						private);
-				inode_unlock(dir);
+				err = PTR_ERR(dentry);
+				if (IS_ERR(dentry))
+					goto out_bad;
 		}
 		if (err != 0)
 			goto out_bad;
@@ -640,16 +656,11 @@ static struct dentry *rpc_mkdir_populate(struct dentry *parent,
 		int (*populate)(struct dentry *, void *), void *args_populate)
 {
 	struct dentry *dentry;
-	struct inode *dir = d_inode(parent);
 	int error;
 
-	dentry = simple_start_creating(parent, name);
+	dentry = rpc_new_dir(parent, name, mode, private);
 	if (IS_ERR(dentry))
 		return dentry;
-	error = __rpc_mkdir(dir, dentry, mode, NULL, private);
-	inode_unlock(dir);
-	if (error != 0)
-		return ERR_PTR(error);
 	if (populate != NULL) {
 		error = populate(dentry, args_populate);
 		if (error) {
-- 
2.39.5


^ permalink raw reply related	[flat|nested] 25+ messages in thread

* [PATCH 11/17] rpc_pipe: saner primitive for creating regular files
  2025-06-13  7:34 ` [PATCH 01/17] simple_recursive_removal(): saner interaction with fsnotify Al Viro
                     ` (8 preceding siblings ...)
  2025-06-13  7:34   ` [PATCH 10/17] rpc_pipe: saner primitive for creating subdirectories Al Viro
@ 2025-06-13  7:34   ` Al Viro
  2025-06-13  7:34   ` [PATCH 12/17] rpc_mkpipe_dentry(): switch to start_creating() Al Viro
                     ` (6 subsequent siblings)
  16 siblings, 0 replies; 25+ messages in thread
From: Al Viro @ 2025-06-13  7:34 UTC (permalink / raw)
  To: linux-fsdevel; +Cc: chuck.lever, jlayton, linux-nfs, neil, torvalds, trondmy

rpc_new_file(); similar to rpc_new_dir(), except that here we pass
file_operations as well.  Callers don't care about dentry, just
return 0 or -E...

Signed-off-by: Al Viro <viro@zeniv.linux.org.uk>
---
 net/sunrpc/rpc_pipe.c | 61 +++++++++++++++++++++++++------------------
 1 file changed, 36 insertions(+), 25 deletions(-)

diff --git a/net/sunrpc/rpc_pipe.c b/net/sunrpc/rpc_pipe.c
index c3f269aadcaf..8f88c75c9b30 100644
--- a/net/sunrpc/rpc_pipe.c
+++ b/net/sunrpc/rpc_pipe.c
@@ -510,20 +510,6 @@ static int __rpc_create_common(struct inode *dir, struct dentry *dentry,
 	return -ENOMEM;
 }
 
-static int __rpc_create(struct inode *dir, struct dentry *dentry,
-			umode_t mode,
-			const struct file_operations *i_fop,
-			void *private)
-{
-	int err;
-
-	err = __rpc_create_common(dir, dentry, S_IFREG | mode, i_fop, private);
-	if (err)
-		return err;
-	fsnotify_create(dir, dentry);
-	return 0;
-}
-
 static void
 init_pipe(struct rpc_pipe *pipe)
 {
@@ -579,6 +565,35 @@ static int __rpc_mkpipe_dentry(struct inode *dir, struct dentry *dentry,
 	return 0;
 }
 
+static int rpc_new_file(struct dentry *parent,
+			   const char *name,
+			   umode_t mode,
+			   const struct file_operations *i_fop,
+			   void *private)
+{
+	struct dentry *dentry = simple_start_creating(parent, name);
+	struct inode *dir = parent->d_inode;
+	struct inode *inode;
+
+	if (IS_ERR(dentry))
+		return PTR_ERR(dentry);
+
+	inode = rpc_get_inode(dir->i_sb, S_IFREG | mode);
+	if (unlikely(!inode)) {
+		dput(dentry);
+		inode_unlock(dir);
+		return -ENOMEM;
+	}
+	inode->i_ino = iunique(dir->i_sb, 100);
+	if (i_fop)
+		inode->i_fop = i_fop;
+	rpc_inode_setowner(inode, private);
+	d_instantiate(dentry, inode);
+	fsnotify_create(dir, dentry);
+	inode_unlock(dir);
+	return 0;
+}
+
 static struct dentry *rpc_new_dir(struct dentry *parent,
 				  const char *name,
 				  umode_t mode,
@@ -613,7 +628,6 @@ static int rpc_populate(struct dentry *parent,
 			int start, int eof,
 			void *private)
 {
-	struct inode *dir = d_inode(parent);
 	struct dentry *dentry;
 	int i, err;
 
@@ -622,27 +636,24 @@ static int rpc_populate(struct dentry *parent,
 			default:
 				BUG();
 			case S_IFREG:
-				dentry = simple_start_creating(parent, files[i].name);
-				err = PTR_ERR(dentry);
-				if (IS_ERR(dentry))
-					goto out_bad;
-				err = __rpc_create(dir, dentry,
+				err = rpc_new_file(parent,
+						files[i].name,
 						files[i].mode,
 						files[i].i_fop,
 						private);
-				inode_unlock(dir);
+				if (err)
+					goto out_bad;
 				break;
 			case S_IFDIR:
 				dentry = rpc_new_dir(parent,
 						files[i].name,
 						files[i].mode,
 						private);
-				err = PTR_ERR(dentry);
-				if (IS_ERR(dentry))
+				if (IS_ERR(dentry)) {
+					err = PTR_ERR(dentry);
 					goto out_bad;
+				}
 		}
-		if (err != 0)
-			goto out_bad;
 	}
 	return 0;
 out_bad:
-- 
2.39.5


^ permalink raw reply related	[flat|nested] 25+ messages in thread

* [PATCH 12/17] rpc_mkpipe_dentry(): switch to start_creating()
  2025-06-13  7:34 ` [PATCH 01/17] simple_recursive_removal(): saner interaction with fsnotify Al Viro
                     ` (9 preceding siblings ...)
  2025-06-13  7:34   ` [PATCH 11/17] rpc_pipe: saner primitive for creating regular files Al Viro
@ 2025-06-13  7:34   ` Al Viro
  2025-06-13 19:27     ` Jeff Layton
  2025-06-13  7:34   ` [PATCH 13/17] rpc_gssd_dummy_populate(): don't bother with rpc_populate() Al Viro
                     ` (5 subsequent siblings)
  16 siblings, 1 reply; 25+ messages in thread
From: Al Viro @ 2025-06-13  7:34 UTC (permalink / raw)
  To: linux-fsdevel; +Cc: chuck.lever, jlayton, linux-nfs, neil, torvalds, trondmy

... and make sure we set the rpc_pipe-private part of inode up before
attaching it to dentry.

Signed-off-by: Al Viro <viro@zeniv.linux.org.uk>
---
 net/sunrpc/rpc_pipe.c | 83 +++++++++++++++----------------------------
 1 file changed, 29 insertions(+), 54 deletions(-)

diff --git a/net/sunrpc/rpc_pipe.c b/net/sunrpc/rpc_pipe.c
index 8f88c75c9b30..a52fe3bbf9dc 100644
--- a/net/sunrpc/rpc_pipe.c
+++ b/net/sunrpc/rpc_pipe.c
@@ -485,31 +485,6 @@ rpc_get_inode(struct super_block *sb, umode_t mode)
 	return inode;
 }
 
-static int __rpc_create_common(struct inode *dir, struct dentry *dentry,
-			       umode_t mode,
-			       const struct file_operations *i_fop,
-			       void *private)
-{
-	struct inode *inode;
-
-	d_drop(dentry);
-	inode = rpc_get_inode(dir->i_sb, mode);
-	if (!inode)
-		goto out_err;
-	inode->i_ino = iunique(dir->i_sb, 100);
-	if (i_fop)
-		inode->i_fop = i_fop;
-	if (private)
-		rpc_inode_setowner(inode, private);
-	d_add(dentry, inode);
-	return 0;
-out_err:
-	printk(KERN_WARNING "%s: %s failed to allocate inode for dentry %pd\n",
-			__FILE__, __func__, dentry);
-	dput(dentry);
-	return -ENOMEM;
-}
-
 static void
 init_pipe(struct rpc_pipe *pipe)
 {
@@ -546,25 +521,6 @@ struct rpc_pipe *rpc_mkpipe_data(const struct rpc_pipe_ops *ops, int flags)
 }
 EXPORT_SYMBOL_GPL(rpc_mkpipe_data);
 
-static int __rpc_mkpipe_dentry(struct inode *dir, struct dentry *dentry,
-			       umode_t mode,
-			       const struct file_operations *i_fop,
-			       void *private,
-			       struct rpc_pipe *pipe)
-{
-	struct rpc_inode *rpci;
-	int err;
-
-	err = __rpc_create_common(dir, dentry, S_IFIFO | mode, i_fop, private);
-	if (err)
-		return err;
-	rpci = RPC_I(d_inode(dentry));
-	rpci->private = private;
-	rpci->pipe = pipe;
-	fsnotify_create(dir, dentry);
-	return 0;
-}
-
 static int rpc_new_file(struct dentry *parent,
 			   const char *name,
 			   umode_t mode,
@@ -704,8 +660,10 @@ static struct dentry *rpc_mkdir_populate(struct dentry *parent,
 int rpc_mkpipe_dentry(struct dentry *parent, const char *name,
 				 void *private, struct rpc_pipe *pipe)
 {
-	struct dentry *dentry;
 	struct inode *dir = d_inode(parent);
+	struct dentry *dentry;
+	struct inode *inode;
+	struct rpc_inode *rpci;
 	umode_t umode = S_IFIFO | 0600;
 	int err;
 
@@ -715,16 +673,33 @@ int rpc_mkpipe_dentry(struct dentry *parent, const char *name,
 		umode &= ~0222;
 
 	dentry = simple_start_creating(parent, name);
-	if (IS_ERR(dentry))
-		return PTR_ERR(dentry);
-	err = __rpc_mkpipe_dentry(dir, dentry, umode, &rpc_pipe_fops,
-				  private, pipe);
-	if (unlikely(err))
-		pr_warn("%s() failed to create pipe %pd/%s (errno = %d)\n",
-			__func__, parent, name, err);
-	else
-		pipe->dentry = dentry;
+	if (IS_ERR(dentry)) {
+		err = PTR_ERR(dentry);
+		goto failed;
+	}
+
+	inode = rpc_get_inode(dir->i_sb, umode);
+	if (unlikely(!inode)) {
+		dput(dentry);
+		inode_unlock(dir);
+		err = -ENOMEM;
+		goto failed;
+	}
+	inode->i_ino = iunique(dir->i_sb, 100);
+	inode->i_fop = &rpc_pipe_fops;
+	rpci = RPC_I(inode);
+	rpci->private = private;
+	rpci->pipe = pipe;
+	rpc_inode_setowner(inode, private);
+	d_instantiate(dentry, inode);
+	pipe->dentry = dentry;
+	fsnotify_create(dir, dentry);
 	inode_unlock(dir);
+	return 0;
+
+failed:
+	pr_warn("%s() failed to create pipe %pd/%s (errno = %d)\n",
+			__func__, parent, name, err);
 	return err;
 }
 EXPORT_SYMBOL_GPL(rpc_mkpipe_dentry);
-- 
2.39.5


^ permalink raw reply related	[flat|nested] 25+ messages in thread

* [PATCH 13/17] rpc_gssd_dummy_populate(): don't bother with rpc_populate()
  2025-06-13  7:34 ` [PATCH 01/17] simple_recursive_removal(): saner interaction with fsnotify Al Viro
                     ` (10 preceding siblings ...)
  2025-06-13  7:34   ` [PATCH 12/17] rpc_mkpipe_dentry(): switch to start_creating() Al Viro
@ 2025-06-13  7:34   ` Al Viro
  2025-06-13  7:34   ` [PATCH 14/17] rpc_pipe: expand the calls of rpc_mkdir_populate() Al Viro
                     ` (4 subsequent siblings)
  16 siblings, 0 replies; 25+ messages in thread
From: Al Viro @ 2025-06-13  7:34 UTC (permalink / raw)
  To: linux-fsdevel; +Cc: chuck.lever, jlayton, linux-nfs, neil, torvalds, trondmy

Just have it create gssd (in root), clntXX in gssd, then info and gssd in clntXX
- all with explicit rpc_new_dir()/rpc_new_file()/rpc_mkpipe_dentry().

Signed-off-by: Al Viro <viro@zeniv.linux.org.uk>
---
 net/sunrpc/rpc_pipe.c | 55 +++++++++----------------------------------
 1 file changed, 11 insertions(+), 44 deletions(-)

diff --git a/net/sunrpc/rpc_pipe.c b/net/sunrpc/rpc_pipe.c
index a52fe3bbf9dc..9051842228ec 100644
--- a/net/sunrpc/rpc_pipe.c
+++ b/net/sunrpc/rpc_pipe.c
@@ -997,7 +997,6 @@ enum {
 	RPCAUTH_nfsd4_cb,
 	RPCAUTH_cache,
 	RPCAUTH_nfsd,
-	RPCAUTH_gssd,
 	RPCAUTH_RootEOF
 };
 
@@ -1034,10 +1033,6 @@ static const struct rpc_filelist files[] = {
 		.name = "nfsd",
 		.mode = S_IFDIR | 0555,
 	},
-	[RPCAUTH_gssd] = {
-		.name = "gssd",
-		.mode = S_IFDIR | 0555,
-	},
 };
 
 /*
@@ -1097,13 +1092,6 @@ void rpc_put_sb_net(const struct net *net)
 }
 EXPORT_SYMBOL_GPL(rpc_put_sb_net);
 
-static const struct rpc_filelist gssd_dummy_clnt_dir[] = {
-	[0] = {
-		.name = "clntXX",
-		.mode = S_IFDIR | 0555,
-	},
-};
-
 static ssize_t
 dummy_downcall(struct file *filp, const char __user *src, size_t len)
 {
@@ -1132,14 +1120,6 @@ rpc_dummy_info_show(struct seq_file *m, void *v)
 }
 DEFINE_SHOW_ATTRIBUTE(rpc_dummy_info);
 
-static const struct rpc_filelist gssd_dummy_info_file[] = {
-	[0] = {
-		.name = "info",
-		.i_fop = &rpc_dummy_info_fops,
-		.mode = S_IFREG | 0400,
-	},
-};
-
 /**
  * rpc_gssd_dummy_populate - create a dummy gssd pipe
  * @root:	root of the rpc_pipefs filesystem
@@ -1151,35 +1131,22 @@ static const struct rpc_filelist gssd_dummy_info_file[] = {
 static int
 rpc_gssd_dummy_populate(struct dentry *root, struct rpc_pipe *pipe_data)
 {
-	int ret = 0;
-	struct dentry *gssd_dentry;
-	struct dentry *clnt_dentry = NULL;
+	struct dentry *gssd_dentry, *clnt_dentry;
+	int err;
 
-	/* We should never get this far if "gssd" doesn't exist */
-	gssd_dentry = try_lookup_noperm(&QSTR(files[RPCAUTH_gssd].name), root);
-	if (!gssd_dentry)
+	gssd_dentry = rpc_new_dir(root, "gssd", 0555, NULL);
+	if (IS_ERR(gssd_dentry))
 		return -ENOENT;
 
-	ret = rpc_populate(gssd_dentry, gssd_dummy_clnt_dir, 0, 1, NULL);
-	if (ret) {
-		dput(gssd_dentry);
-		return ret;
-	}
-
-	clnt_dentry = try_lookup_noperm(&QSTR(gssd_dummy_clnt_dir[0].name),
-					  gssd_dentry);
-	dput(gssd_dentry);
-	if (!clnt_dentry)
+	clnt_dentry = rpc_new_dir(gssd_dentry, "clntXX", 0555, NULL);
+	if (IS_ERR(clnt_dentry))
 		return -ENOENT;
 
-	ret = rpc_populate(clnt_dentry, gssd_dummy_info_file, 0, 1, NULL);
-	if (ret) {
-		dput(clnt_dentry);
-		return ret;
-	}
-	ret = rpc_mkpipe_dentry(clnt_dentry, "gssd", NULL, pipe_data);
-	dput(clnt_dentry);
-	return ret;
+	err = rpc_new_file(clnt_dentry, "info", 0400,
+				   &rpc_dummy_info_fops, NULL);
+	if (!err)
+		err = rpc_mkpipe_dentry(clnt_dentry, "gssd", NULL, pipe_data);
+	return err;
 }
 
 static int
-- 
2.39.5


^ permalink raw reply related	[flat|nested] 25+ messages in thread

* [PATCH 14/17] rpc_pipe: expand the calls of rpc_mkdir_populate()
  2025-06-13  7:34 ` [PATCH 01/17] simple_recursive_removal(): saner interaction with fsnotify Al Viro
                     ` (11 preceding siblings ...)
  2025-06-13  7:34   ` [PATCH 13/17] rpc_gssd_dummy_populate(): don't bother with rpc_populate() Al Viro
@ 2025-06-13  7:34   ` Al Viro
  2025-06-13  7:34   ` [PATCH 15/17] rpc_new_dir(): the last argument is always NULL Al Viro
                     ` (3 subsequent siblings)
  16 siblings, 0 replies; 25+ messages in thread
From: Al Viro @ 2025-06-13  7:34 UTC (permalink / raw)
  To: linux-fsdevel; +Cc: chuck.lever, jlayton, linux-nfs, neil, torvalds, trondmy

... and get rid of convoluted callbacks.

Signed-off-by: Al Viro <viro@zeniv.linux.org.uk>
---
 net/sunrpc/rpc_pipe.c | 63 +++++++++++++++----------------------------
 1 file changed, 22 insertions(+), 41 deletions(-)

diff --git a/net/sunrpc/rpc_pipe.c b/net/sunrpc/rpc_pipe.c
index 9051842228ec..15ec770bb7fb 100644
--- a/net/sunrpc/rpc_pipe.c
+++ b/net/sunrpc/rpc_pipe.c
@@ -618,26 +618,6 @@ static int rpc_populate(struct dentry *parent,
 	return err;
 }
 
-static struct dentry *rpc_mkdir_populate(struct dentry *parent,
-		const char *name, umode_t mode, void *private,
-		int (*populate)(struct dentry *, void *), void *args_populate)
-{
-	struct dentry *dentry;
-	int error;
-
-	dentry = rpc_new_dir(parent, name, mode, private);
-	if (IS_ERR(dentry))
-		return dentry;
-	if (populate != NULL) {
-		error = populate(dentry, args_populate);
-		if (error) {
-			simple_recursive_removal(dentry, NULL);
-			return ERR_PTR(error);
-		}
-	}
-	return dentry;
-}
-
 /**
  * rpc_mkpipe_dentry - make an rpc_pipefs file for kernel<->userspace
  *		       communication
@@ -888,13 +868,6 @@ static const struct rpc_filelist authfiles[] = {
 	},
 };
 
-static int rpc_clntdir_populate(struct dentry *dentry, void *private)
-{
-	return rpc_populate(dentry,
-			    authfiles, RPCAUTH_info, RPCAUTH_EOF,
-			    private);
-}
-
 /**
  * rpc_create_client_dir - Create a new rpc_client directory in rpc_pipefs
  * @dentry: the parent of new directory
@@ -911,13 +884,19 @@ struct dentry *rpc_create_client_dir(struct dentry *dentry,
 				   struct rpc_clnt *rpc_client)
 {
 	struct dentry *ret;
+	int error;
 
-	ret = rpc_mkdir_populate(dentry, name, 0555, NULL,
-				 rpc_clntdir_populate, rpc_client);
-	if (!IS_ERR(ret)) {
-		rpc_client->cl_pipedir_objects.pdh_dentry = ret;
-		rpc_create_pipe_dir_objects(&rpc_client->cl_pipedir_objects);
+	ret = rpc_new_dir(dentry, name, 0555, NULL);
+	if (IS_ERR(ret))
+		return ret;
+	error = rpc_populate(ret, authfiles, RPCAUTH_info, RPCAUTH_EOF,
+		    rpc_client);
+	if (unlikely(error)) {
+		simple_recursive_removal(ret, NULL);
+		return ERR_PTR(error);
 	}
+	rpc_client->cl_pipedir_objects.pdh_dentry = ret;
+	rpc_create_pipe_dir_objects(&rpc_client->cl_pipedir_objects);
 	return ret;
 }
 
@@ -955,18 +934,20 @@ static const struct rpc_filelist cache_pipefs_files[3] = {
 	},
 };
 
-static int rpc_cachedir_populate(struct dentry *dentry, void *private)
-{
-	return rpc_populate(dentry,
-			    cache_pipefs_files, 0, 3,
-			    private);
-}
-
 struct dentry *rpc_create_cache_dir(struct dentry *parent, const char *name,
 				    umode_t umode, struct cache_detail *cd)
 {
-	return rpc_mkdir_populate(parent, name, umode, NULL,
-			rpc_cachedir_populate, cd);
+	struct dentry *dentry;
+
+	dentry = rpc_new_dir(parent, name, umode, NULL);
+	if (!IS_ERR(dentry)) {
+		int error = rpc_populate(dentry, cache_pipefs_files, 0, 3, cd);
+		if (error) {
+			simple_recursive_removal(dentry, NULL);
+			return ERR_PTR(error);
+		}
+	}
+	return dentry;
 }
 
 void rpc_remove_cache_dir(struct dentry *dentry)
-- 
2.39.5


^ permalink raw reply related	[flat|nested] 25+ messages in thread

* [PATCH 15/17] rpc_new_dir(): the last argument is always NULL
  2025-06-13  7:34 ` [PATCH 01/17] simple_recursive_removal(): saner interaction with fsnotify Al Viro
                     ` (12 preceding siblings ...)
  2025-06-13  7:34   ` [PATCH 14/17] rpc_pipe: expand the calls of rpc_mkdir_populate() Al Viro
@ 2025-06-13  7:34   ` Al Viro
  2025-06-13  7:34   ` [PATCH 16/17] rpc_create_client_dir(): don't bother with rpc_populate() Al Viro
                     ` (2 subsequent siblings)
  16 siblings, 0 replies; 25+ messages in thread
From: Al Viro @ 2025-06-13  7:34 UTC (permalink / raw)
  To: linux-fsdevel; +Cc: chuck.lever, jlayton, linux-nfs, neil, torvalds, trondmy

All callers except the one in rpc_populate() pass explicit NULL
there; rpc_populate() passes its last argument ('private') instead,
but in the only call of rpc_populate() that creates any subdirectories
(when creating fixed subdirectories of root) private itself is NULL.

Signed-off-by: Al Viro <viro@zeniv.linux.org.uk>
---
 net/sunrpc/rpc_pipe.c | 15 ++++++---------
 1 file changed, 6 insertions(+), 9 deletions(-)

diff --git a/net/sunrpc/rpc_pipe.c b/net/sunrpc/rpc_pipe.c
index 15ec770bb7fb..c14425d2d0d3 100644
--- a/net/sunrpc/rpc_pipe.c
+++ b/net/sunrpc/rpc_pipe.c
@@ -552,8 +552,7 @@ static int rpc_new_file(struct dentry *parent,
 
 static struct dentry *rpc_new_dir(struct dentry *parent,
 				  const char *name,
-				  umode_t mode,
-				  void *private)
+				  umode_t mode)
 {
 	struct dentry *dentry = simple_start_creating(parent, name);
 	struct inode *dir = parent->d_inode;
@@ -570,7 +569,6 @@ static struct dentry *rpc_new_dir(struct dentry *parent,
 	}
 
 	inode->i_ino = iunique(dir->i_sb, 100);
-	rpc_inode_setowner(inode, private);
 	inc_nlink(dir);
 	d_instantiate(dentry, inode);
 	fsnotify_mkdir(dir, dentry);
@@ -603,8 +601,7 @@ static int rpc_populate(struct dentry *parent,
 			case S_IFDIR:
 				dentry = rpc_new_dir(parent,
 						files[i].name,
-						files[i].mode,
-						private);
+						files[i].mode);
 				if (IS_ERR(dentry)) {
 					err = PTR_ERR(dentry);
 					goto out_bad;
@@ -886,7 +883,7 @@ struct dentry *rpc_create_client_dir(struct dentry *dentry,
 	struct dentry *ret;
 	int error;
 
-	ret = rpc_new_dir(dentry, name, 0555, NULL);
+	ret = rpc_new_dir(dentry, name, 0555);
 	if (IS_ERR(ret))
 		return ret;
 	error = rpc_populate(ret, authfiles, RPCAUTH_info, RPCAUTH_EOF,
@@ -939,7 +936,7 @@ struct dentry *rpc_create_cache_dir(struct dentry *parent, const char *name,
 {
 	struct dentry *dentry;
 
-	dentry = rpc_new_dir(parent, name, umode, NULL);
+	dentry = rpc_new_dir(parent, name, umode);
 	if (!IS_ERR(dentry)) {
 		int error = rpc_populate(dentry, cache_pipefs_files, 0, 3, cd);
 		if (error) {
@@ -1115,11 +1112,11 @@ rpc_gssd_dummy_populate(struct dentry *root, struct rpc_pipe *pipe_data)
 	struct dentry *gssd_dentry, *clnt_dentry;
 	int err;
 
-	gssd_dentry = rpc_new_dir(root, "gssd", 0555, NULL);
+	gssd_dentry = rpc_new_dir(root, "gssd", 0555);
 	if (IS_ERR(gssd_dentry))
 		return -ENOENT;
 
-	clnt_dentry = rpc_new_dir(gssd_dentry, "clntXX", 0555, NULL);
+	clnt_dentry = rpc_new_dir(gssd_dentry, "clntXX", 0555);
 	if (IS_ERR(clnt_dentry))
 		return -ENOENT;
 
-- 
2.39.5


^ permalink raw reply related	[flat|nested] 25+ messages in thread

* [PATCH 16/17] rpc_create_client_dir(): don't bother with rpc_populate()
  2025-06-13  7:34 ` [PATCH 01/17] simple_recursive_removal(): saner interaction with fsnotify Al Viro
                     ` (13 preceding siblings ...)
  2025-06-13  7:34   ` [PATCH 15/17] rpc_new_dir(): the last argument is always NULL Al Viro
@ 2025-06-13  7:34   ` Al Viro
  2025-06-13  7:34   ` [PATCH 17/17] rpc_create_client_dir(): return 0 or -E Al Viro
  2025-06-13  8:19   ` [PATCH 01/17] simple_recursive_removal(): saner interaction with fsnotify Amir Goldstein
  16 siblings, 0 replies; 25+ messages in thread
From: Al Viro @ 2025-06-13  7:34 UTC (permalink / raw)
  To: linux-fsdevel; +Cc: chuck.lever, jlayton, linux-nfs, neil, torvalds, trondmy

not for a single file...

Signed-off-by: Al Viro <viro@zeniv.linux.org.uk>
---
 net/sunrpc/rpc_pipe.c | 25 +++++++------------------
 1 file changed, 7 insertions(+), 18 deletions(-)

diff --git a/net/sunrpc/rpc_pipe.c b/net/sunrpc/rpc_pipe.c
index c14425d2d0d3..e4b53530eb1b 100644
--- a/net/sunrpc/rpc_pipe.c
+++ b/net/sunrpc/rpc_pipe.c
@@ -852,19 +852,6 @@ rpc_destroy_pipe_dir_objects(struct rpc_pipe_dir_head *pdh)
 		pdo->pdo_ops->destroy(dir, pdo);
 }
 
-enum {
-	RPCAUTH_info,
-	RPCAUTH_EOF
-};
-
-static const struct rpc_filelist authfiles[] = {
-	[RPCAUTH_info] = {
-		.name = "info",
-		.i_fop = &rpc_info_operations,
-		.mode = S_IFREG | 0400,
-	},
-};
-
 /**
  * rpc_create_client_dir - Create a new rpc_client directory in rpc_pipefs
  * @dentry: the parent of new directory
@@ -881,16 +868,18 @@ struct dentry *rpc_create_client_dir(struct dentry *dentry,
 				   struct rpc_clnt *rpc_client)
 {
 	struct dentry *ret;
-	int error;
+	int err;
 
 	ret = rpc_new_dir(dentry, name, 0555);
 	if (IS_ERR(ret))
 		return ret;
-	error = rpc_populate(ret, authfiles, RPCAUTH_info, RPCAUTH_EOF,
-		    rpc_client);
-	if (unlikely(error)) {
+	err = rpc_new_file(ret, "info", S_IFREG | 0400,
+			      &rpc_info_operations, rpc_client);
+	if (err) {
+		pr_warn("%s failed to populate directory %pd\n",
+				__func__, ret);
 		simple_recursive_removal(ret, NULL);
-		return ERR_PTR(error);
+		return ERR_PTR(err);
 	}
 	rpc_client->cl_pipedir_objects.pdh_dentry = ret;
 	rpc_create_pipe_dir_objects(&rpc_client->cl_pipedir_objects);
-- 
2.39.5


^ permalink raw reply related	[flat|nested] 25+ messages in thread

* [PATCH 17/17] rpc_create_client_dir(): return 0 or -E...
  2025-06-13  7:34 ` [PATCH 01/17] simple_recursive_removal(): saner interaction with fsnotify Al Viro
                     ` (14 preceding siblings ...)
  2025-06-13  7:34   ` [PATCH 16/17] rpc_create_client_dir(): don't bother with rpc_populate() Al Viro
@ 2025-06-13  7:34   ` Al Viro
  2025-06-13  8:19   ` [PATCH 01/17] simple_recursive_removal(): saner interaction with fsnotify Amir Goldstein
  16 siblings, 0 replies; 25+ messages in thread
From: Al Viro @ 2025-06-13  7:34 UTC (permalink / raw)
  To: linux-fsdevel; +Cc: chuck.lever, jlayton, linux-nfs, neil, torvalds, trondmy

Callers couldn't care less which dentry did we get - anything
valid is treated as success.

Signed-off-by: Al Viro <viro@zeniv.linux.org.uk>
---
 include/linux/sunrpc/rpc_pipe_fs.h |  2 +-
 net/sunrpc/clnt.c                  | 36 ++++++++++++------------------
 net/sunrpc/rpc_pipe.c              | 12 +++++-----
 3 files changed, 21 insertions(+), 29 deletions(-)

diff --git a/include/linux/sunrpc/rpc_pipe_fs.h b/include/linux/sunrpc/rpc_pipe_fs.h
index 8cc3a5df9801..2cb406f8ff4e 100644
--- a/include/linux/sunrpc/rpc_pipe_fs.h
+++ b/include/linux/sunrpc/rpc_pipe_fs.h
@@ -98,7 +98,7 @@ static inline bool rpc_msg_is_inflight(const struct rpc_pipe_msg *msg) {
 }
 
 struct rpc_clnt;
-extern struct dentry *rpc_create_client_dir(struct dentry *, const char *, struct rpc_clnt *);
+extern int rpc_create_client_dir(struct dentry *, const char *, struct rpc_clnt *);
 extern int rpc_remove_client_dir(struct rpc_clnt *);
 
 extern void rpc_init_pipe_dir_head(struct rpc_pipe_dir_head *pdh);
diff --git a/net/sunrpc/clnt.c b/net/sunrpc/clnt.c
index 21426c3049d3..8ca354ecfd02 100644
--- a/net/sunrpc/clnt.c
+++ b/net/sunrpc/clnt.c
@@ -112,47 +112,46 @@ static void rpc_clnt_remove_pipedir(struct rpc_clnt *clnt)
 	}
 }
 
-static struct dentry *rpc_setup_pipedir_sb(struct super_block *sb,
+static int rpc_setup_pipedir_sb(struct super_block *sb,
 				    struct rpc_clnt *clnt)
 {
 	static uint32_t clntid;
 	const char *dir_name = clnt->cl_program->pipe_dir_name;
 	char name[15];
-	struct dentry *dir, *dentry;
+	struct dentry *dir;
+	int err;
 
 	dir = rpc_d_lookup_sb(sb, dir_name);
 	if (dir == NULL) {
 		pr_info("RPC: pipefs directory doesn't exist: %s\n", dir_name);
-		return dir;
+		return -ENOENT;
 	}
 	for (;;) {
 		snprintf(name, sizeof(name), "clnt%x", (unsigned int)clntid++);
 		name[sizeof(name) - 1] = '\0';
-		dentry = rpc_create_client_dir(dir, name, clnt);
-		if (!IS_ERR(dentry))
+		err = rpc_create_client_dir(dir, name, clnt);
+		if (!err)
 			break;
-		if (dentry == ERR_PTR(-EEXIST))
+		if (err == -EEXIST)
 			continue;
 		printk(KERN_INFO "RPC: Couldn't create pipefs entry"
-				" %s/%s, error %ld\n",
-				dir_name, name, PTR_ERR(dentry));
+				" %s/%s, error %d\n",
+				dir_name, name, err);
 		break;
 	}
 	dput(dir);
-	return dentry;
+	return err;
 }
 
 static int
 rpc_setup_pipedir(struct super_block *pipefs_sb, struct rpc_clnt *clnt)
 {
-	struct dentry *dentry;
-
 	clnt->pipefs_sb = pipefs_sb;
 
 	if (clnt->cl_program->pipe_dir_name != NULL) {
-		dentry = rpc_setup_pipedir_sb(pipefs_sb, clnt);
-		if (IS_ERR(dentry))
-			return PTR_ERR(dentry);
+		int err = rpc_setup_pipedir_sb(pipefs_sb, clnt);
+		if (err && err != -ENOENT)
+			return err;
 	}
 	return 0;
 }
@@ -180,16 +179,9 @@ static int rpc_clnt_skip_event(struct rpc_clnt *clnt, unsigned long event)
 static int __rpc_clnt_handle_event(struct rpc_clnt *clnt, unsigned long event,
 				   struct super_block *sb)
 {
-	struct dentry *dentry;
-
 	switch (event) {
 	case RPC_PIPEFS_MOUNT:
-		dentry = rpc_setup_pipedir_sb(sb, clnt);
-		if (!dentry)
-			return -ENOENT;
-		if (IS_ERR(dentry))
-			return PTR_ERR(dentry);
-		break;
+		return rpc_setup_pipedir_sb(sb, clnt);
 	case RPC_PIPEFS_UMOUNT:
 		__rpc_clnt_remove_pipedir(clnt);
 		break;
diff --git a/net/sunrpc/rpc_pipe.c b/net/sunrpc/rpc_pipe.c
index e4b53530eb1b..a12ec709c445 100644
--- a/net/sunrpc/rpc_pipe.c
+++ b/net/sunrpc/rpc_pipe.c
@@ -863,27 +863,27 @@ rpc_destroy_pipe_dir_objects(struct rpc_pipe_dir_head *pdh)
  * information about the client, together with any "pipes" that may
  * later be created using rpc_mkpipe().
  */
-struct dentry *rpc_create_client_dir(struct dentry *dentry,
-				   const char *name,
-				   struct rpc_clnt *rpc_client)
+int rpc_create_client_dir(struct dentry *dentry,
+			   const char *name,
+			   struct rpc_clnt *rpc_client)
 {
 	struct dentry *ret;
 	int err;
 
 	ret = rpc_new_dir(dentry, name, 0555);
 	if (IS_ERR(ret))
-		return ret;
+		return PTR_ERR(ret);
 	err = rpc_new_file(ret, "info", S_IFREG | 0400,
 			      &rpc_info_operations, rpc_client);
 	if (err) {
 		pr_warn("%s failed to populate directory %pd\n",
 				__func__, ret);
 		simple_recursive_removal(ret, NULL);
-		return ERR_PTR(err);
+		return err;
 	}
 	rpc_client->cl_pipedir_objects.pdh_dentry = ret;
 	rpc_create_pipe_dir_objects(&rpc_client->cl_pipedir_objects);
-	return ret;
+	return 0;
 }
 
 /**
-- 
2.39.5


^ permalink raw reply related	[flat|nested] 25+ messages in thread

* Re: [PATCH 01/17] simple_recursive_removal(): saner interaction with fsnotify
  2025-06-13  7:34 ` [PATCH 01/17] simple_recursive_removal(): saner interaction with fsnotify Al Viro
                     ` (15 preceding siblings ...)
  2025-06-13  7:34   ` [PATCH 17/17] rpc_create_client_dir(): return 0 or -E Al Viro
@ 2025-06-13  8:19   ` Amir Goldstein
  16 siblings, 0 replies; 25+ messages in thread
From: Amir Goldstein @ 2025-06-13  8:19 UTC (permalink / raw)
  To: Al Viro
  Cc: linux-fsdevel, chuck.lever, jlayton, linux-nfs, neil, torvalds,
	trondmy

On Fri, Jun 13, 2025 at 9:35 AM Al Viro <viro@zeniv.linux.org.uk> wrote:
>
> Make it match the real unlink(2)/rmdir(2) - notify *after* the
> operation.  And use fsnotify_delete() instead of messing with
> fsnotify_unlink()/fsnotify_rmdir().
>
> Currently the only caller that cares is the one in debugfs, and
> there the order matching the normal syscalls makes more sense;
> it'll get more serious for users introduced later in the series.
>
> Signed-off-by: Al Viro <viro@zeniv.linux.org.uk>

Makes sense.
Reviewed-by: Amir Goldstein <amir73il@gmail.com>

> ---
>  fs/libfs.c | 5 +----
>  1 file changed, 1 insertion(+), 4 deletions(-)
>
> diff --git a/fs/libfs.c b/fs/libfs.c
> index 9ea0ecc325a8..42e226af6095 100644
> --- a/fs/libfs.c
> +++ b/fs/libfs.c
> @@ -628,12 +628,9 @@ void simple_recursive_removal(struct dentry *dentry,
>                         inode_lock(inode);
>                         if (simple_positive(victim)) {
>                                 d_invalidate(victim);   // avoid lost mounts
> -                               if (d_is_dir(victim))
> -                                       fsnotify_rmdir(inode, victim);
> -                               else
> -                                       fsnotify_unlink(inode, victim);
>                                 if (callback)
>                                         callback(victim);
> +                               fsnotify_delete(inode, d_inode(victim), victim);
>                                 dput(victim);           // unpin it
>                         }
>                         if (victim == dentry) {
> --
> 2.39.5
>
>

^ permalink raw reply	[flat|nested] 25+ messages in thread

* Re: [PATCH 02/17] new helper: simple_start_creating()
  2025-06-13  7:34   ` [PATCH 02/17] new helper: simple_start_creating() Al Viro
@ 2025-06-13 18:31     ` Jeff Layton
  2025-06-13 22:36       ` Al Viro
  0 siblings, 1 reply; 25+ messages in thread
From: Jeff Layton @ 2025-06-13 18:31 UTC (permalink / raw)
  To: Al Viro, linux-fsdevel; +Cc: chuck.lever, linux-nfs, neil, torvalds, trondmy

On Fri, 2025-06-13 at 08:34 +0100, Al Viro wrote:
> Set the things up for kernel-initiated creation of object in
> a tree-in-dcache filesystem.  With respect to locking it's
> an equivalent of filename_create() - we either get a negative
> dentry with locked parent, or ERR_PTR() and no locks taken.
> 
> tracefs and debugfs had that open-coded as part of their
> object creation machinery; switched to calling new helper.
> 
> Signed-off-by: Al Viro <viro@zeniv.linux.org.uk>
> ---
>  fs/debugfs/inode.c | 21 ++-------------------
>  fs/libfs.c         | 25 +++++++++++++++++++++++++
>  fs/tracefs/inode.c | 15 ++-------------
>  include/linux/fs.h |  1 +
>  4 files changed, 30 insertions(+), 32 deletions(-)
> 
> diff --git a/fs/debugfs/inode.c b/fs/debugfs/inode.c
> index 30c4944e1862..08638e39bd12 100644
> --- a/fs/debugfs/inode.c
> +++ b/fs/debugfs/inode.c
> @@ -384,26 +384,9 @@ static struct dentry *start_creating(const char *name, struct dentry *parent)
>  	if (!parent)
>  		parent = debugfs_mount->mnt_root;
>  
> -	inode_lock(d_inode(parent));
> -	if (unlikely(IS_DEADDIR(d_inode(parent))))
> -		dentry = ERR_PTR(-ENOENT);
> -	else
> -		dentry = lookup_noperm(&QSTR(name), parent);
> -	if (!IS_ERR(dentry) && d_really_is_positive(dentry)) {
> -		if (d_is_dir(dentry))
> -			pr_err("Directory '%s' with parent '%s' already present!\n",
> -			       name, parent->d_name.name);
> -		else
> -			pr_err("File '%s' in directory '%s' already present!\n",
> -			       name, parent->d_name.name);

Any chance we could keep a pr_err() for this case? I was doing some
debugfs work recently, and found it helpful.

> -		dput(dentry);
> -		dentry = ERR_PTR(-EEXIST);
> -	}
> -
> -	if (IS_ERR(dentry)) {
> -		inode_unlock(d_inode(parent));
> +	dentry = simple_start_creating(parent, name);
> +	if (IS_ERR(dentry))
>  		simple_release_fs(&debugfs_mount, &debugfs_mount_count);
> -	}
>  
>  	return dentry;
>  }
> diff --git a/fs/libfs.c b/fs/libfs.c
> index 42e226af6095..833ad5ed10f5 100644
> --- a/fs/libfs.c
> +++ b/fs/libfs.c
> @@ -2260,3 +2260,28 @@ void stashed_dentry_prune(struct dentry *dentry)
>  	 */
>  	cmpxchg(stashed, dentry, NULL);
>  }
> +
> +/* parent must be held exclusive */
> +struct dentry *simple_start_creating(struct dentry *parent, const char *name)
> +{
> +	struct dentry *dentry;
> +	struct inode *dir = d_inode(parent);
> +
> +	inode_lock(dir);
> +	if (unlikely(IS_DEADDIR(dir))) {
> +		inode_unlock(dir);
> +		return ERR_PTR(-ENOENT);
> +	}
> +	dentry = lookup_noperm(&QSTR(name), parent);
> +	if (IS_ERR(dentry)) {
> +		inode_unlock(dir);
> +		return dentry;
> +	}
> +	if (dentry->d_inode) {
> +		dput(dentry);
> +		inode_unlock(dir);
> +		return ERR_PTR(-EEXIST);
> +	}
> +	return dentry;
> +}
> +EXPORT_SYMBOL(simple_start_creating);
> diff --git a/fs/tracefs/inode.c b/fs/tracefs/inode.c
> index a3fd3cc591bd..4e5d091e9263 100644
> --- a/fs/tracefs/inode.c
> +++ b/fs/tracefs/inode.c
> @@ -551,20 +551,9 @@ struct dentry *tracefs_start_creating(const char *name, struct dentry *parent)
>  	if (!parent)
>  		parent = tracefs_mount->mnt_root;
>  
> -	inode_lock(d_inode(parent));
> -	if (unlikely(IS_DEADDIR(d_inode(parent))))
> -		dentry = ERR_PTR(-ENOENT);
> -	else
> -		dentry = lookup_noperm(&QSTR(name), parent);
> -	if (!IS_ERR(dentry) && d_inode(dentry)) {
> -		dput(dentry);
> -		dentry = ERR_PTR(-EEXIST);
> -	}
> -
> -	if (IS_ERR(dentry)) {
> -		inode_unlock(d_inode(parent));
> +	dentry = simple_start_creating(parent, name);
> +	if (IS_ERR(dentry))
>  		simple_release_fs(&tracefs_mount, &tracefs_mount_count);
> -	}
>  
>  	return dentry;
>  }
> diff --git a/include/linux/fs.h b/include/linux/fs.h
> index 96c7925a6551..9f75f8836bbd 100644
> --- a/include/linux/fs.h
> +++ b/include/linux/fs.h
> @@ -3619,6 +3619,7 @@ extern int simple_fill_super(struct super_block *, unsigned long,
>  			     const struct tree_descr *);
>  extern int simple_pin_fs(struct file_system_type *, struct vfsmount **mount, int *count);
>  extern void simple_release_fs(struct vfsmount **mount, int *count);
> +struct dentry *simple_start_creating(struct dentry *, const char *);
>  
>  extern ssize_t simple_read_from_buffer(void __user *to, size_t count,
>  			loff_t *ppos, const void *from, size_t available);

-- 
Jeff Layton <jlayton@kernel.org>

^ permalink raw reply	[flat|nested] 25+ messages in thread

* Re: [PATCH 12/17] rpc_mkpipe_dentry(): switch to start_creating()
  2025-06-13  7:34   ` [PATCH 12/17] rpc_mkpipe_dentry(): switch to start_creating() Al Viro
@ 2025-06-13 19:27     ` Jeff Layton
  2025-06-16 19:26       ` Al Viro
  0 siblings, 1 reply; 25+ messages in thread
From: Jeff Layton @ 2025-06-13 19:27 UTC (permalink / raw)
  To: Al Viro, linux-fsdevel; +Cc: chuck.lever, linux-nfs, neil, torvalds, trondmy

On Fri, 2025-06-13 at 08:34 +0100, Al Viro wrote:
> ... and make sure we set the rpc_pipe-private part of inode up before
> attaching it to dentry.
> 

"rpc_pipe->private"

nit: subject should say  "...switch to simple_start_creating()".

> Signed-off-by: Al Viro <viro@zeniv.linux.org.uk>
> ---
>  net/sunrpc/rpc_pipe.c | 83 +++++++++++++++----------------------------
>  1 file changed, 29 insertions(+), 54 deletions(-)
> 
> diff --git a/net/sunrpc/rpc_pipe.c b/net/sunrpc/rpc_pipe.c
> index 8f88c75c9b30..a52fe3bbf9dc 100644
> --- a/net/sunrpc/rpc_pipe.c
> +++ b/net/sunrpc/rpc_pipe.c
> @@ -485,31 +485,6 @@ rpc_get_inode(struct super_block *sb, umode_t mode)
>  	return inode;
>  }
>  
> -static int __rpc_create_common(struct inode *dir, struct dentry *dentry,
> -			       umode_t mode,
> -			       const struct file_operations *i_fop,
> -			       void *private)
> -{
> -	struct inode *inode;
> -
> -	d_drop(dentry);
> -	inode = rpc_get_inode(dir->i_sb, mode);
> -	if (!inode)
> -		goto out_err;
> -	inode->i_ino = iunique(dir->i_sb, 100);
> -	if (i_fop)
> -		inode->i_fop = i_fop;
> -	if (private)
> -		rpc_inode_setowner(inode, private);
> -	d_add(dentry, inode);
> -	return 0;
> -out_err:
> -	printk(KERN_WARNING "%s: %s failed to allocate inode for dentry %pd\n",
> -			__FILE__, __func__, dentry);
> -	dput(dentry);
> -	return -ENOMEM;
> -}
> -
>  static void
>  init_pipe(struct rpc_pipe *pipe)
>  {
> @@ -546,25 +521,6 @@ struct rpc_pipe *rpc_mkpipe_data(const struct rpc_pipe_ops *ops, int flags)
>  }
>  EXPORT_SYMBOL_GPL(rpc_mkpipe_data);
>  
> -static int __rpc_mkpipe_dentry(struct inode *dir, struct dentry *dentry,
> -			       umode_t mode,
> -			       const struct file_operations *i_fop,
> -			       void *private,
> -			       struct rpc_pipe *pipe)
> -{
> -	struct rpc_inode *rpci;
> -	int err;
> -
> -	err = __rpc_create_common(dir, dentry, S_IFIFO | mode, i_fop, private);
> -	if (err)
> -		return err;
> -	rpci = RPC_I(d_inode(dentry));
> -	rpci->private = private;
> -	rpci->pipe = pipe;
> -	fsnotify_create(dir, dentry);
> -	return 0;
> -}
> -
>  static int rpc_new_file(struct dentry *parent,
>  			   const char *name,
>  			   umode_t mode,
> @@ -704,8 +660,10 @@ static struct dentry *rpc_mkdir_populate(struct dentry *parent,
>  int rpc_mkpipe_dentry(struct dentry *parent, const char *name,
>  				 void *private, struct rpc_pipe *pipe)
>  {
> -	struct dentry *dentry;
>  	struct inode *dir = d_inode(parent);
> +	struct dentry *dentry;
> +	struct inode *inode;
> +	struct rpc_inode *rpci;
>  	umode_t umode = S_IFIFO | 0600;
>  	int err;
>  
> @@ -715,16 +673,33 @@ int rpc_mkpipe_dentry(struct dentry *parent, const char *name,
>  		umode &= ~0222;
>  
>  	dentry = simple_start_creating(parent, name);
> -	if (IS_ERR(dentry))
> -		return PTR_ERR(dentry);
> -	err = __rpc_mkpipe_dentry(dir, dentry, umode, &rpc_pipe_fops,
> -				  private, pipe);
> -	if (unlikely(err))
> -		pr_warn("%s() failed to create pipe %pd/%s (errno = %d)\n",
> -			__func__, parent, name, err);
> -	else
> -		pipe->dentry = dentry;
> +	if (IS_ERR(dentry)) {
> +		err = PTR_ERR(dentry);
> +		goto failed;
> +	}
> +
> +	inode = rpc_get_inode(dir->i_sb, umode);
> +	if (unlikely(!inode)) {
> +		dput(dentry);
> +		inode_unlock(dir);
> +		err = -ENOMEM;
> +		goto failed;
> +	}
> +	inode->i_ino = iunique(dir->i_sb, 100);
> +	inode->i_fop = &rpc_pipe_fops;
> +	rpci = RPC_I(inode);
> +	rpci->private = private;
> +	rpci->pipe = pipe;
> +	rpc_inode_setowner(inode, private);
> +	d_instantiate(dentry, inode);
> +	pipe->dentry = dentry;
> +	fsnotify_create(dir, dentry);
>  	inode_unlock(dir);
> +	return 0;
> +
> +failed:
> +	pr_warn("%s() failed to create pipe %pd/%s (errno = %d)\n",
> +			__func__, parent, name, err);
>  	return err;
>  }
>  EXPORT_SYMBOL_GPL(rpc_mkpipe_dentry);

-- 
Jeff Layton <jlayton@kernel.org>

^ permalink raw reply	[flat|nested] 25+ messages in thread

* Re: [PATCHES][RFC][CFT] rpc_pipefs cleanups
  2025-06-13  7:31 [PATCHES][RFC][CFT] rpc_pipefs cleanups Al Viro
  2025-06-13  7:34 ` [PATCH 01/17] simple_recursive_removal(): saner interaction with fsnotify Al Viro
@ 2025-06-13 19:32 ` Jeff Layton
  1 sibling, 0 replies; 25+ messages in thread
From: Jeff Layton @ 2025-06-13 19:32 UTC (permalink / raw)
  To: Al Viro, linux-fsdevel
  Cc: linux-nfs, Chuck Lever, NeilBrown, Trond Myklebust,
	Linus Torvalds

On Fri, 2025-06-13 at 08:31 +0100, Al Viro wrote:
> 	Another series pulled out of tree-in-dcache pile; it massages
> rpc_pipefs to use saner primitives.  Lives in
> git://git.kernel.org/pub/scm/linux/kernel/git/viro/vfs.git #work.rpc_pipe
> 6.16-rc1-based, 17 commits, -314 lines of code...
> 
> Individual patches in followups.
> 
> Folks, please test and review.  In various forms this has sat in my tree
> for more than a year and I'd rather get that logjam dealt with.
> 
> Overview:
> 
> 	Prep/infrastructure (#1 is shared with #work.simple_recursive_removal)
> 
> 1) simple_recursive_removal(): saner interaction with fsnotify
> 	fsnotify events are triggered before the callback, unlike in real
> unlink(2)/rmdir(2) syscalls.  Obviously matters only in case when callback
> is non-empty, which excludes most of the current users in the kernel.
> 
> 2) new helper: simple_start_creating()
> 	Set the things up for kernel-initiated creation of object in a
> tree-in-dcache filesystem.  With respect to locking it's an equivalent of
> filename_create() - we either get a negative dentry with locked parent,
> or ERR_PTR() and no locks taken.
> 	tracefs and debugfs had that open-coded as part of their object
> creation machinery; switched to calling new helper.
> 
>       rpc_pipefs proper:
> 
> 3) rpc_pipe: clean failure exits in fill_super
> 	->kill_sb() will be called immediately after a failure
> return anyway, so we don't need to bother with notifier chain and
> rpc_gssd_dummy_depopulate().  What's more, rpc_gssd_dummy_populate()
> failure exits do not need to bother with __rpc_depopulate() - anything
> added to the tree will be taken out by ->kill_sb().
> 
> 4) rpc_{rmdir_,}depopulate(): use simple_recursive_removal() instead
> 	no need to give an exact list of objects to be remove when it's
> simply every child of the victim directory.
> 
> 5) rpc_unlink(): use simple_recursive_removal()
> 	Previous commit was dealing with directories; this one is for
> named pipes (i.e. the thing rpc_pipefs is used for).  Note that the
> callback of simple_recursive_removal() is called with the parent locked;
> the victim isn't locked by the caller.
> 
> 6) 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.
> 
> 7) rpc_unlink(): saner calling conventions
> 	* pass it pipe instead of pipe->dentry
> 	* zero pipe->dentry afterwards
> 	* it always returns 0; why bother?
> 	
> 8) rpc_mkpipe_dentry(): saner calling conventions
> 	Instead of returning a dentry or ERR_PTR(-E...), return 0 and
> store dentry into pipe->dentry on success and return -E... on failure.
> Callers are happier that way...
> 
> 9) rpc_pipe: don't overdo directory locking
> 	Don't try to hold directories locked more than VFS requires;
> lock just before getting a child to be made positive (using
> simple_start_creating()) and unlock as soon as the child is created.
> There's no benefit in keeping the parent locked while populating the
> child - it won't stop dcache lookups anyway.
> 
> 10) rpc_pipe: saner primitive for creating subdirectories
> 	All users of __rpc_mkdir() have the same form - start_creating(),
> followed, in case of success, by __rpc_mkdir() and unlocking parent.
> Combine that into a single helper, expanding __rpc_mkdir() into it, along
> with the call of __rpc_create_common() in it.
> 	Don't mess with d_drop() + d_add() - just d_instantiate()
> and be done with that.	The reason __rpc_create_common() goes for that
> dance is that dentry it gets might or might not be hashed; here we know
> it's hashed.
> 
> 11) rpc_pipe: saner primitive for creating regular files
> 	rpc_new_file(); similar to rpc_new_dir(), except that here we
> pass file_operations as well.  Callers don't care about dentry, just
> return 0 or -E...
> 
> 12) rpc_mkpipe_dentry(): switch to start_creating()
> 	... and make sure we set the rpc_pipe-private part of inode up
> before attaching it to dentry.
> 
> 13) rpc_gssd_dummy_populate(): don't bother with rpc_populate()
> 	Just have it create gssd (in root), clntXX in gssd, then info
> and gssd in clntXX - all with explicit
> rpc_new_dir()/rpc_new_file()/rpc_mkpipe_dentry().
> 
> 14) rpc_pipe: expand the calls of rpc_mkdir_populate()
> 	... and get rid of convoluted callbacks.
> 
> 15) rpc_new_dir(): the last argument is always NULL
> 	All callers except the one in rpc_populate() pass explicit NULL
> there; rpc_populate() passes its last argument ('private') instead,
> but in the only call of rpc_populate() that creates any subdirectories
> (when creating fixed subdirectories of root) private itself is NULL.
> 
> 16) rpc_create_client_dir(): don't bother with rpc_populate()
> 	not for a single file...
> 
> 17) rpc_create_client_dir(): return 0 or -E...
> 	Callers couldn't care less which dentry did we get - anything
> valid is treated as success.

Aside from a couple of minor nits, this all looks great, Al.

Pity you don't use git format-patch --cover-letter or we'd have the
aggregate diffstat! I imagine this shrinks the rpc_pipefs code
significantly.

You can add this to the pile.

Reviewed-by: Jeff Layton <jlayton@kernel.org>

^ permalink raw reply	[flat|nested] 25+ messages in thread

* Re: [PATCH 02/17] new helper: simple_start_creating()
  2025-06-13 18:31     ` Jeff Layton
@ 2025-06-13 22:36       ` Al Viro
  2025-06-13 23:46         ` Jeff Layton
  0 siblings, 1 reply; 25+ messages in thread
From: Al Viro @ 2025-06-13 22:36 UTC (permalink / raw)
  To: Jeff Layton
  Cc: linux-fsdevel, chuck.lever, linux-nfs, neil, torvalds, trondmy

On Fri, Jun 13, 2025 at 02:31:56PM -0400, Jeff Layton wrote:
> > -	if (unlikely(IS_DEADDIR(d_inode(parent))))
> > -		dentry = ERR_PTR(-ENOENT);
> > -	else
> > -		dentry = lookup_noperm(&QSTR(name), parent);
> > -	if (!IS_ERR(dentry) && d_really_is_positive(dentry)) {
> > -		if (d_is_dir(dentry))
> > -			pr_err("Directory '%s' with parent '%s' already present!\n",
> > -			       name, parent->d_name.name);
> > -		else
> > -			pr_err("File '%s' in directory '%s' already present!\n",
> > -			       name, parent->d_name.name);
> 
> Any chance we could keep a pr_err() for this case? I was doing some
> debugfs work recently, and found it helpful.

Umm...  Not in simple_start_creating(), obviously, but...
Would something like
	dentry = simple_start_creating(parent, name);
        if (IS_ERR(dentry)) {
		if (dentry == ERR_PTR(-EEXIST))
			pr_err("'%s' already exists in '%pd'\n", name, parent);
		simple_release_fs(&debugfs_mount, &debugfs_mount_count);
	}
work for you?

^ permalink raw reply	[flat|nested] 25+ messages in thread

* Re: [PATCH 02/17] new helper: simple_start_creating()
  2025-06-13 22:36       ` Al Viro
@ 2025-06-13 23:46         ` Jeff Layton
  0 siblings, 0 replies; 25+ messages in thread
From: Jeff Layton @ 2025-06-13 23:46 UTC (permalink / raw)
  To: Al Viro; +Cc: linux-fsdevel, chuck.lever, linux-nfs, neil, torvalds, trondmy

On Fri, 2025-06-13 at 23:36 +0100, Al Viro wrote:
> On Fri, Jun 13, 2025 at 02:31:56PM -0400, Jeff Layton wrote:
> > > -	if (unlikely(IS_DEADDIR(d_inode(parent))))
> > > -		dentry = ERR_PTR(-ENOENT);
> > > -	else
> > > -		dentry = lookup_noperm(&QSTR(name), parent);
> > > -	if (!IS_ERR(dentry) && d_really_is_positive(dentry)) {
> > > -		if (d_is_dir(dentry))
> > > -			pr_err("Directory '%s' with parent '%s' already present!\n",
> > > -			       name, parent->d_name.name);
> > > -		else
> > > -			pr_err("File '%s' in directory '%s' already present!\n",
> > > -			       name, parent->d_name.name);
> > 
> > Any chance we could keep a pr_err() for this case? I was doing some
> > debugfs work recently, and found it helpful.
> 
> Umm...  Not in simple_start_creating(), obviously, but...
> Would something like
> 	dentry = simple_start_creating(parent, name);
>         if (IS_ERR(dentry)) {
> 		if (dentry == ERR_PTR(-EEXIST))
> 			pr_err("'%s' already exists in '%pd'\n", name, parent);
> 		simple_release_fs(&debugfs_mount, &debugfs_mount_count);
> 	}
> work for you?

That's exactly what I was thinking.
-- 
Jeff Layton <jlayton@kernel.org>

^ permalink raw reply	[flat|nested] 25+ messages in thread

* Re: [PATCH 12/17] rpc_mkpipe_dentry(): switch to start_creating()
  2025-06-13 19:27     ` Jeff Layton
@ 2025-06-16 19:26       ` Al Viro
  0 siblings, 0 replies; 25+ messages in thread
From: Al Viro @ 2025-06-16 19:26 UTC (permalink / raw)
  To: Jeff Layton
  Cc: linux-fsdevel, chuck.lever, linux-nfs, neil, torvalds, trondmy

On Fri, Jun 13, 2025 at 03:27:39PM -0400, Jeff Layton wrote:
> On Fri, 2025-06-13 at 08:34 +0100, Al Viro wrote:
> > ... and make sure we set the rpc_pipe-private part of inode up before
> > attaching it to dentry.
> > 
> 
> "rpc_pipe->private"

Nope; fs-private, if anything.  That, or rpc_pipefs-private...

> nit: subject should say  "...switch to simple_start_creating()".

D'oh...

^ permalink raw reply	[flat|nested] 25+ messages in thread

end of thread, other threads:[~2025-06-16 19:26 UTC | newest]

Thread overview: 25+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2025-06-13  7:31 [PATCHES][RFC][CFT] rpc_pipefs cleanups Al Viro
2025-06-13  7:34 ` [PATCH 01/17] simple_recursive_removal(): saner interaction with fsnotify Al Viro
2025-06-13  7:34   ` [PATCH 02/17] new helper: simple_start_creating() Al Viro
2025-06-13 18:31     ` Jeff Layton
2025-06-13 22:36       ` Al Viro
2025-06-13 23:46         ` Jeff Layton
2025-06-13  7:34   ` [PATCH 03/17] rpc_pipe: clean failure exits in fill_super Al Viro
2025-06-13  7:34   ` [PATCH 04/17] rpc_{rmdir_,}depopulate(): use simple_recursive_removal() instead Al Viro
2025-06-13  7:34   ` [PATCH 05/17] rpc_unlink(): use simple_recursive_removal() Al Viro
2025-06-13  7:34   ` [PATCH 06/17] rpc_populate(): lift cleanup into callers Al Viro
2025-06-13  7:34   ` [PATCH 07/17] rpc_unlink(): saner calling conventions Al Viro
2025-06-13  7:34   ` [PATCH 08/17] rpc_mkpipe_dentry(): " Al Viro
2025-06-13  7:34   ` [PATCH 09/17] rpc_pipe: don't overdo directory locking Al Viro
2025-06-13  7:34   ` [PATCH 10/17] rpc_pipe: saner primitive for creating subdirectories Al Viro
2025-06-13  7:34   ` [PATCH 11/17] rpc_pipe: saner primitive for creating regular files Al Viro
2025-06-13  7:34   ` [PATCH 12/17] rpc_mkpipe_dentry(): switch to start_creating() Al Viro
2025-06-13 19:27     ` Jeff Layton
2025-06-16 19:26       ` Al Viro
2025-06-13  7:34   ` [PATCH 13/17] rpc_gssd_dummy_populate(): don't bother with rpc_populate() Al Viro
2025-06-13  7:34   ` [PATCH 14/17] rpc_pipe: expand the calls of rpc_mkdir_populate() Al Viro
2025-06-13  7:34   ` [PATCH 15/17] rpc_new_dir(): the last argument is always NULL Al Viro
2025-06-13  7:34   ` [PATCH 16/17] rpc_create_client_dir(): don't bother with rpc_populate() Al Viro
2025-06-13  7:34   ` [PATCH 17/17] rpc_create_client_dir(): return 0 or -E Al Viro
2025-06-13  8:19   ` [PATCH 01/17] simple_recursive_removal(): saner interaction with fsnotify Amir Goldstein
2025-06-13 19:32 ` [PATCHES][RFC][CFT] rpc_pipefs cleanups Jeff Layton

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).