Linux NFS development
 help / color / mirror / Atom feed
* [PATCH v3 02/34] Documentation: Add the RPC language description of NFSv3
@ 2026-10-13 12:49 Chuck Lever
  2026-10-13 12:49 ` [PATCH v3 03/34] NFSD: Add infrastructure for generating NFSv3 XDR encoders and decoders Chuck Lever
                   ` (6 more replies)
  0 siblings, 7 replies; 8+ 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, Chuck Lever

From: Chuck Lever <chuck.lever@oracle.com>

In order to generate source code to encode and decode NFSv3 protocol
elements, include a copy of the RPC language description of NFSv3
for xdrgen to process. The language description is copied from
RFC 1813.

The goals of replacing hand-written XDR functions with ones that
are tool-generated are to improve memory safety and make XDR
encoding and decoding less brittle to maintain. Parts of the
NFSv4 protocol are still being extended actively. Tool-generated
XDR code reduces the time it takes to get a working implementation
of new protocol elements.

The xdrgen utility derives both the type definitions and the
encode/decode functions directly from protocol specifications,
using names and symbols familiar to anyone who knows those specs.
Unlike hand-written code that can inadvertently diverge from the
specification, xdrgen guarantees that the generated code matches
the specification exactly.

We would eventually like xdrgen to generate Rust code as well,
making the conversion of the kernel's NFS stacks to use Rust just
a little easier for us.

Signed-off-by: Chuck Lever <cel@kernel.org>
---
 Documentation/sunrpc/xdr/nfs3.x | 812 ++++++++++++++++++++++++++++++++
 1 file changed, 812 insertions(+)
 create mode 100644 Documentation/sunrpc/xdr/nfs3.x

diff --git a/Documentation/sunrpc/xdr/nfs3.x b/Documentation/sunrpc/xdr/nfs3.x
new file mode 100644
index 000000000000..7996775fb4ae
--- /dev/null
+++ b/Documentation/sunrpc/xdr/nfs3.x
@@ -0,0 +1,812 @@
+/*
+ * Copyright (c) 1995 IETF Trust and the persons identified
+ * as the document authors.  All rights reserved.
+ *
+ * The document authors are identified in RFC 1813.
+ *
+ * Redistribution and use in source and binary forms, with
+ * or without modification, are permitted provided that the
+ * following conditions are met:
+ *
+ * - Redistributions of source code must retain the above
+ *   copyright notice, this list of conditions and the
+ *   following disclaimer.
+ *
+ * - Redistributions in binary form must reproduce the above
+ *   copyright notice, this list of conditions and the
+ *   following disclaimer in the documentation and/or other
+ *   materials provided with the distribution.
+ *
+ * - Neither the name of Internet Society, IETF or IETF
+ *   Trust, nor the names of specific contributors, may be
+ *   used to endorse or promote products derived from this
+ *   software without specific prior written permission.
+ *
+ *   THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS
+ *   AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED
+ *   WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ *   IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
+ *   FOR A PARTICULAR PURPOSE ARE DISCLAIMED.  IN NO
+ *   EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
+ *   LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ *   EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ *   NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+ *   SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ *   INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ *   LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
+ *   OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
+ *   IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
+ *   ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+const NFS3_FHSIZE		= 64;
+const NFS3_COOKIEVERFSIZE	= 8;
+const NFS3_CREATEVERFSIZE	= 8;
+const NFS3_WRITEVERFSIZE	= 8;
+
+typedef unsigned hyper uint64;
+typedef hyper int64;
+typedef unsigned long uint32;
+typedef long int32;
+typedef string filename3<>;
+typedef string nfspath3<>;
+typedef uint64 fileid3;
+typedef uint64 cookie3;
+typedef opaque cookieverf3[NFS3_COOKIEVERFSIZE];
+typedef opaque createverf3[NFS3_CREATEVERFSIZE];
+typedef opaque writeverf3[NFS3_WRITEVERFSIZE];
+typedef uint32 uid3;
+typedef uint32 gid3;
+typedef uint64 size3;
+typedef uint64 offset3;
+typedef uint32 mode3;
+typedef uint32 count3;
+
+enum nfsstat3 {
+	NFS3_OK			= 0,
+	NFS3ERR_PERM		= 1,
+	NFS3ERR_NOENT		= 2,
+	NFS3ERR_IO		= 5,
+	NFS3ERR_NXIO		= 6,
+	NFS3ERR_ACCES		= 13,
+	NFS3ERR_EXIST		= 17,
+	NFS3ERR_XDEV		= 18,
+	NFS3ERR_NODEV		= 19,
+	NFS3ERR_NOTDIR		= 20,
+	NFS3ERR_ISDIR		= 21,
+	NFS3ERR_INVAL		= 22,
+	NFS3ERR_FBIG		= 27,
+	NFS3ERR_NOSPC		= 28,
+	NFS3ERR_ROFS		= 30,
+	NFS3ERR_MLINK		= 31,
+	NFS3ERR_NAMETOOLONG	= 63,
+	NFS3ERR_NOTEMPTY	= 66,
+	NFS3ERR_DQUOT		= 69,
+	NFS3ERR_STALE		= 70,
+	NFS3ERR_REMOTE		= 71,
+	NFS3ERR_BADHANDLE	= 10001,
+	NFS3ERR_NOT_SYNC	= 10002,
+	NFS3ERR_BAD_COOKIE	= 10003,
+	NFS3ERR_NOTSUPP		= 10004,
+	NFS3ERR_TOOSMALL	= 10005,
+	NFS3ERR_SERVERFAULT	= 10006,
+	NFS3ERR_BADTYPE		= 10007,
+	NFS3ERR_JUKEBOX		= 10008
+};
+
+enum ftype3 {
+	NF3REG		= 1,
+	NF3DIR		= 2,
+	NF3BLK		= 3,
+	NF3CHR		= 4,
+	NF3LNK		= 5,
+	NF3SOCK		= 6,
+	NF3FIFO		= 7
+};
+
+struct specdata3 {
+	uint32		specdata1;
+	uint32		specdata2;
+};
+
+struct nfs_fh3 {
+	opaque		data<NFS3_FHSIZE>;
+};
+
+struct nfstime3 {
+	uint32		seconds;
+	uint32		nseconds;
+};
+
+struct fattr3 {
+	ftype3		type;
+	mode3		mode;
+	uint32		nlink;
+	uid3		uid;
+	gid3		gid;
+	size3		size;
+	size3		used;
+	specdata3	rdev;
+	uint64		fsid;
+	fileid3		fileid;
+	nfstime3	atime;
+	nfstime3	mtime;
+	nfstime3	ctime;
+};
+
+union post_op_attr switch (bool attributes_follow) {
+	case TRUE:
+		fattr3		attributes;
+	case FALSE:
+		void;
+};
+
+struct wcc_attr {
+	size3		size;
+	nfstime3	mtime;
+	nfstime3	ctime;
+};
+
+union pre_op_attr switch (bool attributes_follow) {
+	case TRUE:
+		wcc_attr	attributes;
+	case FALSE:
+		void;
+};
+
+struct wcc_data {
+	pre_op_attr	before;
+	post_op_attr	after;
+};
+
+union post_op_fh3 switch (bool handle_follows) {
+	case TRUE:
+		nfs_fh3		handle;
+	case FALSE:
+		void;
+};
+
+enum time_how {
+	DONT_CHANGE		= 0,
+	SET_TO_SERVER_TIME	= 1,
+	SET_TO_CLIENT_TIME	= 2
+};
+
+union set_mode3 switch (bool set_it) {
+	case TRUE:
+		mode3		mode;
+	default:
+		void;
+};
+
+union set_uid3 switch (bool set_it) {
+	case TRUE:
+		uid3		uid;
+	default:
+		void;
+};
+
+union set_gid3 switch (bool set_it) {
+	case TRUE:
+		gid3		gid;
+	default:
+		void;
+};
+
+union set_size3 switch (bool set_it) {
+	case TRUE:
+		size3		size;
+	default:
+		void;
+};
+
+union set_atime switch (time_how set_it) {
+	case SET_TO_CLIENT_TIME:
+		nfstime3	atime;
+	default:
+		void;
+};
+
+union set_mtime switch (time_how set_it) {
+	case SET_TO_CLIENT_TIME:
+		nfstime3	mtime;
+	default:
+		void;
+};
+
+struct sattr3 {
+	set_mode3	mode;
+	set_uid3	uid;
+	set_gid3	gid;
+	set_size3	size;
+	set_atime	atime;
+	set_mtime	mtime;
+};
+
+struct diropargs3 {
+	nfs_fh3		dir;
+	filename3	name;
+};
+
+struct GETATTR3args {
+	nfs_fh3		object;
+};
+
+struct GETATTR3resok {
+	fattr3		obj_attributes;
+};
+
+union GETATTR3res switch (nfsstat3 status) {
+	case NFS3_OK:
+		GETATTR3resok	resok;
+	default:
+		void;
+};
+
+union sattrguard3 switch (bool check) {
+	case TRUE:
+		nfstime3	obj_ctime;
+	case FALSE:
+		void;
+};
+
+struct SETATTR3args {
+	nfs_fh3		object;
+	sattr3		new_attributes;
+	sattrguard3	guard;
+};
+
+struct SETATTR3resok {
+	wcc_data	obj_wcc;
+};
+
+struct SETATTR3resfail {
+	wcc_data	obj_wcc;
+};
+
+union SETATTR3res switch (nfsstat3 status) {
+	case NFS3_OK:
+		SETATTR3resok		resok;
+	default:
+		SETATTR3resfail		resfail;
+};
+
+struct LOOKUP3args {
+	diropargs3	what;
+};
+
+struct LOOKUP3resok {
+	nfs_fh3		object;
+	post_op_attr	obj_attributes;
+	post_op_attr	dir_attributes;
+};
+
+struct LOOKUP3resfail {
+	post_op_attr	dir_attributes;
+};
+
+union LOOKUP3res switch (nfsstat3 status) {
+	case NFS3_OK:
+		LOOKUP3resok		resok;
+	default:
+		LOOKUP3resfail		resfail;
+};
+
+const ACCESS3_READ	= 0x0001;
+const ACCESS3_LOOKUP	= 0x0002;
+const ACCESS3_MODIFY	= 0x0004;
+const ACCESS3_EXTEND	= 0x0008;
+const ACCESS3_DELETE	= 0x0010;
+const ACCESS3_EXECUTE	= 0x0020;
+
+struct ACCESS3args {
+	nfs_fh3		object;
+	uint32		access;
+};
+
+struct ACCESS3resok {
+	post_op_attr	obj_attributes;
+	uint32		access;
+};
+
+struct ACCESS3resfail {
+	post_op_attr	obj_attributes;
+};
+
+union ACCESS3res switch (nfsstat3 status) {
+	case NFS3_OK:
+		ACCESS3resok	resok;
+	default:
+		ACCESS3resfail	resfail;
+};
+
+struct READLINK3args {
+	nfs_fh3		symlink;
+};
+
+struct READLINK3resok {
+	post_op_attr	symlink_attributes;
+	nfspath3	data;
+};
+
+struct READLINK3resfail {
+	post_op_attr	symlink_attributes;
+};
+
+union READLINK3res switch (nfsstat3 status) {
+	case NFS3_OK:
+		READLINK3resok	resok;
+	default:
+		READLINK3resfail	resfail;
+};
+
+struct READ3args {
+	nfs_fh3		file;
+	offset3		offset;
+	count3		count;
+};
+
+struct READ3resok {
+	post_op_attr	file_attributes;
+	count3		count;
+	bool		eof;
+	opaque		data<>;
+};
+
+struct READ3resfail {
+	post_op_attr	file_attributes;
+};
+
+union READ3res switch (nfsstat3 status) {
+	case NFS3_OK:
+		READ3resok	resok;
+	default:
+		READ3resfail	resfail;
+};
+
+enum stable_how {
+	UNSTABLE	= 0,
+	DATA_SYNC	= 1,
+	FILE_SYNC	= 2
+};
+
+struct WRITE3args {
+	nfs_fh3		file;
+	offset3		offset;
+	count3		count;
+	stable_how	stable;
+	opaque		data<>;
+};
+
+struct WRITE3resok {
+	wcc_data	file_wcc;
+	count3		count;
+	stable_how	committed;
+	writeverf3	verf;
+};
+
+struct WRITE3resfail {
+	wcc_data	file_wcc;
+};
+
+union WRITE3res switch (nfsstat3 status) {
+	case NFS3_OK:
+		WRITE3resok		resok;
+	default:
+		WRITE3resfail		resfail;
+};
+
+enum createmode3 {
+	UNCHECKED	= 0,
+	GUARDED		= 1,
+	EXCLUSIVE	= 2
+};
+
+union createhow3 switch (createmode3 mode) {
+	case UNCHECKED:
+	case GUARDED:
+		sattr3			obj_attributes;
+	case EXCLUSIVE:
+		createverf3		verf;
+};
+
+struct CREATE3args {
+	diropargs3	where;
+	createhow3	how;
+};
+
+struct CREATE3resok {
+	post_op_fh3	obj;
+	post_op_attr	obj_attributes;
+	wcc_data	dir_wcc;
+};
+
+struct CREATE3resfail {
+	wcc_data	dir_wcc;
+};
+
+union CREATE3res switch (nfsstat3 status) {
+	case NFS3_OK:
+		CREATE3resok		resok;
+	default:
+		CREATE3resfail		resfail;
+};
+
+struct MKDIR3args {
+	diropargs3	where;
+	sattr3		attributes;
+};
+
+struct MKDIR3resok {
+	post_op_fh3	obj;
+	post_op_attr	obj_attributes;
+	wcc_data	dir_wcc;
+};
+
+struct MKDIR3resfail {
+	wcc_data	dir_wcc;
+};
+
+union MKDIR3res switch (nfsstat3 status) {
+	case NFS3_OK:
+		MKDIR3resok		resok;
+	default:
+		MKDIR3resfail		resfail;
+};
+
+struct symlinkdata3 {
+	sattr3		symlink_attributes;
+	nfspath3	symlink_data;
+};
+
+struct SYMLINK3args {
+	diropargs3	where;
+	symlinkdata3	symlink;
+};
+
+struct SYMLINK3resok {
+	post_op_fh3	obj;
+	post_op_attr	obj_attributes;
+	wcc_data	dir_wcc;
+};
+
+struct SYMLINK3resfail {
+	wcc_data	dir_wcc;
+};
+
+union SYMLINK3res switch (nfsstat3 status) {
+	case NFS3_OK:
+		SYMLINK3resok		resok;
+	default:
+		SYMLINK3resfail		resfail;
+};
+
+struct devicedata3 {
+	sattr3		dev_attributes;
+	specdata3	spec;
+};
+
+union mknoddata3 switch (ftype3 type) {
+	case NF3CHR:
+	case NF3BLK:
+		devicedata3	device;
+	case NF3SOCK:
+	case NF3FIFO:
+		sattr3		pipe_attributes;
+	default:
+		void;
+};
+
+struct MKNOD3args {
+	diropargs3	where;
+	mknoddata3	what;
+};
+
+struct MKNOD3resok {
+	post_op_fh3	obj;
+	post_op_attr	obj_attributes;
+	wcc_data	dir_wcc;
+};
+
+struct MKNOD3resfail {
+	wcc_data	dir_wcc;
+};
+
+union MKNOD3res switch (nfsstat3 status) {
+	case NFS3_OK:
+		MKNOD3resok		resok;
+	default:
+		MKNOD3resfail		resfail;
+};
+
+struct REMOVE3args {
+	diropargs3	object;
+};
+
+struct REMOVE3resok {
+	wcc_data	dir_wcc;
+};
+
+struct REMOVE3resfail {
+	wcc_data	dir_wcc;
+};
+
+union REMOVE3res switch (nfsstat3 status) {
+	case NFS3_OK:
+		REMOVE3resok		resok;
+	default:
+		REMOVE3resfail		resfail;
+};
+
+struct RMDIR3args {
+	diropargs3	object;
+};
+
+struct RMDIR3resok {
+	wcc_data	dir_wcc;
+};
+
+struct RMDIR3resfail {
+	wcc_data	dir_wcc;
+};
+
+union RMDIR3res switch (nfsstat3 status) {
+	case NFS3_OK:
+		RMDIR3resok		resok;
+	default:
+		RMDIR3resfail		resfail;
+};
+
+struct RENAME3args {
+	diropargs3	from;
+	diropargs3	to;
+};
+
+struct RENAME3resok {
+	wcc_data	fromdir_wcc;
+	wcc_data	todir_wcc;
+};
+
+struct RENAME3resfail {
+	wcc_data	fromdir_wcc;
+	wcc_data	todir_wcc;
+};
+
+union RENAME3res switch (nfsstat3 status) {
+	case NFS3_OK:
+		RENAME3resok		resok;
+	default:
+		RENAME3resfail		resfail;
+};
+
+struct LINK3args {
+	nfs_fh3		file;
+	diropargs3	link;
+};
+
+struct LINK3resok {
+	post_op_attr	file_attributes;
+	wcc_data	linkdir_wcc;
+};
+
+struct LINK3resfail {
+	post_op_attr	file_attributes;
+	wcc_data	linkdir_wcc;
+};
+
+union LINK3res switch (nfsstat3 status) {
+	case NFS3_OK:
+		LINK3resok		resok;
+	default:
+		LINK3resfail		resfail;
+};
+
+struct READDIR3args {
+	nfs_fh3		dir;
+	cookie3		cookie;
+	cookieverf3	cookieverf;
+	count3		count;
+};
+
+struct entry3 {
+	fileid3		fileid;
+	filename3	name;
+	cookie3		cookie;
+	entry3		*nextentry;
+};
+
+struct dirlist3 {
+	entry3		*entries;
+	bool		eof;
+};
+
+struct READDIR3resok {
+	post_op_attr	dir_attributes;
+	cookieverf3	cookieverf;
+	dirlist3	reply;
+};
+
+struct READDIR3resfail {
+	post_op_attr	dir_attributes;
+};
+
+union READDIR3res switch (nfsstat3 status) {
+	case NFS3_OK:
+		READDIR3resok		resok;
+	default:
+		READDIR3resfail		resfail;
+};
+
+struct READDIRPLUS3args {
+	nfs_fh3		dir;
+	cookie3		cookie;
+	cookieverf3	cookieverf;
+	count3		dircount;
+	count3		maxcount;
+};
+
+struct entryplus3 {
+	fileid3		fileid;
+	filename3	name;
+	cookie3		cookie;
+	post_op_attr	name_attributes;
+	post_op_fh3	name_handle;
+	entryplus3	*nextentry;
+};
+
+struct dirlistplus3 {
+	entryplus3	*entries;
+	bool		eof;
+};
+
+struct READDIRPLUS3resok {
+	post_op_attr	dir_attributes;
+	cookieverf3	cookieverf;
+	dirlistplus3	reply;
+};
+
+struct READDIRPLUS3resfail {
+	post_op_attr	dir_attributes;
+};
+
+union READDIRPLUS3res switch (nfsstat3 status) {
+	case NFS3_OK:
+		READDIRPLUS3resok	resok;
+	default:
+		READDIRPLUS3resfail	resfail;
+};
+
+
+struct FSSTAT3args {
+	nfs_fh3		fsroot;
+};
+
+struct FSSTAT3resok {
+	post_op_attr	obj_attributes;
+	size3		tbytes;
+	size3		fbytes;
+	size3		abytes;
+	size3		tfiles;
+	size3		ffiles;
+	size3		afiles;
+	uint32		invarsec;
+};
+
+struct FSSTAT3resfail {
+	post_op_attr	obj_attributes;
+};
+
+union FSSTAT3res switch (nfsstat3 status) {
+	case NFS3_OK:
+		FSSTAT3resok		resok;
+	default:
+		FSSTAT3resfail		resfail;
+};
+
+const FSF3_LINK		= 0x0001;
+const FSF3_SYMLINK	= 0x0002;
+const FSF3_HOMOGENEOUS	= 0x0008;
+const FSF3_CANSETTIME	= 0x0010;
+
+struct FSINFO3args {
+	nfs_fh3		fsroot;
+};
+
+struct FSINFO3resok {
+	post_op_attr	obj_attributes;
+	uint32		rtmax;
+	uint32		rtpref;
+	uint32		rtmult;
+	uint32		wtmax;
+	uint32		wtpref;
+	uint32		wtmult;
+	uint32		dtpref;
+	size3		maxfilesize;
+	nfstime3	time_delta;
+	uint32		properties;
+};
+
+struct FSINFO3resfail {
+	post_op_attr	obj_attributes;
+};
+
+union FSINFO3res switch (nfsstat3 status) {
+	case NFS3_OK:
+		FSINFO3resok		resok;
+	default:
+		FSINFO3resfail		resfail;
+};
+
+struct PATHCONF3args {
+	nfs_fh3		object;
+};
+
+struct PATHCONF3resok {
+	post_op_attr	obj_attributes;
+	uint32		linkmax;
+	uint32		name_max;
+	bool		no_trunc;
+	bool		chown_restricted;
+	bool		case_insensitive;
+	bool		case_preserving;
+};
+
+struct PATHCONF3resfail {
+	post_op_attr	obj_attributes;
+};
+
+union PATHCONF3res switch (nfsstat3 status) {
+	case NFS3_OK:
+		PATHCONF3resok		resok;
+	default:
+		PATHCONF3resfail	resfail;
+};
+
+struct COMMIT3args {
+	nfs_fh3		file;
+	offset3		offset;
+	count3		count;
+};
+
+struct COMMIT3resok {
+	wcc_data	file_wcc;
+	writeverf3	verf;
+};
+
+struct COMMIT3resfail {
+	wcc_data	file_wcc;
+};
+
+union COMMIT3res switch (nfsstat3 status) {
+	case NFS3_OK:
+		COMMIT3resok		resok;
+	default:
+		COMMIT3resfail		resfail;
+};
+
+program NFS_PROGRAM {
+	version NFS_V3 {
+		void		NFSPROC3_NULL(void) = 0;
+		GETATTR3res	NFSPROC3_GETATTR(GETATTR3args) = 1;
+		SETATTR3res	NFSPROC3_SETATTR(SETATTR3args) = 2;
+		LOOKUP3res	NFSPROC3_LOOKUP(LOOKUP3args) = 3;
+		ACCESS3res	NFSPROC3_ACCESS(ACCESS3args) = 4;
+		READLINK3res	NFSPROC3_READLINK(READLINK3args) = 5;
+		READ3res	NFSPROC3_READ(READ3args) = 6;
+		WRITE3res	NFSPROC3_WRITE(WRITE3args) = 7;
+		CREATE3res	NFSPROC3_CREATE(CREATE3args) = 8;
+		MKDIR3res	NFSPROC3_MKDIR(MKDIR3args) = 9;
+		SYMLINK3res	NFSPROC3_SYMLINK(SYMLINK3args) = 10;
+		MKNOD3res	NFSPROC3_MKNOD(MKNOD3args) = 11;
+		REMOVE3res	NFSPROC3_REMOVE(REMOVE3args) = 12;
+		RMDIR3res	NFSPROC3_RMDIR(RMDIR3args) = 13;
+		RENAME3res	NFSPROC3_RENAME(RENAME3args) = 14;
+		LINK3res	NFSPROC3_LINK(LINK3args) = 15;
+		READDIR3res	NFSPROC3_READDIR(READDIR3args) = 16;
+		READDIRPLUS3res	NFSPROC3_READDIRPLUS(READDIRPLUS3args) = 17;
+		FSSTAT3res	NFSPROC3_FSSTAT(FSSTAT3args) = 18;
+		FSINFO3res	NFSPROC3_FSINFO(FSINFO3args) = 19;
+		PATHCONF3res	NFSPROC3_PATHCONF(PATHCONF3args) = 20;
+		COMMIT3res	NFSPROC3_COMMIT(COMMIT3args) = 21;
+	} = 3;
+} = 100003;
-- 
2.55.0


^ permalink raw reply related	[flat|nested] 8+ messages in thread

* [PATCH v3 03/34] NFSD: Add infrastructure for generating NFSv3 XDR encoders and decoders
  2026-10-13 12:49 [PATCH v3 02/34] Documentation: Add the RPC language description of NFSv3 Chuck Lever
@ 2026-10-13 12:49 ` Chuck Lever
  2026-10-13 12:49 ` [PATCH v3 04/34] NFSD: Replace nfs3.h with nfs3xdr_gen.h Chuck Lever
                   ` (5 subsequent siblings)
  6 siblings, 0 replies; 8+ 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

NFSD's NFSv3 XDR codecs are hand-maintained; they are being converted
to xdrgen-generated code one RPC procedure at a time. The first step
is to generate and commit the xdrgen C code based on nfs3.x. The
generated code can be refreshed any time nfs3.x is modified by
running "(cd fs/nfsd && make xdrgen)".

Signed-off-by: Chuck Lever <cel@kernel.org>
---
 Documentation/sunrpc/xdr/nfs3.x    |    2 +
 fs/nfsd/Makefile                   |   15 +-
 fs/nfsd/nfs3xdr_gen.c              | 3768 ++++++++++++++++++++++++++++
 fs/nfsd/nfs3xdr_gen.h              |   60 +
 include/linux/sunrpc/xdrgen/nfs3.h | 1092 ++++++++
 5 files changed, 4933 insertions(+), 4 deletions(-)
 create mode 100644 fs/nfsd/nfs3xdr_gen.c
 create mode 100644 fs/nfsd/nfs3xdr_gen.h
 create mode 100644 include/linux/sunrpc/xdrgen/nfs3.h

diff --git a/Documentation/sunrpc/xdr/nfs3.x b/Documentation/sunrpc/xdr/nfs3.x
index 7996775fb4ae..9feabfda94e7 100644
--- a/Documentation/sunrpc/xdr/nfs3.x
+++ b/Documentation/sunrpc/xdr/nfs3.x
@@ -39,6 +39,8 @@
  *   ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
  */
 
+pragma header nfs3;
+
 const NFS3_FHSIZE		= 64;
 const NFS3_COOKIEVERFSIZE	= 8;
 const NFS3_CREATEVERFSIZE	= 8;
diff --git a/fs/nfsd/Makefile b/fs/nfsd/Makefile
index 05fb814f760b..1dc449af28f4 100644
--- a/fs/nfsd/Makefile
+++ b/fs/nfsd/Makefile
@@ -12,8 +12,8 @@ nfsd-y			+= trace.o
 
 nfsd-y 			+= nfssvc.o nfsctl.o nfsfh.o vfs.o \
 			   export.o auth.o lockd.o nfscache.o \
-			   stats.o filecache.o nfs3proc.o nfs3xdr.o \
-			   netlink.o
+			   stats.o filecache.o netlink.o \
+			   nfs3proc.o nfs3xdr.o nfs3xdr_gen.o
 nfsd-$(CONFIG_NFSD_V2) += nfsproc.o nfsxdr.o nfs2xdr_gen.o
 nfsd-$(CONFIG_NFSD_V2_ACL) += nfs2acl.o
 nfsd-$(CONFIG_NFSD_V3_ACL) += nfs3acl.o
@@ -38,23 +38,30 @@ nfsd-$(CONFIG_DEBUG_FS) += debugfs.o
 .PHONY: xdrgen
 
 XDRGEN_DEFINITIONS	= ../../include/linux/sunrpc/xdrgen/nfs2.h \
+			  ../../include/linux/sunrpc/xdrgen/nfs3.h \
 			  ../../include/linux/sunrpc/xdrgen/nfs4_1.h
-XDRGEN_DECLARATIONS	= nfs2xdr_gen.h nfs4xdr_gen.h
-XDRGEN_SOURCE		= nfs2xdr_gen.c nfs4xdr_gen.c
+XDRGEN_DECLARATIONS	= nfs2xdr_gen.h nfs3xdr_gen.h nfs4xdr_gen.h
+XDRGEN_SOURCE		= nfs2xdr_gen.c nfs3xdr_gen.c nfs4xdr_gen.c
 
 xdrgen: $(XDRGEN_DEFINITIONS) $(XDRGEN_DECLARATIONS) $(XDRGEN_SOURCE)
 
 ../../include/linux/sunrpc/xdrgen/nfs2.h: ../../Documentation/sunrpc/xdr/nfs2.x
 	../../tools/net/sunrpc/xdrgen/xdrgen definitions $< > $@
+../../include/linux/sunrpc/xdrgen/nfs3.h: ../../Documentation/sunrpc/xdr/nfs3.x
+	../../tools/net/sunrpc/xdrgen/xdrgen definitions $< > $@
 ../../include/linux/sunrpc/xdrgen/nfs4_1.h: ../../Documentation/sunrpc/xdr/nfs4_1.x
 	../../tools/net/sunrpc/xdrgen/xdrgen definitions $< > $@
 
 nfs2xdr_gen.h: ../../Documentation/sunrpc/xdr/nfs2.x
 	../../tools/net/sunrpc/xdrgen/xdrgen declarations $< > $@
+nfs3xdr_gen.h: ../../Documentation/sunrpc/xdr/nfs3.x
+	../../tools/net/sunrpc/xdrgen/xdrgen declarations $< > $@
 nfs4xdr_gen.h: ../../Documentation/sunrpc/xdr/nfs4_1.x
 	../../tools/net/sunrpc/xdrgen/xdrgen declarations $< > $@
 
 nfs2xdr_gen.c: ../../Documentation/sunrpc/xdr/nfs2.x
 	../../tools/net/sunrpc/xdrgen/xdrgen source $< > $@
+nfs3xdr_gen.c: ../../Documentation/sunrpc/xdr/nfs3.x
+	../../tools/net/sunrpc/xdrgen/xdrgen source $< > $@
 nfs4xdr_gen.c: ../../Documentation/sunrpc/xdr/nfs4_1.x
 	../../tools/net/sunrpc/xdrgen/xdrgen source $< > $@
