git: 5e0b96e728af - main - tmpfs: extract tmpfs_rename_check/set_parent() from tmpfs_rename()
- Go to: [ bottom of page ] [ top of archives ] [ this month ]
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);
}
}