[PATCH 15/18] nfsd: reduce want-write range in nfsd4_create_file(

NeilBrown <[email protected]>
Newsgroups gmane.linux.nfs,gmane.linux.file-systems
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 | 27 +++++++++++++++++++++++----
 1 file changed, 23 insertions(+), 4 deletions(-)

diff --git a/fs/nfsd/nfs4proc.c b/fs/nfsd/nfs4proc.c
index 03eb93f696f9..5bd19e5d9e34 100644
--- a/fs/nfsd/nfs4proc.c
+++ b/fs/nfsd/nfs4proc.c
@@ -310,7 +310,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;
 
@@ -323,12 +323,13 @@ 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)
@@ -367,7 +368,22 @@ nfsd4_create_file(struct svc_rqst *rqstp, struct svc_fh *fhp,
 	fh_fill_post_attrs(fhp);
 
 	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 provide 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;
@@ -380,8 +396,11 @@ nfsd4_create_file(struct svc_rqst *rqstp, struct svc_fh *fhp,
 	}
 out:
 	nfsd_attrs_free(&attrs);
-	fh_drop_write(fhp);
 	return status;
+
+out_write:
+	fh_drop_write(fhp);
+	goto out;
 }
 
 /**
-- 
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.