--- /dev/null
+From db11de653c2fdd198722c6647c23d8ecbf2dc80a Mon Sep 17 00:00:00 2001
+From: David Disseldorp <ddiss@suse.de>
+Date: Fri, 21 Oct 2022 14:24:14 +0200
+Subject: exportfs: use pr_debug for unreachable debug statements
+
+From: David Disseldorp <ddiss@suse.de>
+
+[ Upstream commit 427505ffeaa464f683faba945a88d3e3248f6979 ]
+
+expfs.c has a bunch of dprintk statements which are unusable due to:
+ #define dprintk(fmt, args...) do{}while(0)
+Use pr_debug so that they can be enabled dynamically.
+Also make some minor changes to the debug statements to fix some
+incorrect types, and remove __func__ which can be handled by dynamic
+debug separately.
+
+Signed-off-by: David Disseldorp <ddiss@suse.de>
+Reviewed-by: NeilBrown <neilb@suse.de>
+Signed-off-by: Chuck Lever <chuck.lever@oracle.com>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+---
+ fs/exportfs/expfs.c | 8 ++++----
+ 1 file changed, 4 insertions(+), 4 deletions(-)
+
+--- a/fs/exportfs/expfs.c
++++ b/fs/exportfs/expfs.c
+@@ -18,7 +18,7 @@
+ #include <linux/sched.h>
+ #include <linux/cred.h>
+
+-#define dprintk(fmt, args...) do{}while(0)
++#define dprintk(fmt, args...) pr_debug(fmt, ##args)
+
+
+ static int get_name(const struct path *path, char *name, struct dentry *child);
+@@ -132,8 +132,8 @@ static struct dentry *reconnect_one(stru
+ inode_unlock(dentry->d_inode);
+
+ if (IS_ERR(parent)) {
+- dprintk("%s: get_parent of %ld failed, err %d\n",
+- __func__, dentry->d_inode->i_ino, PTR_ERR(parent));
++ dprintk("get_parent of %lu failed, err %ld\n",
++ dentry->d_inode->i_ino, PTR_ERR(parent));
+ return parent;
+ }
+
+@@ -147,7 +147,7 @@ static struct dentry *reconnect_one(stru
+ dprintk("%s: found name: %s\n", __func__, nbuf);
+ tmp = lookup_one_unlocked(mnt_user_ns(mnt), nbuf, parent, strlen(nbuf));
+ if (IS_ERR(tmp)) {
+- dprintk("%s: lookup failed: %d\n", __func__, PTR_ERR(tmp));
++ dprintk("lookup failed: %ld\n", PTR_ERR(tmp));
+ err = PTR_ERR(tmp);
+ goto out_err;
+ }
--- /dev/null
+From 5c8dcb0ee71e3d832d3f7b67bcf369fc206fed1a Mon Sep 17 00:00:00 2001
+From: Jeff Layton <jlayton@kernel.org>
+Date: Wed, 16 Nov 2022 09:02:30 -0500
+Subject: filelock: add a new locks_inode_context accessor function
+
+From: Jeff Layton <jlayton@kernel.org>
+
+[ Upstream commit 401a8b8fd5acd51582b15238d72a8d0edd580e9f ]
+
+There are a number of places in the kernel that are accessing the
+inode->i_flctx field without smp_load_acquire. This is required to
+ensure that the caller doesn't see a partially-initialized structure.
+
+Add a new accessor function for it to make this clear and convert all of
+the relevant accesses in locks.c to use it. Also, convert
+locks_free_lock_context to use the helper as well instead of just doing
+a "bare" assignment.
+
+Reviewed-by: Christoph Hellwig <hch@lst.de>
+Signed-off-by: Jeff Layton <jlayton@kernel.org>
+Stable-dep-of: 77c67530e1f9 ("nfsd: use locks_inode_context helper")
+Signed-off-by: Chuck Lever <chuck.lever@oracle.com>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+---
+ fs/locks.c | 24 ++++++++++++------------
+ include/linux/fs.h | 14 ++++++++++++++
+ 2 files changed, 26 insertions(+), 12 deletions(-)
+
+--- a/fs/locks.c
++++ b/fs/locks.c
+@@ -175,7 +175,7 @@ locks_get_lock_context(struct inode *ino
+ struct file_lock_context *ctx;
+
+ /* paired with cmpxchg() below */
+- ctx = smp_load_acquire(&inode->i_flctx);
++ ctx = locks_inode_context(inode);
+ if (likely(ctx) || type == F_UNLCK)
+ goto out;
+
+@@ -194,7 +194,7 @@ locks_get_lock_context(struct inode *ino
+ */
+ if (cmpxchg(&inode->i_flctx, NULL, ctx)) {
+ kmem_cache_free(flctx_cache, ctx);
+- ctx = smp_load_acquire(&inode->i_flctx);
++ ctx = locks_inode_context(inode);
+ }
+ out:
+ trace_locks_get_lock_context(inode, type, ctx);
+@@ -247,7 +247,7 @@ locks_check_ctx_file_list(struct file *f
+ void
+ locks_free_lock_context(struct inode *inode)
+ {
+- struct file_lock_context *ctx = inode->i_flctx;
++ struct file_lock_context *ctx = locks_inode_context(inode);
+
+ if (unlikely(ctx)) {
+ locks_check_ctx_lists(inode);
+@@ -891,7 +891,7 @@ posix_test_lock(struct file *filp, struc
+ void *owner;
+ void (*func)(void);
+
+- ctx = smp_load_acquire(&inode->i_flctx);
++ ctx = locks_inode_context(inode);
+ if (!ctx || list_empty_careful(&ctx->flc_posix)) {
+ fl->fl_type = F_UNLCK;
+ return;
+@@ -1483,7 +1483,7 @@ int __break_lease(struct inode *inode, u
+ new_fl->fl_flags = type;
+
+ /* typically we will check that ctx is non-NULL before calling */
+- ctx = smp_load_acquire(&inode->i_flctx);
++ ctx = locks_inode_context(inode);
+ if (!ctx) {
+ WARN_ON_ONCE(1);
+ goto free_lock;
+@@ -1588,7 +1588,7 @@ void lease_get_mtime(struct inode *inode
+ struct file_lock_context *ctx;
+ struct file_lock *fl;
+
+- ctx = smp_load_acquire(&inode->i_flctx);
++ ctx = locks_inode_context(inode);
+ if (ctx && !list_empty_careful(&ctx->flc_lease)) {
+ spin_lock(&ctx->flc_lock);
+ fl = list_first_entry_or_null(&ctx->flc_lease,
+@@ -1634,7 +1634,7 @@ int fcntl_getlease(struct file *filp)
+ int type = F_UNLCK;
+ LIST_HEAD(dispose);
+
+- ctx = smp_load_acquire(&inode->i_flctx);
++ ctx = locks_inode_context(inode);
+ if (ctx && !list_empty_careful(&ctx->flc_lease)) {
+ percpu_down_read(&file_rwsem);
+ spin_lock(&ctx->flc_lock);
+@@ -1823,7 +1823,7 @@ static int generic_delete_lease(struct f
+ struct file_lock_context *ctx;
+ LIST_HEAD(dispose);
+
+- ctx = smp_load_acquire(&inode->i_flctx);
++ ctx = locks_inode_context(inode);
+ if (!ctx) {
+ trace_generic_delete_lease(inode, NULL);
+ return error;
+@@ -2562,7 +2562,7 @@ void locks_remove_posix(struct file *fil
+ * posix_lock_file(). Another process could be setting a lock on this
+ * file at the same time, but we wouldn't remove that lock anyway.
+ */
+- ctx = smp_load_acquire(&inode->i_flctx);
++ ctx = locks_inode_context(inode);
+ if (!ctx || list_empty(&ctx->flc_posix))
+ return;
+
+@@ -2635,7 +2635,7 @@ void locks_remove_file(struct file *filp
+ {
+ struct file_lock_context *ctx;
+
+- ctx = smp_load_acquire(&locks_inode(filp)->i_flctx);
++ ctx = locks_inode_context(locks_inode(filp));
+ if (!ctx)
+ return;
+
+@@ -2682,7 +2682,7 @@ bool vfs_inode_has_locks(struct inode *i
+ struct file_lock_context *ctx;
+ bool ret;
+
+- ctx = smp_load_acquire(&inode->i_flctx);
++ ctx = locks_inode_context(inode);
+ if (!ctx)
+ return false;
+
+@@ -2863,7 +2863,7 @@ void show_fd_locks(struct seq_file *f,
+ struct file_lock_context *ctx;
+ int id = 0;
+
+- ctx = smp_load_acquire(&inode->i_flctx);
++ ctx = locks_inode_context(inode);
+ if (!ctx)
+ return;
+
+--- a/include/linux/fs.h
++++ b/include/linux/fs.h
+@@ -1189,6 +1189,13 @@ extern void show_fd_locks(struct seq_fil
+ struct file *filp, struct files_struct *files);
+ extern bool locks_owner_has_blockers(struct file_lock_context *flctx,
+ fl_owner_t owner);
++
++static inline struct file_lock_context *
++locks_inode_context(const struct inode *inode)
++{
++ return smp_load_acquire(&inode->i_flctx);
++}
++
+ #else /* !CONFIG_FILE_LOCKING */
+ static inline int fcntl_getlk(struct file *file, unsigned int cmd,
+ struct flock __user *user)
+@@ -1334,6 +1341,13 @@ static inline bool locks_owner_has_block
+ {
+ return false;
+ }
++
++static inline struct file_lock_context *
++locks_inode_context(const struct inode *inode)
++{
++ return NULL;
++}
++
+ #endif /* !CONFIG_FILE_LOCKING */
+
+ static inline struct inode *file_inode(const struct file *f)
--- /dev/null
+From f9d843598ec499abdb2f040a1c6665cfc7ab1b87 Mon Sep 17 00:00:00 2001
+From: Jeff Layton <jlayton@kernel.org>
+Date: Fri, 11 Nov 2022 14:36:37 -0500
+Subject: lockd: ensure we use the correct file descriptor when unlocking
+
+From: Jeff Layton <jlayton@kernel.org>
+
+[ Upstream commit 69efce009f7df888e1fede3cb2913690eb829f52 ]
+
+Shared locks are set on O_RDONLY descriptors and exclusive locks are set
+on O_WRONLY ones. nlmsvc_unlock however calls vfs_lock_file twice, once
+for each descriptor, but it doesn't reset fl_file. Ensure that it does.
+
+Signed-off-by: Jeff Layton <jlayton@kernel.org>
+Signed-off-by: Chuck Lever <chuck.lever@oracle.com>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+---
+ fs/lockd/svclock.c | 10 ++++++----
+ 1 file changed, 6 insertions(+), 4 deletions(-)
+
+--- a/fs/lockd/svclock.c
++++ b/fs/lockd/svclock.c
+@@ -659,11 +659,13 @@ nlmsvc_unlock(struct net *net, struct nl
+ nlmsvc_cancel_blocked(net, file, lock);
+
+ lock->fl.fl_type = F_UNLCK;
+- if (file->f_file[O_RDONLY])
+- error = vfs_lock_file(file->f_file[O_RDONLY], F_SETLK,
++ lock->fl.fl_file = file->f_file[O_RDONLY];
++ if (lock->fl.fl_file)
++ error = vfs_lock_file(lock->fl.fl_file, F_SETLK,
+ &lock->fl, NULL);
+- if (file->f_file[O_WRONLY])
+- error = vfs_lock_file(file->f_file[O_WRONLY], F_SETLK,
++ lock->fl.fl_file = file->f_file[O_WRONLY];
++ if (lock->fl.fl_file)
++ error |= vfs_lock_file(lock->fl.fl_file, F_SETLK,
+ &lock->fl, NULL);
+
+ return (error < 0)? nlm_lck_denied_nolocks : nlm_granted;
--- /dev/null
+From fdf4fd6f05ae4659354de48f42dcee40eb4405dd Mon Sep 17 00:00:00 2001
+From: Jeff Layton <jlayton@kernel.org>
+Date: Fri, 11 Nov 2022 14:36:38 -0500
+Subject: lockd: fix file selection in nlmsvc_cancel_blocked
+
+From: Jeff Layton <jlayton@kernel.org>
+
+[ Upstream commit 9f27783b4dd235ef3c8dbf69fc6322777450323c ]
+
+We currently do a lock_to_openmode call based on the arguments from the
+NLM_UNLOCK call, but that will always set the fl_type of the lock to
+F_UNLCK, and the O_RDONLY descriptor is always chosen.
+
+Fix it to use the file_lock from the block instead.
+
+Signed-off-by: Jeff Layton <jlayton@kernel.org>
+Signed-off-by: Chuck Lever <chuck.lever@oracle.com>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+---
+ fs/lockd/svclock.c | 7 ++++---
+ 1 file changed, 4 insertions(+), 3 deletions(-)
+
+--- a/fs/lockd/svclock.c
++++ b/fs/lockd/svclock.c
+@@ -699,9 +699,10 @@ nlmsvc_cancel_blocked(struct net *net, s
+ block = nlmsvc_lookup_block(file, lock);
+ mutex_unlock(&file->f_mutex);
+ if (block != NULL) {
+- mode = lock_to_openmode(&lock->fl);
+- vfs_cancel_lock(block->b_file->f_file[mode],
+- &block->b_call->a_args.lock.fl);
++ struct file_lock *fl = &block->b_call->a_args.lock.fl;
++
++ mode = lock_to_openmode(fl);
++ vfs_cancel_lock(block->b_file->f_file[mode], fl);
+ status = nlmsvc_unlink_block(block);
+ nlmsvc_release_block(block);
+ }
--- /dev/null
+From c9bb9f1f9a8a13d5c4d8d0dc61826710edfa5ee4 Mon Sep 17 00:00:00 2001
+From: Jeff Layton <jlayton@kernel.org>
+Date: Fri, 11 Nov 2022 14:36:36 -0500
+Subject: lockd: set missing fl_flags field when retrieving args
+
+From: Jeff Layton <jlayton@kernel.org>
+
+[ Upstream commit 75c7940d2a86d3f1b60a0a265478cb8fc887b970 ]
+
+Signed-off-by: Jeff Layton <jlayton@kernel.org>
+Signed-off-by: Chuck Lever <chuck.lever@oracle.com>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+---
+ fs/lockd/svc4proc.c | 1 +
+ fs/lockd/svcproc.c | 1 +
+ 2 files changed, 2 insertions(+)
+
+--- a/fs/lockd/svc4proc.c
++++ b/fs/lockd/svc4proc.c
+@@ -52,6 +52,7 @@ nlm4svc_retrieve_args(struct svc_rqst *r
+ *filp = file;
+
+ /* Set up the missing parts of the file_lock structure */
++ lock->fl.fl_flags = FL_POSIX;
+ lock->fl.fl_file = file->f_file[mode];
+ lock->fl.fl_pid = current->tgid;
+ lock->fl.fl_start = (loff_t)lock->lock_start;
+--- a/fs/lockd/svcproc.c
++++ b/fs/lockd/svcproc.c
+@@ -77,6 +77,7 @@ nlmsvc_retrieve_args(struct svc_rqst *rq
+
+ /* Set up the missing parts of the file_lock structure */
+ mode = lock_to_openmode(&lock->fl);
++ lock->fl.fl_flags = FL_POSIX;
+ lock->fl.fl_file = file->f_file[mode];
+ lock->fl.fl_pid = current->tgid;
+ lock->fl.fl_lmops = &nlmsvc_lock_operations;
--- /dev/null
+From 444f52797c77c16ddea5319f53c0d650d775606c Mon Sep 17 00:00:00 2001
+From: Jeff Layton <jlayton@kernel.org>
+Date: Wed, 16 Nov 2022 09:19:43 -0500
+Subject: lockd: use locks_inode_context helper
+
+From: Jeff Layton <jlayton@kernel.org>
+
+[ Upstream commit 98b41ffe0afdfeaa1439a5d6bd2db4a94277e31b ]
+
+lockd currently doesn't access i_flctx safely. This requires a
+smp_load_acquire, as the pointer is set via cmpxchg (a release
+operation).
+
+Cc: Trond Myklebust <trond.myklebust@hammerspace.com>
+Cc: Anna Schumaker <anna@kernel.org>
+Cc: Chuck Lever <chuck.lever@oracle.com>
+Reviewed-by: Christoph Hellwig <hch@lst.de>
+Signed-off-by: Jeff Layton <jlayton@kernel.org>
+Signed-off-by: Chuck Lever <chuck.lever@oracle.com>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+---
+ fs/lockd/svcsubs.c | 4 ++--
+ 1 file changed, 2 insertions(+), 2 deletions(-)
+
+--- a/fs/lockd/svcsubs.c
++++ b/fs/lockd/svcsubs.c
+@@ -210,7 +210,7 @@ nlm_traverse_locks(struct nlm_host *host
+ {
+ struct inode *inode = nlmsvc_file_inode(file);
+ struct file_lock *fl;
+- struct file_lock_context *flctx = inode->i_flctx;
++ struct file_lock_context *flctx = locks_inode_context(inode);
+ struct nlm_host *lockhost;
+
+ if (!flctx || list_empty_careful(&flctx->flc_posix))
+@@ -265,7 +265,7 @@ nlm_file_inuse(struct nlm_file *file)
+ {
+ struct inode *inode = nlmsvc_file_inode(file);
+ struct file_lock *fl;
+- struct file_lock_context *flctx = inode->i_flctx;
++ struct file_lock_context *flctx = locks_inode_context(inode);
+
+ if (file->f_count || !list_empty(&file->f_blocks) || file->f_shares)
+ return 1;
--- /dev/null
+From 29ddbb46d0563b2f0dc15886308b67aa5916965a Mon Sep 17 00:00:00 2001
+From: Chuck Lever <chuck.lever@oracle.com>
+Date: Fri, 28 Oct 2022 10:47:34 -0400
+Subject: NFSD: Add a nfsd4_file_hash_remove() helper
+
+From: Chuck Lever <chuck.lever@oracle.com>
+
+[ Upstream commit 3341678f2fd6106055cead09e513fad6950a0d19 ]
+
+Refactor to relocate hash deletion operation to a helper function
+that is close to most other nfs4_file data structure operations.
+
+The "noinline" annotation will become useful in a moment when the
+hlist_del_rcu() is replaced with a more complex rhash remove
+operation. It also guarantees that hash remove operations can be
+traced with "-p function -l remove_nfs4_file_locked".
+
+This also simplifies the organization of forward declarations: the
+to-be-added rhashtable and its param structure will be defined
+/after/ put_nfs4_file().
+
+Signed-off-by: Chuck Lever <chuck.lever@oracle.com>
+Reviewed-by: NeilBrown <neilb@suse.de>
+Reviewed-by: Jeff Layton <jlayton@kernel.org>
+Signed-off-by: Chuck Lever <chuck.lever@oracle.com>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+---
+ fs/nfsd/nfs4state.c | 8 +++++++-
+ 1 file changed, 7 insertions(+), 1 deletion(-)
+
+--- a/fs/nfsd/nfs4state.c
++++ b/fs/nfsd/nfs4state.c
+@@ -84,6 +84,7 @@ static bool check_for_locks(struct nfs4_
+ static void nfs4_free_ol_stateid(struct nfs4_stid *stid);
+ void nfsd4_end_grace(struct nfsd_net *nn);
+ static void _free_cpntf_state_locked(struct nfsd_net *nn, struct nfs4_cpntf_state *cps);
++static void nfsd4_file_hash_remove(struct nfs4_file *fi);
+
+ /* Locking: */
+
+@@ -591,7 +592,7 @@ put_nfs4_file(struct nfs4_file *fi)
+ might_lock(&state_lock);
+
+ if (refcount_dec_and_lock(&fi->fi_ref, &state_lock)) {
+- hlist_del_rcu(&fi->fi_hash);
++ nfsd4_file_hash_remove(fi);
+ spin_unlock(&state_lock);
+ WARN_ON_ONCE(!list_empty(&fi->fi_clnt_odstate));
+ WARN_ON_ONCE(!list_empty(&fi->fi_delegations));
+@@ -4750,6 +4751,11 @@ find_or_add_file(struct nfs4_file *new,
+ return insert_file(new, fh, hashval);
+ }
+
++static noinline_for_stack void nfsd4_file_hash_remove(struct nfs4_file *fi)
++{
++ hlist_del_rcu(&fi->fi_hash);
++}
++
+ /*
+ * Called to check deny when READ with all zero stateid or
+ * WRITE with all zero or all one stateid
--- /dev/null
+From f8705e063165c4cd87f1bbdec9211992c5d434e4 Mon Sep 17 00:00:00 2001
+From: Dai Ngo <dai.ngo@oracle.com>
+Date: Wed, 16 Nov 2022 19:44:48 -0800
+Subject: NFSD: add CB_RECALL_ANY tracepoints
+
+From: Dai Ngo <dai.ngo@oracle.com>
+
+[ Upstream commit 638593be55c0b37a1930038460a9918215d5c24b ]
+
+Add tracepoints to trace start and end of CB_RECALL_ANY operation.
+
+Signed-off-by: Dai Ngo <dai.ngo@oracle.com>
+[ cel: added show_rca_mask() macro ]
+Signed-off-by: Chuck Lever <chuck.lever@oracle.com>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+---
+ fs/nfsd/nfs4state.c | 2 +
+ fs/nfsd/trace.h | 50 +++++++++++++++++++++++++++++++++++++++++++++++
+ include/trace/misc/nfs.h | 12 +++++++++++
+ 3 files changed, 64 insertions(+)
+
+--- a/fs/nfsd/nfs4state.c
++++ b/fs/nfsd/nfs4state.c
+@@ -2877,6 +2877,7 @@ static int
+ nfsd4_cb_recall_any_done(struct nfsd4_callback *cb,
+ struct rpc_task *task)
+ {
++ trace_nfsd_cb_recall_any_done(cb, task);
+ switch (task->tk_status) {
+ case -NFS4ERR_DELAY:
+ rpc_delay(task, 2 * HZ);
+@@ -6254,6 +6255,7 @@ deleg_reaper(struct nfsd_net *nn)
+ list_del_init(&clp->cl_ra_cblist);
+ clp->cl_ra->ra_keep = 0;
+ clp->cl_ra->ra_bmval[0] = BIT(RCA4_TYPE_MASK_RDATA_DLG);
++ trace_nfsd_cb_recall_any(clp->cl_ra);
+ nfsd4_run_cb(&clp->cl_ra->ra_cb);
+ }
+ }
+--- a/fs/nfsd/trace.h
++++ b/fs/nfsd/trace.h
+@@ -9,9 +9,12 @@
+ #define _NFSD_TRACE_H
+
+ #include <linux/tracepoint.h>
++#include <linux/sunrpc/xprt.h>
++#include <trace/misc/nfs.h>
+
+ #include "export.h"
+ #include "nfsfh.h"
++#include "xdr4.h"
+
+ #define NFSD_TRACE_PROC_RES_FIELDS \
+ __field(unsigned int, netns_ino) \
+@@ -1492,6 +1495,32 @@ TRACE_EVENT(nfsd_cb_offload,
+ __entry->fh_hash, __entry->count, __entry->status)
+ );
+
++TRACE_EVENT(nfsd_cb_recall_any,
++ TP_PROTO(
++ const struct nfsd4_cb_recall_any *ra
++ ),
++ TP_ARGS(ra),
++ TP_STRUCT__entry(
++ __field(u32, cl_boot)
++ __field(u32, cl_id)
++ __field(u32, keep)
++ __field(unsigned long, bmval0)
++ __sockaddr(addr, ra->ra_cb.cb_clp->cl_cb_conn.cb_addrlen)
++ ),
++ TP_fast_assign(
++ __entry->cl_boot = ra->ra_cb.cb_clp->cl_clientid.cl_boot;
++ __entry->cl_id = ra->ra_cb.cb_clp->cl_clientid.cl_id;
++ __entry->keep = ra->ra_keep;
++ __entry->bmval0 = ra->ra_bmval[0];
++ __assign_sockaddr(addr, &ra->ra_cb.cb_clp->cl_addr,
++ ra->ra_cb.cb_clp->cl_cb_conn.cb_addrlen);
++ ),
++ TP_printk("addr=%pISpc client %08x:%08x keep=%u bmval0=%s",
++ __get_sockaddr(addr), __entry->cl_boot, __entry->cl_id,
++ __entry->keep, show_rca_mask(__entry->bmval0)
++ )
++);
++
+ DECLARE_EVENT_CLASS(nfsd_cb_done_class,
+ TP_PROTO(
+ const stateid_t *stp,
+@@ -1531,6 +1560,27 @@ DEFINE_NFSD_CB_DONE_EVENT(nfsd_cb_notify
+ DEFINE_NFSD_CB_DONE_EVENT(nfsd_cb_layout_done);
+ DEFINE_NFSD_CB_DONE_EVENT(nfsd_cb_offload_done);
+
++TRACE_EVENT(nfsd_cb_recall_any_done,
++ TP_PROTO(
++ const struct nfsd4_callback *cb,
++ const struct rpc_task *task
++ ),
++ TP_ARGS(cb, task),
++ TP_STRUCT__entry(
++ __field(u32, cl_boot)
++ __field(u32, cl_id)
++ __field(int, status)
++ ),
++ TP_fast_assign(
++ __entry->status = task->tk_status;
++ __entry->cl_boot = cb->cb_clp->cl_clientid.cl_boot;
++ __entry->cl_id = cb->cb_clp->cl_clientid.cl_id;
++ ),
++ TP_printk("client %08x:%08x status=%d",
++ __entry->cl_boot, __entry->cl_id, __entry->status
++ )
++);
++
+ #endif /* _NFSD_TRACE_H */
+
+ #undef TRACE_INCLUDE_PATH
+--- a/include/trace/misc/nfs.h
++++ b/include/trace/misc/nfs.h
+@@ -360,6 +360,18 @@ 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" }, \
--- /dev/null
+From ae75430dec3ea9b1eeaeefdfc28470352dd00dc5 Mon Sep 17 00:00:00 2001
+From: Dai Ngo <dai.ngo@oracle.com>
+Date: Wed, 16 Nov 2022 19:44:47 -0800
+Subject: NFSD: add delegation reaper to react to low memory condition
+
+From: Dai Ngo <dai.ngo@oracle.com>
+
+[ Upstream commit 44df6f439a1790a5f602e3842879efa88f346672 ]
+
+The delegation reaper is called by nfsd memory shrinker's on
+the 'count' callback. It scans the client list and sends the
+courtesy CB_RECALL_ANY to the clients that hold delegations.
+
+To avoid flooding the clients with CB_RECALL_ANY requests, the
+delegation reaper sends only one CB_RECALL_ANY request to each
+client per 5 seconds.
+
+Signed-off-by: Dai Ngo <dai.ngo@oracle.com>
+[ cel: moved definition of RCA4_TYPE_MASK_RDATA_DLG ]
+Signed-off-by: Chuck Lever <chuck.lever@oracle.com>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+---
+ fs/nfsd/nfs4state.c | 88 ++++++++++++++++++++++++++++++++++++++++++++++++---
+ fs/nfsd/state.h | 5 ++
+ include/linux/nfs4.h | 13 +++++++
+ 3 files changed, 102 insertions(+), 4 deletions(-)
+
+--- a/fs/nfsd/nfs4state.c
++++ b/fs/nfsd/nfs4state.c
+@@ -2145,6 +2145,7 @@ static void __free_client(struct kref *k
+ kfree(clp->cl_nii_domain.data);
+ kfree(clp->cl_nii_name.data);
+ idr_destroy(&clp->cl_stateids);
++ kfree(clp->cl_ra);
+ kmem_cache_free(client_slab, clp);
+ }
+
+@@ -2872,6 +2873,36 @@ static const struct tree_descr client_fi
+ [3] = {""},
+ };
+
++static int
++nfsd4_cb_recall_any_done(struct nfsd4_callback *cb,
++ struct rpc_task *task)
++{
++ switch (task->tk_status) {
++ case -NFS4ERR_DELAY:
++ rpc_delay(task, 2 * HZ);
++ return 0;
++ default:
++ return 1;
++ }
++}
++
++static void
++nfsd4_cb_recall_any_release(struct nfsd4_callback *cb)
++{
++ struct nfs4_client *clp = cb->cb_clp;
++ struct nfsd_net *nn = net_generic(clp->net, nfsd_net_id);
++
++ spin_lock(&nn->client_lock);
++ clear_bit(NFSD4_CLIENT_CB_RECALL_ANY, &clp->cl_flags);
++ put_client_renew_locked(clp);
++ spin_unlock(&nn->client_lock);
++}
++
++static const struct nfsd4_callback_ops nfsd4_cb_recall_any_ops = {
++ .done = nfsd4_cb_recall_any_done,
++ .release = nfsd4_cb_recall_any_release,
++};
++
+ static struct nfs4_client *create_client(struct xdr_netobj name,
+ struct svc_rqst *rqstp, nfs4_verifier *verf)
+ {
+@@ -2909,6 +2940,14 @@ static struct nfs4_client *create_client
+ free_client(clp);
+ return NULL;
+ }
++ clp->cl_ra = kzalloc(sizeof(*clp->cl_ra), GFP_KERNEL);
++ if (!clp->cl_ra) {
++ free_client(clp);
++ return NULL;
++ }
++ clp->cl_ra_time = 0;
++ nfsd4_init_cb(&clp->cl_ra->ra_cb, clp, &nfsd4_cb_recall_any_ops,
++ NFSPROC4_CLNT_CB_RECALL_ANY);
+ return clp;
+ }
+
+@@ -4364,14 +4403,16 @@ out:
+ static unsigned long
+ nfsd4_state_shrinker_count(struct shrinker *shrink, struct shrink_control *sc)
+ {
+- int cnt;
++ int count;
+ struct nfsd_net *nn = container_of(shrink,
+ struct nfsd_net, nfsd_client_shrinker);
+
+- cnt = atomic_read(&nn->nfsd_courtesy_clients);
+- if (cnt > 0)
++ count = atomic_read(&nn->nfsd_courtesy_clients);
++ if (!count)
++ count = atomic_long_read(&num_delegations);
++ if (count)
+ mod_delayed_work(laundry_wq, &nn->nfsd_shrinker_work, 0);
+- return (unsigned long)cnt;
++ return (unsigned long)count;
+ }
+
+ static unsigned long
+@@ -6180,6 +6221,44 @@ courtesy_client_reaper(struct nfsd_net *
+ }
+
+ static void
++deleg_reaper(struct nfsd_net *nn)
++{
++ struct list_head *pos, *next;
++ struct nfs4_client *clp;
++ struct list_head cblist;
++
++ INIT_LIST_HEAD(&cblist);
++ spin_lock(&nn->client_lock);
++ list_for_each_safe(pos, next, &nn->client_lru) {
++ clp = list_entry(pos, struct nfs4_client, cl_lru);
++ if (clp->cl_state != NFSD4_ACTIVE ||
++ list_empty(&clp->cl_delegations) ||
++ atomic_read(&clp->cl_delegs_in_recall) ||
++ test_bit(NFSD4_CLIENT_CB_RECALL_ANY, &clp->cl_flags) ||
++ (ktime_get_boottime_seconds() -
++ clp->cl_ra_time < 5)) {
++ continue;
++ }
++ list_add(&clp->cl_ra_cblist, &cblist);
++
++ /* release in nfsd4_cb_recall_any_release */
++ atomic_inc(&clp->cl_rpc_users);
++ set_bit(NFSD4_CLIENT_CB_RECALL_ANY, &clp->cl_flags);
++ clp->cl_ra_time = ktime_get_boottime_seconds();
++ }
++ spin_unlock(&nn->client_lock);
++
++ while (!list_empty(&cblist)) {
++ clp = list_first_entry(&cblist, struct nfs4_client,
++ cl_ra_cblist);
++ list_del_init(&clp->cl_ra_cblist);
++ clp->cl_ra->ra_keep = 0;
++ clp->cl_ra->ra_bmval[0] = BIT(RCA4_TYPE_MASK_RDATA_DLG);
++ nfsd4_run_cb(&clp->cl_ra->ra_cb);
++ }
++}
++
++static void
+ nfsd4_state_shrinker_worker(struct work_struct *work)
+ {
+ struct delayed_work *dwork = to_delayed_work(work);
+@@ -6187,6 +6266,7 @@ nfsd4_state_shrinker_worker(struct work_
+ nfsd_shrinker_work);
+
+ courtesy_client_reaper(nn);
++ deleg_reaper(nn);
+ }
+
+ static inline __be32 nfs4_check_fh(struct svc_fh *fhp, struct nfs4_stid *stp)
+--- a/fs/nfsd/state.h
++++ b/fs/nfsd/state.h
+@@ -368,6 +368,7 @@ struct nfs4_client {
+ #define NFSD4_CLIENT_UPCALL_LOCK (5) /* upcall serialization */
+ #define NFSD4_CLIENT_CB_FLAG_MASK (1 << NFSD4_CLIENT_CB_UPDATE | \
+ 1 << NFSD4_CLIENT_CB_KILL)
++#define NFSD4_CLIENT_CB_RECALL_ANY (6)
+ unsigned long cl_flags;
+ const struct cred *cl_cb_cred;
+ struct rpc_clnt *cl_cb_client;
+@@ -411,6 +412,10 @@ struct nfs4_client {
+
+ unsigned int cl_state;
+ atomic_t cl_delegs_in_recall;
++
++ struct nfsd4_cb_recall_any *cl_ra;
++ time64_t cl_ra_time;
++ struct list_head cl_ra_cblist;
+ };
+
+ /* struct nfs4_client_reset
+--- a/include/linux/nfs4.h
++++ b/include/linux/nfs4.h
+@@ -732,4 +732,17 @@ enum nfs4_setxattr_options {
+ SETXATTR4_CREATE = 1,
+ SETXATTR4_REPLACE = 2,
+ };
++
++enum {
++ RCA4_TYPE_MASK_RDATA_DLG = 0,
++ RCA4_TYPE_MASK_WDATA_DLG = 1,
++ RCA4_TYPE_MASK_DIR_DLG = 2,
++ RCA4_TYPE_MASK_FILE_LAYOUT = 3,
++ RCA4_TYPE_MASK_BLK_LAYOUT = 4,
++ RCA4_TYPE_MASK_OBJ_LAYOUT_MIN = 8,
++ RCA4_TYPE_MASK_OBJ_LAYOUT_MAX = 9,
++ RCA4_TYPE_MASK_OTHER_LAYOUT_MIN = 12,
++ RCA4_TYPE_MASK_OTHER_LAYOUT_MAX = 15,
++};
++
+ #endif
--- /dev/null
+From 08607743476ffa171431efaec0d6e7c29bbbed4e Mon Sep 17 00:00:00 2001
+From: Dai Ngo <dai.ngo@oracle.com>
+Date: Wed, 16 Nov 2022 19:44:46 -0800
+Subject: NFSD: add support for sending CB_RECALL_ANY
+
+From: Dai Ngo <dai.ngo@oracle.com>
+
+[ Upstream commit 3959066b697b5dfbb7141124ae9665337d4bc638 ]
+
+Add XDR encode and decode function for CB_RECALL_ANY.
+
+Signed-off-by: Dai Ngo <dai.ngo@oracle.com>
+Signed-off-by: Chuck Lever <chuck.lever@oracle.com>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+---
+ fs/nfsd/nfs4callback.c | 72 +++++++++++++++++++++++++++++++++++++++++++++++++
+ fs/nfsd/state.h | 1
+ fs/nfsd/xdr4.h | 5 +++
+ fs/nfsd/xdr4cb.h | 6 ++++
+ 4 files changed, 84 insertions(+)
+
+--- a/fs/nfsd/nfs4callback.c
++++ b/fs/nfsd/nfs4callback.c
+@@ -76,6 +76,17 @@ static __be32 *xdr_encode_empty_array(__
+ * 1 Protocol"
+ */
+
++static void encode_uint32(struct xdr_stream *xdr, u32 n)
++{
++ WARN_ON_ONCE(xdr_stream_encode_u32(xdr, n) < 0);
++}
++
++static void encode_bitmap4(struct xdr_stream *xdr, const __u32 *bitmap,
++ size_t len)
++{
++ WARN_ON_ONCE(xdr_stream_encode_uint32_array(xdr, bitmap, len) < 0);
++}
++
+ /*
+ * nfs_cb_opnum4
+ *
+@@ -329,6 +340,24 @@ static void encode_cb_recall4args(struct
+ }
+
+ /*
++ * CB_RECALLANY4args
++ *
++ * struct CB_RECALLANY4args {
++ * uint32_t craa_objects_to_keep;
++ * bitmap4 craa_type_mask;
++ * };
++ */
++static void
++encode_cb_recallany4args(struct xdr_stream *xdr,
++ struct nfs4_cb_compound_hdr *hdr, struct nfsd4_cb_recall_any *ra)
++{
++ encode_nfs_cb_opnum4(xdr, OP_CB_RECALL_ANY);
++ encode_uint32(xdr, ra->ra_keep);
++ encode_bitmap4(xdr, ra->ra_bmval, ARRAY_SIZE(ra->ra_bmval));
++ hdr->nops++;
++}
++
++/*
+ * CB_SEQUENCE4args
+ *
+ * struct CB_SEQUENCE4args {
+@@ -482,6 +511,26 @@ static void nfs4_xdr_enc_cb_recall(struc
+ encode_cb_nops(&hdr);
+ }
+
++/*
++ * 20.6. Operation 8: CB_RECALL_ANY - Keep Any N Recallable Objects
++ */
++static void
++nfs4_xdr_enc_cb_recall_any(struct rpc_rqst *req,
++ struct xdr_stream *xdr, const void *data)
++{
++ const struct nfsd4_callback *cb = data;
++ struct nfsd4_cb_recall_any *ra;
++ struct nfs4_cb_compound_hdr hdr = {
++ .ident = cb->cb_clp->cl_cb_ident,
++ .minorversion = cb->cb_clp->cl_minorversion,
++ };
++
++ ra = container_of(cb, struct nfsd4_cb_recall_any, ra_cb);
++ encode_cb_compound4args(xdr, &hdr);
++ encode_cb_sequence4args(xdr, cb, &hdr);
++ encode_cb_recallany4args(xdr, &hdr, ra);
++ encode_cb_nops(&hdr);
++}
+
+ /*
+ * NFSv4.0 and NFSv4.1 XDR decode functions
+@@ -520,6 +569,28 @@ static int nfs4_xdr_dec_cb_recall(struct
+ return decode_cb_op_status(xdr, OP_CB_RECALL, &cb->cb_status);
+ }
+
++/*
++ * 20.6. Operation 8: CB_RECALL_ANY - Keep Any N Recallable Objects
++ */
++static int
++nfs4_xdr_dec_cb_recall_any(struct rpc_rqst *rqstp,
++ struct xdr_stream *xdr,
++ void *data)
++{
++ struct nfsd4_callback *cb = data;
++ struct nfs4_cb_compound_hdr hdr;
++ int status;
++
++ status = decode_cb_compound4res(xdr, &hdr);
++ if (unlikely(status))
++ return status;
++ status = decode_cb_sequence4res(xdr, cb);
++ if (unlikely(status || cb->cb_seq_status))
++ return status;
++ status = decode_cb_op_status(xdr, OP_CB_RECALL_ANY, &cb->cb_status);
++ return status;
++}
++
+ #ifdef CONFIG_NFSD_PNFS
+ /*
+ * CB_LAYOUTRECALL4args
+@@ -783,6 +854,7 @@ static const struct rpc_procinfo nfs4_cb
+ #endif
+ PROC(CB_NOTIFY_LOCK, COMPOUND, cb_notify_lock, cb_notify_lock),
+ PROC(CB_OFFLOAD, COMPOUND, cb_offload, cb_offload),
++ PROC(CB_RECALL_ANY, COMPOUND, cb_recall_any, cb_recall_any),
+ };
+
+ static unsigned int nfs4_cb_counts[ARRAY_SIZE(nfs4_cb_procedures)];
+--- a/fs/nfsd/state.h
++++ b/fs/nfsd/state.h
+@@ -636,6 +636,7 @@ enum nfsd4_cb_op {
+ NFSPROC4_CLNT_CB_OFFLOAD,
+ NFSPROC4_CLNT_CB_SEQUENCE,
+ NFSPROC4_CLNT_CB_NOTIFY_LOCK,
++ NFSPROC4_CLNT_CB_RECALL_ANY,
+ };
+
+ /* Returns true iff a is later than b: */
+--- a/fs/nfsd/xdr4.h
++++ b/fs/nfsd/xdr4.h
+@@ -896,5 +896,10 @@ struct nfsd4_operation {
+ union nfsd4_op_u *);
+ };
+
++struct nfsd4_cb_recall_any {
++ struct nfsd4_callback ra_cb;
++ u32 ra_keep;
++ u32 ra_bmval[1];
++};
+
+ #endif
+--- a/fs/nfsd/xdr4cb.h
++++ b/fs/nfsd/xdr4cb.h
+@@ -48,3 +48,9 @@
+ #define NFS4_dec_cb_offload_sz (cb_compound_dec_hdr_sz + \
+ cb_sequence_dec_sz + \
+ op_dec_sz)
++#define NFS4_enc_cb_recall_any_sz (cb_compound_enc_hdr_sz + \
++ cb_sequence_enc_sz + \
++ 1 + 1 + 1)
++#define NFS4_dec_cb_recall_any_sz (cb_compound_dec_hdr_sz + \
++ cb_sequence_dec_sz + \
++ op_dec_sz)
--- /dev/null
+From ca0bebbcc3bee825aa4f8768aca93a41aa076bbb Mon Sep 17 00:00:00 2001
+From: Jeff Layton <jlayton@kernel.org>
+Date: Tue, 18 Oct 2022 07:47:56 -0400
+Subject: nfsd: allow disabling NFSv2 at compile time
+
+From: Jeff Layton <jlayton@kernel.org>
+
+[ Upstream commit 2f3a4b2ac2f28b9be78ad21f401f31e263845214 ]
+
+rpc.nfsd stopped supporting NFSv2 a year ago. Take the next logical
+step toward deprecating it and allow NFSv2 support to be compiled out.
+
+Add a new CONFIG_NFSD_V2 option that can be turned off and rework the
+CONFIG_NFSD_V?_ACL option dependencies. Add a description that
+discourages enabling it.
+
+Also, change the description of CONFIG_NFSD to state that the always-on
+version is now 3 instead of 2.
+
+Finally, add an #ifdef around "case 2:" in __write_versions. When NFSv2
+is disabled at compile time, this should make the kernel ignore attempts
+to disable it at runtime, but still error out when trying to enable it.
+
+Signed-off-by: Jeff Layton <jlayton@kernel.org>
+Reviewed-by: Tom Talpey <tom@talpey.com>
+Signed-off-by: Chuck Lever <chuck.lever@oracle.com>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+---
+ fs/nfsd/Kconfig | 19 +++++++++++++++----
+ fs/nfsd/Makefile | 5 +++--
+ fs/nfsd/nfsctl.c | 2 ++
+ fs/nfsd/nfsd.h | 3 +--
+ fs/nfsd/nfssvc.c | 6 ++++++
+ 5 files changed, 27 insertions(+), 8 deletions(-)
+
+--- a/fs/nfsd/Kconfig
++++ b/fs/nfsd/Kconfig
+@@ -8,6 +8,7 @@ config NFSD
+ select SUNRPC
+ select EXPORTFS
+ select NFS_ACL_SUPPORT if NFSD_V2_ACL
++ select NFS_ACL_SUPPORT if NFSD_V3_ACL
+ depends on MULTIUSER
+ help
+ Choose Y here if you want to allow other computers to access
+@@ -26,19 +27,29 @@ config NFSD
+
+ Below you can choose which versions of the NFS protocol are
+ available to clients mounting the NFS server on this system.
+- Support for NFS version 2 (RFC 1094) is always available when
++ Support for NFS version 3 (RFC 1813) is always available when
+ CONFIG_NFSD is selected.
+
+ If unsure, say N.
+
+-config NFSD_V2_ACL
+- bool
++config NFSD_V2
++ bool "NFS server support for NFS version 2 (DEPRECATED)"
+ depends on NFSD
++ default n
++ help
++ NFSv2 (RFC 1094) was the first publicly-released version of NFS.
++ Unless you are hosting ancient (1990's era) NFS clients, you don't
++ need this.
++
++ If unsure, say N.
++
++config NFSD_V2_ACL
++ bool "NFS server support for the NFSv2 ACL protocol extension"
++ depends on NFSD_V2
+
+ config NFSD_V3_ACL
+ bool "NFS server support for the NFSv3 ACL protocol extension"
+ depends on NFSD
+- select NFSD_V2_ACL
+ help
+ Solaris NFS servers support an auxiliary NFSv3 ACL protocol that
+ never became an official part of the NFS version 3 protocol.
+--- a/fs/nfsd/Makefile
++++ b/fs/nfsd/Makefile
+@@ -10,9 +10,10 @@ obj-$(CONFIG_NFSD) += nfsd.o
+ # this one should be compiled first, as the tracing macros can easily blow up
+ nfsd-y += trace.o
+
+-nfsd-y += nfssvc.o nfsctl.o nfsproc.o nfsfh.o vfs.o \
+- export.o auth.o lockd.o nfscache.o nfsxdr.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
++nfsd-$(CONFIG_NFSD_V2) += nfsproc.o nfsxdr.o
+ nfsd-$(CONFIG_NFSD_V2_ACL) += nfs2acl.o
+ nfsd-$(CONFIG_NFSD_V3_ACL) += nfs3acl.o
+ nfsd-$(CONFIG_NFSD_V4) += nfs4proc.o nfs4xdr.o nfs4state.o nfs4idmap.o \
+--- a/fs/nfsd/nfsctl.c
++++ b/fs/nfsd/nfsctl.c
+@@ -581,7 +581,9 @@ static ssize_t __write_versions(struct f
+
+ cmd = sign == '-' ? NFSD_CLEAR : NFSD_SET;
+ switch(num) {
++#ifdef CONFIG_NFSD_V2
+ case 2:
++#endif
+ case 3:
+ nfsd_vers(nn, num, cmd);
+ break;
+--- a/fs/nfsd/nfsd.h
++++ b/fs/nfsd/nfsd.h
+@@ -64,8 +64,7 @@ struct readdir_cd {
+
+
+ extern struct svc_program nfsd_program;
+-extern const struct svc_version nfsd_version2, nfsd_version3,
+- nfsd_version4;
++extern const struct svc_version nfsd_version2, nfsd_version3, nfsd_version4;
+ extern struct mutex nfsd_mutex;
+ extern spinlock_t nfsd_drc_lock;
+ extern unsigned long nfsd_drc_max_mem;
+--- a/fs/nfsd/nfssvc.c
++++ b/fs/nfsd/nfssvc.c
+@@ -91,8 +91,12 @@ unsigned long nfsd_drc_mem_used;
+ #if defined(CONFIG_NFSD_V2_ACL) || defined(CONFIG_NFSD_V3_ACL)
+ static struct svc_stat nfsd_acl_svcstats;
+ static const struct svc_version *nfsd_acl_version[] = {
++# if defined(CONFIG_NFSD_V2_ACL)
+ [2] = &nfsd_acl_version2,
++# endif
++# if defined(CONFIG_NFSD_V3_ACL)
+ [3] = &nfsd_acl_version3,
++# endif
+ };
+
+ #define NFSD_ACL_MINVERS 2
+@@ -116,7 +120,9 @@ static struct svc_stat nfsd_acl_svcstats
+ #endif /* defined(CONFIG_NFSD_V2_ACL) || defined(CONFIG_NFSD_V3_ACL) */
+
+ static const struct svc_version *nfsd_version[] = {
++#if defined(CONFIG_NFSD_V2)
+ [2] = &nfsd_version2,
++#endif
+ [3] = &nfsd_version3,
+ #if defined(CONFIG_NFSD_V4)
+ [4] = &nfsd_version4,
--- /dev/null
+From deb43baeb013c36694511a8751b59a4c68170a29 Mon Sep 17 00:00:00 2001
+From: Kees Cook <keescook@chromium.org>
+Date: Fri, 2 Dec 2022 12:48:59 -0800
+Subject: NFSD: Avoid clashing function prototypes
+
+From: Kees Cook <keescook@chromium.org>
+
+[ Upstream commit e78e274eb22d966258a3845acc71d3c5b8ee2ea8 ]
+
+When built with Control Flow Integrity, function prototypes between
+caller and function declaration must match. These mismatches are visible
+at compile time with the new -Wcast-function-type-strict in Clang[1].
+
+There were 97 warnings produced by NFS. For example:
+
+fs/nfsd/nfs4xdr.c:2228:17: warning: cast from '__be32 (*)(struct nfsd4_compoundargs *, struct nfsd4_access *)' (aka 'unsigned int (*)(struct nfsd4_compoundargs *, struct nfsd4_access *)') to 'nfsd4_dec' (aka 'unsigned int (*)(struct nfsd4_compoundargs *, void *)') converts to incompatible function type [-Wcast-function-type-strict]
+ [OP_ACCESS] = (nfsd4_dec)nfsd4_decode_access,
+ ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+The enc/dec callbacks were defined as passing "void *" as the second
+argument, but were being implicitly cast to a new type. Replace the
+argument with union nfsd4_op_u, and perform explicit member selection
+in the function body. There are no resulting binary differences.
+
+Changes were made mechanically using the following Coccinelle script,
+with minor by-hand fixes for members that didn't already match their
+existing argument name:
+
+@find@
+identifier func;
+type T, opsT;
+identifier ops, N;
+@@
+
+ opsT ops[] = {
+ [N] = (T) func,
+ };
+
+@already_void@
+identifier find.func;
+identifier name;
+@@
+
+ func(...,
+-void
++union nfsd4_op_u
+ *name)
+ {
+ ...
+ }
+
+@proto depends on !already_void@
+identifier find.func;
+type T;
+identifier name;
+position p;
+@@
+
+ func@p(...,
+ T name
+ ) {
+ ...
+ }
+
+@script:python get_member@
+type_name << proto.T;
+member;
+@@
+
+coccinelle.member = cocci.make_ident(type_name.split("_", 1)[1].split(' ',1)[0])
+
+@convert@
+identifier find.func;
+type proto.T;
+identifier proto.name;
+position proto.p;
+identifier get_member.member;
+@@
+
+ func@p(...,
+- T name
++ union nfsd4_op_u *u
+ ) {
++ T name = &u->member;
+ ...
+ }
+
+@cast@
+identifier find.func;
+type T, opsT;
+identifier ops, N;
+@@
+
+ opsT ops[] = {
+ [N] =
+- (T)
+ func,
+ };
+
+Cc: Chuck Lever <chuck.lever@oracle.com>
+Cc: Jeff Layton <jlayton@kernel.org>
+Cc: Gustavo A. R. Silva <gustavoars@kernel.org>
+Cc: linux-nfs@vger.kernel.org
+Signed-off-by: Kees Cook <keescook@chromium.org>
+Signed-off-by: Chuck Lever <chuck.lever@oracle.com>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+---
+ fs/nfsd/nfs4xdr.c | 632 ++++++++++++++++++++++++++++++++----------------------
+ 1 file changed, 377 insertions(+), 255 deletions(-)
+
+--- a/fs/nfsd/nfs4xdr.c
++++ b/fs/nfsd/nfs4xdr.c
+@@ -770,16 +770,18 @@ nfsd4_decode_cb_sec(struct nfsd4_compoun
+
+ static __be32
+ nfsd4_decode_access(struct nfsd4_compoundargs *argp,
+- struct nfsd4_access *access)
++ union nfsd4_op_u *u)
+ {
++ struct nfsd4_access *access = &u->access;
+ if (xdr_stream_decode_u32(argp->xdr, &access->ac_req_access) < 0)
+ return nfserr_bad_xdr;
+ return nfs_ok;
+ }
+
+ static __be32
+-nfsd4_decode_close(struct nfsd4_compoundargs *argp, struct nfsd4_close *close)
++nfsd4_decode_close(struct nfsd4_compoundargs *argp, union nfsd4_op_u *u)
+ {
++ struct nfsd4_close *close = &u->close;
+ if (xdr_stream_decode_u32(argp->xdr, &close->cl_seqid) < 0)
+ return nfserr_bad_xdr;
+ return nfsd4_decode_stateid4(argp, &close->cl_stateid);
+@@ -787,8 +789,9 @@ nfsd4_decode_close(struct nfsd4_compound
+
+
+ static __be32
+-nfsd4_decode_commit(struct nfsd4_compoundargs *argp, struct nfsd4_commit *commit)
++nfsd4_decode_commit(struct nfsd4_compoundargs *argp, union nfsd4_op_u *u)
+ {
++ struct nfsd4_commit *commit = &u->commit;
+ if (xdr_stream_decode_u64(argp->xdr, &commit->co_offset) < 0)
+ return nfserr_bad_xdr;
+ if (xdr_stream_decode_u32(argp->xdr, &commit->co_count) < 0)
+@@ -798,8 +801,9 @@ nfsd4_decode_commit(struct nfsd4_compoun
+ }
+
+ static __be32
+-nfsd4_decode_create(struct nfsd4_compoundargs *argp, struct nfsd4_create *create)
++nfsd4_decode_create(struct nfsd4_compoundargs *argp, union nfsd4_op_u *u)
+ {
++ struct nfsd4_create *create = &u->create;
+ __be32 *p, status;
+
+ memset(create, 0, sizeof(*create));
+@@ -844,22 +848,25 @@ nfsd4_decode_create(struct nfsd4_compoun
+ }
+
+ static inline __be32
+-nfsd4_decode_delegreturn(struct nfsd4_compoundargs *argp, struct nfsd4_delegreturn *dr)
++nfsd4_decode_delegreturn(struct nfsd4_compoundargs *argp, union nfsd4_op_u *u)
+ {
++ struct nfsd4_delegreturn *dr = &u->delegreturn;
+ return nfsd4_decode_stateid4(argp, &dr->dr_stateid);
+ }
+
+ static inline __be32
+-nfsd4_decode_getattr(struct nfsd4_compoundargs *argp, struct nfsd4_getattr *getattr)
++nfsd4_decode_getattr(struct nfsd4_compoundargs *argp, union nfsd4_op_u *u)
+ {
++ struct nfsd4_getattr *getattr = &u->getattr;
+ memset(getattr, 0, sizeof(*getattr));
+ return nfsd4_decode_bitmap4(argp, getattr->ga_bmval,
+ ARRAY_SIZE(getattr->ga_bmval));
+ }
+
+ static __be32
+-nfsd4_decode_link(struct nfsd4_compoundargs *argp, struct nfsd4_link *link)
++nfsd4_decode_link(struct nfsd4_compoundargs *argp, union nfsd4_op_u *u)
+ {
++ struct nfsd4_link *link = &u->link;
+ memset(link, 0, sizeof(*link));
+ return nfsd4_decode_component4(argp, &link->li_name, &link->li_namelen);
+ }
+@@ -907,8 +914,9 @@ nfsd4_decode_locker4(struct nfsd4_compou
+ }
+
+ static __be32
+-nfsd4_decode_lock(struct nfsd4_compoundargs *argp, struct nfsd4_lock *lock)
++nfsd4_decode_lock(struct nfsd4_compoundargs *argp, union nfsd4_op_u *u)
+ {
++ struct nfsd4_lock *lock = &u->lock;
+ memset(lock, 0, sizeof(*lock));
+ if (xdr_stream_decode_u32(argp->xdr, &lock->lk_type) < 0)
+ return nfserr_bad_xdr;
+@@ -924,8 +932,9 @@ nfsd4_decode_lock(struct nfsd4_compounda
+ }
+
+ static __be32
+-nfsd4_decode_lockt(struct nfsd4_compoundargs *argp, struct nfsd4_lockt *lockt)
++nfsd4_decode_lockt(struct nfsd4_compoundargs *argp, union nfsd4_op_u *u)
+ {
++ struct nfsd4_lockt *lockt = &u->lockt;
+ memset(lockt, 0, sizeof(*lockt));
+ if (xdr_stream_decode_u32(argp->xdr, &lockt->lt_type) < 0)
+ return nfserr_bad_xdr;
+@@ -940,8 +949,9 @@ nfsd4_decode_lockt(struct nfsd4_compound
+ }
+
+ static __be32
+-nfsd4_decode_locku(struct nfsd4_compoundargs *argp, struct nfsd4_locku *locku)
++nfsd4_decode_locku(struct nfsd4_compoundargs *argp, union nfsd4_op_u *u)
+ {
++ struct nfsd4_locku *locku = &u->locku;
+ __be32 status;
+
+ if (xdr_stream_decode_u32(argp->xdr, &locku->lu_type) < 0)
+@@ -962,8 +972,9 @@ nfsd4_decode_locku(struct nfsd4_compound
+ }
+
+ static __be32
+-nfsd4_decode_lookup(struct nfsd4_compoundargs *argp, struct nfsd4_lookup *lookup)
++nfsd4_decode_lookup(struct nfsd4_compoundargs *argp, union nfsd4_op_u *u)
+ {
++ struct nfsd4_lookup *lookup = &u->lookup;
+ return nfsd4_decode_component4(argp, &lookup->lo_name, &lookup->lo_len);
+ }
+
+@@ -1143,8 +1154,9 @@ nfsd4_decode_open_claim4(struct nfsd4_co
+ }
+
+ static __be32
+-nfsd4_decode_open(struct nfsd4_compoundargs *argp, struct nfsd4_open *open)
++nfsd4_decode_open(struct nfsd4_compoundargs *argp, union nfsd4_op_u *u)
+ {
++ struct nfsd4_open *open = &u->open;
+ __be32 status;
+ u32 dummy;
+
+@@ -1171,8 +1183,10 @@ nfsd4_decode_open(struct nfsd4_compounda
+ }
+
+ static __be32
+-nfsd4_decode_open_confirm(struct nfsd4_compoundargs *argp, struct nfsd4_open_confirm *open_conf)
++nfsd4_decode_open_confirm(struct nfsd4_compoundargs *argp,
++ union nfsd4_op_u *u)
+ {
++ struct nfsd4_open_confirm *open_conf = &u->open_confirm;
+ __be32 status;
+
+ if (argp->minorversion >= 1)
+@@ -1190,8 +1204,10 @@ nfsd4_decode_open_confirm(struct nfsd4_c
+ }
+
+ static __be32
+-nfsd4_decode_open_downgrade(struct nfsd4_compoundargs *argp, struct nfsd4_open_downgrade *open_down)
++nfsd4_decode_open_downgrade(struct nfsd4_compoundargs *argp,
++ union nfsd4_op_u *u)
+ {
++ struct nfsd4_open_downgrade *open_down = &u->open_downgrade;
+ __be32 status;
+
+ memset(open_down, 0, sizeof(*open_down));
+@@ -1209,8 +1225,9 @@ nfsd4_decode_open_downgrade(struct nfsd4
+ }
+
+ static __be32
+-nfsd4_decode_putfh(struct nfsd4_compoundargs *argp, struct nfsd4_putfh *putfh)
++nfsd4_decode_putfh(struct nfsd4_compoundargs *argp, union nfsd4_op_u *u)
+ {
++ struct nfsd4_putfh *putfh = &u->putfh;
+ __be32 *p;
+
+ if (xdr_stream_decode_u32(argp->xdr, &putfh->pf_fhlen) < 0)
+@@ -1229,7 +1246,7 @@ nfsd4_decode_putfh(struct nfsd4_compound
+ }
+
+ static __be32
+-nfsd4_decode_putpubfh(struct nfsd4_compoundargs *argp, void *p)
++nfsd4_decode_putpubfh(struct nfsd4_compoundargs *argp, union nfsd4_op_u *p)
+ {
+ if (argp->minorversion == 0)
+ return nfs_ok;
+@@ -1237,8 +1254,9 @@ nfsd4_decode_putpubfh(struct nfsd4_compo
+ }
+
+ static __be32
+-nfsd4_decode_read(struct nfsd4_compoundargs *argp, struct nfsd4_read *read)
++nfsd4_decode_read(struct nfsd4_compoundargs *argp, union nfsd4_op_u *u)
+ {
++ struct nfsd4_read *read = &u->read;
+ __be32 status;
+
+ memset(read, 0, sizeof(*read));
+@@ -1254,8 +1272,9 @@ nfsd4_decode_read(struct nfsd4_compounda
+ }
+
+ static __be32
+-nfsd4_decode_readdir(struct nfsd4_compoundargs *argp, struct nfsd4_readdir *readdir)
++nfsd4_decode_readdir(struct nfsd4_compoundargs *argp, union nfsd4_op_u *u)
+ {
++ struct nfsd4_readdir *readdir = &u->readdir;
+ __be32 status;
+
+ memset(readdir, 0, sizeof(*readdir));
+@@ -1276,15 +1295,17 @@ nfsd4_decode_readdir(struct nfsd4_compou
+ }
+
+ static __be32
+-nfsd4_decode_remove(struct nfsd4_compoundargs *argp, struct nfsd4_remove *remove)
++nfsd4_decode_remove(struct nfsd4_compoundargs *argp, union nfsd4_op_u *u)
+ {
++ struct nfsd4_remove *remove = &u->remove;
+ memset(&remove->rm_cinfo, 0, sizeof(remove->rm_cinfo));
+ return nfsd4_decode_component4(argp, &remove->rm_name, &remove->rm_namelen);
+ }
+
+ static __be32
+-nfsd4_decode_rename(struct nfsd4_compoundargs *argp, struct nfsd4_rename *rename)
++nfsd4_decode_rename(struct nfsd4_compoundargs *argp, union nfsd4_op_u *u)
+ {
++ struct nfsd4_rename *rename = &u->rename;
+ __be32 status;
+
+ memset(rename, 0, sizeof(*rename));
+@@ -1295,22 +1316,25 @@ nfsd4_decode_rename(struct nfsd4_compoun
+ }
+
+ static __be32
+-nfsd4_decode_renew(struct nfsd4_compoundargs *argp, clientid_t *clientid)
++nfsd4_decode_renew(struct nfsd4_compoundargs *argp, union nfsd4_op_u *u)
+ {
++ clientid_t *clientid = &u->renew;
+ return nfsd4_decode_clientid4(argp, clientid);
+ }
+
+ static __be32
+ nfsd4_decode_secinfo(struct nfsd4_compoundargs *argp,
+- struct nfsd4_secinfo *secinfo)
++ union nfsd4_op_u *u)
+ {
++ struct nfsd4_secinfo *secinfo = &u->secinfo;
+ secinfo->si_exp = NULL;
+ return nfsd4_decode_component4(argp, &secinfo->si_name, &secinfo->si_namelen);
+ }
+
+ static __be32
+-nfsd4_decode_setattr(struct nfsd4_compoundargs *argp, struct nfsd4_setattr *setattr)
++nfsd4_decode_setattr(struct nfsd4_compoundargs *argp, union nfsd4_op_u *u)
+ {
++ struct nfsd4_setattr *setattr = &u->setattr;
+ __be32 status;
+
+ memset(setattr, 0, sizeof(*setattr));
+@@ -1324,8 +1348,9 @@ nfsd4_decode_setattr(struct nfsd4_compou
+ }
+
+ static __be32
+-nfsd4_decode_setclientid(struct nfsd4_compoundargs *argp, struct nfsd4_setclientid *setclientid)
++nfsd4_decode_setclientid(struct nfsd4_compoundargs *argp, union nfsd4_op_u *u)
+ {
++ struct nfsd4_setclientid *setclientid = &u->setclientid;
+ __be32 *p, status;
+
+ memset(setclientid, 0, sizeof(*setclientid));
+@@ -1367,8 +1392,10 @@ nfsd4_decode_setclientid(struct nfsd4_co
+ }
+
+ static __be32
+-nfsd4_decode_setclientid_confirm(struct nfsd4_compoundargs *argp, struct nfsd4_setclientid_confirm *scd_c)
++nfsd4_decode_setclientid_confirm(struct nfsd4_compoundargs *argp,
++ union nfsd4_op_u *u)
+ {
++ struct nfsd4_setclientid_confirm *scd_c = &u->setclientid_confirm;
+ __be32 status;
+
+ if (argp->minorversion >= 1)
+@@ -1382,8 +1409,9 @@ nfsd4_decode_setclientid_confirm(struct
+
+ /* Also used for NVERIFY */
+ static __be32
+-nfsd4_decode_verify(struct nfsd4_compoundargs *argp, struct nfsd4_verify *verify)
++nfsd4_decode_verify(struct nfsd4_compoundargs *argp, union nfsd4_op_u *u)
+ {
++ struct nfsd4_verify *verify = &u->verify;
+ __be32 *p, status;
+
+ memset(verify, 0, sizeof(*verify));
+@@ -1409,8 +1437,9 @@ nfsd4_decode_verify(struct nfsd4_compoun
+ }
+
+ static __be32
+-nfsd4_decode_write(struct nfsd4_compoundargs *argp, struct nfsd4_write *write)
++nfsd4_decode_write(struct nfsd4_compoundargs *argp, union nfsd4_op_u *u)
+ {
++ struct nfsd4_write *write = &u->write;
+ __be32 status;
+
+ status = nfsd4_decode_stateid4(argp, &write->wr_stateid);
+@@ -1434,8 +1463,10 @@ nfsd4_decode_write(struct nfsd4_compound
+ }
+
+ static __be32
+-nfsd4_decode_release_lockowner(struct nfsd4_compoundargs *argp, struct nfsd4_release_lockowner *rlockowner)
++nfsd4_decode_release_lockowner(struct nfsd4_compoundargs *argp,
++ union nfsd4_op_u *u)
+ {
++ struct nfsd4_release_lockowner *rlockowner = &u->release_lockowner;
+ __be32 status;
+
+ if (argp->minorversion >= 1)
+@@ -1452,16 +1483,20 @@ nfsd4_decode_release_lockowner(struct nf
+ return nfs_ok;
+ }
+
+-static __be32 nfsd4_decode_backchannel_ctl(struct nfsd4_compoundargs *argp, struct nfsd4_backchannel_ctl *bc)
++static __be32 nfsd4_decode_backchannel_ctl(struct nfsd4_compoundargs *argp,
++ union nfsd4_op_u *u)
+ {
++ struct nfsd4_backchannel_ctl *bc = &u->backchannel_ctl;
+ memset(bc, 0, sizeof(*bc));
+ if (xdr_stream_decode_u32(argp->xdr, &bc->bc_cb_program) < 0)
+ return nfserr_bad_xdr;
+ return nfsd4_decode_cb_sec(argp, &bc->bc_cb_sec);
+ }
+
+-static __be32 nfsd4_decode_bind_conn_to_session(struct nfsd4_compoundargs *argp, struct nfsd4_bind_conn_to_session *bcts)
++static __be32 nfsd4_decode_bind_conn_to_session(struct nfsd4_compoundargs *argp,
++ union nfsd4_op_u *u)
+ {
++ struct nfsd4_bind_conn_to_session *bcts = &u->bind_conn_to_session;
+ u32 use_conn_in_rdma_mode;
+ __be32 status;
+
+@@ -1603,8 +1638,9 @@ nfsd4_decode_nfs_impl_id4(struct nfsd4_c
+
+ static __be32
+ nfsd4_decode_exchange_id(struct nfsd4_compoundargs *argp,
+- struct nfsd4_exchange_id *exid)
++ union nfsd4_op_u *u)
+ {
++ struct nfsd4_exchange_id *exid = &u->exchange_id;
+ __be32 status;
+
+ memset(exid, 0, sizeof(*exid));
+@@ -1656,8 +1692,9 @@ nfsd4_decode_channel_attrs4(struct nfsd4
+
+ static __be32
+ nfsd4_decode_create_session(struct nfsd4_compoundargs *argp,
+- struct nfsd4_create_session *sess)
++ union nfsd4_op_u *u)
+ {
++ struct nfsd4_create_session *sess = &u->create_session;
+ __be32 status;
+
+ memset(sess, 0, sizeof(*sess));
+@@ -1681,23 +1718,26 @@ nfsd4_decode_create_session(struct nfsd4
+
+ static __be32
+ nfsd4_decode_destroy_session(struct nfsd4_compoundargs *argp,
+- struct nfsd4_destroy_session *destroy_session)
++ union nfsd4_op_u *u)
+ {
++ struct nfsd4_destroy_session *destroy_session = &u->destroy_session;
+ return nfsd4_decode_sessionid4(argp, &destroy_session->sessionid);
+ }
+
+ static __be32
+ nfsd4_decode_free_stateid(struct nfsd4_compoundargs *argp,
+- struct nfsd4_free_stateid *free_stateid)
++ union nfsd4_op_u *u)
+ {
++ struct nfsd4_free_stateid *free_stateid = &u->free_stateid;
+ return nfsd4_decode_stateid4(argp, &free_stateid->fr_stateid);
+ }
+
+ #ifdef CONFIG_NFSD_PNFS
+ static __be32
+ nfsd4_decode_getdeviceinfo(struct nfsd4_compoundargs *argp,
+- struct nfsd4_getdeviceinfo *gdev)
++ union nfsd4_op_u *u)
+ {
++ struct nfsd4_getdeviceinfo *gdev = &u->getdeviceinfo;
+ __be32 status;
+
+ memset(gdev, 0, sizeof(*gdev));
+@@ -1717,8 +1757,9 @@ nfsd4_decode_getdeviceinfo(struct nfsd4_
+
+ static __be32
+ nfsd4_decode_layoutcommit(struct nfsd4_compoundargs *argp,
+- struct nfsd4_layoutcommit *lcp)
++ union nfsd4_op_u *u)
+ {
++ struct nfsd4_layoutcommit *lcp = &u->layoutcommit;
+ __be32 *p, status;
+
+ memset(lcp, 0, sizeof(*lcp));
+@@ -1753,8 +1794,9 @@ nfsd4_decode_layoutcommit(struct nfsd4_c
+
+ static __be32
+ nfsd4_decode_layoutget(struct nfsd4_compoundargs *argp,
+- struct nfsd4_layoutget *lgp)
++ union nfsd4_op_u *u)
+ {
++ struct nfsd4_layoutget *lgp = &u->layoutget;
+ __be32 status;
+
+ memset(lgp, 0, sizeof(*lgp));
+@@ -1781,8 +1823,9 @@ nfsd4_decode_layoutget(struct nfsd4_comp
+
+ static __be32
+ nfsd4_decode_layoutreturn(struct nfsd4_compoundargs *argp,
+- struct nfsd4_layoutreturn *lrp)
++ union nfsd4_op_u *u)
+ {
++ struct nfsd4_layoutreturn *lrp = &u->layoutreturn;
+ memset(lrp, 0, sizeof(*lrp));
+ if (xdr_stream_decode_bool(argp->xdr, &lrp->lr_reclaim) < 0)
+ return nfserr_bad_xdr;
+@@ -1795,8 +1838,9 @@ nfsd4_decode_layoutreturn(struct nfsd4_c
+ #endif /* CONFIG_NFSD_PNFS */
+
+ static __be32 nfsd4_decode_secinfo_no_name(struct nfsd4_compoundargs *argp,
+- struct nfsd4_secinfo_no_name *sin)
++ union nfsd4_op_u *u)
+ {
++ struct nfsd4_secinfo_no_name *sin = &u->secinfo_no_name;
+ if (xdr_stream_decode_u32(argp->xdr, &sin->sin_style) < 0)
+ return nfserr_bad_xdr;
+
+@@ -1806,8 +1850,9 @@ static __be32 nfsd4_decode_secinfo_no_na
+
+ static __be32
+ nfsd4_decode_sequence(struct nfsd4_compoundargs *argp,
+- struct nfsd4_sequence *seq)
++ union nfsd4_op_u *u)
+ {
++ struct nfsd4_sequence *seq = &u->sequence;
+ __be32 *p, status;
+
+ status = nfsd4_decode_sessionid4(argp, &seq->sessionid);
+@@ -1826,8 +1871,10 @@ nfsd4_decode_sequence(struct nfsd4_compo
+ }
+
+ static __be32
+-nfsd4_decode_test_stateid(struct nfsd4_compoundargs *argp, struct nfsd4_test_stateid *test_stateid)
++nfsd4_decode_test_stateid(struct nfsd4_compoundargs *argp,
++ union nfsd4_op_u *u)
+ {
++ struct nfsd4_test_stateid *test_stateid = &u->test_stateid;
+ struct nfsd4_test_stateid_id *stateid;
+ __be32 status;
+ u32 i;
+@@ -1852,14 +1899,16 @@ nfsd4_decode_test_stateid(struct nfsd4_c
+ }
+
+ static __be32 nfsd4_decode_destroy_clientid(struct nfsd4_compoundargs *argp,
+- struct nfsd4_destroy_clientid *dc)
++ union nfsd4_op_u *u)
+ {
++ struct nfsd4_destroy_clientid *dc = &u->destroy_clientid;
+ return nfsd4_decode_clientid4(argp, &dc->clientid);
+ }
+
+ static __be32 nfsd4_decode_reclaim_complete(struct nfsd4_compoundargs *argp,
+- struct nfsd4_reclaim_complete *rc)
++ union nfsd4_op_u *u)
+ {
++ struct nfsd4_reclaim_complete *rc = &u->reclaim_complete;
+ if (xdr_stream_decode_bool(argp->xdr, &rc->rca_one_fs) < 0)
+ return nfserr_bad_xdr;
+ return nfs_ok;
+@@ -1867,8 +1916,9 @@ static __be32 nfsd4_decode_reclaim_compl
+
+ static __be32
+ nfsd4_decode_fallocate(struct nfsd4_compoundargs *argp,
+- struct nfsd4_fallocate *fallocate)
++ union nfsd4_op_u *u)
+ {
++ struct nfsd4_fallocate *fallocate = &u->allocate;
+ __be32 status;
+
+ status = nfsd4_decode_stateid4(argp, &fallocate->falloc_stateid);
+@@ -1924,8 +1974,9 @@ static __be32 nfsd4_decode_nl4_server(st
+ }
+
+ static __be32
+-nfsd4_decode_copy(struct nfsd4_compoundargs *argp, struct nfsd4_copy *copy)
++nfsd4_decode_copy(struct nfsd4_compoundargs *argp, union nfsd4_op_u *u)
+ {
++ struct nfsd4_copy *copy = &u->copy;
+ u32 consecutive, i, count, sync;
+ struct nl4_server *ns_dummy;
+ __be32 status;
+@@ -1982,8 +2033,9 @@ nfsd4_decode_copy(struct nfsd4_compounda
+
+ static __be32
+ nfsd4_decode_copy_notify(struct nfsd4_compoundargs *argp,
+- struct nfsd4_copy_notify *cn)
++ union nfsd4_op_u *u)
+ {
++ struct nfsd4_copy_notify *cn = &u->copy_notify;
+ __be32 status;
+
+ memset(cn, 0, sizeof(*cn));
+@@ -2002,16 +2054,18 @@ nfsd4_decode_copy_notify(struct nfsd4_co
+
+ static __be32
+ nfsd4_decode_offload_status(struct nfsd4_compoundargs *argp,
+- struct nfsd4_offload_status *os)
++ union nfsd4_op_u *u)
+ {
++ struct nfsd4_offload_status *os = &u->offload_status;
+ os->count = 0;
+ os->status = 0;
+ return nfsd4_decode_stateid4(argp, &os->stateid);
+ }
+
+ static __be32
+-nfsd4_decode_seek(struct nfsd4_compoundargs *argp, struct nfsd4_seek *seek)
++nfsd4_decode_seek(struct nfsd4_compoundargs *argp, union nfsd4_op_u *u)
+ {
++ struct nfsd4_seek *seek = &u->seek;
+ __be32 status;
+
+ status = nfsd4_decode_stateid4(argp, &seek->seek_stateid);
+@@ -2028,8 +2082,9 @@ nfsd4_decode_seek(struct nfsd4_compounda
+ }
+
+ static __be32
+-nfsd4_decode_clone(struct nfsd4_compoundargs *argp, struct nfsd4_clone *clone)
++nfsd4_decode_clone(struct nfsd4_compoundargs *argp, union nfsd4_op_u *u)
+ {
++ struct nfsd4_clone *clone = &u->clone;
+ __be32 status;
+
+ status = nfsd4_decode_stateid4(argp, &clone->cl_src_stateid);
+@@ -2154,8 +2209,9 @@ nfsd4_decode_xattr_name(struct nfsd4_com
+ */
+ static __be32
+ nfsd4_decode_getxattr(struct nfsd4_compoundargs *argp,
+- struct nfsd4_getxattr *getxattr)
++ union nfsd4_op_u *u)
+ {
++ struct nfsd4_getxattr *getxattr = &u->getxattr;
+ __be32 status;
+ u32 maxcount;
+
+@@ -2173,8 +2229,9 @@ nfsd4_decode_getxattr(struct nfsd4_compo
+
+ static __be32
+ nfsd4_decode_setxattr(struct nfsd4_compoundargs *argp,
+- struct nfsd4_setxattr *setxattr)
++ union nfsd4_op_u *u)
+ {
++ struct nfsd4_setxattr *setxattr = &u->setxattr;
+ u32 flags, maxcount, size;
+ __be32 status;
+
+@@ -2214,8 +2271,9 @@ nfsd4_decode_setxattr(struct nfsd4_compo
+
+ static __be32
+ nfsd4_decode_listxattrs(struct nfsd4_compoundargs *argp,
+- struct nfsd4_listxattrs *listxattrs)
++ union nfsd4_op_u *u)
+ {
++ struct nfsd4_listxattrs *listxattrs = &u->listxattrs;
+ u32 maxcount;
+
+ memset(listxattrs, 0, sizeof(*listxattrs));
+@@ -2245,113 +2303,114 @@ nfsd4_decode_listxattrs(struct nfsd4_com
+
+ static __be32
+ nfsd4_decode_removexattr(struct nfsd4_compoundargs *argp,
+- struct nfsd4_removexattr *removexattr)
++ union nfsd4_op_u *u)
+ {
++ struct nfsd4_removexattr *removexattr = &u->removexattr;
+ memset(removexattr, 0, sizeof(*removexattr));
+ return nfsd4_decode_xattr_name(argp, &removexattr->rmxa_name);
+ }
+
+ static __be32
+-nfsd4_decode_noop(struct nfsd4_compoundargs *argp, void *p)
++nfsd4_decode_noop(struct nfsd4_compoundargs *argp, union nfsd4_op_u *p)
+ {
+ return nfs_ok;
+ }
+
+ static __be32
+-nfsd4_decode_notsupp(struct nfsd4_compoundargs *argp, void *p)
++nfsd4_decode_notsupp(struct nfsd4_compoundargs *argp, union nfsd4_op_u *p)
+ {
+ return nfserr_notsupp;
+ }
+
+-typedef __be32(*nfsd4_dec)(struct nfsd4_compoundargs *argp, void *);
++typedef __be32(*nfsd4_dec)(struct nfsd4_compoundargs *argp, union nfsd4_op_u *u);
+
+ static const nfsd4_dec nfsd4_dec_ops[] = {
+- [OP_ACCESS] = (nfsd4_dec)nfsd4_decode_access,
+- [OP_CLOSE] = (nfsd4_dec)nfsd4_decode_close,
+- [OP_COMMIT] = (nfsd4_dec)nfsd4_decode_commit,
+- [OP_CREATE] = (nfsd4_dec)nfsd4_decode_create,
+- [OP_DELEGPURGE] = (nfsd4_dec)nfsd4_decode_notsupp,
+- [OP_DELEGRETURN] = (nfsd4_dec)nfsd4_decode_delegreturn,
+- [OP_GETATTR] = (nfsd4_dec)nfsd4_decode_getattr,
+- [OP_GETFH] = (nfsd4_dec)nfsd4_decode_noop,
+- [OP_LINK] = (nfsd4_dec)nfsd4_decode_link,
+- [OP_LOCK] = (nfsd4_dec)nfsd4_decode_lock,
+- [OP_LOCKT] = (nfsd4_dec)nfsd4_decode_lockt,
+- [OP_LOCKU] = (nfsd4_dec)nfsd4_decode_locku,
+- [OP_LOOKUP] = (nfsd4_dec)nfsd4_decode_lookup,
+- [OP_LOOKUPP] = (nfsd4_dec)nfsd4_decode_noop,
+- [OP_NVERIFY] = (nfsd4_dec)nfsd4_decode_verify,
+- [OP_OPEN] = (nfsd4_dec)nfsd4_decode_open,
+- [OP_OPENATTR] = (nfsd4_dec)nfsd4_decode_notsupp,
+- [OP_OPEN_CONFIRM] = (nfsd4_dec)nfsd4_decode_open_confirm,
+- [OP_OPEN_DOWNGRADE] = (nfsd4_dec)nfsd4_decode_open_downgrade,
+- [OP_PUTFH] = (nfsd4_dec)nfsd4_decode_putfh,
+- [OP_PUTPUBFH] = (nfsd4_dec)nfsd4_decode_putpubfh,
+- [OP_PUTROOTFH] = (nfsd4_dec)nfsd4_decode_noop,
+- [OP_READ] = (nfsd4_dec)nfsd4_decode_read,
+- [OP_READDIR] = (nfsd4_dec)nfsd4_decode_readdir,
+- [OP_READLINK] = (nfsd4_dec)nfsd4_decode_noop,
+- [OP_REMOVE] = (nfsd4_dec)nfsd4_decode_remove,
+- [OP_RENAME] = (nfsd4_dec)nfsd4_decode_rename,
+- [OP_RENEW] = (nfsd4_dec)nfsd4_decode_renew,
+- [OP_RESTOREFH] = (nfsd4_dec)nfsd4_decode_noop,
+- [OP_SAVEFH] = (nfsd4_dec)nfsd4_decode_noop,
+- [OP_SECINFO] = (nfsd4_dec)nfsd4_decode_secinfo,
+- [OP_SETATTR] = (nfsd4_dec)nfsd4_decode_setattr,
+- [OP_SETCLIENTID] = (nfsd4_dec)nfsd4_decode_setclientid,
+- [OP_SETCLIENTID_CONFIRM] = (nfsd4_dec)nfsd4_decode_setclientid_confirm,
+- [OP_VERIFY] = (nfsd4_dec)nfsd4_decode_verify,
+- [OP_WRITE] = (nfsd4_dec)nfsd4_decode_write,
+- [OP_RELEASE_LOCKOWNER] = (nfsd4_dec)nfsd4_decode_release_lockowner,
++ [OP_ACCESS] = nfsd4_decode_access,
++ [OP_CLOSE] = nfsd4_decode_close,
++ [OP_COMMIT] = nfsd4_decode_commit,
++ [OP_CREATE] = nfsd4_decode_create,
++ [OP_DELEGPURGE] = nfsd4_decode_notsupp,
++ [OP_DELEGRETURN] = nfsd4_decode_delegreturn,
++ [OP_GETATTR] = nfsd4_decode_getattr,
++ [OP_GETFH] = nfsd4_decode_noop,
++ [OP_LINK] = nfsd4_decode_link,
++ [OP_LOCK] = nfsd4_decode_lock,
++ [OP_LOCKT] = nfsd4_decode_lockt,
++ [OP_LOCKU] = nfsd4_decode_locku,
++ [OP_LOOKUP] = nfsd4_decode_lookup,
++ [OP_LOOKUPP] = nfsd4_decode_noop,
++ [OP_NVERIFY] = nfsd4_decode_verify,
++ [OP_OPEN] = nfsd4_decode_open,
++ [OP_OPENATTR] = nfsd4_decode_notsupp,
++ [OP_OPEN_CONFIRM] = nfsd4_decode_open_confirm,
++ [OP_OPEN_DOWNGRADE] = nfsd4_decode_open_downgrade,
++ [OP_PUTFH] = nfsd4_decode_putfh,
++ [OP_PUTPUBFH] = nfsd4_decode_putpubfh,
++ [OP_PUTROOTFH] = nfsd4_decode_noop,
++ [OP_READ] = nfsd4_decode_read,
++ [OP_READDIR] = nfsd4_decode_readdir,
++ [OP_READLINK] = nfsd4_decode_noop,
++ [OP_REMOVE] = nfsd4_decode_remove,
++ [OP_RENAME] = nfsd4_decode_rename,
++ [OP_RENEW] = nfsd4_decode_renew,
++ [OP_RESTOREFH] = nfsd4_decode_noop,
++ [OP_SAVEFH] = nfsd4_decode_noop,
++ [OP_SECINFO] = nfsd4_decode_secinfo,
++ [OP_SETATTR] = nfsd4_decode_setattr,
++ [OP_SETCLIENTID] = nfsd4_decode_setclientid,
++ [OP_SETCLIENTID_CONFIRM] = nfsd4_decode_setclientid_confirm,
++ [OP_VERIFY] = nfsd4_decode_verify,
++ [OP_WRITE] = nfsd4_decode_write,
++ [OP_RELEASE_LOCKOWNER] = nfsd4_decode_release_lockowner,
+
+ /* new operations for NFSv4.1 */
+- [OP_BACKCHANNEL_CTL] = (nfsd4_dec)nfsd4_decode_backchannel_ctl,
+- [OP_BIND_CONN_TO_SESSION]= (nfsd4_dec)nfsd4_decode_bind_conn_to_session,
+- [OP_EXCHANGE_ID] = (nfsd4_dec)nfsd4_decode_exchange_id,
+- [OP_CREATE_SESSION] = (nfsd4_dec)nfsd4_decode_create_session,
+- [OP_DESTROY_SESSION] = (nfsd4_dec)nfsd4_decode_destroy_session,
+- [OP_FREE_STATEID] = (nfsd4_dec)nfsd4_decode_free_stateid,
+- [OP_GET_DIR_DELEGATION] = (nfsd4_dec)nfsd4_decode_notsupp,
++ [OP_BACKCHANNEL_CTL] = nfsd4_decode_backchannel_ctl,
++ [OP_BIND_CONN_TO_SESSION] = nfsd4_decode_bind_conn_to_session,
++ [OP_EXCHANGE_ID] = nfsd4_decode_exchange_id,
++ [OP_CREATE_SESSION] = nfsd4_decode_create_session,
++ [OP_DESTROY_SESSION] = nfsd4_decode_destroy_session,
++ [OP_FREE_STATEID] = nfsd4_decode_free_stateid,
++ [OP_GET_DIR_DELEGATION] = nfsd4_decode_notsupp,
+ #ifdef CONFIG_NFSD_PNFS
+- [OP_GETDEVICEINFO] = (nfsd4_dec)nfsd4_decode_getdeviceinfo,
+- [OP_GETDEVICELIST] = (nfsd4_dec)nfsd4_decode_notsupp,
+- [OP_LAYOUTCOMMIT] = (nfsd4_dec)nfsd4_decode_layoutcommit,
+- [OP_LAYOUTGET] = (nfsd4_dec)nfsd4_decode_layoutget,
+- [OP_LAYOUTRETURN] = (nfsd4_dec)nfsd4_decode_layoutreturn,
++ [OP_GETDEVICEINFO] = nfsd4_decode_getdeviceinfo,
++ [OP_GETDEVICELIST] = nfsd4_decode_notsupp,
++ [OP_LAYOUTCOMMIT] = nfsd4_decode_layoutcommit,
++ [OP_LAYOUTGET] = nfsd4_decode_layoutget,
++ [OP_LAYOUTRETURN] = nfsd4_decode_layoutreturn,
+ #else
+- [OP_GETDEVICEINFO] = (nfsd4_dec)nfsd4_decode_notsupp,
+- [OP_GETDEVICELIST] = (nfsd4_dec)nfsd4_decode_notsupp,
+- [OP_LAYOUTCOMMIT] = (nfsd4_dec)nfsd4_decode_notsupp,
+- [OP_LAYOUTGET] = (nfsd4_dec)nfsd4_decode_notsupp,
+- [OP_LAYOUTRETURN] = (nfsd4_dec)nfsd4_decode_notsupp,
++ [OP_GETDEVICEINFO] = nfsd4_decode_notsupp,
++ [OP_GETDEVICELIST] = nfsd4_decode_notsupp,
++ [OP_LAYOUTCOMMIT] = nfsd4_decode_notsupp,
++ [OP_LAYOUTGET] = nfsd4_decode_notsupp,
++ [OP_LAYOUTRETURN] = nfsd4_decode_notsupp,
+ #endif
+- [OP_SECINFO_NO_NAME] = (nfsd4_dec)nfsd4_decode_secinfo_no_name,
+- [OP_SEQUENCE] = (nfsd4_dec)nfsd4_decode_sequence,
+- [OP_SET_SSV] = (nfsd4_dec)nfsd4_decode_notsupp,
+- [OP_TEST_STATEID] = (nfsd4_dec)nfsd4_decode_test_stateid,
+- [OP_WANT_DELEGATION] = (nfsd4_dec)nfsd4_decode_notsupp,
+- [OP_DESTROY_CLIENTID] = (nfsd4_dec)nfsd4_decode_destroy_clientid,
+- [OP_RECLAIM_COMPLETE] = (nfsd4_dec)nfsd4_decode_reclaim_complete,
++ [OP_SECINFO_NO_NAME] = nfsd4_decode_secinfo_no_name,
++ [OP_SEQUENCE] = nfsd4_decode_sequence,
++ [OP_SET_SSV] = nfsd4_decode_notsupp,
++ [OP_TEST_STATEID] = nfsd4_decode_test_stateid,
++ [OP_WANT_DELEGATION] = nfsd4_decode_notsupp,
++ [OP_DESTROY_CLIENTID] = nfsd4_decode_destroy_clientid,
++ [OP_RECLAIM_COMPLETE] = nfsd4_decode_reclaim_complete,
+
+ /* new operations for NFSv4.2 */
+- [OP_ALLOCATE] = (nfsd4_dec)nfsd4_decode_fallocate,
+- [OP_COPY] = (nfsd4_dec)nfsd4_decode_copy,
+- [OP_COPY_NOTIFY] = (nfsd4_dec)nfsd4_decode_copy_notify,
+- [OP_DEALLOCATE] = (nfsd4_dec)nfsd4_decode_fallocate,
+- [OP_IO_ADVISE] = (nfsd4_dec)nfsd4_decode_notsupp,
+- [OP_LAYOUTERROR] = (nfsd4_dec)nfsd4_decode_notsupp,
+- [OP_LAYOUTSTATS] = (nfsd4_dec)nfsd4_decode_notsupp,
+- [OP_OFFLOAD_CANCEL] = (nfsd4_dec)nfsd4_decode_offload_status,
+- [OP_OFFLOAD_STATUS] = (nfsd4_dec)nfsd4_decode_offload_status,
+- [OP_READ_PLUS] = (nfsd4_dec)nfsd4_decode_read,
+- [OP_SEEK] = (nfsd4_dec)nfsd4_decode_seek,
+- [OP_WRITE_SAME] = (nfsd4_dec)nfsd4_decode_notsupp,
+- [OP_CLONE] = (nfsd4_dec)nfsd4_decode_clone,
++ [OP_ALLOCATE] = nfsd4_decode_fallocate,
++ [OP_COPY] = nfsd4_decode_copy,
++ [OP_COPY_NOTIFY] = nfsd4_decode_copy_notify,
++ [OP_DEALLOCATE] = nfsd4_decode_fallocate,
++ [OP_IO_ADVISE] = nfsd4_decode_notsupp,
++ [OP_LAYOUTERROR] = nfsd4_decode_notsupp,
++ [OP_LAYOUTSTATS] = nfsd4_decode_notsupp,
++ [OP_OFFLOAD_CANCEL] = nfsd4_decode_offload_status,
++ [OP_OFFLOAD_STATUS] = nfsd4_decode_offload_status,
++ [OP_READ_PLUS] = nfsd4_decode_read,
++ [OP_SEEK] = nfsd4_decode_seek,
++ [OP_WRITE_SAME] = nfsd4_decode_notsupp,
++ [OP_CLONE] = nfsd4_decode_clone,
+ /* RFC 8276 extended atributes operations */
+- [OP_GETXATTR] = (nfsd4_dec)nfsd4_decode_getxattr,
+- [OP_SETXATTR] = (nfsd4_dec)nfsd4_decode_setxattr,
+- [OP_LISTXATTRS] = (nfsd4_dec)nfsd4_decode_listxattrs,
+- [OP_REMOVEXATTR] = (nfsd4_dec)nfsd4_decode_removexattr,
++ [OP_GETXATTR] = nfsd4_decode_getxattr,
++ [OP_SETXATTR] = nfsd4_decode_setxattr,
++ [OP_LISTXATTRS] = nfsd4_decode_listxattrs,
++ [OP_REMOVEXATTR] = nfsd4_decode_removexattr,
+ };
+
+ static inline bool
+@@ -3643,8 +3702,10 @@ nfsd4_encode_stateid(struct xdr_stream *
+ }
+
+ static __be32
+-nfsd4_encode_access(struct nfsd4_compoundres *resp, __be32 nfserr, struct nfsd4_access *access)
++nfsd4_encode_access(struct nfsd4_compoundres *resp, __be32 nfserr,
++ union nfsd4_op_u *u)
+ {
++ struct nfsd4_access *access = &u->access;
+ struct xdr_stream *xdr = resp->xdr;
+ __be32 *p;
+
+@@ -3656,8 +3717,10 @@ nfsd4_encode_access(struct nfsd4_compoun
+ return 0;
+ }
+
+-static __be32 nfsd4_encode_bind_conn_to_session(struct nfsd4_compoundres *resp, __be32 nfserr, struct nfsd4_bind_conn_to_session *bcts)
++static __be32 nfsd4_encode_bind_conn_to_session(struct nfsd4_compoundres *resp, __be32 nfserr,
++ union nfsd4_op_u *u)
+ {
++ struct nfsd4_bind_conn_to_session *bcts = &u->bind_conn_to_session;
+ struct xdr_stream *xdr = resp->xdr;
+ __be32 *p;
+
+@@ -3673,8 +3736,10 @@ static __be32 nfsd4_encode_bind_conn_to_
+ }
+
+ static __be32
+-nfsd4_encode_close(struct nfsd4_compoundres *resp, __be32 nfserr, struct nfsd4_close *close)
++nfsd4_encode_close(struct nfsd4_compoundres *resp, __be32 nfserr,
++ union nfsd4_op_u *u)
+ {
++ struct nfsd4_close *close = &u->close;
+ struct xdr_stream *xdr = resp->xdr;
+
+ return nfsd4_encode_stateid(xdr, &close->cl_stateid);
+@@ -3682,8 +3747,10 @@ nfsd4_encode_close(struct nfsd4_compound
+
+
+ static __be32
+-nfsd4_encode_commit(struct nfsd4_compoundres *resp, __be32 nfserr, struct nfsd4_commit *commit)
++nfsd4_encode_commit(struct nfsd4_compoundres *resp, __be32 nfserr,
++ union nfsd4_op_u *u)
+ {
++ struct nfsd4_commit *commit = &u->commit;
+ struct xdr_stream *xdr = resp->xdr;
+ __be32 *p;
+
+@@ -3696,8 +3763,10 @@ nfsd4_encode_commit(struct nfsd4_compoun
+ }
+
+ static __be32
+-nfsd4_encode_create(struct nfsd4_compoundres *resp, __be32 nfserr, struct nfsd4_create *create)
++nfsd4_encode_create(struct nfsd4_compoundres *resp, __be32 nfserr,
++ union nfsd4_op_u *u)
+ {
++ struct nfsd4_create *create = &u->create;
+ struct xdr_stream *xdr = resp->xdr;
+ __be32 *p;
+
+@@ -3710,8 +3779,10 @@ nfsd4_encode_create(struct nfsd4_compoun
+ }
+
+ static __be32
+-nfsd4_encode_getattr(struct nfsd4_compoundres *resp, __be32 nfserr, struct nfsd4_getattr *getattr)
++nfsd4_encode_getattr(struct nfsd4_compoundres *resp, __be32 nfserr,
++ union nfsd4_op_u *u)
+ {
++ struct nfsd4_getattr *getattr = &u->getattr;
+ struct svc_fh *fhp = getattr->ga_fhp;
+ struct xdr_stream *xdr = resp->xdr;
+
+@@ -3720,8 +3791,10 @@ nfsd4_encode_getattr(struct nfsd4_compou
+ }
+
+ static __be32
+-nfsd4_encode_getfh(struct nfsd4_compoundres *resp, __be32 nfserr, struct svc_fh **fhpp)
++nfsd4_encode_getfh(struct nfsd4_compoundres *resp, __be32 nfserr,
++ union nfsd4_op_u *u)
+ {
++ struct svc_fh **fhpp = &u->getfh;
+ struct xdr_stream *xdr = resp->xdr;
+ struct svc_fh *fhp = *fhpp;
+ unsigned int len;
+@@ -3775,8 +3848,10 @@ again:
+ }
+
+ static __be32
+-nfsd4_encode_lock(struct nfsd4_compoundres *resp, __be32 nfserr, struct nfsd4_lock *lock)
++nfsd4_encode_lock(struct nfsd4_compoundres *resp, __be32 nfserr,
++ union nfsd4_op_u *u)
+ {
++ struct nfsd4_lock *lock = &u->lock;
+ struct xdr_stream *xdr = resp->xdr;
+
+ if (!nfserr)
+@@ -3788,8 +3863,10 @@ nfsd4_encode_lock(struct nfsd4_compoundr
+ }
+
+ static __be32
+-nfsd4_encode_lockt(struct nfsd4_compoundres *resp, __be32 nfserr, struct nfsd4_lockt *lockt)
++nfsd4_encode_lockt(struct nfsd4_compoundres *resp, __be32 nfserr,
++ union nfsd4_op_u *u)
+ {
++ struct nfsd4_lockt *lockt = &u->lockt;
+ struct xdr_stream *xdr = resp->xdr;
+
+ if (nfserr == nfserr_denied)
+@@ -3798,8 +3875,10 @@ nfsd4_encode_lockt(struct nfsd4_compound
+ }
+
+ static __be32
+-nfsd4_encode_locku(struct nfsd4_compoundres *resp, __be32 nfserr, struct nfsd4_locku *locku)
++nfsd4_encode_locku(struct nfsd4_compoundres *resp, __be32 nfserr,
++ union nfsd4_op_u *u)
+ {
++ struct nfsd4_locku *locku = &u->locku;
+ struct xdr_stream *xdr = resp->xdr;
+
+ return nfsd4_encode_stateid(xdr, &locku->lu_stateid);
+@@ -3807,8 +3886,10 @@ nfsd4_encode_locku(struct nfsd4_compound
+
+
+ static __be32
+-nfsd4_encode_link(struct nfsd4_compoundres *resp, __be32 nfserr, struct nfsd4_link *link)
++nfsd4_encode_link(struct nfsd4_compoundres *resp, __be32 nfserr,
++ union nfsd4_op_u *u)
+ {
++ struct nfsd4_link *link = &u->link;
+ struct xdr_stream *xdr = resp->xdr;
+ __be32 *p;
+
+@@ -3821,8 +3902,10 @@ nfsd4_encode_link(struct nfsd4_compoundr
+
+
+ static __be32
+-nfsd4_encode_open(struct nfsd4_compoundres *resp, __be32 nfserr, struct nfsd4_open *open)
++nfsd4_encode_open(struct nfsd4_compoundres *resp, __be32 nfserr,
++ union nfsd4_op_u *u)
+ {
++ struct nfsd4_open *open = &u->open;
+ struct xdr_stream *xdr = resp->xdr;
+ __be32 *p;
+
+@@ -3915,16 +3998,20 @@ nfsd4_encode_open(struct nfsd4_compoundr
+ }
+
+ static __be32
+-nfsd4_encode_open_confirm(struct nfsd4_compoundres *resp, __be32 nfserr, struct nfsd4_open_confirm *oc)
++nfsd4_encode_open_confirm(struct nfsd4_compoundres *resp, __be32 nfserr,
++ union nfsd4_op_u *u)
+ {
++ struct nfsd4_open_confirm *oc = &u->open_confirm;
+ struct xdr_stream *xdr = resp->xdr;
+
+ return nfsd4_encode_stateid(xdr, &oc->oc_resp_stateid);
+ }
+
+ static __be32
+-nfsd4_encode_open_downgrade(struct nfsd4_compoundres *resp, __be32 nfserr, struct nfsd4_open_downgrade *od)
++nfsd4_encode_open_downgrade(struct nfsd4_compoundres *resp, __be32 nfserr,
++ union nfsd4_op_u *u)
+ {
++ struct nfsd4_open_downgrade *od = &u->open_downgrade;
+ struct xdr_stream *xdr = resp->xdr;
+
+ return nfsd4_encode_stateid(xdr, &od->od_stateid);
+@@ -4023,8 +4110,9 @@ static __be32 nfsd4_encode_readv(struct
+
+ static __be32
+ nfsd4_encode_read(struct nfsd4_compoundres *resp, __be32 nfserr,
+- struct nfsd4_read *read)
++ union nfsd4_op_u *u)
+ {
++ struct nfsd4_read *read = &u->read;
+ bool splice_ok = test_bit(RQ_SPLICE_OK, &resp->rqstp->rq_flags);
+ unsigned long maxcount;
+ struct xdr_stream *xdr = resp->xdr;
+@@ -4065,8 +4153,10 @@ nfsd4_encode_read(struct nfsd4_compoundr
+ }
+
+ static __be32
+-nfsd4_encode_readlink(struct nfsd4_compoundres *resp, __be32 nfserr, struct nfsd4_readlink *readlink)
++nfsd4_encode_readlink(struct nfsd4_compoundres *resp, __be32 nfserr,
++ union nfsd4_op_u *u)
+ {
++ struct nfsd4_readlink *readlink = &u->readlink;
+ __be32 *p, *maxcount_p, zero = xdr_zero;
+ struct xdr_stream *xdr = resp->xdr;
+ int length_offset = xdr->buf->len;
+@@ -4110,8 +4200,10 @@ out_err:
+ }
+
+ static __be32
+-nfsd4_encode_readdir(struct nfsd4_compoundres *resp, __be32 nfserr, struct nfsd4_readdir *readdir)
++nfsd4_encode_readdir(struct nfsd4_compoundres *resp, __be32 nfserr,
++ union nfsd4_op_u *u)
+ {
++ struct nfsd4_readdir *readdir = &u->readdir;
+ int maxcount;
+ int bytes_left;
+ loff_t offset;
+@@ -4201,8 +4293,10 @@ err_no_verf:
+ }
+
+ static __be32
+-nfsd4_encode_remove(struct nfsd4_compoundres *resp, __be32 nfserr, struct nfsd4_remove *remove)
++nfsd4_encode_remove(struct nfsd4_compoundres *resp, __be32 nfserr,
++ union nfsd4_op_u *u)
+ {
++ struct nfsd4_remove *remove = &u->remove;
+ struct xdr_stream *xdr = resp->xdr;
+ __be32 *p;
+
+@@ -4214,8 +4308,10 @@ nfsd4_encode_remove(struct nfsd4_compoun
+ }
+
+ static __be32
+-nfsd4_encode_rename(struct nfsd4_compoundres *resp, __be32 nfserr, struct nfsd4_rename *rename)
++nfsd4_encode_rename(struct nfsd4_compoundres *resp, __be32 nfserr,
++ union nfsd4_op_u *u)
+ {
++ struct nfsd4_rename *rename = &u->rename;
+ struct xdr_stream *xdr = resp->xdr;
+ __be32 *p;
+
+@@ -4297,8 +4393,9 @@ nfsd4_do_encode_secinfo(struct xdr_strea
+
+ static __be32
+ nfsd4_encode_secinfo(struct nfsd4_compoundres *resp, __be32 nfserr,
+- struct nfsd4_secinfo *secinfo)
++ union nfsd4_op_u *u)
+ {
++ struct nfsd4_secinfo *secinfo = &u->secinfo;
+ struct xdr_stream *xdr = resp->xdr;
+
+ return nfsd4_do_encode_secinfo(xdr, secinfo->si_exp);
+@@ -4306,8 +4403,9 @@ nfsd4_encode_secinfo(struct nfsd4_compou
+
+ static __be32
+ nfsd4_encode_secinfo_no_name(struct nfsd4_compoundres *resp, __be32 nfserr,
+- struct nfsd4_secinfo_no_name *secinfo)
++ union nfsd4_op_u *u)
+ {
++ struct nfsd4_secinfo_no_name *secinfo = &u->secinfo_no_name;
+ struct xdr_stream *xdr = resp->xdr;
+
+ return nfsd4_do_encode_secinfo(xdr, secinfo->sin_exp);
+@@ -4318,8 +4416,10 @@ nfsd4_encode_secinfo_no_name(struct nfsd
+ * regardless of the error status.
+ */
+ static __be32
+-nfsd4_encode_setattr(struct nfsd4_compoundres *resp, __be32 nfserr, struct nfsd4_setattr *setattr)
++nfsd4_encode_setattr(struct nfsd4_compoundres *resp, __be32 nfserr,
++ union nfsd4_op_u *u)
+ {
++ struct nfsd4_setattr *setattr = &u->setattr;
+ struct xdr_stream *xdr = resp->xdr;
+ __be32 *p;
+
+@@ -4342,8 +4442,10 @@ nfsd4_encode_setattr(struct nfsd4_compou
+ }
+
+ static __be32
+-nfsd4_encode_setclientid(struct nfsd4_compoundres *resp, __be32 nfserr, struct nfsd4_setclientid *scd)
++nfsd4_encode_setclientid(struct nfsd4_compoundres *resp, __be32 nfserr,
++ union nfsd4_op_u *u)
+ {
++ struct nfsd4_setclientid *scd = &u->setclientid;
+ struct xdr_stream *xdr = resp->xdr;
+ __be32 *p;
+
+@@ -4366,8 +4468,10 @@ nfsd4_encode_setclientid(struct nfsd4_co
+ }
+
+ static __be32
+-nfsd4_encode_write(struct nfsd4_compoundres *resp, __be32 nfserr, struct nfsd4_write *write)
++nfsd4_encode_write(struct nfsd4_compoundres *resp, __be32 nfserr,
++ union nfsd4_op_u *u)
+ {
++ struct nfsd4_write *write = &u->write;
+ struct xdr_stream *xdr = resp->xdr;
+ __be32 *p;
+
+@@ -4383,8 +4487,9 @@ nfsd4_encode_write(struct nfsd4_compound
+
+ static __be32
+ nfsd4_encode_exchange_id(struct nfsd4_compoundres *resp, __be32 nfserr,
+- struct nfsd4_exchange_id *exid)
++ union nfsd4_op_u *u)
+ {
++ struct nfsd4_exchange_id *exid = &u->exchange_id;
+ struct xdr_stream *xdr = resp->xdr;
+ __be32 *p;
+ char *major_id;
+@@ -4461,8 +4566,9 @@ nfsd4_encode_exchange_id(struct nfsd4_co
+
+ static __be32
+ nfsd4_encode_create_session(struct nfsd4_compoundres *resp, __be32 nfserr,
+- struct nfsd4_create_session *sess)
++ union nfsd4_op_u *u)
+ {
++ struct nfsd4_create_session *sess = &u->create_session;
+ struct xdr_stream *xdr = resp->xdr;
+ __be32 *p;
+
+@@ -4514,8 +4620,9 @@ nfsd4_encode_create_session(struct nfsd4
+
+ static __be32
+ nfsd4_encode_sequence(struct nfsd4_compoundres *resp, __be32 nfserr,
+- struct nfsd4_sequence *seq)
++ union nfsd4_op_u *u)
+ {
++ struct nfsd4_sequence *seq = &u->sequence;
+ struct xdr_stream *xdr = resp->xdr;
+ __be32 *p;
+
+@@ -4537,8 +4644,9 @@ nfsd4_encode_sequence(struct nfsd4_compo
+
+ static __be32
+ nfsd4_encode_test_stateid(struct nfsd4_compoundres *resp, __be32 nfserr,
+- struct nfsd4_test_stateid *test_stateid)
++ union nfsd4_op_u *u)
+ {
++ struct nfsd4_test_stateid *test_stateid = &u->test_stateid;
+ struct xdr_stream *xdr = resp->xdr;
+ struct nfsd4_test_stateid_id *stateid, *next;
+ __be32 *p;
+@@ -4558,8 +4666,9 @@ nfsd4_encode_test_stateid(struct nfsd4_c
+ #ifdef CONFIG_NFSD_PNFS
+ static __be32
+ nfsd4_encode_getdeviceinfo(struct nfsd4_compoundres *resp, __be32 nfserr,
+- struct nfsd4_getdeviceinfo *gdev)
++ union nfsd4_op_u *u)
+ {
++ struct nfsd4_getdeviceinfo *gdev = &u->getdeviceinfo;
+ struct xdr_stream *xdr = resp->xdr;
+ const struct nfsd4_layout_ops *ops;
+ u32 starting_len = xdr->buf->len, needed_len;
+@@ -4611,8 +4720,9 @@ toosmall:
+
+ static __be32
+ nfsd4_encode_layoutget(struct nfsd4_compoundres *resp, __be32 nfserr,
+- struct nfsd4_layoutget *lgp)
++ union nfsd4_op_u *u)
+ {
++ struct nfsd4_layoutget *lgp = &u->layoutget;
+ struct xdr_stream *xdr = resp->xdr;
+ const struct nfsd4_layout_ops *ops;
+ __be32 *p;
+@@ -4638,8 +4748,9 @@ nfsd4_encode_layoutget(struct nfsd4_comp
+
+ static __be32
+ nfsd4_encode_layoutcommit(struct nfsd4_compoundres *resp, __be32 nfserr,
+- struct nfsd4_layoutcommit *lcp)
++ union nfsd4_op_u *u)
+ {
++ struct nfsd4_layoutcommit *lcp = &u->layoutcommit;
+ struct xdr_stream *xdr = resp->xdr;
+ __be32 *p;
+
+@@ -4659,8 +4770,9 @@ nfsd4_encode_layoutcommit(struct nfsd4_c
+
+ static __be32
+ nfsd4_encode_layoutreturn(struct nfsd4_compoundres *resp, __be32 nfserr,
+- struct nfsd4_layoutreturn *lrp)
++ union nfsd4_op_u *u)
+ {
++ struct nfsd4_layoutreturn *lrp = &u->layoutreturn;
+ struct xdr_stream *xdr = resp->xdr;
+ __be32 *p;
+
+@@ -4745,8 +4857,9 @@ nfsd42_encode_nl4_server(struct nfsd4_co
+
+ static __be32
+ nfsd4_encode_copy(struct nfsd4_compoundres *resp, __be32 nfserr,
+- struct nfsd4_copy *copy)
++ union nfsd4_op_u *u)
+ {
++ struct nfsd4_copy *copy = &u->copy;
+ __be32 *p;
+
+ nfserr = nfsd42_encode_write_res(resp, ©->cp_res,
+@@ -4762,8 +4875,9 @@ nfsd4_encode_copy(struct nfsd4_compoundr
+
+ static __be32
+ nfsd4_encode_offload_status(struct nfsd4_compoundres *resp, __be32 nfserr,
+- struct nfsd4_offload_status *os)
++ union nfsd4_op_u *u)
+ {
++ struct nfsd4_offload_status *os = &u->offload_status;
+ struct xdr_stream *xdr = resp->xdr;
+ __be32 *p;
+
+@@ -4813,8 +4927,9 @@ nfsd4_encode_read_plus_data(struct nfsd4
+
+ static __be32
+ nfsd4_encode_read_plus(struct nfsd4_compoundres *resp, __be32 nfserr,
+- struct nfsd4_read *read)
++ union nfsd4_op_u *u)
+ {
++ struct nfsd4_read *read = &u->read;
+ struct file *file = read->rd_nf->nf_file;
+ struct xdr_stream *xdr = resp->xdr;
+ int starting_len = xdr->buf->len;
+@@ -4850,8 +4965,9 @@ out:
+
+ static __be32
+ nfsd4_encode_copy_notify(struct nfsd4_compoundres *resp, __be32 nfserr,
+- struct nfsd4_copy_notify *cn)
++ union nfsd4_op_u *u)
+ {
++ struct nfsd4_copy_notify *cn = &u->copy_notify;
+ struct xdr_stream *xdr = resp->xdr;
+ __be32 *p;
+
+@@ -4885,8 +5001,9 @@ nfsd4_encode_copy_notify(struct nfsd4_co
+
+ static __be32
+ nfsd4_encode_seek(struct nfsd4_compoundres *resp, __be32 nfserr,
+- struct nfsd4_seek *seek)
++ union nfsd4_op_u *u)
+ {
++ struct nfsd4_seek *seek = &u->seek;
+ __be32 *p;
+
+ p = xdr_reserve_space(resp->xdr, 4 + 8);
+@@ -4897,7 +5014,8 @@ nfsd4_encode_seek(struct nfsd4_compoundr
+ }
+
+ static __be32
+-nfsd4_encode_noop(struct nfsd4_compoundres *resp, __be32 nfserr, void *p)
++nfsd4_encode_noop(struct nfsd4_compoundres *resp, __be32 nfserr,
++ union nfsd4_op_u *p)
+ {
+ return nfserr;
+ }
+@@ -4948,8 +5066,9 @@ nfsd4_vbuf_to_stream(struct xdr_stream *
+
+ static __be32
+ nfsd4_encode_getxattr(struct nfsd4_compoundres *resp, __be32 nfserr,
+- struct nfsd4_getxattr *getxattr)
++ union nfsd4_op_u *u)
+ {
++ struct nfsd4_getxattr *getxattr = &u->getxattr;
+ struct xdr_stream *xdr = resp->xdr;
+ __be32 *p, err;
+
+@@ -4972,8 +5091,9 @@ nfsd4_encode_getxattr(struct nfsd4_compo
+
+ static __be32
+ nfsd4_encode_setxattr(struct nfsd4_compoundres *resp, __be32 nfserr,
+- struct nfsd4_setxattr *setxattr)
++ union nfsd4_op_u *u)
+ {
++ struct nfsd4_setxattr *setxattr = &u->setxattr;
+ struct xdr_stream *xdr = resp->xdr;
+ __be32 *p;
+
+@@ -5013,8 +5133,9 @@ nfsd4_listxattr_validate_cookie(struct n
+
+ static __be32
+ nfsd4_encode_listxattrs(struct nfsd4_compoundres *resp, __be32 nfserr,
+- struct nfsd4_listxattrs *listxattrs)
++ union nfsd4_op_u *u)
+ {
++ struct nfsd4_listxattrs *listxattrs = &u->listxattrs;
+ struct xdr_stream *xdr = resp->xdr;
+ u32 cookie_offset, count_offset, eof;
+ u32 left, xdrleft, slen, count;
+@@ -5124,8 +5245,9 @@ out:
+
+ static __be32
+ nfsd4_encode_removexattr(struct nfsd4_compoundres *resp, __be32 nfserr,
+- struct nfsd4_removexattr *removexattr)
++ union nfsd4_op_u *u)
+ {
++ struct nfsd4_removexattr *removexattr = &u->removexattr;
+ struct xdr_stream *xdr = resp->xdr;
+ __be32 *p;
+
+@@ -5137,7 +5259,7 @@ nfsd4_encode_removexattr(struct nfsd4_co
+ return 0;
+ }
+
+-typedef __be32(* nfsd4_enc)(struct nfsd4_compoundres *, __be32, void *);
++typedef __be32(*nfsd4_enc)(struct nfsd4_compoundres *, __be32, union nfsd4_op_u *u);
+
+ /*
+ * Note: nfsd4_enc_ops vector is shared for v4.0 and v4.1
+@@ -5145,93 +5267,93 @@ typedef __be32(* nfsd4_enc)(struct nfsd4
+ * done in the decoding phase.
+ */
+ static const nfsd4_enc nfsd4_enc_ops[] = {
+- [OP_ACCESS] = (nfsd4_enc)nfsd4_encode_access,
+- [OP_CLOSE] = (nfsd4_enc)nfsd4_encode_close,
+- [OP_COMMIT] = (nfsd4_enc)nfsd4_encode_commit,
+- [OP_CREATE] = (nfsd4_enc)nfsd4_encode_create,
+- [OP_DELEGPURGE] = (nfsd4_enc)nfsd4_encode_noop,
+- [OP_DELEGRETURN] = (nfsd4_enc)nfsd4_encode_noop,
+- [OP_GETATTR] = (nfsd4_enc)nfsd4_encode_getattr,
+- [OP_GETFH] = (nfsd4_enc)nfsd4_encode_getfh,
+- [OP_LINK] = (nfsd4_enc)nfsd4_encode_link,
+- [OP_LOCK] = (nfsd4_enc)nfsd4_encode_lock,
+- [OP_LOCKT] = (nfsd4_enc)nfsd4_encode_lockt,
+- [OP_LOCKU] = (nfsd4_enc)nfsd4_encode_locku,
+- [OP_LOOKUP] = (nfsd4_enc)nfsd4_encode_noop,
+- [OP_LOOKUPP] = (nfsd4_enc)nfsd4_encode_noop,
+- [OP_NVERIFY] = (nfsd4_enc)nfsd4_encode_noop,
+- [OP_OPEN] = (nfsd4_enc)nfsd4_encode_open,
+- [OP_OPENATTR] = (nfsd4_enc)nfsd4_encode_noop,
+- [OP_OPEN_CONFIRM] = (nfsd4_enc)nfsd4_encode_open_confirm,
+- [OP_OPEN_DOWNGRADE] = (nfsd4_enc)nfsd4_encode_open_downgrade,
+- [OP_PUTFH] = (nfsd4_enc)nfsd4_encode_noop,
+- [OP_PUTPUBFH] = (nfsd4_enc)nfsd4_encode_noop,
+- [OP_PUTROOTFH] = (nfsd4_enc)nfsd4_encode_noop,
+- [OP_READ] = (nfsd4_enc)nfsd4_encode_read,
+- [OP_READDIR] = (nfsd4_enc)nfsd4_encode_readdir,
+- [OP_READLINK] = (nfsd4_enc)nfsd4_encode_readlink,
+- [OP_REMOVE] = (nfsd4_enc)nfsd4_encode_remove,
+- [OP_RENAME] = (nfsd4_enc)nfsd4_encode_rename,
+- [OP_RENEW] = (nfsd4_enc)nfsd4_encode_noop,
+- [OP_RESTOREFH] = (nfsd4_enc)nfsd4_encode_noop,
+- [OP_SAVEFH] = (nfsd4_enc)nfsd4_encode_noop,
+- [OP_SECINFO] = (nfsd4_enc)nfsd4_encode_secinfo,
+- [OP_SETATTR] = (nfsd4_enc)nfsd4_encode_setattr,
+- [OP_SETCLIENTID] = (nfsd4_enc)nfsd4_encode_setclientid,
+- [OP_SETCLIENTID_CONFIRM] = (nfsd4_enc)nfsd4_encode_noop,
+- [OP_VERIFY] = (nfsd4_enc)nfsd4_encode_noop,
+- [OP_WRITE] = (nfsd4_enc)nfsd4_encode_write,
+- [OP_RELEASE_LOCKOWNER] = (nfsd4_enc)nfsd4_encode_noop,
++ [OP_ACCESS] = nfsd4_encode_access,
++ [OP_CLOSE] = nfsd4_encode_close,
++ [OP_COMMIT] = nfsd4_encode_commit,
++ [OP_CREATE] = nfsd4_encode_create,
++ [OP_DELEGPURGE] = nfsd4_encode_noop,
++ [OP_DELEGRETURN] = nfsd4_encode_noop,
++ [OP_GETATTR] = nfsd4_encode_getattr,
++ [OP_GETFH] = nfsd4_encode_getfh,
++ [OP_LINK] = nfsd4_encode_link,
++ [OP_LOCK] = nfsd4_encode_lock,
++ [OP_LOCKT] = nfsd4_encode_lockt,
++ [OP_LOCKU] = nfsd4_encode_locku,
++ [OP_LOOKUP] = nfsd4_encode_noop,
++ [OP_LOOKUPP] = nfsd4_encode_noop,
++ [OP_NVERIFY] = nfsd4_encode_noop,
++ [OP_OPEN] = nfsd4_encode_open,
++ [OP_OPENATTR] = nfsd4_encode_noop,
++ [OP_OPEN_CONFIRM] = nfsd4_encode_open_confirm,
++ [OP_OPEN_DOWNGRADE] = nfsd4_encode_open_downgrade,
++ [OP_PUTFH] = nfsd4_encode_noop,
++ [OP_PUTPUBFH] = nfsd4_encode_noop,
++ [OP_PUTROOTFH] = nfsd4_encode_noop,
++ [OP_READ] = nfsd4_encode_read,
++ [OP_READDIR] = nfsd4_encode_readdir,
++ [OP_READLINK] = nfsd4_encode_readlink,
++ [OP_REMOVE] = nfsd4_encode_remove,
++ [OP_RENAME] = nfsd4_encode_rename,
++ [OP_RENEW] = nfsd4_encode_noop,
++ [OP_RESTOREFH] = nfsd4_encode_noop,
++ [OP_SAVEFH] = nfsd4_encode_noop,
++ [OP_SECINFO] = nfsd4_encode_secinfo,
++ [OP_SETATTR] = nfsd4_encode_setattr,
++ [OP_SETCLIENTID] = nfsd4_encode_setclientid,
++ [OP_SETCLIENTID_CONFIRM] = nfsd4_encode_noop,
++ [OP_VERIFY] = nfsd4_encode_noop,
++ [OP_WRITE] = nfsd4_encode_write,
++ [OP_RELEASE_LOCKOWNER] = nfsd4_encode_noop,
+
+ /* NFSv4.1 operations */
+- [OP_BACKCHANNEL_CTL] = (nfsd4_enc)nfsd4_encode_noop,
+- [OP_BIND_CONN_TO_SESSION] = (nfsd4_enc)nfsd4_encode_bind_conn_to_session,
+- [OP_EXCHANGE_ID] = (nfsd4_enc)nfsd4_encode_exchange_id,
+- [OP_CREATE_SESSION] = (nfsd4_enc)nfsd4_encode_create_session,
+- [OP_DESTROY_SESSION] = (nfsd4_enc)nfsd4_encode_noop,
+- [OP_FREE_STATEID] = (nfsd4_enc)nfsd4_encode_noop,
+- [OP_GET_DIR_DELEGATION] = (nfsd4_enc)nfsd4_encode_noop,
++ [OP_BACKCHANNEL_CTL] = nfsd4_encode_noop,
++ [OP_BIND_CONN_TO_SESSION] = nfsd4_encode_bind_conn_to_session,
++ [OP_EXCHANGE_ID] = nfsd4_encode_exchange_id,
++ [OP_CREATE_SESSION] = nfsd4_encode_create_session,
++ [OP_DESTROY_SESSION] = nfsd4_encode_noop,
++ [OP_FREE_STATEID] = nfsd4_encode_noop,
++ [OP_GET_DIR_DELEGATION] = nfsd4_encode_noop,
+ #ifdef CONFIG_NFSD_PNFS
+- [OP_GETDEVICEINFO] = (nfsd4_enc)nfsd4_encode_getdeviceinfo,
+- [OP_GETDEVICELIST] = (nfsd4_enc)nfsd4_encode_noop,
+- [OP_LAYOUTCOMMIT] = (nfsd4_enc)nfsd4_encode_layoutcommit,
+- [OP_LAYOUTGET] = (nfsd4_enc)nfsd4_encode_layoutget,
+- [OP_LAYOUTRETURN] = (nfsd4_enc)nfsd4_encode_layoutreturn,
++ [OP_GETDEVICEINFO] = nfsd4_encode_getdeviceinfo,
++ [OP_GETDEVICELIST] = nfsd4_encode_noop,
++ [OP_LAYOUTCOMMIT] = nfsd4_encode_layoutcommit,
++ [OP_LAYOUTGET] = nfsd4_encode_layoutget,
++ [OP_LAYOUTRETURN] = nfsd4_encode_layoutreturn,
+ #else
+- [OP_GETDEVICEINFO] = (nfsd4_enc)nfsd4_encode_noop,
+- [OP_GETDEVICELIST] = (nfsd4_enc)nfsd4_encode_noop,
+- [OP_LAYOUTCOMMIT] = (nfsd4_enc)nfsd4_encode_noop,
+- [OP_LAYOUTGET] = (nfsd4_enc)nfsd4_encode_noop,
+- [OP_LAYOUTRETURN] = (nfsd4_enc)nfsd4_encode_noop,
++ [OP_GETDEVICEINFO] = nfsd4_encode_noop,
++ [OP_GETDEVICELIST] = nfsd4_encode_noop,
++ [OP_LAYOUTCOMMIT] = nfsd4_encode_noop,
++ [OP_LAYOUTGET] = nfsd4_encode_noop,
++ [OP_LAYOUTRETURN] = nfsd4_encode_noop,
+ #endif
+- [OP_SECINFO_NO_NAME] = (nfsd4_enc)nfsd4_encode_secinfo_no_name,
+- [OP_SEQUENCE] = (nfsd4_enc)nfsd4_encode_sequence,
+- [OP_SET_SSV] = (nfsd4_enc)nfsd4_encode_noop,
+- [OP_TEST_STATEID] = (nfsd4_enc)nfsd4_encode_test_stateid,
+- [OP_WANT_DELEGATION] = (nfsd4_enc)nfsd4_encode_noop,
+- [OP_DESTROY_CLIENTID] = (nfsd4_enc)nfsd4_encode_noop,
+- [OP_RECLAIM_COMPLETE] = (nfsd4_enc)nfsd4_encode_noop,
++ [OP_SECINFO_NO_NAME] = nfsd4_encode_secinfo_no_name,
++ [OP_SEQUENCE] = nfsd4_encode_sequence,
++ [OP_SET_SSV] = nfsd4_encode_noop,
++ [OP_TEST_STATEID] = nfsd4_encode_test_stateid,
++ [OP_WANT_DELEGATION] = nfsd4_encode_noop,
++ [OP_DESTROY_CLIENTID] = nfsd4_encode_noop,
++ [OP_RECLAIM_COMPLETE] = nfsd4_encode_noop,
+
+ /* NFSv4.2 operations */
+- [OP_ALLOCATE] = (nfsd4_enc)nfsd4_encode_noop,
+- [OP_COPY] = (nfsd4_enc)nfsd4_encode_copy,
+- [OP_COPY_NOTIFY] = (nfsd4_enc)nfsd4_encode_copy_notify,
+- [OP_DEALLOCATE] = (nfsd4_enc)nfsd4_encode_noop,
+- [OP_IO_ADVISE] = (nfsd4_enc)nfsd4_encode_noop,
+- [OP_LAYOUTERROR] = (nfsd4_enc)nfsd4_encode_noop,
+- [OP_LAYOUTSTATS] = (nfsd4_enc)nfsd4_encode_noop,
+- [OP_OFFLOAD_CANCEL] = (nfsd4_enc)nfsd4_encode_noop,
+- [OP_OFFLOAD_STATUS] = (nfsd4_enc)nfsd4_encode_offload_status,
+- [OP_READ_PLUS] = (nfsd4_enc)nfsd4_encode_read_plus,
+- [OP_SEEK] = (nfsd4_enc)nfsd4_encode_seek,
+- [OP_WRITE_SAME] = (nfsd4_enc)nfsd4_encode_noop,
+- [OP_CLONE] = (nfsd4_enc)nfsd4_encode_noop,
++ [OP_ALLOCATE] = nfsd4_encode_noop,
++ [OP_COPY] = nfsd4_encode_copy,
++ [OP_COPY_NOTIFY] = nfsd4_encode_copy_notify,
++ [OP_DEALLOCATE] = nfsd4_encode_noop,
++ [OP_IO_ADVISE] = nfsd4_encode_noop,
++ [OP_LAYOUTERROR] = nfsd4_encode_noop,
++ [OP_LAYOUTSTATS] = nfsd4_encode_noop,
++ [OP_OFFLOAD_CANCEL] = nfsd4_encode_noop,
++ [OP_OFFLOAD_STATUS] = nfsd4_encode_offload_status,
++ [OP_READ_PLUS] = nfsd4_encode_read_plus,
++ [OP_SEEK] = nfsd4_encode_seek,
++ [OP_WRITE_SAME] = nfsd4_encode_noop,
++ [OP_CLONE] = nfsd4_encode_noop,
+
+ /* RFC 8276 extended atributes operations */
+- [OP_GETXATTR] = (nfsd4_enc)nfsd4_encode_getxattr,
+- [OP_SETXATTR] = (nfsd4_enc)nfsd4_encode_setxattr,
+- [OP_LISTXATTRS] = (nfsd4_enc)nfsd4_encode_listxattrs,
+- [OP_REMOVEXATTR] = (nfsd4_enc)nfsd4_encode_removexattr,
++ [OP_GETXATTR] = nfsd4_encode_getxattr,
++ [OP_SETXATTR] = nfsd4_encode_setxattr,
++ [OP_LISTXATTRS] = nfsd4_encode_listxattrs,
++ [OP_REMOVEXATTR] = nfsd4_encode_removexattr,
+ };
+
+ /*
--- /dev/null
+From 51805844c0d7f3311515967959269b4f38278d31 Mon Sep 17 00:00:00 2001
+From: Chuck Lever <chuck.lever@oracle.com>
+Date: Fri, 28 Oct 2022 10:47:41 -0400
+Subject: NFSD: Clean up find_or_add_file()
+
+From: Chuck Lever <chuck.lever@oracle.com>
+
+[ Upstream commit 9270fc514ba7d415636b23bcb937573a1ce54f6a ]
+
+Remove the call to find_file_locked() in insert_nfs4_file(). Tracing
+shows that over 99% of these calls return NULL. Thus it is not worth
+the expense of the extra bucket list traversal. insert_file() already
+deals correctly with the case where the item is already in the hash
+bucket.
+
+Since nfsd4_file_hash_insert() is now just a wrapper around
+insert_file(), move the meat of insert_file() into
+nfsd4_file_hash_insert() and get rid of it.
+
+Signed-off-by: Chuck Lever <chuck.lever@oracle.com>
+Reviewed-by: NeilBrown <neilb@suse.de>
+Signed-off-by: Chuck Lever <chuck.lever@oracle.com>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+---
+ fs/nfsd/nfs4state.c | 64 ++++++++++++++++++++++------------------------------
+ 1 file changed, 28 insertions(+), 36 deletions(-)
+
+--- a/fs/nfsd/nfs4state.c
++++ b/fs/nfsd/nfs4state.c
+@@ -4699,24 +4699,42 @@ find_file_locked(const struct svc_fh *fh
+ return NULL;
+ }
+
+-static struct nfs4_file *insert_file(struct nfs4_file *new, struct svc_fh *fh,
+- unsigned int hashval)
++static struct nfs4_file * find_file(struct svc_fh *fh)
+ {
+ struct nfs4_file *fp;
++ unsigned int hashval = file_hashval(fh);
++
++ rcu_read_lock();
++ fp = find_file_locked(fh, hashval);
++ rcu_read_unlock();
++ return fp;
++}
++
++/*
++ * On hash insertion, identify entries with the same inode but
++ * distinct filehandles. They will all be in the same hash bucket
++ * because nfs4_file's are hashed by the address in the fi_inode
++ * field.
++ */
++static noinline_for_stack struct nfs4_file *
++nfsd4_file_hash_insert(struct nfs4_file *new, const struct svc_fh *fhp)
++{
++ unsigned int hashval = file_hashval(fhp);
+ struct nfs4_file *ret = NULL;
+ bool alias_found = false;
++ struct nfs4_file *fi;
+
+ spin_lock(&state_lock);
+- hlist_for_each_entry_rcu(fp, &file_hashtbl[hashval], fi_hash,
++ hlist_for_each_entry_rcu(fi, &file_hashtbl[hashval], fi_hash,
+ lockdep_is_held(&state_lock)) {
+- if (fh_match(&fp->fi_fhandle, &fh->fh_handle)) {
+- if (refcount_inc_not_zero(&fp->fi_ref))
+- ret = fp;
+- } else if (d_inode(fh->fh_dentry) == fp->fi_inode)
+- fp->fi_aliased = alias_found = true;
++ if (fh_match(&fi->fi_fhandle, &fhp->fh_handle)) {
++ if (refcount_inc_not_zero(&fi->fi_ref))
++ ret = fi;
++ } else if (d_inode(fhp->fh_dentry) == fi->fi_inode)
++ fi->fi_aliased = alias_found = true;
+ }
+ if (likely(ret == NULL)) {
+- nfsd4_file_init(fh, new);
++ nfsd4_file_init(fhp, new);
+ hlist_add_head_rcu(&new->fi_hash, &file_hashtbl[hashval]);
+ new->fi_aliased = alias_found;
+ ret = new;
+@@ -4725,32 +4743,6 @@ static struct nfs4_file *insert_file(str
+ return ret;
+ }
+
+-static struct nfs4_file * find_file(struct svc_fh *fh)
+-{
+- struct nfs4_file *fp;
+- unsigned int hashval = file_hashval(fh);
+-
+- rcu_read_lock();
+- fp = find_file_locked(fh, hashval);
+- rcu_read_unlock();
+- return fp;
+-}
+-
+-static struct nfs4_file *
+-find_or_add_file(struct nfs4_file *new, struct svc_fh *fh)
+-{
+- struct nfs4_file *fp;
+- unsigned int hashval = file_hashval(fh);
+-
+- rcu_read_lock();
+- fp = find_file_locked(fh, hashval);
+- rcu_read_unlock();
+- if (fp)
+- return fp;
+-
+- return insert_file(new, fh, hashval);
+-}
+-
+ static noinline_for_stack void nfsd4_file_hash_remove(struct nfs4_file *fi)
+ {
+ hlist_del_rcu(&fi->fi_hash);
+@@ -5661,7 +5653,7 @@ nfsd4_process_open2(struct svc_rqst *rqs
+ * and check for delegations in the process of being recalled.
+ * If not found, create the nfs4_file struct
+ */
+- fp = find_or_add_file(open->op_file, current_fh);
++ fp = nfsd4_file_hash_insert(open->op_file, current_fh);
+ if (fp != open->op_file) {
+ status = nfs4_check_deleg(cl, open, &dp);
+ if (status)
--- /dev/null
+From 757d584649721520e10e32a12d7919f5035e0334 Mon Sep 17 00:00:00 2001
+From: Chuck Lever <chuck.lever@oracle.com>
+Date: Fri, 28 Oct 2022 10:46:57 -0400
+Subject: NFSD: Clean up nfs4_preprocess_stateid_op() call sites
+
+From: Chuck Lever <chuck.lever@oracle.com>
+
+[ Upstream commit eeff73f7c1c583f79a401284f46c619294859310 ]
+
+Remove the lame-duck dprintk()s around nfs4_preprocess_stateid_op()
+call sites.
+
+Signed-off-by: Chuck Lever <chuck.lever@oracle.com>
+Tested-by: Jeff Layton <jlayton@kernel.org>
+Reviewed-by: Jeff Layton <jlayton@kernel.org>
+Reviewed-by: NeilBrown <neilb@suse.de>
+Signed-off-by: Chuck Lever <chuck.lever@oracle.com>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+---
+ fs/nfsd/nfs4proc.c | 31 +++++++------------------------
+ 1 file changed, 7 insertions(+), 24 deletions(-)
+
+--- a/fs/nfsd/nfs4proc.c
++++ b/fs/nfsd/nfs4proc.c
+@@ -943,12 +943,7 @@ nfsd4_read(struct svc_rqst *rqstp, struc
+ status = nfs4_preprocess_stateid_op(rqstp, cstate, &cstate->current_fh,
+ &read->rd_stateid, RD_STATE,
+ &read->rd_nf, NULL);
+- if (status) {
+- dprintk("NFSD: nfsd4_read: couldn't process stateid!\n");
+- goto out;
+- }
+- status = nfs_ok;
+-out:
++
+ read->rd_rqstp = rqstp;
+ read->rd_fhp = &cstate->current_fh;
+ return status;
+@@ -1117,10 +1112,8 @@ nfsd4_setattr(struct svc_rqst *rqstp, st
+ status = nfs4_preprocess_stateid_op(rqstp, cstate,
+ &cstate->current_fh, &setattr->sa_stateid,
+ WR_STATE, NULL, NULL);
+- if (status) {
+- dprintk("NFSD: nfsd4_setattr: couldn't process stateid!\n");
++ if (status)
+ return status;
+- }
+ }
+ err = fh_want_write(&cstate->current_fh);
+ if (err)
+@@ -1170,10 +1163,8 @@ nfsd4_write(struct svc_rqst *rqstp, stru
+ write->wr_offset, cnt);
+ status = nfs4_preprocess_stateid_op(rqstp, cstate, &cstate->current_fh,
+ stateid, WR_STATE, &nf, NULL);
+- if (status) {
+- dprintk("NFSD: nfsd4_write: couldn't process stateid!\n");
++ if (status)
+ return status;
+- }
+
+ write->wr_how_written = write->wr_stable_how;
+
+@@ -1204,17 +1195,13 @@ nfsd4_verify_copy(struct svc_rqst *rqstp
+
+ status = nfs4_preprocess_stateid_op(rqstp, cstate, &cstate->save_fh,
+ src_stateid, RD_STATE, src, NULL);
+- if (status) {
+- dprintk("NFSD: %s: couldn't process src stateid!\n", __func__);
++ if (status)
+ goto out;
+- }
+
+ status = nfs4_preprocess_stateid_op(rqstp, cstate, &cstate->current_fh,
+ dst_stateid, WR_STATE, dst, NULL);
+- if (status) {
+- dprintk("NFSD: %s: couldn't process dst stateid!\n", __func__);
++ if (status)
+ goto out_put_src;
+- }
+
+ /* fix up for NFS-specific error code */
+ if (!S_ISREG(file_inode((*src)->nf_file)->i_mode) ||
+@@ -1935,10 +1922,8 @@ nfsd4_fallocate(struct svc_rqst *rqstp,
+ status = nfs4_preprocess_stateid_op(rqstp, cstate, &cstate->current_fh,
+ &fallocate->falloc_stateid,
+ WR_STATE, &nf, NULL);
+- if (status != nfs_ok) {
+- dprintk("NFSD: nfsd4_fallocate: couldn't process stateid!\n");
++ if (status != nfs_ok)
+ return status;
+- }
+
+ status = nfsd4_vfs_fallocate(rqstp, &cstate->current_fh, nf->nf_file,
+ fallocate->falloc_offset,
+@@ -1994,10 +1979,8 @@ nfsd4_seek(struct svc_rqst *rqstp, struc
+ status = nfs4_preprocess_stateid_op(rqstp, cstate, &cstate->current_fh,
+ &seek->seek_stateid,
+ RD_STATE, &nf, NULL);
+- if (status) {
+- dprintk("NFSD: nfsd4_seek: couldn't process stateid!\n");
++ if (status)
+ return status;
+- }
+
+ switch (seek->seek_whence) {
+ case NFS4_CONTENT_DATA:
--- /dev/null
+From 4ff0477fc99f1f54c18bb867bf4b4fcfc752a090 Mon Sep 17 00:00:00 2001
+From: Chuck Lever <chuck.lever@oracle.com>
+Date: Fri, 28 Oct 2022 10:47:28 -0400
+Subject: NFSD: Clean up nfsd4_init_file()
+
+From: Chuck Lever <chuck.lever@oracle.com>
+
+[ Upstream commit 81a21fa3e7fdecb3c5b97014f0fc5a17d5806cae ]
+
+Name this function more consistently. I'm going to use nfsd4_file_
+and nfsd4_file_hash_ for these helpers.
+
+Change the @fh parameter to be const pointer for better type safety.
+
+Finally, move the hash insertion operation to the caller. This is
+typical for most other "init_object" type helpers, and it is where
+most of the other nfs4_file hash table operations are located.
+
+Signed-off-by: Chuck Lever <chuck.lever@oracle.com>
+Reviewed-by: NeilBrown <neilb@suse.de>
+Reviewed-by: Jeff Layton <jlayton@kernel.org>
+Signed-off-by: Chuck Lever <chuck.lever@oracle.com>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+---
+ fs/nfsd/nfs4state.c | 10 ++++------
+ 1 file changed, 4 insertions(+), 6 deletions(-)
+
+--- a/fs/nfsd/nfs4state.c
++++ b/fs/nfsd/nfs4state.c
+@@ -4278,11 +4278,9 @@ static struct nfs4_file *nfsd4_alloc_fil
+ }
+
+ /* OPEN Share state helper functions */
+-static void nfsd4_init_file(struct svc_fh *fh, unsigned int hashval,
+- struct nfs4_file *fp)
+-{
+- lockdep_assert_held(&state_lock);
+
++static void nfsd4_file_init(const struct svc_fh *fh, struct nfs4_file *fp)
++{
+ refcount_set(&fp->fi_ref, 1);
+ spin_lock_init(&fp->fi_lock);
+ INIT_LIST_HEAD(&fp->fi_stateids);
+@@ -4300,7 +4298,6 @@ static void nfsd4_init_file(struct svc_f
+ INIT_LIST_HEAD(&fp->fi_lo_states);
+ atomic_set(&fp->fi_lo_recalls, 0);
+ #endif
+- hlist_add_head_rcu(&fp->fi_hash, &file_hashtbl[hashval]);
+ }
+
+ void
+@@ -4718,7 +4715,8 @@ static struct nfs4_file *insert_file(str
+ fp->fi_aliased = alias_found = true;
+ }
+ if (likely(ret == NULL)) {
+- nfsd4_init_file(fh, hashval, new);
++ nfsd4_file_init(fh, new);
++ hlist_add_head_rcu(&new->fi_hash, &file_hashtbl[hashval]);
+ new->fi_aliased = alias_found;
+ ret = new;
+ }
--- /dev/null
+From a6bc8b37ffcdf3cbd880a5725b717c4c215b7196 Mon Sep 17 00:00:00 2001
+From: Jeff Layton <jlayton@kernel.org>
+Date: Sat, 11 Feb 2023 07:50:08 -0500
+Subject: nfsd: don't destroy global nfs4_file table in per-net shutdown
+
+From: Jeff Layton <jlayton@kernel.org>
+
+[ Upstream commit 4102db175b5d884d133270fdbd0e59111ce688fc ]
+
+The nfs4_file table is global, so shutting it down when a containerized
+nfsd is shut down is wrong and can lead to double-frees. Tear down the
+nfs4_file_rhltable in nfs4_state_shutdown instead of
+nfs4_state_shutdown_net.
+
+Fixes: d47b295e8d76 ("NFSD: Use rhashtable for managing nfs4_file objects")
+Link: https://bugzilla.redhat.com/show_bug.cgi?id=2169017
+Reported-by: JianHong Yin <jiyin@redhat.com>
+Signed-off-by: Jeff Layton <jlayton@kernel.org>
+Signed-off-by: Chuck Lever <chuck.lever@oracle.com>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+---
+ fs/nfsd/nfs4state.c | 2 +-
+ 1 file changed, 1 insertion(+), 1 deletion(-)
+
+--- a/fs/nfsd/nfs4state.c
++++ b/fs/nfsd/nfs4state.c
+@@ -8212,7 +8212,6 @@ nfs4_state_shutdown_net(struct net *net)
+
+ nfsd4_client_tracking_exit(net);
+ nfs4_state_destroy_net(net);
+- rhltable_destroy(&nfs4_file_rhltable);
+ #ifdef CONFIG_NFSD_V4_2_INTER_SSC
+ nfsd4_ssc_shutdown_umount(nn);
+ #endif
+@@ -8222,6 +8221,7 @@ void
+ nfs4_state_shutdown(void)
+ {
+ nfsd4_destroy_callback_queue();
++ rhltable_destroy(&nfs4_file_rhltable);
+ }
+
+ static void
--- /dev/null
+From 275fc0e08f2112b49b304af978f149b684d4ac14 Mon Sep 17 00:00:00 2001
+From: Chuck Lever <chuck.lever@oracle.com>
+Date: Mon, 31 Oct 2022 09:53:26 -0400
+Subject: NFSD: Fix licensing header in filecache.c
+
+From: Chuck Lever <chuck.lever@oracle.com>
+
+[ Upstream commit 3f054211b29c0fa06dfdcab402c795fd7e906be1 ]
+
+Add a missing SPDX header.
+
+Signed-off-by: Chuck Lever <chuck.lever@oracle.com>
+Reviewed-by: Jeff Layton <jlayton@kernel.org>
+Signed-off-by: Chuck Lever <chuck.lever@oracle.com>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+---
+ fs/nfsd/filecache.c | 3 ++-
+ 1 file changed, 2 insertions(+), 1 deletion(-)
+
+--- a/fs/nfsd/filecache.c
++++ b/fs/nfsd/filecache.c
+@@ -1,5 +1,6 @@
++// SPDX-License-Identifier: GPL-2.0
+ /*
+- * Open file cache.
++ * The NFSD open file cache.
+ *
+ * (c) 2015 - Jeff Layton <jeff.layton@primarydata.com>
+ *
--- /dev/null
+From 98f2fa4692468cd565264518f82d6d669e982547 Mon Sep 17 00:00:00 2001
+From: Jeff Layton <jlayton@kernel.org>
+Date: Wed, 2 Nov 2022 14:44:50 -0400
+Subject: nfsd: fix up the filecache laundrette scheduling
+
+From: Jeff Layton <jlayton@kernel.org>
+
+[ Upstream commit 22ae4c114f77b55a4c5036e8f70409a0799a08f8 ]
+
+We don't really care whether there are hashed entries when it comes to
+scheduling the laundrette. They might all be non-gc entries, after all.
+We only want to schedule it if there are entries on the LRU.
+
+Switch to using list_lru_count, and move the check into
+nfsd_file_gc_worker. The other callsite in nfsd_file_put doesn't need to
+count entries, since it only schedules the laundrette after adding an
+entry to the LRU.
+
+Signed-off-by: Jeff Layton <jlayton@kernel.org>
+Signed-off-by: Chuck Lever <chuck.lever@oracle.com>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+---
+ fs/nfsd/filecache.c | 12 +++++-------
+ 1 file changed, 5 insertions(+), 7 deletions(-)
+
+--- a/fs/nfsd/filecache.c
++++ b/fs/nfsd/filecache.c
+@@ -211,12 +211,9 @@ static const struct rhashtable_params nf
+ static void
+ nfsd_file_schedule_laundrette(void)
+ {
+- if ((atomic_read(&nfsd_file_rhash_tbl.nelems) == 0) ||
+- test_bit(NFSD_FILE_CACHE_UP, &nfsd_file_flags) == 0)
+- return;
+-
+- queue_delayed_work(system_wq, &nfsd_filecache_laundrette,
+- NFSD_LAUNDRETTE_DELAY);
++ if (test_bit(NFSD_FILE_CACHE_UP, &nfsd_file_flags))
++ queue_delayed_work(system_wq, &nfsd_filecache_laundrette,
++ NFSD_LAUNDRETTE_DELAY);
+ }
+
+ static void
+@@ -614,7 +611,8 @@ static void
+ nfsd_file_gc_worker(struct work_struct *work)
+ {
+ nfsd_file_gc();
+- nfsd_file_schedule_laundrette();
++ if (list_lru_count(&nfsd_file_lru))
++ nfsd_file_schedule_laundrette();
+ }
+
+ static unsigned long
--- /dev/null
+From 06d8447f0ae19330b1214367aa39fbd956dc4fee Mon Sep 17 00:00:00 2001
+From: Chuck Lever <chuck.lever@oracle.com>
+Date: Tue, 1 Nov 2022 13:30:46 -0400
+Subject: NFSD: Flesh out a documenting comment for filecache.c
+
+From: Chuck Lever <chuck.lever@oracle.com>
+
+[ Upstream commit b3276c1f5b268ff56622e9e125b792b4c3dc03ac ]
+
+Record what we've learned recently about the NFSD filecache in a
+documenting comment so our future selves don't forget what all this
+is for.
+
+Signed-off-by: Chuck Lever <chuck.lever@oracle.com>
+Reviewed-by: Jeff Layton <jlayton@kernel.org>
+Signed-off-by: Chuck Lever <chuck.lever@oracle.com>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+---
+ fs/nfsd/filecache.c | 24 ++++++++++++++++++++++++
+ 1 file changed, 24 insertions(+)
+
+--- a/fs/nfsd/filecache.c
++++ b/fs/nfsd/filecache.c
+@@ -2,6 +2,30 @@
+ * Open file cache.
+ *
+ * (c) 2015 - Jeff Layton <jeff.layton@primarydata.com>
++ *
++ * An nfsd_file object is a per-file collection of open state that binds
++ * together:
++ * - a struct file *
++ * - a user credential
++ * - a network namespace
++ * - a read-ahead context
++ * - monitoring for writeback errors
++ *
++ * nfsd_file objects are reference-counted. Consumers acquire a new
++ * object via the nfsd_file_acquire API. They manage their interest in
++ * the acquired object, and hence the object's reference count, via
++ * nfsd_file_get and nfsd_file_put. There are two varieties of nfsd_file
++ * object:
++ *
++ * * non-garbage-collected: When a consumer wants to precisely control
++ * the lifetime of a file's open state, it acquires a non-garbage-
++ * collected nfsd_file. The final nfsd_file_put releases the open
++ * state immediately.
++ *
++ * * garbage-collected: When a consumer does not control the lifetime
++ * of open state, it acquires a garbage-collected nfsd_file. The
++ * final nfsd_file_put allows the open state to linger for a period
++ * during which it may be re-used.
+ */
+
+ #include <linux/hash.h>
--- /dev/null
+From 8fdcafa904d391a0b4e26c8bcc9b7126676c4631 Mon Sep 17 00:00:00 2001
+From: Jeff Layton <jlayton@kernel.org>
+Date: Tue, 18 Oct 2022 07:47:54 -0400
+Subject: nfsd: ignore requests to disable unsupported versions
+
+From: Jeff Layton <jlayton@kernel.org>
+
+[ Upstream commit 8e823bafff2308753d430566256c83d8085952da ]
+
+The kernel currently errors out if you attempt to enable or disable a
+version that it doesn't recognize. Change it to ignore attempts to
+disable an unrecognized version. If we don't support it, then there is
+no harm in doing so.
+
+Signed-off-by: Jeff Layton <jlayton@kernel.org>
+Reviewed-by: Tom Talpey <tom@talpey.com>
+Signed-off-by: Chuck Lever <chuck.lever@oracle.com>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+---
+ fs/nfsd/nfsctl.c | 4 +++-
+ 1 file changed, 3 insertions(+), 1 deletion(-)
+
+--- a/fs/nfsd/nfsctl.c
++++ b/fs/nfsd/nfsctl.c
+@@ -601,7 +601,9 @@ static ssize_t __write_versions(struct f
+ }
+ break;
+ default:
+- return -EINVAL;
++ /* Ignore requests to disable non-existent versions */
++ if (cmd == NFSD_SET)
++ return -EINVAL;
+ }
+ vers += len + 1;
+ } while ((len = qword_get(&mesg, vers, size)) > 0);
--- /dev/null
+From 7cc60aa13f695b5585a494331d16d0c7e31fc05f Mon Sep 17 00:00:00 2001
+From: Jeff Layton <jlayton@kernel.org>
+Date: Tue, 18 Oct 2022 07:47:55 -0400
+Subject: nfsd: move nfserrno() to vfs.c
+
+From: Jeff Layton <jlayton@kernel.org>
+
+[ Upstream commit cb12fae1c34b1fa7eaae92c5aadc72d86d7fae19 ]
+
+nfserrno() is common to all nfs versions, but nfsproc.c is specifically
+for NFSv2. Move it to vfs.c, and the prototype to vfs.h.
+
+While we're in here, remove the #ifdef EDQUOT check in this function.
+It's apparently a holdover from the initial merge of the nfsd code in
+1997. No other place in the kernel checks that that symbol is defined
+before using it, so I think we can dispense with it here.
+
+Signed-off-by: Jeff Layton <jlayton@kernel.org>
+Signed-off-by: Chuck Lever <chuck.lever@oracle.com>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+---
+ fs/nfsd/blocklayout.c | 1
+ fs/nfsd/blocklayoutxdr.c | 1
+ fs/nfsd/export.h | 1
+ fs/nfsd/flexfilelayout.c | 1
+ fs/nfsd/nfs4idmap.c | 1
+ fs/nfsd/nfsproc.c | 62 ----------------------------------------------
+ fs/nfsd/vfs.c | 63 +++++++++++++++++++++++++++++++++++++++++++++++
+ fs/nfsd/vfs.h | 1
+ 8 files changed, 68 insertions(+), 63 deletions(-)
+
+--- a/fs/nfsd/blocklayout.c
++++ b/fs/nfsd/blocklayout.c
+@@ -12,6 +12,7 @@
+ #include "blocklayoutxdr.h"
+ #include "pnfs.h"
+ #include "filecache.h"
++#include "vfs.h"
+
+ #define NFSDDBG_FACILITY NFSDDBG_PNFS
+
+--- a/fs/nfsd/blocklayoutxdr.c
++++ b/fs/nfsd/blocklayoutxdr.c
+@@ -9,6 +9,7 @@
+
+ #include "nfsd.h"
+ #include "blocklayoutxdr.h"
++#include "vfs.h"
+
+ #define NFSDDBG_FACILITY NFSDDBG_PNFS
+
+--- a/fs/nfsd/export.h
++++ b/fs/nfsd/export.h
+@@ -115,7 +115,6 @@ struct svc_export * rqst_find_fsidzero_e
+ int exp_rootfh(struct net *, struct auth_domain *,
+ char *path, struct knfsd_fh *, int maxsize);
+ __be32 exp_pseudoroot(struct svc_rqst *, struct svc_fh *);
+-__be32 nfserrno(int errno);
+
+ static inline void exp_put(struct svc_export *exp)
+ {
+--- a/fs/nfsd/flexfilelayout.c
++++ b/fs/nfsd/flexfilelayout.c
+@@ -15,6 +15,7 @@
+
+ #include "flexfilelayoutxdr.h"
+ #include "pnfs.h"
++#include "vfs.h"
+
+ #define NFSDDBG_FACILITY NFSDDBG_PNFS
+
+--- a/fs/nfsd/nfs4idmap.c
++++ b/fs/nfsd/nfs4idmap.c
+@@ -41,6 +41,7 @@
+ #include "idmap.h"
+ #include "nfsd.h"
+ #include "netns.h"
++#include "vfs.h"
+
+ /*
+ * Turn off idmapping when using AUTH_SYS.
+--- a/fs/nfsd/nfsproc.c
++++ b/fs/nfsd/nfsproc.c
+@@ -848,65 +848,3 @@ const struct svc_version nfsd_version2 =
+ .vs_dispatch = nfsd_dispatch,
+ .vs_xdrsize = NFS2_SVC_XDRSIZE,
+ };
+-
+-/*
+- * Map errnos to NFS errnos.
+- */
+-__be32
+-nfserrno (int errno)
+-{
+- static struct {
+- __be32 nfserr;
+- int syserr;
+- } nfs_errtbl[] = {
+- { nfs_ok, 0 },
+- { nfserr_perm, -EPERM },
+- { nfserr_noent, -ENOENT },
+- { nfserr_io, -EIO },
+- { nfserr_nxio, -ENXIO },
+- { nfserr_fbig, -E2BIG },
+- { nfserr_stale, -EBADF },
+- { nfserr_acces, -EACCES },
+- { nfserr_exist, -EEXIST },
+- { nfserr_xdev, -EXDEV },
+- { nfserr_mlink, -EMLINK },
+- { nfserr_nodev, -ENODEV },
+- { nfserr_notdir, -ENOTDIR },
+- { nfserr_isdir, -EISDIR },
+- { nfserr_inval, -EINVAL },
+- { nfserr_fbig, -EFBIG },
+- { nfserr_nospc, -ENOSPC },
+- { nfserr_rofs, -EROFS },
+- { nfserr_mlink, -EMLINK },
+- { nfserr_nametoolong, -ENAMETOOLONG },
+- { nfserr_notempty, -ENOTEMPTY },
+-#ifdef EDQUOT
+- { nfserr_dquot, -EDQUOT },
+-#endif
+- { nfserr_stale, -ESTALE },
+- { nfserr_jukebox, -ETIMEDOUT },
+- { nfserr_jukebox, -ERESTARTSYS },
+- { nfserr_jukebox, -EAGAIN },
+- { nfserr_jukebox, -EWOULDBLOCK },
+- { nfserr_jukebox, -ENOMEM },
+- { nfserr_io, -ETXTBSY },
+- { nfserr_notsupp, -EOPNOTSUPP },
+- { nfserr_toosmall, -ETOOSMALL },
+- { nfserr_serverfault, -ESERVERFAULT },
+- { nfserr_serverfault, -ENFILE },
+- { nfserr_io, -EREMOTEIO },
+- { nfserr_stale, -EOPENSTALE },
+- { nfserr_io, -EUCLEAN },
+- { nfserr_perm, -ENOKEY },
+- { nfserr_no_grace, -ENOGRACE},
+- };
+- int i;
+-
+- for (i = 0; i < ARRAY_SIZE(nfs_errtbl); i++) {
+- if (nfs_errtbl[i].syserr == errno)
+- return nfs_errtbl[i].nfserr;
+- }
+- WARN_ONCE(1, "nfsd: non-standard errno: %d\n", errno);
+- return nfserr_io;
+-}
+-
+--- a/fs/nfsd/vfs.c
++++ b/fs/nfsd/vfs.c
+@@ -49,6 +49,69 @@
+
+ #define NFSDDBG_FACILITY NFSDDBG_FILEOP
+
++/**
++ * nfserrno - Map Linux errnos to NFS errnos
++ * @errno: POSIX(-ish) error code to be mapped
++ *
++ * Returns the appropriate (net-endian) nfserr_* (or nfs_ok if errno is 0). If
++ * it's an error we don't expect, log it once and return nfserr_io.
++ */
++__be32
++nfserrno (int errno)
++{
++ static struct {
++ __be32 nfserr;
++ int syserr;
++ } nfs_errtbl[] = {
++ { nfs_ok, 0 },
++ { nfserr_perm, -EPERM },
++ { nfserr_noent, -ENOENT },
++ { nfserr_io, -EIO },
++ { nfserr_nxio, -ENXIO },
++ { nfserr_fbig, -E2BIG },
++ { nfserr_stale, -EBADF },
++ { nfserr_acces, -EACCES },
++ { nfserr_exist, -EEXIST },
++ { nfserr_xdev, -EXDEV },
++ { nfserr_mlink, -EMLINK },
++ { nfserr_nodev, -ENODEV },
++ { nfserr_notdir, -ENOTDIR },
++ { nfserr_isdir, -EISDIR },
++ { nfserr_inval, -EINVAL },
++ { nfserr_fbig, -EFBIG },
++ { nfserr_nospc, -ENOSPC },
++ { nfserr_rofs, -EROFS },
++ { nfserr_mlink, -EMLINK },
++ { nfserr_nametoolong, -ENAMETOOLONG },
++ { nfserr_notempty, -ENOTEMPTY },
++ { nfserr_dquot, -EDQUOT },
++ { nfserr_stale, -ESTALE },
++ { nfserr_jukebox, -ETIMEDOUT },
++ { nfserr_jukebox, -ERESTARTSYS },
++ { nfserr_jukebox, -EAGAIN },
++ { nfserr_jukebox, -EWOULDBLOCK },
++ { nfserr_jukebox, -ENOMEM },
++ { nfserr_io, -ETXTBSY },
++ { nfserr_notsupp, -EOPNOTSUPP },
++ { nfserr_toosmall, -ETOOSMALL },
++ { nfserr_serverfault, -ESERVERFAULT },
++ { nfserr_serverfault, -ENFILE },
++ { nfserr_io, -EREMOTEIO },
++ { nfserr_stale, -EOPENSTALE },
++ { nfserr_io, -EUCLEAN },
++ { nfserr_perm, -ENOKEY },
++ { nfserr_no_grace, -ENOGRACE},
++ };
++ int i;
++
++ for (i = 0; i < ARRAY_SIZE(nfs_errtbl); i++) {
++ if (nfs_errtbl[i].syserr == errno)
++ return nfs_errtbl[i].nfserr;
++ }
++ WARN_ONCE(1, "nfsd: non-standard errno: %d\n", errno);
++ return nfserr_io;
++}
++
+ /*
+ * Called from nfsd_lookup and encode_dirent. Check if we have crossed
+ * a mount point.
+--- a/fs/nfsd/vfs.h
++++ b/fs/nfsd/vfs.h
+@@ -60,6 +60,7 @@ static inline void nfsd_attrs_free(struc
+ posix_acl_release(attrs->na_dpacl);
+ }
+
++__be32 nfserrno (int errno);
+ int nfsd_cross_mnt(struct svc_rqst *rqstp, struct dentry **dpp,
+ struct svc_export **expp);
+ __be32 nfsd_lookup(struct svc_rqst *, struct svc_fh *,
--- /dev/null
+From 77b17162b368c0ba3ac6f505cbee2d23a01d6294 Mon Sep 17 00:00:00 2001
+From: Chuck Lever <chuck.lever@oracle.com>
+Date: Fri, 28 Oct 2022 10:47:47 -0400
+Subject: NFSD: Refactor find_file()
+
+From: Chuck Lever <chuck.lever@oracle.com>
+
+[ Upstream commit 15424748001a9b5ea62b3e6ad45f0a8b27f01df9 ]
+
+find_file() is now the only caller of find_file_locked(), so just
+fold these two together.
+
+Signed-off-by: Chuck Lever <chuck.lever@oracle.com>
+Reviewed-by: NeilBrown <neilb@suse.de>
+Reviewed-by: Jeff Layton <jlayton@kernel.org>
+Signed-off-by: Chuck Lever <chuck.lever@oracle.com>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+---
+ fs/nfsd/nfs4state.c | 36 +++++++++++++++---------------------
+ 1 file changed, 15 insertions(+), 21 deletions(-)
+
+--- a/fs/nfsd/nfs4state.c
++++ b/fs/nfsd/nfs4state.c
+@@ -4683,31 +4683,24 @@ move_to_close_lru(struct nfs4_ol_stateid
+ nfs4_put_stid(&last->st_stid);
+ }
+
+-/* search file_hashtbl[] for file */
+-static struct nfs4_file *
+-find_file_locked(const struct svc_fh *fh, unsigned int hashval)
++static noinline_for_stack struct nfs4_file *
++nfsd4_file_hash_lookup(const struct svc_fh *fhp)
+ {
+- struct nfs4_file *fp;
++ unsigned int hashval = file_hashval(fhp);
++ struct nfs4_file *fi;
+
+- hlist_for_each_entry_rcu(fp, &file_hashtbl[hashval], fi_hash,
+- lockdep_is_held(&state_lock)) {
+- if (fh_match(&fp->fi_fhandle, &fh->fh_handle)) {
+- if (refcount_inc_not_zero(&fp->fi_ref))
+- return fp;
++ rcu_read_lock();
++ hlist_for_each_entry_rcu(fi, &file_hashtbl[hashval], fi_hash,
++ lockdep_is_held(&state_lock)) {
++ if (fh_match(&fi->fi_fhandle, &fhp->fh_handle)) {
++ if (refcount_inc_not_zero(&fi->fi_ref)) {
++ rcu_read_unlock();
++ return fi;
++ }
+ }
+ }
+- return NULL;
+-}
+-
+-static struct nfs4_file * find_file(struct svc_fh *fh)
+-{
+- struct nfs4_file *fp;
+- unsigned int hashval = file_hashval(fh);
+-
+- rcu_read_lock();
+- fp = find_file_locked(fh, hashval);
+ rcu_read_unlock();
+- return fp;
++ return NULL;
+ }
+
+ /*
+@@ -4758,9 +4751,10 @@ nfs4_share_conflict(struct svc_fh *curre
+ struct nfs4_file *fp;
+ __be32 ret = nfs_ok;
+
+- fp = find_file(current_fh);
++ fp = nfsd4_file_hash_lookup(current_fh);
+ if (!fp)
+ return ret;
++
+ /* Check for conflicting share reservations */
+ spin_lock(&fp->fi_lock);
+ if (fp->fi_share_deny & deny_type)
--- /dev/null
+From 1644e0ed649c0f951c08c81853485cbbcb3d5eaf Mon Sep 17 00:00:00 2001
+From: Dai Ngo <dai.ngo@oracle.com>
+Date: Wed, 16 Nov 2022 19:44:45 -0800
+Subject: NFSD: refactoring courtesy_client_reaper to a generic low memory shrinker
+
+From: Dai Ngo <dai.ngo@oracle.com>
+
+[ Upstream commit a1049eb47f20b9eabf9afb218578fff16b4baca6 ]
+
+Refactoring courtesy_client_reaper to generic low memory
+shrinker so it can be used for other purposes.
+
+Signed-off-by: Dai Ngo <dai.ngo@oracle.com>
+Signed-off-by: Chuck Lever <chuck.lever@oracle.com>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+---
+ fs/nfsd/nfs4state.c | 25 ++++++++++++++++---------
+ 1 file changed, 16 insertions(+), 9 deletions(-)
+
+--- a/fs/nfsd/nfs4state.c
++++ b/fs/nfsd/nfs4state.c
+@@ -4362,7 +4362,7 @@ out:
+ }
+
+ static unsigned long
+-nfsd_courtesy_client_count(struct shrinker *shrink, struct shrink_control *sc)
++nfsd4_state_shrinker_count(struct shrinker *shrink, struct shrink_control *sc)
+ {
+ int cnt;
+ struct nfsd_net *nn = container_of(shrink,
+@@ -4375,7 +4375,7 @@ nfsd_courtesy_client_count(struct shrink
+ }
+
+ static unsigned long
+-nfsd_courtesy_client_scan(struct shrinker *shrink, struct shrink_control *sc)
++nfsd4_state_shrinker_scan(struct shrinker *shrink, struct shrink_control *sc)
+ {
+ return SHRINK_STOP;
+ }
+@@ -4402,8 +4402,8 @@ nfsd4_init_leases_net(struct nfsd_net *n
+ nn->nfs4_max_clients = max_t(int, max_clients, NFS4_CLIENTS_PER_GB);
+
+ atomic_set(&nn->nfsd_courtesy_clients, 0);
+- nn->nfsd_client_shrinker.scan_objects = nfsd_courtesy_client_scan;
+- nn->nfsd_client_shrinker.count_objects = nfsd_courtesy_client_count;
++ nn->nfsd_client_shrinker.scan_objects = nfsd4_state_shrinker_scan;
++ nn->nfsd_client_shrinker.count_objects = nfsd4_state_shrinker_count;
+ nn->nfsd_client_shrinker.seeks = DEFAULT_SEEKS;
+ return register_shrinker(&nn->nfsd_client_shrinker, "nfsd-client");
+ }
+@@ -6171,17 +6171,24 @@ laundromat_main(struct work_struct *laun
+ }
+
+ static void
+-courtesy_client_reaper(struct work_struct *reaper)
++courtesy_client_reaper(struct nfsd_net *nn)
+ {
+ struct list_head reaplist;
+- struct delayed_work *dwork = to_delayed_work(reaper);
+- struct nfsd_net *nn = container_of(dwork, struct nfsd_net,
+- nfsd_shrinker_work);
+
+ nfs4_get_courtesy_client_reaplist(nn, &reaplist);
+ nfs4_process_client_reaplist(&reaplist);
+ }
+
++static void
++nfsd4_state_shrinker_worker(struct work_struct *work)
++{
++ struct delayed_work *dwork = to_delayed_work(work);
++ struct nfsd_net *nn = container_of(dwork, struct nfsd_net,
++ nfsd_shrinker_work);
++
++ courtesy_client_reaper(nn);
++}
++
+ static inline __be32 nfs4_check_fh(struct svc_fh *fhp, struct nfs4_stid *stp)
+ {
+ if (!fh_match(&fhp->fh_handle, &stp->sc_file->fi_fhandle))
+@@ -8007,7 +8014,7 @@ static int nfs4_state_create_net(struct
+ INIT_LIST_HEAD(&nn->blocked_locks_lru);
+
+ INIT_DELAYED_WORK(&nn->laundromat_work, laundromat_main);
+- INIT_DELAYED_WORK(&nn->nfsd_shrinker_work, courtesy_client_reaper);
++ INIT_DELAYED_WORK(&nn->nfsd_shrinker_work, nfsd4_state_shrinker_worker);
+ get_net(net);
+
+ return 0;
--- /dev/null
+From 11c632570a2654947799ddc6d16db0780d2232c2 Mon Sep 17 00:00:00 2001
+From: Dai Ngo <dai.ngo@oracle.com>
+Date: Wed, 11 Jan 2023 12:17:09 -0800
+Subject: NFSD: register/unregister of nfsd-client shrinker at nfsd startup/shutdown time
+
+From: Dai Ngo <dai.ngo@oracle.com>
+
+[ Upstream commit f385f7d244134246f984975ed34cd75f77de479f ]
+
+Currently the nfsd-client shrinker is registered and unregistered at
+the time the nfsd module is loaded and unloaded. The problem with this
+is the shrinker is being registered before all of the relevant fields
+in nfsd_net are initialized when nfsd is started. This can lead to an
+oops when memory is low and the shrinker is called while nfsd is not
+running.
+
+This patch moves the register/unregister of nfsd-client shrinker from
+module load/unload time to nfsd startup/shutdown time.
+
+Fixes: 44df6f439a17 ("NFSD: add delegation reaper to react to low memory condition")
+Reported-by: Mike Galbraith <efault@gmx.de>
+Signed-off-by: Dai Ngo <dai.ngo@oracle.com>
+Signed-off-by: Chuck Lever <chuck.lever@oracle.com>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+---
+ fs/nfsd/nfs4state.c | 22 +++++++++++-----------
+ fs/nfsd/nfsctl.c | 7 +------
+ fs/nfsd/nfsd.h | 6 ++----
+ 3 files changed, 14 insertions(+), 21 deletions(-)
+
+--- a/fs/nfsd/nfs4state.c
++++ b/fs/nfsd/nfs4state.c
+@@ -4422,7 +4422,7 @@ nfsd4_state_shrinker_scan(struct shrinke
+ return SHRINK_STOP;
+ }
+
+-int
++void
+ nfsd4_init_leases_net(struct nfsd_net *nn)
+ {
+ struct sysinfo si;
+@@ -4444,16 +4444,6 @@ nfsd4_init_leases_net(struct nfsd_net *n
+ nn->nfs4_max_clients = max_t(int, max_clients, NFS4_CLIENTS_PER_GB);
+
+ atomic_set(&nn->nfsd_courtesy_clients, 0);
+- nn->nfsd_client_shrinker.scan_objects = nfsd4_state_shrinker_scan;
+- nn->nfsd_client_shrinker.count_objects = nfsd4_state_shrinker_count;
+- nn->nfsd_client_shrinker.seeks = DEFAULT_SEEKS;
+- return register_shrinker(&nn->nfsd_client_shrinker, "nfsd-client");
+-}
+-
+-void
+-nfsd4_leases_net_shutdown(struct nfsd_net *nn)
+-{
+- unregister_shrinker(&nn->nfsd_client_shrinker);
+ }
+
+ static void init_nfs4_replay(struct nfs4_replay *rp)
+@@ -8099,8 +8089,17 @@ static int nfs4_state_create_net(struct
+ INIT_DELAYED_WORK(&nn->nfsd_shrinker_work, nfsd4_state_shrinker_worker);
+ get_net(net);
+
++ nn->nfsd_client_shrinker.scan_objects = nfsd4_state_shrinker_scan;
++ nn->nfsd_client_shrinker.count_objects = nfsd4_state_shrinker_count;
++ nn->nfsd_client_shrinker.seeks = DEFAULT_SEEKS;
++
++ if (register_shrinker(&nn->nfsd_client_shrinker, "nfsd-client"))
++ goto err_shrinker;
+ return 0;
+
++err_shrinker:
++ put_net(net);
++ kfree(nn->sessionid_hashtbl);
+ err_sessionid:
+ kfree(nn->unconf_id_hashtbl);
+ err_unconf_id:
+@@ -8193,6 +8192,7 @@ nfs4_state_shutdown_net(struct net *net)
+ struct list_head *pos, *next, reaplist;
+ struct nfsd_net *nn = net_generic(net, nfsd_net_id);
+
++ unregister_shrinker(&nn->nfsd_client_shrinker);
+ cancel_delayed_work_sync(&nn->laundromat_work);
+ locks_end_grace(&nn->nfsd4_manager);
+
+--- a/fs/nfsd/nfsctl.c
++++ b/fs/nfsd/nfsctl.c
+@@ -1452,9 +1452,7 @@ static __net_init int nfsd_init_net(stru
+ goto out_idmap_error;
+ nn->nfsd_versions = NULL;
+ nn->nfsd4_minorversions = NULL;
+- retval = nfsd4_init_leases_net(nn);
+- if (retval)
+- goto out_drc_error;
++ nfsd4_init_leases_net(nn);
+ retval = nfsd_reply_cache_init(nn);
+ if (retval)
+ goto out_cache_error;
+@@ -1464,8 +1462,6 @@ static __net_init int nfsd_init_net(stru
+ return 0;
+
+ out_cache_error:
+- nfsd4_leases_net_shutdown(nn);
+-out_drc_error:
+ nfsd_idmap_shutdown(net);
+ out_idmap_error:
+ nfsd_export_shutdown(net);
+@@ -1481,7 +1477,6 @@ static __net_exit void nfsd_exit_net(str
+ nfsd_idmap_shutdown(net);
+ nfsd_export_shutdown(net);
+ nfsd_netns_free_versions(net_generic(net, nfsd_net_id));
+- nfsd4_leases_net_shutdown(nn);
+ }
+
+ static struct pernet_operations nfsd_net_ops = {
+--- a/fs/nfsd/nfsd.h
++++ b/fs/nfsd/nfsd.h
+@@ -504,8 +504,7 @@ extern void unregister_cld_notifier(void
+ extern void nfsd4_ssc_init_umount_work(struct nfsd_net *nn);
+ #endif
+
+-extern int nfsd4_init_leases_net(struct nfsd_net *nn);
+-extern void nfsd4_leases_net_shutdown(struct nfsd_net *nn);
++extern void nfsd4_init_leases_net(struct nfsd_net *nn);
+
+ #else /* CONFIG_NFSD_V4 */
+ static inline int nfsd4_is_junction(struct dentry *dentry)
+@@ -513,8 +512,7 @@ static inline int nfsd4_is_junction(stru
+ return 0;
+ }
+
+-static inline int nfsd4_init_leases_net(struct nfsd_net *nn) { return 0; };
+-static inline void nfsd4_leases_net_shutdown(struct nfsd_net *nn) {};
++static inline void nfsd4_init_leases_net(struct nfsd_net *nn) { };
+
+ #define register_cld_notifier() 0
+ #define unregister_cld_notifier() do { } while(0)
--- /dev/null
+From 2e3aa79f392f5bfca11a1dbbdf422bc088a1a65a Mon Sep 17 00:00:00 2001
+From: Colin Ian King <colin.i.king@gmail.com>
+Date: Mon, 10 Oct 2022 21:24:23 +0100
+Subject: NFSD: Remove redundant assignment to variable host_err
+
+From: Colin Ian King <colin.i.king@gmail.com>
+
+[ Upstream commit 69eed23baf877bbb1f14d7f4df54f89807c9ee2a ]
+
+Variable host_err is assigned a value that is never read, it is being
+re-assigned a value in every different execution path in the following
+switch statement. The assignment is redundant and can be removed.
+
+Cleans up clang-scan warning:
+warning: Value stored to 'host_err' is never read [deadcode.DeadStores]
+
+Signed-off-by: Colin Ian King <colin.i.king@gmail.com>
+Reviewed-by: Jeff Layton <jlayton@kernel.org>
+Signed-off-by: Chuck Lever <chuck.lever@oracle.com>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+---
+ fs/nfsd/vfs.c | 1 -
+ 1 file changed, 1 deletion(-)
+
+--- a/fs/nfsd/vfs.c
++++ b/fs/nfsd/vfs.c
+@@ -1317,7 +1317,6 @@ nfsd_create_locked(struct svc_rqst *rqst
+ iap->ia_mode &= ~current_umask();
+
+ err = 0;
+- host_err = 0;
+ switch (type) {
+ case S_IFREG:
+ host_err = vfs_create(&init_user_ns, dirp, dchild, iap->ia_mode, true);
--- /dev/null
+From da15771ea07c26181d5eece014d9336ff7ff6d07 Mon Sep 17 00:00:00 2001
+From: Dai Ngo <dai.ngo@oracle.com>
+Date: Wed, 11 Jan 2023 16:06:51 -0800
+Subject: NFSD: replace delayed_work with work_struct for nfsd_client_shrinker
+
+From: Dai Ngo <dai.ngo@oracle.com>
+
+[ Upstream commit 7c24fa225081f31bc6da6a355c1ba801889ab29a ]
+
+Since nfsd4_state_shrinker_count always calls mod_delayed_work with
+0 delay, we can replace delayed_work with work_struct to save some
+space and overhead.
+
+Also add the call to cancel_work after unregister the shrinker
+in nfs4_state_shutdown_net.
+
+Signed-off-by: Dai Ngo <dai.ngo@oracle.com>
+Reviewed-by: Jeff Layton <jlayton@kernel.org>
+Signed-off-by: Chuck Lever <chuck.lever@oracle.com>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+---
+ fs/nfsd/netns.h | 2 +-
+ fs/nfsd/nfs4state.c | 8 ++++----
+ 2 files changed, 5 insertions(+), 5 deletions(-)
+
+--- a/fs/nfsd/netns.h
++++ b/fs/nfsd/netns.h
+@@ -195,7 +195,7 @@ struct nfsd_net {
+
+ atomic_t nfsd_courtesy_clients;
+ struct shrinker nfsd_client_shrinker;
+- struct delayed_work nfsd_shrinker_work;
++ struct work_struct nfsd_shrinker_work;
+ };
+
+ /* Simple check to find out if a given net was properly initialized */
+--- a/fs/nfsd/nfs4state.c
++++ b/fs/nfsd/nfs4state.c
+@@ -4412,7 +4412,7 @@ nfsd4_state_shrinker_count(struct shrink
+ if (!count)
+ count = atomic_long_read(&num_delegations);
+ if (count)
+- mod_delayed_work(laundry_wq, &nn->nfsd_shrinker_work, 0);
++ queue_work(laundry_wq, &nn->nfsd_shrinker_work);
+ return (unsigned long)count;
+ }
+
+@@ -6253,8 +6253,7 @@ deleg_reaper(struct nfsd_net *nn)
+ static void
+ nfsd4_state_shrinker_worker(struct work_struct *work)
+ {
+- struct delayed_work *dwork = to_delayed_work(work);
+- struct nfsd_net *nn = container_of(dwork, struct nfsd_net,
++ struct nfsd_net *nn = container_of(work, struct nfsd_net,
+ nfsd_shrinker_work);
+
+ courtesy_client_reaper(nn);
+@@ -8086,7 +8085,7 @@ static int nfs4_state_create_net(struct
+ INIT_LIST_HEAD(&nn->blocked_locks_lru);
+
+ INIT_DELAYED_WORK(&nn->laundromat_work, laundromat_main);
+- INIT_DELAYED_WORK(&nn->nfsd_shrinker_work, nfsd4_state_shrinker_worker);
++ INIT_WORK(&nn->nfsd_shrinker_work, nfsd4_state_shrinker_worker);
+ get_net(net);
+
+ nn->nfsd_client_shrinker.scan_objects = nfsd4_state_shrinker_scan;
+@@ -8193,6 +8192,7 @@ nfs4_state_shutdown_net(struct net *net)
+ struct nfsd_net *nn = net_generic(net, nfsd_net_id);
+
+ unregister_shrinker(&nn->nfsd_client_shrinker);
++ cancel_work(&nn->nfsd_shrinker_work);
+ cancel_delayed_work_sync(&nn->laundromat_work);
+ locks_end_grace(&nn->nfsd4_manager);
+
--- /dev/null
+From 46a3747d8b4e5aa83a6f8cc8adbad5c1643a69a1 Mon Sep 17 00:00:00 2001
+From: Anna Schumaker <Anna.Schumaker@Netapp.com>
+Date: Tue, 13 Sep 2022 14:01:51 -0400
+Subject: NFSD: Simplify READ_PLUS
+
+From: Anna Schumaker <Anna.Schumaker@Netapp.com>
+
+[ Upstream commit eeadcb75794516839078c28b3730132aeb700ce6 ]
+
+Chuck had suggested reverting READ_PLUS so it returns a single DATA
+segment covering the requested read range. This prepares the server for
+a future "sparse read" function so support can easily be added without
+needing to rip out the old READ_PLUS code at the same time.
+
+Signed-off-by: Anna Schumaker <Anna.Schumaker@Netapp.com>
+Signed-off-by: Chuck Lever <chuck.lever@oracle.com>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+---
+ fs/nfsd/nfs4xdr.c | 139 ++++++++++++------------------------------------------
+ 1 file changed, 32 insertions(+), 107 deletions(-)
+
+--- a/fs/nfsd/nfs4xdr.c
++++ b/fs/nfsd/nfs4xdr.c
+@@ -4777,79 +4777,37 @@ nfsd4_encode_offload_status(struct nfsd4
+
+ static __be32
+ nfsd4_encode_read_plus_data(struct nfsd4_compoundres *resp,
+- struct nfsd4_read *read,
+- unsigned long *maxcount, u32 *eof,
+- loff_t *pos)
++ struct nfsd4_read *read)
+ {
+- struct xdr_stream *xdr = resp->xdr;
++ bool splice_ok = test_bit(RQ_SPLICE_OK, &resp->rqstp->rq_flags);
+ struct file *file = read->rd_nf->nf_file;
+- int starting_len = xdr->buf->len;
+- loff_t hole_pos;
+- __be32 nfserr;
+- __be32 *p, tmp;
+- __be64 tmp64;
+-
+- hole_pos = pos ? *pos : vfs_llseek(file, read->rd_offset, SEEK_HOLE);
+- if (hole_pos > read->rd_offset)
+- *maxcount = min_t(unsigned long, *maxcount, hole_pos - read->rd_offset);
+- *maxcount = min_t(unsigned long, *maxcount, (xdr->buf->buflen - xdr->buf->len));
++ struct xdr_stream *xdr = resp->xdr;
++ unsigned long maxcount;
++ __be32 nfserr, *p;
+
+ /* Content type, offset, byte count */
+ p = xdr_reserve_space(xdr, 4 + 8 + 4);
+ if (!p)
+- return nfserr_resource;
++ return nfserr_io;
++ if (resp->xdr->buf->page_len && splice_ok) {
++ WARN_ON_ONCE(splice_ok);
++ return nfserr_serverfault;
++ }
+
+- read->rd_vlen = xdr_reserve_space_vec(xdr, resp->rqstp->rq_vec, *maxcount);
+- if (read->rd_vlen < 0)
+- return nfserr_resource;
++ maxcount = min_t(unsigned long, read->rd_length,
++ (xdr->buf->buflen - xdr->buf->len));
+
+- nfserr = nfsd_readv(resp->rqstp, read->rd_fhp, file, read->rd_offset,
+- resp->rqstp->rq_vec, read->rd_vlen, maxcount, eof);
++ if (file->f_op->splice_read && splice_ok)
++ nfserr = nfsd4_encode_splice_read(resp, read, file, maxcount);
++ else
++ nfserr = nfsd4_encode_readv(resp, read, file, maxcount);
+ if (nfserr)
+ return nfserr;
+- xdr_truncate_encode(xdr, starting_len + 16 + xdr_align_size(*maxcount));
+-
+- tmp = htonl(NFS4_CONTENT_DATA);
+- write_bytes_to_xdr_buf(xdr->buf, starting_len, &tmp, 4);
+- tmp64 = cpu_to_be64(read->rd_offset);
+- write_bytes_to_xdr_buf(xdr->buf, starting_len + 4, &tmp64, 8);
+- tmp = htonl(*maxcount);
+- write_bytes_to_xdr_buf(xdr->buf, starting_len + 12, &tmp, 4);
+-
+- tmp = xdr_zero;
+- write_bytes_to_xdr_buf(xdr->buf, starting_len + 16 + *maxcount, &tmp,
+- xdr_pad_size(*maxcount));
+- return nfs_ok;
+-}
+-
+-static __be32
+-nfsd4_encode_read_plus_hole(struct nfsd4_compoundres *resp,
+- struct nfsd4_read *read,
+- unsigned long *maxcount, u32 *eof)
+-{
+- struct file *file = read->rd_nf->nf_file;
+- loff_t data_pos = vfs_llseek(file, read->rd_offset, SEEK_DATA);
+- loff_t f_size = i_size_read(file_inode(file));
+- unsigned long count;
+- __be32 *p;
+-
+- if (data_pos == -ENXIO)
+- data_pos = f_size;
+- else if (data_pos <= read->rd_offset || (data_pos < f_size && data_pos % PAGE_SIZE))
+- return nfsd4_encode_read_plus_data(resp, read, maxcount, eof, &f_size);
+- count = data_pos - read->rd_offset;
+
+- /* Content type, offset, byte count */
+- p = xdr_reserve_space(resp->xdr, 4 + 8 + 8);
+- if (!p)
+- return nfserr_resource;
+-
+- *p++ = htonl(NFS4_CONTENT_HOLE);
++ *p++ = cpu_to_be32(NFS4_CONTENT_DATA);
+ p = xdr_encode_hyper(p, read->rd_offset);
+- p = xdr_encode_hyper(p, count);
++ *p = cpu_to_be32(read->rd_length);
+
+- *eof = (read->rd_offset + count) >= f_size;
+- *maxcount = min_t(unsigned long, count, *maxcount);
+ return nfs_ok;
+ }
+
+@@ -4857,69 +4815,36 @@ static __be32
+ nfsd4_encode_read_plus(struct nfsd4_compoundres *resp, __be32 nfserr,
+ struct nfsd4_read *read)
+ {
+- unsigned long maxcount, count;
++ struct file *file = read->rd_nf->nf_file;
+ struct xdr_stream *xdr = resp->xdr;
+- struct file *file;
+ int starting_len = xdr->buf->len;
+- int last_segment = xdr->buf->len;
+- int segments = 0;
+- __be32 *p, tmp;
+- bool is_data;
+- loff_t pos;
+- u32 eof;
++ u32 segments = 0;
++ __be32 *p;
+
+ if (nfserr)
+ return nfserr;
+- file = read->rd_nf->nf_file;
+
+ /* eof flag, segment count */
+ p = xdr_reserve_space(xdr, 4 + 4);
+ if (!p)
+- return nfserr_resource;
++ return nfserr_io;
+ xdr_commit_encode(xdr);
+
+- maxcount = min_t(unsigned long, read->rd_length,
+- (xdr->buf->buflen - xdr->buf->len));
+- count = maxcount;
+-
+- eof = read->rd_offset >= i_size_read(file_inode(file));
+- if (eof)
++ read->rd_eof = read->rd_offset >= i_size_read(file_inode(file));
++ if (read->rd_eof)
+ goto out;
+
+- pos = vfs_llseek(file, read->rd_offset, SEEK_HOLE);
+- is_data = pos > read->rd_offset;
+-
+- while (count > 0 && !eof) {
+- maxcount = count;
+- if (is_data)
+- nfserr = nfsd4_encode_read_plus_data(resp, read, &maxcount, &eof,
+- segments == 0 ? &pos : NULL);
+- else
+- nfserr = nfsd4_encode_read_plus_hole(resp, read, &maxcount, &eof);
+- if (nfserr)
+- goto out;
+- count -= maxcount;
+- read->rd_offset += maxcount;
+- is_data = !is_data;
+- last_segment = xdr->buf->len;
+- segments++;
+- }
+-
+-out:
+- if (nfserr && segments == 0)
++ nfserr = nfsd4_encode_read_plus_data(resp, read);
++ if (nfserr) {
+ xdr_truncate_encode(xdr, starting_len);
+- else {
+- if (nfserr) {
+- xdr_truncate_encode(xdr, last_segment);
+- nfserr = nfs_ok;
+- eof = 0;
+- }
+- tmp = htonl(eof);
+- write_bytes_to_xdr_buf(xdr->buf, starting_len, &tmp, 4);
+- tmp = htonl(segments);
+- write_bytes_to_xdr_buf(xdr->buf, starting_len + 4, &tmp, 4);
++ return nfserr;
+ }
+
++ segments++;
++
++out:
++ p = xdr_encode_bool(p, read->rd_eof);
++ *p = cpu_to_be32(segments);
+ return nfserr;
+ }
+
--- /dev/null
+From b41a2f6cb1d1aeea3275b6a96504ea5dc82b0012 Mon Sep 17 00:00:00 2001
+From: Chuck Lever <chuck.lever@oracle.com>
+Date: Fri, 28 Oct 2022 10:47:09 -0400
+Subject: NFSD: Trace delegation revocations
+
+From: Chuck Lever <chuck.lever@oracle.com>
+
+[ Upstream commit a1c74569bbde91299f24535abf711be5c84df9de ]
+
+Delegation revocation is an exceptional event that is not otherwise
+visible externally (eg, no network traffic is emitted). Generate a
+trace record when it occurs so that revocation can be observed or
+other activity can be triggered. Example:
+
+nfsd-1104 [005] 1912.002544: nfsd_stid_revoke: client 633c9343:4e82788d stateid 00000003:00000001 ref=2 type=DELEG
+
+Trace infrastructure is provided for subsequent additional tracing
+related to nfs4_stid activity.
+
+Signed-off-by: Chuck Lever <chuck.lever@oracle.com>
+Tested-by: Jeff Layton <jlayton@kernel.org>
+Reviewed-by: Jeff Layton <jlayton@kernel.org>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+---
+ fs/nfsd/nfs4state.c | 2 +
+ fs/nfsd/trace.h | 55 ++++++++++++++++++++++++++++++++++++++++++++++++++++
+ 2 files changed, 57 insertions(+)
+
+--- a/fs/nfsd/nfs4state.c
++++ b/fs/nfsd/nfs4state.c
+@@ -1367,6 +1367,8 @@ static void revoke_delegation(struct nfs
+
+ WARN_ON(!list_empty(&dp->dl_recall_lru));
+
++ trace_nfsd_stid_revoke(&dp->dl_stid);
++
+ if (clp->cl_minorversion) {
+ spin_lock(&clp->cl_lock);
+ dp->dl_stid.sc_type = NFS4_REVOKED_DELEG_STID;
+--- a/fs/nfsd/trace.h
++++ b/fs/nfsd/trace.h
+@@ -637,6 +637,61 @@ DEFINE_EVENT(nfsd_stateseqid_class, nfsd
+ DEFINE_STATESEQID_EVENT(preprocess);
+ DEFINE_STATESEQID_EVENT(open_confirm);
+
++TRACE_DEFINE_ENUM(NFS4_OPEN_STID);
++TRACE_DEFINE_ENUM(NFS4_LOCK_STID);
++TRACE_DEFINE_ENUM(NFS4_DELEG_STID);
++TRACE_DEFINE_ENUM(NFS4_CLOSED_STID);
++TRACE_DEFINE_ENUM(NFS4_REVOKED_DELEG_STID);
++TRACE_DEFINE_ENUM(NFS4_CLOSED_DELEG_STID);
++TRACE_DEFINE_ENUM(NFS4_LAYOUT_STID);
++
++#define show_stid_type(x) \
++ __print_flags(x, "|", \
++ { NFS4_OPEN_STID, "OPEN" }, \
++ { NFS4_LOCK_STID, "LOCK" }, \
++ { NFS4_DELEG_STID, "DELEG" }, \
++ { NFS4_CLOSED_STID, "CLOSED" }, \
++ { NFS4_REVOKED_DELEG_STID, "REVOKED" }, \
++ { NFS4_CLOSED_DELEG_STID, "CLOSED_DELEG" }, \
++ { NFS4_LAYOUT_STID, "LAYOUT" })
++
++DECLARE_EVENT_CLASS(nfsd_stid_class,
++ TP_PROTO(
++ const struct nfs4_stid *stid
++ ),
++ TP_ARGS(stid),
++ TP_STRUCT__entry(
++ __field(unsigned long, sc_type)
++ __field(int, sc_count)
++ __field(u32, cl_boot)
++ __field(u32, cl_id)
++ __field(u32, si_id)
++ __field(u32, si_generation)
++ ),
++ TP_fast_assign(
++ const stateid_t *stp = &stid->sc_stateid;
++
++ __entry->sc_type = stid->sc_type;
++ __entry->sc_count = refcount_read(&stid->sc_count);
++ __entry->cl_boot = stp->si_opaque.so_clid.cl_boot;
++ __entry->cl_id = stp->si_opaque.so_clid.cl_id;
++ __entry->si_id = stp->si_opaque.so_id;
++ __entry->si_generation = stp->si_generation;
++ ),
++ TP_printk("client %08x:%08x stateid %08x:%08x ref=%d type=%s",
++ __entry->cl_boot, __entry->cl_id,
++ __entry->si_id, __entry->si_generation,
++ __entry->sc_count, show_stid_type(__entry->sc_type)
++ )
++);
++
++#define DEFINE_STID_EVENT(name) \
++DEFINE_EVENT(nfsd_stid_class, nfsd_stid_##name, \
++ TP_PROTO(const struct nfs4_stid *stid), \
++ TP_ARGS(stid))
++
++DEFINE_STID_EVENT(revoke);
++
+ DECLARE_EVENT_CLASS(nfsd_clientid_class,
+ TP_PROTO(const clientid_t *clid),
+ TP_ARGS(clid),
--- /dev/null
+From 8bf3a8b39dca377e31a2fb35c6166bcd09e4c614 Mon Sep 17 00:00:00 2001
+From: Chuck Lever <chuck.lever@oracle.com>
+Date: Fri, 28 Oct 2022 10:47:03 -0400
+Subject: NFSD: Trace stateids returned via DELEGRETURN
+
+From: Chuck Lever <chuck.lever@oracle.com>
+
+[ Upstream commit 20eee313ff4b8a7e71ae9560f5c4ba27cd763005 ]
+
+Handing out a delegation stateid is recorded with the
+nfsd_deleg_read tracepoint, but there isn't a matching tracepoint
+for recording when the stateid is returned.
+
+Signed-off-by: Chuck Lever <chuck.lever@oracle.com>
+Reviewed-by: Jeff Layton <jlayton@kernel.org>
+Signed-off-by: Chuck Lever <chuck.lever@oracle.com>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+---
+ fs/nfsd/nfs4state.c | 1 +
+ fs/nfsd/trace.h | 1 +
+ 2 files changed, 2 insertions(+)
+
+--- a/fs/nfsd/nfs4state.c
++++ b/fs/nfsd/nfs4state.c
+@@ -6935,6 +6935,7 @@ nfsd4_delegreturn(struct svc_rqst *rqstp
+ if (status)
+ goto put_stateid;
+
++ trace_nfsd_deleg_return(stateid);
+ wake_up_var(d_inode(cstate->current_fh.fh_dentry));
+ destroy_delegation(dp);
+ put_stateid:
+--- a/fs/nfsd/trace.h
++++ b/fs/nfsd/trace.h
+@@ -604,6 +604,7 @@ DEFINE_STATEID_EVENT(layout_recall_relea
+
+ DEFINE_STATEID_EVENT(open);
+ DEFINE_STATEID_EVENT(deleg_read);
++DEFINE_STATEID_EVENT(deleg_return);
+ DEFINE_STATEID_EVENT(deleg_recall);
+
+ DECLARE_EVENT_CLASS(nfsd_stateseqid_class,
--- /dev/null
+From 3ac41c7dc2312e3fd4ce27676c54c596f06981f4 Mon Sep 17 00:00:00 2001
+From: Chuck Lever <chuck.lever@oracle.com>
+Date: Fri, 28 Oct 2022 10:47:22 -0400
+Subject: NFSD: Update file_hashtbl() helpers
+
+From: Chuck Lever <chuck.lever@oracle.com>
+
+[ Upstream commit 3fe828caddd81e68e9d29353c6e9285a658ca056 ]
+
+Enable callers to use const pointers for type safety.
+
+Signed-off-by: Chuck Lever <chuck.lever@oracle.com>
+Reviewed-by: NeilBrown <neilb@suse.de>
+Reviewed-by: Jeff Layton <jlayton@kernel.org>
+Signed-off-by: Chuck Lever <chuck.lever@oracle.com>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+---
+ fs/nfsd/nfs4state.c | 4 ++--
+ 1 file changed, 2 insertions(+), 2 deletions(-)
+
+--- a/fs/nfsd/nfs4state.c
++++ b/fs/nfsd/nfs4state.c
+@@ -721,7 +721,7 @@ static unsigned int ownerstr_hashval(str
+ #define FILE_HASH_BITS 8
+ #define FILE_HASH_SIZE (1 << FILE_HASH_BITS)
+
+-static unsigned int file_hashval(struct svc_fh *fh)
++static unsigned int file_hashval(const struct svc_fh *fh)
+ {
+ struct inode *inode = d_inode(fh->fh_dentry);
+
+@@ -4687,7 +4687,7 @@ move_to_close_lru(struct nfs4_ol_stateid
+
+ /* search file_hashtbl[] for file */
+ static struct nfs4_file *
+-find_file_locked(struct svc_fh *fh, unsigned int hashval)
++find_file_locked(const struct svc_fh *fh, unsigned int hashval)
+ {
+ struct nfs4_file *fp;
+
--- /dev/null
+From 26e1bf703d792962a07841f94026324d690a938d Mon Sep 17 00:00:00 2001
+From: Chuck Lever <chuck.lever@oracle.com>
+Date: Fri, 28 Oct 2022 10:47:16 -0400
+Subject: NFSD: Use const pointers as parameters to fh_ helpers
+
+From: Chuck Lever <chuck.lever@oracle.com>
+
+[ Upstream commit b48f8056c034f28dd54668399f1d22be421b0bef ]
+
+Enable callers to use const pointers where they are able to.
+
+Signed-off-by: Chuck Lever <chuck.lever@oracle.com>
+Tested-by: Jeff Layton <jlayton@kernel.org>
+Reviewed-by: Jeff Layton <jlayton@kernel.org>
+Reviewed-by: NeilBrown <neilb@suse.de>
+Signed-off-by: Chuck Lever <chuck.lever@oracle.com>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+---
+ fs/nfsd/nfsfh.h | 10 ++++++----
+ 1 file changed, 6 insertions(+), 4 deletions(-)
+
+--- a/fs/nfsd/nfsfh.h
++++ b/fs/nfsd/nfsfh.h
+@@ -220,7 +220,7 @@ __be32 fh_update(struct svc_fh *);
+ void fh_put(struct svc_fh *);
+
+ static __inline__ struct svc_fh *
+-fh_copy(struct svc_fh *dst, struct svc_fh *src)
++fh_copy(struct svc_fh *dst, const struct svc_fh *src)
+ {
+ WARN_ON(src->fh_dentry);
+
+@@ -229,7 +229,7 @@ fh_copy(struct svc_fh *dst, struct svc_f
+ }
+
+ static inline void
+-fh_copy_shallow(struct knfsd_fh *dst, struct knfsd_fh *src)
++fh_copy_shallow(struct knfsd_fh *dst, const struct knfsd_fh *src)
+ {
+ dst->fh_size = src->fh_size;
+ memcpy(&dst->fh_raw, &src->fh_raw, src->fh_size);
+@@ -243,7 +243,8 @@ fh_init(struct svc_fh *fhp, int maxsize)
+ return fhp;
+ }
+
+-static inline bool fh_match(struct knfsd_fh *fh1, struct knfsd_fh *fh2)
++static inline bool fh_match(const struct knfsd_fh *fh1,
++ const struct knfsd_fh *fh2)
+ {
+ if (fh1->fh_size != fh2->fh_size)
+ return false;
+@@ -252,7 +253,8 @@ static inline bool fh_match(struct knfsd
+ return true;
+ }
+
+-static inline bool fh_fsid_match(struct knfsd_fh *fh1, struct knfsd_fh *fh2)
++static inline bool fh_fsid_match(const struct knfsd_fh *fh1,
++ const struct knfsd_fh *fh2)
+ {
+ if (fh1->fh_fsid_type != fh2->fh_fsid_type)
+ return false;
--- /dev/null
+From 38d71d411f45436b789a5db9bfeb814a049ea1d3 Mon Sep 17 00:00:00 2001
+From: Jeff Layton <jlayton@kernel.org>
+Date: Wed, 16 Nov 2022 09:36:07 -0500
+Subject: nfsd: use locks_inode_context helper
+
+From: Jeff Layton <jlayton@kernel.org>
+
+[ Upstream commit 77c67530e1f95ac25c7075635f32f04367380894 ]
+
+nfsd currently doesn't access i_flctx safely everywhere. This requires a
+smp_load_acquire, as the pointer is set via cmpxchg (a release
+operation).
+
+Acked-by: Chuck Lever <chuck.lever@oracle.com>
+Reviewed-by: Christoph Hellwig <hch@lst.de>
+Signed-off-by: Jeff Layton <jlayton@kernel.org>
+Signed-off-by: Chuck Lever <chuck.lever@oracle.com>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+---
+ fs/nfsd/nfs4state.c | 6 +++---
+ 1 file changed, 3 insertions(+), 3 deletions(-)
+
+--- a/fs/nfsd/nfs4state.c
++++ b/fs/nfsd/nfs4state.c
+@@ -4784,7 +4784,7 @@ nfs4_share_conflict(struct svc_fh *curre
+
+ static bool nfsd4_deleg_present(const struct inode *inode)
+ {
+- struct file_lock_context *ctx = smp_load_acquire(&inode->i_flctx);
++ struct file_lock_context *ctx = locks_inode_context(inode);
+
+ return ctx && !list_empty_careful(&ctx->flc_lease);
+ }
+@@ -5944,7 +5944,7 @@ nfs4_lockowner_has_blockers(struct nfs4_
+
+ list_for_each_entry(stp, &lo->lo_owner.so_stateids, st_perstateowner) {
+ nf = stp->st_stid.sc_file;
+- ctx = nf->fi_inode->i_flctx;
++ ctx = locks_inode_context(nf->fi_inode);
+ if (!ctx)
+ continue;
+ if (locks_owner_has_blockers(ctx, lo))
+@@ -7761,7 +7761,7 @@ check_for_locks(struct nfs4_file *fp, st
+ }
+
+ inode = locks_inode(nf->nf_file);
+- flctx = inode->i_flctx;
++ flctx = locks_inode_context(inode);
+
+ if (flctx && !list_empty_careful(&flctx->flc_posix)) {
+ spin_lock(&flctx->flc_lock);
--- /dev/null
+From c719a184ac3261c27c996d0ca852456be53ed7b8 Mon Sep 17 00:00:00 2001
+From: Chuck Lever <chuck.lever@oracle.com>
+Date: Sat, 26 Nov 2022 15:55:30 -0500
+Subject: NFSD: Use only RQ_DROPME to signal the need to drop a reply
+
+From: Chuck Lever <chuck.lever@oracle.com>
+
+[ Upstream commit 9315564747cb6a570e99196b3a4880fb817635fd ]
+
+Clean up: NFSv2 has the only two usages of rpc_drop_reply in the
+NFSD code base. Since NFSv2 is going away at some point, replace
+these in order to simplify the "drop this reply?" check in
+nfsd_dispatch().
+
+Signed-off-by: Chuck Lever <chuck.lever@oracle.com>
+Reviewed-by: Jeff Layton <jlayton@kernel.org>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+---
+ fs/nfsd/nfsproc.c | 4 ++--
+ fs/nfsd/nfssvc.c | 2 +-
+ 2 files changed, 3 insertions(+), 3 deletions(-)
+
+--- a/fs/nfsd/nfsproc.c
++++ b/fs/nfsd/nfsproc.c
+@@ -211,7 +211,7 @@ nfsd_proc_read(struct svc_rqst *rqstp)
+ if (resp->status == nfs_ok)
+ resp->status = fh_getattr(&resp->fh, &resp->stat);
+ else if (resp->status == nfserr_jukebox)
+- return rpc_drop_reply;
++ __set_bit(RQ_DROPME, &rqstp->rq_flags);
+ return rpc_success;
+ }
+
+@@ -246,7 +246,7 @@ nfsd_proc_write(struct svc_rqst *rqstp)
+ if (resp->status == nfs_ok)
+ resp->status = fh_getattr(&resp->fh, &resp->stat);
+ else if (resp->status == nfserr_jukebox)
+- return rpc_drop_reply;
++ __set_bit(RQ_DROPME, &rqstp->rq_flags);
+ return rpc_success;
+ }
+
+--- a/fs/nfsd/nfssvc.c
++++ b/fs/nfsd/nfssvc.c
+@@ -1071,7 +1071,7 @@ int nfsd_dispatch(struct svc_rqst *rqstp
+
+ nfs_reply = xdr_inline_decode(&rqstp->rq_res_stream, 0);
+ *statp = proc->pc_func(rqstp);
+- if (*statp == rpc_drop_reply || test_bit(RQ_DROPME, &rqstp->rq_flags))
++ if (test_bit(RQ_DROPME, &rqstp->rq_flags))
+ goto out_update_drop;
+
+ if (!proc->pc_encode(rqstp, &rqstp->rq_res_stream))
--- /dev/null
+From d43d4bc06612be58600f8999e59dc569c0c45ca8 Mon Sep 17 00:00:00 2001
+From: Chuck Lever <chuck.lever@oracle.com>
+Date: Fri, 28 Oct 2022 10:47:53 -0400
+Subject: NFSD: Use rhashtable for managing nfs4_file objects
+
+From: Chuck Lever <chuck.lever@oracle.com>
+
+[ Upstream commit d47b295e8d76a4d69f0e2ea0cd8a79c9d3488280 ]
+
+fh_match() is costly, especially when filehandles are large (as is
+the case for NFSv4). It needs to be used sparingly when searching
+data structures. Unfortunately, with common workloads, I see
+multiple thousands of objects stored in file_hashtbl[], which has
+just 256 buckets, making its bucket hash chains quite lengthy.
+
+Walking long hash chains with the state_lock held blocks other
+activity that needs that lock. Sizable hash chains are a common
+occurrance once the server has handed out some delegations, for
+example -- IIUC, each delegated file is held open on the server by
+an nfs4_file object.
+
+To help mitigate the cost of searching with fh_match(), replace the
+nfs4_file hash table with an rhashtable, which can dynamically
+resize its bucket array to minimize hash chain length.
+
+The result of this modification is an improvement in the latency of
+NFSv4 operations, and the reduction of nfsd CPU utilization due to
+eliminating the cost of multiple calls to fh_match() and reducing
+the CPU cache misses incurred while walking long hash chains in the
+nfs4_file hash table.
+
+Signed-off-by: Chuck Lever <chuck.lever@oracle.com>
+Reviewed-by: NeilBrown <neilb@suse.de>
+Reviewed-by: Jeff Layton <jlayton@kernel.org>
+Signed-off-by: Chuck Lever <chuck.lever@oracle.com>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+---
+ fs/nfsd/nfs4state.c | 97 +++++++++++++++++++++++++++++++++-------------------
+ fs/nfsd/state.h | 5 --
+ 2 files changed, 63 insertions(+), 39 deletions(-)
+
+--- a/fs/nfsd/nfs4state.c
++++ b/fs/nfsd/nfs4state.c
+@@ -44,7 +44,9 @@
+ #include <linux/jhash.h>
+ #include <linux/string_helpers.h>
+ #include <linux/fsnotify.h>
++#include <linux/rhashtable.h>
+ #include <linux/nfs_ssc.h>
++
+ #include "xdr4.h"
+ #include "xdr4cb.h"
+ #include "vfs.h"
+@@ -589,11 +591,8 @@ static void nfsd4_free_file_rcu(struct r
+ void
+ put_nfs4_file(struct nfs4_file *fi)
+ {
+- might_lock(&state_lock);
+-
+- if (refcount_dec_and_lock(&fi->fi_ref, &state_lock)) {
++ if (refcount_dec_and_test(&fi->fi_ref)) {
+ nfsd4_file_hash_remove(fi);
+- spin_unlock(&state_lock);
+ WARN_ON_ONCE(!list_empty(&fi->fi_clnt_odstate));
+ WARN_ON_ONCE(!list_empty(&fi->fi_delegations));
+ call_rcu(&fi->fi_rcu, nfsd4_free_file_rcu);
+@@ -718,19 +717,20 @@ static unsigned int ownerstr_hashval(str
+ return ret & OWNER_HASH_MASK;
+ }
+
+-/* hash table for nfs4_file */
+-#define FILE_HASH_BITS 8
+-#define FILE_HASH_SIZE (1 << FILE_HASH_BITS)
+-
+-static unsigned int file_hashval(const struct svc_fh *fh)
+-{
+- struct inode *inode = d_inode(fh->fh_dentry);
++static struct rhltable nfs4_file_rhltable ____cacheline_aligned_in_smp;
+
+- /* XXX: why not (here & in file cache) use inode? */
+- return (unsigned int)hash_long(inode->i_ino, FILE_HASH_BITS);
+-}
++static const struct rhashtable_params nfs4_file_rhash_params = {
++ .key_len = sizeof_field(struct nfs4_file, fi_inode),
++ .key_offset = offsetof(struct nfs4_file, fi_inode),
++ .head_offset = offsetof(struct nfs4_file, fi_rlist),
+
+-static struct hlist_head file_hashtbl[FILE_HASH_SIZE];
++ /*
++ * Start with a single page hash table to reduce resizing churn
++ * on light workloads.
++ */
++ .min_size = 256,
++ .automatic_shrinking = true,
++};
+
+ /*
+ * Check if courtesy clients have conflicting access and resolve it if possible
+@@ -4686,12 +4686,14 @@ move_to_close_lru(struct nfs4_ol_stateid
+ static noinline_for_stack struct nfs4_file *
+ nfsd4_file_hash_lookup(const struct svc_fh *fhp)
+ {
+- unsigned int hashval = file_hashval(fhp);
++ struct inode *inode = d_inode(fhp->fh_dentry);
++ struct rhlist_head *tmp, *list;
+ struct nfs4_file *fi;
+
+ rcu_read_lock();
+- hlist_for_each_entry_rcu(fi, &file_hashtbl[hashval], fi_hash,
+- lockdep_is_held(&state_lock)) {
++ list = rhltable_lookup(&nfs4_file_rhltable, &inode,
++ nfs4_file_rhash_params);
++ rhl_for_each_entry_rcu(fi, tmp, list, fi_rlist) {
+ if (fh_match(&fi->fi_fhandle, &fhp->fh_handle)) {
+ if (refcount_inc_not_zero(&fi->fi_ref)) {
+ rcu_read_unlock();
+@@ -4705,40 +4707,56 @@ nfsd4_file_hash_lookup(const struct svc_
+
+ /*
+ * On hash insertion, identify entries with the same inode but
+- * distinct filehandles. They will all be in the same hash bucket
+- * because nfs4_file's are hashed by the address in the fi_inode
+- * field.
++ * distinct filehandles. They will all be on the list returned
++ * by rhltable_lookup().
++ *
++ * inode->i_lock prevents racing insertions from adding an entry
++ * for the same inode/fhp pair twice.
+ */
+ static noinline_for_stack struct nfs4_file *
+ nfsd4_file_hash_insert(struct nfs4_file *new, const struct svc_fh *fhp)
+ {
+- unsigned int hashval = file_hashval(fhp);
++ struct inode *inode = d_inode(fhp->fh_dentry);
++ struct rhlist_head *tmp, *list;
+ struct nfs4_file *ret = NULL;
+ bool alias_found = false;
+ struct nfs4_file *fi;
++ int err;
+
+- spin_lock(&state_lock);
+- hlist_for_each_entry_rcu(fi, &file_hashtbl[hashval], fi_hash,
+- lockdep_is_held(&state_lock)) {
++ rcu_read_lock();
++ spin_lock(&inode->i_lock);
++
++ list = rhltable_lookup(&nfs4_file_rhltable, &inode,
++ nfs4_file_rhash_params);
++ rhl_for_each_entry_rcu(fi, tmp, list, fi_rlist) {
+ if (fh_match(&fi->fi_fhandle, &fhp->fh_handle)) {
+ if (refcount_inc_not_zero(&fi->fi_ref))
+ ret = fi;
+- } else if (d_inode(fhp->fh_dentry) == fi->fi_inode)
++ } else
+ fi->fi_aliased = alias_found = true;
+ }
+- if (likely(ret == NULL)) {
+- nfsd4_file_init(fhp, new);
+- hlist_add_head_rcu(&new->fi_hash, &file_hashtbl[hashval]);
+- new->fi_aliased = alias_found;
+- ret = new;
+- }
+- spin_unlock(&state_lock);
++ if (ret)
++ goto out_unlock;
++
++ nfsd4_file_init(fhp, new);
++ err = rhltable_insert(&nfs4_file_rhltable, &new->fi_rlist,
++ nfs4_file_rhash_params);
++ if (err)
++ goto out_unlock;
++
++ new->fi_aliased = alias_found;
++ ret = new;
++
++out_unlock:
++ spin_unlock(&inode->i_lock);
++ rcu_read_unlock();
+ return ret;
+ }
+
+ static noinline_for_stack void nfsd4_file_hash_remove(struct nfs4_file *fi)
+ {
+- hlist_del_rcu(&fi->fi_hash);
++ rhltable_remove(&nfs4_file_rhltable, &fi->fi_rlist,
++ nfs4_file_rhash_params);
+ }
+
+ /*
+@@ -5648,6 +5666,8 @@ nfsd4_process_open2(struct svc_rqst *rqs
+ * If not found, create the nfs4_file struct
+ */
+ fp = nfsd4_file_hash_insert(open->op_file, current_fh);
++ if (unlikely(!fp))
++ return nfserr_jukebox;
+ if (fp != open->op_file) {
+ status = nfs4_check_deleg(cl, open, &dp);
+ if (status)
+@@ -8064,10 +8084,16 @@ nfs4_state_start(void)
+ {
+ int ret;
+
+- ret = nfsd4_create_callback_queue();
++ ret = rhltable_init(&nfs4_file_rhltable, &nfs4_file_rhash_params);
+ if (ret)
+ return ret;
+
++ ret = nfsd4_create_callback_queue();
++ if (ret) {
++ rhltable_destroy(&nfs4_file_rhltable);
++ return ret;
++ }
++
+ set_max_delegations();
+ return 0;
+ }
+@@ -8098,6 +8124,7 @@ nfs4_state_shutdown_net(struct net *net)
+
+ nfsd4_client_tracking_exit(net);
+ nfs4_state_destroy_net(net);
++ rhltable_destroy(&nfs4_file_rhltable);
+ #ifdef CONFIG_NFSD_V4_2_INTER_SSC
+ nfsd4_ssc_shutdown_umount(nn);
+ #endif
+--- a/fs/nfsd/state.h
++++ b/fs/nfsd/state.h
+@@ -536,16 +536,13 @@ struct nfs4_clnt_odstate {
+ * inode can have multiple filehandles associated with it, so there is
+ * (potentially) a many to one relationship between this struct and struct
+ * inode.
+- *
+- * These are hashed by filehandle in the file_hashtbl, which is protected by
+- * the global state_lock spinlock.
+ */
+ struct nfs4_file {
+ refcount_t fi_ref;
+ struct inode * fi_inode;
+ bool fi_aliased;
+ spinlock_t fi_lock;
+- struct hlist_node fi_hash; /* hash on fi_fhandle */
++ struct rhlist_head fi_rlist;
+ struct list_head fi_stateids;
+ union {
+ struct list_head fi_delegations;
--- /dev/null
+From a84e0f59363de87491392d26c0b8a61993276898 Mon Sep 17 00:00:00 2001
+From: Chuck Lever <chuck.lever@oracle.com>
+Date: Sat, 7 Jan 2023 10:15:35 -0500
+Subject: NFSD: Use set_bit(RQ_DROPME)
+
+From: Chuck Lever <chuck.lever@oracle.com>
+
+[ Upstream commit 5304930dbae82d259bcf7e5611db7c81e7a42eff ]
+
+The premise that "Once an svc thread is scheduled and executing an
+RPC, no other processes will touch svc_rqst::rq_flags" is false.
+svc_xprt_enqueue() examines the RQ_BUSY flag in scheduled nfsd
+threads when determining which thread to wake up next.
+
+Fixes: 9315564747cb ("NFSD: Use only RQ_DROPME to signal the need to drop a reply")
+Signed-off-by: Chuck Lever <chuck.lever@oracle.com>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+---
+ fs/nfsd/nfsproc.c | 4 ++--
+ 1 file changed, 2 insertions(+), 2 deletions(-)
+
+--- a/fs/nfsd/nfsproc.c
++++ b/fs/nfsd/nfsproc.c
+@@ -211,7 +211,7 @@ nfsd_proc_read(struct svc_rqst *rqstp)
+ if (resp->status == nfs_ok)
+ resp->status = fh_getattr(&resp->fh, &resp->stat);
+ else if (resp->status == nfserr_jukebox)
+- __set_bit(RQ_DROPME, &rqstp->rq_flags);
++ set_bit(RQ_DROPME, &rqstp->rq_flags);
+ return rpc_success;
+ }
+
+@@ -246,7 +246,7 @@ nfsd_proc_write(struct svc_rqst *rqstp)
+ if (resp->status == nfs_ok)
+ resp->status = fh_getattr(&resp->fh, &resp->stat);
+ else if (resp->status == nfserr_jukebox)
+- __set_bit(RQ_DROPME, &rqstp->rq_flags);
++ set_bit(RQ_DROPME, &rqstp->rq_flags);
+ return rpc_success;
+ }
+
--- /dev/null
+From dd2b71cd068ca2cad01164b0500faae1dc607005 Mon Sep 17 00:00:00 2001
+From: Xiu Jianfeng <xiujianfeng@huawei.com>
+Date: Fri, 11 Nov 2022 17:18:35 +0800
+Subject: NFSD: Use struct_size() helper in alloc_session()
+
+From: Xiu Jianfeng <xiujianfeng@huawei.com>
+
+[ Upstream commit 85a0d0c9a58002ef7d1bf5e3ea630f4fbd42a4f0 ]
+
+Use struct_size() helper to simplify the code, no functional changes.
+
+Signed-off-by: Xiu Jianfeng <xiujianfeng@huawei.com>
+Reviewed-by: Jeff Layton <jlayton@kernel.org>
+Signed-off-by: Chuck Lever <chuck.lever@oracle.com>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+---
+ fs/nfsd/nfs4state.c | 9 ++++-----
+ 1 file changed, 4 insertions(+), 5 deletions(-)
+
+--- a/fs/nfsd/nfs4state.c
++++ b/fs/nfsd/nfs4state.c
+@@ -1834,13 +1834,12 @@ static struct nfsd4_session *alloc_sessi
+ int numslots = fattrs->maxreqs;
+ int slotsize = slot_bytes(fattrs);
+ struct nfsd4_session *new;
+- int mem, i;
++ int i;
+
+- BUILD_BUG_ON(NFSD_MAX_SLOTS_PER_SESSION * sizeof(struct nfsd4_slot *)
+- + sizeof(struct nfsd4_session) > PAGE_SIZE);
+- mem = numslots * sizeof(struct nfsd4_slot *);
++ BUILD_BUG_ON(struct_size(new, se_slots, NFSD_MAX_SLOTS_PER_SESSION)
++ > PAGE_SIZE);
+
+- new = kzalloc(sizeof(*new) + mem, GFP_KERNEL);
++ new = kzalloc(struct_size(new, se_slots, numslots), GFP_KERNEL);
+ if (!new)
+ return NULL;
+ /* allocate each struct nfsd4_slot and data cache in one piece */
decompress-use-8-byte-alignment.patch
drm-amd-display-increase-frame-warning-limit-with-kasan-or-kcsan-in-dml.patch
nfs-fix-data-corruption-caused-by-congestion.patch
+nfsd-simplify-read_plus.patch
+nfsd-remove-redundant-assignment-to-variable-host_err.patch
+nfsd-ignore-requests-to-disable-unsupported-versions.patch
+nfsd-move-nfserrno-to-vfs.c.patch
+nfsd-allow-disabling-nfsv2-at-compile-time.patch
+exportfs-use-pr_debug-for-unreachable-debug-statements.patch
+nfsd-flesh-out-a-documenting-comment-for-filecache.c.patch
+nfsd-clean-up-nfs4_preprocess_stateid_op-call-sites.patch
+nfsd-trace-stateids-returned-via-delegreturn.patch
+nfsd-trace-delegation-revocations.patch
+nfsd-use-const-pointers-as-parameters-to-fh_-helpers.patch
+nfsd-update-file_hashtbl-helpers.patch
+nfsd-clean-up-nfsd4_init_file.patch
+nfsd-add-a-nfsd4_file_hash_remove-helper.patch
+nfsd-clean-up-find_or_add_file.patch
+nfsd-refactor-find_file.patch
+nfsd-use-rhashtable-for-managing-nfs4_file-objects.patch
+nfsd-fix-licensing-header-in-filecache.c.patch
+filelock-add-a-new-locks_inode_context-accessor-function.patch
+lockd-use-locks_inode_context-helper.patch
+nfsd-use-locks_inode_context-helper.patch
+nfsd-fix-up-the-filecache-laundrette-scheduling.patch
+nfsd-use-struct_size-helper-in-alloc_session.patch
+lockd-set-missing-fl_flags-field-when-retrieving-args.patch
+lockd-ensure-we-use-the-correct-file-descriptor-when-unlocking.patch
+lockd-fix-file-selection-in-nlmsvc_cancel_blocked.patch
+trace-relocate-event-helper-files.patch
+nfsd-refactoring-courtesy_client_reaper-to-a-generic-low-memory-shrinker.patch
+nfsd-add-support-for-sending-cb_recall_any.patch
+nfsd-add-delegation-reaper-to-react-to-low-memory-condition.patch
+nfsd-add-cb_recall_any-tracepoints.patch
+nfsd-use-only-rq_dropme-to-signal-the-need-to-drop-a-reply.patch
+nfsd-avoid-clashing-function-prototypes.patch
+nfsd-use-set_bit-rq_dropme.patch
+nfsd-register-unregister-of-nfsd-client-shrinker-at-nfsd-startup-shutdown-time.patch
+nfsd-replace-delayed_work-with-work_struct-for-nfsd_client_shrinker.patch
+nfsd-don-t-destroy-global-nfs4_file-table-in-per-net-shutdown.patch
--- /dev/null
+From 9611f3b43fd527f64ebd2a6620268096affc46e8 Mon Sep 17 00:00:00 2001
+From: Chuck Lever <chuck.lever@oracle.com>
+Date: Mon, 14 Nov 2022 08:57:43 -0500
+Subject: trace: Relocate event helper files
+
+From: Chuck Lever <chuck.lever@oracle.com>
+
+[ Upstream commit 247c01ff5f8d66e62a404c91733be52fecb8b7f6 ]
+
+Steven Rostedt says:
+> The include/trace/events/ directory should only hold files that
+> are to create events, not headers that hold helper functions.
+>
+> Can you please move them out of include/trace/events/ as that
+> directory is "special" in the creation of events.
+
+Signed-off-by: Chuck Lever <chuck.lever@oracle.com>
+Acked-by: Leon Romanovsky <leonro@nvidia.com>
+Acked-by: Steven Rostedt (Google) <rostedt@goodmis.org>
+Acked-by: Anna Schumaker <Anna.Schumaker@Netapp.com>
+Stable-dep-of: 638593be55c0 ("NFSD: add CB_RECALL_ANY tracepoints")
+Signed-off-by: Chuck Lever <chuck.lever@oracle.com>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+---
+ MAINTAINERS | 7 +++++++
+ drivers/infiniband/core/cm_trace.h | 2 +-
+ drivers/infiniband/core/cma_trace.h | 2 +-
+ fs/nfs/nfs4trace.h | 6 +++---
+ fs/nfs/nfstrace.h | 6 +++---
+ include/trace/events/rpcgss.h | 2 +-
+ include/trace/events/rpcrdma.h | 4 ++--
+ include/trace/events/sunrpc.h | 2 +-
+ include/trace/{events => misc}/fs.h | 0
+ include/trace/{events => misc}/nfs.h | 0
+ include/trace/{events => misc}/rdma.h | 0
+ include/trace/{events/sunrpc_base.h => misc/sunrpc.h} | 0
+ MAINTAINERS | 7
+ drivers/infiniband/core/cm_trace.h | 2
+ drivers/infiniband/core/cma_trace.h | 2
+ fs/nfs/nfs4trace.h | 6
+ fs/nfs/nfstrace.h | 6
+ include/trace/events/fs.h | 122 -----------
+ include/trace/events/nfs.h | 375 ------------------------------------
+ include/trace/events/rdma.h | 168 ----------------
+ include/trace/events/rpcgss.h | 2
+ include/trace/events/rpcrdma.h | 4
+ include/trace/events/sunrpc.h | 2
+ include/trace/events/sunrpc_base.h | 18 -
+ include/trace/misc/fs.h | 122 +++++++++++
+ include/trace/misc/nfs.h | 375 ++++++++++++++++++++++++++++++++++++
+ include/trace/misc/rdma.h | 168 ++++++++++++++++
+ include/trace/misc/sunrpc.h | 18 +
+ 16 files changed, 702 insertions(+), 695 deletions(-)
+ rename include/trace/{events => misc}/fs.h (100%)
+ rename include/trace/{events => misc}/nfs.h (100%)
+ rename include/trace/{events => misc}/rdma.h (100%)
+ rename include/trace/{events/sunrpc_base.h => misc/sunrpc.h} (100%)
+
+--- a/MAINTAINERS
++++ b/MAINTAINERS
+@@ -10051,6 +10051,7 @@ F: drivers/infiniband/
+ F: include/rdma/
+ F: include/trace/events/ib_mad.h
+ F: include/trace/events/ib_umad.h
++F: include/trace/misc/rdma.h
+ F: include/uapi/linux/if_infiniband.h
+ F: include/uapi/rdma/
+ F: samples/bpf/ibumad_kern.c
+@@ -11139,6 +11140,12 @@ F: fs/nfs_common/
+ F: fs/nfsd/
+ F: include/linux/lockd/
+ F: include/linux/sunrpc/
++F: include/trace/events/rpcgss.h
++F: include/trace/events/rpcrdma.h
++F: include/trace/events/sunrpc.h
++F: include/trace/misc/fs.h
++F: include/trace/misc/nfs.h
++F: include/trace/misc/sunrpc.h
+ F: include/uapi/linux/nfsd/
+ F: include/uapi/linux/sunrpc/
+ F: net/sunrpc/
+--- a/drivers/infiniband/core/cm_trace.h
++++ b/drivers/infiniband/core/cm_trace.h
+@@ -16,7 +16,7 @@
+
+ #include <linux/tracepoint.h>
+ #include <rdma/ib_cm.h>
+-#include <trace/events/rdma.h>
++#include <trace/misc/rdma.h>
+
+ /*
+ * enum ib_cm_state, from include/rdma/ib_cm.h
+--- a/drivers/infiniband/core/cma_trace.h
++++ b/drivers/infiniband/core/cma_trace.h
+@@ -15,7 +15,7 @@
+ #define _TRACE_RDMA_CMA_H
+
+ #include <linux/tracepoint.h>
+-#include <trace/events/rdma.h>
++#include <trace/misc/rdma.h>
+
+
+ DECLARE_EVENT_CLASS(cma_fsm_class,
+--- a/fs/nfs/nfs4trace.h
++++ b/fs/nfs/nfs4trace.h
+@@ -9,10 +9,10 @@
+ #define _TRACE_NFS4_H
+
+ #include <linux/tracepoint.h>
+-#include <trace/events/sunrpc_base.h>
++#include <trace/misc/sunrpc.h>
+
+-#include <trace/events/fs.h>
+-#include <trace/events/nfs.h>
++#include <trace/misc/fs.h>
++#include <trace/misc/nfs.h>
+
+ #define show_nfs_fattr_flags(valid) \
+ __print_flags((unsigned long)valid, "|", \
+--- a/fs/nfs/nfstrace.h
++++ b/fs/nfs/nfstrace.h
+@@ -11,9 +11,9 @@
+ #include <linux/tracepoint.h>
+ #include <linux/iversion.h>
+
+-#include <trace/events/fs.h>
+-#include <trace/events/nfs.h>
+-#include <trace/events/sunrpc_base.h>
++#include <trace/misc/fs.h>
++#include <trace/misc/nfs.h>
++#include <trace/misc/sunrpc.h>
+
+ #define nfs_show_cache_validity(v) \
+ __print_flags(v, "|", \
+--- a/include/trace/events/fs.h
++++ /dev/null
+@@ -1,122 +0,0 @@
+-/* SPDX-License-Identifier: GPL-2.0 */
+-/*
+- * Display helpers for generic filesystem items
+- *
+- * Author: Chuck Lever <chuck.lever@oracle.com>
+- *
+- * Copyright (c) 2020, Oracle and/or its affiliates.
+- */
+-
+-#include <linux/fs.h>
+-
+-#define show_fs_dirent_type(x) \
+- __print_symbolic(x, \
+- { DT_UNKNOWN, "UNKNOWN" }, \
+- { DT_FIFO, "FIFO" }, \
+- { DT_CHR, "CHR" }, \
+- { DT_DIR, "DIR" }, \
+- { DT_BLK, "BLK" }, \
+- { DT_REG, "REG" }, \
+- { DT_LNK, "LNK" }, \
+- { DT_SOCK, "SOCK" }, \
+- { DT_WHT, "WHT" })
+-
+-#define show_fs_fcntl_open_flags(x) \
+- __print_flags(x, "|", \
+- { O_WRONLY, "O_WRONLY" }, \
+- { O_RDWR, "O_RDWR" }, \
+- { O_CREAT, "O_CREAT" }, \
+- { O_EXCL, "O_EXCL" }, \
+- { O_NOCTTY, "O_NOCTTY" }, \
+- { O_TRUNC, "O_TRUNC" }, \
+- { O_APPEND, "O_APPEND" }, \
+- { O_NONBLOCK, "O_NONBLOCK" }, \
+- { O_DSYNC, "O_DSYNC" }, \
+- { O_DIRECT, "O_DIRECT" }, \
+- { O_LARGEFILE, "O_LARGEFILE" }, \
+- { O_DIRECTORY, "O_DIRECTORY" }, \
+- { O_NOFOLLOW, "O_NOFOLLOW" }, \
+- { O_NOATIME, "O_NOATIME" }, \
+- { O_CLOEXEC, "O_CLOEXEC" })
+-
+-#define __fmode_flag(x) { (__force unsigned long)FMODE_##x, #x }
+-#define show_fs_fmode_flags(x) \
+- __print_flags(x, "|", \
+- __fmode_flag(READ), \
+- __fmode_flag(WRITE), \
+- __fmode_flag(EXEC))
+-
+-#ifdef CONFIG_64BIT
+-#define show_fs_fcntl_cmd(x) \
+- __print_symbolic(x, \
+- { F_DUPFD, "DUPFD" }, \
+- { F_GETFD, "GETFD" }, \
+- { F_SETFD, "SETFD" }, \
+- { F_GETFL, "GETFL" }, \
+- { F_SETFL, "SETFL" }, \
+- { F_GETLK, "GETLK" }, \
+- { F_SETLK, "SETLK" }, \
+- { F_SETLKW, "SETLKW" }, \
+- { F_SETOWN, "SETOWN" }, \
+- { F_GETOWN, "GETOWN" }, \
+- { F_SETSIG, "SETSIG" }, \
+- { F_GETSIG, "GETSIG" }, \
+- { F_SETOWN_EX, "SETOWN_EX" }, \
+- { F_GETOWN_EX, "GETOWN_EX" }, \
+- { F_GETOWNER_UIDS, "GETOWNER_UIDS" }, \
+- { F_OFD_GETLK, "OFD_GETLK" }, \
+- { F_OFD_SETLK, "OFD_SETLK" }, \
+- { F_OFD_SETLKW, "OFD_SETLKW" })
+-#else /* CONFIG_64BIT */
+-#define show_fs_fcntl_cmd(x) \
+- __print_symbolic(x, \
+- { F_DUPFD, "DUPFD" }, \
+- { F_GETFD, "GETFD" }, \
+- { F_SETFD, "SETFD" }, \
+- { F_GETFL, "GETFL" }, \
+- { F_SETFL, "SETFL" }, \
+- { F_GETLK, "GETLK" }, \
+- { F_SETLK, "SETLK" }, \
+- { F_SETLKW, "SETLKW" }, \
+- { F_SETOWN, "SETOWN" }, \
+- { F_GETOWN, "GETOWN" }, \
+- { F_SETSIG, "SETSIG" }, \
+- { F_GETSIG, "GETSIG" }, \
+- { F_GETLK64, "GETLK64" }, \
+- { F_SETLK64, "SETLK64" }, \
+- { F_SETLKW64, "SETLKW64" }, \
+- { F_SETOWN_EX, "SETOWN_EX" }, \
+- { F_GETOWN_EX, "GETOWN_EX" }, \
+- { F_GETOWNER_UIDS, "GETOWNER_UIDS" }, \
+- { F_OFD_GETLK, "OFD_GETLK" }, \
+- { F_OFD_SETLK, "OFD_SETLK" }, \
+- { F_OFD_SETLKW, "OFD_SETLKW" })
+-#endif /* CONFIG_64BIT */
+-
+-#define show_fs_fcntl_lock_type(x) \
+- __print_symbolic(x, \
+- { F_RDLCK, "RDLCK" }, \
+- { F_WRLCK, "WRLCK" }, \
+- { F_UNLCK, "UNLCK" })
+-
+-#define show_fs_lookup_flags(flags) \
+- __print_flags(flags, "|", \
+- { LOOKUP_FOLLOW, "FOLLOW" }, \
+- { LOOKUP_DIRECTORY, "DIRECTORY" }, \
+- { LOOKUP_AUTOMOUNT, "AUTOMOUNT" }, \
+- { LOOKUP_EMPTY, "EMPTY" }, \
+- { LOOKUP_DOWN, "DOWN" }, \
+- { LOOKUP_MOUNTPOINT, "MOUNTPOINT" }, \
+- { LOOKUP_REVAL, "REVAL" }, \
+- { LOOKUP_RCU, "RCU" }, \
+- { LOOKUP_OPEN, "OPEN" }, \
+- { LOOKUP_CREATE, "CREATE" }, \
+- { LOOKUP_EXCL, "EXCL" }, \
+- { LOOKUP_RENAME_TARGET, "RENAME_TARGET" }, \
+- { LOOKUP_PARENT, "PARENT" }, \
+- { LOOKUP_NO_SYMLINKS, "NO_SYMLINKS" }, \
+- { LOOKUP_NO_MAGICLINKS, "NO_MAGICLINKS" }, \
+- { LOOKUP_NO_XDEV, "NO_XDEV" }, \
+- { LOOKUP_BENEATH, "BENEATH" }, \
+- { LOOKUP_IN_ROOT, "IN_ROOT" }, \
+- { LOOKUP_CACHED, "CACHED" })
+--- a/include/trace/events/nfs.h
++++ /dev/null
+@@ -1,375 +0,0 @@
+-/* SPDX-License-Identifier: GPL-2.0 */
+-/*
+- * Display helpers for NFS protocol elements
+- *
+- * Author: Chuck Lever <chuck.lever@oracle.com>
+- *
+- * Copyright (c) 2020, Oracle and/or its affiliates.
+- */
+-
+-#include <linux/nfs.h>
+-#include <linux/nfs4.h>
+-#include <uapi/linux/nfs.h>
+-
+-TRACE_DEFINE_ENUM(NFS_OK);
+-TRACE_DEFINE_ENUM(NFSERR_PERM);
+-TRACE_DEFINE_ENUM(NFSERR_NOENT);
+-TRACE_DEFINE_ENUM(NFSERR_IO);
+-TRACE_DEFINE_ENUM(NFSERR_NXIO);
+-TRACE_DEFINE_ENUM(NFSERR_EAGAIN);
+-TRACE_DEFINE_ENUM(NFSERR_ACCES);
+-TRACE_DEFINE_ENUM(NFSERR_EXIST);
+-TRACE_DEFINE_ENUM(NFSERR_XDEV);
+-TRACE_DEFINE_ENUM(NFSERR_NODEV);
+-TRACE_DEFINE_ENUM(NFSERR_NOTDIR);
+-TRACE_DEFINE_ENUM(NFSERR_ISDIR);
+-TRACE_DEFINE_ENUM(NFSERR_INVAL);
+-TRACE_DEFINE_ENUM(NFSERR_FBIG);
+-TRACE_DEFINE_ENUM(NFSERR_NOSPC);
+-TRACE_DEFINE_ENUM(NFSERR_ROFS);
+-TRACE_DEFINE_ENUM(NFSERR_MLINK);
+-TRACE_DEFINE_ENUM(NFSERR_OPNOTSUPP);
+-TRACE_DEFINE_ENUM(NFSERR_NAMETOOLONG);
+-TRACE_DEFINE_ENUM(NFSERR_NOTEMPTY);
+-TRACE_DEFINE_ENUM(NFSERR_DQUOT);
+-TRACE_DEFINE_ENUM(NFSERR_STALE);
+-TRACE_DEFINE_ENUM(NFSERR_REMOTE);
+-TRACE_DEFINE_ENUM(NFSERR_WFLUSH);
+-TRACE_DEFINE_ENUM(NFSERR_BADHANDLE);
+-TRACE_DEFINE_ENUM(NFSERR_NOT_SYNC);
+-TRACE_DEFINE_ENUM(NFSERR_BAD_COOKIE);
+-TRACE_DEFINE_ENUM(NFSERR_NOTSUPP);
+-TRACE_DEFINE_ENUM(NFSERR_TOOSMALL);
+-TRACE_DEFINE_ENUM(NFSERR_SERVERFAULT);
+-TRACE_DEFINE_ENUM(NFSERR_BADTYPE);
+-TRACE_DEFINE_ENUM(NFSERR_JUKEBOX);
+-
+-#define show_nfs_status(x) \
+- __print_symbolic(x, \
+- { NFS_OK, "OK" }, \
+- { NFSERR_PERM, "PERM" }, \
+- { NFSERR_NOENT, "NOENT" }, \
+- { NFSERR_IO, "IO" }, \
+- { NFSERR_NXIO, "NXIO" }, \
+- { ECHILD, "CHILD" }, \
+- { NFSERR_EAGAIN, "AGAIN" }, \
+- { NFSERR_ACCES, "ACCES" }, \
+- { NFSERR_EXIST, "EXIST" }, \
+- { NFSERR_XDEV, "XDEV" }, \
+- { NFSERR_NODEV, "NODEV" }, \
+- { NFSERR_NOTDIR, "NOTDIR" }, \
+- { NFSERR_ISDIR, "ISDIR" }, \
+- { NFSERR_INVAL, "INVAL" }, \
+- { NFSERR_FBIG, "FBIG" }, \
+- { NFSERR_NOSPC, "NOSPC" }, \
+- { NFSERR_ROFS, "ROFS" }, \
+- { NFSERR_MLINK, "MLINK" }, \
+- { NFSERR_OPNOTSUPP, "OPNOTSUPP" }, \
+- { NFSERR_NAMETOOLONG, "NAMETOOLONG" }, \
+- { NFSERR_NOTEMPTY, "NOTEMPTY" }, \
+- { NFSERR_DQUOT, "DQUOT" }, \
+- { NFSERR_STALE, "STALE" }, \
+- { NFSERR_REMOTE, "REMOTE" }, \
+- { NFSERR_WFLUSH, "WFLUSH" }, \
+- { NFSERR_BADHANDLE, "BADHANDLE" }, \
+- { NFSERR_NOT_SYNC, "NOTSYNC" }, \
+- { NFSERR_BAD_COOKIE, "BADCOOKIE" }, \
+- { NFSERR_NOTSUPP, "NOTSUPP" }, \
+- { NFSERR_TOOSMALL, "TOOSMALL" }, \
+- { NFSERR_SERVERFAULT, "REMOTEIO" }, \
+- { NFSERR_BADTYPE, "BADTYPE" }, \
+- { NFSERR_JUKEBOX, "JUKEBOX" })
+-
+-TRACE_DEFINE_ENUM(NFS_UNSTABLE);
+-TRACE_DEFINE_ENUM(NFS_DATA_SYNC);
+-TRACE_DEFINE_ENUM(NFS_FILE_SYNC);
+-
+-#define show_nfs_stable_how(x) \
+- __print_symbolic(x, \
+- { NFS_UNSTABLE, "UNSTABLE" }, \
+- { NFS_DATA_SYNC, "DATA_SYNC" }, \
+- { NFS_FILE_SYNC, "FILE_SYNC" })
+-
+-TRACE_DEFINE_ENUM(NFS4_OK);
+-TRACE_DEFINE_ENUM(NFS4ERR_ACCESS);
+-TRACE_DEFINE_ENUM(NFS4ERR_ATTRNOTSUPP);
+-TRACE_DEFINE_ENUM(NFS4ERR_ADMIN_REVOKED);
+-TRACE_DEFINE_ENUM(NFS4ERR_BACK_CHAN_BUSY);
+-TRACE_DEFINE_ENUM(NFS4ERR_BADCHAR);
+-TRACE_DEFINE_ENUM(NFS4ERR_BADHANDLE);
+-TRACE_DEFINE_ENUM(NFS4ERR_BADIOMODE);
+-TRACE_DEFINE_ENUM(NFS4ERR_BADLAYOUT);
+-TRACE_DEFINE_ENUM(NFS4ERR_BADLABEL);
+-TRACE_DEFINE_ENUM(NFS4ERR_BADNAME);
+-TRACE_DEFINE_ENUM(NFS4ERR_BADOWNER);
+-TRACE_DEFINE_ENUM(NFS4ERR_BADSESSION);
+-TRACE_DEFINE_ENUM(NFS4ERR_BADSLOT);
+-TRACE_DEFINE_ENUM(NFS4ERR_BADTYPE);
+-TRACE_DEFINE_ENUM(NFS4ERR_BADXDR);
+-TRACE_DEFINE_ENUM(NFS4ERR_BAD_COOKIE);
+-TRACE_DEFINE_ENUM(NFS4ERR_BAD_HIGH_SLOT);
+-TRACE_DEFINE_ENUM(NFS4ERR_BAD_RANGE);
+-TRACE_DEFINE_ENUM(NFS4ERR_BAD_SEQID);
+-TRACE_DEFINE_ENUM(NFS4ERR_BAD_SESSION_DIGEST);
+-TRACE_DEFINE_ENUM(NFS4ERR_BAD_STATEID);
+-TRACE_DEFINE_ENUM(NFS4ERR_CB_PATH_DOWN);
+-TRACE_DEFINE_ENUM(NFS4ERR_CLID_INUSE);
+-TRACE_DEFINE_ENUM(NFS4ERR_CLIENTID_BUSY);
+-TRACE_DEFINE_ENUM(NFS4ERR_COMPLETE_ALREADY);
+-TRACE_DEFINE_ENUM(NFS4ERR_CONN_NOT_BOUND_TO_SESSION);
+-TRACE_DEFINE_ENUM(NFS4ERR_DEADLOCK);
+-TRACE_DEFINE_ENUM(NFS4ERR_DEADSESSION);
+-TRACE_DEFINE_ENUM(NFS4ERR_DELAY);
+-TRACE_DEFINE_ENUM(NFS4ERR_DELEG_ALREADY_WANTED);
+-TRACE_DEFINE_ENUM(NFS4ERR_DELEG_REVOKED);
+-TRACE_DEFINE_ENUM(NFS4ERR_DENIED);
+-TRACE_DEFINE_ENUM(NFS4ERR_DIRDELEG_UNAVAIL);
+-TRACE_DEFINE_ENUM(NFS4ERR_DQUOT);
+-TRACE_DEFINE_ENUM(NFS4ERR_ENCR_ALG_UNSUPP);
+-TRACE_DEFINE_ENUM(NFS4ERR_EXIST);
+-TRACE_DEFINE_ENUM(NFS4ERR_EXPIRED);
+-TRACE_DEFINE_ENUM(NFS4ERR_FBIG);
+-TRACE_DEFINE_ENUM(NFS4ERR_FHEXPIRED);
+-TRACE_DEFINE_ENUM(NFS4ERR_FILE_OPEN);
+-TRACE_DEFINE_ENUM(NFS4ERR_GRACE);
+-TRACE_DEFINE_ENUM(NFS4ERR_HASH_ALG_UNSUPP);
+-TRACE_DEFINE_ENUM(NFS4ERR_INVAL);
+-TRACE_DEFINE_ENUM(NFS4ERR_IO);
+-TRACE_DEFINE_ENUM(NFS4ERR_ISDIR);
+-TRACE_DEFINE_ENUM(NFS4ERR_LAYOUTTRYLATER);
+-TRACE_DEFINE_ENUM(NFS4ERR_LAYOUTUNAVAILABLE);
+-TRACE_DEFINE_ENUM(NFS4ERR_LEASE_MOVED);
+-TRACE_DEFINE_ENUM(NFS4ERR_LOCKED);
+-TRACE_DEFINE_ENUM(NFS4ERR_LOCKS_HELD);
+-TRACE_DEFINE_ENUM(NFS4ERR_LOCK_RANGE);
+-TRACE_DEFINE_ENUM(NFS4ERR_MINOR_VERS_MISMATCH);
+-TRACE_DEFINE_ENUM(NFS4ERR_MLINK);
+-TRACE_DEFINE_ENUM(NFS4ERR_MOVED);
+-TRACE_DEFINE_ENUM(NFS4ERR_NAMETOOLONG);
+-TRACE_DEFINE_ENUM(NFS4ERR_NOENT);
+-TRACE_DEFINE_ENUM(NFS4ERR_NOFILEHANDLE);
+-TRACE_DEFINE_ENUM(NFS4ERR_NOMATCHING_LAYOUT);
+-TRACE_DEFINE_ENUM(NFS4ERR_NOSPC);
+-TRACE_DEFINE_ENUM(NFS4ERR_NOTDIR);
+-TRACE_DEFINE_ENUM(NFS4ERR_NOTEMPTY);
+-TRACE_DEFINE_ENUM(NFS4ERR_NOTSUPP);
+-TRACE_DEFINE_ENUM(NFS4ERR_NOT_ONLY_OP);
+-TRACE_DEFINE_ENUM(NFS4ERR_NOT_SAME);
+-TRACE_DEFINE_ENUM(NFS4ERR_NO_GRACE);
+-TRACE_DEFINE_ENUM(NFS4ERR_NXIO);
+-TRACE_DEFINE_ENUM(NFS4ERR_OLD_STATEID);
+-TRACE_DEFINE_ENUM(NFS4ERR_OPENMODE);
+-TRACE_DEFINE_ENUM(NFS4ERR_OP_ILLEGAL);
+-TRACE_DEFINE_ENUM(NFS4ERR_OP_NOT_IN_SESSION);
+-TRACE_DEFINE_ENUM(NFS4ERR_PERM);
+-TRACE_DEFINE_ENUM(NFS4ERR_PNFS_IO_HOLE);
+-TRACE_DEFINE_ENUM(NFS4ERR_PNFS_NO_LAYOUT);
+-TRACE_DEFINE_ENUM(NFS4ERR_RECALLCONFLICT);
+-TRACE_DEFINE_ENUM(NFS4ERR_RECLAIM_BAD);
+-TRACE_DEFINE_ENUM(NFS4ERR_RECLAIM_CONFLICT);
+-TRACE_DEFINE_ENUM(NFS4ERR_REJECT_DELEG);
+-TRACE_DEFINE_ENUM(NFS4ERR_REP_TOO_BIG);
+-TRACE_DEFINE_ENUM(NFS4ERR_REP_TOO_BIG_TO_CACHE);
+-TRACE_DEFINE_ENUM(NFS4ERR_REQ_TOO_BIG);
+-TRACE_DEFINE_ENUM(NFS4ERR_RESOURCE);
+-TRACE_DEFINE_ENUM(NFS4ERR_RESTOREFH);
+-TRACE_DEFINE_ENUM(NFS4ERR_RETRY_UNCACHED_REP);
+-TRACE_DEFINE_ENUM(NFS4ERR_RETURNCONFLICT);
+-TRACE_DEFINE_ENUM(NFS4ERR_ROFS);
+-TRACE_DEFINE_ENUM(NFS4ERR_SAME);
+-TRACE_DEFINE_ENUM(NFS4ERR_SHARE_DENIED);
+-TRACE_DEFINE_ENUM(NFS4ERR_SEQUENCE_POS);
+-TRACE_DEFINE_ENUM(NFS4ERR_SEQ_FALSE_RETRY);
+-TRACE_DEFINE_ENUM(NFS4ERR_SEQ_MISORDERED);
+-TRACE_DEFINE_ENUM(NFS4ERR_SERVERFAULT);
+-TRACE_DEFINE_ENUM(NFS4ERR_STALE);
+-TRACE_DEFINE_ENUM(NFS4ERR_STALE_CLIENTID);
+-TRACE_DEFINE_ENUM(NFS4ERR_STALE_STATEID);
+-TRACE_DEFINE_ENUM(NFS4ERR_SYMLINK);
+-TRACE_DEFINE_ENUM(NFS4ERR_TOOSMALL);
+-TRACE_DEFINE_ENUM(NFS4ERR_TOO_MANY_OPS);
+-TRACE_DEFINE_ENUM(NFS4ERR_UNKNOWN_LAYOUTTYPE);
+-TRACE_DEFINE_ENUM(NFS4ERR_UNSAFE_COMPOUND);
+-TRACE_DEFINE_ENUM(NFS4ERR_WRONGSEC);
+-TRACE_DEFINE_ENUM(NFS4ERR_WRONG_CRED);
+-TRACE_DEFINE_ENUM(NFS4ERR_WRONG_TYPE);
+-TRACE_DEFINE_ENUM(NFS4ERR_XDEV);
+-
+-TRACE_DEFINE_ENUM(NFS4ERR_RESET_TO_MDS);
+-TRACE_DEFINE_ENUM(NFS4ERR_RESET_TO_PNFS);
+-
+-#define show_nfs4_status(x) \
+- __print_symbolic(x, \
+- { NFS4_OK, "OK" }, \
+- { EPERM, "EPERM" }, \
+- { ENOENT, "ENOENT" }, \
+- { EIO, "EIO" }, \
+- { ENXIO, "ENXIO" }, \
+- { EACCES, "EACCES" }, \
+- { EEXIST, "EEXIST" }, \
+- { EXDEV, "EXDEV" }, \
+- { ENOTDIR, "ENOTDIR" }, \
+- { EISDIR, "EISDIR" }, \
+- { EFBIG, "EFBIG" }, \
+- { ENOSPC, "ENOSPC" }, \
+- { EROFS, "EROFS" }, \
+- { EMLINK, "EMLINK" }, \
+- { ENAMETOOLONG, "ENAMETOOLONG" }, \
+- { ENOTEMPTY, "ENOTEMPTY" }, \
+- { EDQUOT, "EDQUOT" }, \
+- { ESTALE, "ESTALE" }, \
+- { EBADHANDLE, "EBADHANDLE" }, \
+- { EBADCOOKIE, "EBADCOOKIE" }, \
+- { ENOTSUPP, "ENOTSUPP" }, \
+- { ETOOSMALL, "ETOOSMALL" }, \
+- { EREMOTEIO, "EREMOTEIO" }, \
+- { EBADTYPE, "EBADTYPE" }, \
+- { EAGAIN, "EAGAIN" }, \
+- { ELOOP, "ELOOP" }, \
+- { EOPNOTSUPP, "EOPNOTSUPP" }, \
+- { EDEADLK, "EDEADLK" }, \
+- { ENOMEM, "ENOMEM" }, \
+- { EKEYEXPIRED, "EKEYEXPIRED" }, \
+- { ETIMEDOUT, "ETIMEDOUT" }, \
+- { ERESTARTSYS, "ERESTARTSYS" }, \
+- { ECONNREFUSED, "ECONNREFUSED" }, \
+- { ECONNRESET, "ECONNRESET" }, \
+- { ENETUNREACH, "ENETUNREACH" }, \
+- { EHOSTUNREACH, "EHOSTUNREACH" }, \
+- { EHOSTDOWN, "EHOSTDOWN" }, \
+- { EPIPE, "EPIPE" }, \
+- { EPFNOSUPPORT, "EPFNOSUPPORT" }, \
+- { EPROTONOSUPPORT, "EPROTONOSUPPORT" }, \
+- { NFS4ERR_ACCESS, "ACCESS" }, \
+- { NFS4ERR_ATTRNOTSUPP, "ATTRNOTSUPP" }, \
+- { NFS4ERR_ADMIN_REVOKED, "ADMIN_REVOKED" }, \
+- { NFS4ERR_BACK_CHAN_BUSY, "BACK_CHAN_BUSY" }, \
+- { NFS4ERR_BADCHAR, "BADCHAR" }, \
+- { NFS4ERR_BADHANDLE, "BADHANDLE" }, \
+- { NFS4ERR_BADIOMODE, "BADIOMODE" }, \
+- { NFS4ERR_BADLAYOUT, "BADLAYOUT" }, \
+- { NFS4ERR_BADLABEL, "BADLABEL" }, \
+- { NFS4ERR_BADNAME, "BADNAME" }, \
+- { NFS4ERR_BADOWNER, "BADOWNER" }, \
+- { NFS4ERR_BADSESSION, "BADSESSION" }, \
+- { NFS4ERR_BADSLOT, "BADSLOT" }, \
+- { NFS4ERR_BADTYPE, "BADTYPE" }, \
+- { NFS4ERR_BADXDR, "BADXDR" }, \
+- { NFS4ERR_BAD_COOKIE, "BAD_COOKIE" }, \
+- { NFS4ERR_BAD_HIGH_SLOT, "BAD_HIGH_SLOT" }, \
+- { NFS4ERR_BAD_RANGE, "BAD_RANGE" }, \
+- { NFS4ERR_BAD_SEQID, "BAD_SEQID" }, \
+- { NFS4ERR_BAD_SESSION_DIGEST, "BAD_SESSION_DIGEST" }, \
+- { NFS4ERR_BAD_STATEID, "BAD_STATEID" }, \
+- { NFS4ERR_CB_PATH_DOWN, "CB_PATH_DOWN" }, \
+- { NFS4ERR_CLID_INUSE, "CLID_INUSE" }, \
+- { NFS4ERR_CLIENTID_BUSY, "CLIENTID_BUSY" }, \
+- { NFS4ERR_COMPLETE_ALREADY, "COMPLETE_ALREADY" }, \
+- { NFS4ERR_CONN_NOT_BOUND_TO_SESSION, "CONN_NOT_BOUND_TO_SESSION" }, \
+- { NFS4ERR_DEADLOCK, "DEADLOCK" }, \
+- { NFS4ERR_DEADSESSION, "DEAD_SESSION" }, \
+- { NFS4ERR_DELAY, "DELAY" }, \
+- { NFS4ERR_DELEG_ALREADY_WANTED, "DELEG_ALREADY_WANTED" }, \
+- { NFS4ERR_DELEG_REVOKED, "DELEG_REVOKED" }, \
+- { NFS4ERR_DENIED, "DENIED" }, \
+- { NFS4ERR_DIRDELEG_UNAVAIL, "DIRDELEG_UNAVAIL" }, \
+- { NFS4ERR_DQUOT, "DQUOT" }, \
+- { NFS4ERR_ENCR_ALG_UNSUPP, "ENCR_ALG_UNSUPP" }, \
+- { NFS4ERR_EXIST, "EXIST" }, \
+- { NFS4ERR_EXPIRED, "EXPIRED" }, \
+- { NFS4ERR_FBIG, "FBIG" }, \
+- { NFS4ERR_FHEXPIRED, "FHEXPIRED" }, \
+- { NFS4ERR_FILE_OPEN, "FILE_OPEN" }, \
+- { NFS4ERR_GRACE, "GRACE" }, \
+- { NFS4ERR_HASH_ALG_UNSUPP, "HASH_ALG_UNSUPP" }, \
+- { NFS4ERR_INVAL, "INVAL" }, \
+- { NFS4ERR_IO, "IO" }, \
+- { NFS4ERR_ISDIR, "ISDIR" }, \
+- { NFS4ERR_LAYOUTTRYLATER, "LAYOUTTRYLATER" }, \
+- { NFS4ERR_LAYOUTUNAVAILABLE, "LAYOUTUNAVAILABLE" }, \
+- { NFS4ERR_LEASE_MOVED, "LEASE_MOVED" }, \
+- { NFS4ERR_LOCKED, "LOCKED" }, \
+- { NFS4ERR_LOCKS_HELD, "LOCKS_HELD" }, \
+- { NFS4ERR_LOCK_RANGE, "LOCK_RANGE" }, \
+- { NFS4ERR_MINOR_VERS_MISMATCH, "MINOR_VERS_MISMATCH" }, \
+- { NFS4ERR_MLINK, "MLINK" }, \
+- { NFS4ERR_MOVED, "MOVED" }, \
+- { NFS4ERR_NAMETOOLONG, "NAMETOOLONG" }, \
+- { NFS4ERR_NOENT, "NOENT" }, \
+- { NFS4ERR_NOFILEHANDLE, "NOFILEHANDLE" }, \
+- { NFS4ERR_NOMATCHING_LAYOUT, "NOMATCHING_LAYOUT" }, \
+- { NFS4ERR_NOSPC, "NOSPC" }, \
+- { NFS4ERR_NOTDIR, "NOTDIR" }, \
+- { NFS4ERR_NOTEMPTY, "NOTEMPTY" }, \
+- { NFS4ERR_NOTSUPP, "NOTSUPP" }, \
+- { NFS4ERR_NOT_ONLY_OP, "NOT_ONLY_OP" }, \
+- { NFS4ERR_NOT_SAME, "NOT_SAME" }, \
+- { NFS4ERR_NO_GRACE, "NO_GRACE" }, \
+- { NFS4ERR_NXIO, "NXIO" }, \
+- { NFS4ERR_OLD_STATEID, "OLD_STATEID" }, \
+- { NFS4ERR_OPENMODE, "OPENMODE" }, \
+- { NFS4ERR_OP_ILLEGAL, "OP_ILLEGAL" }, \
+- { NFS4ERR_OP_NOT_IN_SESSION, "OP_NOT_IN_SESSION" }, \
+- { NFS4ERR_PERM, "PERM" }, \
+- { NFS4ERR_PNFS_IO_HOLE, "PNFS_IO_HOLE" }, \
+- { NFS4ERR_PNFS_NO_LAYOUT, "PNFS_NO_LAYOUT" }, \
+- { NFS4ERR_RECALLCONFLICT, "RECALLCONFLICT" }, \
+- { NFS4ERR_RECLAIM_BAD, "RECLAIM_BAD" }, \
+- { NFS4ERR_RECLAIM_CONFLICT, "RECLAIM_CONFLICT" }, \
+- { NFS4ERR_REJECT_DELEG, "REJECT_DELEG" }, \
+- { NFS4ERR_REP_TOO_BIG, "REP_TOO_BIG" }, \
+- { NFS4ERR_REP_TOO_BIG_TO_CACHE, "REP_TOO_BIG_TO_CACHE" }, \
+- { NFS4ERR_REQ_TOO_BIG, "REQ_TOO_BIG" }, \
+- { NFS4ERR_RESOURCE, "RESOURCE" }, \
+- { NFS4ERR_RESTOREFH, "RESTOREFH" }, \
+- { NFS4ERR_RETRY_UNCACHED_REP, "RETRY_UNCACHED_REP" }, \
+- { NFS4ERR_RETURNCONFLICT, "RETURNCONFLICT" }, \
+- { NFS4ERR_ROFS, "ROFS" }, \
+- { NFS4ERR_SAME, "SAME" }, \
+- { NFS4ERR_SHARE_DENIED, "SHARE_DENIED" }, \
+- { NFS4ERR_SEQUENCE_POS, "SEQUENCE_POS" }, \
+- { NFS4ERR_SEQ_FALSE_RETRY, "SEQ_FALSE_RETRY" }, \
+- { NFS4ERR_SEQ_MISORDERED, "SEQ_MISORDERED" }, \
+- { NFS4ERR_SERVERFAULT, "SERVERFAULT" }, \
+- { NFS4ERR_STALE, "STALE" }, \
+- { NFS4ERR_STALE_CLIENTID, "STALE_CLIENTID" }, \
+- { NFS4ERR_STALE_STATEID, "STALE_STATEID" }, \
+- { NFS4ERR_SYMLINK, "SYMLINK" }, \
+- { NFS4ERR_TOOSMALL, "TOOSMALL" }, \
+- { NFS4ERR_TOO_MANY_OPS, "TOO_MANY_OPS" }, \
+- { NFS4ERR_UNKNOWN_LAYOUTTYPE, "UNKNOWN_LAYOUTTYPE" }, \
+- { NFS4ERR_UNSAFE_COMPOUND, "UNSAFE_COMPOUND" }, \
+- { NFS4ERR_WRONGSEC, "WRONGSEC" }, \
+- { NFS4ERR_WRONG_CRED, "WRONG_CRED" }, \
+- { NFS4ERR_WRONG_TYPE, "WRONG_TYPE" }, \
+- { NFS4ERR_XDEV, "XDEV" }, \
+- /* ***** Internal to Linux NFS client ***** */ \
+- { NFS4ERR_RESET_TO_MDS, "RESET_TO_MDS" }, \
+- { NFS4ERR_RESET_TO_PNFS, "RESET_TO_PNFS" })
+-
+-#define show_nfs4_verifier(x) \
+- __print_hex_str(x, NFS4_VERIFIER_SIZE)
+-
+-TRACE_DEFINE_ENUM(IOMODE_READ);
+-TRACE_DEFINE_ENUM(IOMODE_RW);
+-TRACE_DEFINE_ENUM(IOMODE_ANY);
+-
+-#define show_pnfs_layout_iomode(x) \
+- __print_symbolic(x, \
+- { IOMODE_READ, "READ" }, \
+- { IOMODE_RW, "RW" }, \
+- { IOMODE_ANY, "ANY" })
+-
+-#define show_nfs4_seq4_status(x) \
+- __print_flags(x, "|", \
+- { SEQ4_STATUS_CB_PATH_DOWN, "CB_PATH_DOWN" }, \
+- { SEQ4_STATUS_CB_GSS_CONTEXTS_EXPIRING, "CB_GSS_CONTEXTS_EXPIRING" }, \
+- { SEQ4_STATUS_CB_GSS_CONTEXTS_EXPIRED, "CB_GSS_CONTEXTS_EXPIRED" }, \
+- { SEQ4_STATUS_EXPIRED_ALL_STATE_REVOKED, "EXPIRED_ALL_STATE_REVOKED" }, \
+- { SEQ4_STATUS_EXPIRED_SOME_STATE_REVOKED, "EXPIRED_SOME_STATE_REVOKED" }, \
+- { SEQ4_STATUS_ADMIN_STATE_REVOKED, "ADMIN_STATE_REVOKED" }, \
+- { SEQ4_STATUS_RECALLABLE_STATE_REVOKED, "RECALLABLE_STATE_REVOKED" }, \
+- { SEQ4_STATUS_LEASE_MOVED, "LEASE_MOVED" }, \
+- { SEQ4_STATUS_RESTART_RECLAIM_NEEDED, "RESTART_RECLAIM_NEEDED" }, \
+- { SEQ4_STATUS_CB_PATH_DOWN_SESSION, "CB_PATH_DOWN_SESSION" }, \
+- { SEQ4_STATUS_BACKCHANNEL_FAULT, "BACKCHANNEL_FAULT" })
+--- a/include/trace/events/rdma.h
++++ /dev/null
+@@ -1,168 +0,0 @@
+-/* SPDX-License-Identifier: GPL-2.0 */
+-/*
+- * Copyright (c) 2017 Oracle. All rights reserved.
+- */
+-
+-/*
+- * enum ib_event_type, from include/rdma/ib_verbs.h
+- */
+-#define IB_EVENT_LIST \
+- ib_event(CQ_ERR) \
+- ib_event(QP_FATAL) \
+- ib_event(QP_REQ_ERR) \
+- ib_event(QP_ACCESS_ERR) \
+- ib_event(COMM_EST) \
+- ib_event(SQ_DRAINED) \
+- ib_event(PATH_MIG) \
+- ib_event(PATH_MIG_ERR) \
+- ib_event(DEVICE_FATAL) \
+- ib_event(PORT_ACTIVE) \
+- ib_event(PORT_ERR) \
+- ib_event(LID_CHANGE) \
+- ib_event(PKEY_CHANGE) \
+- ib_event(SM_CHANGE) \
+- ib_event(SRQ_ERR) \
+- ib_event(SRQ_LIMIT_REACHED) \
+- ib_event(QP_LAST_WQE_REACHED) \
+- ib_event(CLIENT_REREGISTER) \
+- ib_event(GID_CHANGE) \
+- ib_event_end(WQ_FATAL)
+-
+-#undef ib_event
+-#undef ib_event_end
+-
+-#define ib_event(x) TRACE_DEFINE_ENUM(IB_EVENT_##x);
+-#define ib_event_end(x) TRACE_DEFINE_ENUM(IB_EVENT_##x);
+-
+-IB_EVENT_LIST
+-
+-#undef ib_event
+-#undef ib_event_end
+-
+-#define ib_event(x) { IB_EVENT_##x, #x },
+-#define ib_event_end(x) { IB_EVENT_##x, #x }
+-
+-#define rdma_show_ib_event(x) \
+- __print_symbolic(x, IB_EVENT_LIST)
+-
+-/*
+- * enum ib_wc_status type, from include/rdma/ib_verbs.h
+- */
+-#define IB_WC_STATUS_LIST \
+- ib_wc_status(SUCCESS) \
+- ib_wc_status(LOC_LEN_ERR) \
+- ib_wc_status(LOC_QP_OP_ERR) \
+- ib_wc_status(LOC_EEC_OP_ERR) \
+- ib_wc_status(LOC_PROT_ERR) \
+- ib_wc_status(WR_FLUSH_ERR) \
+- ib_wc_status(MW_BIND_ERR) \
+- ib_wc_status(BAD_RESP_ERR) \
+- ib_wc_status(LOC_ACCESS_ERR) \
+- ib_wc_status(REM_INV_REQ_ERR) \
+- ib_wc_status(REM_ACCESS_ERR) \
+- ib_wc_status(REM_OP_ERR) \
+- ib_wc_status(RETRY_EXC_ERR) \
+- ib_wc_status(RNR_RETRY_EXC_ERR) \
+- ib_wc_status(LOC_RDD_VIOL_ERR) \
+- ib_wc_status(REM_INV_RD_REQ_ERR) \
+- ib_wc_status(REM_ABORT_ERR) \
+- ib_wc_status(INV_EECN_ERR) \
+- ib_wc_status(INV_EEC_STATE_ERR) \
+- ib_wc_status(FATAL_ERR) \
+- ib_wc_status(RESP_TIMEOUT_ERR) \
+- ib_wc_status_end(GENERAL_ERR)
+-
+-#undef ib_wc_status
+-#undef ib_wc_status_end
+-
+-#define ib_wc_status(x) TRACE_DEFINE_ENUM(IB_WC_##x);
+-#define ib_wc_status_end(x) TRACE_DEFINE_ENUM(IB_WC_##x);
+-
+-IB_WC_STATUS_LIST
+-
+-#undef ib_wc_status
+-#undef ib_wc_status_end
+-
+-#define ib_wc_status(x) { IB_WC_##x, #x },
+-#define ib_wc_status_end(x) { IB_WC_##x, #x }
+-
+-#define rdma_show_wc_status(x) \
+- __print_symbolic(x, IB_WC_STATUS_LIST)
+-
+-/*
+- * enum ib_cm_event_type, from include/rdma/ib_cm.h
+- */
+-#define IB_CM_EVENT_LIST \
+- ib_cm_event(REQ_ERROR) \
+- ib_cm_event(REQ_RECEIVED) \
+- ib_cm_event(REP_ERROR) \
+- ib_cm_event(REP_RECEIVED) \
+- ib_cm_event(RTU_RECEIVED) \
+- ib_cm_event(USER_ESTABLISHED) \
+- ib_cm_event(DREQ_ERROR) \
+- ib_cm_event(DREQ_RECEIVED) \
+- ib_cm_event(DREP_RECEIVED) \
+- ib_cm_event(TIMEWAIT_EXIT) \
+- ib_cm_event(MRA_RECEIVED) \
+- ib_cm_event(REJ_RECEIVED) \
+- ib_cm_event(LAP_ERROR) \
+- ib_cm_event(LAP_RECEIVED) \
+- ib_cm_event(APR_RECEIVED) \
+- ib_cm_event(SIDR_REQ_ERROR) \
+- ib_cm_event(SIDR_REQ_RECEIVED) \
+- ib_cm_event_end(SIDR_REP_RECEIVED)
+-
+-#undef ib_cm_event
+-#undef ib_cm_event_end
+-
+-#define ib_cm_event(x) TRACE_DEFINE_ENUM(IB_CM_##x);
+-#define ib_cm_event_end(x) TRACE_DEFINE_ENUM(IB_CM_##x);
+-
+-IB_CM_EVENT_LIST
+-
+-#undef ib_cm_event
+-#undef ib_cm_event_end
+-
+-#define ib_cm_event(x) { IB_CM_##x, #x },
+-#define ib_cm_event_end(x) { IB_CM_##x, #x }
+-
+-#define rdma_show_ib_cm_event(x) \
+- __print_symbolic(x, IB_CM_EVENT_LIST)
+-
+-/*
+- * enum rdma_cm_event_type, from include/rdma/rdma_cm.h
+- */
+-#define RDMA_CM_EVENT_LIST \
+- rdma_cm_event(ADDR_RESOLVED) \
+- rdma_cm_event(ADDR_ERROR) \
+- rdma_cm_event(ROUTE_RESOLVED) \
+- rdma_cm_event(ROUTE_ERROR) \
+- rdma_cm_event(CONNECT_REQUEST) \
+- rdma_cm_event(CONNECT_RESPONSE) \
+- rdma_cm_event(CONNECT_ERROR) \
+- rdma_cm_event(UNREACHABLE) \
+- rdma_cm_event(REJECTED) \
+- rdma_cm_event(ESTABLISHED) \
+- rdma_cm_event(DISCONNECTED) \
+- rdma_cm_event(DEVICE_REMOVAL) \
+- rdma_cm_event(MULTICAST_JOIN) \
+- rdma_cm_event(MULTICAST_ERROR) \
+- rdma_cm_event(ADDR_CHANGE) \
+- rdma_cm_event_end(TIMEWAIT_EXIT)
+-
+-#undef rdma_cm_event
+-#undef rdma_cm_event_end
+-
+-#define rdma_cm_event(x) TRACE_DEFINE_ENUM(RDMA_CM_EVENT_##x);
+-#define rdma_cm_event_end(x) TRACE_DEFINE_ENUM(RDMA_CM_EVENT_##x);
+-
+-RDMA_CM_EVENT_LIST
+-
+-#undef rdma_cm_event
+-#undef rdma_cm_event_end
+-
+-#define rdma_cm_event(x) { RDMA_CM_EVENT_##x, #x },
+-#define rdma_cm_event_end(x) { RDMA_CM_EVENT_##x, #x }
+-
+-#define rdma_show_cm_event(x) \
+- __print_symbolic(x, RDMA_CM_EVENT_LIST)
+--- a/include/trace/events/rpcgss.h
++++ b/include/trace/events/rpcgss.h
+@@ -13,7 +13,7 @@
+
+ #include <linux/tracepoint.h>
+
+-#include <trace/events/sunrpc_base.h>
++#include <trace/misc/sunrpc.h>
+
+ /**
+ ** GSS-API related trace events
+--- a/include/trace/events/rpcrdma.h
++++ b/include/trace/events/rpcrdma.h
+@@ -15,8 +15,8 @@
+ #include <linux/tracepoint.h>
+ #include <rdma/ib_cm.h>
+
+-#include <trace/events/rdma.h>
+-#include <trace/events/sunrpc_base.h>
++#include <trace/misc/rdma.h>
++#include <trace/misc/sunrpc.h>
+
+ /**
+ ** Event classes
+--- a/include/trace/events/sunrpc.h
++++ b/include/trace/events/sunrpc.h
+@@ -14,7 +14,7 @@
+ #include <linux/net.h>
+ #include <linux/tracepoint.h>
+
+-#include <trace/events/sunrpc_base.h>
++#include <trace/misc/sunrpc.h>
+
+ TRACE_DEFINE_ENUM(SOCK_STREAM);
+ TRACE_DEFINE_ENUM(SOCK_DGRAM);
+--- a/include/trace/events/sunrpc_base.h
++++ /dev/null
+@@ -1,18 +0,0 @@
+-/* SPDX-License-Identifier: GPL-2.0 */
+-/*
+- * Copyright (c) 2021 Oracle and/or its affiliates.
+- *
+- * Common types and format specifiers for sunrpc.
+- */
+-
+-#if !defined(_TRACE_SUNRPC_BASE_H)
+-#define _TRACE_SUNRPC_BASE_H
+-
+-#include <linux/tracepoint.h>
+-
+-#define SUNRPC_TRACE_PID_SPECIFIER "%08x"
+-#define SUNRPC_TRACE_CLID_SPECIFIER "%08x"
+-#define SUNRPC_TRACE_TASK_SPECIFIER \
+- "task:" SUNRPC_TRACE_PID_SPECIFIER "@" SUNRPC_TRACE_CLID_SPECIFIER
+-
+-#endif /* _TRACE_SUNRPC_BASE_H */
+--- /dev/null
++++ b/include/trace/misc/fs.h
+@@ -0,0 +1,122 @@
++/* SPDX-License-Identifier: GPL-2.0 */
++/*
++ * Display helpers for generic filesystem items
++ *
++ * Author: Chuck Lever <chuck.lever@oracle.com>
++ *
++ * Copyright (c) 2020, Oracle and/or its affiliates.
++ */
++
++#include <linux/fs.h>
++
++#define show_fs_dirent_type(x) \
++ __print_symbolic(x, \
++ { DT_UNKNOWN, "UNKNOWN" }, \
++ { DT_FIFO, "FIFO" }, \
++ { DT_CHR, "CHR" }, \
++ { DT_DIR, "DIR" }, \
++ { DT_BLK, "BLK" }, \
++ { DT_REG, "REG" }, \
++ { DT_LNK, "LNK" }, \
++ { DT_SOCK, "SOCK" }, \
++ { DT_WHT, "WHT" })
++
++#define show_fs_fcntl_open_flags(x) \
++ __print_flags(x, "|", \
++ { O_WRONLY, "O_WRONLY" }, \
++ { O_RDWR, "O_RDWR" }, \
++ { O_CREAT, "O_CREAT" }, \
++ { O_EXCL, "O_EXCL" }, \
++ { O_NOCTTY, "O_NOCTTY" }, \
++ { O_TRUNC, "O_TRUNC" }, \
++ { O_APPEND, "O_APPEND" }, \
++ { O_NONBLOCK, "O_NONBLOCK" }, \
++ { O_DSYNC, "O_DSYNC" }, \
++ { O_DIRECT, "O_DIRECT" }, \
++ { O_LARGEFILE, "O_LARGEFILE" }, \
++ { O_DIRECTORY, "O_DIRECTORY" }, \
++ { O_NOFOLLOW, "O_NOFOLLOW" }, \
++ { O_NOATIME, "O_NOATIME" }, \
++ { O_CLOEXEC, "O_CLOEXEC" })
++
++#define __fmode_flag(x) { (__force unsigned long)FMODE_##x, #x }
++#define show_fs_fmode_flags(x) \
++ __print_flags(x, "|", \
++ __fmode_flag(READ), \
++ __fmode_flag(WRITE), \
++ __fmode_flag(EXEC))
++
++#ifdef CONFIG_64BIT
++#define show_fs_fcntl_cmd(x) \
++ __print_symbolic(x, \
++ { F_DUPFD, "DUPFD" }, \
++ { F_GETFD, "GETFD" }, \
++ { F_SETFD, "SETFD" }, \
++ { F_GETFL, "GETFL" }, \
++ { F_SETFL, "SETFL" }, \
++ { F_GETLK, "GETLK" }, \
++ { F_SETLK, "SETLK" }, \
++ { F_SETLKW, "SETLKW" }, \
++ { F_SETOWN, "SETOWN" }, \
++ { F_GETOWN, "GETOWN" }, \
++ { F_SETSIG, "SETSIG" }, \
++ { F_GETSIG, "GETSIG" }, \
++ { F_SETOWN_EX, "SETOWN_EX" }, \
++ { F_GETOWN_EX, "GETOWN_EX" }, \
++ { F_GETOWNER_UIDS, "GETOWNER_UIDS" }, \
++ { F_OFD_GETLK, "OFD_GETLK" }, \
++ { F_OFD_SETLK, "OFD_SETLK" }, \
++ { F_OFD_SETLKW, "OFD_SETLKW" })
++#else /* CONFIG_64BIT */
++#define show_fs_fcntl_cmd(x) \
++ __print_symbolic(x, \
++ { F_DUPFD, "DUPFD" }, \
++ { F_GETFD, "GETFD" }, \
++ { F_SETFD, "SETFD" }, \
++ { F_GETFL, "GETFL" }, \
++ { F_SETFL, "SETFL" }, \
++ { F_GETLK, "GETLK" }, \
++ { F_SETLK, "SETLK" }, \
++ { F_SETLKW, "SETLKW" }, \
++ { F_SETOWN, "SETOWN" }, \
++ { F_GETOWN, "GETOWN" }, \
++ { F_SETSIG, "SETSIG" }, \
++ { F_GETSIG, "GETSIG" }, \
++ { F_GETLK64, "GETLK64" }, \
++ { F_SETLK64, "SETLK64" }, \
++ { F_SETLKW64, "SETLKW64" }, \
++ { F_SETOWN_EX, "SETOWN_EX" }, \
++ { F_GETOWN_EX, "GETOWN_EX" }, \
++ { F_GETOWNER_UIDS, "GETOWNER_UIDS" }, \
++ { F_OFD_GETLK, "OFD_GETLK" }, \
++ { F_OFD_SETLK, "OFD_SETLK" }, \
++ { F_OFD_SETLKW, "OFD_SETLKW" })
++#endif /* CONFIG_64BIT */
++
++#define show_fs_fcntl_lock_type(x) \
++ __print_symbolic(x, \
++ { F_RDLCK, "RDLCK" }, \
++ { F_WRLCK, "WRLCK" }, \
++ { F_UNLCK, "UNLCK" })
++
++#define show_fs_lookup_flags(flags) \
++ __print_flags(flags, "|", \
++ { LOOKUP_FOLLOW, "FOLLOW" }, \
++ { LOOKUP_DIRECTORY, "DIRECTORY" }, \
++ { LOOKUP_AUTOMOUNT, "AUTOMOUNT" }, \
++ { LOOKUP_EMPTY, "EMPTY" }, \
++ { LOOKUP_DOWN, "DOWN" }, \
++ { LOOKUP_MOUNTPOINT, "MOUNTPOINT" }, \
++ { LOOKUP_REVAL, "REVAL" }, \
++ { LOOKUP_RCU, "RCU" }, \
++ { LOOKUP_OPEN, "OPEN" }, \
++ { LOOKUP_CREATE, "CREATE" }, \
++ { LOOKUP_EXCL, "EXCL" }, \
++ { LOOKUP_RENAME_TARGET, "RENAME_TARGET" }, \
++ { LOOKUP_PARENT, "PARENT" }, \
++ { LOOKUP_NO_SYMLINKS, "NO_SYMLINKS" }, \
++ { LOOKUP_NO_MAGICLINKS, "NO_MAGICLINKS" }, \
++ { LOOKUP_NO_XDEV, "NO_XDEV" }, \
++ { LOOKUP_BENEATH, "BENEATH" }, \
++ { LOOKUP_IN_ROOT, "IN_ROOT" }, \
++ { LOOKUP_CACHED, "CACHED" })
+--- /dev/null
++++ b/include/trace/misc/nfs.h
+@@ -0,0 +1,375 @@
++/* SPDX-License-Identifier: GPL-2.0 */
++/*
++ * Display helpers for NFS protocol elements
++ *
++ * Author: Chuck Lever <chuck.lever@oracle.com>
++ *
++ * Copyright (c) 2020, Oracle and/or its affiliates.
++ */
++
++#include <linux/nfs.h>
++#include <linux/nfs4.h>
++#include <uapi/linux/nfs.h>
++
++TRACE_DEFINE_ENUM(NFS_OK);
++TRACE_DEFINE_ENUM(NFSERR_PERM);
++TRACE_DEFINE_ENUM(NFSERR_NOENT);
++TRACE_DEFINE_ENUM(NFSERR_IO);
++TRACE_DEFINE_ENUM(NFSERR_NXIO);
++TRACE_DEFINE_ENUM(NFSERR_EAGAIN);
++TRACE_DEFINE_ENUM(NFSERR_ACCES);
++TRACE_DEFINE_ENUM(NFSERR_EXIST);
++TRACE_DEFINE_ENUM(NFSERR_XDEV);
++TRACE_DEFINE_ENUM(NFSERR_NODEV);
++TRACE_DEFINE_ENUM(NFSERR_NOTDIR);
++TRACE_DEFINE_ENUM(NFSERR_ISDIR);
++TRACE_DEFINE_ENUM(NFSERR_INVAL);
++TRACE_DEFINE_ENUM(NFSERR_FBIG);
++TRACE_DEFINE_ENUM(NFSERR_NOSPC);
++TRACE_DEFINE_ENUM(NFSERR_ROFS);
++TRACE_DEFINE_ENUM(NFSERR_MLINK);
++TRACE_DEFINE_ENUM(NFSERR_OPNOTSUPP);
++TRACE_DEFINE_ENUM(NFSERR_NAMETOOLONG);
++TRACE_DEFINE_ENUM(NFSERR_NOTEMPTY);
++TRACE_DEFINE_ENUM(NFSERR_DQUOT);
++TRACE_DEFINE_ENUM(NFSERR_STALE);
++TRACE_DEFINE_ENUM(NFSERR_REMOTE);
++TRACE_DEFINE_ENUM(NFSERR_WFLUSH);
++TRACE_DEFINE_ENUM(NFSERR_BADHANDLE);
++TRACE_DEFINE_ENUM(NFSERR_NOT_SYNC);
++TRACE_DEFINE_ENUM(NFSERR_BAD_COOKIE);
++TRACE_DEFINE_ENUM(NFSERR_NOTSUPP);
++TRACE_DEFINE_ENUM(NFSERR_TOOSMALL);
++TRACE_DEFINE_ENUM(NFSERR_SERVERFAULT);
++TRACE_DEFINE_ENUM(NFSERR_BADTYPE);
++TRACE_DEFINE_ENUM(NFSERR_JUKEBOX);
++
++#define show_nfs_status(x) \
++ __print_symbolic(x, \
++ { NFS_OK, "OK" }, \
++ { NFSERR_PERM, "PERM" }, \
++ { NFSERR_NOENT, "NOENT" }, \
++ { NFSERR_IO, "IO" }, \
++ { NFSERR_NXIO, "NXIO" }, \
++ { ECHILD, "CHILD" }, \
++ { NFSERR_EAGAIN, "AGAIN" }, \
++ { NFSERR_ACCES, "ACCES" }, \
++ { NFSERR_EXIST, "EXIST" }, \
++ { NFSERR_XDEV, "XDEV" }, \
++ { NFSERR_NODEV, "NODEV" }, \
++ { NFSERR_NOTDIR, "NOTDIR" }, \
++ { NFSERR_ISDIR, "ISDIR" }, \
++ { NFSERR_INVAL, "INVAL" }, \
++ { NFSERR_FBIG, "FBIG" }, \
++ { NFSERR_NOSPC, "NOSPC" }, \
++ { NFSERR_ROFS, "ROFS" }, \
++ { NFSERR_MLINK, "MLINK" }, \
++ { NFSERR_OPNOTSUPP, "OPNOTSUPP" }, \
++ { NFSERR_NAMETOOLONG, "NAMETOOLONG" }, \
++ { NFSERR_NOTEMPTY, "NOTEMPTY" }, \
++ { NFSERR_DQUOT, "DQUOT" }, \
++ { NFSERR_STALE, "STALE" }, \
++ { NFSERR_REMOTE, "REMOTE" }, \
++ { NFSERR_WFLUSH, "WFLUSH" }, \
++ { NFSERR_BADHANDLE, "BADHANDLE" }, \
++ { NFSERR_NOT_SYNC, "NOTSYNC" }, \
++ { NFSERR_BAD_COOKIE, "BADCOOKIE" }, \
++ { NFSERR_NOTSUPP, "NOTSUPP" }, \
++ { NFSERR_TOOSMALL, "TOOSMALL" }, \
++ { NFSERR_SERVERFAULT, "REMOTEIO" }, \
++ { NFSERR_BADTYPE, "BADTYPE" }, \
++ { NFSERR_JUKEBOX, "JUKEBOX" })
++
++TRACE_DEFINE_ENUM(NFS_UNSTABLE);
++TRACE_DEFINE_ENUM(NFS_DATA_SYNC);
++TRACE_DEFINE_ENUM(NFS_FILE_SYNC);
++
++#define show_nfs_stable_how(x) \
++ __print_symbolic(x, \
++ { NFS_UNSTABLE, "UNSTABLE" }, \
++ { NFS_DATA_SYNC, "DATA_SYNC" }, \
++ { NFS_FILE_SYNC, "FILE_SYNC" })
++
++TRACE_DEFINE_ENUM(NFS4_OK);
++TRACE_DEFINE_ENUM(NFS4ERR_ACCESS);
++TRACE_DEFINE_ENUM(NFS4ERR_ATTRNOTSUPP);
++TRACE_DEFINE_ENUM(NFS4ERR_ADMIN_REVOKED);
++TRACE_DEFINE_ENUM(NFS4ERR_BACK_CHAN_BUSY);
++TRACE_DEFINE_ENUM(NFS4ERR_BADCHAR);
++TRACE_DEFINE_ENUM(NFS4ERR_BADHANDLE);
++TRACE_DEFINE_ENUM(NFS4ERR_BADIOMODE);
++TRACE_DEFINE_ENUM(NFS4ERR_BADLAYOUT);
++TRACE_DEFINE_ENUM(NFS4ERR_BADLABEL);
++TRACE_DEFINE_ENUM(NFS4ERR_BADNAME);
++TRACE_DEFINE_ENUM(NFS4ERR_BADOWNER);
++TRACE_DEFINE_ENUM(NFS4ERR_BADSESSION);
++TRACE_DEFINE_ENUM(NFS4ERR_BADSLOT);
++TRACE_DEFINE_ENUM(NFS4ERR_BADTYPE);
++TRACE_DEFINE_ENUM(NFS4ERR_BADXDR);
++TRACE_DEFINE_ENUM(NFS4ERR_BAD_COOKIE);
++TRACE_DEFINE_ENUM(NFS4ERR_BAD_HIGH_SLOT);
++TRACE_DEFINE_ENUM(NFS4ERR_BAD_RANGE);
++TRACE_DEFINE_ENUM(NFS4ERR_BAD_SEQID);
++TRACE_DEFINE_ENUM(NFS4ERR_BAD_SESSION_DIGEST);
++TRACE_DEFINE_ENUM(NFS4ERR_BAD_STATEID);
++TRACE_DEFINE_ENUM(NFS4ERR_CB_PATH_DOWN);
++TRACE_DEFINE_ENUM(NFS4ERR_CLID_INUSE);
++TRACE_DEFINE_ENUM(NFS4ERR_CLIENTID_BUSY);
++TRACE_DEFINE_ENUM(NFS4ERR_COMPLETE_ALREADY);
++TRACE_DEFINE_ENUM(NFS4ERR_CONN_NOT_BOUND_TO_SESSION);
++TRACE_DEFINE_ENUM(NFS4ERR_DEADLOCK);
++TRACE_DEFINE_ENUM(NFS4ERR_DEADSESSION);
++TRACE_DEFINE_ENUM(NFS4ERR_DELAY);
++TRACE_DEFINE_ENUM(NFS4ERR_DELEG_ALREADY_WANTED);
++TRACE_DEFINE_ENUM(NFS4ERR_DELEG_REVOKED);
++TRACE_DEFINE_ENUM(NFS4ERR_DENIED);
++TRACE_DEFINE_ENUM(NFS4ERR_DIRDELEG_UNAVAIL);
++TRACE_DEFINE_ENUM(NFS4ERR_DQUOT);
++TRACE_DEFINE_ENUM(NFS4ERR_ENCR_ALG_UNSUPP);
++TRACE_DEFINE_ENUM(NFS4ERR_EXIST);
++TRACE_DEFINE_ENUM(NFS4ERR_EXPIRED);
++TRACE_DEFINE_ENUM(NFS4ERR_FBIG);
++TRACE_DEFINE_ENUM(NFS4ERR_FHEXPIRED);
++TRACE_DEFINE_ENUM(NFS4ERR_FILE_OPEN);
++TRACE_DEFINE_ENUM(NFS4ERR_GRACE);
++TRACE_DEFINE_ENUM(NFS4ERR_HASH_ALG_UNSUPP);
++TRACE_DEFINE_ENUM(NFS4ERR_INVAL);
++TRACE_DEFINE_ENUM(NFS4ERR_IO);
++TRACE_DEFINE_ENUM(NFS4ERR_ISDIR);
++TRACE_DEFINE_ENUM(NFS4ERR_LAYOUTTRYLATER);
++TRACE_DEFINE_ENUM(NFS4ERR_LAYOUTUNAVAILABLE);
++TRACE_DEFINE_ENUM(NFS4ERR_LEASE_MOVED);
++TRACE_DEFINE_ENUM(NFS4ERR_LOCKED);
++TRACE_DEFINE_ENUM(NFS4ERR_LOCKS_HELD);
++TRACE_DEFINE_ENUM(NFS4ERR_LOCK_RANGE);
++TRACE_DEFINE_ENUM(NFS4ERR_MINOR_VERS_MISMATCH);
++TRACE_DEFINE_ENUM(NFS4ERR_MLINK);
++TRACE_DEFINE_ENUM(NFS4ERR_MOVED);
++TRACE_DEFINE_ENUM(NFS4ERR_NAMETOOLONG);
++TRACE_DEFINE_ENUM(NFS4ERR_NOENT);
++TRACE_DEFINE_ENUM(NFS4ERR_NOFILEHANDLE);
++TRACE_DEFINE_ENUM(NFS4ERR_NOMATCHING_LAYOUT);
++TRACE_DEFINE_ENUM(NFS4ERR_NOSPC);
++TRACE_DEFINE_ENUM(NFS4ERR_NOTDIR);
++TRACE_DEFINE_ENUM(NFS4ERR_NOTEMPTY);
++TRACE_DEFINE_ENUM(NFS4ERR_NOTSUPP);
++TRACE_DEFINE_ENUM(NFS4ERR_NOT_ONLY_OP);
++TRACE_DEFINE_ENUM(NFS4ERR_NOT_SAME);
++TRACE_DEFINE_ENUM(NFS4ERR_NO_GRACE);
++TRACE_DEFINE_ENUM(NFS4ERR_NXIO);
++TRACE_DEFINE_ENUM(NFS4ERR_OLD_STATEID);
++TRACE_DEFINE_ENUM(NFS4ERR_OPENMODE);
++TRACE_DEFINE_ENUM(NFS4ERR_OP_ILLEGAL);
++TRACE_DEFINE_ENUM(NFS4ERR_OP_NOT_IN_SESSION);
++TRACE_DEFINE_ENUM(NFS4ERR_PERM);
++TRACE_DEFINE_ENUM(NFS4ERR_PNFS_IO_HOLE);
++TRACE_DEFINE_ENUM(NFS4ERR_PNFS_NO_LAYOUT);
++TRACE_DEFINE_ENUM(NFS4ERR_RECALLCONFLICT);
++TRACE_DEFINE_ENUM(NFS4ERR_RECLAIM_BAD);
++TRACE_DEFINE_ENUM(NFS4ERR_RECLAIM_CONFLICT);
++TRACE_DEFINE_ENUM(NFS4ERR_REJECT_DELEG);
++TRACE_DEFINE_ENUM(NFS4ERR_REP_TOO_BIG);
++TRACE_DEFINE_ENUM(NFS4ERR_REP_TOO_BIG_TO_CACHE);
++TRACE_DEFINE_ENUM(NFS4ERR_REQ_TOO_BIG);
++TRACE_DEFINE_ENUM(NFS4ERR_RESOURCE);
++TRACE_DEFINE_ENUM(NFS4ERR_RESTOREFH);
++TRACE_DEFINE_ENUM(NFS4ERR_RETRY_UNCACHED_REP);
++TRACE_DEFINE_ENUM(NFS4ERR_RETURNCONFLICT);
++TRACE_DEFINE_ENUM(NFS4ERR_ROFS);
++TRACE_DEFINE_ENUM(NFS4ERR_SAME);
++TRACE_DEFINE_ENUM(NFS4ERR_SHARE_DENIED);
++TRACE_DEFINE_ENUM(NFS4ERR_SEQUENCE_POS);
++TRACE_DEFINE_ENUM(NFS4ERR_SEQ_FALSE_RETRY);
++TRACE_DEFINE_ENUM(NFS4ERR_SEQ_MISORDERED);
++TRACE_DEFINE_ENUM(NFS4ERR_SERVERFAULT);
++TRACE_DEFINE_ENUM(NFS4ERR_STALE);
++TRACE_DEFINE_ENUM(NFS4ERR_STALE_CLIENTID);
++TRACE_DEFINE_ENUM(NFS4ERR_STALE_STATEID);
++TRACE_DEFINE_ENUM(NFS4ERR_SYMLINK);
++TRACE_DEFINE_ENUM(NFS4ERR_TOOSMALL);
++TRACE_DEFINE_ENUM(NFS4ERR_TOO_MANY_OPS);
++TRACE_DEFINE_ENUM(NFS4ERR_UNKNOWN_LAYOUTTYPE);
++TRACE_DEFINE_ENUM(NFS4ERR_UNSAFE_COMPOUND);
++TRACE_DEFINE_ENUM(NFS4ERR_WRONGSEC);
++TRACE_DEFINE_ENUM(NFS4ERR_WRONG_CRED);
++TRACE_DEFINE_ENUM(NFS4ERR_WRONG_TYPE);
++TRACE_DEFINE_ENUM(NFS4ERR_XDEV);
++
++TRACE_DEFINE_ENUM(NFS4ERR_RESET_TO_MDS);
++TRACE_DEFINE_ENUM(NFS4ERR_RESET_TO_PNFS);
++
++#define show_nfs4_status(x) \
++ __print_symbolic(x, \
++ { NFS4_OK, "OK" }, \
++ { EPERM, "EPERM" }, \
++ { ENOENT, "ENOENT" }, \
++ { EIO, "EIO" }, \
++ { ENXIO, "ENXIO" }, \
++ { EACCES, "EACCES" }, \
++ { EEXIST, "EEXIST" }, \
++ { EXDEV, "EXDEV" }, \
++ { ENOTDIR, "ENOTDIR" }, \
++ { EISDIR, "EISDIR" }, \
++ { EFBIG, "EFBIG" }, \
++ { ENOSPC, "ENOSPC" }, \
++ { EROFS, "EROFS" }, \
++ { EMLINK, "EMLINK" }, \
++ { ENAMETOOLONG, "ENAMETOOLONG" }, \
++ { ENOTEMPTY, "ENOTEMPTY" }, \
++ { EDQUOT, "EDQUOT" }, \
++ { ESTALE, "ESTALE" }, \
++ { EBADHANDLE, "EBADHANDLE" }, \
++ { EBADCOOKIE, "EBADCOOKIE" }, \
++ { ENOTSUPP, "ENOTSUPP" }, \
++ { ETOOSMALL, "ETOOSMALL" }, \
++ { EREMOTEIO, "EREMOTEIO" }, \
++ { EBADTYPE, "EBADTYPE" }, \
++ { EAGAIN, "EAGAIN" }, \
++ { ELOOP, "ELOOP" }, \
++ { EOPNOTSUPP, "EOPNOTSUPP" }, \
++ { EDEADLK, "EDEADLK" }, \
++ { ENOMEM, "ENOMEM" }, \
++ { EKEYEXPIRED, "EKEYEXPIRED" }, \
++ { ETIMEDOUT, "ETIMEDOUT" }, \
++ { ERESTARTSYS, "ERESTARTSYS" }, \
++ { ECONNREFUSED, "ECONNREFUSED" }, \
++ { ECONNRESET, "ECONNRESET" }, \
++ { ENETUNREACH, "ENETUNREACH" }, \
++ { EHOSTUNREACH, "EHOSTUNREACH" }, \
++ { EHOSTDOWN, "EHOSTDOWN" }, \
++ { EPIPE, "EPIPE" }, \
++ { EPFNOSUPPORT, "EPFNOSUPPORT" }, \
++ { EPROTONOSUPPORT, "EPROTONOSUPPORT" }, \
++ { NFS4ERR_ACCESS, "ACCESS" }, \
++ { NFS4ERR_ATTRNOTSUPP, "ATTRNOTSUPP" }, \
++ { NFS4ERR_ADMIN_REVOKED, "ADMIN_REVOKED" }, \
++ { NFS4ERR_BACK_CHAN_BUSY, "BACK_CHAN_BUSY" }, \
++ { NFS4ERR_BADCHAR, "BADCHAR" }, \
++ { NFS4ERR_BADHANDLE, "BADHANDLE" }, \
++ { NFS4ERR_BADIOMODE, "BADIOMODE" }, \
++ { NFS4ERR_BADLAYOUT, "BADLAYOUT" }, \
++ { NFS4ERR_BADLABEL, "BADLABEL" }, \
++ { NFS4ERR_BADNAME, "BADNAME" }, \
++ { NFS4ERR_BADOWNER, "BADOWNER" }, \
++ { NFS4ERR_BADSESSION, "BADSESSION" }, \
++ { NFS4ERR_BADSLOT, "BADSLOT" }, \
++ { NFS4ERR_BADTYPE, "BADTYPE" }, \
++ { NFS4ERR_BADXDR, "BADXDR" }, \
++ { NFS4ERR_BAD_COOKIE, "BAD_COOKIE" }, \
++ { NFS4ERR_BAD_HIGH_SLOT, "BAD_HIGH_SLOT" }, \
++ { NFS4ERR_BAD_RANGE, "BAD_RANGE" }, \
++ { NFS4ERR_BAD_SEQID, "BAD_SEQID" }, \
++ { NFS4ERR_BAD_SESSION_DIGEST, "BAD_SESSION_DIGEST" }, \
++ { NFS4ERR_BAD_STATEID, "BAD_STATEID" }, \
++ { NFS4ERR_CB_PATH_DOWN, "CB_PATH_DOWN" }, \
++ { NFS4ERR_CLID_INUSE, "CLID_INUSE" }, \
++ { NFS4ERR_CLIENTID_BUSY, "CLIENTID_BUSY" }, \
++ { NFS4ERR_COMPLETE_ALREADY, "COMPLETE_ALREADY" }, \
++ { NFS4ERR_CONN_NOT_BOUND_TO_SESSION, "CONN_NOT_BOUND_TO_SESSION" }, \
++ { NFS4ERR_DEADLOCK, "DEADLOCK" }, \
++ { NFS4ERR_DEADSESSION, "DEAD_SESSION" }, \
++ { NFS4ERR_DELAY, "DELAY" }, \
++ { NFS4ERR_DELEG_ALREADY_WANTED, "DELEG_ALREADY_WANTED" }, \
++ { NFS4ERR_DELEG_REVOKED, "DELEG_REVOKED" }, \
++ { NFS4ERR_DENIED, "DENIED" }, \
++ { NFS4ERR_DIRDELEG_UNAVAIL, "DIRDELEG_UNAVAIL" }, \
++ { NFS4ERR_DQUOT, "DQUOT" }, \
++ { NFS4ERR_ENCR_ALG_UNSUPP, "ENCR_ALG_UNSUPP" }, \
++ { NFS4ERR_EXIST, "EXIST" }, \
++ { NFS4ERR_EXPIRED, "EXPIRED" }, \
++ { NFS4ERR_FBIG, "FBIG" }, \
++ { NFS4ERR_FHEXPIRED, "FHEXPIRED" }, \
++ { NFS4ERR_FILE_OPEN, "FILE_OPEN" }, \
++ { NFS4ERR_GRACE, "GRACE" }, \
++ { NFS4ERR_HASH_ALG_UNSUPP, "HASH_ALG_UNSUPP" }, \
++ { NFS4ERR_INVAL, "INVAL" }, \
++ { NFS4ERR_IO, "IO" }, \
++ { NFS4ERR_ISDIR, "ISDIR" }, \
++ { NFS4ERR_LAYOUTTRYLATER, "LAYOUTTRYLATER" }, \
++ { NFS4ERR_LAYOUTUNAVAILABLE, "LAYOUTUNAVAILABLE" }, \
++ { NFS4ERR_LEASE_MOVED, "LEASE_MOVED" }, \
++ { NFS4ERR_LOCKED, "LOCKED" }, \
++ { NFS4ERR_LOCKS_HELD, "LOCKS_HELD" }, \
++ { NFS4ERR_LOCK_RANGE, "LOCK_RANGE" }, \
++ { NFS4ERR_MINOR_VERS_MISMATCH, "MINOR_VERS_MISMATCH" }, \
++ { NFS4ERR_MLINK, "MLINK" }, \
++ { NFS4ERR_MOVED, "MOVED" }, \
++ { NFS4ERR_NAMETOOLONG, "NAMETOOLONG" }, \
++ { NFS4ERR_NOENT, "NOENT" }, \
++ { NFS4ERR_NOFILEHANDLE, "NOFILEHANDLE" }, \
++ { NFS4ERR_NOMATCHING_LAYOUT, "NOMATCHING_LAYOUT" }, \
++ { NFS4ERR_NOSPC, "NOSPC" }, \
++ { NFS4ERR_NOTDIR, "NOTDIR" }, \
++ { NFS4ERR_NOTEMPTY, "NOTEMPTY" }, \
++ { NFS4ERR_NOTSUPP, "NOTSUPP" }, \
++ { NFS4ERR_NOT_ONLY_OP, "NOT_ONLY_OP" }, \
++ { NFS4ERR_NOT_SAME, "NOT_SAME" }, \
++ { NFS4ERR_NO_GRACE, "NO_GRACE" }, \
++ { NFS4ERR_NXIO, "NXIO" }, \
++ { NFS4ERR_OLD_STATEID, "OLD_STATEID" }, \
++ { NFS4ERR_OPENMODE, "OPENMODE" }, \
++ { NFS4ERR_OP_ILLEGAL, "OP_ILLEGAL" }, \
++ { NFS4ERR_OP_NOT_IN_SESSION, "OP_NOT_IN_SESSION" }, \
++ { NFS4ERR_PERM, "PERM" }, \
++ { NFS4ERR_PNFS_IO_HOLE, "PNFS_IO_HOLE" }, \
++ { NFS4ERR_PNFS_NO_LAYOUT, "PNFS_NO_LAYOUT" }, \
++ { NFS4ERR_RECALLCONFLICT, "RECALLCONFLICT" }, \
++ { NFS4ERR_RECLAIM_BAD, "RECLAIM_BAD" }, \
++ { NFS4ERR_RECLAIM_CONFLICT, "RECLAIM_CONFLICT" }, \
++ { NFS4ERR_REJECT_DELEG, "REJECT_DELEG" }, \
++ { NFS4ERR_REP_TOO_BIG, "REP_TOO_BIG" }, \
++ { NFS4ERR_REP_TOO_BIG_TO_CACHE, "REP_TOO_BIG_TO_CACHE" }, \
++ { NFS4ERR_REQ_TOO_BIG, "REQ_TOO_BIG" }, \
++ { NFS4ERR_RESOURCE, "RESOURCE" }, \
++ { NFS4ERR_RESTOREFH, "RESTOREFH" }, \
++ { NFS4ERR_RETRY_UNCACHED_REP, "RETRY_UNCACHED_REP" }, \
++ { NFS4ERR_RETURNCONFLICT, "RETURNCONFLICT" }, \
++ { NFS4ERR_ROFS, "ROFS" }, \
++ { NFS4ERR_SAME, "SAME" }, \
++ { NFS4ERR_SHARE_DENIED, "SHARE_DENIED" }, \
++ { NFS4ERR_SEQUENCE_POS, "SEQUENCE_POS" }, \
++ { NFS4ERR_SEQ_FALSE_RETRY, "SEQ_FALSE_RETRY" }, \
++ { NFS4ERR_SEQ_MISORDERED, "SEQ_MISORDERED" }, \
++ { NFS4ERR_SERVERFAULT, "SERVERFAULT" }, \
++ { NFS4ERR_STALE, "STALE" }, \
++ { NFS4ERR_STALE_CLIENTID, "STALE_CLIENTID" }, \
++ { NFS4ERR_STALE_STATEID, "STALE_STATEID" }, \
++ { NFS4ERR_SYMLINK, "SYMLINK" }, \
++ { NFS4ERR_TOOSMALL, "TOOSMALL" }, \
++ { NFS4ERR_TOO_MANY_OPS, "TOO_MANY_OPS" }, \
++ { NFS4ERR_UNKNOWN_LAYOUTTYPE, "UNKNOWN_LAYOUTTYPE" }, \
++ { NFS4ERR_UNSAFE_COMPOUND, "UNSAFE_COMPOUND" }, \
++ { NFS4ERR_WRONGSEC, "WRONGSEC" }, \
++ { NFS4ERR_WRONG_CRED, "WRONG_CRED" }, \
++ { NFS4ERR_WRONG_TYPE, "WRONG_TYPE" }, \
++ { NFS4ERR_XDEV, "XDEV" }, \
++ /* ***** Internal to Linux NFS client ***** */ \
++ { NFS4ERR_RESET_TO_MDS, "RESET_TO_MDS" }, \
++ { NFS4ERR_RESET_TO_PNFS, "RESET_TO_PNFS" })
++
++#define show_nfs4_verifier(x) \
++ __print_hex_str(x, NFS4_VERIFIER_SIZE)
++
++TRACE_DEFINE_ENUM(IOMODE_READ);
++TRACE_DEFINE_ENUM(IOMODE_RW);
++TRACE_DEFINE_ENUM(IOMODE_ANY);
++
++#define show_pnfs_layout_iomode(x) \
++ __print_symbolic(x, \
++ { IOMODE_READ, "READ" }, \
++ { IOMODE_RW, "RW" }, \
++ { IOMODE_ANY, "ANY" })
++
++#define show_nfs4_seq4_status(x) \
++ __print_flags(x, "|", \
++ { SEQ4_STATUS_CB_PATH_DOWN, "CB_PATH_DOWN" }, \
++ { SEQ4_STATUS_CB_GSS_CONTEXTS_EXPIRING, "CB_GSS_CONTEXTS_EXPIRING" }, \
++ { SEQ4_STATUS_CB_GSS_CONTEXTS_EXPIRED, "CB_GSS_CONTEXTS_EXPIRED" }, \
++ { SEQ4_STATUS_EXPIRED_ALL_STATE_REVOKED, "EXPIRED_ALL_STATE_REVOKED" }, \
++ { SEQ4_STATUS_EXPIRED_SOME_STATE_REVOKED, "EXPIRED_SOME_STATE_REVOKED" }, \
++ { SEQ4_STATUS_ADMIN_STATE_REVOKED, "ADMIN_STATE_REVOKED" }, \
++ { SEQ4_STATUS_RECALLABLE_STATE_REVOKED, "RECALLABLE_STATE_REVOKED" }, \
++ { SEQ4_STATUS_LEASE_MOVED, "LEASE_MOVED" }, \
++ { SEQ4_STATUS_RESTART_RECLAIM_NEEDED, "RESTART_RECLAIM_NEEDED" }, \
++ { SEQ4_STATUS_CB_PATH_DOWN_SESSION, "CB_PATH_DOWN_SESSION" }, \
++ { SEQ4_STATUS_BACKCHANNEL_FAULT, "BACKCHANNEL_FAULT" })
+--- /dev/null
++++ b/include/trace/misc/rdma.h
+@@ -0,0 +1,168 @@
++/* SPDX-License-Identifier: GPL-2.0 */
++/*
++ * Copyright (c) 2017 Oracle. All rights reserved.
++ */
++
++/*
++ * enum ib_event_type, from include/rdma/ib_verbs.h
++ */
++#define IB_EVENT_LIST \
++ ib_event(CQ_ERR) \
++ ib_event(QP_FATAL) \
++ ib_event(QP_REQ_ERR) \
++ ib_event(QP_ACCESS_ERR) \
++ ib_event(COMM_EST) \
++ ib_event(SQ_DRAINED) \
++ ib_event(PATH_MIG) \
++ ib_event(PATH_MIG_ERR) \
++ ib_event(DEVICE_FATAL) \
++ ib_event(PORT_ACTIVE) \
++ ib_event(PORT_ERR) \
++ ib_event(LID_CHANGE) \
++ ib_event(PKEY_CHANGE) \
++ ib_event(SM_CHANGE) \
++ ib_event(SRQ_ERR) \
++ ib_event(SRQ_LIMIT_REACHED) \
++ ib_event(QP_LAST_WQE_REACHED) \
++ ib_event(CLIENT_REREGISTER) \
++ ib_event(GID_CHANGE) \
++ ib_event_end(WQ_FATAL)
++
++#undef ib_event
++#undef ib_event_end
++
++#define ib_event(x) TRACE_DEFINE_ENUM(IB_EVENT_##x);
++#define ib_event_end(x) TRACE_DEFINE_ENUM(IB_EVENT_##x);
++
++IB_EVENT_LIST
++
++#undef ib_event
++#undef ib_event_end
++
++#define ib_event(x) { IB_EVENT_##x, #x },
++#define ib_event_end(x) { IB_EVENT_##x, #x }
++
++#define rdma_show_ib_event(x) \
++ __print_symbolic(x, IB_EVENT_LIST)
++
++/*
++ * enum ib_wc_status type, from include/rdma/ib_verbs.h
++ */
++#define IB_WC_STATUS_LIST \
++ ib_wc_status(SUCCESS) \
++ ib_wc_status(LOC_LEN_ERR) \
++ ib_wc_status(LOC_QP_OP_ERR) \
++ ib_wc_status(LOC_EEC_OP_ERR) \
++ ib_wc_status(LOC_PROT_ERR) \
++ ib_wc_status(WR_FLUSH_ERR) \
++ ib_wc_status(MW_BIND_ERR) \
++ ib_wc_status(BAD_RESP_ERR) \
++ ib_wc_status(LOC_ACCESS_ERR) \
++ ib_wc_status(REM_INV_REQ_ERR) \
++ ib_wc_status(REM_ACCESS_ERR) \
++ ib_wc_status(REM_OP_ERR) \
++ ib_wc_status(RETRY_EXC_ERR) \
++ ib_wc_status(RNR_RETRY_EXC_ERR) \
++ ib_wc_status(LOC_RDD_VIOL_ERR) \
++ ib_wc_status(REM_INV_RD_REQ_ERR) \
++ ib_wc_status(REM_ABORT_ERR) \
++ ib_wc_status(INV_EECN_ERR) \
++ ib_wc_status(INV_EEC_STATE_ERR) \
++ ib_wc_status(FATAL_ERR) \
++ ib_wc_status(RESP_TIMEOUT_ERR) \
++ ib_wc_status_end(GENERAL_ERR)
++
++#undef ib_wc_status
++#undef ib_wc_status_end
++
++#define ib_wc_status(x) TRACE_DEFINE_ENUM(IB_WC_##x);
++#define ib_wc_status_end(x) TRACE_DEFINE_ENUM(IB_WC_##x);
++
++IB_WC_STATUS_LIST
++
++#undef ib_wc_status
++#undef ib_wc_status_end
++
++#define ib_wc_status(x) { IB_WC_##x, #x },
++#define ib_wc_status_end(x) { IB_WC_##x, #x }
++
++#define rdma_show_wc_status(x) \
++ __print_symbolic(x, IB_WC_STATUS_LIST)
++
++/*
++ * enum ib_cm_event_type, from include/rdma/ib_cm.h
++ */
++#define IB_CM_EVENT_LIST \
++ ib_cm_event(REQ_ERROR) \
++ ib_cm_event(REQ_RECEIVED) \
++ ib_cm_event(REP_ERROR) \
++ ib_cm_event(REP_RECEIVED) \
++ ib_cm_event(RTU_RECEIVED) \
++ ib_cm_event(USER_ESTABLISHED) \
++ ib_cm_event(DREQ_ERROR) \
++ ib_cm_event(DREQ_RECEIVED) \
++ ib_cm_event(DREP_RECEIVED) \
++ ib_cm_event(TIMEWAIT_EXIT) \
++ ib_cm_event(MRA_RECEIVED) \
++ ib_cm_event(REJ_RECEIVED) \
++ ib_cm_event(LAP_ERROR) \
++ ib_cm_event(LAP_RECEIVED) \
++ ib_cm_event(APR_RECEIVED) \
++ ib_cm_event(SIDR_REQ_ERROR) \
++ ib_cm_event(SIDR_REQ_RECEIVED) \
++ ib_cm_event_end(SIDR_REP_RECEIVED)
++
++#undef ib_cm_event
++#undef ib_cm_event_end
++
++#define ib_cm_event(x) TRACE_DEFINE_ENUM(IB_CM_##x);
++#define ib_cm_event_end(x) TRACE_DEFINE_ENUM(IB_CM_##x);
++
++IB_CM_EVENT_LIST
++
++#undef ib_cm_event
++#undef ib_cm_event_end
++
++#define ib_cm_event(x) { IB_CM_##x, #x },
++#define ib_cm_event_end(x) { IB_CM_##x, #x }
++
++#define rdma_show_ib_cm_event(x) \
++ __print_symbolic(x, IB_CM_EVENT_LIST)
++
++/*
++ * enum rdma_cm_event_type, from include/rdma/rdma_cm.h
++ */
++#define RDMA_CM_EVENT_LIST \
++ rdma_cm_event(ADDR_RESOLVED) \
++ rdma_cm_event(ADDR_ERROR) \
++ rdma_cm_event(ROUTE_RESOLVED) \
++ rdma_cm_event(ROUTE_ERROR) \
++ rdma_cm_event(CONNECT_REQUEST) \
++ rdma_cm_event(CONNECT_RESPONSE) \
++ rdma_cm_event(CONNECT_ERROR) \
++ rdma_cm_event(UNREACHABLE) \
++ rdma_cm_event(REJECTED) \
++ rdma_cm_event(ESTABLISHED) \
++ rdma_cm_event(DISCONNECTED) \
++ rdma_cm_event(DEVICE_REMOVAL) \
++ rdma_cm_event(MULTICAST_JOIN) \
++ rdma_cm_event(MULTICAST_ERROR) \
++ rdma_cm_event(ADDR_CHANGE) \
++ rdma_cm_event_end(TIMEWAIT_EXIT)
++
++#undef rdma_cm_event
++#undef rdma_cm_event_end
++
++#define rdma_cm_event(x) TRACE_DEFINE_ENUM(RDMA_CM_EVENT_##x);
++#define rdma_cm_event_end(x) TRACE_DEFINE_ENUM(RDMA_CM_EVENT_##x);
++
++RDMA_CM_EVENT_LIST
++
++#undef rdma_cm_event
++#undef rdma_cm_event_end
++
++#define rdma_cm_event(x) { RDMA_CM_EVENT_##x, #x },
++#define rdma_cm_event_end(x) { RDMA_CM_EVENT_##x, #x }
++
++#define rdma_show_cm_event(x) \
++ __print_symbolic(x, RDMA_CM_EVENT_LIST)
+--- /dev/null
++++ b/include/trace/misc/sunrpc.h
+@@ -0,0 +1,18 @@
++/* SPDX-License-Identifier: GPL-2.0 */
++/*
++ * Copyright (c) 2021 Oracle and/or its affiliates.
++ *
++ * Common types and format specifiers for sunrpc.
++ */
++
++#if !defined(_TRACE_SUNRPC_BASE_H)
++#define _TRACE_SUNRPC_BASE_H
++
++#include <linux/tracepoint.h>
++
++#define SUNRPC_TRACE_PID_SPECIFIER "%08x"
++#define SUNRPC_TRACE_CLID_SPECIFIER "%08x"
++#define SUNRPC_TRACE_TASK_SPECIFIER \
++ "task:" SUNRPC_TRACE_PID_SPECIFIER "@" SUNRPC_TRACE_CLID_SPECIFIER
++
++#endif /* _TRACE_SUNRPC_BASE_H */