diff --git a/fs/nfsd/nfs3xdr_gen.c b/fs/nfsd/nfs3xdr_gen.c
new file mode 100644
index 000000000000..48b382ccfc81
--- /dev/null
+++ b/fs/nfsd/nfs3xdr_gen.c
@@ -0,0 +1,3768 @@
+// SPDX-License-Identifier: GPL-2.0
+// Generated by xdrgen. Manual edits will be lost.
+// XDR specification file: ../../Documentation/sunrpc/xdr/nfs3.x
+// XDR specification modification time: Fri Jul 10 23:20:55 2026
+
+#include <linux/sunrpc/svc.h>
+
+#include "nfs3xdr_gen.h"
+
+static bool __maybe_unused
+xdrgen_decode_uint64(struct xdr_stream *xdr, uint64 *ptr)
+{
+	return xdrgen_decode_unsigned_hyper(xdr, ptr);
+}
+
+static bool __maybe_unused
+xdrgen_decode_int64(struct xdr_stream *xdr, int64 *ptr)
+{
+	return xdrgen_decode_hyper(xdr, ptr);
+}
+
+static bool __maybe_unused
+xdrgen_decode_uint32(struct xdr_stream *xdr, uint32 *ptr)
+{
+	return xdrgen_decode_unsigned_long(xdr, ptr);
+}
+
+static bool __maybe_unused
+xdrgen_decode_int32(struct xdr_stream *xdr, int32 *ptr)
+{
+	return xdrgen_decode_long(xdr, ptr);
+}
+
+static bool __maybe_unused
+xdrgen_decode_filename3(struct xdr_stream *xdr, filename3 *ptr)
+{
+	return xdrgen_decode_string(xdr, ptr, 0);
+}
+
+static bool __maybe_unused
+xdrgen_decode_nfspath3(struct xdr_stream *xdr, nfspath3 *ptr)
+{
+	return xdrgen_decode_string(xdr, ptr, 0);
+}
+
+static bool __maybe_unused
+xdrgen_decode_fileid3(struct xdr_stream *xdr, fileid3 *ptr)
+{
+	return xdrgen_decode_uint64(xdr, ptr);
+}
+
+static bool __maybe_unused
+xdrgen_decode_cookie3(struct xdr_stream *xdr, cookie3 *ptr)
+{
+	return xdrgen_decode_uint64(xdr, ptr);
+}
+
+static bool __maybe_unused
+xdrgen_decode_cookieverf3(struct xdr_stream *xdr, cookieverf3 *ptr)
+{
+	return xdr_stream_decode_opaque_fixed(xdr, ptr, NFS3_COOKIEVERFSIZE) == 0;
+}
+
+static bool __maybe_unused
+xdrgen_decode_createverf3(struct xdr_stream *xdr, createverf3 *ptr)
+{
+	return xdr_stream_decode_opaque_fixed(xdr, ptr, NFS3_CREATEVERFSIZE) == 0;
+}
+
+static bool __maybe_unused
+xdrgen_decode_writeverf3(struct xdr_stream *xdr, writeverf3 *ptr)
+{
+	return xdr_stream_decode_opaque_fixed(xdr, ptr, NFS3_WRITEVERFSIZE) == 0;
+}
+
+static bool __maybe_unused
+xdrgen_decode_uid3(struct xdr_stream *xdr, uid3 *ptr)
+{
+	return xdrgen_decode_uint32(xdr, ptr);
+}
+
+static bool __maybe_unused
+xdrgen_decode_gid3(struct xdr_stream *xdr, gid3 *ptr)
+{
+	return xdrgen_decode_uint32(xdr, ptr);
+}
+
+static bool __maybe_unused
+xdrgen_decode_size3(struct xdr_stream *xdr, size3 *ptr)
+{
+	return xdrgen_decode_uint64(xdr, ptr);
+}
+
+static bool __maybe_unused
+xdrgen_decode_offset3(struct xdr_stream *xdr, offset3 *ptr)
+{
+	return xdrgen_decode_uint64(xdr, ptr);
+}
+
+static bool __maybe_unused
+xdrgen_decode_mode3(struct xdr_stream *xdr, mode3 *ptr)
+{
+	return xdrgen_decode_uint32(xdr, ptr);
+}
+
+static bool __maybe_unused
+xdrgen_decode_count3(struct xdr_stream *xdr, count3 *ptr)
+{
+	return xdrgen_decode_uint32(xdr, ptr);
+}
+
+static bool __maybe_unused
+xdrgen_decode_nfsstat3(struct xdr_stream *xdr, nfsstat3 *ptr)
+{
+	u32 val;
+
+	if (xdr_stream_decode_u32(xdr, &val) < 0)
+		return false;
+	/* Compiler may optimize to a range check for dense enums */
+	switch (val) {
+	case NFS3_OK:
+	case NFS3ERR_PERM:
+	case NFS3ERR_NOENT:
+	case NFS3ERR_IO:
+	case NFS3ERR_NXIO:
+	case NFS3ERR_ACCES:
+	case NFS3ERR_EXIST:
+	case NFS3ERR_XDEV:
+	case NFS3ERR_NODEV:
+	case NFS3ERR_NOTDIR:
+	case NFS3ERR_ISDIR:
+	case NFS3ERR_INVAL:
+	case NFS3ERR_FBIG:
+	case NFS3ERR_NOSPC:
+	case NFS3ERR_ROFS:
+	case NFS3ERR_MLINK:
+	case NFS3ERR_NAMETOOLONG:
+	case NFS3ERR_NOTEMPTY:
+	case NFS3ERR_DQUOT:
+	case NFS3ERR_STALE:
+	case NFS3ERR_REMOTE:
+	case NFS3ERR_BADHANDLE:
+	case NFS3ERR_NOT_SYNC:
+	case NFS3ERR_BAD_COOKIE:
+	case NFS3ERR_NOTSUPP:
+	case NFS3ERR_TOOSMALL:
+	case NFS3ERR_SERVERFAULT:
+	case NFS3ERR_BADTYPE:
+	case NFS3ERR_JUKEBOX:
+		break;
+	default:
+		return false;
+	}
+	*ptr = val;
+	return true;
+}
+
+static bool __maybe_unused
+xdrgen_decode_ftype3(struct xdr_stream *xdr, ftype3 *ptr)
+{
+	u32 val;
+
+	if (xdr_stream_decode_u32(xdr, &val) < 0)
+		return false;
+	/* Compiler may optimize to a range check for dense enums */
+	switch (val) {
+	case NF3REG:
+	case NF3DIR:
+	case NF3BLK:
+	case NF3CHR:
+	case NF3LNK:
+	case NF3SOCK:
+	case NF3FIFO:
+		break;
+	default:
+		return false;
+	}
+	*ptr = val;
+	return true;
+}
+
+static bool __maybe_unused
+xdrgen_decode_specdata3(struct xdr_stream *xdr, struct specdata3 *ptr)
+{
+	if (!xdrgen_decode_uint32(xdr, &ptr->specdata1))
+		return false;
+	if (!xdrgen_decode_uint32(xdr, &ptr->specdata2))
+		return false;
+	return true;
+}
+
+static bool __maybe_unused
+xdrgen_decode_nfs_fh3(struct xdr_stream *xdr, struct nfs_fh3 *ptr)
+{
+	if (!xdrgen_decode_opaque(xdr, &ptr->data, NFS3_FHSIZE))
+		return false;
+	return true;
+}
+
+static bool __maybe_unused
+xdrgen_decode_nfstime3(struct xdr_stream *xdr, struct nfstime3 *ptr)
+{
+	if (!xdrgen_decode_uint32(xdr, &ptr->seconds))
+		return false;
+	if (!xdrgen_decode_uint32(xdr, &ptr->nseconds))
+		return false;
+	return true;
+}
+
+static bool __maybe_unused
+xdrgen_decode_fattr3(struct xdr_stream *xdr, struct fattr3 *ptr)
+{
+	if (!xdrgen_decode_ftype3(xdr, &ptr->type))
+		return false;
+	if (!xdrgen_decode_mode3(xdr, &ptr->mode))
+		return false;
+	if (!xdrgen_decode_uint32(xdr, &ptr->nlink))
+		return false;
+	if (!xdrgen_decode_uid3(xdr, &ptr->uid))
+		return false;
+	if (!xdrgen_decode_gid3(xdr, &ptr->gid))
+		return false;
+	if (!xdrgen_decode_size3(xdr, &ptr->size))
+		return false;
+	if (!xdrgen_decode_size3(xdr, &ptr->used))
+		return false;
+	if (!xdrgen_decode_specdata3(xdr, &ptr->rdev))
+		return false;
+	if (!xdrgen_decode_uint64(xdr, &ptr->fsid))
+		return false;
+	if (!xdrgen_decode_fileid3(xdr, &ptr->fileid))
+		return false;
+	if (!xdrgen_decode_nfstime3(xdr, &ptr->atime))
+		return false;
+	if (!xdrgen_decode_nfstime3(xdr, &ptr->mtime))
+		return false;
+	if (!xdrgen_decode_nfstime3(xdr, &ptr->ctime))
+		return false;
+	return true;
+}
+
+static bool __maybe_unused
+xdrgen_decode_post_op_attr(struct xdr_stream *xdr, struct post_op_attr *ptr)
+{
+	if (!xdrgen_decode_bool(xdr, &ptr->attributes_follow))
+		return false;
+	if (ptr->attributes_follow) {
+		if (!xdrgen_decode_fattr3(xdr, &ptr->u.attributes))
+			return false;
+	}
+	return true;
+}
+
+static bool __maybe_unused
+xdrgen_decode_wcc_attr(struct xdr_stream *xdr, struct wcc_attr *ptr)
+{
+	if (!xdrgen_decode_size3(xdr, &ptr->size))
+		return false;
+	if (!xdrgen_decode_nfstime3(xdr, &ptr->mtime))
+		return false;
+	if (!xdrgen_decode_nfstime3(xdr, &ptr->ctime))
+		return false;
+	return true;
+}
+
+static bool __maybe_unused
+xdrgen_decode_pre_op_attr(struct xdr_stream *xdr, struct pre_op_attr *ptr)
+{
+	if (!xdrgen_decode_bool(xdr, &ptr->attributes_follow))
+		return false;
+	if (ptr->attributes_follow) {
+		if (!xdrgen_decode_wcc_attr(xdr, &ptr->u.attributes))
+			return false;
+	}
+	return true;
+}
+
+static bool __maybe_unused
+xdrgen_decode_wcc_data(struct xdr_stream *xdr, struct wcc_data *ptr)
+{
+	if (!xdrgen_decode_pre_op_attr(xdr, &ptr->before))
+		return false;
+	if (!xdrgen_decode_post_op_attr(xdr, &ptr->after))
+		return false;
+	return true;
+}
+
+static bool __maybe_unused
+xdrgen_decode_post_op_fh3(struct xdr_stream *xdr, struct post_op_fh3 *ptr)
+{
+	if (!xdrgen_decode_bool(xdr, &ptr->handle_follows))
+		return false;
+	if (ptr->handle_follows) {
+		if (!xdrgen_decode_nfs_fh3(xdr, &ptr->u.handle))
+			return false;
+	}
+	return true;
+}
+
+static bool __maybe_unused
+xdrgen_decode_time_how(struct xdr_stream *xdr, time_how *ptr)
+{
+	u32 val;
+
+	if (xdr_stream_decode_u32(xdr, &val) < 0)
+		return false;
+	/* Compiler may optimize to a range check for dense enums */
+	switch (val) {
+	case DONT_CHANGE:
+	case SET_TO_SERVER_TIME:
+	case SET_TO_CLIENT_TIME:
+		break;
+	default:
+		return false;
+	}
+	*ptr = val;
+	return true;
+}
+
+static bool __maybe_unused
+xdrgen_decode_set_mode3(struct xdr_stream *xdr, struct set_mode3 *ptr)
+{
+	if (!xdrgen_decode_bool(xdr, &ptr->set_it))
+		return false;
+	if (ptr->set_it) {
+		if (!xdrgen_decode_mode3(xdr, &ptr->u.mode))
+			return false;
+	}
+	return true;
+}
+
+static bool __maybe_unused
+xdrgen_decode_set_uid3(struct xdr_stream *xdr, struct set_uid3 *ptr)
+{
+	if (!xdrgen_decode_bool(xdr, &ptr->set_it))
+		return false;
+	if (ptr->set_it) {
+		if (!xdrgen_decode_uid3(xdr, &ptr->u.uid))
+			return false;
+	}
+	return true;
+}
+
+static bool __maybe_unused
+xdrgen_decode_set_gid3(struct xdr_stream *xdr, struct set_gid3 *ptr)
+{
+	if (!xdrgen_decode_bool(xdr, &ptr->set_it))
+		return false;
+	if (ptr->set_it) {
+		if (!xdrgen_decode_gid3(xdr, &ptr->u.gid))
+			return false;
+	}
+	return true;
+}
+
+static bool __maybe_unused
+xdrgen_decode_set_size3(struct xdr_stream *xdr, struct set_size3 *ptr)
+{
+	if (!xdrgen_decode_bool(xdr, &ptr->set_it))
+		return false;
+	if (ptr->set_it) {
+		if (!xdrgen_decode_size3(xdr, &ptr->u.size))
+			return false;
+	}
+	return true;
+}
+
+static bool __maybe_unused
+xdrgen_decode_set_atime(struct xdr_stream *xdr, struct set_atime *ptr)
+{
+	if (!xdrgen_decode_time_how(xdr, &ptr->set_it))
+		return false;
+	switch (ptr->set_it) {
+	case SET_TO_CLIENT_TIME:
+		if (!xdrgen_decode_nfstime3(xdr, &ptr->u.atime))
+			return false;
+		break;
+	default:
+		break;
+	}
+	return true;
+}
+
+static bool __maybe_unused
+xdrgen_decode_set_mtime(struct xdr_stream *xdr, struct set_mtime *ptr)
+{
+	if (!xdrgen_decode_time_how(xdr, &ptr->set_it))
+		return false;
+	switch (ptr->set_it) {
+	case SET_TO_CLIENT_TIME:
+		if (!xdrgen_decode_nfstime3(xdr, &ptr->u.mtime))
+			return false;
+		break;
+	default:
+		break;
+	}
+	return true;
+}
+
+static bool __maybe_unused
+xdrgen_decode_sattr3(struct xdr_stream *xdr, struct sattr3 *ptr)
+{
+	if (!xdrgen_decode_set_mode3(xdr, &ptr->mode))
+		return false;
+	if (!xdrgen_decode_set_uid3(xdr, &ptr->uid))
+		return false;
+	if (!xdrgen_decode_set_gid3(xdr, &ptr->gid))
+		return false;
+	if (!xdrgen_decode_set_size3(xdr, &ptr->size))
+		return false;
+	if (!xdrgen_decode_set_atime(xdr, &ptr->atime))
+		return false;
+	if (!xdrgen_decode_set_mtime(xdr, &ptr->mtime))
+		return false;
+	return true;
+}
+
+static bool __maybe_unused
+xdrgen_decode_diropargs3(struct xdr_stream *xdr, struct diropargs3 *ptr)
+{
+	if (!xdrgen_decode_nfs_fh3(xdr, &ptr->dir))
+		return false;
+	if (!xdrgen_decode_filename3(xdr, &ptr->name))
+		return false;
+	return true;
+}
+
+static bool __maybe_unused
+xdrgen_decode_GETATTR3args(struct xdr_stream *xdr, struct GETATTR3args *ptr)
+{
+	if (!xdrgen_decode_nfs_fh3(xdr, &ptr->object))
+		return false;
+	return true;
+}
+
+static bool __maybe_unused
+xdrgen_decode_GETATTR3resok(struct xdr_stream *xdr, struct GETATTR3resok *ptr)
+{
+	if (!xdrgen_decode_fattr3(xdr, &ptr->obj_attributes))
+		return false;
+	return true;
+}
+
+static bool __maybe_unused
+xdrgen_decode_GETATTR3res(struct xdr_stream *xdr, struct GETATTR3res *ptr)
+{
+	if (!xdrgen_decode_nfsstat3(xdr, &ptr->status))
+		return false;
+	switch (ptr->status) {
+	case NFS3_OK:
+		if (!xdrgen_decode_GETATTR3resok(xdr, &ptr->u.resok))
+			return false;
+		break;
+	default:
+		break;
+	}
+	return true;
+}
+
+static bool __maybe_unused
+xdrgen_decode_sattrguard3(struct xdr_stream *xdr, struct sattrguard3 *ptr)
+{
+	if (!xdrgen_decode_bool(xdr, &ptr->check))
+		return false;
+	if (ptr->check) {
+		if (!xdrgen_decode_nfstime3(xdr, &ptr->u.obj_ctime))
+			return false;
+	}
+	return true;
+}
+
+static bool __maybe_unused
+xdrgen_decode_SETATTR3args(struct xdr_stream *xdr, struct SETATTR3args *ptr)
+{
+	if (!xdrgen_decode_nfs_fh3(xdr, &ptr->object))
+		return false;
+	if (!xdrgen_decode_sattr3(xdr, &ptr->new_attributes))
+		return false;
+	if (!xdrgen_decode_sattrguard3(xdr, &ptr->guard))
+		return false;
+	return true;
+}
+
+static bool __maybe_unused
+xdrgen_decode_SETATTR3resok(struct xdr_stream *xdr, struct SETATTR3resok *ptr)
+{
+	if (!xdrgen_decode_wcc_data(xdr, &ptr->obj_wcc))
+		return false;
+	return true;
+}
+
+static bool __maybe_unused
+xdrgen_decode_SETATTR3resfail(struct xdr_stream *xdr, struct SETATTR3resfail *ptr)
+{
+	if (!xdrgen_decode_wcc_data(xdr, &ptr->obj_wcc))
+		return false;
+	return true;
+}
+
+static bool __maybe_unused
+xdrgen_decode_SETATTR3res(struct xdr_stream *xdr, struct SETATTR3res *ptr)
+{
+	if (!xdrgen_decode_nfsstat3(xdr, &ptr->status))
+		return false;
+	switch (ptr->status) {
+	case NFS3_OK:
+		if (!xdrgen_decode_SETATTR3resok(xdr, &ptr->u.resok))
+			return false;
+		break;
+	default:
+		if (!xdrgen_decode_SETATTR3resfail(xdr, &ptr->u.resfail))
+			return false;
+	}
+	return true;
+}
+
+static bool __maybe_unused
+xdrgen_decode_LOOKUP3args(struct xdr_stream *xdr, struct LOOKUP3args *ptr)
+{
+	if (!xdrgen_decode_diropargs3(xdr, &ptr->what))
+		return false;
+	return true;
+}
+
+static bool __maybe_unused
+xdrgen_decode_LOOKUP3resok(struct xdr_stream *xdr, struct LOOKUP3resok *ptr)
+{
+	if (!xdrgen_decode_nfs_fh3(xdr, &ptr->object))
+		return false;
+	if (!xdrgen_decode_post_op_attr(xdr, &ptr->obj_attributes))
+		return false;
+	if (!xdrgen_decode_post_op_attr(xdr, &ptr->dir_attributes))
+		return false;
+	return true;
+}
+
+static bool __maybe_unused
+xdrgen_decode_LOOKUP3resfail(struct xdr_stream *xdr, struct LOOKUP3resfail *ptr)
+{
+	if (!xdrgen_decode_post_op_attr(xdr, &ptr->dir_attributes))
+		return false;
+	return true;
+}
+
+static bool __maybe_unused
+xdrgen_decode_LOOKUP3res(struct xdr_stream *xdr, struct LOOKUP3res *ptr)
+{
+	if (!xdrgen_decode_nfsstat3(xdr, &ptr->status))
+		return false;
+	switch (ptr->status) {
+	case NFS3_OK:
+		if (!xdrgen_decode_LOOKUP3resok(xdr, &ptr->u.resok))
+			return false;
+		break;
+	default:
+		if (!xdrgen_decode_LOOKUP3resfail(xdr, &ptr->u.resfail))
+			return false;
+	}
+	return true;
+}
+
+static bool __maybe_unused
+xdrgen_decode_ACCESS3args(struct xdr_stream *xdr, struct ACCESS3args *ptr)
+{
+	if (!xdrgen_decode_nfs_fh3(xdr, &ptr->object))
+		return false;
+	if (!xdrgen_decode_uint32(xdr, &ptr->access))
+		return false;
+	return true;
+}
+
+static bool __maybe_unused
+xdrgen_decode_ACCESS3resok(struct xdr_stream *xdr, struct ACCESS3resok *ptr)
+{
+	if (!xdrgen_decode_post_op_attr(xdr, &ptr->obj_attributes))
+		return false;
+	if (!xdrgen_decode_uint32(xdr, &ptr->access))
+		return false;
+	return true;
+}
+
+static bool __maybe_unused
+xdrgen_decode_ACCESS3resfail(struct xdr_stream *xdr, struct ACCESS3resfail *ptr)
+{
+	if (!xdrgen_decode_post_op_attr(xdr, &ptr->obj_attributes))
+		return false;
+	return true;
+}
+
+static bool __maybe_unused
+xdrgen_decode_ACCESS3res(struct xdr_stream *xdr, struct ACCESS3res *ptr)
+{
+	if (!xdrgen_decode_nfsstat3(xdr, &ptr->status))
+		return false;
+	switch (ptr->status) {
+	case NFS3_OK:
+		if (!xdrgen_decode_ACCESS3resok(xdr, &ptr->u.resok))
+			return false;
+		break;
+	default:
+		if (!xdrgen_decode_ACCESS3resfail(xdr, &ptr->u.resfail))
+			return false;
+	}
+	return true;
+}
+
+static bool __maybe_unused
+xdrgen_decode_READLINK3args(struct xdr_stream *xdr, struct READLINK3args *ptr)
+{
+	if (!xdrgen_decode_nfs_fh3(xdr, &ptr->symlink))
+		return false;
+	return true;
+}
+
+static bool __maybe_unused
+xdrgen_decode_READLINK3resok(struct xdr_stream *xdr, struct READLINK3resok *ptr)
+{
+	if (!xdrgen_decode_post_op_attr(xdr, &ptr->symlink_attributes))
+		return false;
+	if (!xdrgen_decode_nfspath3(xdr, &ptr->data))
+		return false;
+	return true;
+}
+
+static bool __maybe_unused
+xdrgen_decode_READLINK3resfail(struct xdr_stream *xdr, struct READLINK3resfail *ptr)
+{
+	if (!xdrgen_decode_post_op_attr(xdr, &ptr->symlink_attributes))
+		return false;
+	return true;
+}
+
+static bool __maybe_unused
+xdrgen_decode_READLINK3res(struct xdr_stream *xdr, struct READLINK3res *ptr)
+{
+	if (!xdrgen_decode_nfsstat3(xdr, &ptr->status))
+		return false;
+	switch (ptr->status) {
+	case NFS3_OK:
+		if (!xdrgen_decode_READLINK3resok(xdr, &ptr->u.resok))
+			return false;
+		break;
+	default:
+		if (!xdrgen_decode_READLINK3resfail(xdr, &ptr->u.resfail))
+			return false;
+	}
+	return true;
+}
+
+static bool __maybe_unused
+xdrgen_decode_READ3args(struct xdr_stream *xdr, struct READ3args *ptr)
+{
+	if (!xdrgen_decode_nfs_fh3(xdr, &ptr->file))
+		return false;
+	if (!xdrgen_decode_offset3(xdr, &ptr->offset))
+		return false;
+	if (!xdrgen_decode_count3(xdr, &ptr->count))
+		return false;
+	return true;
+}
+
+static bool __maybe_unused
+xdrgen_decode_READ3resok(struct xdr_stream *xdr, struct READ3resok *ptr)
+{
+	if (!xdrgen_decode_post_op_attr(xdr, &ptr->file_attributes))
+		return false;
+	if (!xdrgen_decode_count3(xdr, &ptr->count))
+		return false;
+	if (!xdrgen_decode_bool(xdr, &ptr->eof))
+		return false;
+	if (!xdrgen_decode_opaque(xdr, &ptr->data, 0))
+		return false;
+	return true;
+}
+
+static bool __maybe_unused
+xdrgen_decode_READ3resfail(struct xdr_stream *xdr, struct READ3resfail *ptr)
+{
+	if (!xdrgen_decode_post_op_attr(xdr, &ptr->file_attributes))
+		return false;
+	return true;
+}
+
+static bool __maybe_unused
+xdrgen_decode_READ3res(struct xdr_stream *xdr, struct READ3res *ptr)
+{
+	if (!xdrgen_decode_nfsstat3(xdr, &ptr->status))
+		return false;
+	switch (ptr->status) {
+	case NFS3_OK:
+		if (!xdrgen_decode_READ3resok(xdr, &ptr->u.resok))
+			return false;
+		break;
+	default:
+		if (!xdrgen_decode_READ3resfail(xdr, &ptr->u.resfail))
+			return false;
+	}
+	return true;
+}
+
+static bool __maybe_unused
+xdrgen_decode_stable_how(struct xdr_stream *xdr, stable_how *ptr)
+{
+	u32 val;
+
+	if (xdr_stream_decode_u32(xdr, &val) < 0)
+		return false;
+	/* Compiler may optimize to a range check for dense enums */
+	switch (val) {
+	case UNSTABLE:
+	case DATA_SYNC:
+	case FILE_SYNC:
+		break;
+	default:
+		return false;
+	}
+	*ptr = val;
+	return true;
+}
+
+static bool __maybe_unused
+xdrgen_decode_WRITE3args(struct xdr_stream *xdr, struct WRITE3args *ptr)
+{
+	if (!xdrgen_decode_nfs_fh3(xdr, &ptr->file))
+		return false;
+	if (!xdrgen_decode_offset3(xdr, &ptr->offset))
+		return false;
+	if (!xdrgen_decode_count3(xdr, &ptr->count))
+		return false;
+	if (!xdrgen_decode_stable_how(xdr, &ptr->stable))
+		return false;
+	if (!xdrgen_decode_opaque(xdr, &ptr->data, 0))
+		return false;
+	return true;
+}
+
+static bool __maybe_unused
+xdrgen_decode_WRITE3resok(struct xdr_stream *xdr, struct WRITE3resok *ptr)
+{
+	if (!xdrgen_decode_wcc_data(xdr, &ptr->file_wcc))
+		return false;
+	if (!xdrgen_decode_count3(xdr, &ptr->count))
+		return false;
+	if (!xdrgen_decode_stable_how(xdr, &ptr->committed))
+		return false;
+	if (!xdrgen_decode_writeverf3(xdr, &ptr->verf))
+		return false;
+	return true;
+}
+
+static bool __maybe_unused
+xdrgen_decode_WRITE3resfail(struct xdr_stream *xdr, struct WRITE3resfail *ptr)
+{
+	if (!xdrgen_decode_wcc_data(xdr, &ptr->file_wcc))
+		return false;
+	return true;
+}
+
+static bool __maybe_unused
+xdrgen_decode_WRITE3res(struct xdr_stream *xdr, struct WRITE3res *ptr)
+{
+	if (!xdrgen_decode_nfsstat3(xdr, &ptr->status))
+		return false;
+	switch (ptr->status) {
+	case NFS3_OK:
+		if (!xdrgen_decode_WRITE3resok(xdr, &ptr->u.resok))
+			return false;
+		break;
+	default:
+		if (!xdrgen_decode_WRITE3resfail(xdr, &ptr->u.resfail))
+			return false;
+	}
+	return true;
+}
+
+static bool __maybe_unused
+xdrgen_decode_createmode3(struct xdr_stream *xdr, createmode3 *ptr)
+{
+	u32 val;
+
+	if (xdr_stream_decode_u32(xdr, &val) < 0)
+		return false;
+	/* Compiler may optimize to a range check for dense enums */
+	switch (val) {
+	case UNCHECKED:
+	case GUARDED:
+	case EXCLUSIVE:
+		break;
+	default:
+		return false;
+	}
+	*ptr = val;
+	return true;
+}
+
+static bool __maybe_unused
+xdrgen_decode_createhow3(struct xdr_stream *xdr, struct createhow3 *ptr)
+{
+	if (!xdrgen_decode_createmode3(xdr, &ptr->mode))
+		return false;
+	switch (ptr->mode) {
+	case UNCHECKED:
+	case GUARDED:
+		if (!xdrgen_decode_sattr3(xdr, &ptr->u.obj_attributes))
+			return false;
+		break;
+	case EXCLUSIVE:
+		if (!xdrgen_decode_createverf3(xdr, &ptr->u.verf))
+			return false;
+		break;
+	default:
+		break;
+	}
+	return true;
+}
+
+static bool __maybe_unused
+xdrgen_decode_CREATE3args(struct xdr_stream *xdr, struct CREATE3args *ptr)
+{
+	if (!xdrgen_decode_diropargs3(xdr, &ptr->where))
+		return false;
+	if (!xdrgen_decode_createhow3(xdr, &ptr->how))
+		return false;
+	return true;
+}
+
+static bool __maybe_unused
+xdrgen_decode_CREATE3resok(struct xdr_stream *xdr, struct CREATE3resok *ptr)
+{
+	if (!xdrgen_decode_post_op_fh3(xdr, &ptr->obj))
+		return false;
+	if (!xdrgen_decode_post_op_attr(xdr, &ptr->obj_attributes))
+		return false;
+	if (!xdrgen_decode_wcc_data(xdr, &ptr->dir_wcc))
+		return false;
+	return true;
+}
+
+static bool __maybe_unused
+xdrgen_decode_CREATE3resfail(struct xdr_stream *xdr, struct CREATE3resfail *ptr)
+{
+	if (!xdrgen_decode_wcc_data(xdr, &ptr->dir_wcc))
+		return false;
+	return true;
+}
+
+static bool __maybe_unused
+xdrgen_decode_CREATE3res(struct xdr_stream *xdr, struct CREATE3res *ptr)
+{
+	if (!xdrgen_decode_nfsstat3(xdr, &ptr->status))
+		return false;
+	switch (ptr->status) {
+	case NFS3_OK:
+		if (!xdrgen_decode_CREATE3resok(xdr, &ptr->u.resok))
+			return false;
+		break;
+	default:
+		if (!xdrgen_decode_CREATE3resfail(xdr, &ptr->u.resfail))
+			return false;
+	}
+	return true;
+}
+
+static bool __maybe_unused
+xdrgen_decode_MKDIR3args(struct xdr_stream *xdr, struct MKDIR3args *ptr)
+{
+	if (!xdrgen_decode_diropargs3(xdr, &ptr->where))
+		return false;
+	if (!xdrgen_decode_sattr3(xdr, &ptr->attributes))
+		return false;
+	return true;
+}
+
+static bool __maybe_unused
+xdrgen_decode_MKDIR3resok(struct xdr_stream *xdr, struct MKDIR3resok *ptr)
+{
+	if (!xdrgen_decode_post_op_fh3(xdr, &ptr->obj))
+		return false;
+	if (!xdrgen_decode_post_op_attr(xdr, &ptr->obj_attributes))
+		return false;
+	if (!xdrgen_decode_wcc_data(xdr, &ptr->dir_wcc))
+		return false;
+	return true;
+}
+
+static bool __maybe_unused
+xdrgen_decode_MKDIR3resfail(struct xdr_stream *xdr, struct MKDIR3resfail *ptr)
+{
+	if (!xdrgen_decode_wcc_data(xdr, &ptr->dir_wcc))
+		return false;
+	return true;
+}
+
+static bool __maybe_unused
+xdrgen_decode_MKDIR3res(struct xdr_stream *xdr, struct MKDIR3res *ptr)
+{
+	if (!xdrgen_decode_nfsstat3(xdr, &ptr->status))
+		return false;
+	switch (ptr->status) {
+	case NFS3_OK:
+		if (!xdrgen_decode_MKDIR3resok(xdr, &ptr->u.resok))
+			return false;
+		break;
+	default:
+		if (!xdrgen_decode_MKDIR3resfail(xdr, &ptr->u.resfail))
+			return false;
+	}
+	return true;
+}
+
+static bool __maybe_unused
+xdrgen_decode_symlinkdata3(struct xdr_stream *xdr, struct symlinkdata3 *ptr)
+{
+	if (!xdrgen_decode_sattr3(xdr, &ptr->symlink_attributes))
+		return false;
+	if (!xdrgen_decode_nfspath3(xdr, &ptr->symlink_data))
+		return false;
+	return true;
+}
+
+static bool __maybe_unused
+xdrgen_decode_SYMLINK3args(struct xdr_stream *xdr, struct SYMLINK3args *ptr)
+{
+	if (!xdrgen_decode_diropargs3(xdr, &ptr->where))
+		return false;
+	if (!xdrgen_decode_symlinkdata3(xdr, &ptr->symlink))
+		return false;
+	return true;
+}
+
+static bool __maybe_unused
+xdrgen_decode_SYMLINK3resok(struct xdr_stream *xdr, struct SYMLINK3resok *ptr)
+{
+	if (!xdrgen_decode_post_op_fh3(xdr, &ptr->obj))
+		return false;
+	if (!xdrgen_decode_post_op_attr(xdr, &ptr->obj_attributes))
+		return false;
+	if (!xdrgen_decode_wcc_data(xdr, &ptr->dir_wcc))
+		return false;
+	return true;
+}
+
+static bool __maybe_unused
+xdrgen_decode_SYMLINK3resfail(struct xdr_stream *xdr, struct SYMLINK3resfail *ptr)
+{
+	if (!xdrgen_decode_wcc_data(xdr, &ptr->dir_wcc))
+		return false;
+	return true;
+}
+
+static bool __maybe_unused
+xdrgen_decode_SYMLINK3res(struct xdr_stream *xdr, struct SYMLINK3res *ptr)
+{
+	if (!xdrgen_decode_nfsstat3(xdr, &ptr->status))
+		return false;
+	switch (ptr->status) {
+	case NFS3_OK:
+		if (!xdrgen_decode_SYMLINK3resok(xdr, &ptr->u.resok))
+			return false;
+		break;
+	default:
+		if (!xdrgen_decode_SYMLINK3resfail(xdr, &ptr->u.resfail))
+			return false;
+	}
+	return true;
+}
+
+static bool __maybe_unused
+xdrgen_decode_devicedata3(struct xdr_stream *xdr, struct devicedata3 *ptr)
+{
+	if (!xdrgen_decode_sattr3(xdr, &ptr->dev_attributes))
+		return false;
+	if (!xdrgen_decode_specdata3(xdr, &ptr->spec))
+		return false;
+	return true;
+}
+
+static bool __maybe_unused
+xdrgen_decode_mknoddata3(struct xdr_stream *xdr, struct mknoddata3 *ptr)
+{
+	if (!xdrgen_decode_ftype3(xdr, &ptr->type))
+		return false;
+	switch (ptr->type) {
+	case NF3CHR:
+	case NF3BLK:
+		if (!xdrgen_decode_devicedata3(xdr, &ptr->u.device))
+			return false;
+		break;
+	case NF3SOCK:
+	case NF3FIFO:
+		if (!xdrgen_decode_sattr3(xdr, &ptr->u.pipe_attributes))
+			return false;
+		break;
+	default:
+		break;
+	}
+	return true;
+}
+
+static bool __maybe_unused
+xdrgen_decode_MKNOD3args(struct xdr_stream *xdr, struct MKNOD3args *ptr)
+{
+	if (!xdrgen_decode_diropargs3(xdr, &ptr->where))
+		return false;
+	if (!xdrgen_decode_mknoddata3(xdr, &ptr->what))
+		return false;
+	return true;
+}
+
+static bool __maybe_unused
+xdrgen_decode_MKNOD3resok(struct xdr_stream *xdr, struct MKNOD3resok *ptr)
+{
+	if (!xdrgen_decode_post_op_fh3(xdr, &ptr->obj))
+		return false;
+	if (!xdrgen_decode_post_op_attr(xdr, &ptr->obj_attributes))
+		return false;
+	if (!xdrgen_decode_wcc_data(xdr, &ptr->dir_wcc))
+		return false;
+	return true;
+}
+
+static bool __maybe_unused
+xdrgen_decode_MKNOD3resfail(struct xdr_stream *xdr, struct MKNOD3resfail *ptr)
+{
+	if (!xdrgen_decode_wcc_data(xdr, &ptr->dir_wcc))
+		return false;
+	return true;
+}
+
+static bool __maybe_unused
+xdrgen_decode_MKNOD3res(struct xdr_stream *xdr, struct MKNOD3res *ptr)
+{
+	if (!xdrgen_decode_nfsstat3(xdr, &ptr->status))
+		return false;
+	switch (ptr->status) {
+	case NFS3_OK:
+		if (!xdrgen_decode_MKNOD3resok(xdr, &ptr->u.resok))
+			return false;
+		break;
+	default:
+		if (!xdrgen_decode_MKNOD3resfail(xdr, &ptr->u.resfail))
+			return false;
+	}
+	return true;
+}
+
+static bool __maybe_unused
+xdrgen_decode_REMOVE3args(struct xdr_stream *xdr, struct REMOVE3args *ptr)
+{
+	if (!xdrgen_decode_diropargs3(xdr, &ptr->object))
+		return false;
+	return true;
+}
+
+static bool __maybe_unused
+xdrgen_decode_REMOVE3resok(struct xdr_stream *xdr, struct REMOVE3resok *ptr)
+{
+	if (!xdrgen_decode_wcc_data(xdr, &ptr->dir_wcc))
+		return false;
+	return true;
+}
+
+static bool __maybe_unused
+xdrgen_decode_REMOVE3resfail(struct xdr_stream *xdr, struct REMOVE3resfail *ptr)
+{
+	if (!xdrgen_decode_wcc_data(xdr, &ptr->dir_wcc))
+		return false;
+	return true;
+}
+
+static bool __maybe_unused
+xdrgen_decode_REMOVE3res(struct xdr_stream *xdr, struct REMOVE3res *ptr)
+{
+	if (!xdrgen_decode_nfsstat3(xdr, &ptr->status))
+		return false;
+	switch (ptr->status) {
+	case NFS3_OK:
+		if (!xdrgen_decode_REMOVE3resok(xdr, &ptr->u.resok))
+			return false;
+		break;
+	default:
+		if (!xdrgen_decode_REMOVE3resfail(xdr, &ptr->u.resfail))
+			return false;
+	}
+	return true;
+}
+
+static bool __maybe_unused
+xdrgen_decode_RMDIR3args(struct xdr_stream *xdr, struct RMDIR3args *ptr)
+{
+	if (!xdrgen_decode_diropargs3(xdr, &ptr->object))
+		return false;
+	return true;
+}
+
+static bool __maybe_unused
+xdrgen_decode_RMDIR3resok(struct xdr_stream *xdr, struct RMDIR3resok *ptr)
+{
+	if (!xdrgen_decode_wcc_data(xdr, &ptr->dir_wcc))
+		return false;
+	return true;
+}
+
+static bool __maybe_unused
+xdrgen_decode_RMDIR3resfail(struct xdr_stream *xdr, struct RMDIR3resfail *ptr)
+{
+	if (!xdrgen_decode_wcc_data(xdr, &ptr->dir_wcc))
+		return false;
+	return true;
+}
+
+static bool __maybe_unused
+xdrgen_decode_RMDIR3res(struct xdr_stream *xdr, struct RMDIR3res *ptr)
+{
+	if (!xdrgen_decode_nfsstat3(xdr, &ptr->status))
+		return false;
+	switch (ptr->status) {
+	case NFS3_OK:
+		if (!xdrgen_decode_RMDIR3resok(xdr, &ptr->u.resok))
+			return false;
+		break;
+	default:
+		if (!xdrgen_decode_RMDIR3resfail(xdr, &ptr->u.resfail))
+			return false;
+	}
+	return true;
+}
+
+static bool __maybe_unused
+xdrgen_decode_RENAME3args(struct xdr_stream *xdr, struct RENAME3args *ptr)
+{
+	if (!xdrgen_decode_diropargs3(xdr, &ptr->from))
+		return false;
+	if (!xdrgen_decode_diropargs3(xdr, &ptr->to))
+		return false;
+	return true;
+}
+
+static bool __maybe_unused
+xdrgen_decode_RENAME3resok(struct xdr_stream *xdr, struct RENAME3resok *ptr)
+{
+	if (!xdrgen_decode_wcc_data(xdr, &ptr->fromdir_wcc))
+		return false;
+	if (!xdrgen_decode_wcc_data(xdr, &ptr->todir_wcc))
+		return false;
+	return true;
+}
+
+static bool __maybe_unused
+xdrgen_decode_RENAME3resfail(struct xdr_stream *xdr, struct RENAME3resfail *ptr)
+{
+	if (!xdrgen_decode_wcc_data(xdr, &ptr->fromdir_wcc))
+		return false;
+	if (!xdrgen_decode_wcc_data(xdr, &ptr->todir_wcc))
+		return false;
+	return true;
+}
+
+static bool __maybe_unused
+xdrgen_decode_RENAME3res(struct xdr_stream *xdr, struct RENAME3res *ptr)
+{
+	if (!xdrgen_decode_nfsstat3(xdr, &ptr->status))
+		return false;
+	switch (ptr->status) {
+	case NFS3_OK:
+		if (!xdrgen_decode_RENAME3resok(xdr, &ptr->u.resok))
+			return false;
+		break;
+	default:
+		if (!xdrgen_decode_RENAME3resfail(xdr, &ptr->u.resfail))
+			return false;
+	}
+	return true;
+}
+
+static bool __maybe_unused
+xdrgen_decode_LINK3args(struct xdr_stream *xdr, struct LINK3args *ptr)
+{
+	if (!xdrgen_decode_nfs_fh3(xdr, &ptr->file))
+		return false;
+	if (!xdrgen_decode_diropargs3(xdr, &ptr->link))
+		return false;
+	return true;
+}
+
+static bool __maybe_unused
+xdrgen_decode_LINK3resok(struct xdr_stream *xdr, struct LINK3resok *ptr)
+{
+	if (!xdrgen_decode_post_op_attr(xdr, &ptr->file_attributes))
+		return false;
+	if (!xdrgen_decode_wcc_data(xdr, &ptr->linkdir_wcc))
+		return false;
+	return true;
+}
+
+static bool __maybe_unused
+xdrgen_decode_LINK3resfail(struct xdr_stream *xdr, struct LINK3resfail *ptr)
+{
+	if (!xdrgen_decode_post_op_attr(xdr, &ptr->file_attributes))
+		return false;
+	if (!xdrgen_decode_wcc_data(xdr, &ptr->linkdir_wcc))
+		return false;
+	return true;
+}
+
+static bool __maybe_unused
+xdrgen_decode_LINK3res(struct xdr_stream *xdr, struct LINK3res *ptr)
+{
+	if (!xdrgen_decode_nfsstat3(xdr, &ptr->status))
+		return false;
+	switch (ptr->status) {
+	case NFS3_OK:
+		if (!xdrgen_decode_LINK3resok(xdr, &ptr->u.resok))
+			return false;
+		break;
+	default:
+		if (!xdrgen_decode_LINK3resfail(xdr, &ptr->u.resfail))
+			return false;
+	}
+	return true;
+}
+
+static bool __maybe_unused
+xdrgen_decode_READDIR3args(struct xdr_stream *xdr, struct READDIR3args *ptr)
+{
+	if (!xdrgen_decode_nfs_fh3(xdr, &ptr->dir))
+		return false;
+	if (!xdrgen_decode_cookie3(xdr, &ptr->cookie))
+		return false;
+	if (!xdrgen_decode_cookieverf3(xdr, &ptr->cookieverf))
+		return false;
+	if (!xdrgen_decode_count3(xdr, &ptr->count))
+		return false;
+	return true;
+}
+
+static bool __maybe_unused
+xdrgen_decode_entry3(struct xdr_stream *xdr, struct entry3 *ptr)
+{
+	bool opted;
+
+	if (!xdrgen_decode_bool(xdr, &opted))
+		return false;
+	if (!opted)
+		return true;
+
+	if (!xdrgen_decode_fileid3(xdr, &ptr->fileid))
+		return false;
+	if (!xdrgen_decode_filename3(xdr, &ptr->name))
+		return false;
+	if (!xdrgen_decode_cookie3(xdr, &ptr->cookie))
+		return false;
+	return true;
+}
+
+static bool __maybe_unused
+xdrgen_decode_dirlist3(struct xdr_stream *xdr, struct dirlist3 *ptr)
+{
+	if (!xdrgen_decode_entry3(xdr, ptr->entries))
+		return false;
+	if (!xdrgen_decode_bool(xdr, &ptr->eof))
+		return false;
+	return true;
+}
+
+static bool __maybe_unused
+xdrgen_decode_READDIR3resok(struct xdr_stream *xdr, struct READDIR3resok *ptr)
+{
+	if (!xdrgen_decode_post_op_attr(xdr, &ptr->dir_attributes))
+		return false;
+	if (!xdrgen_decode_cookieverf3(xdr, &ptr->cookieverf))
+		return false;
+	if (!xdrgen_decode_dirlist3(xdr, &ptr->reply))
+		return false;
+	return true;
+}
+
+static bool __maybe_unused
+xdrgen_decode_READDIR3resfail(struct xdr_stream *xdr, struct READDIR3resfail *ptr)
+{
+	if (!xdrgen_decode_post_op_attr(xdr, &ptr->dir_attributes))
+		return false;
+	return true;
+}
+
+static bool __maybe_unused
+xdrgen_decode_READDIR3res(struct xdr_stream *xdr, struct READDIR3res *ptr)
+{
+	if (!xdrgen_decode_nfsstat3(xdr, &ptr->status))
+		return false;
+	switch (ptr->status) {
+	case NFS3_OK:
+		if (!xdrgen_decode_READDIR3resok(xdr, &ptr->u.resok))
+			return false;
+		break;
+	default:
+		if (!xdrgen_decode_READDIR3resfail(xdr, &ptr->u.resfail))
+			return false;
+	}
+	return true;
+}
+
+static bool __maybe_unused
+xdrgen_decode_READDIRPLUS3args(struct xdr_stream *xdr, struct READDIRPLUS3args *ptr)
+{
+	if (!xdrgen_decode_nfs_fh3(xdr, &ptr->dir))
+		return false;
+	if (!xdrgen_decode_cookie3(xdr, &ptr->cookie))
+		return false;
+	if (!xdrgen_decode_cookieverf3(xdr, &ptr->cookieverf))
+		return false;
+	if (!xdrgen_decode_count3(xdr, &ptr->dircount))
+		return false;
+	if (!xdrgen_decode_count3(xdr, &ptr->maxcount))
+		return false;
+	return true;
+}
+
+static bool __maybe_unused
+xdrgen_decode_entryplus3(struct xdr_stream *xdr, struct entryplus3 *ptr)
+{
+	bool opted;
+
+	if (!xdrgen_decode_bool(xdr, &opted))
+		return false;
+	if (!opted)
+		return true;
+
+	if (!xdrgen_decode_fileid3(xdr, &ptr->fileid))
+		return false;
+	if (!xdrgen_decode_filename3(xdr, &ptr->name))
+		return false;
+	if (!xdrgen_decode_cookie3(xdr, &ptr->cookie))
+		return false;
+	if (!xdrgen_decode_post_op_attr(xdr, &ptr->name_attributes))
+		return false;
+	if (!xdrgen_decode_post_op_fh3(xdr, &ptr->name_handle))
+		return false;
+	return true;
+}
+
+static bool __maybe_unused
+xdrgen_decode_dirlistplus3(struct xdr_stream *xdr, struct dirlistplus3 *ptr)
+{
+	if (!xdrgen_decode_entryplus3(xdr, ptr->entries))
+		return false;
+	if (!xdrgen_decode_bool(xdr, &ptr->eof))
+		return false;
+	return true;
+}
+
+static bool __maybe_unused
+xdrgen_decode_READDIRPLUS3resok(struct xdr_stream *xdr, struct READDIRPLUS3resok *ptr)
+{
+	if (!xdrgen_decode_post_op_attr(xdr, &ptr->dir_attributes))
+		return false;
+	if (!xdrgen_decode_cookieverf3(xdr, &ptr->cookieverf))
+		return false;
+	if (!xdrgen_decode_dirlistplus3(xdr, &ptr->reply))
+		return false;
+	return true;
+}
+
+static bool __maybe_unused
+xdrgen_decode_READDIRPLUS3resfail(struct xdr_stream *xdr, struct READDIRPLUS3resfail *ptr)
+{
+	if (!xdrgen_decode_post_op_attr(xdr, &ptr->dir_attributes))
+		return false;
+	return true;
+}
+
+static bool __maybe_unused
+xdrgen_decode_READDIRPLUS3res(struct xdr_stream *xdr, struct READDIRPLUS3res *ptr)
+{
+	if (!xdrgen_decode_nfsstat3(xdr, &ptr->status))
+		return false;
+	switch (ptr->status) {
+	case NFS3_OK:
+		if (!xdrgen_decode_READDIRPLUS3resok(xdr, &ptr->u.resok))
+			return false;
+		break;
+	default:
+		if (!xdrgen_decode_READDIRPLUS3resfail(xdr, &ptr->u.resfail))
+			return false;
+	}
+	return true;
+}
+
+static bool __maybe_unused
+xdrgen_decode_FSSTAT3args(struct xdr_stream *xdr, struct FSSTAT3args *ptr)
+{
+	if (!xdrgen_decode_nfs_fh3(xdr, &ptr->fsroot))
+		return false;
+	return true;
+}
+
+static bool __maybe_unused
+xdrgen_decode_FSSTAT3resok(struct xdr_stream *xdr, struct FSSTAT3resok *ptr)
+{
+	if (!xdrgen_decode_post_op_attr(xdr, &ptr->obj_attributes))
+		return false;
+	if (!xdrgen_decode_size3(xdr, &ptr->tbytes))
+		return false;
+	if (!xdrgen_decode_size3(xdr, &ptr->fbytes))
+		return false;
+	if (!xdrgen_decode_size3(xdr, &ptr->abytes))
+		return false;
+	if (!xdrgen_decode_size3(xdr, &ptr->tfiles))
+		return false;
+	if (!xdrgen_decode_size3(xdr, &ptr->ffiles))
+		return false;
+	if (!xdrgen_decode_size3(xdr, &ptr->afiles))
+		return false;
+	if (!xdrgen_decode_uint32(xdr, &ptr->invarsec))
+		return false;
+	return true;
+}
+
+static bool __maybe_unused
+xdrgen_decode_FSSTAT3resfail(struct xdr_stream *xdr, struct FSSTAT3resfail *ptr)
+{
+	if (!xdrgen_decode_post_op_attr(xdr, &ptr->obj_attributes))
+		return false;
+	return true;
+}
+
+static bool __maybe_unused
+xdrgen_decode_FSSTAT3res(struct xdr_stream *xdr, struct FSSTAT3res *ptr)
+{
+	if (!xdrgen_decode_nfsstat3(xdr, &ptr->status))
+		return false;
+	switch (ptr->status) {
+	case NFS3_OK:
+		if (!xdrgen_decode_FSSTAT3resok(xdr, &ptr->u.resok))
+			return false;
+		break;
+	default:
+		if (!xdrgen_decode_FSSTAT3resfail(xdr, &ptr->u.resfail))
+			return false;
+	}
+	return true;
+}
+
+static bool __maybe_unused
+xdrgen_decode_FSINFO3args(struct xdr_stream *xdr, struct FSINFO3args *ptr)
+{
+	if (!xdrgen_decode_nfs_fh3(xdr, &ptr->fsroot))
+		return false;
+	return true;
+}
+
+static bool __maybe_unused
+xdrgen_decode_FSINFO3resok(struct xdr_stream *xdr, struct FSINFO3resok *ptr)
+{
+	if (!xdrgen_decode_post_op_attr(xdr, &ptr->obj_attributes))
+		return false;
+	if (!xdrgen_decode_uint32(xdr, &ptr->rtmax))
+		return false;
+	if (!xdrgen_decode_uint32(xdr, &ptr->rtpref))
+		return false;
+	if (!xdrgen_decode_uint32(xdr, &ptr->rtmult))
+		return false;
+	if (!xdrgen_decode_uint32(xdr, &ptr->wtmax))
+		return false;
+	if (!xdrgen_decode_uint32(xdr, &ptr->wtpref))
+		return false;
+	if (!xdrgen_decode_uint32(xdr, &ptr->wtmult))
+		return false;
+	if (!xdrgen_decode_uint32(xdr, &ptr->dtpref))
+		return false;
+	if (!xdrgen_decode_size3(xdr, &ptr->maxfilesize))
+		return false;
+	if (!xdrgen_decode_nfstime3(xdr, &ptr->time_delta))
+		return false;
+	if (!xdrgen_decode_uint32(xdr, &ptr->properties))
+		return false;
+	return true;
+}
+
+static bool __maybe_unused
+xdrgen_decode_FSINFO3resfail(struct xdr_stream *xdr, struct FSINFO3resfail *ptr)
+{
+	if (!xdrgen_decode_post_op_attr(xdr, &ptr->obj_attributes))
+		return false;
+	return true;
+}
+
+static bool __maybe_unused
+xdrgen_decode_FSINFO3res(struct xdr_stream *xdr, struct FSINFO3res *ptr)
+{
+	if (!xdrgen_decode_nfsstat3(xdr, &ptr->status))
+		return false;
+	switch (ptr->status) {
+	case NFS3_OK:
+		if (!xdrgen_decode_FSINFO3resok(xdr, &ptr->u.resok))
+			return false;
+		break;
+	default:
+		if (!xdrgen_decode_FSINFO3resfail(xdr, &ptr->u.resfail))
+			return false;
+	}
+	return true;
+}
+
+static bool __maybe_unused
+xdrgen_decode_PATHCONF3args(struct xdr_stream *xdr, struct PATHCONF3args *ptr)
+{
+	if (!xdrgen_decode_nfs_fh3(xdr, &ptr->object))
+		return false;
+	return true;
+}
+
+static bool __maybe_unused
+xdrgen_decode_PATHCONF3resok(struct xdr_stream *xdr, struct PATHCONF3resok *ptr)
+{
+	if (!xdrgen_decode_post_op_attr(xdr, &ptr->obj_attributes))
+		return false;
+	if (!xdrgen_decode_uint32(xdr, &ptr->linkmax))
+		return false;
+	if (!xdrgen_decode_uint32(xdr, &ptr->name_max))
+		return false;
+	if (!xdrgen_decode_bool(xdr, &ptr->no_trunc))
+		return false;
+	if (!xdrgen_decode_bool(xdr, &ptr->chown_restricted))
+		return false;
+	if (!xdrgen_decode_bool(xdr, &ptr->case_insensitive))
+		return false;
+	if (!xdrgen_decode_bool(xdr, &ptr->case_preserving))
+		return false;
+	return true;
+}
+
+static bool __maybe_unused
+xdrgen_decode_PATHCONF3resfail(struct xdr_stream *xdr, struct PATHCONF3resfail *ptr)
+{
+	if (!xdrgen_decode_post_op_attr(xdr, &ptr->obj_attributes))
+		return false;
+	return true;
+}
+
+static bool __maybe_unused
+xdrgen_decode_PATHCONF3res(struct xdr_stream *xdr, struct PATHCONF3res *ptr)
+{
+	if (!xdrgen_decode_nfsstat3(xdr, &ptr->status))
+		return false;
+	switch (ptr->status) {
+	case NFS3_OK:
+		if (!xdrgen_decode_PATHCONF3resok(xdr, &ptr->u.resok))
+			return false;
+		break;
+	default:
+		if (!xdrgen_decode_PATHCONF3resfail(xdr, &ptr->u.resfail))
+			return false;
+	}
+	return true;
+}
+
+static bool __maybe_unused
+xdrgen_decode_COMMIT3args(struct xdr_stream *xdr, struct COMMIT3args *ptr)
+{
+	if (!xdrgen_decode_nfs_fh3(xdr, &ptr->file))
+		return false;
+	if (!xdrgen_decode_offset3(xdr, &ptr->offset))
+		return false;
+	if (!xdrgen_decode_count3(xdr, &ptr->count))
+		return false;
+	return true;
+}
+
+static bool __maybe_unused
+xdrgen_decode_COMMIT3resok(struct xdr_stream *xdr, struct COMMIT3resok *ptr)
+{
+	if (!xdrgen_decode_wcc_data(xdr, &ptr->file_wcc))
+		return false;
+	if (!xdrgen_decode_writeverf3(xdr, &ptr->verf))
+		return false;
+	return true;
+}
+
+static bool __maybe_unused
+xdrgen_decode_COMMIT3resfail(struct xdr_stream *xdr, struct COMMIT3resfail *ptr)
+{
+	if (!xdrgen_decode_wcc_data(xdr, &ptr->file_wcc))
+		return false;
+	return true;
+}
+
+static bool __maybe_unused
+xdrgen_decode_COMMIT3res(struct xdr_stream *xdr, struct COMMIT3res *ptr)
+{
+	if (!xdrgen_decode_nfsstat3(xdr, &ptr->status))
+		return false;
+	switch (ptr->status) {
+	case NFS3_OK:
+		if (!xdrgen_decode_COMMIT3resok(xdr, &ptr->u.resok))
+			return false;
+		break;
+	default:
+		if (!xdrgen_decode_COMMIT3resfail(xdr, &ptr->u.resfail))
+			return false;
+	}
+	return true;
+}
+
+/**
+ * nfs_svc_decode_GETATTR3args - Decode a GETATTR3args argument
+ * @rqstp: RPC transaction context
+ * @xdr: source XDR data stream
+ *
+ * Return values:
+ *   %true: procedure arguments decoded successfully
+ *   %false: decode failed
+ */
+bool nfs_svc_decode_GETATTR3args(struct svc_rqst *rqstp, struct xdr_stream *xdr)
+{
+	struct GETATTR3args *argp = rqstp->rq_argp;
+
+	return xdrgen_decode_GETATTR3args(xdr, argp);
+}
+
+/**
+ * nfs_svc_decode_SETATTR3args - Decode a SETATTR3args argument
+ * @rqstp: RPC transaction context
+ * @xdr: source XDR data stream
+ *
+ * Return values:
+ *   %true: procedure arguments decoded successfully
+ *   %false: decode failed
+ */
+bool nfs_svc_decode_SETATTR3args(struct svc_rqst *rqstp, struct xdr_stream *xdr)
+{
+	struct SETATTR3args *argp = rqstp->rq_argp;
+
+	return xdrgen_decode_SETATTR3args(xdr, argp);
+}
+
+/**
+ * nfs_svc_decode_LOOKUP3args - Decode a LOOKUP3args argument
+ * @rqstp: RPC transaction context
+ * @xdr: source XDR data stream
+ *
+ * Return values:
+ *   %true: procedure arguments decoded successfully
+ *   %false: decode failed
+ */
+bool nfs_svc_decode_LOOKUP3args(struct svc_rqst *rqstp, struct xdr_stream *xdr)
+{
+	struct LOOKUP3args *argp = rqstp->rq_argp;
+
+	return xdrgen_decode_LOOKUP3args(xdr, argp);
+}
+
+/**
+ * nfs_svc_decode_ACCESS3args - Decode a ACCESS3args argument
+ * @rqstp: RPC transaction context
+ * @xdr: source XDR data stream
+ *
+ * Return values:
+ *   %true: procedure arguments decoded successfully
+ *   %false: decode failed
+ */
+bool nfs_svc_decode_ACCESS3args(struct svc_rqst *rqstp, struct xdr_stream *xdr)
+{
+	struct ACCESS3args *argp = rqstp->rq_argp;
+
+	return xdrgen_decode_ACCESS3args(xdr, argp);
+}
+
+/**
+ * nfs_svc_decode_READLINK3args - Decode a READLINK3args argument
+ * @rqstp: RPC transaction context
+ * @xdr: source XDR data stream
+ *
+ * Return values:
+ *   %true: procedure arguments decoded successfully
+ *   %false: decode failed
+ */
+bool nfs_svc_decode_READLINK3args(struct svc_rqst *rqstp, struct xdr_stream *xdr)
+{
+	struct READLINK3args *argp = rqstp->rq_argp;
+
+	return xdrgen_decode_READLINK3args(xdr, argp);
+}
+
+/**
+ * nfs_svc_decode_READ3args - Decode a READ3args argument
+ * @rqstp: RPC transaction context
+ * @xdr: source XDR data stream
+ *
+ * Return values:
+ *   %true: procedure arguments decoded successfully
+ *   %false: decode failed
+ */
+bool nfs_svc_decode_READ3args(struct svc_rqst *rqstp, struct xdr_stream *xdr)
+{
+	struct READ3args *argp = rqstp->rq_argp;
+
+	return xdrgen_decode_READ3args(xdr, argp);
+}
+
+/**
+ * nfs_svc_decode_WRITE3args - Decode a WRITE3args argument
+ * @rqstp: RPC transaction context
+ * @xdr: source XDR data stream
+ *
+ * Return values:
+ *   %true: procedure arguments decoded successfully
+ *   %false: decode failed
+ */
+bool nfs_svc_decode_WRITE3args(struct svc_rqst *rqstp, struct xdr_stream *xdr)
+{
+	struct WRITE3args *argp = rqstp->rq_argp;
+
+	return xdrgen_decode_WRITE3args(xdr, argp);
+}
+
+/**
+ * nfs_svc_decode_CREATE3args - Decode a CREATE3args argument
+ * @rqstp: RPC transaction context
+ * @xdr: source XDR data stream
+ *
+ * Return values:
+ *   %true: procedure arguments decoded successfully
+ *   %false: decode failed
+ */
+bool nfs_svc_decode_CREATE3args(struct svc_rqst *rqstp, struct xdr_stream *xdr)
+{
+	struct CREATE3args *argp = rqstp->rq_argp;
+
+	return xdrgen_decode_CREATE3args(xdr, argp);
+}
+
+/**
+ * nfs_svc_decode_MKDIR3args - Decode a MKDIR3args argument
+ * @rqstp: RPC transaction context
+ * @xdr: source XDR data stream
+ *
+ * Return values:
+ *   %true: procedure arguments decoded successfully
+ *   %false: decode failed
+ */
+bool nfs_svc_decode_MKDIR3args(struct svc_rqst *rqstp, struct xdr_stream *xdr)
+{
+	struct MKDIR3args *argp = rqstp->rq_argp;
+
+	return xdrgen_decode_MKDIR3args(xdr, argp);
+}
+
+/**
+ * nfs_svc_decode_SYMLINK3args - Decode a SYMLINK3args argument
+ * @rqstp: RPC transaction context
+ * @xdr: source XDR data stream
+ *
+ * Return values:
+ *   %true: procedure arguments decoded successfully
+ *   %false: decode failed
+ */
+bool nfs_svc_decode_SYMLINK3args(struct svc_rqst *rqstp, struct xdr_stream *xdr)
+{
+	struct SYMLINK3args *argp = rqstp->rq_argp;
+
+	return xdrgen_decode_SYMLINK3args(xdr, argp);
+}
+
+/**
+ * nfs_svc_decode_MKNOD3args - Decode a MKNOD3args argument
+ * @rqstp: RPC transaction context
+ * @xdr: source XDR data stream
+ *
+ * Return values:
+ *   %true: procedure arguments decoded successfully
+ *   %false: decode failed
+ */
+bool nfs_svc_decode_MKNOD3args(struct svc_rqst *rqstp, struct xdr_stream *xdr)
+{
+	struct MKNOD3args *argp = rqstp->rq_argp;
+
+	return xdrgen_decode_MKNOD3args(xdr, argp);
+}
+
+/**
+ * nfs_svc_decode_REMOVE3args - Decode a REMOVE3args argument
+ * @rqstp: RPC transaction context
+ * @xdr: source XDR data stream
+ *
+ * Return values:
+ *   %true: procedure arguments decoded successfully
+ *   %false: decode failed
+ */
+bool nfs_svc_decode_REMOVE3args(struct svc_rqst *rqstp, struct xdr_stream *xdr)
+{
+	struct REMOVE3args *argp = rqstp->rq_argp;
+
+	return xdrgen_decode_REMOVE3args(xdr, argp);
+}
+
+/**
+ * nfs_svc_decode_RMDIR3args - Decode a RMDIR3args argument
+ * @rqstp: RPC transaction context
+ * @xdr: source XDR data stream
+ *
+ * Return values:
+ *   %true: procedure arguments decoded successfully
+ *   %false: decode failed
+ */
+bool nfs_svc_decode_RMDIR3args(struct svc_rqst *rqstp, struct xdr_stream *xdr)
+{
+	struct RMDIR3args *argp = rqstp->rq_argp;
+
+	return xdrgen_decode_RMDIR3args(xdr, argp);
+}
+
+/**
+ * nfs_svc_decode_RENAME3args - Decode a RENAME3args argument
+ * @rqstp: RPC transaction context
+ * @xdr: source XDR data stream
+ *
+ * Return values:
+ *   %true: procedure arguments decoded successfully
+ *   %false: decode failed
+ */
+bool nfs_svc_decode_RENAME3args(struct svc_rqst *rqstp, struct xdr_stream *xdr)
+{
+	struct RENAME3args *argp = rqstp->rq_argp;
+
+	return xdrgen_decode_RENAME3args(xdr, argp);
+}
+
+/**
+ * nfs_svc_decode_LINK3args - Decode a LINK3args argument
+ * @rqstp: RPC transaction context
+ * @xdr: source XDR data stream
+ *
+ * Return values:
+ *   %true: procedure arguments decoded successfully
+ *   %false: decode failed
+ */
+bool nfs_svc_decode_LINK3args(struct svc_rqst *rqstp, struct xdr_stream *xdr)
+{
+	struct LINK3args *argp = rqstp->rq_argp;
+
+	return xdrgen_decode_LINK3args(xdr, argp);
+}
+
+/**
+ * nfs_svc_decode_READDIR3args - Decode a READDIR3args argument
+ * @rqstp: RPC transaction context
+ * @xdr: source XDR data stream
+ *
+ * Return values:
+ *   %true: procedure arguments decoded successfully
+ *   %false: decode failed
+ */
+bool nfs_svc_decode_READDIR3args(struct svc_rqst *rqstp, struct xdr_stream *xdr)
+{
+	struct READDIR3args *argp = rqstp->rq_argp;
+
+	return xdrgen_decode_READDIR3args(xdr, argp);
+}
+
+/**
+ * nfs_svc_decode_READDIRPLUS3args - Decode a READDIRPLUS3args argument
+ * @rqstp: RPC transaction context
+ * @xdr: source XDR data stream
+ *
+ * Return values:
+ *   %true: procedure arguments decoded successfully
+ *   %false: decode failed
+ */
+bool nfs_svc_decode_READDIRPLUS3args(struct svc_rqst *rqstp, struct xdr_stream *xdr)
+{
+	struct READDIRPLUS3args *argp = rqstp->rq_argp;
+
+	return xdrgen_decode_READDIRPLUS3args(xdr, argp);
+}
+
+/**
+ * nfs_svc_decode_FSSTAT3args - Decode a FSSTAT3args argument
+ * @rqstp: RPC transaction context
+ * @xdr: source XDR data stream
+ *
+ * Return values:
+ *   %true: procedure arguments decoded successfully
+ *   %false: decode failed
+ */
+bool nfs_svc_decode_FSSTAT3args(struct svc_rqst *rqstp, struct xdr_stream *xdr)
+{
+	struct FSSTAT3args *argp = rqstp->rq_argp;
+
+	return xdrgen_decode_FSSTAT3args(xdr, argp);
+}
+
+/**
+ * nfs_svc_decode_FSINFO3args - Decode a FSINFO3args argument
+ * @rqstp: RPC transaction context
+ * @xdr: source XDR data stream
+ *
+ * Return values:
+ *   %true: procedure arguments decoded successfully
+ *   %false: decode failed
+ */
+bool nfs_svc_decode_FSINFO3args(struct svc_rqst *rqstp, struct xdr_stream *xdr)
+{
+	struct FSINFO3args *argp = rqstp->rq_argp;
+
+	return xdrgen_decode_FSINFO3args(xdr, argp);
+}
+
+/**
+ * nfs_svc_decode_PATHCONF3args - Decode a PATHCONF3args argument
+ * @rqstp: RPC transaction context
+ * @xdr: source XDR data stream
+ *
+ * Return values:
+ *   %true: procedure arguments decoded successfully
+ *   %false: decode failed
+ */
+bool nfs_svc_decode_PATHCONF3args(struct svc_rqst *rqstp, struct xdr_stream *xdr)
+{
+	struct PATHCONF3args *argp = rqstp->rq_argp;
+
+	return xdrgen_decode_PATHCONF3args(xdr, argp);
+}
+
+/**
+ * nfs_svc_decode_COMMIT3args - Decode a COMMIT3args argument
+ * @rqstp: RPC transaction context
+ * @xdr: source XDR data stream
+ *
+ * Return values:
+ *   %true: procedure arguments decoded successfully
+ *   %false: decode failed
+ */
+bool nfs_svc_decode_COMMIT3args(struct svc_rqst *rqstp, struct xdr_stream *xdr)
+{
+	struct COMMIT3args *argp = rqstp->rq_argp;
+
+	return xdrgen_decode_COMMIT3args(xdr, argp);
+}
+
+static bool __maybe_unused
+xdrgen_encode_uint64(struct xdr_stream *xdr, const uint64 value)
+{
+	return xdrgen_encode_unsigned_hyper(xdr, value);
+}
+
+static bool __maybe_unused
+xdrgen_encode_int64(struct xdr_stream *xdr, const int64 value)
+{
+	return xdrgen_encode_hyper(xdr, value);
+}
+
+static bool __maybe_unused
+xdrgen_encode_uint32(struct xdr_stream *xdr, const uint32 value)
+{
+	return xdrgen_encode_unsigned_long(xdr, value);
+}
+
+static bool __maybe_unused
+xdrgen_encode_int32(struct xdr_stream *xdr, const int32 value)
+{
+	return xdrgen_encode_long(xdr, value);
+}
+
+static bool __maybe_unused
+xdrgen_encode_filename3(struct xdr_stream *xdr, const filename3 value)
+{
+	return xdr_stream_encode_opaque(xdr, value.data, value.len) >= 0;
+}
+
+static bool __maybe_unused
+xdrgen_encode_nfspath3(struct xdr_stream *xdr, const nfspath3 value)
+{
+	return xdr_stream_encode_opaque(xdr, value.data, value.len) >= 0;
+}
+
+static bool __maybe_unused
+xdrgen_encode_fileid3(struct xdr_stream *xdr, const fileid3 value)
+{
+	return xdrgen_encode_uint64(xdr, value);
+}
+
+static bool __maybe_unused
+xdrgen_encode_cookie3(struct xdr_stream *xdr, const cookie3 value)
+{
+	return xdrgen_encode_uint64(xdr, value);
+}
+
+static bool __maybe_unused
+xdrgen_encode_cookieverf3(struct xdr_stream *xdr, const cookieverf3 value)
+{
+	return xdr_stream_encode_opaque_fixed(xdr, value, NFS3_COOKIEVERFSIZE) >= 0;
+}
+
+static bool __maybe_unused
+xdrgen_encode_createverf3(struct xdr_stream *xdr, const createverf3 value)
+{
+	return xdr_stream_encode_opaque_fixed(xdr, value, NFS3_CREATEVERFSIZE) >= 0;
+}
+
+static bool __maybe_unused
+xdrgen_encode_writeverf3(struct xdr_stream *xdr, const writeverf3 value)
+{
+	return xdr_stream_encode_opaque_fixed(xdr, value, NFS3_WRITEVERFSIZE) >= 0;
+}
+
+static bool __maybe_unused
+xdrgen_encode_uid3(struct xdr_stream *xdr, const uid3 value)
+{
+	return xdrgen_encode_uint32(xdr, value);
+}
+
+static bool __maybe_unused
+xdrgen_encode_gid3(struct xdr_stream *xdr, const gid3 value)
+{
+	return xdrgen_encode_uint32(xdr, value);
+}
+
+static bool __maybe_unused
+xdrgen_encode_size3(struct xdr_stream *xdr, const size3 value)
+{
+	return xdrgen_encode_uint64(xdr, value);
+}
+
+static bool __maybe_unused
+xdrgen_encode_offset3(struct xdr_stream *xdr, const offset3 value)
+{
+	return xdrgen_encode_uint64(xdr, value);
+}
+
+static bool __maybe_unused
+xdrgen_encode_mode3(struct xdr_stream *xdr, const mode3 value)
+{
+	return xdrgen_encode_uint32(xdr, value);
+}
+
+static bool __maybe_unused
+xdrgen_encode_count3(struct xdr_stream *xdr, const count3 value)
+{
+	return xdrgen_encode_uint32(xdr, value);
+}
+
+static bool __maybe_unused
+xdrgen_encode_nfsstat3(struct xdr_stream *xdr, nfsstat3 value)
+{
+	return xdr_stream_encode_u32(xdr, value) == XDR_UNIT;
+}
+
+static bool __maybe_unused
+xdrgen_encode_ftype3(struct xdr_stream *xdr, ftype3 value)
+{
+	return xdr_stream_encode_u32(xdr, value) == XDR_UNIT;
+}
+
+static bool __maybe_unused
+xdrgen_encode_specdata3(struct xdr_stream *xdr, const struct specdata3 *value)
+{
+	if (!xdrgen_encode_uint32(xdr, value->specdata1))
+		return false;
+	if (!xdrgen_encode_uint32(xdr, value->specdata2))
+		return false;
+	return true;
+}
+
+static bool __maybe_unused
+xdrgen_encode_nfs_fh3(struct xdr_stream *xdr, const struct nfs_fh3 *value)
+{
+	if (value->data.len > NFS3_FHSIZE)
+		return false;
+	if (xdr_stream_encode_opaque(xdr, value->data.data, value->data.len) < 0)
+		return false;
+	return true;
+}
+
+static bool __maybe_unused
+xdrgen_encode_nfstime3(struct xdr_stream *xdr, const struct nfstime3 *value)
+{
+	if (!xdrgen_encode_uint32(xdr, value->seconds))
+		return false;
+	if (!xdrgen_encode_uint32(xdr, value->nseconds))
+		return false;
+	return true;
+}
+
+static bool __maybe_unused
+xdrgen_encode_fattr3(struct xdr_stream *xdr, const struct fattr3 *value)
+{
+	if (!xdrgen_encode_ftype3(xdr, value->type))
+		return false;
+	if (!xdrgen_encode_mode3(xdr, value->mode))
+		return false;
+	if (!xdrgen_encode_uint32(xdr, value->nlink))
+		return false;
+	if (!xdrgen_encode_uid3(xdr, value->uid))
+		return false;
+	if (!xdrgen_encode_gid3(xdr, value->gid))
+		return false;
+	if (!xdrgen_encode_size3(xdr, value->size))
+		return false;
+	if (!xdrgen_encode_size3(xdr, value->used))
+		return false;
+	if (!xdrgen_encode_specdata3(xdr, &value->rdev))
+		return false;
+	if (!xdrgen_encode_uint64(xdr, value->fsid))
+		return false;
+	if (!xdrgen_encode_fileid3(xdr, value->fileid))
+		return false;
+	if (!xdrgen_encode_nfstime3(xdr, &value->atime))
+		return false;
+	if (!xdrgen_encode_nfstime3(xdr, &value->mtime))
+		return false;
+	if (!xdrgen_encode_nfstime3(xdr, &value->ctime))
+		return false;
+	return true;
+}
+
+static bool __maybe_unused
+xdrgen_encode_post_op_attr(struct xdr_stream *xdr, const struct post_op_attr *ptr)
+{
+	if (!xdrgen_encode_bool(xdr, ptr->attributes_follow))
+		return false;
+	if (ptr->attributes_follow) {
+		if (!xdrgen_encode_fattr3(xdr, &ptr->u.attributes))
+			return false;
+	}
+	return true;
+}
+
+static bool __maybe_unused
+xdrgen_encode_wcc_attr(struct xdr_stream *xdr, const struct wcc_attr *value)
+{
+	if (!xdrgen_encode_size3(xdr, value->size))
+		return false;
+	if (!xdrgen_encode_nfstime3(xdr, &value->mtime))
+		return false;
+	if (!xdrgen_encode_nfstime3(xdr, &value->ctime))
+		return false;
+	return true;
+}
+
+static bool __maybe_unused
+xdrgen_encode_pre_op_attr(struct xdr_stream *xdr, const struct pre_op_attr *ptr)
+{
+	if (!xdrgen_encode_bool(xdr, ptr->attributes_follow))
+		return false;
+	if (ptr->attributes_follow) {
+		if (!xdrgen_encode_wcc_attr(xdr, &ptr->u.attributes))
+			return false;
+	}
+	return true;
+}
+
+static bool __maybe_unused
+xdrgen_encode_wcc_data(struct xdr_stream *xdr, const struct wcc_data *value)
+{
+	if (!xdrgen_encode_pre_op_attr(xdr, &value->before))
+		return false;
+	if (!xdrgen_encode_post_op_attr(xdr, &value->after))
+		return false;
+	return true;
+}
+
+static bool __maybe_unused
+xdrgen_encode_post_op_fh3(struct xdr_stream *xdr, const struct post_op_fh3 *ptr)
+{
+	if (!xdrgen_encode_bool(xdr, ptr->handle_follows))
+		return false;
+	if (ptr->handle_follows) {
+		if (!xdrgen_encode_nfs_fh3(xdr, &ptr->u.handle))
+			return false;
+	}
+	return true;
+}
+
+static bool __maybe_unused
+xdrgen_encode_time_how(struct xdr_stream *xdr, time_how value)
+{
+	return xdr_stream_encode_u32(xdr, value) == XDR_UNIT;
+}
+
+static bool __maybe_unused
+xdrgen_encode_set_mode3(struct xdr_stream *xdr, const struct set_mode3 *ptr)
+{
+	if (!xdrgen_encode_bool(xdr, ptr->set_it))
+		return false;
+	if (ptr->set_it) {
+		if (!xdrgen_encode_mode3(xdr, ptr->u.mode))
+			return false;
+	}
+	return true;
+}
+
+static bool __maybe_unused
+xdrgen_encode_set_uid3(struct xdr_stream *xdr, const struct set_uid3 *ptr)
+{
+	if (!xdrgen_encode_bool(xdr, ptr->set_it))
+		return false;
+	if (ptr->set_it) {
+		if (!xdrgen_encode_uid3(xdr, ptr->u.uid))
+			return false;
+	}
+	return true;
+}
+
+static bool __maybe_unused
+xdrgen_encode_set_gid3(struct xdr_stream *xdr, const struct set_gid3 *ptr)
+{
+	if (!xdrgen_encode_bool(xdr, ptr->set_it))
+		return false;
+	if (ptr->set_it) {
+		if (!xdrgen_encode_gid3(xdr, ptr->u.gid))
+			return false;
+	}
+	return true;
+}
+
+static bool __maybe_unused
+xdrgen_encode_set_size3(struct xdr_stream *xdr, const struct set_size3 *ptr)
+{
+	if (!xdrgen_encode_bool(xdr, ptr->set_it))
+		return false;
+	if (ptr->set_it) {
+		if (!xdrgen_encode_size3(xdr, ptr->u.size))
+			return false;
+	}
+	return true;
+}
+
+static bool __maybe_unused
+xdrgen_encode_set_atime(struct xdr_stream *xdr, const struct set_atime *ptr)
+{
+	if (!xdrgen_encode_time_how(xdr, ptr->set_it))
+		return false;
+	switch (ptr->set_it) {
+	case SET_TO_CLIENT_TIME:
+		if (!xdrgen_encode_nfstime3(xdr, &ptr->u.atime))
+			return false;
+		break;
+	default:
+		break;
+	}
+	return true;
+}
+
+static bool __maybe_unused
+xdrgen_encode_set_mtime(struct xdr_stream *xdr, const struct set_mtime *ptr)
+{
+	if (!xdrgen_encode_time_how(xdr, ptr->set_it))
+		return false;
+	switch (ptr->set_it) {
+	case SET_TO_CLIENT_TIME:
+		if (!xdrgen_encode_nfstime3(xdr, &ptr->u.mtime))
+			return false;
+		break;
+	default:
+		break;
+	}
+	return true;
+}
+
+static bool __maybe_unused
+xdrgen_encode_sattr3(struct xdr_stream *xdr, const struct sattr3 *value)
+{
+	if (!xdrgen_encode_set_mode3(xdr, &value->mode))
+		return false;
+	if (!xdrgen_encode_set_uid3(xdr, &value->uid))
+		return false;
+	if (!xdrgen_encode_set_gid3(xdr, &value->gid))
+		return false;
+	if (!xdrgen_encode_set_size3(xdr, &value->size))
+		return false;
+	if (!xdrgen_encode_set_atime(xdr, &value->atime))
+		return false;
+	if (!xdrgen_encode_set_mtime(xdr, &value->mtime))
+		return false;
+	return true;
+}
+
+static bool __maybe_unused
+xdrgen_encode_diropargs3(struct xdr_stream *xdr, const struct diropargs3 *value)
+{
+	if (!xdrgen_encode_nfs_fh3(xdr, &value->dir))
+		return false;
+	if (!xdrgen_encode_filename3(xdr, value->name))
+		return false;
+	return true;
+}
+
+static bool __maybe_unused
+xdrgen_encode_GETATTR3args(struct xdr_stream *xdr, const struct GETATTR3args *value)
+{
+	if (!xdrgen_encode_nfs_fh3(xdr, &value->object))
+		return false;
+	return true;
+}
+
+static bool __maybe_unused
+xdrgen_encode_GETATTR3resok(struct xdr_stream *xdr, const struct GETATTR3resok *value)
+{
+	if (!xdrgen_encode_fattr3(xdr, &value->obj_attributes))
+		return false;
+	return true;
+}
+
+static bool __maybe_unused
+xdrgen_encode_GETATTR3res(struct xdr_stream *xdr, const struct GETATTR3res *ptr)
+{
+	if (!xdrgen_encode_nfsstat3(xdr, ptr->status))
+		return false;
+	switch (ptr->status) {
+	case NFS3_OK:
+		if (!xdrgen_encode_GETATTR3resok(xdr, &ptr->u.resok))
+			return false;
+		break;
+	default:
+		break;
+	}
+	return true;
+}
+
+static bool __maybe_unused
+xdrgen_encode_sattrguard3(struct xdr_stream *xdr, const struct sattrguard3 *ptr)
+{
+	if (!xdrgen_encode_bool(xdr, ptr->check))
+		return false;
+	if (ptr->check) {
+		if (!xdrgen_encode_nfstime3(xdr, &ptr->u.obj_ctime))
+			return false;
+	}
+	return true;
+}
+
+static bool __maybe_unused
+xdrgen_encode_SETATTR3args(struct xdr_stream *xdr, const struct SETATTR3args *value)
+{
+	if (!xdrgen_encode_nfs_fh3(xdr, &value->object))
+		return false;
+	if (!xdrgen_encode_sattr3(xdr, &value->new_attributes))
+		return false;
+	if (!xdrgen_encode_sattrguard3(xdr, &value->guard))
+		return false;
+	return true;
+}
+
+static bool __maybe_unused
+xdrgen_encode_SETATTR3resok(struct xdr_stream *xdr, const struct SETATTR3resok *value)
+{
+	if (!xdrgen_encode_wcc_data(xdr, &value->obj_wcc))
+		return false;
+	return true;
+}
+
+static bool __maybe_unused
+xdrgen_encode_SETATTR3resfail(struct xdr_stream *xdr, const struct SETATTR3resfail *value)
+{
+	if (!xdrgen_encode_wcc_data(xdr, &value->obj_wcc))
+		return false;
+	return true;
+}
+
+static bool __maybe_unused
+xdrgen_encode_SETATTR3res(struct xdr_stream *xdr, const struct SETATTR3res *ptr)
+{
+	if (!xdrgen_encode_nfsstat3(xdr, ptr->status))
+		return false;
+	switch (ptr->status) {
+	case NFS3_OK:
+		if (!xdrgen_encode_SETATTR3resok(xdr, &ptr->u.resok))
+			return false;
+		break;
+	default:
+		if (!xdrgen_encode_SETATTR3resfail(xdr, &ptr->u.resfail))
+			return false;
+	}
+	return true;
+}
+
+static bool __maybe_unused
+xdrgen_encode_LOOKUP3args(struct xdr_stream *xdr, const struct LOOKUP3args *value)
+{
+	if (!xdrgen_encode_diropargs3(xdr, &value->what))
+		return false;
+	return true;
+}
+
+static bool __maybe_unused
+xdrgen_encode_LOOKUP3resok(struct xdr_stream *xdr, const struct LOOKUP3resok *value)
+{
+	if (!xdrgen_encode_nfs_fh3(xdr, &value->object))
+		return false;
+	if (!xdrgen_encode_post_op_attr(xdr, &value->obj_attributes))
+		return false;
+	if (!xdrgen_encode_post_op_attr(xdr, &value->dir_attributes))
+		return false;
+	return true;
+}
+
+static bool __maybe_unused
+xdrgen_encode_LOOKUP3resfail(struct xdr_stream *xdr, const struct LOOKUP3resfail *value)
+{
+	if (!xdrgen_encode_post_op_attr(xdr, &value->dir_attributes))
+		return false;
+	return true;
+}
+
+static bool __maybe_unused
+xdrgen_encode_LOOKUP3res(struct xdr_stream *xdr, const struct LOOKUP3res *ptr)
+{
+	if (!xdrgen_encode_nfsstat3(xdr, ptr->status))
+		return false;
+	switch (ptr->status) {
+	case NFS3_OK:
+		if (!xdrgen_encode_LOOKUP3resok(xdr, &ptr->u.resok))
+			return false;
+		break;
+	default:
+		if (!xdrgen_encode_LOOKUP3resfail(xdr, &ptr->u.resfail))
+			return false;
+	}
+	return true;
+}
+
+static bool __maybe_unused
+xdrgen_encode_ACCESS3args(struct xdr_stream *xdr, const struct ACCESS3args *value)
+{
+	if (!xdrgen_encode_nfs_fh3(xdr, &value->object))
+		return false;
+	if (!xdrgen_encode_uint32(xdr, value->access))
+		return false;
+	return true;
+}
+
+static bool __maybe_unused
+xdrgen_encode_ACCESS3resok(struct xdr_stream *xdr, const struct ACCESS3resok *value)
+{
+	if (!xdrgen_encode_post_op_attr(xdr, &value->obj_attributes))
+		return false;
+	if (!xdrgen_encode_uint32(xdr, value->access))
+		return false;
+	return true;
+}
+
+static bool __maybe_unused
+xdrgen_encode_ACCESS3resfail(struct xdr_stream *xdr, const struct ACCESS3resfail *value)
+{
+	if (!xdrgen_encode_post_op_attr(xdr, &value->obj_attributes))
+		return false;
+	return true;
+}
+
+static bool __maybe_unused
+xdrgen_encode_ACCESS3res(struct xdr_stream *xdr, const struct ACCESS3res *ptr)
+{
+	if (!xdrgen_encode_nfsstat3(xdr, ptr->status))
+		return false;
+	switch (ptr->status) {
+	case NFS3_OK:
+		if (!xdrgen_encode_ACCESS3resok(xdr, &ptr->u.resok))
+			return false;
+		break;
+	default:
+		if (!xdrgen_encode_ACCESS3resfail(xdr, &ptr->u.resfail))
+			return false;
+	}
+	return true;
+}
+
+static bool __maybe_unused
+xdrgen_encode_READLINK3args(struct xdr_stream *xdr, const struct READLINK3args *value)
+{
+	if (!xdrgen_encode_nfs_fh3(xdr, &value->symlink))
+		return false;
+	return true;
+}
+
+static bool __maybe_unused
+xdrgen_encode_READLINK3resok(struct xdr_stream *xdr, const struct READLINK3resok *value)
+{
+	if (!xdrgen_encode_post_op_attr(xdr, &value->symlink_attributes))
+		return false;
+	if (!xdrgen_encode_nfspath3(xdr, value->data))
+		return false;
+	return true;
+}
+
+static bool __maybe_unused
+xdrgen_encode_READLINK3resfail(struct xdr_stream *xdr, const struct READLINK3resfail *value)
+{
+	if (!xdrgen_encode_post_op_attr(xdr, &value->symlink_attributes))
+		return false;
+	return true;
+}
+
+static bool __maybe_unused
+xdrgen_encode_READLINK3res(struct xdr_stream *xdr, const struct READLINK3res *ptr)
+{
+	if (!xdrgen_encode_nfsstat3(xdr, ptr->status))
+		return false;
+	switch (ptr->status) {
+	case NFS3_OK:
+		if (!xdrgen_encode_READLINK3resok(xdr, &ptr->u.resok))
+			return false;
+		break;
+	default:
+		if (!xdrgen_encode_READLINK3resfail(xdr, &ptr->u.resfail))
+			return false;
+	}
+	return true;
+}
+
+static bool __maybe_unused
+xdrgen_encode_READ3args(struct xdr_stream *xdr, const struct READ3args *value)
+{
+	if (!xdrgen_encode_nfs_fh3(xdr, &value->file))
+		return false;
+	if (!xdrgen_encode_offset3(xdr, value->offset))
+		return false;
+	if (!xdrgen_encode_count3(xdr, value->count))
+		return false;
+	return true;
+}
+
+static bool __maybe_unused
+xdrgen_encode_READ3resok(struct xdr_stream *xdr, const struct READ3resok *value)
+{
+	if (!xdrgen_encode_post_op_attr(xdr, &value->file_attributes))
+		return false;
+	if (!xdrgen_encode_count3(xdr, value->count))
+		return false;
+	if (!xdrgen_encode_bool(xdr, value->eof))
+		return false;
+	if (xdr_stream_encode_opaque(xdr, value->data.data, value->data.len) < 0)
+		return false;
+	return true;
+}
+
+static bool __maybe_unused
+xdrgen_encode_READ3resfail(struct xdr_stream *xdr, const struct READ3resfail *value)
+{
+	if (!xdrgen_encode_post_op_attr(xdr, &value->file_attributes))
+		return false;
+	return true;
+}
+
+static bool __maybe_unused
+xdrgen_encode_READ3res(struct xdr_stream *xdr, const struct READ3res *ptr)
+{
+	if (!xdrgen_encode_nfsstat3(xdr, ptr->status))
+		return false;
+	switch (ptr->status) {
+	case NFS3_OK:
+		if (!xdrgen_encode_READ3resok(xdr, &ptr->u.resok))
+			return false;
+		break;
+	default:
+		if (!xdrgen_encode_READ3resfail(xdr, &ptr->u.resfail))
+			return false;
+	}
+	return true;
+}
+
+static bool __maybe_unused
+xdrgen_encode_stable_how(struct xdr_stream *xdr, stable_how value)
+{
+	return xdr_stream_encode_u32(xdr, value) == XDR_UNIT;
+}
+
+static bool __maybe_unused
+xdrgen_encode_WRITE3args(struct xdr_stream *xdr, const struct WRITE3args *value)
+{
+	if (!xdrgen_encode_nfs_fh3(xdr, &value->file))
+		return false;
+	if (!xdrgen_encode_offset3(xdr, value->offset))
+		return false;
+	if (!xdrgen_encode_count3(xdr, value->count))
+		return false;
+	if (!xdrgen_encode_stable_how(xdr, value->stable))
+		return false;
+	if (xdr_stream_encode_opaque(xdr, value->data.data, value->data.len) < 0)
+		return false;
+	return true;
+}
+
+static bool __maybe_unused
+xdrgen_encode_WRITE3resok(struct xdr_stream *xdr, const struct WRITE3resok *value)
+{
+	if (!xdrgen_encode_wcc_data(xdr, &value->file_wcc))
+		return false;
+	if (!xdrgen_encode_count3(xdr, value->count))
+		return false;
+	if (!xdrgen_encode_stable_how(xdr, value->committed))
+		return false;
+	if (!xdrgen_encode_writeverf3(xdr, value->verf))
+		return false;
+	return true;
+}
+
+static bool __maybe_unused
+xdrgen_encode_WRITE3resfail(struct xdr_stream *xdr, const struct WRITE3resfail *value)
+{
+	if (!xdrgen_encode_wcc_data(xdr, &value->file_wcc))
+		return false;
+	return true;
+}
+
+static bool __maybe_unused
+xdrgen_encode_WRITE3res(struct xdr_stream *xdr, const struct WRITE3res *ptr)
+{
+	if (!xdrgen_encode_nfsstat3(xdr, ptr->status))
+		return false;
+	switch (ptr->status) {
+	case NFS3_OK:
+		if (!xdrgen_encode_WRITE3resok(xdr, &ptr->u.resok))
+			return false;
+		break;
+	default:
+		if (!xdrgen_encode_WRITE3resfail(xdr, &ptr->u.resfail))
+			return false;
+	}
+	return true;
+}
+
+static bool __maybe_unused
+xdrgen_encode_createmode3(struct xdr_stream *xdr, createmode3 value)
+{
+	return xdr_stream_encode_u32(xdr, value) == XDR_UNIT;
+}
+
+static bool __maybe_unused
+xdrgen_encode_createhow3(struct xdr_stream *xdr, const struct createhow3 *ptr)
+{
+	if (!xdrgen_encode_createmode3(xdr, ptr->mode))
+		return false;
+	switch (ptr->mode) {
+	case UNCHECKED:
+	case GUARDED:
+		if (!xdrgen_encode_sattr3(xdr, &ptr->u.obj_attributes))
+			return false;
+		break;
+	case EXCLUSIVE:
+		if (!xdrgen_encode_createverf3(xdr, ptr->u.verf))
+			return false;
+		break;
+	default:
+		break;
+	}
+	return true;
+}
+
+static bool __maybe_unused
+xdrgen_encode_CREATE3args(struct xdr_stream *xdr, const struct CREATE3args *value)
+{
+	if (!xdrgen_encode_diropargs3(xdr, &value->where))
+		return false;
+	if (!xdrgen_encode_createhow3(xdr, &value->how))
+		return false;
+	return true;
+}
+
+static bool __maybe_unused
+xdrgen_encode_CREATE3resok(struct xdr_stream *xdr, const struct CREATE3resok *value)
+{
+	if (!xdrgen_encode_post_op_fh3(xdr, &value->obj))
+		return false;
+	if (!xdrgen_encode_post_op_attr(xdr, &value->obj_attributes))
+		return false;
+	if (!xdrgen_encode_wcc_data(xdr, &value->dir_wcc))
+		return false;
+	return true;
+}
+
+static bool __maybe_unused
+xdrgen_encode_CREATE3resfail(struct xdr_stream *xdr, const struct CREATE3resfail *value)
+{
+	if (!xdrgen_encode_wcc_data(xdr, &value->dir_wcc))
+		return false;
+	return true;
+}
+
+static bool __maybe_unused
+xdrgen_encode_CREATE3res(struct xdr_stream *xdr, const struct CREATE3res *ptr)
+{
+	if (!xdrgen_encode_nfsstat3(xdr, ptr->status))
+		return false;
+	switch (ptr->status) {
+	case NFS3_OK:
+		if (!xdrgen_encode_CREATE3resok(xdr, &ptr->u.resok))
+			return false;
+		break;
+	default:
+		if (!xdrgen_encode_CREATE3resfail(xdr, &ptr->u.resfail))
+			return false;
+	}
+	return true;
+}
+
+static bool __maybe_unused
+xdrgen_encode_MKDIR3args(struct xdr_stream *xdr, const struct MKDIR3args *value)
+{
+	if (!xdrgen_encode_diropargs3(xdr, &value->where))
+		return false;
+	if (!xdrgen_encode_sattr3(xdr, &value->attributes))
+		return false;
+	return true;
+}
+
+static bool __maybe_unused
+xdrgen_encode_MKDIR3resok(struct xdr_stream *xdr, const struct MKDIR3resok *value)
+{
+	if (!xdrgen_encode_post_op_fh3(xdr, &value->obj))
+		return false;
+	if (!xdrgen_encode_post_op_attr(xdr, &value->obj_attributes))
+		return false;
+	if (!xdrgen_encode_wcc_data(xdr, &value->dir_wcc))
+		return false;
+	return true;
+}
+
+static bool __maybe_unused
+xdrgen_encode_MKDIR3resfail(struct xdr_stream *xdr, const struct MKDIR3resfail *value)
+{
+	if (!xdrgen_encode_wcc_data(xdr, &value->dir_wcc))
+		return false;
+	return true;
+}
+
+static bool __maybe_unused
+xdrgen_encode_MKDIR3res(struct xdr_stream *xdr, const struct MKDIR3res *ptr)
+{
+	if (!xdrgen_encode_nfsstat3(xdr, ptr->status))
+		return false;
+	switch (ptr->status) {
+	case NFS3_OK:
+		if (!xdrgen_encode_MKDIR3resok(xdr, &ptr->u.resok))
+			return false;
+		break;
+	default:
+		if (!xdrgen_encode_MKDIR3resfail(xdr, &ptr->u.resfail))
+			return false;
+	}
+	return true;
+}
+
+static bool __maybe_unused
+xdrgen_encode_symlinkdata3(struct xdr_stream *xdr, const struct symlinkdata3 *value)
+{
+	if (!xdrgen_encode_sattr3(xdr, &value->symlink_attributes))
+		return false;
+	if (!xdrgen_encode_nfspath3(xdr, value->symlink_data))
+		return false;
+	return true;
+}
+
+static bool __maybe_unused
+xdrgen_encode_SYMLINK3args(struct xdr_stream *xdr, const struct SYMLINK3args *value)
+{
+	if (!xdrgen_encode_diropargs3(xdr, &value->where))
+		return false;
+	if (!xdrgen_encode_symlinkdata3(xdr, &value->symlink))
+		return false;
+	return true;
+}
+
+static bool __maybe_unused
+xdrgen_encode_SYMLINK3resok(struct xdr_stream *xdr, const struct SYMLINK3resok *value)
+{
+	if (!xdrgen_encode_post_op_fh3(xdr, &value->obj))
+		return false;
+	if (!xdrgen_encode_post_op_attr(xdr, &value->obj_attributes))
+		return false;
+	if (!xdrgen_encode_wcc_data(xdr, &value->dir_wcc))
+		return false;
+	return true;
+}
+
+static bool __maybe_unused
+xdrgen_encode_SYMLINK3resfail(struct xdr_stream *xdr, const struct SYMLINK3resfail *value)
+{
+	if (!xdrgen_encode_wcc_data(xdr, &value->dir_wcc))
+		return false;
+	return true;
+}
+
+static bool __maybe_unused
+xdrgen_encode_SYMLINK3res(struct xdr_stream *xdr, const struct SYMLINK3res *ptr)
+{
+	if (!xdrgen_encode_nfsstat3(xdr, ptr->status))
+		return false;
+	switch (ptr->status) {
+	case NFS3_OK:
+		if (!xdrgen_encode_SYMLINK3resok(xdr, &ptr->u.resok))
+			return false;
+		break;
+	default:
+		if (!xdrgen_encode_SYMLINK3resfail(xdr, &ptr->u.resfail))
+			return false;
+	}
+	return true;
+}
+
+static bool __maybe_unused
+xdrgen_encode_devicedata3(struct xdr_stream *xdr, const struct devicedata3 *value)
+{
+	if (!xdrgen_encode_sattr3(xdr, &value->dev_attributes))
+		return false;
+	if (!xdrgen_encode_specdata3(xdr, &value->spec))
+		return false;
+	return true;
+}
+
+static bool __maybe_unused
+xdrgen_encode_mknoddata3(struct xdr_stream *xdr, const struct mknoddata3 *ptr)
+{
+	if (!xdrgen_encode_ftype3(xdr, ptr->type))
+		return false;
+	switch (ptr->type) {
+	case NF3CHR:
+	case NF3BLK:
+		if (!xdrgen_encode_devicedata3(xdr, &ptr->u.device))
+			return false;
+		break;
+	case NF3SOCK:
+	case NF3FIFO:
+		if (!xdrgen_encode_sattr3(xdr, &ptr->u.pipe_attributes))
+			return false;
+		break;
+	default:
+		break;
+	}
+	return true;
+}
+
+static bool __maybe_unused
+xdrgen_encode_MKNOD3args(struct xdr_stream *xdr, const struct MKNOD3args *value)
+{
+	if (!xdrgen_encode_diropargs3(xdr, &value->where))
+		return false;
+	if (!xdrgen_encode_mknoddata3(xdr, &value->what))
+		return false;
+	return true;
+}
+
+static bool __maybe_unused
+xdrgen_encode_MKNOD3resok(struct xdr_stream *xdr, const struct MKNOD3resok *value)
+{
+	if (!xdrgen_encode_post_op_fh3(xdr, &value->obj))
+		return false;
+	if (!xdrgen_encode_post_op_attr(xdr, &value->obj_attributes))
+		return false;
+	if (!xdrgen_encode_wcc_data(xdr, &value->dir_wcc))
+		return false;
+	return true;
+}
+
+static bool __maybe_unused
+xdrgen_encode_MKNOD3resfail(struct xdr_stream *xdr, const struct MKNOD3resfail *value)
+{
+	if (!xdrgen_encode_wcc_data(xdr, &value->dir_wcc))
+		return false;
+	return true;
+}
+
+static bool __maybe_unused
+xdrgen_encode_MKNOD3res(struct xdr_stream *xdr, const struct MKNOD3res *ptr)
+{
+	if (!xdrgen_encode_nfsstat3(xdr, ptr->status))
+		return false;
+	switch (ptr->status) {
+	case NFS3_OK:
+		if (!xdrgen_encode_MKNOD3resok(xdr, &ptr->u.resok))
+			return false;
+		break;
+	default:
+		if (!xdrgen_encode_MKNOD3resfail(xdr, &ptr->u.resfail))
+			return false;
+	}
+	return true;
+}
+
+static bool __maybe_unused
+xdrgen_encode_REMOVE3args(struct xdr_stream *xdr, const struct REMOVE3args *value)
+{
+	if (!xdrgen_encode_diropargs3(xdr, &value->object))
+		return false;
+	return true;
+}
+
+static bool __maybe_unused
+xdrgen_encode_REMOVE3resok(struct xdr_stream *xdr, const struct REMOVE3resok *value)
+{
+	if (!xdrgen_encode_wcc_data(xdr, &value->dir_wcc))
+		return false;
+	return true;
+}
+
+static bool __maybe_unused
+xdrgen_encode_REMOVE3resfail(struct xdr_stream *xdr, const struct REMOVE3resfail *value)
+{
+	if (!xdrgen_encode_wcc_data(xdr, &value->dir_wcc))
+		return false;
+	return true;
+}
+
+static bool __maybe_unused
+xdrgen_encode_REMOVE3res(struct xdr_stream *xdr, const struct REMOVE3res *ptr)
+{
+	if (!xdrgen_encode_nfsstat3(xdr, ptr->status))
+		return false;
+	switch (ptr->status) {
+	case NFS3_OK:
+		if (!xdrgen_encode_REMOVE3resok(xdr, &ptr->u.resok))
+			return false;
+		break;
+	default:
+		if (!xdrgen_encode_REMOVE3resfail(xdr, &ptr->u.resfail))
+			return false;
+	}
+	return true;
+}
+
+static bool __maybe_unused
+xdrgen_encode_RMDIR3args(struct xdr_stream *xdr, const struct RMDIR3args *value)
+{
+	if (!xdrgen_encode_diropargs3(xdr, &value->object))
+		return false;
+	return true;
+}
+
+static bool __maybe_unused
+xdrgen_encode_RMDIR3resok(struct xdr_stream *xdr, const struct RMDIR3resok *value)
+{
+	if (!xdrgen_encode_wcc_data(xdr, &value->dir_wcc))
+		return false;
+	return true;
+}
+
+static bool __maybe_unused
+xdrgen_encode_RMDIR3resfail(struct xdr_stream *xdr, const struct RMDIR3resfail *value)
+{
+	if (!xdrgen_encode_wcc_data(xdr, &value->dir_wcc))
+		return false;
+	return true;
+}
+
+static bool __maybe_unused
+xdrgen_encode_RMDIR3res(struct xdr_stream *xdr, const struct RMDIR3res *ptr)
+{
+	if (!xdrgen_encode_nfsstat3(xdr, ptr->status))
+		return false;
+	switch (ptr->status) {
+	case NFS3_OK:
+		if (!xdrgen_encode_RMDIR3resok(xdr, &ptr->u.resok))
+			return false;
+		break;
+	default:
+		if (!xdrgen_encode_RMDIR3resfail(xdr, &ptr->u.resfail))
+			return false;
+	}
+	return true;
+}
+
+static bool __maybe_unused
+xdrgen_encode_RENAME3args(struct xdr_stream *xdr, const struct RENAME3args *value)
+{
+	if (!xdrgen_encode_diropargs3(xdr, &value->from))
+		return false;
+	if (!xdrgen_encode_diropargs3(xdr, &value->to))
+		return false;
+	return true;
+}
+
+static bool __maybe_unused
+xdrgen_encode_RENAME3resok(struct xdr_stream *xdr, const struct RENAME3resok *value)
+{
+	if (!xdrgen_encode_wcc_data(xdr, &value->fromdir_wcc))
+		return false;
+	if (!xdrgen_encode_wcc_data(xdr, &value->todir_wcc))
+		return false;
+	return true;
+}
+
+static bool __maybe_unused
+xdrgen_encode_RENAME3resfail(struct xdr_stream *xdr, const struct RENAME3resfail *value)
+{
+	if (!xdrgen_encode_wcc_data(xdr, &value->fromdir_wcc))
+		return false;
+	if (!xdrgen_encode_wcc_data(xdr, &value->todir_wcc))
+		return false;
+	return true;
+}
+
+static bool __maybe_unused
+xdrgen_encode_RENAME3res(struct xdr_stream *xdr, const struct RENAME3res *ptr)
+{
+	if (!xdrgen_encode_nfsstat3(xdr, ptr->status))
+		return false;
+	switch (ptr->status) {
+	case NFS3_OK:
+		if (!xdrgen_encode_RENAME3resok(xdr, &ptr->u.resok))
+			return false;
+		break;
+	default:
+		if (!xdrgen_encode_RENAME3resfail(xdr, &ptr->u.resfail))
+			return false;
+	}
+	return true;
+}
+
+static bool __maybe_unused
+xdrgen_encode_LINK3args(struct xdr_stream *xdr, const struct LINK3args *value)
+{
+	if (!xdrgen_encode_nfs_fh3(xdr, &value->file))
+		return false;
+	if (!xdrgen_encode_diropargs3(xdr, &value->link))
+		return false;
+	return true;
+}
+
+static bool __maybe_unused
+xdrgen_encode_LINK3resok(struct xdr_stream *xdr, const struct LINK3resok *value)
+{
+	if (!xdrgen_encode_post_op_attr(xdr, &value->file_attributes))
+		return false;
+	if (!xdrgen_encode_wcc_data(xdr, &value->linkdir_wcc))
+		return false;
+	return true;
+}
+
+static bool __maybe_unused
+xdrgen_encode_LINK3resfail(struct xdr_stream *xdr, const struct LINK3resfail *value)
+{
+	if (!xdrgen_encode_post_op_attr(xdr, &value->file_attributes))
+		return false;
+	if (!xdrgen_encode_wcc_data(xdr, &value->linkdir_wcc))
+		return false;
+	return true;
+}
+
+static bool __maybe_unused
+xdrgen_encode_LINK3res(struct xdr_stream *xdr, const struct LINK3res *ptr)
+{
+	if (!xdrgen_encode_nfsstat3(xdr, ptr->status))
+		return false;
+	switch (ptr->status) {
+	case NFS3_OK:
+		if (!xdrgen_encode_LINK3resok(xdr, &ptr->u.resok))
+			return false;
+		break;
+	default:
+		if (!xdrgen_encode_LINK3resfail(xdr, &ptr->u.resfail))
+			return false;
+	}
+	return true;
+}
+
+static bool __maybe_unused
+xdrgen_encode_READDIR3args(struct xdr_stream *xdr, const struct READDIR3args *value)
+{
+	if (!xdrgen_encode_nfs_fh3(xdr, &value->dir))
+		return false;
+	if (!xdrgen_encode_cookie3(xdr, value->cookie))
+		return false;
+	if (!xdrgen_encode_cookieverf3(xdr, value->cookieverf))
+		return false;
+	if (!xdrgen_encode_count3(xdr, value->count))
+		return false;
+	return true;
+}
+
+static bool __maybe_unused
+xdrgen_encode_entry3(struct xdr_stream *xdr, const struct entry3 *value)
+{
+	if (!xdrgen_encode_bool(xdr, value != NULL))
+		return false;
+	if (!value)
+		return true;
+
+	if (!xdrgen_encode_fileid3(xdr, value->fileid))
+		return false;
+	if (!xdrgen_encode_filename3(xdr, value->name))
+		return false;
+	if (!xdrgen_encode_cookie3(xdr, value->cookie))
+		return false;
+	return true;
+}
+
+static bool __maybe_unused
+xdrgen_encode_dirlist3(struct xdr_stream *xdr, const struct dirlist3 *value)
+{
+	if (!xdrgen_encode_entry3(xdr, value->entries))
+		return false;
+	if (!xdrgen_encode_bool(xdr, value->eof))
+		return false;
+	return true;
+}
+
+static bool __maybe_unused
+xdrgen_encode_READDIR3resok(struct xdr_stream *xdr, const struct READDIR3resok *value)
+{
+	if (!xdrgen_encode_post_op_attr(xdr, &value->dir_attributes))
+		return false;
+	if (!xdrgen_encode_cookieverf3(xdr, value->cookieverf))
+		return false;
+	if (!xdrgen_encode_dirlist3(xdr, &value->reply))
+		return false;
+	return true;
+}
+
+static bool __maybe_unused
+xdrgen_encode_READDIR3resfail(struct xdr_stream *xdr, const struct READDIR3resfail *value)
+{
+	if (!xdrgen_encode_post_op_attr(xdr, &value->dir_attributes))
+		return false;
+	return true;
+}
+
+static bool __maybe_unused
+xdrgen_encode_READDIR3res(struct xdr_stream *xdr, const struct READDIR3res *ptr)
+{
+	if (!xdrgen_encode_nfsstat3(xdr, ptr->status))
+		return false;
+	switch (ptr->status) {
+	case NFS3_OK:
+		if (!xdrgen_encode_READDIR3resok(xdr, &ptr->u.resok))
+			return false;
+		break;
+	default:
+		if (!xdrgen_encode_READDIR3resfail(xdr, &ptr->u.resfail))
+			return false;
+	}
+	return true;
+}
+
+static bool __maybe_unused
+xdrgen_encode_READDIRPLUS3args(struct xdr_stream *xdr, const struct READDIRPLUS3args *value)
+{
+	if (!xdrgen_encode_nfs_fh3(xdr, &value->dir))
+		return false;
+	if (!xdrgen_encode_cookie3(xdr, value->cookie))
+		return false;
+	if (!xdrgen_encode_cookieverf3(xdr, value->cookieverf))
+		return false;
+	if (!xdrgen_encode_count3(xdr, value->dircount))
+		return false;
+	if (!xdrgen_encode_count3(xdr, value->maxcount))
+		return false;
+	return true;
+}
+
+static bool __maybe_unused
+xdrgen_encode_entryplus3(struct xdr_stream *xdr, const struct entryplus3 *value)
+{
+	if (!xdrgen_encode_bool(xdr, value != NULL))
+		return false;
+	if (!value)
+		return true;
+
+	if (!xdrgen_encode_fileid3(xdr, value->fileid))
+		return false;
+	if (!xdrgen_encode_filename3(xdr, value->name))
+		return false;
+	if (!xdrgen_encode_cookie3(xdr, value->cookie))
+		return false;
+	if (!xdrgen_encode_post_op_attr(xdr, &value->name_attributes))
+		return false;
+	if (!xdrgen_encode_post_op_fh3(xdr, &value->name_handle))
+		return false;
+	return true;
+}
+
+static bool __maybe_unused
+xdrgen_encode_dirlistplus3(struct xdr_stream *xdr, const struct dirlistplus3 *value)
+{
+	if (!xdrgen_encode_entryplus3(xdr, value->entries))
+		return false;
+	if (!xdrgen_encode_bool(xdr, value->eof))
+		return false;
+	return true;
+}
+
+static bool __maybe_unused
+xdrgen_encode_READDIRPLUS3resok(struct xdr_stream *xdr, const struct READDIRPLUS3resok *value)
+{
+	if (!xdrgen_encode_post_op_attr(xdr, &value->dir_attributes))
+		return false;
+	if (!xdrgen_encode_cookieverf3(xdr, value->cookieverf))
+		return false;
+	if (!xdrgen_encode_dirlistplus3(xdr, &value->reply))
+		return false;
+	return true;
+}
+
+static bool __maybe_unused
+xdrgen_encode_READDIRPLUS3resfail(struct xdr_stream *xdr, const struct READDIRPLUS3resfail *value)
+{
+	if (!xdrgen_encode_post_op_attr(xdr, &value->dir_attributes))
+		return false;
+	return true;
+}
+
+static bool __maybe_unused
+xdrgen_encode_READDIRPLUS3res(struct xdr_stream *xdr, const struct READDIRPLUS3res *ptr)
+{
+	if (!xdrgen_encode_nfsstat3(xdr, ptr->status))
+		return false;
+	switch (ptr->status) {
+	case NFS3_OK:
+		if (!xdrgen_encode_READDIRPLUS3resok(xdr, &ptr->u.resok))
+			return false;
+		break;
+	default:
+		if (!xdrgen_encode_READDIRPLUS3resfail(xdr, &ptr->u.resfail))
+			return false;
+	}
+	return true;
+}
+
+static bool __maybe_unused
+xdrgen_encode_FSSTAT3args(struct xdr_stream *xdr, const struct FSSTAT3args *value)
+{
+	if (!xdrgen_encode_nfs_fh3(xdr, &value->fsroot))
+		return false;
+	return true;
+}
+
+static bool __maybe_unused
+xdrgen_encode_FSSTAT3resok(struct xdr_stream *xdr, const struct FSSTAT3resok *value)
+{
+	if (!xdrgen_encode_post_op_attr(xdr, &value->obj_attributes))
+		return false;
+	if (!xdrgen_encode_size3(xdr, value->tbytes))
+		return false;
+	if (!xdrgen_encode_size3(xdr, value->fbytes))
+		return false;
+	if (!xdrgen_encode_size3(xdr, value->abytes))
+		return false;
+	if (!xdrgen_encode_size3(xdr, value->tfiles))
+		return false;
+	if (!xdrgen_encode_size3(xdr, value->ffiles))
+		return false;
+	if (!xdrgen_encode_size3(xdr, value->afiles))
+		return false;
+	if (!xdrgen_encode_uint32(xdr, value->invarsec))
+		return false;
+	return true;
+}
+
+static bool __maybe_unused
+xdrgen_encode_FSSTAT3resfail(struct xdr_stream *xdr, const struct FSSTAT3resfail *value)
+{
+	if (!xdrgen_encode_post_op_attr(xdr, &value->obj_attributes))
+		return false;
+	return true;
+}
+
+static bool __maybe_unused
+xdrgen_encode_FSSTAT3res(struct xdr_stream *xdr, const struct FSSTAT3res *ptr)
+{
+	if (!xdrgen_encode_nfsstat3(xdr, ptr->status))
+		return false;
+	switch (ptr->status) {
+	case NFS3_OK:
+		if (!xdrgen_encode_FSSTAT3resok(xdr, &ptr->u.resok))
+			return false;
+		break;
+	default:
+		if (!xdrgen_encode_FSSTAT3resfail(xdr, &ptr->u.resfail))
+			return false;
+	}
+	return true;
+}
+
+static bool __maybe_unused
+xdrgen_encode_FSINFO3args(struct xdr_stream *xdr, const struct FSINFO3args *value)
+{
+	if (!xdrgen_encode_nfs_fh3(xdr, &value->fsroot))
+		return false;
+	return true;
+}
+
+static bool __maybe_unused
+xdrgen_encode_FSINFO3resok(struct xdr_stream *xdr, const struct FSINFO3resok *value)
+{
+	if (!xdrgen_encode_post_op_attr(xdr, &value->obj_attributes))
+		return false;
+	if (!xdrgen_encode_uint32(xdr, value->rtmax))
+		return false;
+	if (!xdrgen_encode_uint32(xdr, value->rtpref))
+		return false;
+	if (!xdrgen_encode_uint32(xdr, value->rtmult))
+		return false;
+	if (!xdrgen_encode_uint32(xdr, value->wtmax))
+		return false;
+	if (!xdrgen_encode_uint32(xdr, value->wtpref))
+		return false;
+	if (!xdrgen_encode_uint32(xdr, value->wtmult))
+		return false;
+	if (!xdrgen_encode_uint32(xdr, value->dtpref))
+		return false;
+	if (!xdrgen_encode_size3(xdr, value->maxfilesize))
+		return false;
+	if (!xdrgen_encode_nfstime3(xdr, &value->time_delta))
+		return false;
+	if (!xdrgen_encode_uint32(xdr, value->properties))
+		return false;
+	return true;
+}
+
+static bool __maybe_unused
+xdrgen_encode_FSINFO3resfail(struct xdr_stream *xdr, const struct FSINFO3resfail *value)
+{
+	if (!xdrgen_encode_post_op_attr(xdr, &value->obj_attributes))
+		return false;
+	return true;
+}
+
+static bool __maybe_unused
+xdrgen_encode_FSINFO3res(struct xdr_stream *xdr, const struct FSINFO3res *ptr)
+{
+	if (!xdrgen_encode_nfsstat3(xdr, ptr->status))
+		return false;
+	switch (ptr->status) {
+	case NFS3_OK:
+		if (!xdrgen_encode_FSINFO3resok(xdr, &ptr->u.resok))
+			return false;
+		break;
+	default:
+		if (!xdrgen_encode_FSINFO3resfail(xdr, &ptr->u.resfail))
+			return false;
+	}
+	return true;
+}
+
+static bool __maybe_unused
+xdrgen_encode_PATHCONF3args(struct xdr_stream *xdr, const struct PATHCONF3args *value)
+{
+	if (!xdrgen_encode_nfs_fh3(xdr, &value->object))
+		return false;
+	return true;
+}
+
+static bool __maybe_unused
+xdrgen_encode_PATHCONF3resok(struct xdr_stream *xdr, const struct PATHCONF3resok *value)
+{
+	if (!xdrgen_encode_post_op_attr(xdr, &value->obj_attributes))
+		return false;
+	if (!xdrgen_encode_uint32(xdr, value->linkmax))
+		return false;
+	if (!xdrgen_encode_uint32(xdr, value->name_max))
+		return false;
+	if (!xdrgen_encode_bool(xdr, value->no_trunc))
+		return false;
+	if (!xdrgen_encode_bool(xdr, value->chown_restricted))
+		return false;
+	if (!xdrgen_encode_bool(xdr, value->case_insensitive))
+		return false;
+	if (!xdrgen_encode_bool(xdr, value->case_preserving))
+		return false;
+	return true;
+}
+
+static bool __maybe_unused
+xdrgen_encode_PATHCONF3resfail(struct xdr_stream *xdr, const struct PATHCONF3resfail *value)
+{
+	if (!xdrgen_encode_post_op_attr(xdr, &value->obj_attributes))
+		return false;
+	return true;
+}
+
+static bool __maybe_unused
+xdrgen_encode_PATHCONF3res(struct xdr_stream *xdr, const struct PATHCONF3res *ptr)
+{
+	if (!xdrgen_encode_nfsstat3(xdr, ptr->status))
+		return false;
+	switch (ptr->status) {
+	case NFS3_OK:
+		if (!xdrgen_encode_PATHCONF3resok(xdr, &ptr->u.resok))
+			return false;
+		break;
+	default:
+		if (!xdrgen_encode_PATHCONF3resfail(xdr, &ptr->u.resfail))
+			return false;
+	}
+	return true;
+}
+
+static bool __maybe_unused
+xdrgen_encode_COMMIT3args(struct xdr_stream *xdr, const struct COMMIT3args *value)
+{
+	if (!xdrgen_encode_nfs_fh3(xdr, &value->file))
+		return false;
+	if (!xdrgen_encode_offset3(xdr, value->offset))
+		return false;
+	if (!xdrgen_encode_count3(xdr, value->count))
+		return false;
+	return true;
+}
+
+static bool __maybe_unused
+xdrgen_encode_COMMIT3resok(struct xdr_stream *xdr, const struct COMMIT3resok *value)
+{
+	if (!xdrgen_encode_wcc_data(xdr, &value->file_wcc))
+		return false;
+	if (!xdrgen_encode_writeverf3(xdr, value->verf))
+		return false;
+	return true;
+}
+
+static bool __maybe_unused
+xdrgen_encode_COMMIT3resfail(struct xdr_stream *xdr, const struct COMMIT3resfail *value)
+{
+	if (!xdrgen_encode_wcc_data(xdr, &value->file_wcc))
+		return false;
+	return true;
+}
+
+static bool __maybe_unused
+xdrgen_encode_COMMIT3res(struct xdr_stream *xdr, const struct COMMIT3res *ptr)
+{
+	if (!xdrgen_encode_nfsstat3(xdr, ptr->status))
+		return false;
+	switch (ptr->status) {
+	case NFS3_OK:
+		if (!xdrgen_encode_COMMIT3resok(xdr, &ptr->u.resok))
+			return false;
+		break;
+	default:
+		if (!xdrgen_encode_COMMIT3resfail(xdr, &ptr->u.resfail))
+			return false;
+	}
+	return true;
+}
+
+/**
+ * nfs_svc_encode_GETATTR3res - Encode a GETATTR3res result
+ * @rqstp: RPC transaction context
+ * @xdr: target XDR data stream
+ *
+ * Return values:
+ *   %true: procedure results encoded successfully
+ *   %false: encode failed
+ */
+bool nfs_svc_encode_GETATTR3res(struct svc_rqst *rqstp, struct xdr_stream *xdr)
+{
+	struct GETATTR3res *resp = rqstp->rq_resp;
+
+	return xdrgen_encode_GETATTR3res(xdr, resp);
+}
+
+/**
+ * nfs_svc_encode_SETATTR3res - Encode a SETATTR3res result
+ * @rqstp: RPC transaction context
+ * @xdr: target XDR data stream
+ *
+ * Return values:
+ *   %true: procedure results encoded successfully
+ *   %false: encode failed
+ */
+bool nfs_svc_encode_SETATTR3res(struct svc_rqst *rqstp, struct xdr_stream *xdr)
+{
+	struct SETATTR3res *resp = rqstp->rq_resp;
+
+	return xdrgen_encode_SETATTR3res(xdr, resp);
+}
+
+/**
+ * nfs_svc_encode_LOOKUP3res - Encode a LOOKUP3res result
+ * @rqstp: RPC transaction context
+ * @xdr: target XDR data stream
+ *
+ * Return values:
+ *   %true: procedure results encoded successfully
+ *   %false: encode failed
+ */
+bool nfs_svc_encode_LOOKUP3res(struct svc_rqst *rqstp, struct xdr_stream *xdr)
+{
+	struct LOOKUP3res *resp = rqstp->rq_resp;
+
+	return xdrgen_encode_LOOKUP3res(xdr, resp);
+}
+
+/**
+ * nfs_svc_encode_ACCESS3res - Encode a ACCESS3res result
+ * @rqstp: RPC transaction context
+ * @xdr: target XDR data stream
+ *
+ * Return values:
+ *   %true: procedure results encoded successfully
+ *   %false: encode failed
+ */
+bool nfs_svc_encode_ACCESS3res(struct svc_rqst *rqstp, struct xdr_stream *xdr)
+{
+	struct ACCESS3res *resp = rqstp->rq_resp;
+
+	return xdrgen_encode_ACCESS3res(xdr, resp);
+}
+
+/**
+ * nfs_svc_encode_READLINK3res - Encode a READLINK3res result
+ * @rqstp: RPC transaction context
+ * @xdr: target XDR data stream
+ *
+ * Return values:
+ *   %true: procedure results encoded successfully
+ *   %false: encode failed
+ */
+bool nfs_svc_encode_READLINK3res(struct svc_rqst *rqstp, struct xdr_stream *xdr)
+{
+	struct READLINK3res *resp = rqstp->rq_resp;
+
+	return xdrgen_encode_READLINK3res(xdr, resp);
+}
+
+/**
+ * nfs_svc_encode_READ3res - Encode a READ3res result
+ * @rqstp: RPC transaction context
+ * @xdr: target XDR data stream
+ *
+ * Return values:
+ *   %true: procedure results encoded successfully
+ *   %false: encode failed
+ */
+bool nfs_svc_encode_READ3res(struct svc_rqst *rqstp, struct xdr_stream *xdr)
+{
+	struct READ3res *resp = rqstp->rq_resp;
+
+	return xdrgen_encode_READ3res(xdr, resp);
+}
+
+/**
+ * nfs_svc_encode_WRITE3res - Encode a WRITE3res result
+ * @rqstp: RPC transaction context
+ * @xdr: target XDR data stream
+ *
+ * Return values:
+ *   %true: procedure results encoded successfully
+ *   %false: encode failed
+ */
+bool nfs_svc_encode_WRITE3res(struct svc_rqst *rqstp, struct xdr_stream *xdr)
+{
+	struct WRITE3res *resp = rqstp->rq_resp;
+
+	return xdrgen_encode_WRITE3res(xdr, resp);
+}
+
+/**
+ * nfs_svc_encode_CREATE3res - Encode a CREATE3res result
+ * @rqstp: RPC transaction context
+ * @xdr: target XDR data stream
+ *
+ * Return values:
+ *   %true: procedure results encoded successfully
+ *   %false: encode failed
+ */
+bool nfs_svc_encode_CREATE3res(struct svc_rqst *rqstp, struct xdr_stream *xdr)
+{
+	struct CREATE3res *resp = rqstp->rq_resp;
+
+	return xdrgen_encode_CREATE3res(xdr, resp);
+}
+
+/**
+ * nfs_svc_encode_MKDIR3res - Encode a MKDIR3res result
+ * @rqstp: RPC transaction context
+ * @xdr: target XDR data stream
+ *
+ * Return values:
+ *   %true: procedure results encoded successfully
+ *   %false: encode failed
+ */
+bool nfs_svc_encode_MKDIR3res(struct svc_rqst *rqstp, struct xdr_stream *xdr)
+{
+	struct MKDIR3res *resp = rqstp->rq_resp;
+
+	return xdrgen_encode_MKDIR3res(xdr, resp);
+}
+
+/**
+ * nfs_svc_encode_SYMLINK3res - Encode a SYMLINK3res result
+ * @rqstp: RPC transaction context
+ * @xdr: target XDR data stream
+ *
+ * Return values:
+ *   %true: procedure results encoded successfully
+ *   %false: encode failed
+ */
+bool nfs_svc_encode_SYMLINK3res(struct svc_rqst *rqstp, struct xdr_stream *xdr)
+{
+	struct SYMLINK3res *resp = rqstp->rq_resp;
+
+	return xdrgen_encode_SYMLINK3res(xdr, resp);
+}
+
+/**
+ * nfs_svc_encode_MKNOD3res - Encode a MKNOD3res result
+ * @rqstp: RPC transaction context
+ * @xdr: target XDR data stream
+ *
+ * Return values:
+ *   %true: procedure results encoded successfully
+ *   %false: encode failed
+ */
+bool nfs_svc_encode_MKNOD3res(struct svc_rqst *rqstp, struct xdr_stream *xdr)
+{
+	struct MKNOD3res *resp = rqstp->rq_resp;
+
+	return xdrgen_encode_MKNOD3res(xdr, resp);
+}
+
+/**
+ * nfs_svc_encode_REMOVE3res - Encode a REMOVE3res result
+ * @rqstp: RPC transaction context
+ * @xdr: target XDR data stream
+ *
+ * Return values:
+ *   %true: procedure results encoded successfully
+ *   %false: encode failed
+ */
+bool nfs_svc_encode_REMOVE3res(struct svc_rqst *rqstp, struct xdr_stream *xdr)
+{
+	struct REMOVE3res *resp = rqstp->rq_resp;
+
+	return xdrgen_encode_REMOVE3res(xdr, resp);
+}
+
+/**
+ * nfs_svc_encode_RMDIR3res - Encode a RMDIR3res result
+ * @rqstp: RPC transaction context
+ * @xdr: target XDR data stream
+ *
+ * Return values:
+ *   %true: procedure results encoded successfully
+ *   %false: encode failed
+ */
+bool nfs_svc_encode_RMDIR3res(struct svc_rqst *rqstp, struct xdr_stream *xdr)
+{
+	struct RMDIR3res *resp = rqstp->rq_resp;
+
+	return xdrgen_encode_RMDIR3res(xdr, resp);
+}
+
+/**
+ * nfs_svc_encode_RENAME3res - Encode a RENAME3res result
+ * @rqstp: RPC transaction context
+ * @xdr: target XDR data stream
+ *
+ * Return values:
+ *   %true: procedure results encoded successfully
+ *   %false: encode failed
+ */
+bool nfs_svc_encode_RENAME3res(struct svc_rqst *rqstp, struct xdr_stream *xdr)
+{
+	struct RENAME3res *resp = rqstp->rq_resp;
+
+	return xdrgen_encode_RENAME3res(xdr, resp);
+}
+
+/**
+ * nfs_svc_encode_LINK3res - Encode a LINK3res result
+ * @rqstp: RPC transaction context
+ * @xdr: target XDR data stream
+ *
+ * Return values:
+ *   %true: procedure results encoded successfully
+ *   %false: encode failed
+ */
+bool nfs_svc_encode_LINK3res(struct svc_rqst *rqstp, struct xdr_stream *xdr)
+{
+	struct LINK3res *resp = rqstp->rq_resp;
+
+	return xdrgen_encode_LINK3res(xdr, resp);
+}
+
+/**
+ * nfs_svc_encode_READDIR3res - Encode a READDIR3res result
+ * @rqstp: RPC transaction context
+ * @xdr: target XDR data stream
+ *
+ * Return values:
+ *   %true: procedure results encoded successfully
+ *   %false: encode failed
+ */
+bool nfs_svc_encode_READDIR3res(struct svc_rqst *rqstp, struct xdr_stream *xdr)
+{
+	struct READDIR3res *resp = rqstp->rq_resp;
+
+	return xdrgen_encode_READDIR3res(xdr, resp);
+}
+
+/**
+ * nfs_svc_encode_READDIRPLUS3res - Encode a READDIRPLUS3res result
+ * @rqstp: RPC transaction context
+ * @xdr: target XDR data stream
+ *
+ * Return values:
+ *   %true: procedure results encoded successfully
+ *   %false: encode failed
+ */
+bool nfs_svc_encode_READDIRPLUS3res(struct svc_rqst *rqstp, struct xdr_stream *xdr)
+{
+	struct READDIRPLUS3res *resp = rqstp->rq_resp;
+
+	return xdrgen_encode_READDIRPLUS3res(xdr, resp);
+}
+
+/**
+ * nfs_svc_encode_FSSTAT3res - Encode a FSSTAT3res result
+ * @rqstp: RPC transaction context
+ * @xdr: target XDR data stream
+ *
+ * Return values:
+ *   %true: procedure results encoded successfully
+ *   %false: encode failed
+ */
+bool nfs_svc_encode_FSSTAT3res(struct svc_rqst *rqstp, struct xdr_stream *xdr)
+{
+	struct FSSTAT3res *resp = rqstp->rq_resp;
+
+	return xdrgen_encode_FSSTAT3res(xdr, resp);
+}
+
+/**
+ * nfs_svc_encode_FSINFO3res - Encode a FSINFO3res result
+ * @rqstp: RPC transaction context
+ * @xdr: target XDR data stream
+ *
+ * Return values:
+ *   %true: procedure results encoded successfully
+ *   %false: encode failed
+ */
+bool nfs_svc_encode_FSINFO3res(struct svc_rqst *rqstp, struct xdr_stream *xdr)
+{
+	struct FSINFO3res *resp = rqstp->rq_resp;
+
+	return xdrgen_encode_FSINFO3res(xdr, resp);
+}
+
+/**
+ * nfs_svc_encode_PATHCONF3res - Encode a PATHCONF3res result
+ * @rqstp: RPC transaction context
+ * @xdr: target XDR data stream
+ *
+ * Return values:
+ *   %true: procedure results encoded successfully
+ *   %false: encode failed
+ */
+bool nfs_svc_encode_PATHCONF3res(struct svc_rqst *rqstp, struct xdr_stream *xdr)
+{
+	struct PATHCONF3res *resp = rqstp->rq_resp;
+
+	return xdrgen_encode_PATHCONF3res(xdr, resp);
+}
+
+/**
+ * nfs_svc_encode_COMMIT3res - Encode a COMMIT3res result
+ * @rqstp: RPC transaction context
+ * @xdr: target XDR data stream
+ *
+ * Return values:
+ *   %true: procedure results encoded successfully
+ *   %false: encode failed
+ */
+bool nfs_svc_encode_COMMIT3res(struct svc_rqst *rqstp, struct xdr_stream *xdr)
+{
+	struct COMMIT3res *resp = rqstp->rq_resp;
+
+	return xdrgen_encode_COMMIT3res(xdr, resp);
+}
diff --git a/fs/nfsd/nfs3xdr_gen.h b/fs/nfsd/nfs3xdr_gen.h
new file mode 100644
index 000000000000..e2fbb583da92
--- /dev/null
+++ b/fs/nfsd/nfs3xdr_gen.h
@@ -0,0 +1,60 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+/* Generated by xdrgen. Manual edits will be lost. */
+/* XDR specification file: ../../Documentation/sunrpc/xdr/nfs3.x */
+/* XDR specification modification time: Fri Jul 10 23:20:55 2026 */
+
+#ifndef _LINUX_XDRGEN_NFS3_DECL_H
+#define _LINUX_XDRGEN_NFS3_DECL_H
+
+#include <linux/types.h>
+
+#include <linux/sunrpc/xdr.h>
+#include <linux/sunrpc/xdrgen/_defs.h>
+#include <linux/sunrpc/xdrgen/_builtins.h>
+#include <linux/sunrpc/xdrgen/nfs3.h>
+
+bool nfs_svc_decode_GETATTR3args(struct svc_rqst *rqstp, struct xdr_stream *xdr);
+bool nfs_svc_decode_SETATTR3args(struct svc_rqst *rqstp, struct xdr_stream *xdr);
+bool nfs_svc_decode_LOOKUP3args(struct svc_rqst *rqstp, struct xdr_stream *xdr);
+bool nfs_svc_decode_ACCESS3args(struct svc_rqst *rqstp, struct xdr_stream *xdr);
+bool nfs_svc_decode_READLINK3args(struct svc_rqst *rqstp, struct xdr_stream *xdr);
+bool nfs_svc_decode_READ3args(struct svc_rqst *rqstp, struct xdr_stream *xdr);
+bool nfs_svc_decode_WRITE3args(struct svc_rqst *rqstp, struct xdr_stream *xdr);
+bool nfs_svc_decode_CREATE3args(struct svc_rqst *rqstp, struct xdr_stream *xdr);
+bool nfs_svc_decode_MKDIR3args(struct svc_rqst *rqstp, struct xdr_stream *xdr);
+bool nfs_svc_decode_SYMLINK3args(struct svc_rqst *rqstp, struct xdr_stream *xdr);
+bool nfs_svc_decode_MKNOD3args(struct svc_rqst *rqstp, struct xdr_stream *xdr);
+bool nfs_svc_decode_REMOVE3args(struct svc_rqst *rqstp, struct xdr_stream *xdr);
+bool nfs_svc_decode_RMDIR3args(struct svc_rqst *rqstp, struct xdr_stream *xdr);
+bool nfs_svc_decode_RENAME3args(struct svc_rqst *rqstp, struct xdr_stream *xdr);
+bool nfs_svc_decode_LINK3args(struct svc_rqst *rqstp, struct xdr_stream *xdr);
+bool nfs_svc_decode_READDIR3args(struct svc_rqst *rqstp, struct xdr_stream *xdr);
+bool nfs_svc_decode_READDIRPLUS3args(struct svc_rqst *rqstp, struct xdr_stream *xdr);
+bool nfs_svc_decode_FSSTAT3args(struct svc_rqst *rqstp, struct xdr_stream *xdr);
+bool nfs_svc_decode_FSINFO3args(struct svc_rqst *rqstp, struct xdr_stream *xdr);
+bool nfs_svc_decode_PATHCONF3args(struct svc_rqst *rqstp, struct xdr_stream *xdr);
+bool nfs_svc_decode_COMMIT3args(struct svc_rqst *rqstp, struct xdr_stream *xdr);
+
+bool nfs_svc_encode_GETATTR3res(struct svc_rqst *rqstp, struct xdr_stream *xdr);
+bool nfs_svc_encode_SETATTR3res(struct svc_rqst *rqstp, struct xdr_stream *xdr);
+bool nfs_svc_encode_LOOKUP3res(struct svc_rqst *rqstp, struct xdr_stream *xdr);
+bool nfs_svc_encode_ACCESS3res(struct svc_rqst *rqstp, struct xdr_stream *xdr);
+bool nfs_svc_encode_READLINK3res(struct svc_rqst *rqstp, struct xdr_stream *xdr);
+bool nfs_svc_encode_READ3res(struct svc_rqst *rqstp, struct xdr_stream *xdr);
+bool nfs_svc_encode_WRITE3res(struct svc_rqst *rqstp, struct xdr_stream *xdr);
+bool nfs_svc_encode_CREATE3res(struct svc_rqst *rqstp, struct xdr_stream *xdr);
+bool nfs_svc_encode_MKDIR3res(struct svc_rqst *rqstp, struct xdr_stream *xdr);
+bool nfs_svc_encode_SYMLINK3res(struct svc_rqst *rqstp, struct xdr_stream *xdr);
+bool nfs_svc_encode_MKNOD3res(struct svc_rqst *rqstp, struct xdr_stream *xdr);
+bool nfs_svc_encode_REMOVE3res(struct svc_rqst *rqstp, struct xdr_stream *xdr);
+bool nfs_svc_encode_RMDIR3res(struct svc_rqst *rqstp, struct xdr_stream *xdr);
+bool nfs_svc_encode_RENAME3res(struct svc_rqst *rqstp, struct xdr_stream *xdr);
+bool nfs_svc_encode_LINK3res(struct svc_rqst *rqstp, struct xdr_stream *xdr);
+bool nfs_svc_encode_READDIR3res(struct svc_rqst *rqstp, struct xdr_stream *xdr);
+bool nfs_svc_encode_READDIRPLUS3res(struct svc_rqst *rqstp, struct xdr_stream *xdr);
+bool nfs_svc_encode_FSSTAT3res(struct svc_rqst *rqstp, struct xdr_stream *xdr);
+bool nfs_svc_encode_FSINFO3res(struct svc_rqst *rqstp, struct xdr_stream *xdr);
+bool nfs_svc_encode_PATHCONF3res(struct svc_rqst *rqstp, struct xdr_stream *xdr);
+bool nfs_svc_encode_COMMIT3res(struct svc_rqst *rqstp, struct xdr_stream *xdr);
+
+#endif /* _LINUX_XDRGEN_NFS3_DECL_H */
diff --git a/include/linux/sunrpc/xdrgen/nfs3.h b/include/linux/sunrpc/xdrgen/nfs3.h
new file mode 100644
index 000000000000..3afc4ffb6daa
--- /dev/null
+++ b/include/linux/sunrpc/xdrgen/nfs3.h
@@ -0,0 +1,1092 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+/* Generated by xdrgen. Manual edits will be lost. */
+/* XDR specification file: ../../Documentation/sunrpc/xdr/nfs3.x */
+/* XDR specification modification time: Fri Jul 10 23:20:55 2026 */
+
+#ifndef _LINUX_XDRGEN_NFS3_DEF_H
+#define _LINUX_XDRGEN_NFS3_DEF_H
+
+#include <linux/types.h>
+#include <linux/sunrpc/xdrgen/_defs.h>
+
+enum { NFS3_FHSIZE = 64 };
+
+enum { NFS3_COOKIEVERFSIZE = 8 };
+
+enum { NFS3_CREATEVERFSIZE = 8 };
+
+enum { NFS3_WRITEVERFSIZE = 8 };
+
+typedef u64 uint64;
+
+typedef s64 int64;
+
+typedef u32 uint32;
+
+typedef s32 int32;
+
+typedef string filename3;
+
+typedef string nfspath3;
+
+typedef uint64 fileid3;
+
+typedef uint64 cookie3;
+
+typedef u8 cookieverf3[NFS3_COOKIEVERFSIZE];
+
+typedef u8 createverf3[NFS3_CREATEVERFSIZE];
+
+typedef u8 writeverf3[NFS3_WRITEVERFSIZE];
+
+typedef uint32 uid3;
+
+typedef uint32 gid3;
+
+typedef uint64 size3;
+
+typedef uint64 offset3;
+
+typedef uint32 mode3;
+
+typedef uint32 count3;
+
+enum nfsstat3 {
+	NFS3_OK = 0,
+	NFS3ERR_PERM = 1,
+	NFS3ERR_NOENT = 2,
+	NFS3ERR_IO = 5,
+	NFS3ERR_NXIO = 6,
+	NFS3ERR_ACCES = 13,
+	NFS3ERR_EXIST = 17,
+	NFS3ERR_XDEV = 18,
+	NFS3ERR_NODEV = 19,
+	NFS3ERR_NOTDIR = 20,
+	NFS3ERR_ISDIR = 21,
+	NFS3ERR_INVAL = 22,
+	NFS3ERR_FBIG = 27,
+	NFS3ERR_NOSPC = 28,
+	NFS3ERR_ROFS = 30,
+	NFS3ERR_MLINK = 31,
+	NFS3ERR_NAMETOOLONG = 63,
+	NFS3ERR_NOTEMPTY = 66,
+	NFS3ERR_DQUOT = 69,
+	NFS3ERR_STALE = 70,
+	NFS3ERR_REMOTE = 71,
+	NFS3ERR_BADHANDLE = 10001,
+	NFS3ERR_NOT_SYNC = 10002,
+	NFS3ERR_BAD_COOKIE = 10003,
+	NFS3ERR_NOTSUPP = 10004,
+	NFS3ERR_TOOSMALL = 10005,
+	NFS3ERR_SERVERFAULT = 10006,
+	NFS3ERR_BADTYPE = 10007,
+	NFS3ERR_JUKEBOX = 10008,
+};
+
+typedef enum nfsstat3 nfsstat3;
+
+enum ftype3 {
+	NF3REG = 1,
+	NF3DIR = 2,
+	NF3BLK = 3,
+	NF3CHR = 4,
+	NF3LNK = 5,
+	NF3SOCK = 6,
+	NF3FIFO = 7,
+};
+
+typedef enum ftype3 ftype3;
+
+struct specdata3 {
+	uint32 specdata1;
+	uint32 specdata2;
+};
+
+struct nfs_fh3 {
+	opaque data;
+};
+
+struct nfstime3 {
+	uint32 seconds;
+	uint32 nseconds;
+};
+
+struct fattr3 {
+	ftype3 type;
+	mode3 mode;
+	uint32 nlink;
+	uid3 uid;
+	gid3 gid;
+	size3 size;
+	size3 used;
+	struct specdata3 rdev;
+	uint64 fsid;
+	fileid3 fileid;
+	struct nfstime3 atime;
+	struct nfstime3 mtime;
+	struct nfstime3 ctime;
+};
+
+struct post_op_attr {
+	bool attributes_follow;
+	union {
+		struct fattr3 attributes;
+	} u;
+};
+
+struct wcc_attr {
+	size3 size;
+	struct nfstime3 mtime;
+	struct nfstime3 ctime;
+};
+
+struct pre_op_attr {
+	bool attributes_follow;
+	union {
+		struct wcc_attr attributes;
+	} u;
+};
+
+struct wcc_data {
+	struct pre_op_attr before;
+	struct post_op_attr after;
+};
+
+struct post_op_fh3 {
+	bool handle_follows;
+	union {
+		struct nfs_fh3 handle;
+	} u;
+};
+
+enum time_how {
+	DONT_CHANGE = 0,
+	SET_TO_SERVER_TIME = 1,
+	SET_TO_CLIENT_TIME = 2,
+};
+
+typedef enum time_how time_how;
+
+struct set_mode3 {
+	bool set_it;
+	union {
+		mode3 mode;
+	} u;
+};
+
+struct set_uid3 {
+	bool set_it;
+	union {
+		uid3 uid;
+	} u;
+};
+
+struct set_gid3 {
+	bool set_it;
+	union {
+		gid3 gid;
+	} u;
+};
+
+struct set_size3 {
+	bool set_it;
+	union {
+		size3 size;
+	} u;
+};
+
+struct set_atime {
+	time_how set_it;
+	union {
+		struct nfstime3 atime;
+	} u;
+};
+
+struct set_mtime {
+	time_how set_it;
+	union {
+		struct nfstime3 mtime;
+	} u;
+};
+
+struct sattr3 {
+	struct set_mode3 mode;
+	struct set_uid3 uid;
+	struct set_gid3 gid;
+	struct set_size3 size;
+	struct set_atime atime;
+	struct set_mtime mtime;
+};
+
+struct diropargs3 {
+	struct nfs_fh3 dir;
+	filename3 name;
+};
+
+struct GETATTR3args {
+	struct nfs_fh3 object;
+};
+
+struct GETATTR3resok {
+	struct fattr3 obj_attributes;
+};
+
+struct GETATTR3res {
+	nfsstat3 status;
+	union {
+		struct GETATTR3resok resok;
+	} u;
+};
+
+struct sattrguard3 {
+	bool check;
+	union {
+		struct nfstime3 obj_ctime;
+	} u;
+};
+
+struct SETATTR3args {
+	struct nfs_fh3 object;
+	struct sattr3 new_attributes;
+	struct sattrguard3 guard;
+};
+
+struct SETATTR3resok {
+	struct wcc_data obj_wcc;
+};
+
+struct SETATTR3resfail {
+	struct wcc_data obj_wcc;
+};
+
+struct SETATTR3res {
+	nfsstat3 status;
+	union {
+		struct SETATTR3resok resok;
+		struct SETATTR3resfail resfail;
+	} u;
+};
+
+struct LOOKUP3args {
+	struct diropargs3 what;
+};
+
+struct LOOKUP3resok {
+	struct nfs_fh3 object;
+	struct post_op_attr obj_attributes;
+	struct post_op_attr dir_attributes;
+};
+
+struct LOOKUP3resfail {
+	struct post_op_attr dir_attributes;
+};
+
+struct LOOKUP3res {
+	nfsstat3 status;
+	union {
+		struct LOOKUP3resok resok;
+		struct LOOKUP3resfail resfail;
+	} u;
+};
+
+enum { ACCESS3_READ = 0x0001 };
+
+enum { ACCESS3_LOOKUP = 0x0002 };
+
+enum { ACCESS3_MODIFY = 0x0004 };
+
+enum { ACCESS3_EXTEND = 0x0008 };
+
+enum { ACCESS3_DELETE = 0x0010 };
+
+enum { ACCESS3_EXECUTE = 0x0020 };
+
+struct ACCESS3args {
+	struct nfs_fh3 object;
+	uint32 access;
+};
+
+struct ACCESS3resok {
+	struct post_op_attr obj_attributes;
+	uint32 access;
+};
+
+struct ACCESS3resfail {
+	struct post_op_attr obj_attributes;
+};
+
+struct ACCESS3res {
+	nfsstat3 status;
+	union {
+		struct ACCESS3resok resok;
+		struct ACCESS3resfail resfail;
+	} u;
+};
+
+struct READLINK3args {
+	struct nfs_fh3 symlink;
+};
+
+struct READLINK3resok {
+	struct post_op_attr symlink_attributes;
+	nfspath3 data;
+};
+
+struct READLINK3resfail {
+	struct post_op_attr symlink_attributes;
+};
+
+struct READLINK3res {
+	nfsstat3 status;
+	union {
+		struct READLINK3resok resok;
+		struct READLINK3resfail resfail;
+	} u;
+};
+
+struct READ3args {
+	struct nfs_fh3 file;
+	offset3 offset;
+	count3 count;
+};
+
+struct READ3resok {
+	struct post_op_attr file_attributes;
+	count3 count;
+	bool eof;
+	opaque data;
+};
+
+struct READ3resfail {
+	struct post_op_attr file_attributes;
+};
+
+struct READ3res {
+	nfsstat3 status;
+	union {
+		struct READ3resok resok;
+		struct READ3resfail resfail;
+	} u;
+};
+
+enum stable_how {
+	UNSTABLE = 0,
+	DATA_SYNC = 1,
+	FILE_SYNC = 2,
+};
+
+typedef enum stable_how stable_how;
+
+struct WRITE3args {
+	struct nfs_fh3 file;
+	offset3 offset;
+	count3 count;
+	stable_how stable;
+	opaque data;
+};
+
+struct WRITE3resok {
+	struct wcc_data file_wcc;
+	count3 count;
+	stable_how committed;
+	writeverf3 verf;
+};
+
+struct WRITE3resfail {
+	struct wcc_data file_wcc;
+};
+
+struct WRITE3res {
+	nfsstat3 status;
+	union {
+		struct WRITE3resok resok;
+		struct WRITE3resfail resfail;
+	} u;
+};
+
+enum createmode3 {
+	UNCHECKED = 0,
+	GUARDED = 1,
+	EXCLUSIVE = 2,
+};
+
+typedef enum createmode3 createmode3;
+
+struct createhow3 {
+	createmode3 mode;
+	union {
+		struct sattr3 obj_attributes;
+		createverf3 verf;
+	} u;
+};
+
+struct CREATE3args {
+	struct diropargs3 where;
+	struct createhow3 how;
+};
+
+struct CREATE3resok {
+	struct post_op_fh3 obj;
+	struct post_op_attr obj_attributes;
+	struct wcc_data dir_wcc;
+};
+
+struct CREATE3resfail {
+	struct wcc_data dir_wcc;
+};
+
+struct CREATE3res {
+	nfsstat3 status;
+	union {
+		struct CREATE3resok resok;
+		struct CREATE3resfail resfail;
+	} u;
+};
+
+struct MKDIR3args {
+	struct diropargs3 where;
+	struct sattr3 attributes;
+};
+
+struct MKDIR3resok {
+	struct post_op_fh3 obj;
+	struct post_op_attr obj_attributes;
+	struct wcc_data dir_wcc;
+};
+
+struct MKDIR3resfail {
+	struct wcc_data dir_wcc;
+};
+
+struct MKDIR3res {
+	nfsstat3 status;
+	union {
+		struct MKDIR3resok resok;
+		struct MKDIR3resfail resfail;
+	} u;
+};
+
+struct symlinkdata3 {
+	struct sattr3 symlink_attributes;
+	nfspath3 symlink_data;
+};
+
+struct SYMLINK3args {
+	struct diropargs3 where;
+	struct symlinkdata3 symlink;
+};
+
+struct SYMLINK3resok {
+	struct post_op_fh3 obj;
+	struct post_op_attr obj_attributes;
+	struct wcc_data dir_wcc;
+};
+
+struct SYMLINK3resfail {
+	struct wcc_data dir_wcc;
+};
+
+struct SYMLINK3res {
+	nfsstat3 status;
+	union {
+		struct SYMLINK3resok resok;
+		struct SYMLINK3resfail resfail;
+	} u;
+};
+
+struct devicedata3 {
+	struct sattr3 dev_attributes;
+	struct specdata3 spec;
+};
+
+struct mknoddata3 {
+	ftype3 type;
+	union {
+		struct devicedata3 device;
+		struct sattr3 pipe_attributes;
+	} u;
+};
+
+struct MKNOD3args {
+	struct diropargs3 where;
+	struct mknoddata3 what;
+};
+
+struct MKNOD3resok {
+	struct post_op_fh3 obj;
+	struct post_op_attr obj_attributes;
+	struct wcc_data dir_wcc;
+};
+
+struct MKNOD3resfail {
+	struct wcc_data dir_wcc;
+};
+
+struct MKNOD3res {
+	nfsstat3 status;
+	union {
+		struct MKNOD3resok resok;
+		struct MKNOD3resfail resfail;
+	} u;
+};
+
+struct REMOVE3args {
+	struct diropargs3 object;
+};
+
+struct REMOVE3resok {
+	struct wcc_data dir_wcc;
+};
+
+struct REMOVE3resfail {
+	struct wcc_data dir_wcc;
+};
+
+struct REMOVE3res {
+	nfsstat3 status;
+	union {
+		struct REMOVE3resok resok;
+		struct REMOVE3resfail resfail;
+	} u;
+};
+
+struct RMDIR3args {
+	struct diropargs3 object;
+};
+
+struct RMDIR3resok {
+	struct wcc_data dir_wcc;
+};
+
+struct RMDIR3resfail {
+	struct wcc_data dir_wcc;
+};
+
+struct RMDIR3res {
+	nfsstat3 status;
+	union {
+		struct RMDIR3resok resok;
+		struct RMDIR3resfail resfail;
+	} u;
+};
+
+struct RENAME3args {
+	struct diropargs3 from;
+	struct diropargs3 to;
+};
+
+struct RENAME3resok {
+	struct wcc_data fromdir_wcc;
+	struct wcc_data todir_wcc;
+};
+
+struct RENAME3resfail {
+	struct wcc_data fromdir_wcc;
+	struct wcc_data todir_wcc;
+};
+
+struct RENAME3res {
+	nfsstat3 status;
+	union {
+		struct RENAME3resok resok;
+		struct RENAME3resfail resfail;
+	} u;
+};
+
+struct LINK3args {
+	struct nfs_fh3 file;
+	struct diropargs3 link;
+};
+
+struct LINK3resok {
+	struct post_op_attr file_attributes;
+	struct wcc_data linkdir_wcc;
+};
+
+struct LINK3resfail {
+	struct post_op_attr file_attributes;
+	struct wcc_data linkdir_wcc;
+};
+
+struct LINK3res {
+	nfsstat3 status;
+	union {
+		struct LINK3resok resok;
+		struct LINK3resfail resfail;
+	} u;
+};
+
+struct READDIR3args {
+	struct nfs_fh3 dir;
+	cookie3 cookie;
+	cookieverf3 cookieverf;
+	count3 count;
+};
+
+struct entry3 {
+	fileid3 fileid;
+	filename3 name;
+	cookie3 cookie;
+};
+
+struct dirlist3 {
+	struct entry3 *entries;
+	bool eof;
+};
+
+struct READDIR3resok {
+	struct post_op_attr dir_attributes;
+	cookieverf3 cookieverf;
+	struct dirlist3 reply;
+};
+
+struct READDIR3resfail {
+	struct post_op_attr dir_attributes;
+};
+
+struct READDIR3res {
+	nfsstat3 status;
+	union {
+		struct READDIR3resok resok;
+		struct READDIR3resfail resfail;
+	} u;
+};
+
+struct READDIRPLUS3args {
+	struct nfs_fh3 dir;
+	cookie3 cookie;
+	cookieverf3 cookieverf;
+	count3 dircount;
+	count3 maxcount;
+};
+
+struct entryplus3 {
+	fileid3 fileid;
+	filename3 name;
+	cookie3 cookie;
+	struct post_op_attr name_attributes;
+	struct post_op_fh3 name_handle;
+};
+
+struct dirlistplus3 {
+	struct entryplus3 *entries;
+	bool eof;
+};
+
+struct READDIRPLUS3resok {
+	struct post_op_attr dir_attributes;
+	cookieverf3 cookieverf;
+	struct dirlistplus3 reply;
+};
+
+struct READDIRPLUS3resfail {
+	struct post_op_attr dir_attributes;
+};
+
+struct READDIRPLUS3res {
+	nfsstat3 status;
+	union {
+		struct READDIRPLUS3resok resok;
+		struct READDIRPLUS3resfail resfail;
+	} u;
+};
+
+struct FSSTAT3args {
+	struct nfs_fh3 fsroot;
+};
+
+struct FSSTAT3resok {
+	struct post_op_attr obj_attributes;
+	size3 tbytes;
+	size3 fbytes;
+	size3 abytes;
+	size3 tfiles;
+	size3 ffiles;
+	size3 afiles;
+	uint32 invarsec;
+};
+
+struct FSSTAT3resfail {
+	struct post_op_attr obj_attributes;
+};
+
+struct FSSTAT3res {
+	nfsstat3 status;
+	union {
+		struct FSSTAT3resok resok;
+		struct FSSTAT3resfail resfail;
+	} u;
+};
+
+enum { FSF3_LINK = 0x0001 };
+
+enum { FSF3_SYMLINK = 0x0002 };
+
+enum { FSF3_HOMOGENEOUS = 0x0008 };
+
+enum { FSF3_CANSETTIME = 0x0010 };
+
+struct FSINFO3args {
+	struct nfs_fh3 fsroot;
+};
+
+struct FSINFO3resok {
+	struct post_op_attr obj_attributes;
+	uint32 rtmax;
+	uint32 rtpref;
+	uint32 rtmult;
+	uint32 wtmax;
+	uint32 wtpref;
+	uint32 wtmult;
+	uint32 dtpref;
+	size3 maxfilesize;
+	struct nfstime3 time_delta;
+	uint32 properties;
+};
+
+struct FSINFO3resfail {
+	struct post_op_attr obj_attributes;
+};
+
+struct FSINFO3res {
+	nfsstat3 status;
+	union {
+		struct FSINFO3resok resok;
+		struct FSINFO3resfail resfail;
+	} u;
+};
+
+struct PATHCONF3args {
+	struct nfs_fh3 object;
+};
+
+struct PATHCONF3resok {
+	struct post_op_attr obj_attributes;
+	uint32 linkmax;
+	uint32 name_max;
+	bool no_trunc;
+	bool chown_restricted;
+	bool case_insensitive;
+	bool case_preserving;
+};
+
+struct PATHCONF3resfail {
+	struct post_op_attr obj_attributes;
+};
+
+struct PATHCONF3res {
+	nfsstat3 status;
+	union {
+		struct PATHCONF3resok resok;
+		struct PATHCONF3resfail resfail;
+	} u;
+};
+
+struct COMMIT3args {
+	struct nfs_fh3 file;
+	offset3 offset;
+	count3 count;
+};
+
+struct COMMIT3resok {
+	struct wcc_data file_wcc;
+	writeverf3 verf;
+};
+
+struct COMMIT3resfail {
+	struct wcc_data file_wcc;
+};
+
+struct COMMIT3res {
+	nfsstat3 status;
+	union {
+		struct COMMIT3resok resok;
+		struct COMMIT3resfail resfail;
+	} u;
+};
+
+enum {
+	NFSPROC3_NULL = 0,
+	NFSPROC3_GETATTR = 1,
+	NFSPROC3_SETATTR = 2,
+	NFSPROC3_LOOKUP = 3,
+	NFSPROC3_ACCESS = 4,
+	NFSPROC3_READLINK = 5,
+	NFSPROC3_READ = 6,
+	NFSPROC3_WRITE = 7,
+	NFSPROC3_CREATE = 8,
+	NFSPROC3_MKDIR = 9,
+	NFSPROC3_SYMLINK = 10,
+	NFSPROC3_MKNOD = 11,
+	NFSPROC3_REMOVE = 12,
+	NFSPROC3_RMDIR = 13,
+	NFSPROC3_RENAME = 14,
+	NFSPROC3_LINK = 15,
+	NFSPROC3_READDIR = 16,
+	NFSPROC3_READDIRPLUS = 17,
+	NFSPROC3_FSSTAT = 18,
+	NFSPROC3_FSINFO = 19,
+	NFSPROC3_PATHCONF = 20,
+	NFSPROC3_COMMIT = 21,
+};
+
+#ifndef NFS_PROGRAM
+#define NFS_PROGRAM (100003)
+#endif
+
+#define NFS3_uint64_sz                  \
+	(XDR_unsigned_hyper)
+#define NFS3_int64_sz                   \
+	(XDR_hyper)
+#define NFS3_uint32_sz                  \
+	(XDR_unsigned_long)
+#define NFS3_int32_sz                   \
+	(XDR_long)
+#define NFS3_filename3_sz               (XDR_unsigned_int)
+#define NFS3_nfspath3_sz                (XDR_unsigned_int)
+#define NFS3_fileid3_sz                 \
+	(NFS3_uint64_sz)
+#define NFS3_cookie3_sz                 \
+	(NFS3_uint64_sz)
+#define NFS3_cookieverf3_sz             (XDR_QUADLEN(NFS3_COOKIEVERFSIZE))
+#define NFS3_createverf3_sz             (XDR_QUADLEN(NFS3_CREATEVERFSIZE))
+#define NFS3_writeverf3_sz              (XDR_QUADLEN(NFS3_WRITEVERFSIZE))
+#define NFS3_uid3_sz                    \
+	(NFS3_uint32_sz)
+#define NFS3_gid3_sz                    \
+	(NFS3_uint32_sz)
+#define NFS3_size3_sz                   \
+	(NFS3_uint64_sz)
+#define NFS3_offset3_sz                 \
+	(NFS3_uint64_sz)
+#define NFS3_mode3_sz                   \
+	(NFS3_uint32_sz)
+#define NFS3_count3_sz                  \
+	(NFS3_uint32_sz)
+#define NFS3_nfsstat3_sz                (XDR_int)
+#define NFS3_ftype3_sz                  (XDR_int)
+#define NFS3_specdata3_sz               \
+	(NFS3_uint32_sz + NFS3_uint32_sz)
+#define NFS3_nfs_fh3_sz                 \
+	(XDR_unsigned_int + XDR_QUADLEN(NFS3_FHSIZE))
+#define NFS3_nfstime3_sz                \
+	(NFS3_uint32_sz + NFS3_uint32_sz)
+#define NFS3_fattr3_sz                  \
+	(NFS3_ftype3_sz + NFS3_mode3_sz + NFS3_uint32_sz + NFS3_uid3_sz + NFS3_gid3_sz + NFS3_size3_sz + NFS3_size3_sz + NFS3_specdata3_sz + NFS3_uint64_sz + NFS3_fileid3_sz + NFS3_nfstime3_sz + NFS3_nfstime3_sz + NFS3_nfstime3_sz)
+#define NFS3_post_op_attr_sz            \
+	(XDR_bool + NFS3_fattr3_sz)
+#define NFS3_wcc_attr_sz                \
+	(NFS3_size3_sz + NFS3_nfstime3_sz + NFS3_nfstime3_sz)
+#define NFS3_pre_op_attr_sz             \
+	(XDR_bool + NFS3_wcc_attr_sz)
+#define NFS3_wcc_data_sz                \
+	(NFS3_pre_op_attr_sz + NFS3_post_op_attr_sz)
+#define NFS3_post_op_fh3_sz             \
+	(XDR_bool + NFS3_nfs_fh3_sz)
+#define NFS3_time_how_sz                (XDR_int)
+#define NFS3_set_mode3_sz               \
+	(NFS3_time_how_sz + NFS3_mode3_sz)
+#define NFS3_set_uid3_sz                \
+	(NFS3_time_how_sz + NFS3_uid3_sz)
+#define NFS3_set_gid3_sz                \
+	(NFS3_time_how_sz + NFS3_gid3_sz)
+#define NFS3_set_size3_sz               \
+	(NFS3_time_how_sz + NFS3_size3_sz)
+#define NFS3_set_atime_sz               \
+	(NFS3_time_how_sz + NFS3_nfstime3_sz)
+#define NFS3_set_mtime_sz               \
+	(NFS3_time_how_sz + NFS3_nfstime3_sz)
+#define NFS3_sattr3_sz                  \
+	(NFS3_set_mode3_sz + NFS3_set_uid3_sz + NFS3_set_gid3_sz + NFS3_set_size3_sz + NFS3_set_atime_sz + NFS3_set_mtime_sz)
+#define NFS3_diropargs3_sz              \
+	(NFS3_nfs_fh3_sz + NFS3_filename3_sz)
+#define NFS3_GETATTR3args_sz            \
+	(NFS3_nfs_fh3_sz)
+#define NFS3_GETATTR3resok_sz           \
+	(NFS3_fattr3_sz)
+#define NFS3_GETATTR3res_sz             \
+	(NFS3_nfsstat3_sz + NFS3_GETATTR3resok_sz)
+#define NFS3_sattrguard3_sz             \
+	(XDR_bool + NFS3_nfstime3_sz)
+#define NFS3_SETATTR3args_sz            \
+	(NFS3_nfs_fh3_sz + NFS3_sattr3_sz + NFS3_sattrguard3_sz)
+#define NFS3_SETATTR3resok_sz           \
+	(NFS3_wcc_data_sz)
+#define NFS3_SETATTR3resfail_sz         \
+	(NFS3_wcc_data_sz)
+#define NFS3_SETATTR3res_sz             \
+	(NFS3_nfsstat3_sz + NFS3_SETATTR3resok_sz)
+#define NFS3_LOOKUP3args_sz             \
+	(NFS3_diropargs3_sz)
+#define NFS3_LOOKUP3resok_sz            \
+	(NFS3_nfs_fh3_sz + NFS3_post_op_attr_sz + NFS3_post_op_attr_sz)
+#define NFS3_LOOKUP3resfail_sz          \
+	(NFS3_post_op_attr_sz)
+#define NFS3_LOOKUP3res_sz              \
+	(NFS3_nfsstat3_sz + NFS3_LOOKUP3resok_sz)
+#define NFS3_ACCESS3args_sz             \
+	(NFS3_nfs_fh3_sz + NFS3_uint32_sz)
+#define NFS3_ACCESS3resok_sz            \
+	(NFS3_post_op_attr_sz + NFS3_uint32_sz)
+#define NFS3_ACCESS3resfail_sz          \
+	(NFS3_post_op_attr_sz)
+#define NFS3_ACCESS3res_sz              \
+	(NFS3_nfsstat3_sz + NFS3_ACCESS3resok_sz)
+#define NFS3_READLINK3args_sz           \
+	(NFS3_nfs_fh3_sz)
+#define NFS3_READLINK3resok_sz          \
+	(NFS3_post_op_attr_sz + NFS3_nfspath3_sz)
+#define NFS3_READLINK3resfail_sz        \
+	(NFS3_post_op_attr_sz)
+#define NFS3_READLINK3res_sz            \
+	(NFS3_nfsstat3_sz + NFS3_READLINK3resok_sz)
+#define NFS3_READ3args_sz               \
+	(NFS3_nfs_fh3_sz + NFS3_offset3_sz + NFS3_count3_sz)
+#define NFS3_READ3resok_sz              \
+	(NFS3_post_op_attr_sz + NFS3_count3_sz + XDR_bool + XDR_unsigned_int)
+#define NFS3_READ3resfail_sz            \
+	(NFS3_post_op_attr_sz)
+#define NFS3_READ3res_sz                \
+	(NFS3_nfsstat3_sz + NFS3_READ3resok_sz)
+#define NFS3_stable_how_sz              (XDR_int)
+#define NFS3_WRITE3args_sz              \
+	(NFS3_nfs_fh3_sz + NFS3_offset3_sz + NFS3_count3_sz + NFS3_stable_how_sz + XDR_unsigned_int)
+#define NFS3_WRITE3resok_sz             \
+	(NFS3_wcc_data_sz + NFS3_count3_sz + NFS3_stable_how_sz + NFS3_writeverf3_sz)
+#define NFS3_WRITE3resfail_sz           \
+	(NFS3_wcc_data_sz)
+#define NFS3_WRITE3res_sz               \
+	(NFS3_nfsstat3_sz + NFS3_WRITE3resok_sz)
+#define NFS3_createmode3_sz             (XDR_int)
+#define NFS3_createhow3_sz              \
+	(NFS3_createmode3_sz + NFS3_sattr3_sz)
+#define NFS3_CREATE3args_sz             \
+	(NFS3_diropargs3_sz + NFS3_createhow3_sz)
+#define NFS3_CREATE3resok_sz            \
+	(NFS3_post_op_fh3_sz + NFS3_post_op_attr_sz + NFS3_wcc_data_sz)
+#define NFS3_CREATE3resfail_sz          \
+	(NFS3_wcc_data_sz)
+#define NFS3_CREATE3res_sz              \
+	(NFS3_nfsstat3_sz + NFS3_CREATE3resok_sz)
+#define NFS3_MKDIR3args_sz              \
+	(NFS3_diropargs3_sz + NFS3_sattr3_sz)
+#define NFS3_MKDIR3resok_sz             \
+	(NFS3_post_op_fh3_sz + NFS3_post_op_attr_sz + NFS3_wcc_data_sz)
+#define NFS3_MKDIR3resfail_sz           \
+	(NFS3_wcc_data_sz)
+#define NFS3_MKDIR3res_sz               \
+	(NFS3_nfsstat3_sz + NFS3_MKDIR3resok_sz)
+#define NFS3_symlinkdata3_sz            \
+	(NFS3_sattr3_sz + NFS3_nfspath3_sz)
+#define NFS3_SYMLINK3args_sz            \
+	(NFS3_diropargs3_sz + NFS3_symlinkdata3_sz)
+#define NFS3_SYMLINK3resok_sz           \
+	(NFS3_post_op_fh3_sz + NFS3_post_op_attr_sz + NFS3_wcc_data_sz)
+#define NFS3_SYMLINK3resfail_sz         \
+	(NFS3_wcc_data_sz)
+#define NFS3_SYMLINK3res_sz             \
+	(NFS3_nfsstat3_sz + NFS3_SYMLINK3resok_sz)
+#define NFS3_devicedata3_sz             \
+	(NFS3_sattr3_sz + NFS3_specdata3_sz)
+#define NFS3_mknoddata3_sz              \
+	(NFS3_ftype3_sz + NFS3_devicedata3_sz)
+#define NFS3_MKNOD3args_sz              \
+	(NFS3_diropargs3_sz + NFS3_mknoddata3_sz)
+#define NFS3_MKNOD3resok_sz             \
+	(NFS3_post_op_fh3_sz + NFS3_post_op_attr_sz + NFS3_wcc_data_sz)
+#define NFS3_MKNOD3resfail_sz           \
+	(NFS3_wcc_data_sz)
+#define NFS3_MKNOD3res_sz               \
+	(NFS3_nfsstat3_sz + NFS3_MKNOD3resok_sz)
+#define NFS3_REMOVE3args_sz             \
+	(NFS3_diropargs3_sz)
+#define NFS3_REMOVE3resok_sz            \
+	(NFS3_wcc_data_sz)
+#define NFS3_REMOVE3resfail_sz          \
+	(NFS3_wcc_data_sz)
+#define NFS3_REMOVE3res_sz              \
+	(NFS3_nfsstat3_sz + NFS3_REMOVE3resok_sz)
+#define NFS3_RMDIR3args_sz              \
+	(NFS3_diropargs3_sz)
+#define NFS3_RMDIR3resok_sz             \
+	(NFS3_wcc_data_sz)
+#define NFS3_RMDIR3resfail_sz           \
+	(NFS3_wcc_data_sz)
+#define NFS3_RMDIR3res_sz               \
+	(NFS3_nfsstat3_sz + NFS3_RMDIR3resok_sz)
+#define NFS3_RENAME3args_sz             \
+	(NFS3_diropargs3_sz + NFS3_diropargs3_sz)
+#define NFS3_RENAME3resok_sz            \
+	(NFS3_wcc_data_sz + NFS3_wcc_data_sz)
+#define NFS3_RENAME3resfail_sz          \
+	(NFS3_wcc_data_sz + NFS3_wcc_data_sz)
+#define NFS3_RENAME3res_sz              \
+	(NFS3_nfsstat3_sz + NFS3_RENAME3resok_sz)
+#define NFS3_LINK3args_sz               \
+	(NFS3_nfs_fh3_sz + NFS3_diropargs3_sz)
+#define NFS3_LINK3resok_sz              \
+	(NFS3_post_op_attr_sz + NFS3_wcc_data_sz)
+#define NFS3_LINK3resfail_sz            \
+	(NFS3_post_op_attr_sz + NFS3_wcc_data_sz)
+#define NFS3_LINK3res_sz                \
+	(NFS3_nfsstat3_sz + NFS3_LINK3resok_sz)
+#define NFS3_READDIR3args_sz            \
+	(NFS3_nfs_fh3_sz + NFS3_cookie3_sz + NFS3_cookieverf3_sz + NFS3_count3_sz)
+#define NFS3_entry3_sz                  \
+	(XDR_bool + NFS3_fileid3_sz + NFS3_filename3_sz + NFS3_cookie3_sz)
+#define NFS3_dirlist3_sz                \
+	(XDR_bool + XDR_bool)
+#define NFS3_READDIR3resok_sz           \
+	(NFS3_post_op_attr_sz + NFS3_cookieverf3_sz + NFS3_dirlist3_sz)
+#define NFS3_READDIR3resfail_sz         \
+	(NFS3_post_op_attr_sz)
+#define NFS3_READDIR3res_sz             \
+	(NFS3_nfsstat3_sz + NFS3_READDIR3resok_sz)
+#define NFS3_READDIRPLUS3args_sz        \
+	(NFS3_nfs_fh3_sz + NFS3_cookie3_sz + NFS3_cookieverf3_sz + NFS3_count3_sz + NFS3_count3_sz)
+#define NFS3_entryplus3_sz              \
+	(XDR_bool + NFS3_fileid3_sz + NFS3_filename3_sz + NFS3_cookie3_sz + NFS3_post_op_attr_sz + NFS3_post_op_fh3_sz)
+#define NFS3_dirlistplus3_sz            \
+	(XDR_bool + XDR_bool)
+#define NFS3_READDIRPLUS3resok_sz       \
+	(NFS3_post_op_attr_sz + NFS3_cookieverf3_sz + NFS3_dirlistplus3_sz)
+#define NFS3_READDIRPLUS3resfail_sz     \
+	(NFS3_post_op_attr_sz)
+#define NFS3_READDIRPLUS3res_sz         \
+	(NFS3_nfsstat3_sz + NFS3_READDIRPLUS3resok_sz)
+#define NFS3_FSSTAT3args_sz             \
+	(NFS3_nfs_fh3_sz)
+#define NFS3_FSSTAT3resok_sz            \
+	(NFS3_post_op_attr_sz + NFS3_size3_sz + NFS3_size3_sz + NFS3_size3_sz + NFS3_size3_sz + NFS3_size3_sz + NFS3_size3_sz + NFS3_uint32_sz)
+#define NFS3_FSSTAT3resfail_sz          \
+	(NFS3_post_op_attr_sz)
+#define NFS3_FSSTAT3res_sz              \
+	(NFS3_nfsstat3_sz + NFS3_FSSTAT3resok_sz)
+#define NFS3_FSINFO3args_sz             \
+	(NFS3_nfs_fh3_sz)
+#define NFS3_FSINFO3resok_sz            \
+	(NFS3_post_op_attr_sz + NFS3_uint32_sz + NFS3_uint32_sz + NFS3_uint32_sz + NFS3_uint32_sz + NFS3_uint32_sz + NFS3_uint32_sz + NFS3_uint32_sz + NFS3_size3_sz + NFS3_nfstime3_sz + NFS3_uint32_sz)
+#define NFS3_FSINFO3resfail_sz          \
+	(NFS3_post_op_attr_sz)
+#define NFS3_FSINFO3res_sz              \
+	(NFS3_nfsstat3_sz + NFS3_FSINFO3resok_sz)
+#define NFS3_PATHCONF3args_sz           \
+	(NFS3_nfs_fh3_sz)
+#define NFS3_PATHCONF3resok_sz          \
+	(NFS3_post_op_attr_sz + NFS3_uint32_sz + NFS3_uint32_sz + XDR_bool + XDR_bool + XDR_bool + XDR_bool)
+#define NFS3_PATHCONF3resfail_sz        \
+	(NFS3_post_op_attr_sz)
+#define NFS3_PATHCONF3res_sz            \
+	(NFS3_nfsstat3_sz + NFS3_PATHCONF3resok_sz)
+#define NFS3_COMMIT3args_sz             \
+	(NFS3_nfs_fh3_sz + NFS3_offset3_sz + NFS3_count3_sz)
+#define NFS3_COMMIT3resok_sz            \
+	(NFS3_wcc_data_sz + NFS3_writeverf3_sz)
+#define NFS3_COMMIT3resfail_sz          \
+	(NFS3_wcc_data_sz)
+#define NFS3_COMMIT3res_sz              \
+	(NFS3_nfsstat3_sz + NFS3_COMMIT3resok_sz)
+#define NFS3_MAX_ARGS_SZ                \
+	(NFS3_MKNOD3args_sz)
+
+#endif /* _LINUX_XDRGEN_NFS3_DEF_H */
-- 
2.55.0


