git: 5e0b96e728af - main - tmpfs: extract tmpfs_rename_check/set_parent() from tmpfs_rename()

From: Konstantin Belousov <kib_at_FreeBSD.org>
Date: Sat, 11 Jul 2026 22:05:25 UTC
The branch main has been updated by kib:

URL: https://cgit.FreeBSD.org/src/commit/?id=5e0b96e728af9916ac59d65e37155a95e06c3b5e

commit 5e0b96e728af9916ac59d65e37155a95e06c3b5e
Author:     Konstantin Belousov <kib@FreeBSD.org>
AuthorDate: 2026-06-18 20:01:35 +0000
Commit:     Konstantin Belousov <kib@FreeBSD.org>
CommitDate: 2026-07-11 22:04:43 +0000

    tmpfs: extract tmpfs_rename_check/set_parent() from tmpfs_rename()
    
    Reviewed by:    mckusick
    Discussed with: markj
    Tested by:      pho
    Sponsored by:   The FreeBSD Foundation
    MFC after:      1 week
    Differential revision:  https://reviews.freebsd.org/D57658
---
 sys/fs/tmpfs/tmpfs_vnops.c | 167 ++++++++++++++++++++++++---------------------
 1 file changed, 89 insertions(+), 78 deletions(-)

diff --git a/sys/fs/tmpfs/tmpfs_vnops.c b/sys/fs/tmpfs/tmpfs_vnops.c
index b635450f205f..8021e42e7c06 100644
--- a/sys/fs/tmpfs/tmpfs_vnops.c
+++ b/sys/fs/tmpfs/tmpfs_vnops.c
@@ -962,6 +962,89 @@ releout:
 	return (error);
 }
 
