aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorRick Macklem <rmacklem@FreeBSD.org>2026-03-29 21:41:36 +0000
committerRick Macklem <rmacklem@FreeBSD.org>2026-03-29 21:41:36 +0000
commitb5815ee99a015c6ac118d7e9646d0c95b72e9f2d (patch)
tree7de9b3d57f49c4b31e53bc317b67e4eb4c410cb4
parent1c10825c6e5fd9a6cab364032458346866223d4f (diff)
nfs_nfsdsocket.c: Allow Copy/Clone from a read-only fs
For some server file system types, such as ZFS, a Copy/Clone operation can be done across file systems of the same file system type. However, without this patch, the Copy/Clone will fail with EROFS if the input file is on a read-only mounted file system. This happens because Copy/Clone will try to do a VOP_SETATTR() of atime to set the atime. This patch pretends the VOP_SETATTR() of atime worked for read-only file systems. It fixes a problem when copying files from a ZFS snapshot. PR: 294010 MFC after: 2 weeks
-rw-r--r--sys/fs/nfsserver/nfs_nfsdserv.c25
1 files changed, 22 insertions, 3 deletions
diff --git a/sys/fs/nfsserver/nfs_nfsdserv.c b/sys/fs/nfsserver/nfs_nfsdserv.c
index b5c7f4743be0..601d536d2456 100644
--- a/sys/fs/nfsserver/nfs_nfsdserv.c
+++ b/sys/fs/nfsserver/nfs_nfsdserv.c
@@ -407,7 +407,7 @@ nfsrvd_setattr(struct nfsrv_descript *nd, __unused int isdgram,
int preat_ret = 1, postat_ret = 1, gcheck = 0, error = 0;
int gotproxystateid;
struct timespec guard = { 0, 0 };
- nfsattrbit_t attrbits, retbits;
+ nfsattrbit_t atimeonly, attrbits, retbits;
nfsv4stateid_t stateid;
NFSACL_T *aclp = NULL, *daclp = NULL;
struct thread *p = curthread;
@@ -481,9 +481,28 @@ nfsrvd_setattr(struct nfsrv_descript *nd, __unused int isdgram,
*/
if (!nd->nd_repstat) {
if (NFSVNO_NOTSETSIZE(&nva)) {
+ /*
+ * For an NFSv4.2 Setattr of atime only that fails with
+ * EROFS, pretend the operation succeeded. This makes
+ * the semantics of copying files from a ZFS snapshot
+ * the same over NFSv4.2 as it is locally.
+ * Without this "hack", the copy will fail
+ * with EROFS unless the NFSv4.2 mount has the
+ * "noatime" mount option.
+ */
+ NFSZERO_ATTRBIT(&atimeonly);
+ NFSSETBIT_ATTRBIT(&atimeonly, NFSATTRBIT_TIMEACCESSSET);
if (NFSVNO_EXRDONLY(exp) ||
- (vp->v_mount->mnt_flag & MNT_RDONLY))
- nd->nd_repstat = EROFS;
+ (vp->v_mount->mnt_flag & MNT_RDONLY)) {
+ if ((nd->nd_flag & ND_NFSV42) != 0 &&
+ NFSEQUAL_ATTRBIT(&attrbits, &atimeonly)) {
+ NFSCLRBIT_ATTRBIT(&attrbits,
+ NFSATTRBIT_TIMEACCESSSET);
+ NFSSETBIT_ATTRBIT(&retbits,
+ NFSATTRBIT_TIMEACCESSSET);
+ } else
+ nd->nd_repstat = EROFS;
+ }
} else {
if (vp->v_type != VREG)
nd->nd_repstat = EINVAL;