summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorNeilBrown <neil@brown.name>2026-07-17 19:28:03 +1000
committerChuck Lever <cel@kernel.org>2026-09-13 20:36:54 -0400
commit4c6e358eca2602d6cfbffa8f6606d4281f140108 (patch)
tree61d1a58ecedb0cb0f0f9cb2e52d207d408d3b586
parent12911aba4f2b90f882ce185c4ce7274f0341ba3b (diff)
downloadlinux-next-4c6e358eca2602d6cfbffa8f6606d4281f140108.tar.gz
linux-next-4c6e358eca2602d6cfbffa8f6606d4281f140108.zip
nfsd: reduce want-write range in nfsd4_create_file()
nfsd4_create_file() needs write access to the mount for two purposes: 1/ to create/open the file. 2/ to set attributes on the newly created (or pre-existing) file. Currently this is all handled by holding the write access across the open and the setattr. A subsequent patch will necessarily change how write access is gained for the open. So we reduce the range for the first want_write, and add another one to cover setattr. If we failed to get write access, it is only fatal if there were attrs to set. We call nfsd_create_setattr() if at all possible, even when no attrs, as it also calls commit_metadata and we need to be certain that the file creation has been synced. If the mount became read-only since the creation happened, we can safely assume that the sync happened as part of that. Signed-off-by: NeilBrown <neil@brown.name> Reviewed-by: Jeff Layton <jlayton@kernel.org> Link: https://patch.msgid.link/20260717093001.1972119-16-neilb@ownmail.net Signed-off-by: Chuck Lever <cel@kernel.org>
-rw-r--r--fs/nfsd/nfs4proc.c17
1 files changed, 14 insertions, 3 deletions
diff --git a/fs/nfsd/nfs4proc.c b/fs/nfsd/nfs4proc.c
index 6dff6013a068..5e047469ba78 100644
--- a/fs/nfsd/nfs4proc.c
+++ b/fs/nfsd/nfs4proc.c
@@ -343,6 +343,8 @@ nfsd4_create_file(struct svc_rqst *rqstp, struct svc_fh *fhp,
&QSTR_LEN(open->op_fname, open->op_fnamelen));
if (IS_ERR(child)) {
status = nfserrno(PTR_ERR(child));
+ if (!want_write_err)
+ fh_drop_write(fhp);
goto out;
}
path.dentry = child;
@@ -377,6 +379,8 @@ nfsd4_create_file(struct svc_rqst *rqstp, struct svc_fh *fhp,
}
}
end_creating(child);
+ if (!want_write_err)
+ fh_drop_write(fhp);
if (status != nfs_ok)
goto out;
@@ -420,7 +424,16 @@ nfsd4_create_file(struct svc_rqst *rqstp, struct svc_fh *fhp,
if ((iap->ia_valid & ATTR_SIZE) && (iap->ia_size == 0))
iap->ia_valid &= ~ATTR_SIZE;
- status = nfsd_create_setattr(rqstp, fhp, resfhp, &attrs);
+ /* We will need write access to set the attrs */
+ want_write_err = fh_want_write(fhp);
+ if (!want_write_err) {
+ status = nfsd_create_setattr(rqstp, fhp,
+ resfhp, &attrs);
+ fh_drop_write(fhp);
+ } else if (nfsd_attrs_valid(&attrs)) {
+ /* Needed write access */
+ status = nfserrno(want_write_err);
+ }
if (attrs.na_labelerr)
open->op_bmval[2] &= ~FATTR4_WORD2_SECURITY_LABEL;
@@ -431,8 +444,6 @@ nfsd4_create_file(struct svc_rqst *rqstp, struct svc_fh *fhp,
if (attrs.na_paclerr)
open->op_bmval[2] &= ~FATTR4_WORD2_POSIX_ACCESS_ACL;
out:
- if (!want_write_err)
- fh_drop_write(fhp);
nfsd_attrs_free(&attrs);
return status;
}