+static int
+tmpfs_rename_check_parent(struct tmpfs_mount *tmp, struct tmpfs_node *fdnode,
+    struct vnode *fvp, struct tmpfs_node *fnode, struct tmpfs_dirent *de,
+    struct tmpfs_node *tdnode, struct ucred *tcred)
+{
+	struct tmpfs_node *n;
+	int error;
+
+	TMPFS_NODE_LOCK(fnode);
+	error = tmpfs_access_locked(fvp, fnode, VWRITE, tcred);
+	TMPFS_NODE_UNLOCK(fnode);
+	if (error != 0)
+		return (error);
+
+	/*
+	 * Ensure the target directory is not a child of the
+	 * directory being moved.  Otherwise, we'd end up
+	 * with stale nodes.
+	 *
+	 * TMPFS_LOCK guarantees that no nodes are freed while
+	 * traversing the list. Nodes can only be marked as
+	 * removed: tn_parent == NULL.
+	 */
+	n = tdnode;
+	TMPFS_LOCK(tmp);
+	TMPFS_NODE_LOCK(n);
+	while (n != n->tn_dir.tn_parent) {
+		struct tmpfs_node *parent;
+
+		if (n == fnode) {
+			TMPFS_NODE_UNLOCK(n);
+			TMPFS_UNLOCK(tmp);
+			return (EINVAL);
+		}
+		parent = n->tn_dir.tn_parent;
+		TMPFS_NODE_UNLOCK(n);
+		if (parent == NULL) {
+			n = NULL;
+			break;
+		}
+		TMPFS_NODE_LOCK(parent);
+		if (parent->tn_dir.tn_parent == NULL) {
+			TMPFS_NODE_UNLOCK(parent);
+			n = NULL;
+			break;
+		}
+		n = parent;
+	}
+	TMPFS_UNLOCK(tmp);
+	if (n == NULL)
+		return (EINVAL);
+
+	TMPFS_NODE_UNLOCK(n);
+
+	return (0);
+}
+
+static void
+tmpfs_rename_set_parent(struct tmpfs_node *fdnode, struct tmpfs_node *fnode,
+    struct tmpfs_dirent *de, struct tmpfs_node *tdnode)
+{
+	/* Adjust the parent pointer. */
+	TMPFS_VALIDATE_DIR(fnode);
+	TMPFS_NODE_LOCK(de->td_node);
+	de->td_node->tn_dir.tn_parent = tdnode;
+	TMPFS_NODE_UNLOCK(de->td_node);
+
+	/*
+	 * As a result of changing the target of the '..'
+	 * entry, the link count of the source and target
+	 * directories has to be adjusted.
+	 */
+	TMPFS_NODE_LOCK(tdnode);
+	TMPFS_ASSERT_LOCKED(tdnode);
+	tdnode->tn_links++;
+	TMPFS_NODE_UNLOCK(tdnode);
+
+	TMPFS_NODE_LOCK(fdnode);
+	TMPFS_ASSERT_LOCKED(fdnode);
+	fdnode->tn_links--;
+	TMPFS_NODE_UNLOCK(fdnode);
+}
+
 static int
 tmpfs_rename(struct vop_rename_args *v)
 {
@@ -1129,86 +1212,14 @@ tmpfs_rename(struct vop_rename_args *v)
 		 * In case we are moving a directory, we have to adjust its
 		 * parent to point to the new parent.
 		 */
-		if (de->td_node->tn_type == VDIR) {
-			struct tmpfs_node *n;
-
-			TMPFS_NODE_LOCK(fnode);
-			error = tmpfs_access_locked(fvp, fnode, VWRITE,
-			    tcnp->cn_cred);
-			TMPFS_NODE_UNLOCK(fnode);
-			if (error) {
-				if (newname != NULL)
-					free(newname, M_TMPFSNAME);
+		if (fnode->tn_type == VDIR) {
+			error = tmpfs_rename_check_parent(tmp, fdnode, fvp,
+			    fnode, de, tdnode, tcnp->cn_cred);
+			if (error != 0) {
+				free(newname, M_TMPFSNAME);
 				goto out_locked;
 			}
-
-			/*
-			 * Ensure the target directory is not a child of the
-			 * directory being moved.  Otherwise, we'd end up
-			 * with stale nodes.
-			 */
-			n = tdnode;
-			/*
-			 * TMPFS_LOCK guaranties that no nodes are freed while
-			 * traversing the list. Nodes can only be marked as
-			 * removed: tn_parent == NULL.
-			 */
-			TMPFS_LOCK(tmp);
-			TMPFS_NODE_LOCK(n);
-			while (n != n->tn_dir.tn_parent) {
-				struct tmpfs_node *parent;
-
-				if (n == fnode) {
-					TMPFS_NODE_UNLOCK(n);
-					TMPFS_UNLOCK(tmp);
-					error = EINVAL;
-					if (newname != NULL)
-						free(newname, M_TMPFSNAME);
-					goto out_locked;
-				}
-				parent = n->tn_dir.tn_parent;
-				TMPFS_NODE_UNLOCK(n);
-				if (parent == NULL) {
-					n = NULL;
-					break;
-				}
-				TMPFS_NODE_LOCK(parent);
-				if (parent->tn_dir.tn_parent == NULL) {
-					TMPFS_NODE_UNLOCK(parent);
-					n = NULL;
-					break;
-				}
-				n = parent;
-			}
-			TMPFS_UNLOCK(tmp);
-			if (n == NULL) {
-				error = EINVAL;
-				if (newname != NULL)
-					    free(newname, M_TMPFSNAME);
-				goto out_locked;
-			}
-			TMPFS_NODE_UNLOCK(n);
-
-			/* Adjust the parent pointer. */
-			TMPFS_VALIDATE_DIR(fnode);
-			TMPFS_NODE_LOCK(de->td_node);
-			de->td_node->tn_dir.tn_parent = tdnode;
-			TMPFS_NODE_UNLOCK(de->td_node);
-
-			/*
-			 * As a result of changing the target of the '..'
-			 * entry, the link count of the source and target
-			 * directories has to be adjusted.
-			 */
-			TMPFS_NODE_LOCK(tdnode);
-			TMPFS_ASSERT_LOCKED(tdnode);
-			tdnode->tn_links++;
-			TMPFS_NODE_UNLOCK(tdnode);
-
-			TMPFS_NODE_LOCK(fdnode);
-			TMPFS_ASSERT_LOCKED(fdnode);
-			fdnode->tn_links--;
-			TMPFS_NODE_UNLOCK(fdnode);
+			tmpfs_rename_set_parent(fdnode, fnode, de, tdnode);
 		}
 	}