Re: [PATCH v3 14/17] nfsd: reduce want-write range in nfsd4_create_file()

Jeff Layton <[email protected]> Thu, 16 Jul 2026 08:29:28 -0400
Newsgroups gmane.linux.nfs
Message-ID <[email protected]>
On Mon, 2026-07-13 at 16:15 +1000, NeilBrown wrote:
> From: NeilBrown <neil-+NVA1uvv1dVBDLzU/[email protected]>
> 
> 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-+NVA1uvv1dVBDLzU/[email protected]>
> ---
>  fs/nfsd/nfs4proc.c | 17 ++++++++++++++---
>  1 file changed, 14 insertions(+), 3 deletions(-)
> 
> diff --git a/fs/nfsd/nfs4proc.c b/fs/nfsd/nfs4proc.c
> index adfc1f5ccd98..0d1bcb12ecbc 100644
> --- a/fs/nfsd/nfs4proc.c
> +++ b/fs/nfsd/nfs4proc.c
> @@ -344,6 +344,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;
> @@ -378,6 +380,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;
>  
> @@ -421,7 +425,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;
> @@ -432,8 +445,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;
>  }

It sucks that file creation is so fraught with peril and places that
things can go wrong and leave stuff sitting out on the fs. I wonder if
we ought to be using O_TMPFILE where possible to do all of this setup
and only later link it into the namespace. That's a much bigger change
though of course.

Reviewed-by: Jeff Layton <[email protected]>