[PATCH 16/18] nfsd: switch nfsd4_create_file() to use vfs_lookup_open()

NeilBrown <[email protected]>
Newsgroups gmane.linux.nfs,gmane.linux.file-systems
Message-ID <[email protected]>
From: NeilBrown <neil-+NVA1uvv1dVBDLzU/[email protected]>

Currently nfsd4_create_file() performs a lookup via start_creating() and
then if that reports a negative dentry it uses dentry_create() to create
the file.
dentry_create() will use ->atomic_open if available.  Part of the point
of supporting atomic_open is to avoid needing a separate lookup.
->atomic_open can do lookup, create, open all in one operation.  So
doing a lookup before dentry_create() is not optimal.

So change to use vfs_lookup_open() which combines lookup, create, and open,
either by using atomic_open or by calling the individual functions (but
not both).

This means that we don't need to lock that parent
(start_creating/end_creating).
We also don't need to get write-access (fh_want_write/fh_drop_write)
except in the unusual case of a read-only creating open.

Also we only set O_EXCL in the NFS4_CREATE_GUARDED case.  This the an
NFS protocol option which requests the server to take full
responsibility for atomic-create.  For NFS4_CREATE_EXCLUSIVE and
NFS4_CREATE_EXCLUSIVE4_1 the NFS protocol takes responsibilty for
exclusive create by providing a verifier to store with the file, and
using O_EXCL would interfere with this.

Signed-off-by: NeilBrown <neil-+NVA1uvv1dVBDLzU/[email protected]>
---
 fs/nfsd/nfs4proc.c | 59 ++++++++++++++++------------------------------
 1 file changed, 20 insertions(+), 39 deletions(-)

diff --git a/fs/nfsd/nfs4proc.c b/fs/nfsd/nfs4proc.c
index 5bd19e5d9e34..61ecd4123817 100644
--- a/fs/nfsd/nfs4proc.c
+++ b/fs/nfsd/nfs4proc.c
@@ -219,14 +219,13 @@ nfsd4_create_file(struct svc_rqst *rqstp, struct svc_fh *fhp,
 		.na_seclabel	= &open->op_label,
 	};
 	int oflags = O_CREAT | O_LARGEFILE;
-	struct dentry *parent, *child = ERR_PTR(-EINVAL);
-	struct path path = {
+	struct dentry *child = ERR_PTR(-EINVAL);
+	struct path parent = {
 		.mnt = fhp->fh_export->ex_path.mnt,
+		.dentry = fhp->fh_dentry,
 	};
 	__u32 v_mtime, v_atime;
-	struct inode *inode;
 	__be32 status;
-	int host_err;
 
 	if (isdotent(open->op_fname, open->op_fnamelen))
 		return nfserr_exist;
@@ -236,10 +235,8 @@ nfsd4_create_file(struct svc_rqst *rqstp, struct svc_fh *fhp,
 	status = fh_verify(rqstp, fhp, S_IFDIR, NFSD_MAY_EXEC);
 	if (status != nfs_ok)
 		return status;
-	parent = fhp->fh_dentry;
-	inode = d_inode(parent);
 
-	if (!IS_POSIXACL(inode))
+	if (!IS_POSIXACL(d_inode(parent.dentry)))
 		iap->ia_mode &= ~current_umask();
 
 	if (!is_create_with_attrs(open)) {
@@ -287,9 +284,12 @@ nfsd4_create_file(struct svc_rqst *rqstp, struct svc_fh *fhp,
 		iap->ia_atime.tv_sec = v_atime;
 		iap->ia_mtime.tv_nsec = 0;
 		iap->ia_atime.tv_nsec = 0;
-
-		oflags |= O_EXCL;
 	}
+	/* Only ask the fs to provide exclusive-create if we aren't using
+	 * the NFS verifier to do it outselves.
+	 */
+	if (open->op_createmode == NFS4_CREATE_GUARDED)
+		oflags |= O_EXCL;
 
 	switch (open->op_share_access & NFS4_SHARE_ACCESS_BOTH) {
 	case NFS4_SHARE_ACCESS_WRITE:
@@ -302,33 +302,18 @@ nfsd4_create_file(struct svc_rqst *rqstp, struct svc_fh *fhp,
 		oflags |= O_RDONLY;
 	}
 
-	host_err = fh_want_write(fhp);
-	if (host_err)
-		return nfserrno(host_err);
-
-	child = start_creating(&nop_mnt_idmap, parent,
-			       &QSTR_LEN(open->op_fname, open->op_fnamelen));
-	if (IS_ERR(child)) {
-		status = nfserrno(PTR_ERR(child));
-		goto out_write;
-	}
-	path.dentry = child;
-
-	if (d_really_is_negative(child)) {
-		open->op_filp = dentry_create(&path, oflags, open->op_iattr.ia_mode,
-					      current_cred());
-		child = path.dentry;
-
-		if (IS_ERR(open->op_filp)) {
-			end_creating(child);
-			status = nfserrno(PTR_ERR(open->op_filp));
-			open->op_filp = NULL;
-			goto out_write;
-		}
-
-		open->op_created = open->op_filp->f_mode & FMODE_CREATED;
+	open->op_filp = vfs_lookup_open(&parent,
+					&QSTR_LEN(open->op_fname,
+						  open->op_fnamelen),
+					oflags,
+					open->op_iattr.ia_mode);
+	if (IS_ERR(open->op_filp)) {
+		status = nfserrno(PTR_ERR(open->op_filp));
+		open->op_filp = NULL;
+		goto out;
 	}
-	end_creating(child);
+	child = open->op_filp->f_path.dentry;
+	open->op_created = open->op_filp->f_mode & FMODE_CREATED;
 	fh_drop_write(fhp);
 
 	status = fh_compose(resfhp, fhp->fh_export, child, fhp);
@@ -397,10 +382,6 @@ nfsd4_create_file(struct svc_rqst *rqstp, struct svc_fh *fhp,
 out:
 	nfsd_attrs_free(&attrs);
 	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.