[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