From: Chuck Lever <cel@kernel.org>
To: NeilBrown <neil@brown.name>, Jeff Layton <jlayton@kernel.org>,
Olga Kornievskaia <okorniev@redhat.com>,
Dai Ngo <dai.ngo@oracle.com>, Tom Talpey <tom@talpey.com>
Cc: <linux-nfs@vger.kernel.org>, Chuck Lever <chuck.lever@oracle.com>
Subject: [PATCH v1 15/27] NFSD: Refactor nfsd_proc_create()
Date: Wed, 16 Sep 2026 12:28:46 -0400 [thread overview]
Message-ID: <20260916162859.2051-18-cel@kernel.org> (raw)
In-Reply-To: <20260916162859.2051-1-cel@kernel.org>
From: Chuck Lever <chuck.lever@oracle.com>
In a spirit consistent with commit df9606abddfb ("NFSD: Refactor
NFSv3 CREATE"), extract NFSv2-specific create behaviors into a
helper function. This clearly delineates the NFSv2-specific
semantics from the generic nfsd_create() utility.
Signed-off-by: Chuck Lever <cel@kernel.org>
---
fs/nfsd/nfsproc.c | 138 ++++++++++++++++++++++++----------------------
1 file changed, 71 insertions(+), 67 deletions(-)
diff --git a/fs/nfsd/nfsproc.c b/fs/nfsd/nfsproc.c
index 4d09da326070..e041598ce68e 100644
--- a/fs/nfsd/nfsproc.c
+++ b/fs/nfsd/nfsproc.c
@@ -627,85 +627,77 @@ static __be32 nfsd_proc_write(struct svc_rqst *rqstp)
}
/*
- * CREATE processing is complicated. The keyword here is `overloaded.'
- * The parent directory is kept locked between the check for existence
- * and the actual create() call in compliance with VFS protocols.
- * N.B. After this call _both_ argp->fh and resp->fh need an fh_put
+ * Implement NFSv2's unchecked CREATE semantics. Based on type bits in the
+ * mode field, NFSv2 CREATE can create regular files, devices, and FIFOs.
+ *
+ * Caller must release @fhp and @resfhp.
*/
static __be32
-nfsd_proc_create(struct svc_rqst *rqstp)
+nfsd_create_file(struct svc_rqst *rqstp, struct svc_fh *fhp,
+ struct svc_fh *resfhp, struct nfsd_createargs *argp)
{
- struct nfsd_createargs *argp = rqstp->rq_argp;
- struct nfsd_diropres *resp = rqstp->rq_resp;
- svc_fh *dirfhp = &argp->fh;
- svc_fh *newfhp = &resp->fh;
- struct iattr *attr = &argp->attrs;
+ struct iattr *attr = &argp->attrs;
+ dev_t rdev = 0, wanted = new_decode_dev(attr->ia_size);
struct nfsd_attrs attrs = {
.na_iattr = attr,
};
struct svc_export *exp;
- struct inode *inode;
- struct dentry *dchild;
- int type, mode;
- int hosterr;
- dev_t rdev = 0, wanted = new_decode_dev(attr->ia_size);
+ struct dentry *dchild;
+ struct inode *inode;
+ int type, mode;
+ __be32 status;
+ int host_err;
- /* First verify the parent file handle */
- resp->status = fh_verify(rqstp, dirfhp, S_IFDIR, NFSD_MAY_EXEC);
- if (resp->status != nfs_ok)
- goto done; /* must fh_put dirfhp even on error */
-
- /* Check for NFSD_MAY_WRITE in nfsd_create if necessary */
-
- resp->status = nfserr_exist;
if (name_is_dot_dotdot(argp->name, argp->len))
- goto done;
- hosterr = fh_want_write(dirfhp);
- if (hosterr) {
- resp->status = nfserrno(hosterr);
- goto done;
- }
+ return nfserr_exist;
- dchild = start_creating(&nop_mnt_idmap, dirfhp->fh_dentry,
+ status = fh_verify(rqstp, fhp, S_IFDIR, NFSD_MAY_EXEC);
+ if (status != nfs_ok)
+ return status;
+
+ host_err = fh_want_write(fhp);
+ if (host_err)
+ return nfserrno(host_err);
+
+ dchild = start_creating(&nop_mnt_idmap, fhp->fh_dentry,
&QSTR_LEN(argp->name, argp->len));
if (IS_ERR(dchild)) {
- resp->status = nfserrno(PTR_ERR(dchild));
- goto out_write;
+ status = nfserrno(PTR_ERR(dchild));
+ goto out_drop_write;
}
/*
* If name exists we need to check for mountpoints
*/
- exp = exp_get(dirfhp->fh_export);
+ exp = exp_get(fhp->fh_export);
if (d_is_reg(dchild) &&
unlikely(nfsd_mountpoint(dchild, exp))) {
- resp->status = nfsd_cross_mnt(rqstp, &dchild, &exp);
- if (resp->status != nfs_ok) {
+ status = nfsd_cross_mnt(rqstp, &dchild, &exp);
+ if (status != nfs_ok) {
exp_put(exp);
- goto out_unlock;
+ goto out;
}
}
- fh_init(newfhp, NFS_FHSIZE);
- resp->status = fh_compose(newfhp, exp, dchild, dirfhp);
+ status = fh_compose(resfhp, exp, dchild, fhp);
exp_put(exp);
- if (!resp->status && d_really_is_negative(dchild))
- resp->status = nfserr_noent;
- if (resp->status) {
- if (resp->status != nfserr_noent)
- goto out_unlock;
+ if (!status && d_really_is_negative(dchild))
+ status = nfserr_noent;
+ if (status) {
+ if (status != nfserr_noent)
+ goto out;
/*
* If the new file handle wasn't verified, we can't tell
* whether the file exists or not. Time to bail ...
*/
- resp->status = nfserr_acces;
- if (!newfhp->fh_dentry) {
+ status = nfserr_acces;
+ if (!resfhp->fh_dentry) {
printk(KERN_WARNING
"nfsd_proc_create: file handle not verified\n");
- goto out_unlock;
+ goto out;
}
}
- inode = d_inode(newfhp->fh_dentry);
+ inode = d_inode(resfhp->fh_dentry);
/* Unfudge the mode bits */
if (attr->ia_valid & ATTR_MODE) {
@@ -716,13 +708,12 @@ nfsd_proc_create(struct svc_rqst *rqstp)
* else assume a file */
if (inode) {
type = inode->i_mode & S_IFMT;
- switch(type) {
+ switch (type) {
case S_IFCHR:
case S_IFBLK:
/* reserve rdev for later checking */
rdev = inode->i_rdev;
attr->ia_valid |= ATTR_SIZE;
-
fallthrough;
case S_IFIFO:
/* this is probably a permission check..
@@ -730,13 +721,13 @@ nfsd_proc_create(struct svc_rqst *rqstp)
* echo thing > device-special-file-or-pipe
* by doing a CREATE with type==0
*/
- resp->status = nfsd_permission(
+ status = nfsd_permission(
&rqstp->rq_cred,
- newfhp->fh_export,
- newfhp->fh_dentry,
+ resfhp->fh_export,
+ resfhp->fh_dentry,
NFSD_MAY_WRITE|NFSD_MAY_LOCAL_ACCESS);
- if (resp->status && resp->status != nfserr_rofs)
- goto out_unlock;
+ if (status && status != nfserr_rofs)
+ goto out;
}
} else
type = S_IFREG;
@@ -771,37 +762,50 @@ nfsd_proc_create(struct svc_rqst *rqstp)
attr->ia_valid &= ~ATTR_SIZE;
/* Make sure the type and device matches */
- resp->status = nfserr_exist;
+ status = nfserr_exist;
if (inode && inode_wrong_type(inode, type))
- goto out_unlock;
+ goto out;
}
- resp->status = nfs_ok;
+ status = nfs_ok;
if (!inode) {
/* File doesn't exist. Create it and set attrs */
- resp->status = nfsd_create_locked(rqstp, dirfhp, &attrs, type,
- rdev, newfhp);
+ status = nfsd_create_locked(rqstp, fhp, &attrs, type,
+ rdev, resfhp);
/* nfsd_create_locked() unlocked the parent */
dput(dchild);
- goto out_write;
+ goto out_drop_write;
} else if (type == S_IFREG) {
dprintk("nfsd: existing %s, valid=%x, size=%ld\n",
- argp->name, attr->ia_valid, (long) attr->ia_size);
+ argp->name, attr->ia_valid, (long)attr->ia_size);
/* File already exists. We ignore all attributes except
* size, so that creat() behaves exactly like
* open(..., O_CREAT|O_TRUNC|O_WRONLY).
*/
attr->ia_valid &= ATTR_SIZE;
if (attr->ia_valid)
- resp->status = nfsd_setattr(rqstp, newfhp, &attrs,
- NULL);
+ status = nfsd_setattr(rqstp, resfhp, &attrs, NULL);
}
-out_unlock:
+out:
end_creating(dchild);
-out_write:
- fh_drop_write(dirfhp);
-done:
+out_drop_write:
+ fh_drop_write(fhp);
+ return status;
+}
+
+/*
+ * N.B. After this call _both_ argp->fh and resp->fh need an fh_put
+ */
+static __be32
+nfsd_proc_create(struct svc_rqst *rqstp)
+{
+ struct nfsd_createargs *argp = rqstp->rq_argp;
+ struct nfsd_diropres *resp = rqstp->rq_resp;
+ svc_fh *dirfhp = &argp->fh;
+ svc_fh *newfhp = fh_init(&resp->fh, NFS_FHSIZE);
+
+ resp->status = nfsd_create_file(rqstp, dirfhp, newfhp, argp);
fh_put(dirfhp);
if (resp->status != nfs_ok)
goto out;
--
2.55.0
next prev parent reply other threads:[~2026-09-16 16:29 UTC|newest]
Thread overview: 34+ messages / expand[flat|nested] mbox.gz Atom feed top
2026-09-16 16:28 [PATCH v1 00/27] Convert server-side NFSv2 XDR to use xdrgen Chuck Lever
2026-09-16 16:28 ` [PATCH v1 01/27] Documentation: Add the RPC language description of NFSv2 Chuck Lever
2026-09-16 16:28 ` [PATCH v1 1/2] NFSD: map fh_verify() status codes for NFS_ACLv2 replies Chuck Lever
2026-09-17 11:57 ` Jeff Layton
2026-09-16 16:28 ` [PATCH v1 02/27] NFSD: Add infrastructure for generating NFSv2 XDR encoders and decoders Chuck Lever
2026-09-16 16:28 ` [PATCH v1 2/2] NFSD: map fh_verify() status codes for NFS_ACLv3 replies Chuck Lever
2026-09-17 11:57 ` Jeff Layton
2026-09-16 16:28 ` [PATCH v1 03/27] NFSD: Use xdrgen-generated NFSv2 protocol definitions Chuck Lever
2026-09-16 16:28 ` [PATCH v1 04/27] NFSD: Remove '#include "xdr.h"' from fs/nfsd/xdr3.h Chuck Lever
2026-09-16 16:28 ` [PATCH v1 05/27] NFSD: Relocate the NFSv2 XDR storage union into nfsproc.c Chuck Lever
2026-09-16 16:28 ` [PATCH v1 06/27] NFSD: Use xdrgen XDR functions for the NFSv2 NULL procedure Chuck Lever
2026-09-16 16:28 ` [PATCH v1 07/27] NFSD: Use xdrgen XDR functions for NFSv2 GETATTR procedure Chuck Lever
2026-09-16 16:28 ` [PATCH v1 08/27] NFSD: Use xdrgen XDR functions for NFSv2 SETATTR procedure Chuck Lever
2026-09-16 16:28 ` [PATCH v1 09/27] NFSD: Use xdrgen XDR functions for the NFSv2 ROOT procedure Chuck Lever
2026-09-16 16:28 ` [PATCH v1 10/27] NFSD: Use xdrgen XDR functions for the NFSv2 LOOKUP procedure Chuck Lever
2026-09-16 16:28 ` [PATCH v1 11/27] NFSD: Use xdrgen XDR functions for NFSv2 READLINK procedure Chuck Lever
2026-09-16 16:28 ` [PATCH v1 12/27] NFSD: Use xdrgen XDR functions for NFSv2 READ procedure Chuck Lever
2026-09-16 16:28 ` [PATCH v1 13/27] NFSD: Use xdrgen XDR functions for the NFSv2 WRITECACHE procedure Chuck Lever
2026-09-16 16:28 ` [PATCH v1 14/27] NFSD: Use xdrgen XDR functions for NFSv2 WRITE procedure Chuck Lever
2026-09-16 16:28 ` Chuck Lever [this message]
2026-09-16 16:28 ` [PATCH v1 16/27] NFSD: Use xdrgen XDR functions for NFSv2 CREATE procedure Chuck Lever
2026-09-16 16:28 ` [PATCH v1 17/27] NFSD: Use xdrgen XDR functions for the NFSv2 REMOVE procedure Chuck Lever
2026-09-16 16:28 ` [PATCH v1 18/27] NFSD: Use xdrgen XDR functions for the NFSv2 RENAME procedure Chuck Lever
2026-09-16 16:28 ` [PATCH v1 19/27] NFSD: Use xdrgen XDR functions for the NFSv2 LINK procedure Chuck Lever
2026-09-16 16:28 ` [PATCH v1 20/27] NFSD: Use xdrgen XDR functions for NFSv2 SYMLINK procedure Chuck Lever
2026-09-16 16:28 ` [PATCH v1 21/27] NFSD: Use xdrgen XDR functions for NFSv2 MKDIR procedure Chuck Lever
2026-09-16 16:28 ` [PATCH v1 22/27] NFSD: Use xdrgen XDR functions for NFSv2 RMDIR procedure Chuck Lever
2026-09-16 16:28 ` [PATCH v1 23/27] NFSD: Use xdrgen XDR functions for the NFSv2 STATFS procedure Chuck Lever
2026-09-16 16:28 ` [PATCH v1 24/27] NFSD: Use xdrgen XDR functions for NFSv2 READDIR arguments Chuck Lever
2026-09-16 16:28 ` [PATCH v1 25/27] NFSD: Add a streaming directory reader Chuck Lever
2026-09-16 16:28 ` [PATCH v1 26/27] NFSD: Refactor NFSv2 directory cookie encoding Chuck Lever
2026-09-16 16:28 ` [PATCH v1 27/27] NFSD: Use xdrgen XDR functions for NFSv2 READDIR results Chuck Lever
2026-09-17 11:56 ` [PATCH v1 00/27] Convert server-side NFSv2 XDR to use xdrgen Jeff Layton
2026-09-17 14:57 ` Chuck Lever
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=20260916162859.2051-18-cel@kernel.org \
--to=cel@kernel.org \
--cc=chuck.lever@oracle.com \
--cc=dai.ngo@oracle.com \
--cc=jlayton@kernel.org \
--cc=linux-nfs@vger.kernel.org \
--cc=neil@brown.name \
--cc=okorniev@redhat.com \
--cc=tom@talpey.com \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.