^ permalink raw reply related	[flat|nested] 8+ messages in thread

* [PATCH v3 04/34] NFSD: Replace nfs3.h with nfs3xdr_gen.h
  2026-10-13 12:49 [PATCH v3 02/34] Documentation: Add the RPC language description of NFSv3 Chuck Lever
  2026-10-13 12:49 ` [PATCH v3 03/34] NFSD: Add infrastructure for generating NFSv3 XDR encoders and decoders Chuck Lever
@ 2026-10-13 12:49 ` Chuck Lever
  2026-10-13 12:49 ` [PATCH v3 05/34] NFSD: Replace the nfsd3_createres macro Chuck Lever
                   ` (4 subsequent siblings)
  6 siblings, 0 replies; 8+ 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

nfs3xdr_gen.h includes a set of header files that are tool-generated
from the nfs3.x specification. The goal is to replace NFSD's XDR
infrastructure with tool-generated files which are to have better
memory safety and are less brittle to maintain.

The generated header names the NFSv3 wire constants as the
specification spells them, so point NFSD's references at the new
names: NFS3_ACCESS_* becomes ACCESS3_*, NFS3PROC_* becomes
NFSPROC3_*, and the createmode and write-stability constants shed
their prefixes entirely. Move to xdr3.h the constants the generator
does not emit: the NF3NON and NF3BAD ftype3 sentinels and the name
and path length limits, none of which appear on the wire.

