git: 7e06c33151e7 - main - tmpfs: implement AT_RENAME_EXCHANGE
- Go to: [ bottom of page ] [ top of archives ] [ this month ]
Date: Sat, 11 Jul 2026 22:05:26 UTC
The branch main has been updated by kib:
URL: https://cgit.FreeBSD.org/src/commit/?id=7e06c33151e7664f6d664ee282d8da1985ce94aa
commit 7e06c33151e7664f6d664ee282d8da1985ce94aa
Author: Konstantin Belousov <kib@FreeBSD.org>
AuthorDate: 2026-06-18 18:40:40 +0000
Commit: Konstantin Belousov <kib@FreeBSD.org>
CommitDate: 2026-07-11 22:04:43 +0000
tmpfs: implement AT_RENAME_EXCHANGE
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 | 90 ++++++++++++++++++++++++++++++++++------------
1 file changed, 67 insertions(+), 23 deletions(-)
diff --git a/sys/fs/tmpfs/tmpfs_vnops.c b/sys/fs/tmpfs/tmpfs_vnops.c
index 8021e42e7c06..fe8507b4936a 100644
--- a/sys/fs/tmpfs/tmpfs_vnops.c
+++ b/sys/fs/tmpfs/tmpfs_vnops.c
@@ -1055,7 +1055,7 @@ tmpfs_rename(struct vop_rename_args *v)
struct vnode *tvp = v->a_tvp;
struct componentname *tcnp = v->a_tcnp;
char *newname;
- struct tmpfs_dirent *de;
+ struct tmpfs_dirent *de, *tde;
struct tmpfs_mount *tmp;
struct tmpfs_node *fdnode;
struct tmpfs_node *fnode;
@@ -1063,8 +1063,11 @@ tmpfs_rename(struct vop_rename_args *v)
struct tmpfs_node *tdnode;
int error;
bool want_seqc_end;
+ bool exchange;
want_seqc_end = false;
+ newname = NULL;
+ error = 0;
/*
* Disallow cross-device renames.
@@ -1076,16 +1079,15 @@ tmpfs_rename(struct vop_rename_args *v)
goto out;
}
- if ((v->a_flags & ~(AT_RENAME_NOREPLACE)) != 0) {
+ if ((v->a_flags & ~(AT_RENAME_NOREPLACE | AT_RENAME_EXCHANGE)) != 0) {
error = EOPNOTSUPP;
goto out;
}
/* If source and target are the same file, there is nothing to do. */
- if (fvp == tvp) {
- error = 0;
+ if (fvp == tvp)
goto out;
- }
+ exchange = (v->a_flags & AT_RENAME_EXCHANGE) != 0;
/*
* If we need to move the directory between entries, lock the
@@ -1138,6 +1140,8 @@ tmpfs_rename(struct vop_rename_args *v)
fdnode = VP_TO_TMPFS_DIR(fdvp);
fnode = VP_TO_TMPFS_NODE(fvp);
de = tmpfs_dir_lookup(fdnode, fnode, fcnp);
+ if (exchange)
+ tde = tmpfs_dir_lookup(tdnode, tnode, tcnp);
/*
* Entry can disappear before we lock fdvp.
@@ -1151,6 +1155,13 @@ tmpfs_rename(struct vop_rename_args *v)
goto out_locked;
}
MPASS(de->td_node == fnode);
+ if (exchange) {
+ if (tde == NULL) {
+ error = ENOENT;
+ goto out_locked;
+ }
+ MPASS(tde->td_node == tnode);
+ }
/*
* If re-naming a directory to another preexisting directory
@@ -1168,22 +1179,27 @@ tmpfs_rename(struct vop_rename_args *v)
goto out_locked;
}
- if (fnode->tn_type == VDIR && tnode->tn_type == VDIR) {
- if (tnode->tn_size != 0 &&
- ((tcnp->cn_flags & IGNOREWHITEOUT) == 0 ||
- tnode->tn_size > tnode->tn_dir.tn_wht_size)) {
- error = ENOTEMPTY;
+ if (!exchange) {
+ if (fnode->tn_type == VDIR && tnode->tn_type == VDIR) {
+ if (tnode->tn_size != 0 &&
+ ((tcnp->cn_flags & IGNOREWHITEOUT) == 0 ||
+ tnode->tn_size >
+ tnode->tn_dir.tn_wht_size)) {
+ error = ENOTEMPTY;
+ goto out_locked;
+ }
+ } else if (fnode->tn_type == VDIR &&
+ tnode->tn_type != VDIR) {
+ error = ENOTDIR;
goto out_locked;
+ } else if (fnode->tn_type != VDIR &&
+ tnode->tn_type == VDIR) {
+ error = EISDIR;
+ goto out_locked;
+ } else {
+ MPASS(fnode->tn_type != VDIR &&
+ tnode->tn_type != VDIR);
}
- } else if (fnode->tn_type == VDIR && tnode->tn_type != VDIR) {
- error = ENOTDIR;
- goto out_locked;
- } else if (fnode->tn_type != VDIR && tnode->tn_type == VDIR) {
- error = EISDIR;
- goto out_locked;
- } else {
- MPASS(fnode->tn_type != VDIR &&
- tnode->tn_type != VDIR);
}
}
@@ -1197,11 +1213,9 @@ tmpfs_rename(struct vop_rename_args *v)
* Ensure that we have enough memory to hold the new name, if it
* has to be changed.
*/
- if (fcnp->cn_namelen != tcnp->cn_namelen ||
- bcmp(fcnp->cn_nameptr, tcnp->cn_nameptr, fcnp->cn_namelen) != 0) {
+ if (!exchange && (fcnp->cn_namelen != tcnp->cn_namelen ||
+ bcmp(fcnp->cn_nameptr, tcnp->cn_nameptr, fcnp->cn_namelen) != 0))
newname = malloc(tcnp->cn_namelen, M_TMPFSNAME, M_WAITOK);
- } else
- newname = NULL;
/*
* If the node is being moved to another directory, we have to do
@@ -1219,8 +1233,38 @@ tmpfs_rename(struct vop_rename_args *v)
free(newname, M_TMPFSNAME);
goto out_locked;
}
+ }
+ if (exchange && tnode->tn_type == VDIR) {
+ MPASS(newname == NULL);
+ error = tmpfs_rename_check_parent(tmp, tdnode, tvp,
+ tnode, tde, fdnode, fcnp->cn_cred);
+ if (error != 0)
+ goto out_locked;
+ }
+ if (fnode->tn_type == VDIR)
tmpfs_rename_set_parent(fdnode, fnode, de, tdnode);
+ if (exchange && tnode->tn_type == VDIR)
+ tmpfs_rename_set_parent(tdnode, tnode, tde, fdnode);
+ }
+ if (exchange) {
+ de->td_node = tnode;
+ tde->td_node = fnode;
+ if (tmpfs_use_nc(fvp)) {
+ cache_purge(fvp);
+ cache_purge(tvp);
+ cache_enter(tdvp, fvp, tcnp);
+ cache_enter(fdvp, tvp, fcnp);
+ }
+ fdnode->tn_status |= TMPFS_NODE_MODIFIED | TMPFS_NODE_CHANGED;
+ fdnode->tn_accessed = true;
+ tmpfs_update(fdvp);
+ if (fdvp != tdvp) {
+ tdnode->tn_status |= TMPFS_NODE_MODIFIED |
+ TMPFS_NODE_CHANGED;
+ tdnode->tn_accessed = true;
+ tmpfs_update(tdvp);
}
+ goto out_locked;
}
/*