diff options
| author | Benjamin Coddington <bcodding@hammerspace.com> | 2025-11-27 11:02:05 -0500 |
|---|---|---|
| committer | Christian Brauner <brauner@kernel.org> | 2025-12-15 14:12:45 +0100 |
| commit | 64a989dbd144e0622371396461b11335459692d2 (patch) | |
| tree | db8583a5c781c323b0e81a2698416774d067b4fc /fs/nfsd | |
| parent | 36411554e8895feb4197a3ddd19259c84cbf0511 (diff) | |
VFS/knfsd: Teach dentry_create() to use atomic_open()
While knfsd offers combined exclusive create and open results to clients,
on some filesystems those results may not be atomic. This behavior can be
observed. For example, an open O_CREAT with mode 0 will succeed in creating
the file but unexpectedly return -EACCES from vfs_open().
Additionally reducing the number of remote RPC calls required for O_CREAT
on network filesystem provides a performance benefit in the open path.
Teach knfsd's helper dentry_create() to use atomic_open() for filesystems
that support it. The previously const @path is passed up to atomic_open()
and may be modified depending on whether an existing entry was found or if
the atomic_open() returned an error and consumed the passed-in dentry.
Signed-off-by: Benjamin Coddington <bcodding@hammerspace.com>
Link: https://patch.msgid.link/8e449bfb64ab055abb9fd82641a171531415a88c.1764259052.git.bcodding@hammerspace.com
Reviewed-by: Jeff Layton <jlayton@kernel.org>
Reviewed-by: Chuck Lever <chuck.lever@oracle.com>
Signed-off-by: Christian Brauner <brauner@kernel.org>
Diffstat (limited to 'fs/nfsd')
| -rw-r--r-- | fs/nfsd/nfs4proc.c | 11 |
1 files changed, 8 insertions, 3 deletions
diff --git a/fs/nfsd/nfs4proc.c b/fs/nfsd/nfs4proc.c index b74800917583..6aa22b3b2f43 100644 --- a/fs/nfsd/nfs4proc.c +++ b/fs/nfsd/nfs4proc.c @@ -194,7 +194,7 @@ static inline bool nfsd4_create_is_exclusive(int createmode) } static __be32 -nfsd4_vfs_create(struct svc_fh *fhp, struct dentry *child, +nfsd4_vfs_create(struct svc_fh *fhp, struct dentry **child, struct nfsd4_open *open) { struct file *filp; @@ -202,6 +202,9 @@ nfsd4_vfs_create(struct svc_fh *fhp, struct dentry *child, int oflags; oflags = O_CREAT | O_LARGEFILE; + if (nfsd4_create_is_exclusive(open->op_createmode)) + oflags |= O_EXCL; + switch (open->op_share_access & NFS4_SHARE_ACCESS_BOTH) { case NFS4_SHARE_ACCESS_WRITE: oflags |= O_WRONLY; @@ -214,9 +217,11 @@ nfsd4_vfs_create(struct svc_fh *fhp, struct dentry *child, } path.mnt = fhp->fh_export->ex_path.mnt; - path.dentry = child; + path.dentry = *child; filp = dentry_create(&path, oflags, open->op_iattr.ia_mode, current_cred()); + *child = path.dentry; + if (IS_ERR(filp)) return nfserrno(PTR_ERR(filp)); @@ -350,7 +355,7 @@ nfsd4_create_file(struct svc_rqst *rqstp, struct svc_fh *fhp, status = fh_fill_pre_attrs(fhp); if (status != nfs_ok) goto out; - status = nfsd4_vfs_create(fhp, child, open); + status = nfsd4_vfs_create(fhp, &child, open); if (status != nfs_ok) goto out; open->op_created = true; |