Signed-off-by: Chuck Lever <cel@kernel.org>
---
 fs/nfsd/nfs2acl.c    | 26 ++++++------
 fs/nfsd/nfs3proc.c   | 96 +++++++++++++++++++++++---------------------
 fs/nfsd/nfs3xdr.c    |  9 ++---
 fs/nfsd/nfsctl.c     |  2 +-
 fs/nfsd/nfserr.h     |  2 +-
 fs/nfsd/nfsfh.c      |  2 +-
 fs/nfsd/xdr3.h       |  6 +++
 include/linux/nfs3.h |  3 --
 8 files changed, 76 insertions(+), 70 deletions(-)

diff --git a/fs/nfsd/nfs2acl.c b/fs/nfsd/nfs2acl.c
index eada1ab51415..13904e2740bf 100644
--- a/fs/nfsd/nfs2acl.c
+++ b/fs/nfsd/nfs2acl.c
@@ -22,19 +22,19 @@
  * the behavior of the two versions to diverge if needed.
  */
 static const struct nfsd_access_map nfsd2_regaccess[] = {
-	{ NFS3_ACCESS_READ,	NFSD_MAY_READ				},
-	{ NFS3_ACCESS_EXECUTE,	NFSD_MAY_EXEC				},
-	{ NFS3_ACCESS_MODIFY,	NFSD_MAY_WRITE|NFSD_MAY_TRUNC		},
-	{ NFS3_ACCESS_EXTEND,	NFSD_MAY_WRITE				},
+	{ ACCESS3_READ,		NFSD_MAY_READ				},
+	{ ACCESS3_EXECUTE,	NFSD_MAY_EXEC				},
+	{ ACCESS3_MODIFY,	NFSD_MAY_WRITE|NFSD_MAY_TRUNC		},
+	{ ACCESS3_EXTEND,	NFSD_MAY_WRITE				},
 	{ 0,			0					}
 };
 
 static const struct nfsd_access_map nfsd2_diraccess[] = {
-	{ NFS3_ACCESS_READ,	NFSD_MAY_READ				},
-	{ NFS3_ACCESS_LOOKUP,	NFSD_MAY_EXEC				},
-	{ NFS3_ACCESS_MODIFY,	NFSD_MAY_EXEC|NFSD_MAY_WRITE|NFSD_MAY_TRUNC },
-	{ NFS3_ACCESS_EXTEND,	NFSD_MAY_EXEC|NFSD_MAY_WRITE		},
-	{ NFS3_ACCESS_DELETE,	NFSD_MAY_REMOVE				},
+	{ ACCESS3_READ,		NFSD_MAY_READ				},
+	{ ACCESS3_LOOKUP,	NFSD_MAY_EXEC				},
+	{ ACCESS3_MODIFY,	NFSD_MAY_EXEC|NFSD_MAY_WRITE|NFSD_MAY_TRUNC },
+	{ ACCESS3_EXTEND,	NFSD_MAY_EXEC|NFSD_MAY_WRITE		},
+	{ ACCESS3_DELETE,	NFSD_MAY_REMOVE				},
 	{ 0,			0					}
 };
 
