Skip site navigation (1)Skip section navigation (2)
Date:      Thu, 05 Mar 2026 23:48:20 +0000
From:      Konstantin Belousov <kib@FreeBSD.org>
To:        src-committers@FreeBSD.org, dev-commits-src-all@FreeBSD.org, dev-commits-src-main@FreeBSD.org
Subject:   git: 7aaec5f3faec - main - renameat2(2): implement AT_RENAME_NOREPLACE flag
Message-ID:  <69aa1644.3e8e0.14839235@gitrepo.freebsd.org>

index | next in thread | raw e-mail

The branch main has been updated by kib:

URL: https://cgit.FreeBSD.org/src/commit/?id=7aaec5f3faecf98e377c97e24dddb9c65f4b2e75

commit 7aaec5f3faecf98e377c97e24dddb9c65f4b2e75
Author:     Konstantin Belousov <kib@FreeBSD.org>
AuthorDate: 2026-02-26 18:57:24 +0000
Commit:     Konstantin Belousov <kib@FreeBSD.org>
CommitDate: 2026-03-05 23:46:53 +0000

    renameat2(2): implement AT_RENAME_NOREPLACE flag
    
    For msdosfs, tmpfs, and ufs.
    
    Reviewed by:    markj
    Tested by:      pho
    Sponsored by:   The FreeBSD Foundation
    MFC after:      1 week
    Differential revision:  https://reviews.freebsd.org/D55539
---
 sys/fs/msdosfs/msdosfs_vnops.c |  9 +++++++--
 sys/fs/tmpfs/tmpfs_vnops.c     |  9 +++++++--
 sys/kern/vfs_syscalls.c        | 24 ++++++++++++++++++++----
 sys/sys/fcntl.h                |  3 +++
 sys/ufs/ufs/ufs_vnops.c        |  7 ++++++-
 5 files changed, 43 insertions(+), 9 deletions(-)

diff --git a/sys/fs/msdosfs/msdosfs_vnops.c b/sys/fs/msdosfs/msdosfs_vnops.c
index 3e28a7ce9d05..d626aed28076 100644
--- a/sys/fs/msdosfs/msdosfs_vnops.c
+++ b/sys/fs/msdosfs/msdosfs_vnops.c
@@ -49,12 +49,12 @@
  * October 1992
  */
 
-#include <sys/param.h>
 #include <sys/systm.h>
 #include <sys/bio.h>
 #include <sys/buf.h>
 #include <sys/clock.h>
 #include <sys/dirent.h>
+#include <sys/fcntl.h>
 #include <sys/lock.h>
 #include <sys/lockf.h>
 #include <sys/malloc.h>
@@ -970,7 +970,7 @@ msdosfs_rename(struct vop_rename_args *ap)
 		goto abortit;
 	}
 
-	if (ap->a_flags != 0) {
+	if ((ap->a_flags & ~(AT_RENAME_NOREPLACE)) != 0) {
 		error = EOPNOTSUPP;
 		goto abortit;
 	}
@@ -1041,6 +1041,11 @@ relock:
 		vrele(tvp);
 		tvp = NULL;
 	}
