[PATCH 10/10] nfsd: reduce want-write range in nfsd4_create_file(
NeilBrown <[email protected]>
| Newsgroups | gmane.linux.nfs |
|---|---|
| Message-ID | <[email protected]> |
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 file. Normally a file being created would be open for write, and once we have an active open we have the write access needed for a setattr. However if a file were created but opened read-only then the setattr wouldn't necessarily have write access to the mount. 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 only if setattr is needed on a read-only open. Signed-off-by: NeilBrown <neil-+NVA1uvv1dVBDLzU/[email protected]> --- fs/nfsd/nfs4proc.c | 34 +++++++++++++++++++++++++++------- 1 file changed, 27 insertions(+), 7 deletions(-) diff --git a/fs/nfsd/nfs4proc.c b/fs/nfsd/nfs4proc.c index 961e0c26e9a2..08e1213de743 100644 --- a/fs/nfsd/nfs4proc.c +++ b/fs/nfsd/nfs4proc.c @@ -308,7 +308,7 @@ 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)); - goto out; + goto out_write; } path.dentry = child; @@ -321,16 +321,17 @@ nfsd4_create_file(struct svc_rqst *rqstp, struct svc_fh *fhp, end_creating(child); status = nfserrno(PTR_ERR(open->op_filp)); open->op_filp = NULL; - goto out; + goto out_write; } open->op_created = open->op_filp->f_mode & FMODE_CREATED; } end_creating(child); + fh_drop_write(fhp); status = fh_compose(resfhp, fhp->fh_export, child, fhp); if (status != nfs_ok) - goto out; + goto out_free; if (!open->op_created && nfsd4_create_is_exclusive(open->op_createmode) && @@ -357,7 +358,7 @@ nfsd4_create_file(struct svc_rqst *rqstp, struct svc_fh *fhp, !iap->ia_size); } else status = nfserr_exist; - goto out; + goto out_free; } /* file was created */ fh_fill_post_attrs(fhp); @@ -367,7 +368,24 @@ nfsd4_create_file(struct svc_rqst *rqstp, struct svc_fh *fhp, iap->ia_valid &= ~ATTR_SIZE; if (is_create_with_attrs(open)) { - status = nfsd_create_setattr(rqstp, fhp, resfhp, &attrs); + if (((oflags & O_ACCMODE) == O_RDONLY)) { + /* + * We will need write access to set the attrs, + * but a successful open won't have provided + * that. + */ + int host_err = fh_want_write(fhp); + if (host_err) { + status = nfserrno(host_err); + } else { + status = nfsd_create_setattr(rqstp, fhp, + resfhp, &attrs); + fh_drop_write(fhp); + } + } else { + status = nfsd_create_setattr(rqstp, fhp, + resfhp, &attrs); + } if (attrs.na_labelerr) open->op_bmval[2] &= ~FATTR4_WORD2_SECURITY_LABEL; @@ -378,11 +396,13 @@ 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: - fh_drop_write(fhp); out_free: nfsd_attrs_free(&attrs); return status; + +out_write: + fh_drop_write(fhp); + goto out_free; } /** -- 2.50.0.107.gf914562f5916.dirty