@@ -46,10 +46,10 @@ static const struct nfsd_access_map nfsd2_diraccess[] = {
  * filesystem checks.
  */
 static const struct nfsd_access_map nfsd2_otheraccess[] = {
-	{ NFS3_ACCESS_READ,	NFSD_MAY_READ				},
-	{ NFS3_ACCESS_EXECUTE,	NFSD_MAY_EXEC				},
-	{ NFS3_ACCESS_MODIFY,	NFSD_MAY_WRITE|NFSD_MAY_LOCAL_ACCESS	},
-	{ NFS3_ACCESS_EXTEND,	NFSD_MAY_WRITE|NFSD_MAY_LOCAL_ACCESS	},
+	{ ACCESS3_READ,		NFSD_MAY_READ				},
+	{ ACCESS3_EXECUTE,	NFSD_MAY_EXEC				},
+	{ ACCESS3_MODIFY,	NFSD_MAY_WRITE|NFSD_MAY_LOCAL_ACCESS	},
+	{ ACCESS3_EXTEND,	NFSD_MAY_WRITE|NFSD_MAY_LOCAL_ACCESS	},
 	{ 0,			0					}
 };
 
diff --git a/fs/nfsd/nfs3proc.c b/fs/nfsd/nfs3proc.c
index 60cd01b6a37d..223398ada3e3 100644
--- a/fs/nfsd/nfs3proc.c
+++ b/fs/nfsd/nfs3proc.c
@@ -9,7 +9,6 @@
 #include <linux/ext2_fs.h>
 #include <linux/magic.h>
 #include <linux/namei.h>
-#include <linux/nfs3.h>
 
 #include "cache.h"
 #include "xdr3.h"
@@ -18,8 +17,13 @@
 #include "filecache.h"
 #include "trace.h"
 
+#include "nfs3xdr_gen.h"
+
 #define NFSDDBG_FACILITY		NFSDDBG_PROC
 
+#define NFS3_FSF_DEFAULT		0x001b
+#define NFS3_FSF_BILLYBOY		0x0018
+
 static int	nfs3_ftypes[] = {
 	0,			/* NF3NON */
 	S_IFREG,		/* NF3REG */
@@ -51,19 +55,19 @@ static bool nfsd3_time_in_range(const struct iattr *iap)
 }
 
 static const struct nfsd_access_map nfsd3_regaccess[] = {
-	{ NFS3_ACCESS_READ,	NFSD_MAY_READ				},
-	{ NFS3_ACCESS_EXECUTE,	NFSD_MAY_EXEC				},
-	{ NFS3_ACCESS_MODIFY,	NFSD_MAY_WRITE|NFSD_MAY_TRUNC		},
-	{ NFS3_ACCESS_EXTEND,	NFSD_MAY_WRITE				},
+	{ ACCESS3_READ,		NFSD_MAY_READ				},
+	{ ACCESS3_EXECUTE,	NFSD_MAY_EXEC				},
+	{ ACCESS3_MODIFY,	NFSD_MAY_WRITE|NFSD_MAY_TRUNC		},
+	{ ACCESS3_EXTEND,	NFSD_MAY_WRITE				},
 	{ 0,			0					}
 };
 
 static const struct nfsd_access_map nfsd3_diraccess[] = {
-	{ NFS3_ACCESS_READ,	NFSD_MAY_READ				},
-	{ NFS3_ACCESS_LOOKUP,	NFSD_MAY_EXEC				},
-	{ NFS3_ACCESS_MODIFY,	NFSD_MAY_EXEC|NFSD_MAY_WRITE|NFSD_MAY_TRUNC },
-	{ NFS3_ACCESS_EXTEND,	NFSD_MAY_EXEC|NFSD_MAY_WRITE		},
-	{ NFS3_ACCESS_DELETE,	NFSD_MAY_REMOVE				},
+	{ ACCESS3_READ,		NFSD_MAY_READ				},
+	{ ACCESS3_LOOKUP,	NFSD_MAY_EXEC				},
+	{ ACCESS3_MODIFY,	NFSD_MAY_EXEC|NFSD_MAY_WRITE|NFSD_MAY_TRUNC },
+	{ ACCESS3_EXTEND,	NFSD_MAY_EXEC|NFSD_MAY_WRITE		},
+	{ ACCESS3_DELETE,	NFSD_MAY_REMOVE				},
 	{ 0,			0					}
 };
 
@@ -75,10 +79,10 @@ static const struct nfsd_access_map nfsd3_diraccess[] = {
  * filesystem checks.
  */
 static const struct nfsd_access_map nfsd3_otheraccess[] = {
-	{ NFS3_ACCESS_READ,	NFSD_MAY_READ				},
-	{ NFS3_ACCESS_EXECUTE,	NFSD_MAY_EXEC				},
-	{ NFS3_ACCESS_MODIFY,	NFSD_MAY_WRITE|NFSD_MAY_LOCAL_ACCESS	},
-	{ NFS3_ACCESS_EXTEND,	NFSD_MAY_WRITE|NFSD_MAY_LOCAL_ACCESS	},
+	{ ACCESS3_READ,		NFSD_MAY_READ				},
+	{ ACCESS3_EXECUTE,	NFSD_MAY_EXEC				},
+	{ ACCESS3_MODIFY,	NFSD_MAY_WRITE|NFSD_MAY_LOCAL_ACCESS	},
+	{ ACCESS3_EXTEND,	NFSD_MAY_WRITE|NFSD_MAY_LOCAL_ACCESS	},
 	{ 0,			0					}
 };
 
@@ -88,13 +92,13 @@ static const struct nfsd_access_maps nfsd3_access_maps = {
 	.other		= nfsd3_otheraccess,
 };
 
-static int nfsd3_iocb_flags(enum nfs3_stable_how how)
+static int nfsd3_iocb_flags(enum stable_how how)
 {
 	switch (how) {
-	case NFS_FILE_SYNC:
+	case FILE_SYNC:
 		/* persist data and timestamps */
 		return IOCB_DSYNC | IOCB_SYNC;
-	case NFS_DATA_SYNC:
+	case DATA_SYNC:
 		/* persist data only */
 		return IOCB_DSYNC;
 	default:
@@ -280,7 +284,7 @@ nfsd3_proc_read(struct svc_rqst *rqstp)
 	 * + 1 (xdr opaque byte count) = 26
 	 */
 	resp->count = argp->count;
-	svc_reserve_auth(rqstp, ((1 + NFS3_POST_OP_ATTR_WORDS + 3) << 2) +
+	svc_reserve_auth(rqstp, ((1 + NFS3_post_op_attr_sz + 3) << 2) +
 			 resp->count + 4);
 
 	fh_copy(&resp->fh, &argp->fh);
@@ -378,7 +382,7 @@ nfsd3_create_file(struct svc_rqst *rqstp, struct svc_fh *fhp,
 	}
 
 	exp = exp_get(fhp->fh_export);
-	if (argp->createmode == NFS3_CREATE_UNCHECKED) {
+	if (argp->createmode == UNCHECKED) {
 		/*
 		 * If name is already in dcache we need to check for mountpoints
 		 */
@@ -399,7 +403,7 @@ nfsd3_create_file(struct svc_rqst *rqstp, struct svc_fh *fhp,
 
 	v_mtime = 0;
 	v_atime = 0;
-	if (argp->createmode == NFS3_CREATE_EXCLUSIVE) {
+	if (argp->createmode == EXCLUSIVE) {
 		u32 *verifier = (u32 *)argp->verf;
 
 		/*
@@ -415,15 +419,15 @@ nfsd3_create_file(struct svc_rqst *rqstp, struct svc_fh *fhp,
 		status = nfs_ok;
 
 		switch (argp->createmode) {
-		case NFS3_CREATE_UNCHECKED:
+		case UNCHECKED:
 			if (!d_is_reg(child))
 				break;
 			iap->ia_valid &= ATTR_SIZE;
 			goto set_attr;
-		case NFS3_CREATE_GUARDED:
+		case GUARDED:
 			status = nfserr_exist;
 			break;
-		case NFS3_CREATE_EXCLUSIVE:
+		case EXCLUSIVE:
 			if (inode_get_mtime_sec(d_inode(child)) == v_mtime &&
 			    inode_get_atime_sec(d_inode(child)) == v_atime &&
 			    d_inode(child)->i_size == 0) {
@@ -450,7 +454,7 @@ nfsd3_create_file(struct svc_rqst *rqstp, struct svc_fh *fhp,
 	/* A newly created file already has a file size of zero. */
 	if ((iap->ia_valid & ATTR_SIZE) && (iap->ia_size == 0))
 		iap->ia_valid &= ~ATTR_SIZE;
-	if (argp->createmode == NFS3_CREATE_EXCLUSIVE) {
+	if (argp->createmode == EXCLUSIVE) {
 		iap->ia_valid = ATTR_MTIME | ATTR_ATIME |
 				ATTR_MTIME_SET | ATTR_ATIME_SET;
 		iap->ia_mtime.tv_sec = v_mtime;
@@ -921,7 +925,7 @@ nfsd3_proc_commit(struct svc_rqst *rqstp)
 #define WC (7+pAT)	/* WCC attributes */
 
 static const struct svc_procedure nfsd_procedures3[22] = {
-	[NFS3PROC_NULL] = {
+	[NFSPROC3_NULL] = {
 		.pc_func = nfsd3_proc_null,
 		.pc_decode = nfssvc_decode_voidarg,
 		.pc_encode = nfssvc_encode_voidres,
@@ -932,7 +936,7 @@ static const struct svc_procedure nfsd_procedures3[22] = {
 		.pc_xdrressize = ST,
 		.pc_name = "NULL",
 	},
-	[NFS3PROC_GETATTR] = {
+	[NFSPROC3_GETATTR] = {
 		.pc_func = nfsd3_proc_getattr,
 		.pc_decode = nfs3svc_decode_fhandleargs,
 		.pc_encode = nfs3svc_encode_getattrres,
@@ -944,7 +948,7 @@ static const struct svc_procedure nfsd_procedures3[22] = {
 		.pc_xdrressize = ST+AT,
 		.pc_name = "GETATTR",
 	},
-	[NFS3PROC_SETATTR] = {
+	[NFSPROC3_SETATTR] = {
 		.pc_func = nfsd3_proc_setattr,
 		.pc_decode = nfs3svc_decode_sattrargs,
 		.pc_encode = nfs3svc_encode_wccstatres,
@@ -956,7 +960,7 @@ static const struct svc_procedure nfsd_procedures3[22] = {
 		.pc_xdrressize = ST+WC,
 		.pc_name = "SETATTR",
 	},
-	[NFS3PROC_LOOKUP] = {
+	[NFSPROC3_LOOKUP] = {
 		.pc_func = nfsd3_proc_lookup,
 		.pc_decode = nfs3svc_decode_diropargs,
 		.pc_encode = nfs3svc_encode_lookupres,
@@ -968,7 +972,7 @@ static const struct svc_procedure nfsd_procedures3[22] = {
 		.pc_xdrressize = ST+FH+pAT+pAT,
 		.pc_name = "LOOKUP",
 	},
-	[NFS3PROC_ACCESS] = {
+	[NFSPROC3_ACCESS] = {
 		.pc_func = nfsd3_proc_access,
 		.pc_decode = nfs3svc_decode_accessargs,
 		.pc_encode = nfs3svc_encode_accessres,
@@ -980,7 +984,7 @@ static const struct svc_procedure nfsd_procedures3[22] = {
 		.pc_xdrressize = ST+pAT+1,
 		.pc_name = "ACCESS",
 	},
-	[NFS3PROC_READLINK] = {
+	[NFSPROC3_READLINK] = {
 		.pc_func = nfsd3_proc_readlink,
 		.pc_decode = nfs3svc_decode_fhandleargs,
 		.pc_encode = nfs3svc_encode_readlinkres,
@@ -992,7 +996,7 @@ static const struct svc_procedure nfsd_procedures3[22] = {
 		.pc_xdrressize = ST+pAT+1+NFS3_MAXPATHLEN/4,
 		.pc_name = "READLINK",
 	},
-	[NFS3PROC_READ] = {
+	[NFSPROC3_READ] = {
 		.pc_func = nfsd3_proc_read,
 		.pc_decode = nfs3svc_decode_readargs,
 		.pc_encode = nfs3svc_encode_readres,
@@ -1004,7 +1008,7 @@ static const struct svc_procedure nfsd_procedures3[22] = {
 		.pc_xdrressize = ST+pAT+4+NFSSVC_MAXBLKSIZE/4,
 		.pc_name = "READ",
 	},
-	[NFS3PROC_WRITE] = {
+	[NFSPROC3_WRITE] = {
 		.pc_func = nfsd3_proc_write,
 		.pc_decode = nfs3svc_decode_writeargs,
 		.pc_encode = nfs3svc_encode_writeres,
@@ -1016,7 +1020,7 @@ static const struct svc_procedure nfsd_procedures3[22] = {
 		.pc_xdrressize = ST+WC+4,
 		.pc_name = "WRITE",
 	},
-	[NFS3PROC_CREATE] = {
+	[NFSPROC3_CREATE] = {
 		.pc_func = nfsd3_proc_create,
 		.pc_decode = nfs3svc_decode_createargs,
 		.pc_encode = nfs3svc_encode_createres,
@@ -1028,7 +1032,7 @@ static const struct svc_procedure nfsd_procedures3[22] = {
 		.pc_xdrressize = ST+(1+FH+pAT)+WC,
 		.pc_name = "CREATE",
 	},
-	[NFS3PROC_MKDIR] = {
+	[NFSPROC3_MKDIR] = {
 		.pc_func = nfsd3_proc_mkdir,
 		.pc_decode = nfs3svc_decode_mkdirargs,
 		.pc_encode = nfs3svc_encode_createres,
@@ -1040,7 +1044,7 @@ static const struct svc_procedure nfsd_procedures3[22] = {
 		.pc_xdrressize = ST+(1+FH+pAT)+WC,
 		.pc_name = "MKDIR",
 	},
-	[NFS3PROC_SYMLINK] = {
+	[NFSPROC3_SYMLINK] = {
 		.pc_func = nfsd3_proc_symlink,
 		.pc_decode = nfs3svc_decode_symlinkargs,
 		.pc_encode = nfs3svc_encode_createres,
@@ -1052,7 +1056,7 @@ static const struct svc_procedure nfsd_procedures3[22] = {
 		.pc_xdrressize = ST+(1+FH+pAT)+WC,
 		.pc_name = "SYMLINK",
 	},
-	[NFS3PROC_MKNOD] = {
+	[NFSPROC3_MKNOD] = {
 		.pc_func = nfsd3_proc_mknod,
 		.pc_decode = nfs3svc_decode_mknodargs,
 		.pc_encode = nfs3svc_encode_createres,
@@ -1064,7 +1068,7 @@ static const struct svc_procedure nfsd_procedures3[22] = {
 		.pc_xdrressize = ST+(1+FH+pAT)+WC,
 		.pc_name = "MKNOD",
 	},
-	[NFS3PROC_REMOVE] = {
+	[NFSPROC3_REMOVE] = {
 		.pc_func = nfsd3_proc_remove,
 		.pc_decode = nfs3svc_decode_diropargs,
 		.pc_encode = nfs3svc_encode_wccstatres,
@@ -1076,7 +1080,7 @@ static const struct svc_procedure nfsd_procedures3[22] = {
 		.pc_xdrressize = ST+WC,
 		.pc_name = "REMOVE",
 	},
-	[NFS3PROC_RMDIR] = {
+	[NFSPROC3_RMDIR] = {
 		.pc_func = nfsd3_proc_rmdir,
 		.pc_decode = nfs3svc_decode_diropargs,
 		.pc_encode = nfs3svc_encode_wccstatres,
@@ -1088,7 +1092,7 @@ static const struct svc_procedure nfsd_procedures3[22] = {
 		.pc_xdrressize = ST+WC,
 		.pc_name = "RMDIR",
 	},
-	[NFS3PROC_RENAME] = {
+	[NFSPROC3_RENAME] = {
 		.pc_func = nfsd3_proc_rename,
 		.pc_decode = nfs3svc_decode_renameargs,
 		.pc_encode = nfs3svc_encode_renameres,
@@ -1100,7 +1104,7 @@ static const struct svc_procedure nfsd_procedures3[22] = {
 		.pc_xdrressize = ST+WC+WC,
 		.pc_name = "RENAME",
 	},
-	[NFS3PROC_LINK] = {
+	[NFSPROC3_LINK] = {
 		.pc_func = nfsd3_proc_link,
 		.pc_decode = nfs3svc_decode_linkargs,
 		.pc_encode = nfs3svc_encode_linkres,
@@ -1112,7 +1116,7 @@ static const struct svc_procedure nfsd_procedures3[22] = {
 		.pc_xdrressize = ST+pAT+WC,
 		.pc_name = "LINK",
 	},
-	[NFS3PROC_READDIR] = {
+	[NFSPROC3_READDIR] = {
 		.pc_func = nfsd3_proc_readdir,
 		.pc_decode = nfs3svc_decode_readdirargs,
 		.pc_encode = nfs3svc_encode_readdirres,
@@ -1123,7 +1127,7 @@ static const struct svc_procedure nfsd_procedures3[22] = {
 		.pc_cachetype = RC_NOCACHE,
 		.pc_name = "READDIR",
 	},
-	[NFS3PROC_READDIRPLUS] = {
+	[NFSPROC3_READDIRPLUS] = {
 		.pc_func = nfsd3_proc_readdirplus,
 		.pc_decode = nfs3svc_decode_readdirplusargs,
 		.pc_encode = nfs3svc_encode_readdirres,
@@ -1134,7 +1138,7 @@ static const struct svc_procedure nfsd_procedures3[22] = {
 		.pc_cachetype = RC_NOCACHE,
 		.pc_name = "READDIRPLUS",
 	},
-	[NFS3PROC_FSSTAT] = {
+	[NFSPROC3_FSSTAT] = {
 		.pc_func = nfsd3_proc_fsstat,
 		.pc_decode = nfs3svc_decode_fhandleargs,
 		.pc_encode = nfs3svc_encode_fsstatres,
@@ -1145,7 +1149,7 @@ static const struct svc_procedure nfsd_procedures3[22] = {
 		.pc_xdrressize = ST+pAT+2*6+1,
 		.pc_name = "FSSTAT",
 	},
-	[NFS3PROC_FSINFO] = {
+	[NFSPROC3_FSINFO] = {
 		.pc_func = nfsd3_proc_fsinfo,
 		.pc_decode = nfs3svc_decode_fhandleargs,
 		.pc_encode = nfs3svc_encode_fsinfores,
@@ -1156,7 +1160,7 @@ static const struct svc_procedure nfsd_procedures3[22] = {
 		.pc_xdrressize = ST+pAT+12,
 		.pc_name = "FSINFO",
 	},
-	[NFS3PROC_PATHCONF] = {
+	[NFSPROC3_PATHCONF] = {
 		.pc_func = nfsd3_proc_pathconf,
 		.pc_decode = nfs3svc_decode_fhandleargs,
 		.pc_encode = nfs3svc_encode_pathconfres,
@@ -1167,7 +1171,7 @@ static const struct svc_procedure nfsd_procedures3[22] = {
 		.pc_xdrressize = ST+pAT+6,
 		.pc_name = "PATHCONF",
 	},
-	[NFS3PROC_COMMIT] = {
+	[NFSPROC3_COMMIT] = {
 		.pc_func = nfsd3_proc_commit,
 		.pc_decode = nfs3svc_decode_commitargs,
 		.pc_encode = nfs3svc_encode_commitres,
diff --git a/fs/nfsd/nfs3xdr.c b/fs/nfsd/nfs3xdr.c
index f0895f5e32f6..d163b51684d5 100644
--- a/fs/nfsd/nfs3xdr.c
+++ b/fs/nfsd/nfs3xdr.c
@@ -8,7 +8,6 @@
  */
 
 #include <linux/namei.h>
-#include <linux/nfs3.h>
 #include <linux/sunrpc/svc_xprt.h>
 
 #include "nfsd.h"
@@ -560,7 +559,7 @@ nfs3svc_decode_writeargs(struct svc_rqst *rqstp, struct xdr_stream *xdr)
 		return false;
 	if (xdr_stream_decode_u32(xdr, &args->stable) < 0)
 		return false;
-	if (args->stable > NFS_FILE_SYNC)
+	if (args->stable > FILE_SYNC)
 		return false;
 
 	/* opaque data */
@@ -588,10 +587,10 @@ nfs3svc_decode_createargs(struct svc_rqst *rqstp, struct xdr_stream *xdr)
 	if (xdr_stream_decode_u32(xdr, &args->createmode) < 0)
 		return false;
 	switch (args->createmode) {
-	case NFS3_CREATE_UNCHECKED:
-	case NFS3_CREATE_GUARDED:
+	case UNCHECKED:
+	case GUARDED:
 		return svcxdr_decode_sattr3(rqstp, xdr, &args->attrs);
-	case NFS3_CREATE_EXCLUSIVE:
+	case EXCLUSIVE:
 		args->verf = xdr_inline_decode(xdr, NFS3_CREATEVERFSIZE);
 		if (!args->verf)
 			return false;
diff --git a/fs/nfsd/nfsctl.c b/fs/nfsd/nfsctl.c
index 5a606086b811..9327b6289904 100644
--- a/fs/nfsd/nfsctl.c
+++ b/fs/nfsd/nfsctl.c
@@ -20,7 +20,7 @@
 #include <linux/module.h>
 #include <linux/fsnotify.h>
 #include <linux/nfslocalio.h>
-#include <linux/nfs3.h>
+#include <linux/sunrpc/xdrgen/nfs3.h>
 
 #include "idmap.h"
 #include "nfsd.h"
diff --git a/fs/nfsd/nfserr.h b/fs/nfsd/nfserr.h
index 35debf1141a3..155a7fa88d52 100644
--- a/fs/nfsd/nfserr.h
+++ b/fs/nfsd/nfserr.h
@@ -11,7 +11,7 @@
 #define LINUX_NFSD_NFSERR_H
 
 #include <linux/sunrpc/xdrgen/nfs2.h>
-#include <linux/nfs3.h>
+#include <linux/sunrpc/xdrgen/nfs3.h>
 #include <linux/nfs4.h>
 
 /*
diff --git a/fs/nfsd/nfsfh.c b/fs/nfsd/nfsfh.c
index 2bd6907f443f..f1ba5a14bb85 100644
--- a/fs/nfsd/nfsfh.c
+++ b/fs/nfsd/nfsfh.c
@@ -9,7 +9,7 @@
  */
 
 #include <linux/exportfs.h>
-#include <linux/nfs3.h>
+#include <linux/sunrpc/xdrgen/nfs3.h>
 
 #include <linux/sunrpc/svcauth_gss.h>
 #include <crypto/utils.h>
diff --git a/fs/nfsd/xdr3.h b/fs/nfsd/xdr3.h
index 22272695e451..60c7fe131e2e 100644
--- a/fs/nfsd/xdr3.h
+++ b/fs/nfsd/xdr3.h
@@ -12,6 +12,12 @@
 
 #include "vfs.h"
 
+#define NF3NON		(0)
+#define NF3BAD		(8)
+
+#define NFS3_MAXNAMLEN			NAME_MAX
+#define NFS3_MAXPATHLEN			PATH_MAX
+
 struct nfsd3_sattrargs {
 	struct svc_fh		fh;
 	struct iattr		attrs;
diff --git a/include/linux/nfs3.h b/include/linux/nfs3.h
index b6539a75edea..1eb8e99390be 100644
--- a/include/linux/nfs3.h
+++ b/include/linux/nfs3.h
@@ -51,7 +51,4 @@ enum nfs3_stable_how {
 	NFS_INVALID_STABLE_HOW = -1
 };
 
-/* Number of 32bit words in post_op_attr */
-#define NFS3_POST_OP_ATTR_WORDS		22
-
 #endif /* _LINUX_NFS3_H */
-- 
2.55.0


^ permalink raw reply related	[flat|nested] 8+ messages in thread

* [PATCH v3 05/34] NFSD: Replace the nfsd3_createres macro
  2026-10-13 12:49 [PATCH v3 02/34] Documentation: Add the RPC language description of NFSv3 Chuck Lever
  2026-10-13 12:49 ` [PATCH v3 03/34] NFSD: Add infrastructure for generating NFSv3 XDR encoders and decoders Chuck Lever
  2026-10-13 12:49 ` [PATCH v3 04/34] NFSD: Replace nfs3.h with nfs3xdr_gen.h Chuck Lever
@ 2026-10-13 12:49 ` Chuck Lever
  2026-10-13 12:49 ` [PATCH v3 06/34] NFSD: Relocate the NFSv3 XDR storage union into nfs3proc.c Chuck Lever
                   ` (3 subsequent siblings)
  6 siblings, 0 replies; 8+ 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, Chuck Lever

From: Chuck Lever <chuck.lever@oracle.com>

I'm about to use the name "nfsd3_createres" for a C struct,
so let's get rid of the macro to reduce confusion.

Signed-off-by: Chuck Lever <chuck.lever@oracle.com>
---
 fs/nfsd/nfs3proc.c | 9 ++++-----
 1 file changed, 4 insertions(+), 5 deletions(-)

diff --git a/fs/nfsd/nfs3proc.c b/fs/nfsd/nfs3proc.c
index 223398ada3e3..200e084d749b 100644
--- a/fs/nfsd/nfs3proc.c
+++ b/fs/nfsd/nfs3proc.c
@@ -916,7 +916,6 @@ nfsd3_proc_commit(struct svc_rqst *rqstp)
 #define nfsd3_fhandleargs		nfsd_fhandle
 #define nfsd3_attrstatres		nfsd3_attrstat
 #define nfsd3_wccstatres		nfsd3_attrstat
-#define nfsd3_createres			nfsd3_diropres
 
 #define ST 1		/* status*/
 #define FH 17		/* filehandle with length */
@@ -1027,7 +1026,7 @@ static const struct svc_procedure nfsd_procedures3[22] = {
 		.pc_release = nfs3svc_release_fhandle2,
 		.pc_argsize = sizeof(struct nfsd3_createargs),
 		.pc_argzero = sizeof(struct nfsd3_createargs),
-		.pc_ressize = sizeof(struct nfsd3_createres),
+		.pc_ressize = sizeof(struct nfsd3_diropres),
 		.pc_cachetype = RC_REPLBUFF,
 		.pc_xdrressize = ST+(1+FH+pAT)+WC,
 		.pc_name = "CREATE",
@@ -1039,7 +1038,7 @@ static const struct svc_procedure nfsd_procedures3[22] = {
 		.pc_release = nfs3svc_release_fhandle2,
 		.pc_argsize = sizeof(struct nfsd3_mkdirargs),
 		.pc_argzero = sizeof(struct nfsd3_mkdirargs),
-		.pc_ressize = sizeof(struct nfsd3_createres),
+		.pc_ressize = sizeof(struct nfsd3_diropres),
 		.pc_cachetype = RC_REPLBUFF,
 		.pc_xdrressize = ST+(1+FH+pAT)+WC,
 		.pc_name = "MKDIR",
@@ -1051,7 +1050,7 @@ static const struct svc_procedure nfsd_procedures3[22] = {
 		.pc_release = nfs3svc_release_fhandle2,
 		.pc_argsize = sizeof(struct nfsd3_symlinkargs),
 		.pc_argzero = sizeof(struct nfsd3_symlinkargs),
-		.pc_ressize = sizeof(struct nfsd3_createres),
+		.pc_ressize = sizeof(struct nfsd3_diropres),
 		.pc_cachetype = RC_REPLBUFF,
 		.pc_xdrressize = ST+(1+FH+pAT)+WC,
 		.pc_name = "SYMLINK",
@@ -1063,7 +1062,7 @@ static const struct svc_procedure nfsd_procedures3[22] = {
 		.pc_release = nfs3svc_release_fhandle2,
 		.pc_argsize = sizeof(struct nfsd3_mknodargs),
 		.pc_argzero = sizeof(struct nfsd3_mknodargs),
-		.pc_ressize = sizeof(struct nfsd3_createres),
+		.pc_ressize = sizeof(struct nfsd3_diropres),
 		.pc_cachetype = RC_REPLBUFF,
 		.pc_xdrressize = ST+(1+FH+pAT)+WC,
 		.pc_name = "MKNOD",
-- 
2.55.0


^ permalink raw reply related	[flat|nested] 8+ messages in thread

* [PATCH v3 06/34] NFSD: Relocate the NFSv3 XDR storage union into nfs3proc.c
  2026-10-13 12:49 [PATCH v3 02/34] Documentation: Add the RPC language description of NFSv3 Chuck Lever
                   ` (2 preceding siblings ...)
  2026-10-13 12:49 ` [PATCH v3 05/34] NFSD: Replace the nfsd3_createres macro Chuck Lever
@ 2026-10-13 12:49 ` Chuck Lever
  2026-10-13 12:49 ` [PATCH v3 07/34] NFSD: Use xdrgen XDR functions for the NFSv3 NULL procedure Chuck Lever
                   ` (2 subsequent siblings)
  6 siblings, 0 replies; 8+ 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

union nfsd3_xdrstore and the NFS3_SVC_XDRSIZE macro it feeds exist
only to size service result buffers, yet xdr3.h exposes them to
every file that includes the header. This couples the NFSv3 XDR type
layout to translation units that have no stake in a service's buffer
size.

Three svc_version structures drew their vs_xdrsize from the shared
union: nfsd_version3 in nfs3proc.c and the two NFSACL programs,
nfsd_acl_version2 and nfsd_acl_version3. Give each its own storage
union next to the version structure it sizes, listing only that
program's own argument and result types, and compute vs_xdrsize from
sizeof of the local union. NFS3_SVC_XDRSIZE then has no users left
and is removed from xdr3.h.

The svc layer allocates rqstp->rq_resp at sv_xdrsize -- the largest
vs_xdrsize among a program's versions -- and clears it to the
dispatched procedure's pc_ressize, so each union must bound the
largest result its version encodes. The NFSACL programs previously
borrowed the full NFSv3 union; sizing them from their own result
types is both tighter and self-contained. This mirrors the recent
lockd conversion, which confined each NLM version's storage union to
the file that defines the version structure.

Signed-off-by: Chuck Lever <cel@kernel.org>
---
 fs/nfsd/nfs2acl.c  | 15 ++++++++++++++-
 fs/nfsd/nfs3acl.c  | 12 +++++++++++-
 fs/nfsd/nfs3proc.c | 30 +++++++++++++++++++++++++++++-
 fs/nfsd/xdr3.h     | 30 ------------------------------
 4 files changed, 54 insertions(+), 33 deletions(-)

diff --git a/fs/nfsd/nfs2acl.c b/fs/nfsd/nfs2acl.c
index 13904e2740bf..db0e260f447d 100644
--- a/fs/nfsd/nfs2acl.c
+++ b/fs/nfsd/nfs2acl.c
@@ -452,10 +452,23 @@ static const struct svc_procedure nfsd_acl_procedures2[5] = {
 	},
 };
 
+/*
+ * Storage requirements for XDR arguments and results.
+ */
+union nfsd_acl2_xdrstore {
+	struct nfsd3_getaclargs		getaclargs;
+	struct nfsd3_setaclargs		setaclargs;
+	struct nfsd3_accessargs		accessargs;
+	struct nfsd_fhandle		fhandle;
+	struct nfsd3_getaclres		getaclres;
+	struct nfsd_attrstat		attrstat;
+	struct nfsd3_accessres		accessres;
+};
+
 const struct svc_version nfsd_acl_version2 = {
 	.vs_vers	= 2,
 	.vs_nproc	= ARRAY_SIZE(nfsd_acl_procedures2),
 	.vs_proc	= nfsd_acl_procedures2,
 	.vs_dispatch	= nfsd_dispatch,
-	.vs_xdrsize	= NFS3_SVC_XDRSIZE,
+	.vs_xdrsize	= sizeof(union nfsd_acl2_xdrstore),
 };
diff --git a/fs/nfsd/nfs3acl.c b/fs/nfsd/nfs3acl.c
index 5219ec634587..324cfdd7b262 100644
--- a/fs/nfsd/nfs3acl.c
+++ b/fs/nfsd/nfs3acl.c
@@ -294,11 +294,21 @@ static const struct svc_procedure nfsd_acl_procedures3[3] = {
 	},
 };
 
+/*
+ * Storage requirements for XDR arguments and results.
+ */
+union nfsd_acl3_xdrstore {
+	struct nfsd3_getaclargs		getaclargs;
+	struct nfsd3_setaclargs		setaclargs;
+	struct nfsd3_getaclres		getaclres;
+	struct nfsd3_attrstat		attrstat;
+};
+
 const struct svc_version nfsd_acl_version3 = {
 	.vs_vers	= 3,
 	.vs_nproc	= ARRAY_SIZE(nfsd_acl_procedures3),
 	.vs_proc	= nfsd_acl_procedures3,
 	.vs_dispatch	= nfsd_dispatch,
-	.vs_xdrsize	= NFS3_SVC_XDRSIZE,
+	.vs_xdrsize	= sizeof(union nfsd_acl3_xdrstore),
 };
 
diff --git a/fs/nfsd/nfs3proc.c b/fs/nfsd/nfs3proc.c
index 200e084d749b..180601d2d139 100644
--- a/fs/nfsd/nfs3proc.c
+++ b/fs/nfsd/nfs3proc.c
@@ -1184,10 +1184,38 @@ static const struct svc_procedure nfsd_procedures3[22] = {
 	},
 };
 
+/*
+ * Storage requirements for XDR arguments and results.
+ */
+union nfsd3_xdrstore {
+	struct nfsd3_sattrargs		sattrargs;
+	struct nfsd3_diropargs		diropargs;
+	struct nfsd3_readargs		readargs;
+	struct nfsd3_writeargs		writeargs;
+	struct nfsd3_createargs		createargs;
+	struct nfsd3_renameargs		renameargs;
+	struct nfsd3_linkargs		linkargs;
+	struct nfsd3_symlinkargs	symlinkargs;
+	struct nfsd3_readdirargs	readdirargs;
+	struct nfsd3_diropres 		diropres;
+	struct nfsd3_accessres		accessres;
+	struct nfsd3_readlinkres	readlinkres;
+	struct nfsd3_readres		readres;
+	struct nfsd3_writeres		writeres;
+	struct nfsd3_renameres		renameres;
+	struct nfsd3_linkres		linkres;
+	struct nfsd3_readdirres		readdirres;
+	struct nfsd3_fsstatres		fsstatres;
+	struct nfsd3_fsinfores		fsinfores;
+	struct nfsd3_pathconfres	pathconfres;
+	struct nfsd3_commitres		commitres;
+	struct nfsd3_getaclres		getaclres;
+};
+
 const struct svc_version nfsd_version3 = {
 	.vs_vers	= 3,
 	.vs_nproc	= ARRAY_SIZE(nfsd_procedures3),
 	.vs_proc	= nfsd_procedures3,
 	.vs_dispatch	= nfsd_dispatch,
-	.vs_xdrsize	= NFS3_SVC_XDRSIZE,
+	.vs_xdrsize	= sizeof(union nfsd3_xdrstore),
 };
diff --git a/fs/nfsd/xdr3.h b/fs/nfsd/xdr3.h
index 60c7fe131e2e..35fb715e7c3f 100644
--- a/fs/nfsd/xdr3.h
+++ b/fs/nfsd/xdr3.h
@@ -243,36 +243,6 @@ struct nfsd3_fhandle_pair {
 	struct svc_fh		fh2;
 };
 
-/*
- * Storage requirements for XDR arguments and results.
- */
-union nfsd3_xdrstore {
-	struct nfsd3_sattrargs		sattrargs;
-	struct nfsd3_diropargs		diropargs;
-	struct nfsd3_readargs		readargs;
-	struct nfsd3_writeargs		writeargs;
-	struct nfsd3_createargs		createargs;
-	struct nfsd3_renameargs		renameargs;
-	struct nfsd3_linkargs		linkargs;
-	struct nfsd3_symlinkargs	symlinkargs;
-	struct nfsd3_readdirargs	readdirargs;
-	struct nfsd3_diropres 		diropres;
-	struct nfsd3_accessres		accessres;
-	struct nfsd3_readlinkres	readlinkres;
-	struct nfsd3_readres		readres;
-	struct nfsd3_writeres		writeres;
-	struct nfsd3_renameres		renameres;
-	struct nfsd3_linkres		linkres;
-	struct nfsd3_readdirres		readdirres;
-	struct nfsd3_fsstatres		fsstatres;
-	struct nfsd3_fsinfores		fsinfores;
-	struct nfsd3_pathconfres	pathconfres;
-	struct nfsd3_commitres		commitres;
-	struct nfsd3_getaclres		getaclres;
-};
-
-#define NFS3_SVC_XDRSIZE		sizeof(union nfsd3_xdrstore)
-
 bool nfs3svc_decode_fhandleargs(struct svc_rqst *rqstp, struct xdr_stream *xdr);
 bool nfs3svc_decode_sattrargs(struct svc_rqst *rqstp, struct xdr_stream *xdr);
 bool nfs3svc_decode_diropargs(struct svc_rqst *rqstp, struct xdr_stream *xdr);
-- 
2.55.0


^ permalink raw reply related	[flat|nested] 8+ messages in thread

* [PATCH v3 07/34] NFSD: Use xdrgen XDR functions for the NFSv3 NULL procedure
  2026-10-13 12:49 [PATCH v3 02/34] Documentation: Add the RPC language description of NFSv3 Chuck Lever
                   ` (3 preceding siblings ...)
  2026-10-13 12:49 ` [PATCH v3 06/34] NFSD: Relocate the NFSv3 XDR storage union into nfs3proc.c Chuck Lever
@ 2026-10-13 12:49 ` Chuck Lever
  2026-10-13 12:49 ` [PATCH v3 08/34] NFSD: Use xdrgen XDR functions for NFSv3 GETATTR procedure Chuck Lever
  2026-10-13 12:49 ` [PATCH v3 09/34] NFSD: Use xdrgen XDR functions for NFSv3 SETATTR procedure Chuck Lever
  6 siblings, 0 replies; 8+ 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

Update the NFSPROC3_NULL entry in the nfsd_procedures3 array
to use the generated XDR encoder and decoder functions
(xdrgen_svc_decode_void and xdrgen_svc_encode_void) instead of the
hand-written nfssvc_decode_voidarg and nfssvc_encode_voidres.

Also update pc_xdrressize to 0 since the NULL procedure returns
a void result with no XDR-encoded data.

Signed-off-by: Chuck Lever <cel@kernel.org>
---
 fs/nfsd/nfs3proc.c | 35 +++++++++++++++++++++++------------
 1 file changed, 23 insertions(+), 12 deletions(-)

diff --git a/fs/nfsd/nfs3proc.c b/fs/nfsd/nfs3proc.c
index 180601d2d139..0c4109bde2bb 100644
--- a/fs/nfsd/nfs3proc.c
+++ b/fs/nfsd/nfs3proc.c
@@ -130,10 +130,21 @@ static __be32 nfsd3_map_status(__be32 status)
 }
 
 /*
- * NULL call.
+ * A full specification of each of the following NFSv3 procedures is
+ * available in RFC 1813 Section 3.3.
  */
-static __be32
-nfsd3_proc_null(struct svc_rqst *rqstp)
+
+/**
+ * nfsd3_proc_null - NULL: Do nothing
+ * @rqstp: RPC transaction context
+ *
+ * Return:
+ *   %rpc_success:		RPC executed successfully
+ *
+ * RPC synopsis:
+ *   void NFSPROC3_NULL(void) = 0;
+ */
+static __be32 nfsd3_proc_null(struct svc_rqst *rqstp)
 {
 	return rpc_success;
 }
@@ -925,15 +936,15 @@ nfsd3_proc_commit(struct svc_rqst *rqstp)
 
 static const struct svc_procedure nfsd_procedures3[22] = {
 	[NFSPROC3_NULL] = {
-		.pc_func = nfsd3_proc_null,
-		.pc_decode = nfssvc_decode_voidarg,
-		.pc_encode = nfssvc_encode_voidres,
-		.pc_argsize = sizeof(struct nfsd_voidargs),
-		.pc_argzero = sizeof(struct nfsd_voidargs),
-		.pc_ressize = sizeof(struct nfsd_voidres),
-		.pc_cachetype = RC_NOCACHE,
-		.pc_xdrressize = ST,
-		.pc_name = "NULL",
+		.pc_func	= nfsd3_proc_null,
+		.pc_decode	= xdrgen_svc_decode_void,
+		.pc_encode	= xdrgen_svc_encode_void,
+		.pc_argsize	= XDR_void,
+		.pc_argzero	= 0,
+		.pc_ressize	= 0,
+		.pc_cachetype	= RC_NOCACHE,
+		.pc_xdrressize	= XDR_void,
+		.pc_name	= "NULL",
 	},
 	[NFSPROC3_GETATTR] = {
 		.pc_func = nfsd3_proc_getattr,
-- 
2.55.0


^ permalink raw reply related	[flat|nested] 8+ messages in thread

* [PATCH v3 08/34] NFSD: Use xdrgen XDR functions for NFSv3 GETATTR procedure
  2026-10-13 12:49 [PATCH v3 02/34] Documentation: Add the RPC language description of NFSv3 Chuck Lever
                   ` (4 preceding siblings ...)
  2026-10-13 12:49 ` [PATCH v3 07/34] NFSD: Use xdrgen XDR functions for the NFSv3 NULL procedure Chuck Lever
@ 2026-10-13 12:49 ` Chuck Lever
  2026-10-13 12:49 ` [PATCH v3 09/34] NFSD: Use xdrgen XDR functions for NFSv3 SETATTR procedure Chuck Lever
  6 siblings, 0 replies; 8+ 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_GETATTR entry in the nfsd_procedures3
array with an entry that dispatches the xdrgen-generated
nfs_svc_decode_GETATTR3args and nfs_svc_encode_GETATTR3res. Wrapper
structures bridge the generated xdrgen types and the legacy svc_fh
and kstat representations the NFSD VFS layer still uses. A few helper
functions are introduced which will be used here and in subsequent
patches.

The pc_argzero field is now set to zero for the NFSv3 GETATTR
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_fattr3(). Because
nfsd3_proc_getattr() now fills in the response attributes, the
fh_getattr() call is 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_getattr(). 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.

Following the precedent of commit 40ee5dc6af35 ("knfsd: 64 bit ino
support for NFS server"), lease_get_mtime() determines the file's
mtime for GETATTR (and later when filling in post-op attributes),
but is not used for WCC data. This seems odd to me; NFSv4 does not use
lease_get_mtime() at all, and not using it for WCC data seems like an
NFSv3 file's reported mtime values might vary depending on how the file
metadata is queried.

nfs3svc_encode_getattrres() no longer has any callers, so it is
removed.

Signed-off-by: Chuck Lever <cel@kernel.org>
---
 Documentation/sunrpc/xdr/nfs3.x    |   1 +
 fs/nfsd/nfs3proc.c                 | 159 ++++++++++++++++++++++++-----
 fs/nfsd/nfs3xdr.c                  |  19 ----
 fs/nfsd/nfs3xdr_gen.c              |  94 ++++++++---------
 fs/nfsd/nfs3xdr_gen.h              |   2 +-
 fs/nfsd/xdr3.h                     |   1 -
 include/linux/sunrpc/xdrgen/nfs3.h |   4 +-
 7 files changed, 185 insertions(+), 95 deletions(-)

diff --git a/Documentation/sunrpc/xdr/nfs3.x b/Documentation/sunrpc/xdr/nfs3.x
index 9feabfda94e7..1ef99ec54103 100644
--- a/Documentation/sunrpc/xdr/nfs3.x
+++ b/Documentation/sunrpc/xdr/nfs3.x
@@ -95,6 +95,7 @@ enum nfsstat3 {
 	NFS3ERR_BADTYPE		= 10007,
 	NFS3ERR_JUKEBOX		= 10008
 };
+pragma big_endian nfsstat3;
 
 enum ftype3 {
 	NF3REG		= 1,
diff --git a/fs/nfsd/nfs3proc.c b/fs/nfsd/nfs3proc.c
index 0c4109bde2bb..99bf1db913c5 100644
--- a/fs/nfsd/nfs3proc.c
+++ b/fs/nfsd/nfs3proc.c
@@ -9,7 +9,10 @@
 #include <linux/ext2_fs.h>
 #include <linux/magic.h>
 #include <linux/namei.h>
+#include <linux/sunrpc/svc.h>
 
+#include "auth.h"
+#include "nfsd.h"
 #include "cache.h"
 #include "xdr3.h"
 #include "vfs.h"
@@ -24,6 +27,26 @@
 #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
+ * to its XDR type for the RPC dispatch layer.
+ */
+
+struct GETATTR3args_wrapper {
+	struct GETATTR3args	xdrgen;
+	struct svc_fh		fh;
+};
+
+static_assert(offsetof(struct GETATTR3args_wrapper, xdrgen) == 0);
+
+struct GETATTR3res_wrapper {
+	struct GETATTR3res	xdrgen;
+	struct kstat		stat;
+};
+
+static_assert(offsetof(struct GETATTR3res_wrapper, xdrgen) == 0);
+
 static int	nfs3_ftypes[] = {
 	0,			/* NF3NON */
 	S_IFREG,		/* NF3REG */
@@ -129,6 +152,75 @@ static __be32 nfsd3_map_status(__be32 status)
 	return status;
 }
 
+/* XDR decoding has already checked that the FH length is valid */
+static __always_inline void
+nfsd3_fh3_to_svc_fh(struct svc_fh *fhp, const struct nfs_fh3 *fh3)
+{
+	fh_init(fhp, NFS3_FHSIZE);
+	fhp->fh_handle.fh_size = fh3->data.len;
+	memcpy(&fhp->fh_handle.fh_raw, fh3->data.data, fh3->data.len);
+}
+
+static __always_inline void
+nfsd3_timespec64_to_nfstime3(struct nfstime3 *dst,
+			     const struct timespec64 *src)
+{
+	dst->seconds = src->tv_sec;
+	dst->nseconds = src->tv_nsec;
+}
+
+static u32
+nfsd3_mode_to_ftype3(umode_t mode)
+{
+	switch (mode & S_IFMT) {
+	case S_IFREG:  return NF3REG;
+	case S_IFDIR:  return NF3DIR;
+	case S_IFBLK:  return NF3BLK;
+	case S_IFCHR:  return NF3CHR;
+	case S_IFLNK:  return NF3LNK;
+	case S_IFSOCK: return NF3SOCK;
+	case S_IFIFO:  return NF3FIFO;
+	}
+	return NF3REG;
+}
+
+static void
+nfsd3_stat_to_fattr3(struct svc_rqst *rqstp, struct fattr3 *fattr,
+		     const struct kstat *stat, const struct svc_fh *fhp)
+{
+	struct user_namespace *userns = nfsd_user_namespace(rqstp);
+
+	fattr->type = nfsd3_mode_to_ftype3(stat->mode);
+	fattr->mode = stat->mode & S_IALLUGO;
+	fattr->nlink = stat->nlink;
+	fattr->uid = from_kuid_munged(userns, stat->uid);
+	fattr->gid = from_kgid_munged(userns, stat->gid);
+	if (S_ISLNK(stat->mode) && stat->size > NFS3_MAXPATHLEN)
+		fattr->size = NFS3_MAXPATHLEN;
+	else
+		fattr->size = stat->size;
+	fattr->used = stat->blocks << 9;
+	fattr->rdev.specdata1 = MAJOR(stat->rdev);
+	fattr->rdev.specdata2 = MINOR(stat->rdev);
+
+	switch (fsid_source(fhp)) {
+	case FSIDSOURCE_FSID:
+		fattr->fsid = (u64)fhp->fh_export->ex_fsid;
+		break;
+	case FSIDSOURCE_UUID:
+		fattr->fsid = ((u64 *)fhp->fh_export->ex_uuid)[0];
+		fattr->fsid ^= ((u64 *)fhp->fh_export->ex_uuid)[1];
+		break;
+	default:
+		fattr->fsid = (u64)huge_encode_dev(fhp->fh_dentry->d_sb->s_dev);
+	}
+	fattr->fileid = stat->ino;
+
+	nfsd3_timespec64_to_nfstime3(&fattr->atime, &stat->atime);
+	nfsd3_timespec64_to_nfstime3(&fattr->mtime, &stat->mtime);
+	nfsd3_timespec64_to_nfstime3(&fattr->ctime, &stat->ctime);
+}
+
 /*
  * A full specification of each of the following NFSv3 procedures is
  * available in RFC 1813 Section 3.3.
@@ -149,26 +241,42 @@ static __be32 nfsd3_proc_null(struct svc_rqst *rqstp)
 	return rpc_success;
 }
 
-/*
- * Get a file's attributes
+/**
+ * nfsd3_proc_getattr - GETATTR: Get file attributes
+ * @rqstp: RPC transaction context
+ *
+ * Return:
+ *   %rpc_success:		RPC executed successfully
+ *
+ * RPC synopsis:
+ *   GETATTR3res NFSPROC3_GETATTR(GETATTR3args) = 1;
  */
-static __be32
-nfsd3_proc_getattr(struct svc_rqst *rqstp)
+static __be32 nfsd3_proc_getattr(struct svc_rqst *rqstp)
 {
-	struct nfsd_fhandle *argp = rqstp->rq_argp;
-	struct nfsd3_attrstat *resp = rqstp->rq_resp;
+	struct GETATTR3args_wrapper *argp = rqstp->rq_argp;
+	struct GETATTR3res_wrapper *resp = rqstp->rq_resp;
+	struct kstat *statp = &resp->stat;
+	struct svc_fh *fhp = &argp->fh;
 
-	trace_nfsd_vfs_getattr(rqstp, &argp->fh);
-
-	fh_copy(&resp->fh, &argp->fh);
-	resp->status = fh_verify(rqstp, &resp->fh, 0,
-				 NFSD_MAY_NOP | NFSD_MAY_BYPASS_GSS_ON_ROOT);
-	if (resp->status != nfs_ok)
+	nfsd3_fh3_to_svc_fh(fhp, &argp->xdrgen.object);
+	trace_nfsd_vfs_getattr(rqstp, fhp);
+	resp->xdrgen.status = fh_verify(rqstp, fhp, 0, NFSD_MAY_NOP |
+					NFSD_MAY_BYPASS_GSS_ON_ROOT);
+	if (resp->xdrgen.status != nfs_ok)
 		goto out;
 
-	resp->status = fh_getattr(&resp->fh, &resp->stat);
+	resp->xdrgen.status = fh_getattr(fhp, statp);
+
 out:
-	resp->status = nfsd3_map_status(resp->status);
+	if (resp->xdrgen.status == nfs_ok) {
+		lease_get_mtime(d_inode(fhp->fh_dentry), &statp->mtime);
+		nfsd3_stat_to_fattr3(rqstp, &resp->xdrgen.u.resok.obj_attributes,
+				     statp, fhp);
+	} else {
+		resp->xdrgen.status = nfsd3_map_status(resp->xdrgen.status);
+	}
+
+	fh_put(fhp);
 	return rpc_success;
 }
 
@@ -920,12 +1028,10 @@ nfsd3_proc_commit(struct svc_rqst *rqstp)
  * NFSv3 Server procedures.
  * Only the results of non-idempotent operations are cached.
  */
-#define nfs3svc_encode_attrstatres	nfs3svc_encode_attrstat
 #define nfs3svc_encode_wccstatres	nfs3svc_encode_wccstat
 #define nfsd3_mkdirargs			nfsd3_createargs
 #define nfsd3_readdirplusargs		nfsd3_readdirargs
 #define nfsd3_fhandleargs		nfsd_fhandle
-#define nfsd3_attrstatres		nfsd3_attrstat
 #define nfsd3_wccstatres		nfsd3_attrstat
 
 #define ST 1		/* status*/
@@ -947,16 +1053,15 @@ static const struct svc_procedure nfsd_procedures3[22] = {
 		.pc_name	= "NULL",
 	},
 	[NFSPROC3_GETATTR] = {
-		.pc_func = nfsd3_proc_getattr,
-		.pc_decode = nfs3svc_decode_fhandleargs,
-		.pc_encode = nfs3svc_encode_getattrres,
-		.pc_release = nfs3svc_release_fhandle,
-		.pc_argsize = sizeof(struct nfsd_fhandle),
-		.pc_argzero = sizeof(struct nfsd_fhandle),
-		.pc_ressize = sizeof(struct nfsd3_attrstatres),
-		.pc_cachetype = RC_NOCACHE,
-		.pc_xdrressize = ST+AT,
-		.pc_name = "GETATTR",
+		.pc_func	= nfsd3_proc_getattr,
+		.pc_decode	= nfs_svc_decode_GETATTR3args,
+		.pc_encode	= nfs_svc_encode_GETATTR3res,
+		.pc_argsize	= sizeof(struct GETATTR3args_wrapper),
+		.pc_argzero	= 0,
+		.pc_ressize	= sizeof(struct GETATTR3res_wrapper),
+		.pc_cachetype	= RC_NOCACHE,
+		.pc_xdrressize	= NFS3_GETATTR3res_sz,
+		.pc_name	= "GETATTR",
 	},
 	[NFSPROC3_SETATTR] = {
 		.pc_func = nfsd3_proc_setattr,
@@ -1199,6 +1304,8 @@ static const struct svc_procedure nfsd_procedures3[22] = {
  * Storage requirements for XDR arguments and results.
  */
 union nfsd3_xdrstore {
+	struct GETATTR3args_wrapper	getattrargs;
+	struct GETATTR3res_wrapper	getattrres;
 	struct nfsd3_sattrargs		sattrargs;
 	struct nfsd3_diropargs		diropargs;
 	struct nfsd3_readargs		readargs;
diff --git a/fs/nfsd/nfs3xdr.c b/fs/nfsd/nfs3xdr.c
index d163b51684d5..5802208f96b7 100644
--- a/fs/nfsd/nfs3xdr.c
+++ b/fs/nfsd/nfs3xdr.c
@@ -738,25 +738,6 @@ nfs3svc_decode_commitargs(struct svc_rqst *rqstp, struct xdr_stream *xdr)
  * XDR encode functions
  */
 
-/* GETATTR */
-bool
-nfs3svc_encode_getattrres(struct svc_rqst *rqstp, struct xdr_stream *xdr)
-{
-	struct nfsd3_attrstat *resp = rqstp->rq_resp;
-
-	if (!svcxdr_encode_nfsstat3(xdr, resp->status))
-		return false;
-	switch (resp->status) {
-	case nfs_ok:
-		lease_get_mtime(d_inode(resp->fh.fh_dentry), &resp->stat.mtime);
-		if (!svcxdr_encode_fattr3(rqstp, xdr, &resp->fh, &resp->stat))
-			return false;
-		break;
-	}
-
-	return true;
-}
-
 /* SETATTR, REMOVE, RMDIR */
 bool
 nfs3svc_encode_wccstat(struct svc_rqst *rqstp, struct xdr_stream *xdr)
diff --git a/fs/nfsd/nfs3xdr_gen.c b/fs/nfsd/nfs3xdr_gen.c
index 48b382ccfc81..e21ee0053129 100644
--- a/fs/nfsd/nfs3xdr_gen.c
+++ b/fs/nfsd/nfs3xdr_gen.c
@@ -1,7 +1,7 @@
 // SPDX-License-Identifier: GPL-2.0
 // Generated by xdrgen. Manual edits will be lost.
 // XDR specification file: ../../Documentation/sunrpc/xdr/nfs3.x
-// XDR specification modification time: Fri Jul 10 23:20:55 2026
+// XDR specification modification time: Fri Jul 10 23:21:45 2026
 
 #include <linux/sunrpc/svc.h>
 
@@ -112,10 +112,12 @@ xdrgen_decode_count3(struct xdr_stream *xdr, count3 *ptr)
 static bool __maybe_unused
 xdrgen_decode_nfsstat3(struct xdr_stream *xdr, nfsstat3 *ptr)
 {
+	__be32 raw;
 	u32 val;
 
-	if (xdr_stream_decode_u32(xdr, &val) < 0)
+	if (xdr_stream_decode_be32(xdr, &raw) < 0)
 		return false;
+	val = be32_to_cpu(raw);
 	/* Compiler may optimize to a range check for dense enums */
 	switch (val) {
 	case NFS3_OK:
@@ -151,7 +153,7 @@ xdrgen_decode_nfsstat3(struct xdr_stream *xdr, nfsstat3 *ptr)
 	default:
 		return false;
 	}
-	*ptr = val;
+	*ptr = raw;
 	return true;
 }
 
@@ -447,7 +449,7 @@ xdrgen_decode_GETATTR3res(struct xdr_stream *xdr, struct GETATTR3res *ptr)
 	if (!xdrgen_decode_nfsstat3(xdr, &ptr->status))
 		return false;
 	switch (ptr->status) {
-	case NFS3_OK:
+	case __constant_cpu_to_be32(NFS3_OK):
 		if (!xdrgen_decode_GETATTR3resok(xdr, &ptr->u.resok))
 			return false;
 		break;
@@ -503,7 +505,7 @@ xdrgen_decode_SETATTR3res(struct xdr_stream *xdr, struct SETATTR3res *ptr)
 	if (!xdrgen_decode_nfsstat3(xdr, &ptr->status))
 		return false;
 	switch (ptr->status) {
-	case NFS3_OK:
+	case __constant_cpu_to_be32(NFS3_OK):
 		if (!xdrgen_decode_SETATTR3resok(xdr, &ptr->u.resok))
 			return false;
 		break;
@@ -548,7 +550,7 @@ xdrgen_decode_LOOKUP3res(struct xdr_stream *xdr, struct LOOKUP3res *ptr)
 	if (!xdrgen_decode_nfsstat3(xdr, &ptr->status))
 		return false;
 	switch (ptr->status) {
-	case NFS3_OK:
+	case __constant_cpu_to_be32(NFS3_OK):
 		if (!xdrgen_decode_LOOKUP3resok(xdr, &ptr->u.resok))
 			return false;
 		break;
@@ -593,7 +595,7 @@ xdrgen_decode_ACCESS3res(struct xdr_stream *xdr, struct ACCESS3res *ptr)
 	if (!xdrgen_decode_nfsstat3(xdr, &ptr->status))
 		return false;
 	switch (ptr->status) {
-	case NFS3_OK:
+	case __constant_cpu_to_be32(NFS3_OK):
 		if (!xdrgen_decode_ACCESS3resok(xdr, &ptr->u.resok))
 			return false;
 		break;
@@ -636,7 +638,7 @@ xdrgen_decode_READLINK3res(struct xdr_stream *xdr, struct READLINK3res *ptr)
 	if (!xdrgen_decode_nfsstat3(xdr, &ptr->status))
 		return false;
 	switch (ptr->status) {
-	case NFS3_OK:
+	case __constant_cpu_to_be32(NFS3_OK):
 		if (!xdrgen_decode_READLINK3resok(xdr, &ptr->u.resok))
 			return false;
 		break;
@@ -687,7 +689,7 @@ xdrgen_decode_READ3res(struct xdr_stream *xdr, struct READ3res *ptr)
 	if (!xdrgen_decode_nfsstat3(xdr, &ptr->status))
 		return false;
 	switch (ptr->status) {
-	case NFS3_OK:
+	case __constant_cpu_to_be32(NFS3_OK):
 		if (!xdrgen_decode_READ3resok(xdr, &ptr->u.resok))
 			return false;
 		break;
@@ -762,7 +764,7 @@ xdrgen_decode_WRITE3res(struct xdr_stream *xdr, struct WRITE3res *ptr)
 	if (!xdrgen_decode_nfsstat3(xdr, &ptr->status))
 		return false;
 	switch (ptr->status) {
-	case NFS3_OK:
+	case __constant_cpu_to_be32(NFS3_OK):
 		if (!xdrgen_decode_WRITE3resok(xdr, &ptr->u.resok))
 			return false;
 		break;
@@ -850,7 +852,7 @@ xdrgen_decode_CREATE3res(struct xdr_stream *xdr, struct CREATE3res *ptr)
 	if (!xdrgen_decode_nfsstat3(xdr, &ptr->status))
 		return false;
 	switch (ptr->status) {
-	case NFS3_OK:
+	case __constant_cpu_to_be32(NFS3_OK):
 		if (!xdrgen_decode_CREATE3resok(xdr, &ptr->u.resok))
 			return false;
 		break;
@@ -897,7 +899,7 @@ xdrgen_decode_MKDIR3res(struct xdr_stream *xdr, struct MKDIR3res *ptr)
 	if (!xdrgen_decode_nfsstat3(xdr, &ptr->status))
 		return false;
 	switch (ptr->status) {
-	case NFS3_OK:
+	case __constant_cpu_to_be32(NFS3_OK):
 		if (!xdrgen_decode_MKDIR3resok(xdr, &ptr->u.resok))
 			return false;
 		break;
@@ -954,7 +956,7 @@ xdrgen_decode_SYMLINK3res(struct xdr_stream *xdr, struct SYMLINK3res *ptr)
 	if (!xdrgen_decode_nfsstat3(xdr, &ptr->status))
 		return false;
 	switch (ptr->status) {
-	case NFS3_OK:
+	case __constant_cpu_to_be32(NFS3_OK):
 		if (!xdrgen_decode_SYMLINK3resok(xdr, &ptr->u.resok))
 			return false;
 		break;
@@ -1033,7 +1035,7 @@ xdrgen_decode_MKNOD3res(struct xdr_stream *xdr, struct MKNOD3res *ptr)
 	if (!xdrgen_decode_nfsstat3(xdr, &ptr->status))
 		return false;
 	switch (ptr->status) {
-	case NFS3_OK:
+	case __constant_cpu_to_be32(NFS3_OK):
 		if (!xdrgen_decode_MKNOD3resok(xdr, &ptr->u.resok))
 			return false;
 		break;
@@ -1074,7 +1076,7 @@ xdrgen_decode_REMOVE3res(struct xdr_stream *xdr, struct REMOVE3res *ptr)
 	if (!xdrgen_decode_nfsstat3(xdr, &ptr->status))
 		return false;
 	switch (ptr->status) {
-	case NFS3_OK:
+	case __constant_cpu_to_be32(NFS3_OK):
 		if (!xdrgen_decode_REMOVE3resok(xdr, &ptr->u.resok))
 			return false;
 		break;
@@ -1115,7 +1117,7 @@ xdrgen_decode_RMDIR3res(struct xdr_stream *xdr, struct RMDIR3res *ptr)
 	if (!xdrgen_decode_nfsstat3(xdr, &ptr->status))
 		return false;
 	switch (ptr->status) {
-	case NFS3_OK:
+	case __constant_cpu_to_be32(NFS3_OK):
 		if (!xdrgen_decode_RMDIR3resok(xdr, &ptr->u.resok))
 			return false;
 		break;
@@ -1162,7 +1164,7 @@ xdrgen_decode_RENAME3res(struct xdr_stream *xdr, struct RENAME3res *ptr)
 	if (!xdrgen_decode_nfsstat3(xdr, &ptr->status))
 		return false;
 	switch (ptr->status) {
-	case NFS3_OK:
+	case __constant_cpu_to_be32(NFS3_OK):
 		if (!xdrgen_decode_RENAME3resok(xdr, &ptr->u.resok))
 			return false;
 		break;
@@ -1209,7 +1211,7 @@ xdrgen_decode_LINK3res(struct xdr_stream *xdr, struct LINK3res *ptr)
 	if (!xdrgen_decode_nfsstat3(xdr, &ptr->status))
 		return false;
 	switch (ptr->status) {
-	case NFS3_OK:
+	case __constant_cpu_to_be32(NFS3_OK):
 		if (!xdrgen_decode_LINK3resok(xdr, &ptr->u.resok))
 			return false;
 		break;
@@ -1289,7 +1291,7 @@ xdrgen_decode_READDIR3res(struct xdr_stream *xdr, struct READDIR3res *ptr)
 	if (!xdrgen_decode_nfsstat3(xdr, &ptr->status))
 		return false;
 	switch (ptr->status) {
-	case NFS3_OK:
+	case __constant_cpu_to_be32(NFS3_OK):
 		if (!xdrgen_decode_READDIR3resok(xdr, &ptr->u.resok))
 			return false;
 		break;
@@ -1375,7 +1377,7 @@ xdrgen_decode_READDIRPLUS3res(struct xdr_stream *xdr, struct READDIRPLUS3res *pt
 	if (!xdrgen_decode_nfsstat3(xdr, &ptr->status))
 		return false;
 	switch (ptr->status) {
-	case NFS3_OK:
+	case __constant_cpu_to_be32(NFS3_OK):
 		if (!xdrgen_decode_READDIRPLUS3resok(xdr, &ptr->u.resok))
 			return false;
 		break;
@@ -1430,7 +1432,7 @@ xdrgen_decode_FSSTAT3res(struct xdr_stream *xdr, struct FSSTAT3res *ptr)
 	if (!xdrgen_decode_nfsstat3(xdr, &ptr->status))
 		return false;
 	switch (ptr->status) {
-	case NFS3_OK:
+	case __constant_cpu_to_be32(NFS3_OK):
 		if (!xdrgen_decode_FSSTAT3resok(xdr, &ptr->u.resok))
 			return false;
 		break;
@@ -1491,7 +1493,7 @@ xdrgen_decode_FSINFO3res(struct xdr_stream *xdr, struct FSINFO3res *ptr)
 	if (!xdrgen_decode_nfsstat3(xdr, &ptr->status))
 		return false;
 	switch (ptr->status) {
-	case NFS3_OK:
+	case __constant_cpu_to_be32(NFS3_OK):
 		if (!xdrgen_decode_FSINFO3resok(xdr, &ptr->u.resok))
 			return false;
 		break;
@@ -1544,7 +1546,7 @@ xdrgen_decode_PATHCONF3res(struct xdr_stream *xdr, struct PATHCONF3res *ptr)
 	if (!xdrgen_decode_nfsstat3(xdr, &ptr->status))
 		return false;
 	switch (ptr->status) {
-	case NFS3_OK:
+	case __constant_cpu_to_be32(NFS3_OK):
 		if (!xdrgen_decode_PATHCONF3resok(xdr, &ptr->u.resok))
 			return false;
 		break;
@@ -1591,7 +1593,7 @@ xdrgen_decode_COMMIT3res(struct xdr_stream *xdr, struct COMMIT3res *ptr)
 	if (!xdrgen_decode_nfsstat3(xdr, &ptr->status))
 		return false;
 	switch (ptr->status) {
-	case NFS3_OK:
+	case __constant_cpu_to_be32(NFS3_OK):
 		if (!xdrgen_decode_COMMIT3resok(xdr, &ptr->u.resok))
 			return false;
 		break;
@@ -2043,7 +2045,7 @@ xdrgen_encode_count3(struct xdr_stream *xdr, const count3 value)
 static bool __maybe_unused
 xdrgen_encode_nfsstat3(struct xdr_stream *xdr, nfsstat3 value)
 {
-	return xdr_stream_encode_u32(xdr, value) == XDR_UNIT;
+	return xdr_stream_encode_be32(xdr, value) == XDR_UNIT;
 }
 
 static bool __maybe_unused
@@ -2308,7 +2310,7 @@ xdrgen_encode_GETATTR3res(struct xdr_stream *xdr, const struct GETATTR3res *ptr)
 	if (!xdrgen_encode_nfsstat3(xdr, ptr->status))
 		return false;
 	switch (ptr->status) {
-	case NFS3_OK:
+	case __constant_cpu_to_be32(NFS3_OK):
 		if (!xdrgen_encode_GETATTR3resok(xdr, &ptr->u.resok))
 			return false;
 		break;
@@ -2364,7 +2366,7 @@ xdrgen_encode_SETATTR3res(struct xdr_stream *xdr, const struct SETATTR3res *ptr)
 	if (!xdrgen_encode_nfsstat3(xdr, ptr->status))
 		return false;
 	switch (ptr->status) {
-	case NFS3_OK:
+	case __constant_cpu_to_be32(NFS3_OK):
 		if (!xdrgen_encode_SETATTR3resok(xdr, &ptr->u.resok))
 			return false;
 		break;
@@ -2409,7 +2411,7 @@ xdrgen_encode_LOOKUP3res(struct xdr_stream *xdr, const struct LOOKUP3res *ptr)
 	if (!xdrgen_encode_nfsstat3(xdr, ptr->status))
 		return false;
 	switch (ptr->status) {
-	case NFS3_OK:
+	case __constant_cpu_to_be32(NFS3_OK):
 		if (!xdrgen_encode_LOOKUP3resok(xdr, &ptr->u.resok))
 			return false;
 		break;
@@ -2454,7 +2456,7 @@ xdrgen_encode_ACCESS3res(struct xdr_stream *xdr, const struct ACCESS3res *ptr)
 	if (!xdrgen_encode_nfsstat3(xdr, ptr->status))
 		return false;
 	switch (ptr->status) {
-	case NFS3_OK:
+	case __constant_cpu_to_be32(NFS3_OK):
 		if (!xdrgen_encode_ACCESS3resok(xdr, &ptr->u.resok))
 			return false;
 		break;
@@ -2497,7 +2499,7 @@ xdrgen_encode_READLINK3res(struct xdr_stream *xdr, const struct READLINK3res *pt
 	if (!xdrgen_encode_nfsstat3(xdr, ptr->status))
 		return false;
 	switch (ptr->status) {
-	case NFS3_OK:
+	case __constant_cpu_to_be32(NFS3_OK):
 		if (!xdrgen_encode_READLINK3resok(xdr, &ptr->u.resok))
 			return false;
 		break;
@@ -2548,7 +2550,7 @@ xdrgen_encode_READ3res(struct xdr_stream *xdr, const struct READ3res *ptr)
 	if (!xdrgen_encode_nfsstat3(xdr, ptr->status))
 		return false;
 	switch (ptr->status) {
-	case NFS3_OK:
+	case __constant_cpu_to_be32(NFS3_OK):
 		if (!xdrgen_encode_READ3resok(xdr, &ptr->u.resok))
 			return false;
 		break;
@@ -2609,7 +2611,7 @@ xdrgen_encode_WRITE3res(struct xdr_stream *xdr, const struct WRITE3res *ptr)
 	if (!xdrgen_encode_nfsstat3(xdr, ptr->status))
 		return false;
 	switch (ptr->status) {
-	case NFS3_OK:
+	case __constant_cpu_to_be32(NFS3_OK):
 		if (!xdrgen_encode_WRITE3resok(xdr, &ptr->u.resok))
 			return false;
 		break;
@@ -2683,7 +2685,7 @@ xdrgen_encode_CREATE3res(struct xdr_stream *xdr, const struct CREATE3res *ptr)
 	if (!xdrgen_encode_nfsstat3(xdr, ptr->status))
 		return false;
 	switch (ptr->status) {
-	case NFS3_OK:
+	case __constant_cpu_to_be32(NFS3_OK):
 		if (!xdrgen_encode_CREATE3resok(xdr, &ptr->u.resok))
 			return false;
 		break;
@@ -2730,7 +2732,7 @@ xdrgen_encode_MKDIR3res(struct xdr_stream *xdr, const struct MKDIR3res *ptr)
 	if (!xdrgen_encode_nfsstat3(xdr, ptr->status))
 		return false;
 	switch (ptr->status) {
-	case NFS3_OK:
+	case __constant_cpu_to_be32(NFS3_OK):
 		if (!xdrgen_encode_MKDIR3resok(xdr, &ptr->u.resok))
 			return false;
 		break;
@@ -2787,7 +2789,7 @@ xdrgen_encode_SYMLINK3res(struct xdr_stream *xdr, const struct SYMLINK3res *ptr)
 	if (!xdrgen_encode_nfsstat3(xdr, ptr->status))
 		return false;
 	switch (ptr->status) {
-	case NFS3_OK:
+	case __constant_cpu_to_be32(NFS3_OK):
 		if (!xdrgen_encode_SYMLINK3resok(xdr, &ptr->u.resok))
 			return false;
 		break;
@@ -2866,7 +2868,7 @@ xdrgen_encode_MKNOD3res(struct xdr_stream *xdr, const struct MKNOD3res *ptr)
 	if (!xdrgen_encode_nfsstat3(xdr, ptr->status))
 		return false;
 	switch (ptr->status) {
-	case NFS3_OK:
+	case __constant_cpu_to_be32(NFS3_OK):
 		if (!xdrgen_encode_MKNOD3resok(xdr, &ptr->u.resok))
 			return false;
 		break;
@@ -2907,7 +2909,7 @@ xdrgen_encode_REMOVE3res(struct xdr_stream *xdr, const struct REMOVE3res *ptr)
 	if (!xdrgen_encode_nfsstat3(xdr, ptr->status))
 		return false;
 	switch (ptr->status) {
-	case NFS3_OK:
+	case __constant_cpu_to_be32(NFS3_OK):
 		if (!xdrgen_encode_REMOVE3resok(xdr, &ptr->u.resok))
 			return false;
 		break;
@@ -2948,7 +2950,7 @@ xdrgen_encode_RMDIR3res(struct xdr_stream *xdr, const struct RMDIR3res *ptr)
 	if (!xdrgen_encode_nfsstat3(xdr, ptr->status))
 		return false;
 	switch (ptr->status) {
-	case NFS3_OK:
+	case __constant_cpu_to_be32(NFS3_OK):
 		if (!xdrgen_encode_RMDIR3resok(xdr, &ptr->u.resok))
 			return false;
 		break;
@@ -2995,7 +2997,7 @@ xdrgen_encode_RENAME3res(struct xdr_stream *xdr, const struct RENAME3res *ptr)
 	if (!xdrgen_encode_nfsstat3(xdr, ptr->status))
 		return false;
 	switch (ptr->status) {
-	case NFS3_OK:
+	case __constant_cpu_to_be32(NFS3_OK):
 		if (!xdrgen_encode_RENAME3resok(xdr, &ptr->u.resok))
 			return false;
 		break;
@@ -3042,7 +3044,7 @@ xdrgen_encode_LINK3res(struct xdr_stream *xdr, const struct LINK3res *ptr)
 	if (!xdrgen_encode_nfsstat3(xdr, ptr->status))
 		return false;
 	switch (ptr->status) {
-	case NFS3_OK:
+	case __constant_cpu_to_be32(NFS3_OK):
 		if (!xdrgen_encode_LINK3resok(xdr, &ptr->u.resok))
 			return false;
 		break;
@@ -3120,7 +3122,7 @@ xdrgen_encode_READDIR3res(struct xdr_stream *xdr, const struct READDIR3res *ptr)
 	if (!xdrgen_encode_nfsstat3(xdr, ptr->status))
 		return false;
 	switch (ptr->status) {
-	case NFS3_OK:
+	case __constant_cpu_to_be32(NFS3_OK):
 		if (!xdrgen_encode_READDIR3resok(xdr, &ptr->u.resok))
 			return false;
 		break;
@@ -3204,7 +3206,7 @@ xdrgen_encode_READDIRPLUS3res(struct xdr_stream *xdr, const struct READDIRPLUS3r
 	if (!xdrgen_encode_nfsstat3(xdr, ptr->status))
 		return false;
 	switch (ptr->status) {
-	case NFS3_OK:
+	case __constant_cpu_to_be32(NFS3_OK):
 		if (!xdrgen_encode_READDIRPLUS3resok(xdr, &ptr->u.resok))
 			return false;
 		break;
@@ -3259,7 +3261,7 @@ xdrgen_encode_FSSTAT3res(struct xdr_stream *xdr, const struct FSSTAT3res *ptr)
 	if (!xdrgen_encode_nfsstat3(xdr, ptr->status))
 		return false;
 	switch (ptr->status) {
-	case NFS3_OK:
+	case __constant_cpu_to_be32(NFS3_OK):
 		if (!xdrgen_encode_FSSTAT3resok(xdr, &ptr->u.resok))
 			return false;
 		break;
@@ -3320,7 +3322,7 @@ xdrgen_encode_FSINFO3res(struct xdr_stream *xdr, const struct FSINFO3res *ptr)
 	if (!xdrgen_encode_nfsstat3(xdr, ptr->status))
 		return false;
 	switch (ptr->status) {
-	case NFS3_OK:
+	case __constant_cpu_to_be32(NFS3_OK):
 		if (!xdrgen_encode_FSINFO3resok(xdr, &ptr->u.resok))
 			return false;
 		break;
@@ -3373,7 +3375,7 @@ xdrgen_encode_PATHCONF3res(struct xdr_stream *xdr, const struct PATHCONF3res *pt
 	if (!xdrgen_encode_nfsstat3(xdr, ptr->status))
 		return false;
 	switch (ptr->status) {
-	case NFS3_OK:
+	case __constant_cpu_to_be32(NFS3_OK):
 		if (!xdrgen_encode_PATHCONF3resok(xdr, &ptr->u.resok))
 			return false;
 		break;
@@ -3420,7 +3422,7 @@ xdrgen_encode_COMMIT3res(struct xdr_stream *xdr, const struct COMMIT3res *ptr)
 	if (!xdrgen_encode_nfsstat3(xdr, ptr->status))
 		return false;
 	switch (ptr->status) {
-	case NFS3_OK:
+	case __constant_cpu_to_be32(NFS3_OK):
 		if (!xdrgen_encode_COMMIT3resok(xdr, &ptr->u.resok))
 			return false;
 		break;
diff --git a/fs/nfsd/nfs3xdr_gen.h b/fs/nfsd/nfs3xdr_gen.h
index e2fbb583da92..58499ca28c43 100644
--- a/fs/nfsd/nfs3xdr_gen.h
+++ b/fs/nfsd/nfs3xdr_gen.h
@@ -1,7 +1,7 @@
 /* SPDX-License-Identifier: GPL-2.0 */
 /* Generated by xdrgen. Manual edits will be lost. */
 /* XDR specification file: ../../Documentation/sunrpc/xdr/nfs3.x */
-/* XDR specification modification time: Fri Jul 10 23:20:55 2026 */
+/* XDR specification modification time: Fri Jul 10 23:21:45 2026 */
 
 #ifndef _LINUX_XDRGEN_NFS3_DECL_H
 #define _LINUX_XDRGEN_NFS3_DECL_H
diff --git a/fs/nfsd/xdr3.h b/fs/nfsd/xdr3.h
index 35fb715e7c3f..2dcd36160ced 100644
--- a/fs/nfsd/xdr3.h
+++ b/fs/nfsd/xdr3.h
@@ -259,7 +259,6 @@ 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_getattrres(struct svc_rqst *rqstp, struct xdr_stream *xdr);
 bool nfs3svc_encode_wccstat(struct svc_rqst *rqstp, struct xdr_stream *xdr);
 bool nfs3svc_encode_lookupres(struct svc_rqst *rqstp, struct xdr_stream *xdr);
 bool nfs3svc_encode_accessres(struct svc_rqst *rqstp, struct xdr_stream *xdr);
diff --git a/include/linux/sunrpc/xdrgen/nfs3.h b/include/linux/sunrpc/xdrgen/nfs3.h
index 3afc4ffb6daa..785ebff351ce 100644
--- a/include/linux/sunrpc/xdrgen/nfs3.h
+++ b/include/linux/sunrpc/xdrgen/nfs3.h
@@ -1,7 +1,7 @@
 /* SPDX-License-Identifier: GPL-2.0 */
 /* Generated by xdrgen. Manual edits will be lost. */
 /* XDR specification file: ../../Documentation/sunrpc/xdr/nfs3.x */
-/* XDR specification modification time: Fri Jul 10 23:20:55 2026 */
+/* XDR specification modification time: Fri Jul 10 23:21:45 2026 */
 
 #ifndef _LINUX_XDRGEN_NFS3_DEF_H
 #define _LINUX_XDRGEN_NFS3_DEF_H
@@ -83,7 +83,7 @@ enum nfsstat3 {
 	NFS3ERR_JUKEBOX = 10008,
 };
 
-typedef enum nfsstat3 nfsstat3;
+typedef __be32 nfsstat3;
 
 enum ftype3 {
 	NF3REG = 1,
-- 
2.55.0


^ permalink raw reply related	[flat|nested] 8+ messages in thread

* [PATCH v3 09/34] NFSD: Use xdrgen XDR functions for NFSv3 SETATTR procedure
  2026-10-13 12:49 [PATCH v3 02/34] Documentation: Add the RPC language description of NFSv3 Chuck Lever
                   ` (5 preceding siblings ...)
  2026-10-13 12:49 ` [PATCH v3 08/34] NFSD: Use xdrgen XDR functions for NFSv3 GETATTR procedure Chuck Lever
@ 2026-10-13 12:49 ` Chuck Lever
  6 siblings, 0 replies; 8+ 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_SETATTR entry in the nfsd_procedures3 array
with an entry that dispatches the xdrgen-generated
nfs_svc_decode_SETATTR3args and nfs_svc_encode_SETATTR3res. A
wrapper structure bridges the generated xdrgen argument type and
the legacy svc_fh and iattr representations the NFSD VFS layer
still uses; the result uses the generated SETATTR3res type
directly. The new nfsd3_sattr3_to_iattr() and
nfsd3_nfstime3_to_timespec64() helpers translate the decoded
sattr3 into the iattr that nfsd_setattr() consumes, and
nfsd3_fill_wcc_data() assembles the weak cache consistency data
that both the success and failure results carry.

When an operation leaves no post-op attributes saved,
svcxdr_encode_wcc_data() omits the pre-op attributes and fetches fresh
post-op attributes instead. nfsd3_fill_wcc_data() keeps that behavior
through a new nfsd3_fill_post_op_attr() helper, which later procedures
also use to fill in post-op attributes.

The pc_argzero field is now set to zero for the NFSv3 SETATTR
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_setattr() 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_setattr().
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_sattrargs() no longer has any callers, so it and
its svcxdr_decode_sattrguard3() helper are removed.

Signed-off-by: Chuck Lever <cel@kernel.org>
---
 fs/nfsd/nfs3proc.c | 211 ++++++++++++++++++++++++++++++++++++++-------
 fs/nfsd/nfs3xdr.c  |  27 ------
 fs/nfsd/xdr3.h     |   8 --
 3 files changed, 179 insertions(+), 67 deletions(-)

diff --git a/fs/nfsd/nfs3proc.c b/fs/nfsd/nfs3proc.c
index 99bf1db913c5..c86b225ff245 100644
--- a/fs/nfsd/nfs3proc.c
+++ b/fs/nfsd/nfs3proc.c
@@ -47,6 +47,15 @@ struct GETATTR3res_wrapper {
 
 static_assert(offsetof(struct GETATTR3res_wrapper, xdrgen) == 0);
 
+struct SETATTR3args_wrapper {
+	struct SETATTR3args	xdrgen;
+	struct svc_fh		fh;
+	struct iattr		iattrs;
+	struct timespec64	guard;
+};
+
+static_assert(offsetof(struct SETATTR3args_wrapper, xdrgen) == 0);
+
 static int	nfs3_ftypes[] = {
 	0,			/* NF3NON */
 	S_IFREG,		/* NF3REG */
@@ -184,6 +193,14 @@ nfsd3_mode_to_ftype3(umode_t mode)
 	return NF3REG;
 }
 
+static __always_inline void
+nfsd3_nfstime3_to_timespec64(struct timespec64 *dst,
+			     const struct nfstime3 *src)
+{
+	dst->tv_sec = src->seconds;
+	dst->tv_nsec = src->nseconds;
+}
+
 static void
 nfsd3_stat_to_fattr3(struct svc_rqst *rqstp, struct fattr3 *fattr,
 		     const struct kstat *stat, const struct svc_fh *fhp)
@@ -221,6 +238,121 @@ nfsd3_stat_to_fattr3(struct svc_rqst *rqstp, struct fattr3 *fattr,
 	nfsd3_timespec64_to_nfstime3(&fattr->ctime, &stat->ctime);
 }
 
+static void
+nfsd3_fill_post_op_attr(struct svc_rqst *rqstp, struct post_op_attr *attr,
+			struct svc_fh *fhp);
+
+static void
+nfsd3_fill_wcc_data(struct svc_rqst *rqstp, struct wcc_data *wcc,
+		    struct svc_fh *fhp)
+{
+	/* Pre-op attributes are of no use to the client without post-op ones */
+	if (!fhp->fh_post_saved) {
+		wcc->before.attributes_follow = false;
+		nfsd3_fill_post_op_attr(rqstp, &wcc->after, fhp);
+		return;
+	}
+
+	wcc->before.attributes_follow = fhp->fh_pre_saved;
+	if (fhp->fh_pre_saved) {
+		struct wcc_attr *wattr = &wcc->before.u.attributes;
+
+		wattr->size = fhp->fh_pre_size;
+		nfsd3_timespec64_to_nfstime3(&wattr->mtime, &fhp->fh_pre_mtime);
+		nfsd3_timespec64_to_nfstime3(&wattr->ctime, &fhp->fh_pre_ctime);
+	}
+
+	wcc->after.attributes_follow = true;
+	nfsd3_stat_to_fattr3(rqstp, &wcc->after.u.attributes,
+			     &fhp->fh_post_attr, fhp);
+}
+
+static void
+nfsd3_sattr3_to_iattr(struct svc_rqst *rqstp, struct iattr *iap,
+		      const struct sattr3 *sattr)
+{
+	/* trace_nfsd_vfs_setattr() records fields ia_valid leaves unset */
+	memset(iap, 0, sizeof(*iap));
+
+	if (sattr->mode.set_it) {
+		iap->ia_valid |= ATTR_MODE;
+		iap->ia_mode = sattr->mode.u.mode;
+	}
+	if (sattr->uid.set_it) {
+		iap->ia_uid = make_kuid(nfsd_user_namespace(rqstp),
+					sattr->uid.u.uid);
+		if (uid_valid(iap->ia_uid))
+			iap->ia_valid |= ATTR_UID;
+	}
+	if (sattr->gid.set_it) {
+		iap->ia_gid = make_kgid(nfsd_user_namespace(rqstp),
+					sattr->gid.u.gid);
+		if (gid_valid(iap->ia_gid))
+			iap->ia_valid |= ATTR_GID;
+	}
+	if (sattr->size.set_it) {
+		iap->ia_valid |= ATTR_SIZE;
+		iap->ia_size = sattr->size.u.size;
+	}
+	switch (sattr->atime.set_it) {
+	case DONT_CHANGE:
+		break;
+	case SET_TO_SERVER_TIME:
+		iap->ia_valid |= ATTR_ATIME;
+		break;
+	case SET_TO_CLIENT_TIME:
+		nfsd3_nfstime3_to_timespec64(&iap->ia_atime,
+					     &sattr->atime.u.atime);
+		iap->ia_valid |= ATTR_ATIME | ATTR_ATIME_SET;
+		break;
+	}
+	switch (sattr->mtime.set_it) {
+	case DONT_CHANGE:
+		break;
+	case SET_TO_SERVER_TIME:
+		iap->ia_valid |= ATTR_MTIME;
+		break;
+	case SET_TO_CLIENT_TIME:
+		nfsd3_nfstime3_to_timespec64(&iap->ia_mtime,
+					     &sattr->mtime.u.mtime);
+		iap->ia_valid |= ATTR_MTIME | ATTR_MTIME_SET;
+		break;
+	}
+}
+
+/*
+ * struct kstat is pretty huge. To reduce stack utilization, reuse @fhp's
+ * fh_post_attr field as the stat buffer passed to fh_getattr.
+ *
+ * This is safe to do as long as proc functions that need both WCC and
+ * post_op_attrs invoke nfsd3_fill_wcc_data() before invoking
+ * nfsd3_fill_post_op_attr() on the same fhp argument.
+ */
+static void
+nfsd3_fill_post_op_attr(struct svc_rqst *rqstp, struct post_op_attr *attr,
+			struct svc_fh *fhp)
+{
+	struct kstat *statp = &fhp->fh_post_attr;
+	struct dentry *dentry = fhp->fh_dentry;
+
+	/*
+	 * The inode may be NULL if the call failed because of a stale
+	 * file handle. In this case, no attributes are returned.
+	 */
+	if (fhp->fh_no_wcc || !dentry || !d_really_is_positive(dentry))
+		goto no_post_op_attrs;
+	if (fh_getattr(fhp, statp) != nfs_ok)
+		goto no_post_op_attrs;
+
+	attr->attributes_follow = true;
+	lease_get_mtime(d_inode(dentry), &statp->mtime);
+	nfsd3_stat_to_fattr3(rqstp, &attr->u.attributes, statp, fhp);
+	return;
+
+no_post_op_attrs:
+	attr->attributes_follow = false;
+}
+
 /*
  * A full specification of each of the following NFSv3 procedures is
  * available in RFC 1813 Section 3.3.
@@ -280,32 +412,47 @@ static __be32 nfsd3_proc_getattr(struct svc_rqst *rqstp)
 	return rpc_success;
 }
 
-/*
- * Set a file's attributes
+/**
+ * nfsd3_proc_setattr - SETATTR: Set file attributes
+ * @rqstp: RPC transaction context
+ *
+ * Return:
+ *   %rpc_success:		RPC executed successfully
+ *
+ * RPC synopsis:
+ *   SETATTR3res NFSPROC3_SETATTR(SETATTR3args) = 2;
  */
-static __be32
-nfsd3_proc_setattr(struct svc_rqst *rqstp)
+static __be32 nfsd3_proc_setattr(struct svc_rqst *rqstp)
 {
-	struct nfsd3_sattrargs *argp = rqstp->rq_argp;
-	struct nfsd3_attrstat *resp = rqstp->rq_resp;
-	struct nfsd_attrs attrs = {
-		.na_iattr	= &argp->attrs,
-	};
+	struct SETATTR3args_wrapper *argp = rqstp->rq_argp;
+	struct SETATTR3res *resp = rqstp->rq_resp;
 	const struct timespec64 *guardtime = NULL;
+	struct svc_fh *fhp = &argp->fh;
+	struct nfsd_attrs nattrs = {
+		.na_iattr	= &argp->iattrs,
+	};
 
-	dprintk("nfsd: SETATTR(3)  %s\n",
-				SVCFH_fmt(&argp->fh));
-
-	fh_copy(&resp->fh, &argp->fh);
-	if (!nfsd3_time_in_range(&argp->attrs)) {
-		resp->status = nfserr_inval;
-		goto out;
+	nfsd3_fh3_to_svc_fh(fhp, &argp->xdrgen.object);
+	nfsd3_sattr3_to_iattr(rqstp, &argp->iattrs, &argp->xdrgen.new_attributes);
+	if (argp->xdrgen.guard.check) {
+		nfsd3_nfstime3_to_timespec64(&argp->guard,
+					     &argp->xdrgen.guard.u.obj_ctime);
+		guardtime = &argp->guard;
 	}
-	if (argp->check_guard)
-		guardtime = &argp->guardtime;
-	resp->status = nfsd_setattr(rqstp, &resp->fh, &attrs, guardtime);
-out:
-	resp->status = nfsd3_map_status(resp->status);
+
+	if (nfsd3_time_in_range(&argp->iattrs))
+		resp->status = nfsd_setattr(rqstp, fhp, &nattrs, guardtime);
+	else
+		resp->status = nfserr_inval;
+
+	if (resp->status == nfs_ok) {
+		nfsd3_fill_wcc_data(rqstp, &resp->u.resok.obj_wcc, fhp);
+	} else {
+		resp->status = nfsd3_map_status(resp->status);
+		nfsd3_fill_wcc_data(rqstp, &resp->u.resfail.obj_wcc, fhp);
+	}
+
+	fh_put(fhp);
 	return rpc_success;
 }
 
@@ -1064,16 +1211,15 @@ static const struct svc_procedure nfsd_procedures3[22] = {
 		.pc_name	= "GETATTR",
 	},
 	[NFSPROC3_SETATTR] = {
-		.pc_func = nfsd3_proc_setattr,
-		.pc_decode = nfs3svc_decode_sattrargs,
-		.pc_encode = nfs3svc_encode_wccstatres,
-		.pc_release = nfs3svc_release_fhandle,
-		.pc_argsize = sizeof(struct nfsd3_sattrargs),
-		.pc_argzero = sizeof(struct nfsd3_sattrargs),
-		.pc_ressize = sizeof(struct nfsd3_wccstatres),
-		.pc_cachetype = RC_REPLBUFF,
-		.pc_xdrressize = ST+WC,
-		.pc_name = "SETATTR",
+		.pc_func	= nfsd3_proc_setattr,
+		.pc_decode	= nfs_svc_decode_SETATTR3args,
+		.pc_encode	= nfs_svc_encode_SETATTR3res,
+		.pc_argsize	= sizeof(struct SETATTR3args_wrapper),
+		.pc_argzero	= 0,
+		.pc_ressize	= sizeof(struct SETATTR3res),
+		.pc_cachetype	= RC_REPLBUFF,
+		.pc_xdrressize	= NFS3_SETATTR3res_sz,
+		.pc_name	= "SETATTR",
 	},
 	[NFSPROC3_LOOKUP] = {
 		.pc_func = nfsd3_proc_lookup,
@@ -1306,7 +1452,8 @@ static const struct svc_procedure nfsd_procedures3[22] = {
 union nfsd3_xdrstore {
 	struct GETATTR3args_wrapper	getattrargs;
 	struct GETATTR3res_wrapper	getattrres;
-	struct nfsd3_sattrargs		sattrargs;
+	struct SETATTR3args_wrapper	setattrargs;
+	struct SETATTR3res		setattrres;
 	struct nfsd3_diropargs		diropargs;
 	struct nfsd3_readargs		readargs;
 	struct nfsd3_writeargs		writeargs;
diff --git a/fs/nfsd/nfs3xdr.c b/fs/nfsd/nfs3xdr.c
index 5802208f96b7..eb5f3148a0ab 100644
--- a/fs/nfsd/nfs3xdr.c
+++ b/fs/nfsd/nfs3xdr.c
@@ -295,23 +295,6 @@ svcxdr_decode_sattr3(struct svc_rqst *rqstp, struct xdr_stream *xdr,
 	return true;
 }
 
-static bool
-svcxdr_decode_sattrguard3(struct xdr_stream *xdr, struct nfsd3_sattrargs *args)
-{
-	u32 check;
-
-	if (xdr_stream_decode_bool(xdr, &check) < 0)
-		return false;
-	if (check) {
-		if (!svcxdr_decode_nfstime3(xdr, &args->guardtime))
-			return false;
-		args->check_guard = 1;
-	} else
-		args->check_guard = 0;
-
-	return true;
-}
-
 static bool
 svcxdr_decode_specdata3(struct xdr_stream *xdr, struct nfsd3_mknodargs *args)
 {
@@ -499,16 +482,6 @@ nfs3svc_decode_fhandleargs(struct svc_rqst *rqstp, struct xdr_stream *xdr)
 	return svcxdr_decode_nfs_fh3(xdr, &args->fh);
 }
 
-bool
-nfs3svc_decode_sattrargs(struct svc_rqst *rqstp, struct xdr_stream *xdr)
-{
-	struct nfsd3_sattrargs *args = rqstp->rq_argp;
-
-	return svcxdr_decode_nfs_fh3(xdr, &args->fh) &&
-		svcxdr_decode_sattr3(rqstp, xdr, &args->attrs) &&
-		svcxdr_decode_sattrguard3(xdr, args);
-}
-
 bool
 nfs3svc_decode_diropargs(struct svc_rqst *rqstp, struct xdr_stream *xdr)
 {
diff --git a/fs/nfsd/xdr3.h b/fs/nfsd/xdr3.h
index 2dcd36160ced..354cff178b75 100644
--- a/fs/nfsd/xdr3.h
+++ b/fs/nfsd/xdr3.h
@@ -18,13 +18,6 @@
 #define NFS3_MAXNAMLEN			NAME_MAX
 #define NFS3_MAXPATHLEN			PATH_MAX
 
-struct nfsd3_sattrargs {
-	struct svc_fh		fh;
-	struct iattr		attrs;
-	int			check_guard;
-	struct timespec64	guardtime;
-};
-
 struct nfsd3_diropargs {
 	struct svc_fh		fh;
 	char *			name;
@@ -244,7 +237,6 @@ struct nfsd3_fhandle_pair {
 };
 
 bool nfs3svc_decode_fhandleargs(struct svc_rqst *rqstp, struct xdr_stream *xdr);
-bool nfs3svc_decode_sattrargs(struct svc_rqst *rqstp, struct xdr_stream *xdr);
 bool nfs3svc_decode_diropargs(struct svc_rqst *rqstp, struct xdr_stream *xdr);
 bool nfs3svc_decode_accessargs(struct svc_rqst *rqstp, struct xdr_stream *xdr);
 bool nfs3svc_decode_readargs(struct svc_rqst *rqstp, struct xdr_stream *xdr);
-- 
2.55.0


^ permalink raw reply related	[flat|nested] 8+ messages in thread

end of thread, other threads:[~2026-10-13 12:49 UTC | newest]

Thread overview: 8+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2026-10-13 12:49 [PATCH v3 02/34] Documentation: Add the RPC language description of NFSv3 Chuck Lever
2026-10-13 12:49 ` [PATCH v3 03/34] NFSD: Add infrastructure for generating NFSv3 XDR encoders and decoders Chuck Lever
2026-10-13 12:49 ` [PATCH v3 04/34] NFSD: Replace nfs3.h with nfs3xdr_gen.h Chuck Lever
2026-10-13 12:49 ` [PATCH v3 05/34] NFSD: Replace the nfsd3_createres macro Chuck Lever
2026-10-13 12:49 ` [PATCH v3 06/34] NFSD: Relocate the NFSv3 XDR storage union into nfs3proc.c Chuck Lever
2026-10-13 12:49 ` [PATCH v3 07/34] NFSD: Use xdrgen XDR functions for the NFSv3 NULL procedure Chuck Lever
2026-10-13 12:49 ` [PATCH v3 08/34] NFSD: Use xdrgen XDR functions for NFSv3 GETATTR procedure Chuck Lever
2026-10-13 12:49 ` [PATCH v3 09/34] NFSD: Use xdrgen XDR functions for NFSv3 SETATTR procedure Chuck Lever

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox