summaryrefslogtreecommitdiff
path: root/include
diff options
context:
space:
mode:
authorMark Brown <broonie@kernel.org>2026-10-13 12:34:28 +0100
committerMark Brown <broonie@kernel.org>2026-10-13 12:34:28 +0100
commit2c09d2499aecd278bc6a2973b79b2a58ea380815 (patch)
tree7da45e627e39b769b3f536cd10f54f497c39aae1 /include
parentffc09a9362e9811ccfc0b9e8eeafd7f25c59bbfc (diff)
parenteafb6de800781f0a1be5cdd98d150620041d8b27 (diff)
downloadlinux-next-2c09d2499aecd278bc6a2973b79b2a58ea380815.tar.gz
linux-next-2c09d2499aecd278bc6a2973b79b2a58ea380815.zip
Merge branch 'nfsd-next' of https://git.kernel.org/pub/scm/linux/kernel/git/cel/linux
Diffstat (limited to 'include')
-rw-r--r--include/linux/nfs.h55
-rw-r--r--include/linux/nfs3.h43
-rw-r--r--include/linux/nfs4.h6
-rw-r--r--include/linux/nfs_common.h4
-rw-r--r--include/linux/nfs_fh.h63
-rw-r--r--include/linux/nfs_ssc.h69
-rw-r--r--include/linux/nfsd_ssc.h38
-rw-r--r--include/linux/nfslocalio.h11
-rw-r--r--include/linux/sunrpc/clnt.h3
-rw-r--r--include/linux/sunrpc/svc.h95
-rw-r--r--include/linux/sunrpc/svc_rdma.h2
-rw-r--r--include/linux/sunrpc/svc_xprt.h5
-rw-r--r--include/linux/sunrpc/xdr.h1
-rw-r--r--include/linux/sunrpc/xdrgen/_defs.h34
-rw-r--r--include/linux/sunrpc/xdrgen/nfs2.h298
-rw-r--r--include/trace/misc/nfs.h13
-rw-r--r--include/uapi/linux/nfsd_netlink.h20
17 files changed, 629 insertions, 131 deletions
diff --git a/include/linux/nfs.h b/include/linux/nfs.h
index 0906a0b40c6a..8c2818db43c5 100644
--- a/include/linux/nfs.h
+++ b/include/linux/nfs.h
@@ -11,59 +11,8 @@
#include <linux/cred.h>
#include <linux/sunrpc/auth.h>
#include <linux/sunrpc/msg_prot.h>
-#include <linux/string.h>
-#include <linux/crc32.h>
-#include <uapi/linux/nfs.h>
-
-/* The LOCALIO program is entirely private to Linux and is
- * NOT part of the uapi.
- */
-#define NFS_LOCALIO_PROGRAM 400122
-#define LOCALIOPROC_NULL 0
-#define LOCALIOPROC_UUID_IS_LOCAL 1
-
-/*
- * This is the kernel NFS client file handle representation
- */
-#define NFS_MAXFHSIZE 128
-struct nfs_fh {
- unsigned short size;
- unsigned char data[NFS_MAXFHSIZE];
-};
-
-/*
- * Returns a zero iff the size and data fields match.
- * Checks only "size" bytes in the data field.
- */
-static inline int nfs_compare_fh(const struct nfs_fh *a, const struct nfs_fh *b)
-{
- return a->size != b->size || memcmp(a->data, b->data, a->size) != 0;
-}
-
-static inline void nfs_copy_fh(struct nfs_fh *target, const struct nfs_fh *source)
-{
- target->size = source->size;
- memcpy(target->data, source->data, source->size);
-}
-
-enum nfs3_stable_how {
- NFS_UNSTABLE = 0,
- NFS_DATA_SYNC = 1,
- NFS_FILE_SYNC = 2,
+#include <linux/nfs_fh.h>
- /* used by direct.c to mark verf as invalid */
- NFS_INVALID_STABLE_HOW = -1
-};
+#include <uapi/linux/nfs.h>
-/**
- * nfs_fhandle_hash - calculate the crc32 hash for the filehandle
- * @fh - pointer to filehandle
- *
- * returns a crc32 hash for the filehandle that is compatible with
- * the one displayed by "wireshark".
- */
-static inline u32 nfs_fhandle_hash(const struct nfs_fh *fh)
-{
- return ~crc32_le(0xFFFFFFFF, &fh->data[0], fh->size);
-}
#endif /* _LINUX_NFS_H */
diff --git a/include/linux/nfs3.h b/include/linux/nfs3.h
index 404b8f724fc9..b6539a75edea 100644
--- a/include/linux/nfs3.h
+++ b/include/linux/nfs3.h
@@ -7,6 +7,49 @@
#include <uapi/linux/nfs3.h>
+/*
+ * NFSv3 error status values.
+ * See RFC 1813 Section 2.5
+ */
+enum {
+ 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 nfs3_stable_how {
+ NFS_UNSTABLE = 0,
+ NFS_DATA_SYNC = 1,
+ NFS_FILE_SYNC = 2,
+
+ /* used to mark verf as invalid */
+ NFS_INVALID_STABLE_HOW = -1
+};
/* Number of 32bit words in post_op_attr */
#define NFS3_POST_OP_ATTR_WORDS 22
diff --git a/include/linux/nfs4.h b/include/linux/nfs4.h
index 1a3981c26b23..41b7cdcc674f 100644
--- a/include/linux/nfs4.h
+++ b/include/linux/nfs4.h
@@ -263,6 +263,12 @@ enum why_no_delegation4 { /* new to v4.1 */
WND4_IS_DIR = 8,
};
+enum stable_how4 {
+ UNSTABLE4 = 0,
+ DATA_SYNC4 = 1,
+ FILE_SYNC4 = 2,
+};
+
enum lock_type4 {
NFS4_UNLOCK_LT = 0,
NFS4_READ_LT = 1,
diff --git a/include/linux/nfs_common.h b/include/linux/nfs_common.h
index a541c3a02887..88dccd8564cf 100644
--- a/include/linux/nfs_common.h
+++ b/include/linux/nfs_common.h
@@ -6,11 +6,11 @@
#define _LINUX_NFS_COMMON_H
#include <linux/errno.h>
-#include <uapi/linux/nfs.h>
+#include <linux/types.h>
/* Mapping from NFS error code to "errno" error code. */
-int nfs_stat_to_errno(enum nfs_stat status);
+int nfs_stat_to_errno(int status);
int nfs4_stat_to_errno(int stat);
__u32 nfs_localio_errno_to_nfs4_stat(int errno);
diff --git a/include/linux/nfs_fh.h b/include/linux/nfs_fh.h
new file mode 100644
index 000000000000..49dfc5ec60fe
--- /dev/null
+++ b/include/linux/nfs_fh.h
@@ -0,0 +1,63 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+/*
+ * struct nfs_fh is an NFS version-agnostic data structure that
+ * stores an NFS file handle. It is also commonly used in NFS
+ * related APIs.
+ */
+#ifndef _LINUX_NFS_FH_H
+#define _LINUX_NFS_FH_H
+
+#include <linux/types.h>
+#include <linux/string.h>
+#include <linux/crc32.h>
+
+/*
+ * The largest file handle size today is an NFSv4 file handle,
+ * which can be up to 128 octets long.
+ */
+#define NFS_MAXFHSIZE 128
+struct nfs_fh {
+ unsigned short size;
+ unsigned char data[NFS_MAXFHSIZE];
+};
+
+/**
+ * nfs_compare_fh - Compare two NFS file handles
+ * @a: An NFS file handle to be compared
+ * @b: An NFS file handle to be compared
+ *
+ * Checks only "size" bytes in each data field.
+ *
+ * Return: %false if the two file handles are equal, otherwise %true
+ */
+static inline bool nfs_compare_fh(const struct nfs_fh *a, const struct nfs_fh *b)
+{
+ return a->size != b->size || memcmp(a->data, b->data, a->size) != 0;
+}
+
+/**
+ * nfs_copy_fh - Copy an NFS file handle
+ * @target: Destination file handle
+ * @source: Source file handle
+ *
+ * Copies source->size bytes of file handle data into target.
+ */
+static inline void nfs_copy_fh(struct nfs_fh *target, const struct nfs_fh *source)
+{
+ target->size = source->size;
+ memcpy(target->data, source->data, source->size);
+}
+
+/**
+ * nfs_fhandle_hash - Calculate the crc32 hash for the filehandle
+ * @fh: An NFS file handle to hash
+ *
+ * Return: a crc32 hash for the filehandle that is compatible with
+ * the one displayed by "wireshark"
+ */
+static inline u32 nfs_fhandle_hash(const struct nfs_fh *fh)
+{
+ return ~crc32_le(0xFFFFFFFF, &fh->data[0], fh->size);
+}
+
+#endif /* _LINUX_NFS_FH_H */
diff --git a/include/linux/nfs_ssc.h b/include/linux/nfs_ssc.h
index 22265b1ff080..c199ea23e7eb 100644
--- a/include/linux/nfs_ssc.h
+++ b/include/linux/nfs_ssc.h
@@ -2,80 +2,33 @@
/*
* include/linux/nfs_ssc.h
*
+ * NFSv4.2 server-to-server copy, NFS client side APIs
+ *
* Author: Dai Ngo <dai.ngo@oracle.com>
*
* Copyright (c) 2020, Oracle and/or its affiliates.
*/
-#include <linux/nfs_fs.h>
-#include <linux/sunrpc/svc.h>
+#ifndef _LINUX_NFS_SSC_H
+#define _LINUX_NFS_SSC_H
-extern struct nfs_ssc_client_ops_tbl nfs_ssc_client_tbl;
+#include <linux/nfs_fh.h>
+#include <linux/nfs4.h>
+
+struct file;
+struct vfsmount;
-/*
- * NFS_V4
- */
struct nfs4_ssc_client_ops {
+ struct module *owner;
struct file *(*sco_open)(struct vfsmount *ss_mnt,
struct nfs_fh *src_fh, nfs4_stateid *stateid);
void (*sco_close)(struct file *filep);
};
-/*
- * NFS_FS
- */
-struct nfs_ssc_client_ops {
- void (*sco_sb_deactive)(struct super_block *sb);
-};
-
-struct nfs_ssc_client_ops_tbl {
- const struct nfs4_ssc_client_ops *ssc_nfs4_ops;
- const struct nfs_ssc_client_ops *ssc_nfs_ops;
-};
-
extern void nfs42_ssc_register_ops(void);
extern void nfs42_ssc_unregister_ops(void);
extern void nfs42_ssc_register(const struct nfs4_ssc_client_ops *ops);
extern void nfs42_ssc_unregister(const struct nfs4_ssc_client_ops *ops);
-#ifdef CONFIG_NFSD_V4_2_INTER_SSC
-static inline struct file *nfs42_ssc_open(struct vfsmount *ss_mnt,
- struct nfs_fh *src_fh, nfs4_stateid *stateid)
-{
- if (nfs_ssc_client_tbl.ssc_nfs4_ops)
- return (*nfs_ssc_client_tbl.ssc_nfs4_ops->sco_open)(ss_mnt, src_fh, stateid);
- return ERR_PTR(-EIO);
-}
-
-static inline void nfs42_ssc_close(struct file *filep)
-{
- if (nfs_ssc_client_tbl.ssc_nfs4_ops)
- (*nfs_ssc_client_tbl.ssc_nfs4_ops->sco_close)(filep);
-}
-#endif
-
-struct nfsd4_ssc_umount_item {
- struct list_head nsui_list;
- bool nsui_busy;
- /*
- * nsui_refcnt inited to 2, 1 on list and 1 for consumer. Entry
- * is removed when refcnt drops to 1 and nsui_expire expires.
- */
- refcount_t nsui_refcnt;
- unsigned long nsui_expire;
- struct vfsmount *nsui_vfsmount;
- char nsui_ipaddr[RPC_MAX_ADDRBUFLEN + 1];
-};
-
-/*
- * NFS_FS
- */
-extern void nfs_ssc_register(const struct nfs_ssc_client_ops *ops);
-extern void nfs_ssc_unregister(const struct nfs_ssc_client_ops *ops);
-
-static inline void nfs_do_sb_deactive(struct super_block *sb)
-{
- if (nfs_ssc_client_tbl.ssc_nfs_ops)
- (*nfs_ssc_client_tbl.ssc_nfs_ops->sco_sb_deactive)(sb);
-}
+#endif /* _LINUX_NFS_SSC_H */
diff --git a/include/linux/nfsd_ssc.h b/include/linux/nfsd_ssc.h
new file mode 100644
index 000000000000..7001410f01c2
--- /dev/null
+++ b/include/linux/nfsd_ssc.h
@@ -0,0 +1,38 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+/*
+ * include/linux/nfsd_ssc.h
+ *
+ * NFSv4.2 server-to-server copy, NFS server side APIs
+ *
+ * Author: Dai Ngo <dai.ngo@oracle.com>
+ *
+ * Copyright (c) 2020, Oracle and/or its affiliates.
+ */
+
+#ifndef _LINUX_NFSD_SSC_H
+#define _LINUX_NFSD_SSC_H
+
+#include <linux/nfs_fh.h>
+#include <linux/nfs4.h>
+
+struct file;
+struct vfsmount;
+
+#if IS_ENABLED(CONFIG_NFS_V4_2_SSC_HELPER)
+struct file *nfsd42_ssc_open(struct vfsmount *ss_mnt, struct nfs_fh *src_fh,
+ nfs4_stateid *stateid);
+void nfsd42_ssc_close(struct file *filp);
+#else
+static inline struct file *nfsd42_ssc_open(struct vfsmount *ss_mnt,
+ struct nfs_fh *src_fh,
+ nfs4_stateid *stateid)
+{
+ return ERR_PTR(-EIO);
+}
+
+static inline void nfsd42_ssc_close(struct file *filp)
+{
+}
+#endif
+
+#endif /* _LINUX_NFSD_SSC_H */
diff --git a/include/linux/nfslocalio.h b/include/linux/nfslocalio.h
index 3d91043254e6..8ce4d978a636 100644
--- a/include/linux/nfslocalio.h
+++ b/include/linux/nfslocalio.h
@@ -13,9 +13,18 @@
#include <linux/uuid.h>
#include <linux/sunrpc/clnt.h>
#include <linux/sunrpc/svcauth.h>
-#include <linux/nfs.h>
+#include <linux/nfs_fh.h>
+
#include <net/net_namespace.h>
+/*
+ * The LOCALIO program is entirely private to Linux and is NOT part of
+ * the uapi.
+ */
+#define NFS_LOCALIO_PROGRAM 400122
+#define LOCALIOPROC_NULL 0
+#define LOCALIOPROC_UUID_IS_LOCAL 1
+
struct nfs_client;
struct nfs_file_localio;
diff --git a/include/linux/sunrpc/clnt.h b/include/linux/sunrpc/clnt.h
index 3c2b8c355ab3..30344c0d6a9d 100644
--- a/include/linux/sunrpc/clnt.h
+++ b/include/linux/sunrpc/clnt.h
@@ -199,7 +199,8 @@ struct rpc_xprt *rpc_task_get_xprt(struct rpc_clnt *clnt,
int rpcb_create_local(struct net *);
void rpcb_put_local(struct net *);
-int rpcb_register(struct net *, u32, u32, int, unsigned short);
+int rpcb_register(struct net *net, u32 prog, u32 vers, int prot,
+ unsigned short port);
int rpcb_v4_register(struct net *net, const u32 program,
const u32 version,
const struct sockaddr *address,
diff --git a/include/linux/sunrpc/svc.h b/include/linux/sunrpc/svc.h
index 2db1b9ec5658..cfb5ab17dabd 100644
--- a/include/linux/sunrpc/svc.h
+++ b/include/linux/sunrpc/svc.h
@@ -78,6 +78,7 @@ struct svc_serv {
unsigned int sv_max_payload; /* datagram payload size */
unsigned int sv_max_mesg; /* max_payload + 1 page for overheads */
unsigned int sv_xdrsize; /* XDR buffer size */
+ atomic_t sv_rpcb_failures; /* unanswered rpcbind calls */
struct list_head sv_permsocks; /* all permanent sockets */
struct list_head sv_tempsocks; /* all temporary sockets */
int sv_tmpcnt; /* count of temporary "valid" sockets */
@@ -86,6 +87,8 @@ struct svc_serv {
char * sv_name; /* service name */
bool sv_is_pooled; /* is this a pooled service? */
+ /* Caller registers with rpcbind itself. Set before svc_bind(). */
+ bool sv_no_rpcbind;
struct svc_pool * sv_pools; /* array of thread pools */
int (*sv_threadfn)(void *data);
@@ -451,6 +454,7 @@ int sunrpc_set_pool_mode(const char *val);
int sunrpc_get_pool_mode(char *val, size_t size);
void svc_rpcb_cleanup(struct svc_serv *serv, struct net *net);
int svc_bind(struct svc_serv *serv, struct net *net);
+unsigned int svc_rpcb_failure_count(struct svc_serv *serv);
struct svc_serv *svc_create(struct svc_program *, unsigned int,
int (*threadfn)(void *data));
bool svc_rqst_replace_page(struct svc_rqst *rqstp,
@@ -471,8 +475,9 @@ unsigned int svc_serv_maxthreads(const struct svc_serv *serv);
int svc_pool_stats_open(struct svc_info *si, struct file *file);
void svc_process(struct svc_rqst *rqstp);
void svc_process_bc(struct rpc_rqst *req, struct svc_rqst *rqstp);
-int svc_register(const struct svc_serv *, struct net *, const int,
- const unsigned short, const unsigned short);
+int svc_register(struct svc_serv *serv, struct net *net,
+ const int family, const unsigned short proto,
+ const unsigned short port);
void svc_wake_up(struct svc_serv *);
void svc_reserve(struct svc_rqst *rqstp, int space);
@@ -529,6 +534,8 @@ static inline void svc_reserve_auth(struct svc_rqst *rqstp, int space)
* svcxdr_init_decode - Prepare an xdr_stream for Call decoding
* @rqstp: controlling server RPC transaction context
*
+ * The stream records @rqstp, so a codec running on it reaches the
+ * transaction with svcxdr_rqst().
*/
static inline void svcxdr_init_decode(struct svc_rqst *rqstp)
{
@@ -541,12 +548,15 @@ static inline void svcxdr_init_decode(struct svc_rqst *rqstp)
xdr_init_decode(xdr, buf, argv->iov_base, NULL);
xdr_set_scratch_folio(xdr, rqstp->rq_scratch_folio);
+ xdr->xdrgen_ctx = rqstp;
}
/**
* svcxdr_init_encode - Prepare an xdr_stream for svc Reply encoding
* @rqstp: controlling server RPC transaction context
*
+ * The stream records @rqstp, so a codec running on it reaches the
+ * transaction with svcxdr_rqst().
*/
static inline void svcxdr_init_encode(struct svc_rqst *rqstp)
{
@@ -564,6 +574,19 @@ static inline void svcxdr_init_encode(struct svc_rqst *rqstp)
xdr->page_ptr = buf->pages - 1;
buf->buflen = PAGE_SIZE * (rqstp->rq_page_end - buf->pages);
xdr->rqst = NULL;
+ xdr->xdrgen_ctx = rqstp;
+}
+
+/**
+ * svcxdr_rqst - Retrieve the transaction bound to an xdr_stream
+ * @xdr: stream to query
+ *
+ * Return: the controlling svc_rqst when @xdr was initialized by
+ * svcxdr_init_decode() or svcxdr_init_encode(), otherwise NULL.
+ */
+static inline struct svc_rqst *svcxdr_rqst(struct xdr_stream *xdr)
+{
+ return xdr->xdrgen_ctx;
}
/**
@@ -588,6 +611,74 @@ static inline void svcxdr_encode_opaque_pages(struct svc_rqst *rqstp,
}
/**
+ * svcxdr_encode_opaque_payload - Encode a page-resident opaque data item
+ * @xdr: xdr_stream to be updated
+ * @len: number of octets of content in the data item
+ *
+ * Context: Process context. @xdr must have been initialized by
+ * svcxdr_init_encode() and still be positioned in the reply
+ * head.
+ *
+ * Return:
+ * %true: Success
+ * %false: The reply head cannot hold the length prefix and XDR
+ * padding, or the transport could not accommodate the result payload
+ */
+static inline bool svcxdr_encode_opaque_payload(struct xdr_stream *xdr, u32 len)
+{
+ struct svc_rqst *rqstp = svcxdr_rqst(xdr);
+ struct xdr_buf *buf = xdr->buf;
+
+ /*
+ * The length prefix and any pad word must land in the reply
+ * head. A prefix that spills into the first Reply page lands
+ * on the payload itself, and xdr_write_pages() BUGs when the
+ * pad word does not fit.
+ */
+ if ((xdr->end - xdr->p) * XDR_UNIT < XDR_UNIT + xdr_pad_size(len))
+ return false;
+ if (xdr_stream_encode_u32(xdr, len) < 0)
+ return false;
+ svcxdr_encode_opaque_pages(rqstp, xdr, buf->pages, buf->page_base, len);
+ if (svc_encode_result_payload(rqstp, buf->head->iov_len, len) < 0)
+ return false;
+ return true;
+}
+
+/**
+ * svcxdr_decode_opaque_payload - Decode a page-resident opaque data item
+ * @xdr: xdr_stream to be decoded
+ * @payload: on success, describes the octets of the data item's content
+ * @maxlen: largest data item length the caller will accept, or zero for
+ * no limit
+ *
+ * A bulk payload such as the content of an NFS WRITE request resides in
+ * the pages of the Receive buffer. Rather than copy it, set @payload to
+ * describe the item's content in place.
+ *
+ * Context: Process context. @xdr must have been initialized by
+ * svcxdr_init_decode().
+ *
+ * Return:
+ * %true: @payload describes the item in place and @xdr has advanced
+ * past it
+ * %false: a bounds error occurred, or the length prefix exceeds
+ * @maxlen; @payload is undefined
+ */
+static inline bool svcxdr_decode_opaque_payload(struct xdr_stream *xdr,
+ struct xdr_buf *payload,
+ u32 maxlen)
+{
+ u32 len;
+
+ if (xdr_stream_decode_u32(xdr, &len) < 0)
+ return false;
+ if (maxlen && len > maxlen)
+ return false;
+ return xdr_stream_subsegment(xdr, payload, len);
+}
+
+/**
* svcxdr_set_auth_slack -
* @rqstp: RPC transaction
* @slack: buffer space to reserve for the transaction's security flavor
diff --git a/include/linux/sunrpc/svc_rdma.h b/include/linux/sunrpc/svc_rdma.h
index 76aa5ec4ab40..5ccb13bf906f 100644
--- a/include/linux/sunrpc/svc_rdma.h
+++ b/include/linux/sunrpc/svc_rdma.h
@@ -142,7 +142,7 @@ enum {
#define RPCSVC_MAXPAYLOAD_RDMA RPCSVC_MAXPAYLOAD
/**
- * svc_rdma_send_cid_init - Initialize a Receive Queue completion ID
+ * svc_rdma_recv_cid_init - Initialize a Receive Queue completion ID
* @rdma: controlling transport
* @cid: completion ID to initialize
*/
diff --git a/include/linux/sunrpc/svc_xprt.h b/include/linux/sunrpc/svc_xprt.h
index da2a2531e110..2af222f3ea2c 100644
--- a/include/linux/sunrpc/svc_xprt.h
+++ b/include/linux/sunrpc/svc_xprt.h
@@ -37,6 +37,9 @@ struct svc_xprt_class {
struct list_head xcl_list;
u32 xcl_max_payload;
int xcl_ident;
+ u32 xcl_flags;
+/* Set only on classes whose xpo_has_wspace() reads xpt_reserved */
+#define SVC_XPRT_FLAG_WSPACE_RESERVE BIT(0)
};
/*
@@ -59,7 +62,7 @@ struct svc_xprt {
unsigned long xpt_flags;
struct svc_serv *xpt_server; /* service for transport */
- atomic_t xpt_reserved; /* space on outq that is rsvd */
+ atomic_t xpt_reserved; /* outq space rsvd, UDP only */
atomic_t xpt_nr_rqsts; /* Number of requests */
struct mutex xpt_mutex; /* to serialize sending data */
spinlock_t xpt_lock; /* protects sk_deferred
diff --git a/include/linux/sunrpc/xdr.h b/include/linux/sunrpc/xdr.h
index b102b4f21e6b..2b33fc64be17 100644
--- a/include/linux/sunrpc/xdr.h
+++ b/include/linux/sunrpc/xdr.h
@@ -244,6 +244,7 @@ struct xdr_stream {
unsigned int nwords; /* Remaining decode buffer length */
struct rpc_rqst *rqst; /* For debugging */
+ void *xdrgen_ctx; /* Context for generated codecs */
};
/*
diff --git a/include/linux/sunrpc/xdrgen/_defs.h b/include/linux/sunrpc/xdrgen/_defs.h
index 8f3776ef3229..d767206feea4 100644
--- a/include/linux/sunrpc/xdrgen/_defs.h
+++ b/include/linux/sunrpc/xdrgen/_defs.h
@@ -5,11 +5,17 @@
* This header defines XDR data type primitives specified in
* Section 4 of RFC 4506, used by RPC programs implemented
* in the Linux kernel.
+ *
+ * A generated definition can also embed a struct xdr_buf, which
+ * carries a page-resident payload captured by reference, so this
+ * header pulls in the kernel's XDR types as well.
*/
#ifndef _SUNRPC_XDRGEN__DEFS_H_
#define _SUNRPC_XDRGEN__DEFS_H_
+#include <linux/sunrpc/xdr.h>
+
#define TRUE (true)
#define FALSE (false)
@@ -23,6 +29,34 @@ typedef struct {
u8 *data;
} opaque;
+/*
+ * Cursor a hook-driven aggregate codec hands to its begin/item/end
+ * hooks, one element at a time, in place of a materialized C array.
+ * The generated framing owns it. @xdr is the RPC layer's stream and
+ * @ctx its xdrgen_ctx, the svc_rqst on the server. @index is the
+ * current element; @member_id selects among a type's marked members.
+ * For a counted array @count is the wire length: a decoder fills it
+ * before the begin hook runs, an encoder's begin hook sets it. The
+ * hook contract is under "Pragma aggregate" in
+ * tools/net/sunrpc/xdrgen/README.
+ *
+ * An optional-data list ("type *name") carries no count. Its encoder
+ * pulls elements until the item hook returns false. False ends the
+ * list rather than failing the encode: the framing writes the
+ * value-follows terminator, so a producer that stops early leaves a
+ * valid truncated list on the wire. A producer that stops for a
+ * mid-list error records it in the application state @ctx reaches,
+ * and either returns false from the end hook, which fails the
+ * encode, or reports it in the procedure status.
+ */
+struct xdrgen_aggregate_cursor {
+ struct xdr_stream *xdr;
+ u32 index;
+ u32 count;
+ unsigned int member_id;
+ void *ctx;
+};
+
#define XDR_void (0)
#define XDR_bool (1)
#define XDR_short (1)
diff --git a/include/linux/sunrpc/xdrgen/nfs2.h b/include/linux/sunrpc/xdrgen/nfs2.h
new file mode 100644
index 000000000000..1d26de39ac69
--- /dev/null
+++ b/include/linux/sunrpc/xdrgen/nfs2.h
@@ -0,0 +1,298 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+/* Generated by xdrgen. Manual edits will be lost. */
+/* XDR specification file: ../../Documentation/sunrpc/xdr/nfs2.x */
+/* XDR specification modification time: Tue Sep 8 11:26:28 2026 */
+
+#ifndef _LINUX_XDRGEN_NFS2_DEF_H
+#define _LINUX_XDRGEN_NFS2_DEF_H
+
+#include <linux/types.h>
+#include <linux/sunrpc/xdrgen/_defs.h>
+
+enum { NFS_MAXDATA = 8192 };
+
+enum { NFS_MAXPATHLEN = 1024 };
+
+enum { NFS_MAXNAMLEN = 255 };
+
+enum { NFS_COOKIESIZE = 4 };
+
+enum { NFS_FHSIZE = 32 };
+
+enum nfsstat {
+ NFS_OK = 0,
+ NFSERR_PERM = 1,
+ NFSERR_NOENT = 2,
+ NFSERR_IO = 5,
+ NFSERR_NXIO = 6,
+ NFSERR_ACCES = 13,
+ NFSERR_EXIST = 17,
+ NFSERR_NODEV = 19,
+ NFSERR_NOTDIR = 20,
+ NFSERR_ISDIR = 21,
+ NFSERR_FBIG = 27,
+ NFSERR_NOSPC = 28,
+ NFSERR_ROFS = 30,
+ NFSERR_NAMETOOLONG = 63,
+ NFSERR_NOTEMPTY = 66,
+ NFSERR_DQUOT = 69,
+ NFSERR_STALE = 70,
+ NFSERR_WFLUSH = 99,
+};
+
+typedef __be32 nfsstat;
+
+enum ftype {
+ NFNON = 0,
+ NFREG = 1,
+ NFDIR = 2,
+ NFBLK = 3,
+ NFCHR = 4,
+ NFLNK = 5,
+};
+
+typedef enum ftype ftype;
+
+typedef u8 fhandle[NFS_FHSIZE];
+
+typedef u8 nfscookie[NFS_COOKIESIZE];
+
+struct timeval {
+ u32 seconds;
+ u32 useconds;
+};
+
+struct fattr {
+ ftype type;
+ u32 mode;
+ u32 nlink;
+ u32 uid;
+ u32 gid;
+ u32 size;
+ u32 blocksize;
+ u32 rdev;
+ u32 blocks;
+ u32 fsid;
+ u32 fileid;
+ struct timeval atime;
+ struct timeval mtime;
+ struct timeval ctime;
+};
+
+struct sattr {
+ u32 mode;
+ u32 uid;
+ u32 gid;
+ u32 size;
+ struct timeval atime;
+ struct timeval mtime;
+};
+
+typedef string filename;
+
+typedef string path;
+
+struct attrstat {
+ nfsstat status;
+ union {
+ struct fattr attributes;
+ } u;
+};
+
+struct diropargs {
+ fhandle dir;
+ filename name;
+};
+
+struct diropok {
+ fhandle file;
+ struct fattr attributes;
+};
+
+struct diropres {
+ nfsstat status;
+ union {
+ struct diropok diropok;
+ } u;
+};
+
+struct sattrargs {
+ fhandle file;
+ struct sattr attributes;
+};
+
+struct readlinkres {
+ nfsstat status;
+ union {
+ path data;
+ } u;
+};
+
+struct readargs {
+ fhandle file;
+ u32 offset;
+ u32 count;
+ u32 totalcount;
+};
+
+struct readresok {
+ struct fattr attributes;
+ opaque data;
+};
+
+struct readres {
+ nfsstat status;
+ union {
+ struct readresok readresok;
+ } u;
+};
+
+struct writeargs {
+ fhandle file;
+ u32 beginoffset;
+ u32 offset;
+ u32 totalcount;
+ struct xdr_buf data;
+};
+
+struct createargs {
+ struct diropargs where;
+ struct sattr attributes;
+};
+
+struct renameargs {
+ struct diropargs from;
+ struct diropargs to;
+};
+
+struct linkargs {
+ fhandle from;
+ struct diropargs to;
+};
+
+struct symlinkargs {
+ struct diropargs from;
+ struct xdr_buf to;
+ struct sattr attributes;
+};
+
+struct readdirargs {
+ fhandle dir;
+ nfscookie cookie;
+ u32 count;
+};
+
+struct entry {
+ u32 fileid;
+ filename name;
+ nfscookie cookie;
+};
+
+struct readdirok {
+ struct entry *entries;
+ bool eof;
+};
+
+struct readdirres {
+ nfsstat status;
+ union {
+ struct readdirok readdirok;
+ } u;
+};
+
+struct info {
+ u32 tsize;
+ u32 bsize;
+ u32 blocks;
+ u32 bfree;
+ u32 bavail;
+};
+
+struct statfsres {
+ nfsstat status;
+ union {
+ struct info info;
+ } u;
+};
+
+enum {
+ NFSPROC_NULL = 0,
+ NFSPROC_GETATTR = 1,
+ NFSPROC_SETATTR = 2,
+ NFSPROC_ROOT = 3,
+ NFSPROC_LOOKUP = 4,
+ NFSPROC_READLINK = 5,
+ NFSPROC_READ = 6,
+ NFSPROC_WRITECACHE = 7,
+ NFSPROC_WRITE = 8,
+ NFSPROC_CREATE = 9,
+ NFSPROC_REMOVE = 10,
+ NFSPROC_RENAME = 11,
+ NFSPROC_LINK = 12,
+ NFSPROC_SYMLINK = 13,
+ NFSPROC_MKDIR = 14,
+ NFSPROC_RMDIR = 15,
+ NFSPROC_READDIR = 16,
+ NFSPROC_STATFS = 17,
+};
+
+#ifndef NFS_PROGRAM
+#define NFS_PROGRAM (100003)
+#endif
+
+#define NFS2_nfsstat_sz (XDR_int)
+#define NFS2_ftype_sz (XDR_int)
+#define NFS2_fhandle_sz (XDR_QUADLEN(NFS_FHSIZE))
+#define NFS2_nfscookie_sz (XDR_QUADLEN(NFS_COOKIESIZE))
+#define NFS2_timeval_sz \
+ (XDR_unsigned_int + XDR_unsigned_int)
+#define NFS2_fattr_sz \
+ (NFS2_ftype_sz + XDR_unsigned_int + XDR_unsigned_int + XDR_unsigned_int + XDR_unsigned_int + XDR_unsigned_int + XDR_unsigned_int + XDR_unsigned_int + XDR_unsigned_int + XDR_unsigned_int + XDR_unsigned_int + NFS2_timeval_sz + NFS2_timeval_sz + NFS2_timeval_sz)
+#define NFS2_sattr_sz \
+ (XDR_unsigned_int + XDR_unsigned_int + XDR_unsigned_int + XDR_unsigned_int + NFS2_timeval_sz + NFS2_timeval_sz)
+#define NFS2_filename_sz (XDR_unsigned_int + XDR_QUADLEN(NFS_MAXNAMLEN))
+#define NFS2_path_sz (XDR_unsigned_int + XDR_QUADLEN(NFS_MAXPATHLEN))
+#define NFS2_attrstat_sz \
+ (NFS2_nfsstat_sz + NFS2_fattr_sz)
+#define NFS2_diropargs_sz \
+ (NFS2_fhandle_sz + NFS2_filename_sz)
+#define NFS2_diropok_sz \
+ (NFS2_fhandle_sz + NFS2_fattr_sz)
+#define NFS2_diropres_sz \
+ (NFS2_nfsstat_sz + NFS2_diropok_sz)
+#define NFS2_sattrargs_sz \
+ (NFS2_fhandle_sz + NFS2_sattr_sz)
+#define NFS2_readlinkres_sz \
+ (NFS2_nfsstat_sz + NFS2_path_sz)
+#define NFS2_readargs_sz \
+ (NFS2_fhandle_sz + XDR_unsigned_int + XDR_unsigned_int + XDR_unsigned_int)
+#define NFS2_readresok_sz \
+ (NFS2_fattr_sz + XDR_unsigned_int + XDR_QUADLEN(NFS_MAXDATA))
+#define NFS2_readres_sz \
+ (NFS2_nfsstat_sz + NFS2_readresok_sz)
+#define NFS2_writeargs_sz \
+ (NFS2_fhandle_sz + XDR_unsigned_int + XDR_unsigned_int + XDR_unsigned_int + XDR_unsigned_int + XDR_QUADLEN(NFS_MAXDATA))
+#define NFS2_createargs_sz \
+ (NFS2_diropargs_sz + NFS2_sattr_sz)
+#define NFS2_renameargs_sz \
+ (NFS2_diropargs_sz + NFS2_diropargs_sz)
+#define NFS2_linkargs_sz \
+ (NFS2_fhandle_sz + NFS2_diropargs_sz)
+#define NFS2_symlinkargs_sz \
+ (NFS2_diropargs_sz + NFS2_path_sz + NFS2_sattr_sz)
+#define NFS2_readdirargs_sz \
+ (NFS2_fhandle_sz + NFS2_nfscookie_sz + XDR_unsigned_int)
+#define NFS2_entry_sz \
+ (XDR_bool + XDR_unsigned_int + NFS2_filename_sz + NFS2_nfscookie_sz)
+#define NFS2_readdirok_sz \
+ (XDR_bool + XDR_bool)
+#define NFS2_readdirres_sz \
+ (NFS2_nfsstat_sz + NFS2_readdirok_sz)
+#define NFS2_info_sz \
+ (XDR_unsigned_int + XDR_unsigned_int + XDR_unsigned_int + XDR_unsigned_int + XDR_unsigned_int)
+#define NFS2_statfsres_sz \
+ (NFS2_nfsstat_sz + NFS2_info_sz)
+#define NFS2_MAX_ARGS_SZ \
+ (NFS2_writeargs_sz)
+
+#endif /* _LINUX_XDRGEN_NFS2_DEF_H */
diff --git a/include/trace/misc/nfs.h b/include/trace/misc/nfs.h
index a394b4d38e18..3146813fc4fe 100644
--- a/include/trace/misc/nfs.h
+++ b/include/trace/misc/nfs.h
@@ -8,6 +8,7 @@
*/
#include <linux/nfs.h>
+#include <linux/nfs3.h>
#include <linux/nfs4.h>
#include <uapi/linux/nfs.h>
@@ -358,18 +359,6 @@ TRACE_DEFINE_ENUM(IOMODE_ANY);
{ IOMODE_RW, "RW" }, \
{ IOMODE_ANY, "ANY" })
-#define show_rca_mask(x) \
- __print_flags(x, "|", \
- { BIT(RCA4_TYPE_MASK_RDATA_DLG), "RDATA_DLG" }, \
- { BIT(RCA4_TYPE_MASK_WDATA_DLG), "WDATA_DLG" }, \
- { BIT(RCA4_TYPE_MASK_DIR_DLG), "DIR_DLG" }, \
- { BIT(RCA4_TYPE_MASK_FILE_LAYOUT), "FILE_LAYOUT" }, \
- { BIT(RCA4_TYPE_MASK_BLK_LAYOUT), "BLK_LAYOUT" }, \
- { BIT(RCA4_TYPE_MASK_OBJ_LAYOUT_MIN), "OBJ_LAYOUT_MIN" }, \
- { BIT(RCA4_TYPE_MASK_OBJ_LAYOUT_MAX), "OBJ_LAYOUT_MAX" }, \
- { BIT(RCA4_TYPE_MASK_OTHER_LAYOUT_MIN), "OTHER_LAYOUT_MIN" }, \
- { BIT(RCA4_TYPE_MASK_OTHER_LAYOUT_MAX), "OTHER_LAYOUT_MAX" })
-
#define show_nfs4_seq4_status(x) \
__print_flags(x, "|", \
{ SEQ4_STATUS_CB_PATH_DOWN, "CB_PATH_DOWN" }, \
diff --git a/include/uapi/linux/nfsd_netlink.h b/include/uapi/linux/nfsd_netlink.h
index 87da1d0bb21e..c125af0cc6a5 100644
--- a/include/uapi/linux/nfsd_netlink.h
+++ b/include/uapi/linux/nfsd_netlink.h
@@ -50,6 +50,15 @@ enum nfsd_xprtsec_mode {
NFSD_XPRTSEC_MODE_MTLS = 4,
};
+/*
+ * Constraints that apply to an rpcbind registration. no-udp means the kernel
+ * would not have registered this program and version over UDP, so the caller
+ * must skip the udp and udp6 netids for it.
+ */
+enum nfsd_rpcbind_flags {
+ NFSD_RPCBIND_FLAGS_NO_UDP = 1,
+};
+
enum {
NFSD_A_CACHE_NOTIFY_CACHE_TYPE = 1,
@@ -114,7 +123,18 @@ enum {
};
enum {
+ NFSD_A_RPCBIND_PROGRAM = 1,
+ NFSD_A_RPCBIND_VERSION,
+ NFSD_A_RPCBIND_FLAGS,
+
+ __NFSD_A_RPCBIND_MAX,
+ NFSD_A_RPCBIND_MAX = (__NFSD_A_RPCBIND_MAX - 1)
+};
+
+enum {
NFSD_A_SERVER_SOCK_ADDR = 1,
+ NFSD_A_SERVER_SOCK_USERSPACE_RPCBIND,
+ NFSD_A_SERVER_SOCK_RPCBIND,
__NFSD_A_SERVER_SOCK_MAX,
NFSD_A_SERVER_SOCK_MAX = (__NFSD_A_SERVER_SOCK_MAX - 1)