[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
lmpx.com only provides a reader for public news (NNTP) servers. It is not affiliated with the servers or forums shown here and is not responsible for the content of articles, which is written by their respective authors.