+	if (error == 0 && tvp != NULL &&
+	    (ap->a_flags & AT_RENAME_NOREPLACE) != 0) {
+		error = EEXIST;
+		goto unlock;
+	}
 	if (error == 0) {
 		nip = NULL;
 		error = deget(pmp, scn, blkoff, LK_EXCLUSIVE | LK_NOWAIT,
diff --git a/sys/fs/tmpfs/tmpfs_vnops.c b/sys/fs/tmpfs/tmpfs_vnops.c
index 6b32f53b3363..05d8f3e863e8 100644
--- a/sys/fs/tmpfs/tmpfs_vnops.c
+++ b/sys/fs/tmpfs/tmpfs_vnops.c
@@ -993,7 +993,7 @@ tmpfs_rename(struct vop_rename_args *v)
 		goto out;
 	}
 
-	if (v->a_flags != 0) {
+	if ((v->a_flags & ~(AT_RENAME_NOREPLACE)) != 0) {
 		error = EOPNOTSUPP;
 		goto out;
 	}
@@ -1018,9 +1018,14 @@ tmpfs_rename(struct vop_rename_args *v)
 			    "tmpfs_rename: fdvp not locked");
 			ASSERT_VOP_ELOCKED(tdvp,
 			    "tmpfs_rename: tdvp not locked");
-			if (tvp != NULL)
+			if (tvp != NULL) {
 				ASSERT_VOP_ELOCKED(tvp,
 				    "tmpfs_rename: tvp not locked");
+				if ((v->a_flags & AT_RENAME_NOREPLACE) != 0) {
+					error = EEXIST;
+					goto out_locked;
+				}
+			}
 			if (fvp == tvp) {
 				error = 0;
 				goto out_locked;
diff --git a/sys/kern/vfs_syscalls.c b/sys/kern/vfs_syscalls.c
index 20780334a6b5..06500909589e 100644
--- a/sys/kern/vfs_syscalls.c
+++ b/sys/kern/vfs_syscalls.c
@@ -3783,7 +3783,7 @@ kern_renameat(struct thread *td, int oldfd, const char *old, int newfd,
 	int error;
 	short irflag;
 
-	if (flags != 0)
+	if ((flags & ~(AT_RENAME_NOREPLACE)) != 0)
 		return (EINVAL);
 again:
 	tmp = mp = NULL;
@@ -3820,6 +3820,19 @@ again:
 	}
 	tdvp = tond.ni_dvp;
 	tvp = tond.ni_vp;
+	if (tvp != NULL && (flags & AT_RENAME_NOREPLACE) != 0) {
+		/*
+		 * Often filesystems need to relock the vnodes in
+		 * VOP_RENAME(), which opens a window for invalidation
+		 * of this check.  Then, not all filesystems might
+		 * implement AT_RENAME_NOREPLACE.  This leads to
+		 * situation where sometimes EOPNOTSUPP might be
+		 * returned from the VOP due to race, while most of
+		 * the time this check works.
+		 */
+		error = EEXIST;
+		goto out;
+	}
 	error = vn_start_write(fvp, &mp, V_NOWAIT);
 	if (error != 0) {
 again1:
@@ -3912,9 +3925,12 @@ out:
 		vrele(fromnd.ni_dvp);
 		vrele(fvp);
 	}
-	lockmgr(&tmp->mnt_renamelock, LK_RELEASE, 0);
-	vfs_rel(tmp);
-	vn_finished_write(mp);
+	if (tmp != NULL) {
+		lockmgr(&tmp->mnt_renamelock, LK_RELEASE, 0);
+		vfs_rel(tmp);
+	}
+	if (mp != NULL)
+		vn_finished_write(mp);
 out1:
 	if (error == ERESTART)
 		return (0);
diff --git a/sys/sys/fcntl.h b/sys/sys/fcntl.h
index 18d3928e91c7..8f2fc1e2debb 100644
--- a/sys/sys/fcntl.h
+++ b/sys/sys/fcntl.h
@@ -245,6 +245,9 @@ typedef	__pid_t		pid_t;
 #define	AT_RESOLVE_BENEATH	0x2000	/* Do not allow name resolution
 					   to walk out of dirfd */
 #define	AT_EMPTY_PATH		0x4000	/* Operate on dirfd if path is empty */
+
+#define	AT_RENAME_NOREPLACE	0x0001	/* Fail rename if target exists */
+#define	RENAME_NOREPLACE	AT_RENAME_NOREPLACE
 #endif	/* __BSD_VISIBLE */
 
 /*
diff --git a/sys/ufs/ufs/ufs_vnops.c b/sys/ufs/ufs/ufs_vnops.c
index 429e6b5c8dd7..4abbd4ee807f 100644
--- a/sys/ufs/ufs/ufs_vnops.c
+++ b/sys/ufs/ufs/ufs_vnops.c
@@ -1294,7 +1294,7 @@ ufs_rename(
 		goto releout;
 	}
 
-	if (ap->a_flags != 0) {
+	if ((ap->a_flags & ~(AT_RENAME_NOREPLACE)) != 0) {
 		error = EOPNOTSUPP;
 		mp = NULL;
 		goto releout;
@@ -1394,6 +1394,11 @@ relock:
 		}
 	}
 
+	if (tvp != NULL && (ap->a_flags & AT_RENAME_NOREPLACE) != 0) {
+		error = EEXIST;
+		goto unlockout;
+	}
+
 	if (DOINGSUJ(fdvp) &&
 	    (seqc_in_modify(fdvp_s) || !vn_seqc_consistent(fdvp, fdvp_s) ||
 	     seqc_in_modify(fvp_s) || !vn_seqc_consistent(fvp, fvp_s) ||


home | help

Want to link to this message? Use this
URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?69aa1644.3e8e0.14839235>