* [PATCH v3 20/34] NFSD: Use xdrgen XDR functions for the NFSv3 RMDIR procedure
@ 2026-10-13 12:49 Chuck Lever
2026-10-13 12:49 ` [PATCH v3 21/34] NFSD: Use xdrgen XDR functions for the NFSv3 RENAME procedure Chuck Lever
` (8 more replies)
0 siblings, 9 replies; 10+ messages in thread
From: Chuck Lever @ 2026-10-13 12:49 UTC (permalink / raw)
To: NeilBrown, Jeff Layton, Olga Kornievskaia, Dai Ngo, Tom Talpey; +Cc: linux-nfs
Replace the NFSPROC3_RMDIR entry in the nfsd_procedures3 array
with an entry that dispatches the xdrgen-generated
nfs_svc_decode_RMDIR3args and nfs_svc_encode_RMDIR3res. A
wrapper structure bridges the generated xdrgen argument type and
the legacy svc_fh representation the NFSD VFS layer still uses;
the result uses the generated RMDIR3res type directly.
Filename validity is now checked by nfsd3_proc_rmdir() so that a
proper NFS3ERR status code can be returned to the client rather
than GARBAGE_ARGS.
The pc_argzero field is now set to zero for the NFSv3 RMDIR
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.
Because nfsd3_proc_rmdir() now assembles the WCC data, that work
moves out of the XDR result encoder, and the reference to the
file handle can be released directly by nfsd3_proc_rmdir(). A
separate ->pc_release callback is thus no longer needed. This
makes it straightforward to confirm that the file handle is
properly released during every error flow.
nfs3svc_decode_diropargs() and nfs3svc_encode_wccstat() no longer
have any callers, so they are removed.
Signed-off-by: Chuck Lever <cel@kernel.org>
---
fs/nfsd/nfs3proc.c | 74 ++++++++++++++++++++++++++++++++--------------
fs/nfsd/nfs3xdr.c | 18 -----------
fs/nfsd/xdr3.h | 8 -----
3 files changed, 51 insertions(+), 49 deletions(-)
diff --git a/fs/nfsd/nfs3proc.c b/fs/nfsd/nfs3proc.c
index 540e4a6a42e0..db33866273fa 100644
--- a/fs/nfsd/nfs3proc.c
+++ b/fs/nfsd/nfs3proc.c
@@ -170,6 +170,13 @@ struct REMOVE3args_wrapper {
static_assert(offsetof(struct REMOVE3args_wrapper, xdrgen) == 0);
+struct RMDIR3args_wrapper {
+ struct RMDIR3args xdrgen;
+ struct svc_fh fh;
+};
+
+static_assert(offsetof(struct RMDIR3args_wrapper, xdrgen) == 0);
+
static int nfsd3_ftype3_to_mode(ftype3 ftype)
{
switch (ftype) {
@@ -1298,19 +1305,42 @@ static __be32 nfsd3_proc_remove(struct svc_rqst *rqstp)
return rpc_success;
}
-/*
- * Remove a directory
+/**
+ * nfsd3_proc_rmdir - RMDIR: Remove a directory
+ * @rqstp: RPC transaction context
+ *
+ * Return:
+ * %rpc_success: RPC executed successfully
+ *
+ * RPC synopsis:
+ * RMDIR3res NFSPROC3_RMDIR(RMDIR3args) = 13;
*/
-static __be32
-nfsd3_proc_rmdir(struct svc_rqst *rqstp)
+static __be32 nfsd3_proc_rmdir(struct svc_rqst *rqstp)
{
- struct nfsd3_diropargs *argp = rqstp->rq_argp;
- struct nfsd3_attrstat *resp = rqstp->rq_resp;
+ struct RMDIR3args_wrapper *argp = rqstp->rq_argp;
+ struct diropargs3 *object = &argp->xdrgen.object;
+ struct RMDIR3res *resp = rqstp->rq_resp;
+ struct svc_fh *fhp = &argp->fh;
- fh_copy(&resp->fh, &argp->fh);
- resp->status = nfsd_unlink(rqstp, &resp->fh, S_IFDIR,
- argp->name, argp->len);
- resp->status = nfsd3_map_status(resp->status);
+ nfsd3_fh3_to_svc_fh(fhp, &object->dir);
+ resp->status = nfsd3_check_filename(object->name.data,
+ object->name.len);
+ if (resp->status != nfs_ok)
+ goto out;
+
+ resp->status = nfsd_unlink(rqstp, fhp, S_IFDIR,
+ (char *)object->name.data,
+ object->name.len);
+
+out:
+ if (resp->status == nfs_ok) {
+ nfsd3_fill_wcc_data(rqstp, &resp->u.resok.dir_wcc, fhp);
+ } else {
+ resp->status = nfsd3_map_status(resp->status);
+ nfsd3_fill_wcc_data(rqstp, &resp->u.resfail.dir_wcc, fhp);
+ }
+
+ fh_put(fhp);
return rpc_success;
}
@@ -1594,10 +1624,8 @@ nfsd3_proc_commit(struct svc_rqst *rqstp)
* NFSv3 Server procedures.
* Only the results of non-idempotent operations are cached.
*/
-#define nfs3svc_encode_wccstatres nfs3svc_encode_wccstat
#define nfsd3_readdirplusargs nfsd3_readdirargs
#define nfsd3_fhandleargs nfsd_fhandle
-#define nfsd3_wccstatres nfsd3_attrstat
#define ST 1 /* status*/
#define AT 21 /* attributes */
@@ -1752,16 +1780,15 @@ static const struct svc_procedure nfsd_procedures3[22] = {
.pc_name = "REMOVE",
},
[NFSPROC3_RMDIR] = {
- .pc_func = nfsd3_proc_rmdir,
- .pc_decode = nfs3svc_decode_diropargs,
- .pc_encode = nfs3svc_encode_wccstatres,
- .pc_release = nfs3svc_release_fhandle,
- .pc_argsize = sizeof(struct nfsd3_diropargs),
- .pc_argzero = sizeof(struct nfsd3_diropargs),
- .pc_ressize = sizeof(struct nfsd3_wccstatres),
- .pc_cachetype = RC_REPLBUFF,
- .pc_xdrressize = ST+WC,
- .pc_name = "RMDIR",
+ .pc_func = nfsd3_proc_rmdir,
+ .pc_decode = nfs_svc_decode_RMDIR3args,
+ .pc_encode = nfs_svc_encode_RMDIR3res,
+ .pc_argsize = sizeof(struct RMDIR3args_wrapper),
+ .pc_argzero = 0,
+ .pc_ressize = sizeof(struct RMDIR3res),
+ .pc_cachetype = RC_REPLBUFF,
+ .pc_xdrressize = NFS3_RMDIR3res_sz,
+ .pc_name = "RMDIR",
},
[NFSPROC3_RENAME] = {
.pc_func = nfsd3_proc_rename,
@@ -1870,7 +1897,6 @@ union nfsd3_xdrstore {
struct ACCESS3res accessres;
struct READLINK3args_wrapper readlinkargs;
struct READ3args_wrapper readargs;
- struct nfsd3_diropargs diropargs;
struct WRITE3args_wrapper writeargs;
struct CREATE3args_wrapper createargs;
struct CREATE3res_wrapper createres;
@@ -1882,6 +1908,8 @@ union nfsd3_xdrstore {
struct MKNOD3res_wrapper mknodres;
struct REMOVE3args_wrapper removeargs;
struct REMOVE3res removeres;
+ struct RMDIR3args_wrapper rmdirargs;
+ struct RMDIR3res rmdirres;
struct nfsd3_renameargs renameargs;
struct nfsd3_linkargs linkargs;
struct nfsd3_readdirargs readdirargs;
diff --git a/fs/nfsd/nfs3xdr.c b/fs/nfsd/nfs3xdr.c
index 53a82af80ad5..1cfc79724450 100644
--- a/fs/nfsd/nfs3xdr.c
+++ b/fs/nfsd/nfs3xdr.c
@@ -360,14 +360,6 @@ nfs3svc_decode_fhandleargs(struct svc_rqst *rqstp, struct xdr_stream *xdr)
return svcxdr_decode_nfs_fh3(xdr, &args->fh);
}
-bool
-nfs3svc_decode_diropargs(struct svc_rqst *rqstp, struct xdr_stream *xdr)
-{
- struct nfsd3_diropargs *args = rqstp->rq_argp;
-
- return svcxdr_decode_diropargs3(xdr, &args->fh, &args->name, &args->len);
-}
-
bool
nfs3svc_decode_renameargs(struct svc_rqst *rqstp, struct xdr_stream *xdr)
{
@@ -448,16 +440,6 @@ nfs3svc_decode_commitargs(struct svc_rqst *rqstp, struct xdr_stream *xdr)
* XDR encode functions
*/
-/* SETATTR, REMOVE, RMDIR */
-bool
-nfs3svc_encode_wccstat(struct svc_rqst *rqstp, struct xdr_stream *xdr)
-{
- struct nfsd3_attrstat *resp = rqstp->rq_resp;
-
- return svcxdr_encode_nfsstat3(xdr, resp->status) &&
- svcxdr_encode_wcc_data(rqstp, xdr, &resp->fh);
-}
-
/* RENAME */
bool
nfs3svc_encode_renameres(struct svc_rqst *rqstp, struct xdr_stream *xdr)
diff --git a/fs/nfsd/xdr3.h b/fs/nfsd/xdr3.h
index 6d5cea6baf3a..fac60fb4cdf9 100644
--- a/fs/nfsd/xdr3.h
+++ b/fs/nfsd/xdr3.h
@@ -19,12 +19,6 @@
#define NFS3_MAXNAMLEN NAME_MAX
#define NFS3_MAXPATHLEN PATH_MAX
-struct nfsd3_diropargs {
- struct svc_fh fh;
- char * name;
- unsigned int len;
-};
-
struct nfsd3_accessargs {
struct svc_fh fh;
__u32 access;
@@ -171,14 +165,12 @@ struct nfsd3_fhandle_pair {
};
bool nfs3svc_decode_fhandleargs(struct svc_rqst *rqstp, struct xdr_stream *xdr);
-bool nfs3svc_decode_diropargs(struct svc_rqst *rqstp, struct xdr_stream *xdr);
bool nfs3svc_decode_renameargs(struct svc_rqst *rqstp, struct xdr_stream *xdr);
bool nfs3svc_decode_linkargs(struct svc_rqst *rqstp, struct xdr_stream *xdr);
bool nfs3svc_decode_readdirargs(struct svc_rqst *rqstp, struct xdr_stream *xdr);
bool nfs3svc_decode_readdirplusargs(struct svc_rqst *rqstp, struct xdr_stream *xdr);
bool nfs3svc_decode_commitargs(struct svc_rqst *rqstp, struct xdr_stream *xdr);
-bool nfs3svc_encode_wccstat(struct svc_rqst *rqstp, struct xdr_stream *xdr);
bool nfs3svc_encode_accessres(struct svc_rqst *rqstp, struct xdr_stream *xdr);
bool nfs3svc_encode_renameres(struct svc_rqst *rqstp, struct xdr_stream *xdr);
bool nfs3svc_encode_linkres(struct svc_rqst *rqstp, struct xdr_stream *xdr);
--
2.55.0
^ permalink raw reply related [flat|nested] 10+ messages in thread
* [PATCH v3 21/34] NFSD: Use xdrgen XDR functions for the NFSv3 RENAME procedure
2026-10-13 12:49 [PATCH v3 20/34] NFSD: Use xdrgen XDR functions for the NFSv3 RMDIR procedure Chuck Lever
@ 2026-10-13 12:49 ` Chuck Lever
2026-10-13 12:49 ` [PATCH v3 22/34] NFSD: Use xdrgen XDR functions for the NFSv3 LINK procedure Chuck Lever
` (7 subsequent siblings)
8 siblings, 0 replies; 10+ messages in thread
From: Chuck Lever @ 2026-10-13 12:49 UTC (permalink / raw)
To: NeilBrown, Jeff Layton, Olga Kornievskaia, Dai Ngo, Tom Talpey; +Cc: linux-nfs
Replace the NFSPROC3_RENAME entry in the nfsd_procedures3 array
with an entry that dispatches the xdrgen-generated
nfs_svc_decode_RENAME3args and nfs_svc_encode_RENAME3res. A
wrapper structure bridges the generated xdrgen argument type and
the legacy svc_fh representation the NFSD VFS layer still uses;
the result uses the generated RENAME3res type directly.
Filename validity is now checked by nfsd3_proc_rename() so that a
proper NFS3ERR status code can be returned to the client rather
than GARBAGE_ARGS.
The pc_argzero field is now set to zero for the NFSv3 RENAME
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.
Because nfsd3_proc_rename() now assembles the WCC data, that work
moves out of the XDR result encoder, and the references to the
file handles can be released directly by nfsd3_proc_rename(). 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.
nfs3svc_decode_renameargs() and nfs3svc_encode_renameres() no
longer have any callers, so they are removed.
Signed-off-by: Chuck Lever <cel@kernel.org>
---
fs/nfsd/nfs3proc.c | 89 +++++++++++++++++++++++++++++++++++-----------
fs/nfsd/nfs3xdr.c | 22 ------------
fs/nfsd/xdr3.h | 17 ---------
3 files changed, 68 insertions(+), 60 deletions(-)
diff --git a/fs/nfsd/nfs3proc.c b/fs/nfsd/nfs3proc.c
index db33866273fa..7fd968fdb145 100644
--- a/fs/nfsd/nfs3proc.c
+++ b/fs/nfsd/nfs3proc.c
@@ -177,6 +177,14 @@ struct RMDIR3args_wrapper {
static_assert(offsetof(struct RMDIR3args_wrapper, xdrgen) == 0);
+struct RENAME3args_wrapper {
+ struct RENAME3args xdrgen;
+ struct svc_fh ffh;
+ struct svc_fh tfh;
+};
+
+static_assert(offsetof(struct RENAME3args_wrapper, xdrgen) == 0);
+
static int nfsd3_ftype3_to_mode(ftype3 ftype)
{
switch (ftype) {
@@ -1344,17 +1352,57 @@ static __be32 nfsd3_proc_rmdir(struct svc_rqst *rqstp)
return rpc_success;
}
-static __be32
-nfsd3_proc_rename(struct svc_rqst *rqstp)
+/**
+ * nfsd3_proc_rename - RENAME: Rename a file or directory
+ * @rqstp: RPC transaction context
+ *
+ * Return:
+ * %rpc_success: RPC executed successfully
+ *
+ * RPC synopsis:
+ * RENAME3res NFSPROC3_RENAME(RENAME3args) = 14;
+ */
+static __be32 nfsd3_proc_rename(struct svc_rqst *rqstp)
{
- struct nfsd3_renameargs *argp = rqstp->rq_argp;
- struct nfsd3_renameres *resp = rqstp->rq_resp;
+ struct RENAME3args_wrapper *argp = rqstp->rq_argp;
+ struct diropargs3 *from = &argp->xdrgen.from;
+ struct diropargs3 *to = &argp->xdrgen.to;
+ struct RENAME3res *resp = rqstp->rq_resp;
+ struct svc_fh *ffhp = &argp->ffh;
+ struct svc_fh *tfhp = &argp->tfh;
- fh_copy(&resp->ffh, &argp->ffh);
- fh_copy(&resp->tfh, &argp->tfh);
- resp->status = nfsd_rename(rqstp, &resp->ffh, argp->fname, argp->flen,
- &resp->tfh, argp->tname, argp->tlen);
- resp->status = nfsd3_map_status(resp->status);
+ nfsd3_fh3_to_svc_fh(ffhp, &from->dir);
+ nfsd3_fh3_to_svc_fh(tfhp, &to->dir);
+ resp->status = nfsd3_check_filename(from->name.data,
+ from->name.len);
+ if (resp->status != nfs_ok)
+ goto out;
+ resp->status = nfsd3_check_filename(to->name.data,
+ to->name.len);
+ if (resp->status != nfs_ok)
+ goto out;
+
+ resp->status = nfsd_rename(rqstp, ffhp, (char *)from->name.data,
+ from->name.len, tfhp,
+ (char *)to->name.data,
+ to->name.len);
+
+out:
+ if (resp->status == nfs_ok) {
+ struct RENAME3resok *resok = &resp->u.resok;
+
+ nfsd3_fill_wcc_data(rqstp, &resok->fromdir_wcc, ffhp);
+ nfsd3_fill_wcc_data(rqstp, &resok->todir_wcc, tfhp);
+ } else {
+ struct RENAME3resfail *resfail = &resp->u.resfail;
+
+ resp->status = nfsd3_map_status(resp->status);
+ nfsd3_fill_wcc_data(rqstp, &resfail->fromdir_wcc, ffhp);
+ nfsd3_fill_wcc_data(rqstp, &resfail->todir_wcc, tfhp);
+ }
+
+ fh_put(ffhp);
+ fh_put(tfhp);
return rpc_success;
}
@@ -1791,16 +1839,15 @@ static const struct svc_procedure nfsd_procedures3[22] = {
.pc_name = "RMDIR",
},
[NFSPROC3_RENAME] = {
- .pc_func = nfsd3_proc_rename,
- .pc_decode = nfs3svc_decode_renameargs,
- .pc_encode = nfs3svc_encode_renameres,
- .pc_release = nfs3svc_release_fhandle2,
- .pc_argsize = sizeof(struct nfsd3_renameargs),
- .pc_argzero = sizeof(struct nfsd3_renameargs),
- .pc_ressize = sizeof(struct nfsd3_renameres),
- .pc_cachetype = RC_REPLBUFF,
- .pc_xdrressize = ST+WC+WC,
- .pc_name = "RENAME",
+ .pc_func = nfsd3_proc_rename,
+ .pc_decode = nfs_svc_decode_RENAME3args,
+ .pc_encode = nfs_svc_encode_RENAME3res,
+ .pc_argsize = sizeof(struct RENAME3args_wrapper),
+ .pc_argzero = 0,
+ .pc_ressize = sizeof(struct RENAME3res),
+ .pc_cachetype = RC_REPLBUFF,
+ .pc_xdrressize = NFS3_RENAME3res_sz,
+ .pc_name = "RENAME",
},
[NFSPROC3_LINK] = {
.pc_func = nfsd3_proc_link,
@@ -1910,13 +1957,13 @@ union nfsd3_xdrstore {
struct REMOVE3res removeres;
struct RMDIR3args_wrapper rmdirargs;
struct RMDIR3res rmdirres;
- struct nfsd3_renameargs renameargs;
+ struct RENAME3args_wrapper renameargs;
+ struct RENAME3res renameres;
struct nfsd3_linkargs linkargs;
struct nfsd3_readdirargs readdirargs;
struct READLINK3res readlinkres;
struct READ3res readres;
struct nfsd3_writeres writeres;
- struct nfsd3_renameres renameres;
struct nfsd3_linkres linkres;
struct nfsd3_readdirres readdirres;
struct nfsd3_fsstatres fsstatres;
diff --git a/fs/nfsd/nfs3xdr.c b/fs/nfsd/nfs3xdr.c
index 1cfc79724450..3ec835e0f364 100644
--- a/fs/nfsd/nfs3xdr.c
+++ b/fs/nfsd/nfs3xdr.c
@@ -360,17 +360,6 @@ nfs3svc_decode_fhandleargs(struct svc_rqst *rqstp, struct xdr_stream *xdr)
return svcxdr_decode_nfs_fh3(xdr, &args->fh);
}
-bool
-nfs3svc_decode_renameargs(struct svc_rqst *rqstp, struct xdr_stream *xdr)
-{
- struct nfsd3_renameargs *args = rqstp->rq_argp;
-
- return svcxdr_decode_diropargs3(xdr, &args->ffh,
- &args->fname, &args->flen) &&
- svcxdr_decode_diropargs3(xdr, &args->tfh,
- &args->tname, &args->tlen);
-}
-
bool
nfs3svc_decode_linkargs(struct svc_rqst *rqstp, struct xdr_stream *xdr)
{
@@ -440,17 +429,6 @@ nfs3svc_decode_commitargs(struct svc_rqst *rqstp, struct xdr_stream *xdr)
* XDR encode functions
*/
-/* RENAME */
-bool
-nfs3svc_encode_renameres(struct svc_rqst *rqstp, struct xdr_stream *xdr)
-{
- struct nfsd3_renameres *resp = rqstp->rq_resp;
-
- return svcxdr_encode_nfsstat3(xdr, resp->status) &&
- svcxdr_encode_wcc_data(rqstp, xdr, &resp->ffh) &&
- svcxdr_encode_wcc_data(rqstp, xdr, &resp->tfh);
-}
-
/* LINK */
bool
nfs3svc_encode_linkres(struct svc_rqst *rqstp, struct xdr_stream *xdr)
diff --git a/fs/nfsd/xdr3.h b/fs/nfsd/xdr3.h
index fac60fb4cdf9..8a15781d7f3c 100644
--- a/fs/nfsd/xdr3.h
+++ b/fs/nfsd/xdr3.h
@@ -24,15 +24,6 @@ struct nfsd3_accessargs {
__u32 access;
};
-struct nfsd3_renameargs {
- struct svc_fh ffh;
- char * fname;
- unsigned int flen;
- struct svc_fh tfh;
- char * tname;
- unsigned int tlen;
-};
-
struct nfsd3_linkargs {
struct svc_fh ffh;
struct svc_fh tfh;
@@ -85,12 +76,6 @@ struct nfsd3_writeres {
static_assert(offsetof(struct nfsd3_writeres, xdrgen) == 0);
-struct nfsd3_renameres {
- __be32 status;
- struct svc_fh ffh;
- struct svc_fh tfh;
-};
-
struct nfsd3_linkres {
__be32 status;
struct svc_fh tfh;
@@ -165,14 +150,12 @@ struct nfsd3_fhandle_pair {
};
bool nfs3svc_decode_fhandleargs(struct svc_rqst *rqstp, struct xdr_stream *xdr);
-bool nfs3svc_decode_renameargs(struct svc_rqst *rqstp, struct xdr_stream *xdr);
bool nfs3svc_decode_linkargs(struct svc_rqst *rqstp, struct xdr_stream *xdr);
bool nfs3svc_decode_readdirargs(struct svc_rqst *rqstp, struct xdr_stream *xdr);
bool nfs3svc_decode_readdirplusargs(struct svc_rqst *rqstp, struct xdr_stream *xdr);
bool nfs3svc_decode_commitargs(struct svc_rqst *rqstp, struct xdr_stream *xdr);
bool nfs3svc_encode_accessres(struct svc_rqst *rqstp, struct xdr_stream *xdr);
-bool nfs3svc_encode_renameres(struct svc_rqst *rqstp, struct xdr_stream *xdr);
bool nfs3svc_encode_linkres(struct svc_rqst *rqstp, struct xdr_stream *xdr);
bool nfs3svc_encode_readdirres(struct svc_rqst *rqstp, struct xdr_stream *xdr);
bool nfs3svc_encode_fsstatres(struct svc_rqst *rqstp, struct xdr_stream *xdr);
--
2.55.0
^ permalink raw reply related [flat|nested] 10+ messages in thread
* [PATCH v3 22/34] NFSD: Use xdrgen XDR functions for the NFSv3 LINK procedure
2026-10-13 12:49 [PATCH v3 20/34] NFSD: Use xdrgen XDR functions for the NFSv3 RMDIR procedure Chuck Lever
2026-10-13 12:49 ` [PATCH v3 21/34] NFSD: Use xdrgen XDR functions for the NFSv3 RENAME procedure Chuck Lever
@ 2026-10-13 12:49 ` Chuck Lever
2026-10-13 12:49 ` [PATCH v3 23/34] NFSD: Use xdrgen XDR functions for the NFSv3 FSSTAT procedure Chuck Lever
` (6 subsequent siblings)
8 siblings, 0 replies; 10+ messages in thread
From: Chuck Lever @ 2026-10-13 12:49 UTC (permalink / raw)
To: NeilBrown, Jeff Layton, Olga Kornievskaia, Dai Ngo, Tom Talpey; +Cc: linux-nfs
Replace the NFSPROC3_LINK entry in the nfsd_procedures3 array with
an entry that dispatches the xdrgen-generated nfs_svc_decode_LINK3args
and nfs_svc_encode_LINK3res. A wrapper structure bridges the
generated xdrgen argument type and the legacy svc_fh representation
the NFSD VFS layer still uses; the result uses the generated LINK3res
type directly.
Filename validity is now checked by nfsd3_proc_link() so that a
proper NFS3ERR status code can be returned to the client rather than
GARBAGE_ARGS.
The pc_argzero field is now set to zero for the NFSv3 LINK 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.
Because nfsd3_proc_link() now fills in the post-op attributes and
assembles the WCC data, that work moves out of the XDR result
encoder, and the references to the file handles can be released
directly by nfsd3_proc_link(). 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.
nfs3svc_decode_linkargs(), nfs3svc_encode_linkres(), and
nfs3svc_release_fhandle2() no longer have any callers, so they are
removed, and with them the now-orphaned svcxdr_decode_filename3() and
svcxdr_decode_diropargs3() decode helpers and the struct
nfsd3_fhandle_pair release type.
Signed-off-by: Chuck Lever <cel@kernel.org>
---
fs/nfsd/nfs3proc.c | 82 ++++++++++++++++++++++++++++++++++------------
fs/nfsd/nfs3xdr.c | 63 -----------------------------------
fs/nfsd/xdr3.h | 23 -------------
3 files changed, 61 insertions(+), 107 deletions(-)
diff --git a/fs/nfsd/nfs3proc.c b/fs/nfsd/nfs3proc.c
index 7fd968fdb145..76963187de20 100644
--- a/fs/nfsd/nfs3proc.c
+++ b/fs/nfsd/nfs3proc.c
@@ -185,6 +185,14 @@ struct RENAME3args_wrapper {
static_assert(offsetof(struct RENAME3args_wrapper, xdrgen) == 0);
+struct LINK3args_wrapper {
+ struct LINK3args xdrgen;
+ struct svc_fh ffh;
+ struct svc_fh tfh;
+};
+
+static_assert(offsetof(struct LINK3args_wrapper, xdrgen) == 0);
+
static int nfsd3_ftype3_to_mode(ftype3 ftype)
{
switch (ftype) {
@@ -1406,17 +1414,50 @@ static __be32 nfsd3_proc_rename(struct svc_rqst *rqstp)
return rpc_success;
}
-static __be32
-nfsd3_proc_link(struct svc_rqst *rqstp)
+/**
+ * nfsd3_proc_link - LINK: Create Link to an object
+ * @rqstp: RPC transaction context
+ *
+ * Return:
+ * %rpc_success: RPC executed successfully
+ *
+ * RPC synopsis:
+ * LINK3res NFSPROC3_LINK(LINK3args) = 15;
+ */
+static __be32 nfsd3_proc_link(struct svc_rqst *rqstp)
{
- struct nfsd3_linkargs *argp = rqstp->rq_argp;
- struct nfsd3_linkres *resp = rqstp->rq_resp;
+ struct LINK3args_wrapper *argp = rqstp->rq_argp;
+ struct diropargs3 *link = &argp->xdrgen.link;
+ struct LINK3res *resp = rqstp->rq_resp;
+ struct svc_fh *ffhp = &argp->ffh;
+ struct svc_fh *tfhp = &argp->tfh;
- fh_copy(&resp->fh, &argp->ffh);
- fh_copy(&resp->tfh, &argp->tfh);
- resp->status = nfsd_link(rqstp, &resp->tfh, argp->tname, argp->tlen,
- &resp->fh);
- resp->status = nfsd3_map_status(resp->status);
+ nfsd3_fh3_to_svc_fh(ffhp, &argp->xdrgen.file);
+ nfsd3_fh3_to_svc_fh(tfhp, &link->dir);
+ resp->status = nfsd3_check_filename(link->name.data,
+ link->name.len);
+ if (resp->status != nfs_ok)
+ goto out;
+
+ resp->status = nfsd_link(rqstp, tfhp, (char *)link->name.data,
+ link->name.len, ffhp);
+
+out:
+ if (resp->status == nfs_ok) {
+ struct LINK3resok *resok = &resp->u.resok;
+
+ nfsd3_fill_post_op_attr(rqstp, &resok->file_attributes, ffhp);
+ nfsd3_fill_wcc_data(rqstp, &resok->linkdir_wcc, tfhp);
+ } else {
+ struct LINK3resfail *resfail = &resp->u.resfail;
+
+ resp->status = nfsd3_map_status(resp->status);
+ nfsd3_fill_post_op_attr(rqstp, &resfail->file_attributes, ffhp);
+ nfsd3_fill_wcc_data(rqstp, &resfail->linkdir_wcc, tfhp);
+ }
+
+ fh_put(ffhp);
+ fh_put(tfhp);
return rpc_success;
}
@@ -1850,16 +1891,15 @@ static const struct svc_procedure nfsd_procedures3[22] = {
.pc_name = "RENAME",
},
[NFSPROC3_LINK] = {
- .pc_func = nfsd3_proc_link,
- .pc_decode = nfs3svc_decode_linkargs,
- .pc_encode = nfs3svc_encode_linkres,
- .pc_release = nfs3svc_release_fhandle2,
- .pc_argsize = sizeof(struct nfsd3_linkargs),
- .pc_argzero = sizeof(struct nfsd3_linkargs),
- .pc_ressize = sizeof(struct nfsd3_linkres),
- .pc_cachetype = RC_REPLBUFF,
- .pc_xdrressize = ST+pAT+WC,
- .pc_name = "LINK",
+ .pc_func = nfsd3_proc_link,
+ .pc_decode = nfs_svc_decode_LINK3args,
+ .pc_encode = nfs_svc_encode_LINK3res,
+ .pc_argsize = sizeof(struct LINK3args_wrapper),
+ .pc_argzero = 0,
+ .pc_ressize = sizeof(struct LINK3res),
+ .pc_cachetype = RC_REPLBUFF,
+ .pc_xdrressize = NFS3_LINK3res_sz,
+ .pc_name = "LINK",
},
[NFSPROC3_READDIR] = {
.pc_func = nfsd3_proc_readdir,
@@ -1959,12 +1999,12 @@ union nfsd3_xdrstore {
struct RMDIR3res rmdirres;
struct RENAME3args_wrapper renameargs;
struct RENAME3res renameres;
- struct nfsd3_linkargs linkargs;
+ struct LINK3args_wrapper linkargs;
+ struct LINK3res linkres;
struct nfsd3_readdirargs readdirargs;
struct READLINK3res readlinkres;
struct READ3res readres;
struct nfsd3_writeres writeres;
- struct nfsd3_linkres linkres;
struct nfsd3_readdirres readdirres;
struct nfsd3_fsstatres fsstatres;
struct nfsd3_fsinfores fsinfores;
diff --git a/fs/nfsd/nfs3xdr.c b/fs/nfsd/nfs3xdr.c
index 3ec835e0f364..59e89b7f9d19 100644
--- a/fs/nfsd/nfs3xdr.c
+++ b/fs/nfsd/nfs3xdr.c
@@ -162,39 +162,6 @@ svcxdr_encode_writeverf3(struct xdr_stream *xdr, const __be32 *verf)
return true;
}
-static bool
-svcxdr_decode_filename3(struct xdr_stream *xdr, char **name, unsigned int *len)
-{
- u32 size, i;
- __be32 *p;
- char *c;
-
- if (xdr_stream_decode_u32(xdr, &size) < 0)
- return false;
- if (size == 0 || size > NFS3_MAXNAMLEN)
- return false;
- p = xdr_inline_decode(xdr, size);
- if (!p)
- return false;
-
- *len = size;
- *name = (char *)p;
- for (i = 0, c = *name; i < size; i++, c++) {
- if (*c == '\0' || *c == '/')
- return false;
- }
-
- return true;
-}
-
-static bool
-svcxdr_decode_diropargs3(struct xdr_stream *xdr, struct svc_fh *fhp,
- char **name, unsigned int *len)
-{
- return svcxdr_decode_nfs_fh3(xdr, fhp) &&
- svcxdr_decode_filename3(xdr, name, len);
-}
-
static bool
svcxdr_encode_fattr3(struct svc_rqst *rqstp, struct xdr_stream *xdr,
const struct svc_fh *fhp, const struct kstat *stat)
@@ -360,16 +327,6 @@ nfs3svc_decode_fhandleargs(struct svc_rqst *rqstp, struct xdr_stream *xdr)
return svcxdr_decode_nfs_fh3(xdr, &args->fh);
}
-bool
-nfs3svc_decode_linkargs(struct svc_rqst *rqstp, struct xdr_stream *xdr)
-{
- struct nfsd3_linkargs *args = rqstp->rq_argp;
-
- return svcxdr_decode_nfs_fh3(xdr, &args->ffh) &&
- svcxdr_decode_diropargs3(xdr, &args->tfh,
- &args->tname, &args->tlen);
-}
-
bool
nfs3svc_decode_readdirargs(struct svc_rqst *rqstp, struct xdr_stream *xdr)
{
@@ -429,17 +386,6 @@ nfs3svc_decode_commitargs(struct svc_rqst *rqstp, struct xdr_stream *xdr)
* XDR encode functions
*/
-/* LINK */
-bool
-nfs3svc_encode_linkres(struct svc_rqst *rqstp, struct xdr_stream *xdr)
-{
- struct nfsd3_linkres *resp = rqstp->rq_resp;
-
- return svcxdr_encode_nfsstat3(xdr, resp->status) &&
- svcxdr_encode_post_op_attr(rqstp, xdr, &resp->fh) &&
- svcxdr_encode_wcc_data(rqstp, xdr, &resp->tfh);
-}
-
/* READDIR */
bool
nfs3svc_encode_readdirres(struct svc_rqst *rqstp, struct xdr_stream *xdr)
@@ -840,12 +786,3 @@ nfs3svc_release_fhandle(struct svc_rqst *rqstp)
fh_put(&resp->fh);
}
-
-void
-nfs3svc_release_fhandle2(struct svc_rqst *rqstp)
-{
- struct nfsd3_fhandle_pair *resp = rqstp->rq_resp;
-
- fh_put(&resp->fh1);
- fh_put(&resp->fh2);
-}
diff --git a/fs/nfsd/xdr3.h b/fs/nfsd/xdr3.h
index 8a15781d7f3c..9a2bdd5a0da5 100644
--- a/fs/nfsd/xdr3.h
+++ b/fs/nfsd/xdr3.h
@@ -24,13 +24,6 @@ struct nfsd3_accessargs {
__u32 access;
};
-struct nfsd3_linkargs {
- struct svc_fh ffh;
- struct svc_fh tfh;
- char * tname;
- unsigned int tlen;
-};
-
struct nfsd3_readdirargs {
struct svc_fh fh;
__u64 cookie;
@@ -76,12 +69,6 @@ struct nfsd3_writeres {
static_assert(offsetof(struct nfsd3_writeres, xdrgen) == 0);
-struct nfsd3_linkres {
- __be32 status;
- struct svc_fh tfh;
- struct svc_fh fh;
-};
-
struct nfsd3_readdirres {
/* Components of the reply */
__be32 status;
@@ -142,21 +129,12 @@ struct nfsd3_getaclres {
struct kstat stat;
};
-/* dummy type for release */
-struct nfsd3_fhandle_pair {
- __u32 dummy;
- struct svc_fh fh1;
- struct svc_fh fh2;
-};
-
bool nfs3svc_decode_fhandleargs(struct svc_rqst *rqstp, struct xdr_stream *xdr);
-bool nfs3svc_decode_linkargs(struct svc_rqst *rqstp, struct xdr_stream *xdr);
bool nfs3svc_decode_readdirargs(struct svc_rqst *rqstp, struct xdr_stream *xdr);
bool nfs3svc_decode_readdirplusargs(struct svc_rqst *rqstp, struct xdr_stream *xdr);
bool nfs3svc_decode_commitargs(struct svc_rqst *rqstp, struct xdr_stream *xdr);
bool nfs3svc_encode_accessres(struct svc_rqst *rqstp, struct xdr_stream *xdr);
-bool nfs3svc_encode_linkres(struct svc_rqst *rqstp, struct xdr_stream *xdr);
bool nfs3svc_encode_readdirres(struct svc_rqst *rqstp, struct xdr_stream *xdr);
bool nfs3svc_encode_fsstatres(struct svc_rqst *rqstp, struct xdr_stream *xdr);
bool nfs3svc_encode_fsinfores(struct svc_rqst *rqstp, struct xdr_stream *xdr);
@@ -164,7 +142,6 @@ bool nfs3svc_encode_pathconfres(struct svc_rqst *rqstp, struct xdr_stream *xdr);
bool nfs3svc_encode_commitres(struct svc_rqst *rqstp, struct xdr_stream *xdr);
void nfs3svc_release_fhandle(struct svc_rqst *);
-void nfs3svc_release_fhandle2(struct svc_rqst *);
void nfs3svc_encode_cookie3(struct nfsd3_readdirres *resp, u64 offset);
int nfs3svc_encode_entry3(void *data, const char *name, int namlen,
--
2.55.0
^ permalink raw reply related [flat|nested] 10+ messages in thread
* [PATCH v3 23/34] NFSD: Use xdrgen XDR functions for the NFSv3 FSSTAT procedure
2026-10-13 12:49 [PATCH v3 20/34] NFSD: Use xdrgen XDR functions for the NFSv3 RMDIR procedure Chuck Lever
2026-10-13 12:49 ` [PATCH v3 21/34] NFSD: Use xdrgen XDR functions for the NFSv3 RENAME procedure Chuck Lever
2026-10-13 12:49 ` [PATCH v3 22/34] NFSD: Use xdrgen XDR functions for the NFSv3 LINK procedure Chuck Lever
@ 2026-10-13 12:49 ` Chuck Lever
2026-10-13 12:49 ` [PATCH v3 24/34] NFSD: Use xdrgen XDR functions for the NFSv3 FSINFO procedure Chuck Lever
` (5 subsequent siblings)
8 siblings, 0 replies; 10+ messages in thread
From: Chuck Lever @ 2026-10-13 12:49 UTC (permalink / raw)
To: NeilBrown, Jeff Layton, Olga Kornievskaia, Dai Ngo, Tom Talpey; +Cc: linux-nfs
Replace the NFSPROC3_FSSTAT entry in the nfsd_procedures3 array with
an entry that dispatches the xdrgen-generated
nfs_svc_decode_FSSTAT3args and nfs_svc_encode_FSSTAT3res. A wrapper
structure bridges the generated xdrgen argument type and the legacy
svc_fh representation the NFSD VFS layer still uses. The result
wrapper carries a scratch kstatfs alongside the generated FSSTAT3res
type, which nfsd_statfs() fills before nfsd3_proc_fsstat() copies the
values into the encoded result.
The pc_argzero field is now set to zero for the NFSv3 FSSTAT
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.
nfsd3_proc_fsstat() now sets the post-op attributes directly. This
makes it straightforward to confirm that the file handle is released
during every error flow.
nfs3svc_encode_fsstatres() no longer has any callers, so it is
removed, and with it the now-orphaned svcxdr_encode_fsstat3resok()
encode helper.
Signed-off-by: Chuck Lever <cel@kernel.org>
---
fs/nfsd/nfs3proc.c | 71 +++++++++++++++++++++++++++++++++++-----------
fs/nfsd/nfs3xdr.c | 45 -----------------------------
fs/nfsd/xdr3.h | 6 ++--
3 files changed, 57 insertions(+), 65 deletions(-)
diff --git a/fs/nfsd/nfs3proc.c b/fs/nfsd/nfs3proc.c
index 76963187de20..0650bfa960e8 100644
--- a/fs/nfsd/nfs3proc.c
+++ b/fs/nfsd/nfs3proc.c
@@ -193,6 +193,13 @@ struct LINK3args_wrapper {
static_assert(offsetof(struct LINK3args_wrapper, xdrgen) == 0);
+struct FSSTAT3args_wrapper {
+ struct FSSTAT3args xdrgen;
+ struct svc_fh fh;
+};
+
+static_assert(offsetof(struct FSSTAT3args_wrapper, xdrgen) == 0);
+
static int nfsd3_ftype3_to_mode(ftype3 ftype)
{
switch (ftype) {
@@ -1555,18 +1562,47 @@ nfsd3_proc_readdirplus(struct svc_rqst *rqstp)
return rpc_success;
}
-/*
- * Get file system stats
+/**
+ * nfsd3_proc_fsstat - FSSTAT: Get dynamic file system information
+ * @rqstp: RPC transaction context
+ *
+ * Return:
+ * %rpc_success: RPC executed successfully
+ *
+ * RPC synopsis:
+ * FSSTAT3res NFSPROC3_FSSTAT(FSSTAT3args) = 18;
*/
-static __be32
-nfsd3_proc_fsstat(struct svc_rqst *rqstp)
+static __be32 nfsd3_proc_fsstat(struct svc_rqst *rqstp)
{
- struct nfsd_fhandle *argp = rqstp->rq_argp;
+ struct FSSTAT3args_wrapper *argp = rqstp->rq_argp;
struct nfsd3_fsstatres *resp = rqstp->rq_resp;
+ struct kstatfs *statp = &resp->stats;
+ struct svc_fh *fhp = &argp->fh;
- resp->status = nfsd_statfs(rqstp, &argp->fh, &resp->stats, 0);
- fh_put(&argp->fh);
- resp->status = nfsd3_map_status(resp->status);
+ nfsd3_fh3_to_svc_fh(fhp, &argp->xdrgen.fsroot);
+
+ resp->xdrgen.status = nfsd_statfs(rqstp, fhp, statp, 0);
+
+ if (resp->xdrgen.status == nfs_ok) {
+ struct FSSTAT3resok *resok = &resp->xdrgen.u.resok;
+ u64 bs = statp->f_bsize;
+
+ resok->obj_attributes.attributes_follow = false;
+ resok->tbytes = bs * statp->f_blocks;
+ resok->fbytes = bs * statp->f_bfree;
+ resok->abytes = bs * statp->f_bavail;
+ resok->tfiles = statp->f_files;
+ resok->ffiles = statp->f_ffree;
+ resok->afiles = statp->f_ffree;
+ resok->invarsec = 0;
+ } else {
+ struct FSSTAT3resfail *resfail = &resp->xdrgen.u.resfail;
+
+ resp->xdrgen.status = nfsd3_map_status(resp->xdrgen.status);
+ resfail->obj_attributes.attributes_follow = false;
+ }
+
+ fh_put(fhp);
return rpc_success;
}
@@ -1924,15 +1960,15 @@ static const struct svc_procedure nfsd_procedures3[22] = {
.pc_name = "READDIRPLUS",
},
[NFSPROC3_FSSTAT] = {
- .pc_func = nfsd3_proc_fsstat,
- .pc_decode = nfs3svc_decode_fhandleargs,
- .pc_encode = nfs3svc_encode_fsstatres,
- .pc_argsize = sizeof(struct nfsd3_fhandleargs),
- .pc_argzero = sizeof(struct nfsd3_fhandleargs),
- .pc_ressize = sizeof(struct nfsd3_fsstatres),
- .pc_cachetype = RC_NOCACHE,
- .pc_xdrressize = ST+pAT+2*6+1,
- .pc_name = "FSSTAT",
+ .pc_func = nfsd3_proc_fsstat,
+ .pc_decode = nfs_svc_decode_FSSTAT3args,
+ .pc_encode = nfs_svc_encode_FSSTAT3res,
+ .pc_argsize = sizeof(struct FSSTAT3args_wrapper),
+ .pc_argzero = 0,
+ .pc_ressize = sizeof(struct nfsd3_fsstatres),
+ .pc_cachetype = RC_NOCACHE,
+ .pc_xdrressize = NFS3_FSSTAT3res_sz,
+ .pc_name = "FSSTAT",
},
[NFSPROC3_FSINFO] = {
.pc_func = nfsd3_proc_fsinfo,
@@ -2006,6 +2042,7 @@ union nfsd3_xdrstore {
struct READ3res readres;
struct nfsd3_writeres writeres;
struct nfsd3_readdirres readdirres;
+ struct FSSTAT3args_wrapper fsstatargs;
struct nfsd3_fsstatres fsstatres;
struct nfsd3_fsinfores fsinfores;
struct nfsd3_pathconfres pathconfres;
diff --git a/fs/nfsd/nfs3xdr.c b/fs/nfsd/nfs3xdr.c
index 59e89b7f9d19..0ca671bdd1c8 100644
--- a/fs/nfsd/nfs3xdr.c
+++ b/fs/nfsd/nfs3xdr.c
@@ -620,51 +620,6 @@ int nfs3svc_encode_entryplus3(void *data, const char *name, int namlen,
return -EINVAL;
}
-static bool
-svcxdr_encode_fsstat3resok(struct xdr_stream *xdr,
- const struct nfsd3_fsstatres *resp)
-{
- const struct kstatfs *s = &resp->stats;
- u64 bs = s->f_bsize;
- __be32 *p;
-
- p = xdr_reserve_space(xdr, XDR_UNIT * 13);
- if (!p)
- return false;
- p = xdr_encode_hyper(p, bs * s->f_blocks); /* total bytes */
- p = xdr_encode_hyper(p, bs * s->f_bfree); /* free bytes */
- p = xdr_encode_hyper(p, bs * s->f_bavail); /* user available bytes */
- p = xdr_encode_hyper(p, s->f_files); /* total inodes */
- p = xdr_encode_hyper(p, s->f_ffree); /* free inodes */
- p = xdr_encode_hyper(p, s->f_ffree); /* user available inodes */
- *p = cpu_to_be32(resp->invarsec); /* mean unchanged time */
-
- return true;
-}
-
-/* FSSTAT */
-bool
-nfs3svc_encode_fsstatres(struct svc_rqst *rqstp, struct xdr_stream *xdr)
-{
- struct nfsd3_fsstatres *resp = rqstp->rq_resp;
-
- if (!svcxdr_encode_nfsstat3(xdr, resp->status))
- return false;
- switch (resp->status) {
- case nfs_ok:
- if (!svcxdr_encode_post_op_attr(rqstp, xdr, &nfs3svc_null_fh))
- return false;
- if (!svcxdr_encode_fsstat3resok(xdr, resp))
- return false;
- break;
- default:
- if (!svcxdr_encode_post_op_attr(rqstp, xdr, &nfs3svc_null_fh))
- return false;
- }
-
- return true;
-}
-
static bool
svcxdr_encode_fsinfo3resok(struct xdr_stream *xdr,
const struct nfsd3_fsinfores *resp)
diff --git a/fs/nfsd/xdr3.h b/fs/nfsd/xdr3.h
index 9a2bdd5a0da5..577a4beaafc3 100644
--- a/fs/nfsd/xdr3.h
+++ b/fs/nfsd/xdr3.h
@@ -86,11 +86,12 @@ struct nfsd3_readdirres {
};
struct nfsd3_fsstatres {
- __be32 status;
+ struct FSSTAT3res xdrgen;
struct kstatfs stats;
- __u32 invarsec;
};
+static_assert(offsetof(struct nfsd3_fsstatres, xdrgen) == 0);
+
struct nfsd3_fsinfores {
__be32 status;
__u32 f_rtmax;
@@ -136,7 +137,6 @@ bool nfs3svc_decode_commitargs(struct svc_rqst *rqstp, struct xdr_stream *xdr);
bool nfs3svc_encode_accessres(struct svc_rqst *rqstp, struct xdr_stream *xdr);
bool nfs3svc_encode_readdirres(struct svc_rqst *rqstp, struct xdr_stream *xdr);
-bool nfs3svc_encode_fsstatres(struct svc_rqst *rqstp, struct xdr_stream *xdr);
bool nfs3svc_encode_fsinfores(struct svc_rqst *rqstp, struct xdr_stream *xdr);
bool nfs3svc_encode_pathconfres(struct svc_rqst *rqstp, struct xdr_stream *xdr);
bool nfs3svc_encode_commitres(struct svc_rqst *rqstp, struct xdr_stream *xdr);
--
2.55.0
^ permalink raw reply related [flat|nested] 10+ messages in thread
* [PATCH v3 24/34] NFSD: Use xdrgen XDR functions for the NFSv3 FSINFO procedure
2026-10-13 12:49 [PATCH v3 20/34] NFSD: Use xdrgen XDR functions for the NFSv3 RMDIR procedure Chuck Lever
` (2 preceding siblings ...)
2026-10-13 12:49 ` [PATCH v3 23/34] NFSD: Use xdrgen XDR functions for the NFSv3 FSSTAT procedure Chuck Lever
@ 2026-10-13 12:49 ` Chuck Lever
2026-10-13 12:49 ` [PATCH v3 25/34] NFSD: Use xdrgen XDR functions for the NFSv3 PATHCONF procedure Chuck Lever
` (4 subsequent siblings)
8 siblings, 0 replies; 10+ messages in thread
From: Chuck Lever @ 2026-10-13 12:49 UTC (permalink / raw)
To: NeilBrown, Jeff Layton, Olga Kornievskaia, Dai Ngo, Tom Talpey; +Cc: linux-nfs
Replace the NFSPROC3_FSINFO entry in the nfsd_procedures3 array with
an entry that dispatches the xdrgen-generated nfs_svc_decode_FSINFO3args
and nfs_svc_encode_FSINFO3res. A wrapper structure bridges the
generated xdrgen argument type and the legacy svc_fh representation the
NFSD VFS layer still uses.
The pc_argzero field is now set to zero for the NFSv3 FSINFO
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.
nfsd3_proc_fsinfo() now sets the post-op attributes directly. This
makes it straightforward to confirm that the file handle is released
during every error flow.
nfs3svc_encode_fsinfores() no longer has any callers, so it is
removed, and with it the now-orphaned svcxdr_encode_fsinfo3resok()
encode helper and the nfs3svc_time_delta constant it referenced.
Signed-off-by: Chuck Lever <cel@kernel.org>
---
fs/nfsd/nfs3proc.c | 107 +++++++++++++++++++++++++++------------------
fs/nfsd/nfs3xdr.c | 55 -----------------------
fs/nfsd/xdr3.h | 14 ++----
3 files changed, 67 insertions(+), 109 deletions(-)
diff --git a/fs/nfsd/nfs3proc.c b/fs/nfsd/nfs3proc.c
index 0650bfa960e8..ff159d3a0fa6 100644
--- a/fs/nfsd/nfs3proc.c
+++ b/fs/nfsd/nfs3proc.c
@@ -24,9 +24,6 @@
#define NFSDDBG_FACILITY NFSDDBG_PROC
-#define NFS3_FSF_DEFAULT 0x001b
-#define NFS3_FSF_BILLYBOY 0x0018
-
/*
* Wrapper structures combine xdrgen types with legacy structures.
* The xdrgen field must be first so the structure can be cast
@@ -200,6 +197,13 @@ struct FSSTAT3args_wrapper {
static_assert(offsetof(struct FSSTAT3args_wrapper, xdrgen) == 0);
+struct FSINFO3args_wrapper {
+ struct FSINFO3args xdrgen;
+ struct svc_fh fh;
+};
+
+static_assert(offsetof(struct FSINFO3args_wrapper, xdrgen) == 0);
+
static int nfsd3_ftype3_to_mode(ftype3 ftype)
{
switch (ftype) {
@@ -1606,47 +1610,63 @@ static __be32 nfsd3_proc_fsstat(struct svc_rqst *rqstp)
return rpc_success;
}
-/*
- * Get file system info
+/**
+ * nfsd3_proc_fsinfo - FSINFO: Get static file system information
+ * @rqstp: RPC transaction context
+ *
+ * Return:
+ * %rpc_success: RPC executed successfully
+ *
+ * RPC synopsis:
+ * FSINFO3res NFSPROC3_FSINFO(FSINFO3args) = 19;
*/
-static __be32
-nfsd3_proc_fsinfo(struct svc_rqst *rqstp)
+static __be32 nfsd3_proc_fsinfo(struct svc_rqst *rqstp)
{
- struct nfsd_fhandle *argp = rqstp->rq_argp;
+ struct FSINFO3args_wrapper *argp = rqstp->rq_argp;
struct nfsd3_fsinfores *resp = rqstp->rq_resp;
- u32 max_blocksize = svc_max_payload(rqstp);
+ struct svc_fh *fhp = &argp->fh;
- dprintk("nfsd: FSINFO(3) %s\n",
- SVCFH_fmt(&argp->fh));
+ nfsd3_fh3_to_svc_fh(fhp, &argp->xdrgen.fsroot);
- resp->f_rtmax = max_blocksize;
- resp->f_rtpref = max_blocksize;
- resp->f_rtmult = PAGE_SIZE;
- resp->f_wtmax = max_blocksize;
- resp->f_wtpref = max_blocksize;
- resp->f_wtmult = PAGE_SIZE;
- resp->f_dtpref = max_blocksize;
- resp->f_maxfilesize = ~(u32) 0;
- resp->f_properties = NFS3_FSF_DEFAULT;
+ resp->xdrgen.status = fh_verify(rqstp, fhp, 0, NFSD_MAY_NOP |
+ NFSD_MAY_BYPASS_GSS_ON_ROOT);
- resp->status = fh_verify(rqstp, &argp->fh, 0,
- NFSD_MAY_NOP | NFSD_MAY_BYPASS_GSS_ON_ROOT);
+ if (resp->xdrgen.status == nfs_ok) {
+ struct FSINFO3resok *resok = &resp->xdrgen.u.resok;
+ struct super_block *sb = fhp->fh_dentry->d_sb;
+ u32 max_blocksize = svc_max_payload(rqstp);
- /* Check special features of the file system. May request
- * different read/write sizes for file systems known to have
- * problems with large blocks */
- if (resp->status == nfs_ok) {
- struct super_block *sb = argp->fh.fh_dentry->d_sb;
+ resok->obj_attributes.attributes_follow = false;
+ resok->rtmax = max_blocksize;
+ resok->rtpref = max_blocksize;
+ resok->rtmult = PAGE_SIZE;
+ resok->wtmax = max_blocksize;
+ resok->wtpref = max_blocksize;
+ resok->wtmult = PAGE_SIZE;
+ resok->dtpref = max_blocksize;
+ resok->maxfilesize = ~(u32)0;
+ /* NFSD is accurate to the nearest second. */
+ resok->time_delta.seconds = 1;
+ resok->time_delta.nseconds = 0;
+ resok->properties = FSF3_LINK | FSF3_SYMLINK |
+ FSF3_HOMOGENEOUS | FSF3_CANSETTIME;
- /* Note that we don't care for remote fs's here */
- if (sb->s_magic == MSDOS_SUPER_MAGIC) {
- resp->f_properties = NFS3_FSF_BILLYBOY;
- }
- resp->f_maxfilesize = sb->s_maxbytes;
+ /*
+ * Check special features of the file system. May
+ * request different read/write sizes for file systems
+ * known to have problems with large blocks.
+ */
+ if (sb->s_magic == MSDOS_SUPER_MAGIC)
+ resok->properties = FSF3_HOMOGENEOUS | FSF3_CANSETTIME;
+ resok->maxfilesize = sb->s_maxbytes;
+ } else {
+ struct FSINFO3resfail *resfail = &resp->xdrgen.u.resfail;
+
+ resp->xdrgen.status = nfsd3_map_status(resp->xdrgen.status);
+ resfail->obj_attributes.attributes_follow = false;
}
- fh_put(&argp->fh);
- resp->status = nfsd3_map_status(resp->status);
+ fh_put(fhp);
return rpc_success;
}
@@ -1971,15 +1991,15 @@ static const struct svc_procedure nfsd_procedures3[22] = {
.pc_name = "FSSTAT",
},
[NFSPROC3_FSINFO] = {
- .pc_func = nfsd3_proc_fsinfo,
- .pc_decode = nfs3svc_decode_fhandleargs,
- .pc_encode = nfs3svc_encode_fsinfores,
- .pc_argsize = sizeof(struct nfsd3_fhandleargs),
- .pc_argzero = sizeof(struct nfsd3_fhandleargs),
- .pc_ressize = sizeof(struct nfsd3_fsinfores),
- .pc_cachetype = RC_NOCACHE,
- .pc_xdrressize = ST+pAT+12,
- .pc_name = "FSINFO",
+ .pc_func = nfsd3_proc_fsinfo,
+ .pc_decode = nfs_svc_decode_FSINFO3args,
+ .pc_encode = nfs_svc_encode_FSINFO3res,
+ .pc_argsize = sizeof(struct FSINFO3args_wrapper),
+ .pc_argzero = 0,
+ .pc_ressize = sizeof(struct nfsd3_fsinfores),
+ .pc_cachetype = RC_NOCACHE,
+ .pc_xdrressize = NFS3_FSINFO3res_sz,
+ .pc_name = "FSINFO",
},
[NFSPROC3_PATHCONF] = {
.pc_func = nfsd3_proc_pathconf,
@@ -2044,6 +2064,7 @@ union nfsd3_xdrstore {
struct nfsd3_readdirres readdirres;
struct FSSTAT3args_wrapper fsstatargs;
struct nfsd3_fsstatres fsstatres;
+ struct FSINFO3args_wrapper fsinfoargs;
struct nfsd3_fsinfores fsinfores;
struct nfsd3_pathconfres pathconfres;
struct nfsd3_commitres commitres;
diff --git a/fs/nfsd/nfs3xdr.c b/fs/nfsd/nfs3xdr.c
index 0ca671bdd1c8..9e400a97e435 100644
--- a/fs/nfsd/nfs3xdr.c
+++ b/fs/nfsd/nfs3xdr.c
@@ -24,15 +24,6 @@ static const struct svc_fh nfs3svc_null_fh = {
.fh_no_wcc = true,
};
-/*
- * time_delta. {1, 0} means the server is accurate only
- * to the nearest second.
- */
-static const struct timespec64 nfs3svc_time_delta = {
- .tv_sec = 1,
- .tv_nsec = 0,
-};
-
/*
* Mapping of S_IF* types to NFS file types
*/
@@ -620,52 +611,6 @@ int nfs3svc_encode_entryplus3(void *data, const char *name, int namlen,
return -EINVAL;
}
-static bool
-svcxdr_encode_fsinfo3resok(struct xdr_stream *xdr,
- const struct nfsd3_fsinfores *resp)
-{
- __be32 *p;
-
- p = xdr_reserve_space(xdr, XDR_UNIT * 12);
- if (!p)
- return false;
- *p++ = cpu_to_be32(resp->f_rtmax);
- *p++ = cpu_to_be32(resp->f_rtpref);
- *p++ = cpu_to_be32(resp->f_rtmult);
- *p++ = cpu_to_be32(resp->f_wtmax);
- *p++ = cpu_to_be32(resp->f_wtpref);
- *p++ = cpu_to_be32(resp->f_wtmult);
- *p++ = cpu_to_be32(resp->f_dtpref);
- p = xdr_encode_hyper(p, resp->f_maxfilesize);
- p = encode_nfstime3(p, &nfs3svc_time_delta);
- *p = cpu_to_be32(resp->f_properties);
-
- return true;
-}
-
-/* FSINFO */
-bool
-nfs3svc_encode_fsinfores(struct svc_rqst *rqstp, struct xdr_stream *xdr)
-{
- struct nfsd3_fsinfores *resp = rqstp->rq_resp;
-
- if (!svcxdr_encode_nfsstat3(xdr, resp->status))
- return false;
- switch (resp->status) {
- case nfs_ok:
- if (!svcxdr_encode_post_op_attr(rqstp, xdr, &nfs3svc_null_fh))
- return false;
- if (!svcxdr_encode_fsinfo3resok(xdr, resp))
- return false;
- break;
- default:
- if (!svcxdr_encode_post_op_attr(rqstp, xdr, &nfs3svc_null_fh))
- return false;
- }
-
- return true;
-}
-
static bool
svcxdr_encode_pathconf3resok(struct xdr_stream *xdr,
const struct nfsd3_pathconfres *resp)
diff --git a/fs/nfsd/xdr3.h b/fs/nfsd/xdr3.h
index 577a4beaafc3..979b9ea5b86d 100644
--- a/fs/nfsd/xdr3.h
+++ b/fs/nfsd/xdr3.h
@@ -93,18 +93,11 @@ struct nfsd3_fsstatres {
static_assert(offsetof(struct nfsd3_fsstatres, xdrgen) == 0);
struct nfsd3_fsinfores {
- __be32 status;
- __u32 f_rtmax;
- __u32 f_rtpref;
- __u32 f_rtmult;
- __u32 f_wtmax;
- __u32 f_wtpref;
- __u32 f_wtmult;
- __u32 f_dtpref;
- __u64 f_maxfilesize;
- __u32 f_properties;
+ struct FSINFO3res xdrgen;
};
+static_assert(offsetof(struct nfsd3_fsinfores, xdrgen) == 0);
+
struct nfsd3_pathconfres {
__be32 status;
__u32 p_link_max;
@@ -137,7 +130,6 @@ bool nfs3svc_decode_commitargs(struct svc_rqst *rqstp, struct xdr_stream *xdr);
bool nfs3svc_encode_accessres(struct svc_rqst *rqstp, struct xdr_stream *xdr);
bool nfs3svc_encode_readdirres(struct svc_rqst *rqstp, struct xdr_stream *xdr);
-bool nfs3svc_encode_fsinfores(struct svc_rqst *rqstp, struct xdr_stream *xdr);
bool nfs3svc_encode_pathconfres(struct svc_rqst *rqstp, struct xdr_stream *xdr);
bool nfs3svc_encode_commitres(struct svc_rqst *rqstp, struct xdr_stream *xdr);
--
2.55.0
^ permalink raw reply related [flat|nested] 10+ messages in thread
* [PATCH v3 25/34] NFSD: Use xdrgen XDR functions for the NFSv3 PATHCONF procedure
2026-10-13 12:49 [PATCH v3 20/34] NFSD: Use xdrgen XDR functions for the NFSv3 RMDIR procedure Chuck Lever
` (3 preceding siblings ...)
2026-10-13 12:49 ` [PATCH v3 24/34] NFSD: Use xdrgen XDR functions for the NFSv3 FSINFO procedure Chuck Lever
@ 2026-10-13 12:49 ` Chuck Lever
2026-10-13 12:49 ` [PATCH v3 26/34] NFSD: Use xdrgen XDR functions for the NFSv3 COMMIT procedure Chuck Lever
` (3 subsequent siblings)
8 siblings, 0 replies; 10+ messages in thread
From: Chuck Lever @ 2026-10-13 12:49 UTC (permalink / raw)
To: NeilBrown, Jeff Layton, Olga Kornievskaia, Dai Ngo, Tom Talpey; +Cc: linux-nfs
Replace the NFSPROC3_PATHCONF entry in the nfsd_procedures3 array
with an entry that dispatches the xdrgen-generated
nfs_svc_decode_PATHCONF3args and nfs_svc_encode_PATHCONF3res. A
wrapper structure bridges the generated xdrgen argument type and the
legacy svc_fh representation the NFSD VFS layer still uses.
The pc_argzero field is now set to zero for the NFSv3 PATHCONF
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.
nfsd3_proc_pathconf() now sets the post-op attributes directly. This
makes it straightforward to confirm that the file handle is released
during every error flow.
nfs3svc_encode_pathconfres() no longer has any callers, so it is
removed, and with it the now-orphaned svcxdr_encode_pathconf3resok()
encode helper and the nfs3svc_null_fh constant it referenced. This
was also the last user of the shared nfs3svc_decode_fhandleargs()
decoder, so that too is removed.
Signed-off-by: Chuck Lever <cel@kernel.org>
---
fs/nfsd/nfs3proc.c | 94 +++++++++++++++++++++++++++-------------------
fs/nfsd/nfs3xdr.c | 57 ----------------------------
fs/nfsd/xdr3.h | 12 ++----
3 files changed, 59 insertions(+), 104 deletions(-)
diff --git a/fs/nfsd/nfs3proc.c b/fs/nfsd/nfs3proc.c
index ff159d3a0fa6..c1bb9ede4535 100644
--- a/fs/nfsd/nfs3proc.c
+++ b/fs/nfsd/nfs3proc.c
@@ -204,6 +204,13 @@ struct FSINFO3args_wrapper {
static_assert(offsetof(struct FSINFO3args_wrapper, xdrgen) == 0);
+struct PATHCONF3args_wrapper {
+ struct PATHCONF3args xdrgen;
+ struct svc_fh fh;
+};
+
+static_assert(offsetof(struct PATHCONF3args_wrapper, xdrgen) == 0);
+
static int nfsd3_ftype3_to_mode(ftype3 ftype)
{
switch (ftype) {
@@ -1670,40 +1677,47 @@ static __be32 nfsd3_proc_fsinfo(struct svc_rqst *rqstp)
return rpc_success;
}
-/*
- * Get pathconf info for the specified file
+/**
+ * nfsd3_proc_pathconf - PATHCONF: Retrieve POSIX information
+ * @rqstp: RPC transaction context
+ *
+ * Return:
+ * %rpc_success: RPC executed successfully
+ *
+ * RPC synopsis:
+ * PATHCONF3res NFSPROC3_PATHCONF(PATHCONF3args) = 20;
*/
-static __be32
-nfsd3_proc_pathconf(struct svc_rqst *rqstp)
+static __be32 nfsd3_proc_pathconf(struct svc_rqst *rqstp)
{
- struct nfsd_fhandle *argp = rqstp->rq_argp;
+ struct PATHCONF3args_wrapper *argp = rqstp->rq_argp;
struct nfsd3_pathconfres *resp = rqstp->rq_resp;
+ struct svc_fh *fhp = &argp->fh;
- dprintk("nfsd: PATHCONF(3) %s\n",
- SVCFH_fmt(&argp->fh));
+ nfsd3_fh3_to_svc_fh(fhp, &argp->xdrgen.object);
- /* Set default pathconf */
- resp->p_link_max = 255; /* at least */
- resp->p_name_max = 255; /* at least */
- resp->p_no_trunc = 0;
- resp->p_chown_restricted = 1;
- resp->p_case_insensitive = false;
- resp->p_case_preserving = true;
+ resp->xdrgen.status = fh_verify(rqstp, fhp, 0, NFSD_MAY_NOP);
- resp->status = fh_verify(rqstp, &argp->fh, 0, NFSD_MAY_NOP);
-
- if (resp->status == nfs_ok) {
- struct super_block *sb = argp->fh.fh_dentry->d_sb;
+ if (resp->xdrgen.status == nfs_ok) {
+ struct PATHCONF3resok *resok = &resp->xdrgen.u.resok;
+ struct super_block *sb = fhp->fh_dentry->d_sb;
int err;
+ resok->obj_attributes.attributes_follow = false;
+ resok->linkmax = 255;
+ resok->name_max = NAME_MAX;
+ resok->no_trunc = false;
+ resok->chown_restricted = true;
+ resok->case_insensitive = false;
+ resok->case_preserving = true;
+
if (sb->s_magic == EXT2_SUPER_MAGIC) {
- resp->p_link_max = EXT2_LINK_MAX;
- resp->p_name_max = EXT2_NAME_LEN;
+ resok->linkmax = EXT2_LINK_MAX;
+ resok->name_max = EXT2_NAME_LEN;
}
- err = nfsd_get_case_info(argp->fh.fh_dentry,
- &resp->p_case_insensitive,
- &resp->p_case_preserving);
+ err = nfsd_get_case_info(fhp->fh_dentry,
+ &resok->case_insensitive,
+ &resok->case_preserving);
/*
* RFC 1813 lists NFS3ERR_STALE, NFS3ERR_BADHANDLE, and
* NFS3ERR_SERVERFAULT as the only PATHCONF errors.
@@ -1720,19 +1734,23 @@ nfsd3_proc_pathconf(struct svc_rqst *rqstp)
* handle is unusable without implying a server
* malfunction.
*/
- resp->status = nfserr_stale;
+ resp->xdrgen.status = nfserr_stale;
break;
case -ESTALE:
- resp->status = nfserr_stale;
+ resp->xdrgen.status = nfserr_stale;
break;
default:
- resp->status = nfserr_serverfault;
+ resp->xdrgen.status = nfserr_serverfault;
break;
}
+ } else {
+ struct PATHCONF3resfail *resfail = &resp->xdrgen.u.resfail;
+
+ resp->xdrgen.status = nfsd3_map_status(resp->xdrgen.status);
+ resfail->obj_attributes.attributes_follow = false;
}
- fh_put(&argp->fh);
- resp->status = nfsd3_map_status(resp->status);
+ fh_put(fhp);
return rpc_success;
}
@@ -1770,7 +1788,6 @@ nfsd3_proc_commit(struct svc_rqst *rqstp)
* Only the results of non-idempotent operations are cached.
*/
#define nfsd3_readdirplusargs nfsd3_readdirargs
-#define nfsd3_fhandleargs nfsd_fhandle
#define ST 1 /* status*/
#define AT 21 /* attributes */
@@ -2002,15 +2019,15 @@ static const struct svc_procedure nfsd_procedures3[22] = {
.pc_name = "FSINFO",
},
[NFSPROC3_PATHCONF] = {
- .pc_func = nfsd3_proc_pathconf,
- .pc_decode = nfs3svc_decode_fhandleargs,
- .pc_encode = nfs3svc_encode_pathconfres,
- .pc_argsize = sizeof(struct nfsd3_fhandleargs),
- .pc_argzero = sizeof(struct nfsd3_fhandleargs),
- .pc_ressize = sizeof(struct nfsd3_pathconfres),
- .pc_cachetype = RC_NOCACHE,
- .pc_xdrressize = ST+pAT+6,
- .pc_name = "PATHCONF",
+ .pc_func = nfsd3_proc_pathconf,
+ .pc_decode = nfs_svc_decode_PATHCONF3args,
+ .pc_encode = nfs_svc_encode_PATHCONF3res,
+ .pc_argsize = sizeof(struct PATHCONF3args_wrapper),
+ .pc_argzero = 0,
+ .pc_ressize = sizeof(struct nfsd3_pathconfres),
+ .pc_cachetype = RC_NOCACHE,
+ .pc_xdrressize = NFS3_PATHCONF3res_sz,
+ .pc_name = "PATHCONF",
},
[NFSPROC3_COMMIT] = {
.pc_func = nfsd3_proc_commit,
@@ -2066,6 +2083,7 @@ union nfsd3_xdrstore {
struct nfsd3_fsstatres fsstatres;
struct FSINFO3args_wrapper fsinfoargs;
struct nfsd3_fsinfores fsinfores;
+ struct PATHCONF3args_wrapper pathconfargs;
struct nfsd3_pathconfres pathconfres;
struct nfsd3_commitres commitres;
struct nfsd3_getaclres getaclres;
diff --git a/fs/nfsd/nfs3xdr.c b/fs/nfsd/nfs3xdr.c
index 9e400a97e435..3da66b5cac22 100644
--- a/fs/nfsd/nfs3xdr.c
+++ b/fs/nfsd/nfs3xdr.c
@@ -17,13 +17,6 @@
#include "vfs.h"
#include "nfserr.h"
-/*
- * Force construction of an empty post-op attr
- */
-static const struct svc_fh nfs3svc_null_fh = {
- .fh_no_wcc = true,
-};
-
/*
* Mapping of S_IF* types to NFS file types
*/
@@ -310,14 +303,6 @@ svcxdr_encode_wcc_data(struct svc_rqst *rqstp, struct xdr_stream *xdr,
* XDR decode functions
*/
-bool
-nfs3svc_decode_fhandleargs(struct svc_rqst *rqstp, struct xdr_stream *xdr)
-{
- struct nfsd_fhandle *args = rqstp->rq_argp;
-
- return svcxdr_decode_nfs_fh3(xdr, &args->fh);
-}
-
bool
nfs3svc_decode_readdirargs(struct svc_rqst *rqstp, struct xdr_stream *xdr)
{
@@ -611,48 +596,6 @@ int nfs3svc_encode_entryplus3(void *data, const char *name, int namlen,
return -EINVAL;
}
-static bool
-svcxdr_encode_pathconf3resok(struct xdr_stream *xdr,
- const struct nfsd3_pathconfres *resp)
-{
- __be32 *p;
-
- p = xdr_reserve_space(xdr, XDR_UNIT * 6);
- if (!p)
- return false;
- *p++ = cpu_to_be32(resp->p_link_max);
- *p++ = cpu_to_be32(resp->p_name_max);
- p = xdr_encode_bool(p, resp->p_no_trunc);
- p = xdr_encode_bool(p, resp->p_chown_restricted);
- p = xdr_encode_bool(p, resp->p_case_insensitive);
- xdr_encode_bool(p, resp->p_case_preserving);
-
- return true;
-}
-
-/* PATHCONF */
-bool
-nfs3svc_encode_pathconfres(struct svc_rqst *rqstp, struct xdr_stream *xdr)
-{
- struct nfsd3_pathconfres *resp = rqstp->rq_resp;
-
- if (!svcxdr_encode_nfsstat3(xdr, resp->status))
- return false;
- switch (resp->status) {
- case nfs_ok:
- if (!svcxdr_encode_post_op_attr(rqstp, xdr, &nfs3svc_null_fh))
- return false;
- if (!svcxdr_encode_pathconf3resok(xdr, resp))
- return false;
- break;
- default:
- if (!svcxdr_encode_post_op_attr(rqstp, xdr, &nfs3svc_null_fh))
- return false;
- }
-
- return true;
-}
-
/* COMMIT */
bool
nfs3svc_encode_commitres(struct svc_rqst *rqstp, struct xdr_stream *xdr)
diff --git a/fs/nfsd/xdr3.h b/fs/nfsd/xdr3.h
index 979b9ea5b86d..6428d9a190b0 100644
--- a/fs/nfsd/xdr3.h
+++ b/fs/nfsd/xdr3.h
@@ -99,15 +99,11 @@ struct nfsd3_fsinfores {
static_assert(offsetof(struct nfsd3_fsinfores, xdrgen) == 0);
struct nfsd3_pathconfres {
- __be32 status;
- __u32 p_link_max;
- __u32 p_name_max;
- __u32 p_no_trunc;
- __u32 p_chown_restricted;
- bool p_case_insensitive;
- bool p_case_preserving;
+ struct PATHCONF3res xdrgen;
};
+static_assert(offsetof(struct nfsd3_pathconfres, xdrgen) == 0);
+
struct nfsd3_commitres {
__be32 status;
struct svc_fh fh;
@@ -123,14 +119,12 @@ struct nfsd3_getaclres {
struct kstat stat;
};
-bool nfs3svc_decode_fhandleargs(struct svc_rqst *rqstp, struct xdr_stream *xdr);
bool nfs3svc_decode_readdirargs(struct svc_rqst *rqstp, struct xdr_stream *xdr);
bool nfs3svc_decode_readdirplusargs(struct svc_rqst *rqstp, struct xdr_stream *xdr);
bool nfs3svc_decode_commitargs(struct svc_rqst *rqstp, struct xdr_stream *xdr);
bool nfs3svc_encode_accessres(struct svc_rqst *rqstp, struct xdr_stream *xdr);
bool nfs3svc_encode_readdirres(struct svc_rqst *rqstp, struct xdr_stream *xdr);
-bool nfs3svc_encode_pathconfres(struct svc_rqst *rqstp, struct xdr_stream *xdr);
bool nfs3svc_encode_commitres(struct svc_rqst *rqstp, struct xdr_stream *xdr);
void nfs3svc_release_fhandle(struct svc_rqst *);
--
2.55.0
^ permalink raw reply related [flat|nested] 10+ messages in thread
* [PATCH v3 26/34] NFSD: Use xdrgen XDR functions for the NFSv3 COMMIT procedure
2026-10-13 12:49 [PATCH v3 20/34] NFSD: Use xdrgen XDR functions for the NFSv3 RMDIR procedure Chuck Lever
` (4 preceding siblings ...)
2026-10-13 12:49 ` [PATCH v3 25/34] NFSD: Use xdrgen XDR functions for the NFSv3 PATHCONF procedure Chuck Lever
@ 2026-10-13 12:49 ` Chuck Lever
2026-10-13 12:49 ` [PATCH v3 27/34] NFSD: Use xdrgen XDR functions for NFSv3 READDIR arguments Chuck Lever
` (2 subsequent siblings)
8 siblings, 0 replies; 10+ messages in thread
From: Chuck Lever @ 2026-10-13 12:49 UTC (permalink / raw)
To: NeilBrown, Jeff Layton, Olga Kornievskaia, Dai Ngo, Tom Talpey; +Cc: linux-nfs
Replace the NFSPROC3_COMMIT entry in the nfsd_procedures3 array with
an entry that dispatches the xdrgen-generated
nfs_svc_decode_COMMIT3args and nfs_svc_encode_COMMIT3res. A wrapper
structure bridges the generated xdrgen argument type and the legacy
svc_fh representation the NFSD VFS layer still uses.
The pc_argzero field is now set to zero for the NFSv3 COMMIT
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.
Because nfsd3_proc_commit() now fills in the WCC data, including
both the pre-op and post-op attributes, the fh_getattr() calls are
made in the proc function rather than in the XDR result encoder, and
the reference to the file handle can be released directly by
nfsd3_proc_commit(). A separate ->pc_release callback is thus no
longer needed. This makes it straightforward to confirm that the
file handle is properly released during every error flow.
nfs3svc_decode_commitargs() and nfs3svc_encode_commitres() no longer
have any callers, so they are removed. COMMIT was the last caller of
the hand-written WCC encoders, so svcxdr_encode_wcc_data() and its
svcxdr_encode_pre_op_attr() and svcxdr_encode_wcc_attr() helpers are
removed as well, along with the now-orphaned svcxdr_encode_writeverf3()
encode helper.
Signed-off-by: Chuck Lever <cel@kernel.org>
---
fs/nfsd/nfs3proc.c | 80 +++++++++++++++++++-------------
fs/nfsd/nfs3xdr.c | 113 ---------------------------------------------
fs/nfsd/xdr3.h | 14 ++----
3 files changed, 52 insertions(+), 155 deletions(-)
diff --git a/fs/nfsd/nfs3proc.c b/fs/nfsd/nfs3proc.c
index c1bb9ede4535..7a03c9ed8fbd 100644
--- a/fs/nfsd/nfs3proc.c
+++ b/fs/nfsd/nfs3proc.c
@@ -211,6 +211,13 @@ struct PATHCONF3args_wrapper {
static_assert(offsetof(struct PATHCONF3args_wrapper, xdrgen) == 0);
+struct COMMIT3args_wrapper {
+ struct COMMIT3args xdrgen;
+ struct svc_fh fh;
+};
+
+static_assert(offsetof(struct COMMIT3args_wrapper, xdrgen) == 0);
+
static int nfsd3_ftype3_to_mode(ftype3 ftype)
{
switch (ftype) {
@@ -1754,31 +1761,47 @@ static __be32 nfsd3_proc_pathconf(struct svc_rqst *rqstp)
return rpc_success;
}
-/*
- * Commit a file (range) to stable storage.
+/**
+ * nfsd3_proc_commit - COMMIT: Commit cached data on a server to stable storage
+ * @rqstp: RPC transaction context
+ *
+ * Return:
+ * %rpc_success: RPC executed successfully
+ *
+ * RPC synopsis:
+ * COMMIT3res NFSPROC3_COMMIT(COMMIT3args) = 21;
*/
-static __be32
-nfsd3_proc_commit(struct svc_rqst *rqstp)
+static __be32 nfsd3_proc_commit(struct svc_rqst *rqstp)
{
- struct nfsd3_commitargs *argp = rqstp->rq_argp;
+ struct COMMIT3args_wrapper *argp = rqstp->rq_argp;
struct nfsd3_commitres *resp = rqstp->rq_resp;
+ struct svc_fh *fhp = &argp->fh;
struct nfsd_file *nf;
- dprintk("nfsd: COMMIT(3) %s %u@%Lu\n",
- SVCFH_fmt(&argp->fh),
- argp->count,
- (unsigned long long) argp->offset);
+ nfsd3_fh3_to_svc_fh(fhp, &argp->xdrgen.file);
- fh_copy(&resp->fh, &argp->fh);
- resp->status = nfsd_file_acquire_gc(rqstp, &resp->fh, NFSD_MAY_WRITE |
- NFSD_MAY_NOT_BREAK_LEASE, &nf);
- if (resp->status)
+ resp->xdrgen.status = nfsd_file_acquire_gc(rqstp, fhp, NFSD_MAY_WRITE |
+ NFSD_MAY_NOT_BREAK_LEASE, &nf);
+ if (resp->xdrgen.status)
goto out;
- resp->status = nfsd_commit(rqstp, &resp->fh, nf, argp->offset,
- argp->count, resp->verf);
+ resp->xdrgen.status = nfsd_commit(rqstp, fhp, nf,
+ argp->xdrgen.offset, argp->xdrgen.count,
+ (__be32 *)resp->xdrgen.u.resok.verf);
nfsd_file_put(nf);
+
out:
- resp->status = nfsd3_map_status(resp->status);
+ if (resp->xdrgen.status == nfs_ok) {
+ struct COMMIT3resok *resok = &resp->xdrgen.u.resok;
+
+ nfsd3_fill_wcc_data(rqstp, &resok->file_wcc, fhp);
+ } else {
+ struct COMMIT3resfail *resfail = &resp->xdrgen.u.resfail;
+
+ resp->xdrgen.status = nfsd3_map_status(resp->xdrgen.status);
+ nfsd3_fill_wcc_data(rqstp, &resfail->file_wcc, fhp);
+ }
+
+ fh_put(fhp);
return rpc_success;
}
@@ -1789,11 +1812,6 @@ nfsd3_proc_commit(struct svc_rqst *rqstp)
*/
#define nfsd3_readdirplusargs nfsd3_readdirargs
-#define ST 1 /* status*/
-#define AT 21 /* attributes */
-#define pAT (1+AT) /* post attributes - conditional */
-#define WC (7+pAT) /* WCC attributes */
-
static const struct svc_procedure nfsd_procedures3[22] = {
[NFSPROC3_NULL] = {
.pc_func = nfsd3_proc_null,
@@ -2030,16 +2048,15 @@ static const struct svc_procedure nfsd_procedures3[22] = {
.pc_name = "PATHCONF",
},
[NFSPROC3_COMMIT] = {
- .pc_func = nfsd3_proc_commit,
- .pc_decode = nfs3svc_decode_commitargs,
- .pc_encode = nfs3svc_encode_commitres,
- .pc_release = nfs3svc_release_fhandle,
- .pc_argsize = sizeof(struct nfsd3_commitargs),
- .pc_argzero = sizeof(struct nfsd3_commitargs),
- .pc_ressize = sizeof(struct nfsd3_commitres),
- .pc_cachetype = RC_NOCACHE,
- .pc_xdrressize = ST+WC+2,
- .pc_name = "COMMIT",
+ .pc_func = nfsd3_proc_commit,
+ .pc_decode = nfs_svc_decode_COMMIT3args,
+ .pc_encode = nfs_svc_encode_COMMIT3res,
+ .pc_argsize = sizeof(struct COMMIT3args_wrapper),
+ .pc_argzero = 0,
+ .pc_ressize = sizeof(struct nfsd3_commitres),
+ .pc_cachetype = RC_NOCACHE,
+ .pc_xdrressize = NFS3_COMMIT3res_sz,
+ .pc_name = "COMMIT",
},
};
@@ -2085,6 +2102,7 @@ union nfsd3_xdrstore {
struct nfsd3_fsinfores fsinfores;
struct PATHCONF3args_wrapper pathconfargs;
struct nfsd3_pathconfres pathconfres;
+ struct COMMIT3args_wrapper commitargs;
struct nfsd3_commitres commitres;
struct nfsd3_getaclres getaclres;
};
diff --git a/fs/nfsd/nfs3xdr.c b/fs/nfsd/nfs3xdr.c
index 3da66b5cac22..e93983d08aa5 100644
--- a/fs/nfsd/nfs3xdr.c
+++ b/fs/nfsd/nfs3xdr.c
@@ -133,19 +133,6 @@ svcxdr_encode_cookieverf3(struct xdr_stream *xdr, const __be32 *verf)
return true;
}
-static bool
-svcxdr_encode_writeverf3(struct xdr_stream *xdr, const __be32 *verf)
-{
- __be32 *p;
-
- p = xdr_reserve_space(xdr, NFS3_WRITEVERFSIZE);
- if (!p)
- return false;
- memcpy(p, verf, NFS3_WRITEVERFSIZE);
-
- return true;
-}
-
static bool
svcxdr_encode_fattr3(struct svc_rqst *rqstp, struct xdr_stream *xdr,
const struct svc_fh *fhp, const struct kstat *stat)
@@ -198,35 +185,6 @@ svcxdr_encode_fattr3(struct svc_rqst *rqstp, struct xdr_stream *xdr,
return true;
}
-static bool
-svcxdr_encode_wcc_attr(struct xdr_stream *xdr, const struct svc_fh *fhp)
-{
- __be32 *p;
-
- p = xdr_reserve_space(xdr, XDR_UNIT * 6);
- if (!p)
- return false;
- p = xdr_encode_hyper(p, (u64)fhp->fh_pre_size);
- p = encode_nfstime3(p, &fhp->fh_pre_mtime);
- encode_nfstime3(p, &fhp->fh_pre_ctime);
-
- return true;
-}
-
-static bool
-svcxdr_encode_pre_op_attr(struct xdr_stream *xdr, const struct svc_fh *fhp)
-{
- if (!fhp->fh_pre_saved) {
- if (xdr_stream_encode_item_absent(xdr) < 0)
- return false;
- return true;
- }
-
- if (xdr_stream_encode_item_present(xdr) < 0)
- return false;
- return svcxdr_encode_wcc_attr(xdr, fhp);
-}
-
/**
* svcxdr_encode_post_op_attr - Encode NFSv3 post-op attributes
* @rqstp: Context of a completed RPC transaction
@@ -266,39 +224,6 @@ svcxdr_encode_post_op_attr(struct svc_rqst *rqstp, struct xdr_stream *xdr,
return xdr_stream_encode_item_absent(xdr) > 0;
}
-/*
- * Encode weak cache consistency data
- */
-static bool
-svcxdr_encode_wcc_data(struct svc_rqst *rqstp, struct xdr_stream *xdr,
- const struct svc_fh *fhp)
-{
- struct dentry *dentry = fhp->fh_dentry;
-
- if (!dentry || !d_really_is_positive(dentry) || !fhp->fh_post_saved)
- goto neither;
-
- /* before */
- if (!svcxdr_encode_pre_op_attr(xdr, fhp))
- return false;
-
- /* after */
- if (xdr_stream_encode_item_present(xdr) < 0)
- return false;
- if (!svcxdr_encode_fattr3(rqstp, xdr, fhp, &fhp->fh_post_attr))
- return false;
-
- return true;
-
-neither:
- if (xdr_stream_encode_item_absent(xdr) < 0)
- return false;
- if (!svcxdr_encode_post_op_attr(rqstp, xdr, fhp))
- return false;
-
- return true;
-}
-
/*
* XDR decode functions
*/
@@ -343,21 +268,6 @@ nfs3svc_decode_readdirplusargs(struct svc_rqst *rqstp, struct xdr_stream *xdr)
return true;
}
-bool
-nfs3svc_decode_commitargs(struct svc_rqst *rqstp, struct xdr_stream *xdr)
-{
- struct nfsd3_commitargs *args = rqstp->rq_argp;
-
- if (!svcxdr_decode_nfs_fh3(xdr, &args->fh))
- return false;
- if (xdr_stream_decode_u64(xdr, &args->offset) < 0)
- return false;
- if (xdr_stream_decode_u32(xdr, &args->count) < 0)
- return false;
-
- return true;
-}
-
/*
* XDR encode functions
*/
@@ -596,29 +506,6 @@ int nfs3svc_encode_entryplus3(void *data, const char *name, int namlen,
return -EINVAL;
}
-/* COMMIT */
-bool
-nfs3svc_encode_commitres(struct svc_rqst *rqstp, struct xdr_stream *xdr)
-{
- struct nfsd3_commitres *resp = rqstp->rq_resp;
-
- if (!svcxdr_encode_nfsstat3(xdr, resp->status))
- return false;
- switch (resp->status) {
- case nfs_ok:
- if (!svcxdr_encode_wcc_data(rqstp, xdr, &resp->fh))
- return false;
- if (!svcxdr_encode_writeverf3(xdr, resp->verf))
- return false;
- break;
- default:
- if (!svcxdr_encode_wcc_data(rqstp, xdr, &resp->fh))
- return false;
- }
-
- return true;
-}
-
/*
* XDR release functions
*/
diff --git a/fs/nfsd/xdr3.h b/fs/nfsd/xdr3.h
index 6428d9a190b0..e2110f9a126b 100644
--- a/fs/nfsd/xdr3.h
+++ b/fs/nfsd/xdr3.h
@@ -31,12 +31,6 @@ struct nfsd3_readdirargs {
__be32 * verf;
};
-struct nfsd3_commitargs {
- struct svc_fh fh;
- __u64 offset;
- __u32 count;
-};
-
struct nfsd3_getaclargs {
struct svc_fh fh;
__u32 mask;
@@ -105,11 +99,11 @@ struct nfsd3_pathconfres {
static_assert(offsetof(struct nfsd3_pathconfres, xdrgen) == 0);
struct nfsd3_commitres {
- __be32 status;
- struct svc_fh fh;
- __be32 verf[2];
+ struct COMMIT3res xdrgen;
};
+static_assert(offsetof(struct nfsd3_commitres, xdrgen) == 0);
+
struct nfsd3_getaclres {
__be32 status;
struct svc_fh fh;
@@ -121,11 +115,9 @@ struct nfsd3_getaclres {
bool nfs3svc_decode_readdirargs(struct svc_rqst *rqstp, struct xdr_stream *xdr);
bool nfs3svc_decode_readdirplusargs(struct svc_rqst *rqstp, struct xdr_stream *xdr);
-bool nfs3svc_decode_commitargs(struct svc_rqst *rqstp, struct xdr_stream *xdr);
bool nfs3svc_encode_accessres(struct svc_rqst *rqstp, struct xdr_stream *xdr);
bool nfs3svc_encode_readdirres(struct svc_rqst *rqstp, struct xdr_stream *xdr);
-bool nfs3svc_encode_commitres(struct svc_rqst *rqstp, struct xdr_stream *xdr);
void nfs3svc_release_fhandle(struct svc_rqst *);
--
2.55.0
^ permalink raw reply related [flat|nested] 10+ messages in thread
* [PATCH v3 27/34] NFSD: Use xdrgen XDR functions for NFSv3 READDIR arguments
2026-10-13 12:49 [PATCH v3 20/34] NFSD: Use xdrgen XDR functions for the NFSv3 RMDIR procedure Chuck Lever
` (5 preceding siblings ...)
2026-10-13 12:49 ` [PATCH v3 26/34] NFSD: Use xdrgen XDR functions for the NFSv3 COMMIT procedure Chuck Lever
@ 2026-10-13 12:49 ` Chuck Lever
2026-10-13 12:49 ` [PATCH v3 28/34] NFSD: Use xdrgen XDR functions for NFSv3 READDIRPLUS arguments Chuck Lever
2026-10-13 12:49 ` [PATCH v3 29/34] NFSD: Refactor NFSv3 directory cookie encoding Chuck Lever
8 siblings, 0 replies; 10+ messages in thread
From: Chuck Lever @ 2026-10-13 12:49 UTC (permalink / raw)
To: NeilBrown, Jeff Layton, Olga Kornievskaia, Dai Ngo, Tom Talpey; +Cc: linux-nfs
Replace the NFSPROC3_READDIR entry in the nfsd_procedures3 array
with an entry that dispatches the xdrgen-generated
nfs_svc_decode_READDIR3args. A wrapper structure bridges the
generated xdrgen READDIR3args type and the legacy svc_fh
representation the NFSD VFS layer still uses.
The pc_argzero field is now set to zero for the NFSv3 READDIR
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.
nfs3svc_decode_readdirargs() no longer has any callers, so it is
removed.
Signed-off-by: Chuck Lever <cel@kernel.org>
---
fs/nfsd/nfs3proc.c | 59 +++++++++++++++++++++++++++++-----------------
fs/nfsd/nfs3xdr.c | 18 --------------
fs/nfsd/xdr3.h | 1 -
3 files changed, 37 insertions(+), 41 deletions(-)
diff --git a/fs/nfsd/nfs3proc.c b/fs/nfsd/nfs3proc.c
index 7a03c9ed8fbd..1764cd5e562d 100644
--- a/fs/nfsd/nfs3proc.c
+++ b/fs/nfsd/nfs3proc.c
@@ -218,6 +218,13 @@ struct COMMIT3args_wrapper {
static_assert(offsetof(struct COMMIT3args_wrapper, xdrgen) == 0);
+struct READDIR3args_wrapper {
+ struct READDIR3args xdrgen;
+ struct svc_fh fh;
+};
+
+static_assert(offsetof(struct READDIR3args_wrapper, xdrgen) == 0);
+
static int nfsd3_ftype3_to_mode(ftype3 ftype)
{
switch (ftype) {
@@ -1506,28 +1513,35 @@ static void nfsd3_init_dirlist_pages(struct svc_rqst *rqstp,
xdr_init_encode_pages(xdr, buf);
}
-/*
- * Read a portion of a directory.
+/**
+ * nfsd3_proc_readdir - READDIR: Read from directory
+ * @rqstp: RPC transaction context
+ *
+ * Return:
+ * %rpc_success: RPC executed successfully
+ *
+ * RPC synopsis:
+ * READDIR3res NFSPROC3_READDIR(READDIR3args) = 16;
*/
-static __be32
-nfsd3_proc_readdir(struct svc_rqst *rqstp)
+static __be32 nfsd3_proc_readdir(struct svc_rqst *rqstp)
{
- struct nfsd3_readdirargs *argp = rqstp->rq_argp;
+ struct READDIR3args_wrapper *argp = rqstp->rq_argp;
struct nfsd3_readdirres *resp = rqstp->rq_resp;
- loff_t offset;
+ loff_t offset = argp->xdrgen.cookie;
+ struct svc_fh *fhp = &argp->fh;
- trace_nfsd_vfs_readdir(rqstp, &argp->fh, argp->count, argp->cookie);
+ nfsd3_fh3_to_svc_fh(fhp, &argp->xdrgen.dir);
+ trace_nfsd_vfs_readdir(rqstp, fhp, argp->xdrgen.count,
+ argp->xdrgen.cookie);
- nfsd3_init_dirlist_pages(rqstp, resp, argp->count);
-
- fh_copy(&resp->fh, &argp->fh);
+ nfsd3_init_dirlist_pages(rqstp, resp, argp->xdrgen.count);
+ fh_copy(&resp->fh, fhp);
resp->common.err = nfs_ok;
resp->cookie_offset = 0;
resp->rqstp = rqstp;
- offset = argp->cookie;
resp->status = nfsd_readdir(rqstp, &resp->fh, &offset,
&resp->common, nfs3svc_encode_entry3);
- memcpy(resp->verf, argp->verf, 8);
+ memcpy(resp->verf, argp->xdrgen.cookieverf, NFS3_COOKIEVERFSIZE);
nfs3svc_encode_cookie3(resp, offset);
/* Recycle only pages that were part of the reply */
@@ -1993,15 +2007,15 @@ static const struct svc_procedure nfsd_procedures3[22] = {
.pc_name = "LINK",
},
[NFSPROC3_READDIR] = {
- .pc_func = nfsd3_proc_readdir,
- .pc_decode = nfs3svc_decode_readdirargs,
- .pc_encode = nfs3svc_encode_readdirres,
- .pc_release = nfs3svc_release_fhandle,
- .pc_argsize = sizeof(struct nfsd3_readdirargs),
- .pc_argzero = sizeof(struct nfsd3_readdirargs),
- .pc_ressize = sizeof(struct nfsd3_readdirres),
- .pc_cachetype = RC_NOCACHE,
- .pc_name = "READDIR",
+ .pc_func = nfsd3_proc_readdir,
+ .pc_decode = nfs_svc_decode_READDIR3args,
+ .pc_encode = nfs3svc_encode_readdirres,
+ .pc_release = nfs3svc_release_fhandle,
+ .pc_argsize = sizeof(struct READDIR3args_wrapper),
+ .pc_argzero = 0,
+ .pc_ressize = sizeof(struct nfsd3_readdirres),
+ .pc_cachetype = RC_NOCACHE,
+ .pc_name = "READDIR",
},
[NFSPROC3_READDIRPLUS] = {
.pc_func = nfsd3_proc_readdirplus,
@@ -2091,7 +2105,8 @@ union nfsd3_xdrstore {
struct RENAME3res renameres;
struct LINK3args_wrapper linkargs;
struct LINK3res linkres;
- struct nfsd3_readdirargs readdirargs;
+ struct READDIR3args_wrapper readdirargs;
+ struct nfsd3_readdirargs readdirplusargs;
struct READLINK3res readlinkres;
struct READ3res readres;
struct nfsd3_writeres writeres;
diff --git a/fs/nfsd/nfs3xdr.c b/fs/nfsd/nfs3xdr.c
index e93983d08aa5..0e83a2245c45 100644
--- a/fs/nfsd/nfs3xdr.c
+++ b/fs/nfsd/nfs3xdr.c
@@ -228,24 +228,6 @@ svcxdr_encode_post_op_attr(struct svc_rqst *rqstp, struct xdr_stream *xdr,
* XDR decode functions
*/
-bool
-nfs3svc_decode_readdirargs(struct svc_rqst *rqstp, struct xdr_stream *xdr)
-{
- struct nfsd3_readdirargs *args = rqstp->rq_argp;
-
- if (!svcxdr_decode_nfs_fh3(xdr, &args->fh))
- return false;
- if (xdr_stream_decode_u64(xdr, &args->cookie) < 0)
- return false;
- args->verf = xdr_inline_decode(xdr, NFS3_COOKIEVERFSIZE);
- if (!args->verf)
- return false;
- if (xdr_stream_decode_u32(xdr, &args->count) < 0)
- return false;
-
- return true;
-}
-
bool
nfs3svc_decode_readdirplusargs(struct svc_rqst *rqstp, struct xdr_stream *xdr)
{
diff --git a/fs/nfsd/xdr3.h b/fs/nfsd/xdr3.h
index e2110f9a126b..3fb4a01011ca 100644
--- a/fs/nfsd/xdr3.h
+++ b/fs/nfsd/xdr3.h
@@ -113,7 +113,6 @@ struct nfsd3_getaclres {
struct kstat stat;
};
-bool nfs3svc_decode_readdirargs(struct svc_rqst *rqstp, struct xdr_stream *xdr);
bool nfs3svc_decode_readdirplusargs(struct svc_rqst *rqstp, struct xdr_stream *xdr);
bool nfs3svc_encode_accessres(struct svc_rqst *rqstp, struct xdr_stream *xdr);
--
2.55.0
^ permalink raw reply related [flat|nested] 10+ messages in thread
* [PATCH v3 28/34] NFSD: Use xdrgen XDR functions for NFSv3 READDIRPLUS arguments
2026-10-13 12:49 [PATCH v3 20/34] NFSD: Use xdrgen XDR functions for the NFSv3 RMDIR procedure Chuck Lever
` (6 preceding siblings ...)
2026-10-13 12:49 ` [PATCH v3 27/34] NFSD: Use xdrgen XDR functions for NFSv3 READDIR arguments Chuck Lever
@ 2026-10-13 12:49 ` Chuck Lever
2026-10-13 12:49 ` [PATCH v3 29/34] NFSD: Refactor NFSv3 directory cookie encoding Chuck Lever
8 siblings, 0 replies; 10+ messages in thread
From: Chuck Lever @ 2026-10-13 12:49 UTC (permalink / raw)
To: NeilBrown, Jeff Layton, Olga Kornievskaia, Dai Ngo, Tom Talpey; +Cc: linux-nfs
Replace the NFSPROC3_READDIRPLUS entry in the nfsd_procedures3 array
with an entry that dispatches the xdrgen-generated
nfs_svc_decode_READDIRPLUS3args. A wrapper structure bridges the
generated xdrgen READDIRPLUS3args type and the legacy svc_fh
representation the NFSD VFS layer still uses.
The pc_argzero field is now set to zero for the NFSv3 READDIRPLUS
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.
nfs3svc_decode_readdirplusargs() no longer has any callers, so it
is removed.
Signed-off-by: Chuck Lever <cel@kernel.org>
---
fs/nfsd/nfs3proc.c | 62 +++++++++++++++++++++++++++-------------------
fs/nfsd/nfs3xdr.c | 26 -------------------
fs/nfsd/xdr3.h | 9 -------
3 files changed, 36 insertions(+), 61 deletions(-)
diff --git a/fs/nfsd/nfs3proc.c b/fs/nfsd/nfs3proc.c
index 1764cd5e562d..307a3b195364 100644
--- a/fs/nfsd/nfs3proc.c
+++ b/fs/nfsd/nfs3proc.c
@@ -225,6 +225,13 @@ struct READDIR3args_wrapper {
static_assert(offsetof(struct READDIR3args_wrapper, xdrgen) == 0);
+struct READDIRPLUS3args_wrapper {
+ struct READDIRPLUS3args xdrgen;
+ struct svc_fh fh;
+};
+
+static_assert(offsetof(struct READDIRPLUS3args_wrapper, xdrgen) == 0);
+
static int nfsd3_ftype3_to_mode(ftype3 ftype)
{
switch (ftype) {
@@ -1551,27 +1558,32 @@ static __be32 nfsd3_proc_readdir(struct svc_rqst *rqstp)
return rpc_success;
}
-/*
- * Read a portion of a directory, including file handles and attrs.
- * For now, we choose to ignore the dircount parameter.
+/**
+ * nfsd3_proc_readdirplus - READDIRPLUS: Extended read from directory
+ * @rqstp: RPC transaction context
+ *
+ * Return:
+ * %rpc_success: RPC executed successfully
+ *
+ * RPC synopsis:
+ * READDIRPLUS3res NFSPROC3_READDIRPLUS(READDIRPLUS3args) = 17;
*/
-static __be32
-nfsd3_proc_readdirplus(struct svc_rqst *rqstp)
+static __be32 nfsd3_proc_readdirplus(struct svc_rqst *rqstp)
{
- struct nfsd3_readdirargs *argp = rqstp->rq_argp;
+ struct READDIRPLUS3args_wrapper *argp = rqstp->rq_argp;
struct nfsd3_readdirres *resp = rqstp->rq_resp;
- loff_t offset;
+ loff_t offset = argp->xdrgen.cookie;
+ struct svc_fh *fhp = &argp->fh;
- trace_nfsd_vfs_readdir(rqstp, &argp->fh, argp->count, argp->cookie);
+ nfsd3_fh3_to_svc_fh(fhp, &argp->xdrgen.dir);
+ trace_nfsd_vfs_readdir(rqstp, fhp, argp->xdrgen.maxcount,
+ argp->xdrgen.cookie);
- nfsd3_init_dirlist_pages(rqstp, resp, argp->count);
-
- fh_copy(&resp->fh, &argp->fh);
+ nfsd3_init_dirlist_pages(rqstp, resp, argp->xdrgen.maxcount);
+ fh_copy(&resp->fh, fhp);
resp->common.err = nfs_ok;
resp->cookie_offset = 0;
resp->rqstp = rqstp;
- offset = argp->cookie;
-
resp->status = fh_verify(rqstp, &resp->fh, S_IFDIR, NFSD_MAY_NOP);
if (resp->status != nfs_ok)
goto out;
@@ -1583,7 +1595,7 @@ nfsd3_proc_readdirplus(struct svc_rqst *rqstp)
resp->status = nfsd_readdir(rqstp, &resp->fh, &offset,
&resp->common, nfs3svc_encode_entryplus3);
- memcpy(resp->verf, argp->verf, 8);
+ memcpy(resp->verf, argp->xdrgen.cookieverf, NFS3_COOKIEVERFSIZE);
nfs3svc_encode_cookie3(resp, offset);
/* Recycle only pages that were part of the reply */
@@ -1824,8 +1836,6 @@ static __be32 nfsd3_proc_commit(struct svc_rqst *rqstp)
* NFSv3 Server procedures.
* Only the results of non-idempotent operations are cached.
*/
-#define nfsd3_readdirplusargs nfsd3_readdirargs
-
static const struct svc_procedure nfsd_procedures3[22] = {
[NFSPROC3_NULL] = {
.pc_func = nfsd3_proc_null,
@@ -2018,15 +2028,15 @@ static const struct svc_procedure nfsd_procedures3[22] = {
.pc_name = "READDIR",
},
[NFSPROC3_READDIRPLUS] = {
- .pc_func = nfsd3_proc_readdirplus,
- .pc_decode = nfs3svc_decode_readdirplusargs,
- .pc_encode = nfs3svc_encode_readdirres,
- .pc_release = nfs3svc_release_fhandle,
- .pc_argsize = sizeof(struct nfsd3_readdirplusargs),
- .pc_argzero = sizeof(struct nfsd3_readdirplusargs),
- .pc_ressize = sizeof(struct nfsd3_readdirres),
- .pc_cachetype = RC_NOCACHE,
- .pc_name = "READDIRPLUS",
+ .pc_func = nfsd3_proc_readdirplus,
+ .pc_decode = nfs_svc_decode_READDIRPLUS3args,
+ .pc_encode = nfs3svc_encode_readdirres,
+ .pc_release = nfs3svc_release_fhandle,
+ .pc_argsize = sizeof(struct READDIRPLUS3args_wrapper),
+ .pc_argzero = 0,
+ .pc_ressize = sizeof(struct nfsd3_readdirres),
+ .pc_cachetype = RC_NOCACHE,
+ .pc_name = "READDIRPLUS",
},
[NFSPROC3_FSSTAT] = {
.pc_func = nfsd3_proc_fsstat,
@@ -2106,7 +2116,7 @@ union nfsd3_xdrstore {
struct LINK3args_wrapper linkargs;
struct LINK3res linkres;
struct READDIR3args_wrapper readdirargs;
- struct nfsd3_readdirargs readdirplusargs;
+ struct READDIRPLUS3args_wrapper readdirplusargs;
struct READLINK3res readlinkres;
struct READ3res readres;
struct nfsd3_writeres writeres;
diff --git a/fs/nfsd/nfs3xdr.c b/fs/nfsd/nfs3xdr.c
index 0e83a2245c45..b1a930b857d7 100644
--- a/fs/nfsd/nfs3xdr.c
+++ b/fs/nfsd/nfs3xdr.c
@@ -224,32 +224,6 @@ svcxdr_encode_post_op_attr(struct svc_rqst *rqstp, struct xdr_stream *xdr,
return xdr_stream_encode_item_absent(xdr) > 0;
}
-/*
- * XDR decode functions
- */
-
-bool
-nfs3svc_decode_readdirplusargs(struct svc_rqst *rqstp, struct xdr_stream *xdr)
-{
- struct nfsd3_readdirargs *args = rqstp->rq_argp;
- u32 dircount;
-
- if (!svcxdr_decode_nfs_fh3(xdr, &args->fh))
- return false;
- if (xdr_stream_decode_u64(xdr, &args->cookie) < 0)
- return false;
- args->verf = xdr_inline_decode(xdr, NFS3_COOKIEVERFSIZE);
- if (!args->verf)
- return false;
- /* dircount is ignored */
- if (xdr_stream_decode_u32(xdr, &dircount) < 0)
- return false;
- if (xdr_stream_decode_u32(xdr, &args->count) < 0)
- return false;
-
- return true;
-}
-
/*
* XDR encode functions
*/
diff --git a/fs/nfsd/xdr3.h b/fs/nfsd/xdr3.h
index 3fb4a01011ca..4c4642077342 100644
--- a/fs/nfsd/xdr3.h
+++ b/fs/nfsd/xdr3.h
@@ -24,13 +24,6 @@ struct nfsd3_accessargs {
__u32 access;
};
-struct nfsd3_readdirargs {
- struct svc_fh fh;
- __u64 cookie;
- __u32 count;
- __be32 * verf;
-};
-
struct nfsd3_getaclargs {
struct svc_fh fh;
__u32 mask;
@@ -113,8 +106,6 @@ struct nfsd3_getaclres {
struct kstat stat;
};
-bool nfs3svc_decode_readdirplusargs(struct svc_rqst *rqstp, struct xdr_stream *xdr);
-
bool nfs3svc_encode_accessres(struct svc_rqst *rqstp, struct xdr_stream *xdr);
bool nfs3svc_encode_readdirres(struct svc_rqst *rqstp, struct xdr_stream *xdr);
--
2.55.0
^ permalink raw reply related [flat|nested] 10+ messages in thread
* [PATCH v3 29/34] NFSD: Refactor NFSv3 directory cookie encoding
2026-10-13 12:49 [PATCH v3 20/34] NFSD: Use xdrgen XDR functions for the NFSv3 RMDIR procedure Chuck Lever
` (7 preceding siblings ...)
2026-10-13 12:49 ` [PATCH v3 28/34] NFSD: Use xdrgen XDR functions for NFSv3 READDIRPLUS arguments Chuck Lever
@ 2026-10-13 12:49 ` Chuck Lever
8 siblings, 0 replies; 10+ messages in thread
From: Chuck Lever @ 2026-10-13 12:49 UTC (permalink / raw)
To: NeilBrown, Jeff Layton, Olga Kornievskaia, Dai Ngo, Tom Talpey; +Cc: linux-nfs
The current synopsis of nfs3svc_encode_cookie3() takes a "struct
nfsd3_readdirres" argument, which is common to the NFSv3 READDIR and
READDIRPLUS procedures.
xdrgen defines two distinct argument structures for these procedures
since they are actually two distinct procedures and have different
arguments.
With a "struct READDIR3args" and a "struct READDIRPLUS3args," the
cookie3 encoder will need generic parameter types in order to be
callable from both.
Note that NFSD can't use the xdrgen-generated cookie3 encoder. This
is because directory cookies need to point to the previous directory
entry. Space for each cookie in the send buffer is reserved when
each directory entry is encoded; when the /next/ entry is encoded,
the encoder writes its offset into that reserved space.
As a clean-up, remove "resp->cookie_offset = 0;" :
- In nfs3svc_encode_entry3() and nfs3svc_encode_entryplus3(),
immediately after calling nfs3svc_encode_cookie3(), the code calls
svcxdr_encode_entry3_common() which sets a new resp->cookie_offset
value. The cookie_offset value was immediately overwritten.
- In nfsd3_proc_readdir() and nfsd3_proc_readdirplus(),
nfs3svc_encode_cookie3() is called as the last cookie encoding,
and no further use of cookie_offset follows.
- The out_toosmall error paths in entry encoders continue to set
resp->cookie_offset = 0
Signed-off-by: Chuck Lever <cel@kernel.org>
---
fs/nfsd/nfs3proc.c | 4 ++--
fs/nfsd/nfs3xdr.c | 22 +++++++++++-----------
fs/nfsd/xdr3.h | 3 ++-
3 files changed, 15 insertions(+), 14 deletions(-)
diff --git a/fs/nfsd/nfs3proc.c b/fs/nfsd/nfs3proc.c
index 307a3b195364..9d2fcb697e72 100644
--- a/fs/nfsd/nfs3proc.c
+++ b/fs/nfsd/nfs3proc.c
@@ -1549,7 +1549,7 @@ static __be32 nfsd3_proc_readdir(struct svc_rqst *rqstp)
resp->status = nfsd_readdir(rqstp, &resp->fh, &offset,
&resp->common, nfs3svc_encode_entry3);
memcpy(resp->verf, argp->xdrgen.cookieverf, NFS3_COOKIEVERFSIZE);
- nfs3svc_encode_cookie3(resp, offset);
+ nfs3svc_encode_cookie3(&resp->xdr, resp->cookie_offset, offset);
/* Recycle only pages that were part of the reply */
rqstp->rq_next_page = resp->xdr.page_ptr + 1;
@@ -1596,7 +1596,7 @@ static __be32 nfsd3_proc_readdirplus(struct svc_rqst *rqstp)
resp->status = nfsd_readdir(rqstp, &resp->fh, &offset,
&resp->common, nfs3svc_encode_entryplus3);
memcpy(resp->verf, argp->xdrgen.cookieverf, NFS3_COOKIEVERFSIZE);
- nfs3svc_encode_cookie3(resp, offset);
+ nfs3svc_encode_cookie3(&resp->xdr, resp->cookie_offset, offset);
/* Recycle only pages that were part of the reply */
rqstp->rq_next_page = resp->xdr.page_ptr + 1;
diff --git a/fs/nfsd/nfs3xdr.c b/fs/nfsd/nfs3xdr.c
index b1a930b857d7..279b19d5e3ac 100644
--- a/fs/nfsd/nfs3xdr.c
+++ b/fs/nfsd/nfs3xdr.c
@@ -300,22 +300,22 @@ compose_entry_fh(struct nfsd3_readdirres *cd, struct svc_fh *fhp,
}
/**
- * nfs3svc_encode_cookie3 - Encode a directory offset cookie
- * @resp: readdir result context
- * @offset: offset cookie to encode
+ * nfs3svc_encode_cookie3 - Encode a directory cookie
+ * @xdr: stream into which to encode the cookie
+ * @pos: byte position in the stream
+ * @cookie: cookie to be encoded
*
* The buffer space for the offset cookie has already been reserved
* by svcxdr_encode_entry3_common().
*/
-void nfs3svc_encode_cookie3(struct nfsd3_readdirres *resp, u64 offset)
+void nfs3svc_encode_cookie3(struct xdr_stream *xdr, unsigned int pos,
+ u64 cookie)
{
- __be64 cookie = cpu_to_be64(offset);
+ __be64 wire_cookie = cpu_to_be64(cookie);
- if (!resp->cookie_offset)
+ if (!pos)
return;
- write_bytes_to_xdr_buf(&resp->dirlist, resp->cookie_offset, &cookie,
- sizeof(cookie));
- resp->cookie_offset = 0;
+ write_bytes_to_xdr_buf(xdr->buf, pos, &wire_cookie, XDR_UNIT * 2);
}
static bool
@@ -369,7 +369,7 @@ int nfs3svc_encode_entry3(void *data, const char *name, int namlen,
unsigned int starting_length = resp->dirlist.len;
/* The offset cookie for the previous entry */
- nfs3svc_encode_cookie3(resp, offset);
+ nfs3svc_encode_cookie3(&resp->xdr, resp->cookie_offset, offset);
if (!svcxdr_encode_entry3_common(resp, name, namlen, offset, ino))
goto out_toosmall;
@@ -444,7 +444,7 @@ int nfs3svc_encode_entryplus3(void *data, const char *name, int namlen,
unsigned int starting_length = resp->dirlist.len;
/* The offset cookie for the previous entry */
- nfs3svc_encode_cookie3(resp, offset);
+ nfs3svc_encode_cookie3(&resp->xdr, resp->cookie_offset, offset);
if (!svcxdr_encode_entry3_common(resp, name, namlen, offset, ino))
goto out_toosmall;
diff --git a/fs/nfsd/xdr3.h b/fs/nfsd/xdr3.h
index 4c4642077342..fdb2e68e16d5 100644
--- a/fs/nfsd/xdr3.h
+++ b/fs/nfsd/xdr3.h
@@ -111,7 +111,8 @@ bool nfs3svc_encode_readdirres(struct svc_rqst *rqstp, struct xdr_stream *xdr);
void nfs3svc_release_fhandle(struct svc_rqst *);
-void nfs3svc_encode_cookie3(struct nfsd3_readdirres *resp, u64 offset);
+void nfs3svc_encode_cookie3(struct xdr_stream *xdr, unsigned int pos,
+ u64 cookie);
int nfs3svc_encode_entry3(void *data, const char *name, int namlen,
loff_t offset, u64 ino, unsigned int d_type);
int nfs3svc_encode_entryplus3(void *data, const char *name, int namlen,
--
2.55.0
^ permalink raw reply related [flat|nested] 10+ messages in thread
end of thread, other threads:[~2026-10-13 12:49 UTC | newest]
Thread overview: 10+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2026-10-13 12:49 [PATCH v3 20/34] NFSD: Use xdrgen XDR functions for the NFSv3 RMDIR procedure Chuck Lever
2026-10-13 12:49 ` [PATCH v3 21/34] NFSD: Use xdrgen XDR functions for the NFSv3 RENAME procedure Chuck Lever
2026-10-13 12:49 ` [PATCH v3 22/34] NFSD: Use xdrgen XDR functions for the NFSv3 LINK procedure Chuck Lever
2026-10-13 12:49 ` [PATCH v3 23/34] NFSD: Use xdrgen XDR functions for the NFSv3 FSSTAT procedure Chuck Lever
2026-10-13 12:49 ` [PATCH v3 24/34] NFSD: Use xdrgen XDR functions for the NFSv3 FSINFO procedure Chuck Lever
2026-10-13 12:49 ` [PATCH v3 25/34] NFSD: Use xdrgen XDR functions for the NFSv3 PATHCONF procedure Chuck Lever
2026-10-13 12:49 ` [PATCH v3 26/34] NFSD: Use xdrgen XDR functions for the NFSv3 COMMIT procedure Chuck Lever
2026-10-13 12:49 ` [PATCH v3 27/34] NFSD: Use xdrgen XDR functions for NFSv3 READDIR arguments Chuck Lever
2026-10-13 12:49 ` [PATCH v3 28/34] NFSD: Use xdrgen XDR functions for NFSv3 READDIRPLUS arguments Chuck Lever
2026-10-13 12:49 ` [PATCH v3 29/34] NFSD: Refactor NFSv3 directory cookie encoding Chuck Lever
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.