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>
Subject: [PATCH v1 21/27] NFSD: Use xdrgen XDR functions for NFSv2 MKDIR procedure
Date: Wed, 16 Sep 2026 12:28:52 -0400 [thread overview]
Message-ID: <20260916162859.2051-24-cel@kernel.org> (raw)
In-Reply-To: <20260916162859.2051-1-cel@kernel.org>
Replace the NFSPROC_MKDIR entry in the nfsd_procedures2 array
with an entry that dispatches the xdrgen-generated
nfs_svc_decode_createargs and nfs_svc_encode_diropres. MKDIR
reuses the createargs and diropres wrapper structures introduced
for the CREATE conversion, which bridge the generated xdrgen
types and the legacy svc_fh, iattr, and kstat representations the
NFSD VFS layer still uses.
The pc_argzero field is now set to zero for the NFSv2 MKDIR
procedure. The xdrgen decoders are trusted to initialize all
arguments in the argp->xdrgen field, making the early defensive
memset unnecessary. The remaining argp fields are cleared as
needed.
This refactor replaces the use of svcxdr_encode_fattr(), so the
references to the parent directory and the new object file
handles can be released directly by nfsd_proc_mkdir(). A separate
->pc_release callback is thus no longer needed. This makes it
straightforward to confirm that the file handles are properly
released during every error flow.
With CREATE and MKDIR both converted, nfssvc_decode_createargs(),
nfssvc_encode_diropres(), and nfssvc_release_diropres() no longer
have any callers, so they are removed, along with the
svcxdr_decode_sattr() and svcxdr_encode_fhandle() helpers they
relied on. The now-unused nfsd_createargs and nfsd_diropres
structures are removed as well.
Signed-off-by: Chuck Lever <cel@kernel.org>
---
fs/nfsd/nfsproc.c | 80 ++++++++++++++++-----------
fs/nfsd/nfsxdr.c | 134 ----------------------------------------------
fs/nfsd/xdr.h | 16 ------
3 files changed, 49 insertions(+), 181 deletions(-)
diff --git a/fs/nfsd/nfsproc.c b/fs/nfsd/nfsproc.c
index 830d90d0ef9e..8317029850c9 100644
--- a/fs/nfsd/nfsproc.c
+++ b/fs/nfsd/nfsproc.c
@@ -1030,35 +1030,55 @@ static __be32 nfsd_proc_symlink(struct svc_rqst *rqstp)
return rpc_success;
}
-/*
- * Make directory. This operation is not idempotent.
- * N.B. After this call resp->fh needs an fh_put
+/**
+ * nfsd_proc_mkdir - MKDIR: Create a directory
+ * @rqstp: RPC transaction context
+ *
+ * Return:
+ * %rpc_success: RPC executed successfully
+ *
+ * RPC synopsis:
+ * diropres NFSPROC_MKDIR(createargs) = 14;
*/
-static __be32
-nfsd_proc_mkdir(struct svc_rqst *rqstp)
+static __be32 nfsd_proc_mkdir(struct svc_rqst *rqstp)
{
- struct nfsd_createargs *argp = rqstp->rq_argp;
- struct nfsd_diropres *resp = rqstp->rq_resp;
- struct nfsd_attrs attrs = {
- .na_iattr = &argp->attrs,
+ struct createargs_wrapper *argp = rqstp->rq_argp;
+ struct diropargs *where = &argp->xdrgen.where;
+ struct diropres_wrapper *resp = rqstp->rq_resp;
+ struct kstat *statp = &resp->stat;
+ struct svc_fh *dirfhp = &argp->fh;
+ struct svc_fh *fhp = &resp->fh;
+ struct nfsd_attrs nattrs = {
+ .na_iattr = &argp->iattrs,
};
- if (resp->fh.fh_dentry) {
- printk(KERN_WARNING
- "nfsd_proc_mkdir: response already verified??\n");
+ nfsd_fhandle_to_svc_fh(dirfhp, &where->dir);
+ fh_init(fhp, NFS_FHSIZE);
+ if (!nfsd_sattr_to_iattr(rqstp, &argp->iattrs, &argp->xdrgen.attributes)) {
+ resp->xdrgen.status = nfserr_io;
+ goto out;
}
- argp->attrs.ia_valid &= ~ATTR_SIZE;
- fh_init(&resp->fh, NFS_FHSIZE);
- resp->status = nfsd_create(rqstp, &argp->fh, argp->name, argp->len,
- &attrs, S_IFDIR, 0, &resp->fh);
- fh_put(&argp->fh);
- if (resp->status != nfs_ok)
+ argp->iattrs.ia_valid &= ~ATTR_SIZE;
+ resp->xdrgen.status = nfsd_create(rqstp, dirfhp,
+ (char *)where->name.data,
+ where->name.len, &nattrs,
+ S_IFDIR, 0, fhp);
+ if (resp->xdrgen.status != nfs_ok)
goto out;
+ resp->xdrgen.status = fh_getattr(fhp, statp);
- resp->status = fh_getattr(&resp->fh, &resp->stat);
out:
- resp->status = nfsd_map_status(resp->status);
+ if (resp->xdrgen.status == nfs_ok) {
+ nfsd_svc_fh_to_fhandle(&resp->xdrgen.u.diropok.file, fhp);
+ nfsd_stat_to_fattr(rqstp, &resp->xdrgen.u.diropok.attributes,
+ statp, fhp);
+ } else {
+ resp->xdrgen.status = nfsd_map_status(resp->xdrgen.status);
+ }
+
+ fh_put(fhp);
+ fh_put(dirfhp);
return rpc_success;
}
@@ -1303,16 +1323,15 @@ static const struct svc_procedure nfsd_procedures2[18] = {
.pc_name = "SYMLINK",
},
[NFSPROC_MKDIR] = {
- .pc_func = nfsd_proc_mkdir,
- .pc_decode = nfssvc_decode_createargs,
- .pc_encode = nfssvc_encode_diropres,
- .pc_release = nfssvc_release_diropres,
- .pc_argsize = sizeof(struct nfsd_createargs),
- .pc_argzero = sizeof(struct nfsd_createargs),
- .pc_ressize = sizeof(struct nfsd_diropres),
- .pc_cachetype = RC_REPLBUFF,
- .pc_xdrressize = ST+FH+AT,
- .pc_name = "MKDIR",
+ .pc_func = nfsd_proc_mkdir,
+ .pc_decode = nfs_svc_decode_createargs,
+ .pc_encode = nfs_svc_encode_diropres,
+ .pc_argsize = sizeof(struct createargs_wrapper),
+ .pc_argzero = 0,
+ .pc_ressize = sizeof(struct diropres_wrapper),
+ .pc_cachetype = RC_REPLBUFF,
+ .pc_xdrressize = NFS2_diropres_sz,
+ .pc_name = "MKDIR",
},
[NFSPROC_RMDIR] = {
.pc_func = nfsd_proc_rmdir,
@@ -1361,7 +1380,6 @@ union nfsd_xdrstore {
struct renameargs_wrapper renameargs;
struct linkargs_wrapper linkargs;
struct symlinkargs_wrapper symlinkargs;
- struct nfsd_readdirargs readdir;
struct attrstat_wrapper attrstat;
struct diropres_wrapper diropres;
struct readlinkres readlinkres;
diff --git a/fs/nfsd/nfsxdr.c b/fs/nfsd/nfsxdr.c
index eb87ee218f12..8989957a94e0 100644
--- a/fs/nfsd/nfsxdr.c
+++ b/fs/nfsd/nfsxdr.c
@@ -13,16 +13,6 @@
#include "nfs2xdr_gen.h"
#include "auth.h"
-/*
- * Sun convention: a sattr time-useconds field of one full second (an
- * otherwise out-of-range value) means "set this time to the current
- * server time." It's needed to make permissions checks for the "touch"
- * program across NFSv2 mounts work correctly. See description of
- * sattr in section 6.1 of "NFS Illustrated" by Brent Callaghan,
- * Addison-Wesley, ISBN 0-201-32750-5
- */
-#define NFS2_SATTR_SET_TO_SERVER_TIME (1000000)
-
/*
* Linux-internal ftype values for socket and unknown inodes, not
* in RFC 1094's wire enum; values match enum nfs_ftype.
@@ -91,19 +81,6 @@ svcxdr_decode_fhandle(struct xdr_stream *xdr, struct svc_fh *fhp)
return true;
}
-static bool
-svcxdr_encode_fhandle(struct xdr_stream *xdr, const struct svc_fh *fhp)
-{
- __be32 *p;
-
- p = xdr_reserve_space(xdr, NFS_FHSIZE);
- if (!p)
- return false;
- memcpy(p, &fhp->fh_handle.fh_raw, NFS_FHSIZE);
-
- return true;
-}
-
static __be32 *
encode_timeval(__be32 *p, const struct timespec64 *time)
{
@@ -147,81 +124,6 @@ svcxdr_decode_diropargs(struct xdr_stream *xdr, struct svc_fh *fhp,
svcxdr_decode_filename(xdr, name, len);
}
-static bool
-svcxdr_decode_sattr(struct svc_rqst *rqstp, struct xdr_stream *xdr,
- struct iattr *iap)
-{
- u32 tmp1, tmp2;
- __be32 *p;
-
- p = xdr_inline_decode(xdr, XDR_UNIT * 8);
- if (!p)
- return false;
-
- iap->ia_valid = 0;
-
- /*
- * Some Sun clients put 0xffff in the mode field when they
- * mean 0xffffffff.
- */
- tmp1 = be32_to_cpup(p++);
- if (tmp1 != (u32)-1 && tmp1 != 0xffff) {
- iap->ia_valid |= ATTR_MODE;
- iap->ia_mode = tmp1;
- }
-
- tmp1 = be32_to_cpup(p++);
- if (tmp1 != (u32)-1) {
- iap->ia_uid = make_kuid(nfsd_user_namespace(rqstp), tmp1);
- if (uid_valid(iap->ia_uid))
- iap->ia_valid |= ATTR_UID;
- }
-
- tmp1 = be32_to_cpup(p++);
- if (tmp1 != (u32)-1) {
- iap->ia_gid = make_kgid(nfsd_user_namespace(rqstp), tmp1);
- if (gid_valid(iap->ia_gid))
- iap->ia_valid |= ATTR_GID;
- }
-
- tmp1 = be32_to_cpup(p++);
- if (tmp1 != (u32)-1) {
- iap->ia_valid |= ATTR_SIZE;
- iap->ia_size = tmp1;
- }
-
- tmp1 = be32_to_cpup(p++);
- tmp2 = be32_to_cpup(p++);
- if (tmp1 != (u32)-1 && tmp2 != (u32)-1) {
- /*
- * Range test here to prevent the multiplication from
- * wrapping to a valid (but incorrect) value on 32-bit
- * platforms.
- */
- if (tmp2 > NFS2_SATTR_SET_TO_SERVER_TIME)
- return false;
- iap->ia_valid |= ATTR_ATIME | ATTR_ATIME_SET;
- iap->ia_atime.tv_sec = tmp1;
- iap->ia_atime.tv_nsec = tmp2 * NSEC_PER_USEC;
- if (tmp2 == NFS2_SATTR_SET_TO_SERVER_TIME)
- iap->ia_valid &= ~ATTR_ATIME_SET;
- }
-
- tmp1 = be32_to_cpup(p++);
- tmp2 = be32_to_cpup(p++);
- if (tmp1 != (u32)-1 && tmp2 != (u32)-1) {
- if (tmp2 > NFS2_SATTR_SET_TO_SERVER_TIME)
- return false;
- iap->ia_valid |= ATTR_MTIME | ATTR_MTIME_SET;
- iap->ia_mtime.tv_sec = tmp1;
- iap->ia_mtime.tv_nsec = tmp2 * NSEC_PER_USEC;
- if (tmp2 == NFS2_SATTR_SET_TO_SERVER_TIME)
- iap->ia_valid &= ~(ATTR_ATIME_SET|ATTR_MTIME_SET);
- }
-
- return true;
-}
-
/**
* svcxdr_encode_fattr - Encode NFSv2 file attributes
* @rqstp: Context of a completed RPC transaction
@@ -311,16 +213,6 @@ nfssvc_decode_diropargs(struct svc_rqst *rqstp, struct xdr_stream *xdr)
return svcxdr_decode_diropargs(xdr, &args->fh, &args->name, &args->len);
}
-bool
-nfssvc_decode_createargs(struct svc_rqst *rqstp, struct xdr_stream *xdr)
-{
- struct nfsd_createargs *args = rqstp->rq_argp;
-
- return svcxdr_decode_diropargs(xdr, &args->fh,
- &args->name, &args->len) &&
- svcxdr_decode_sattr(rqstp, xdr, &args->attrs);
-}
-
bool
nfssvc_decode_readdirargs(struct svc_rqst *rqstp, struct xdr_stream *xdr)
{
@@ -365,25 +257,6 @@ nfssvc_encode_attrstatres(struct svc_rqst *rqstp, struct xdr_stream *xdr)
return true;
}
-bool
-nfssvc_encode_diropres(struct svc_rqst *rqstp, struct xdr_stream *xdr)
-{
- struct nfsd_diropres *resp = rqstp->rq_resp;
-
- if (!svcxdr_encode_stat(xdr, resp->status))
- return false;
- switch (resp->status) {
- case nfs_ok:
- if (!svcxdr_encode_fhandle(xdr, &resp->fh))
- return false;
- if (!svcxdr_encode_fattr(rqstp, xdr, &resp->fh, &resp->stat))
- return false;
- break;
- }
-
- return true;
-}
-
bool
nfssvc_encode_readdirres(struct svc_rqst *rqstp, struct xdr_stream *xdr)
{
@@ -528,10 +401,3 @@ void nfssvc_release_attrstat(struct svc_rqst *rqstp)
fh_put(&resp->fh);
}
-
-void nfssvc_release_diropres(struct svc_rqst *rqstp)
-{
- struct nfsd_diropres *resp = rqstp->rq_resp;
-
- fh_put(&resp->fh);
-}
diff --git a/fs/nfsd/xdr.h b/fs/nfsd/xdr.h
index eeea28caf19d..bd3123179f61 100644
--- a/fs/nfsd/xdr.h
+++ b/fs/nfsd/xdr.h
@@ -14,13 +14,6 @@ struct nfsd_diropargs {
unsigned int len;
};
-struct nfsd_createargs {
- struct svc_fh fh;
- char * name;
- unsigned int len;
- struct iattr attrs;
-};
-
struct nfsd_readdirargs {
struct svc_fh fh;
__u32 cookie;
@@ -37,12 +30,6 @@ struct nfsd_attrstat {
struct kstat stat;
};
-struct nfsd_diropres {
- __be32 status;
- struct svc_fh fh;
- struct kstat stat;
-};
-
struct nfsd_readdirres {
/* Components of the reply */
__be32 status;
@@ -63,12 +50,10 @@ struct nfsd_statfsres {
bool nfssvc_decode_fhandleargs(struct svc_rqst *rqstp, struct xdr_stream *xdr);
bool nfssvc_decode_diropargs(struct svc_rqst *rqstp, struct xdr_stream *xdr);
-bool nfssvc_decode_createargs(struct svc_rqst *rqstp, struct xdr_stream *xdr);
bool nfssvc_decode_readdirargs(struct svc_rqst *rqstp, struct xdr_stream *xdr);
bool nfssvc_encode_statres(struct svc_rqst *rqstp, struct xdr_stream *xdr);
bool nfssvc_encode_attrstatres(struct svc_rqst *rqstp, struct xdr_stream *xdr);
-bool nfssvc_encode_diropres(struct svc_rqst *rqstp, struct xdr_stream *xdr);
bool nfssvc_encode_statfsres(struct svc_rqst *rqstp, struct xdr_stream *xdr);
bool nfssvc_encode_readdirres(struct svc_rqst *rqstp, struct xdr_stream *xdr);
@@ -77,7 +62,6 @@ int nfssvc_encode_entry(void *data, const char *name, int namlen,
loff_t offset, u64 ino, unsigned int d_type);
void nfssvc_release_attrstat(struct svc_rqst *rqstp);
-void nfssvc_release_diropres(struct svc_rqst *rqstp);
/* Helper functions for NFSv2 ACL code */
bool svcxdr_decode_fhandle(struct xdr_stream *xdr, struct svc_fh *fhp);
--
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 ` [PATCH v1 15/27] NFSD: Refactor nfsd_proc_create() Chuck Lever
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 ` Chuck Lever [this message]
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-24-cel@kernel.org \
--to=cel@kernel.org \
--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 a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox