diff options
| author | Rick Macklem <rmacklem@FreeBSD.org> | 2026-03-29 21:41:36 +0000 |
|---|---|---|
| committer | Rick Macklem <rmacklem@FreeBSD.org> | 2026-03-29 21:41:36 +0000 |
| commit | b5815ee99a015c6ac118d7e9646d0c95b72e9f2d (patch) | |
| tree | 7de9b3d57f49c4b31e53bc317b67e4eb4c410cb4 | |
| parent | 1c10825c6e5fd9a6cab364032458346866223d4f (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.c | 25 |
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; |
