Merge tag 'nfs-for-6.9-1' of git://git.linux-nfs.org/projects/trondmy/linux-nfs
authorLinus Torvalds <torvalds@linux-foundation.org>
Sat, 16 Mar 2024 18:44:00 +0000 (11:44 -0700)
committerLinus Torvalds <torvalds@linux-foundation.org>
Sat, 16 Mar 2024 18:44:00 +0000 (11:44 -0700)
Pull NFS client updates from Trond Myklebust:
 "Highlights include:

  Bugfixes:
   - Fix for an Oops in the NFSv4.2 listxattr handler
   - Correct an incorrect buffer size in listxattr
   - Fix for an Oops in the pNFS flexfiles layout
   - Fix a refcount leak in NFS O_DIRECT writes
   - Fix missing locking in NFS O_DIRECT
   - Avoid an infinite loop in pnfs_update_layout
   - Fix an overflow in the RPC waitqueue queue length counter
   - Ensure that pNFS I/O is also protected by TLS when xprtsec is
     specified by the mount options
   - Fix a leaked folio lock in the netfs read code
   - Fix a potential deadlock in fscache
   - Allow setting the fscache uniquifier in NFSv4
   - Fix an off by one in root_nfs_cat()
   - Fix another off by one in rpc_sockaddr2uaddr()
   - nfs4_do_open() can incorrectly trigger state recovery
   - Various fixes for connection shutdown

  Features and cleanups:
   - Ensure that containers only see their own RPC and NFS stats
   - Enable nconnect for RDMA
   - Remove dead code from nfs_writepage_locked()
   - Various tracepoint additions to track EXCHANGE_ID, GETDEVICEINFO,
     and mount options"

* tag 'nfs-for-6.9-1' of git://git.linux-nfs.org/projects/trondmy/linux-nfs: (29 commits)
  nfs: fix panic when nfs4_ff_layout_prepare_ds() fails
  NFS: trace the uniquifier of fscache
  NFS: Read unlock folio on nfs_page_create_from_folio() error
  NFS: remove unused variable nfs_rpcstat
  nfs: fix UAF in direct writes
  nfs: properly protect nfs_direct_req fields
  NFS: enable nconnect for RDMA
  NFSv4: nfs4_do_open() is incorrectly triggering state recovery
  NFS: avoid infinite loop in pnfs_update_layout.
  NFS: remove sync_mode test from nfs_writepage_locked()
  NFSv4.1/pnfs: fix NFS with TLS in pnfs
  NFS: Fix an off by one in root_nfs_cat()
  nfs: make the rpc_stat per net namespace
  nfs: expose /proc/net/sunrpc/nfs in net namespaces
  sunrpc: add a struct rpc_stats arg to rpc_create_args
  nfs: remove unused NFS_CALL macro
  NFSv4.1: add tracepoint to trunked nfs4_exchange_id calls
  NFS: Fix nfs_netfs_issue_read() xarray locking for writeback interrupt
  SUNRPC: increase size of rpc_wait_queue.qlen from unsigned short to unsigned int
  nfs: fix regression in handling of fsc= option in NFSv4
  ...

36 files changed:
fs/nfs/client.c
fs/nfs/delegation.c
fs/nfs/direct.c
fs/nfs/filelayout/filelayoutdev.c
fs/nfs/flexfilelayout/flexfilelayout.c
fs/nfs/fs_context.c
fs/nfs/fscache.c
fs/nfs/inode.c
fs/nfs/internal.h
fs/nfs/netns.h
fs/nfs/nfs3client.c
fs/nfs/nfs42.h
fs/nfs/nfs4_fs.h
fs/nfs/nfs4client.c
fs/nfs/nfs4proc.c
fs/nfs/nfs4state.c
fs/nfs/nfs4super.c
fs/nfs/nfs4trace.c
fs/nfs/nfs4trace.h
fs/nfs/nfsroot.c
fs/nfs/pnfs.c
fs/nfs/pnfs_nfs.c
fs/nfs/read.c
fs/nfs/super.c
fs/nfs/write.c
include/linux/nfs_fs.h
include/linux/nfs_xdr.h
include/linux/sunrpc/clnt.h
include/linux/sunrpc/sched.h
include/linux/sunrpc/xprt.h
include/trace/events/sunrpc.h
include/trace/misc/nfs.h
net/sunrpc/addr.c
net/sunrpc/clnt.c
net/sunrpc/xprt.c
net/sunrpc/xprtsock.c

index fbdc9ca80f714bdf3d3cad54e63d7c858612e5f1..de77848ae6545566a5c38501516f3769e142f4cd 100644 (file)
@@ -73,14 +73,9 @@ const struct rpc_program nfs_program = {
        .number                 = NFS_PROGRAM,
        .nrvers                 = ARRAY_SIZE(nfs_version),
        .version                = nfs_version,
-       .stats                  = &nfs_rpcstat,
        .pipe_dir_name          = NFS_PIPE_DIRNAME,
 };
 
-struct rpc_stat nfs_rpcstat = {
-       .program                = &nfs_program
-};
-
 static struct nfs_subversion *find_nfs_version(unsigned int version)
 {
        struct nfs_subversion *nfs;
@@ -502,6 +497,7 @@ int nfs_create_rpc_client(struct nfs_client *clp,
                          const struct nfs_client_initdata *cl_init,
                          rpc_authflavor_t flavor)
 {
+       struct nfs_net          *nn = net_generic(clp->cl_net, nfs_net_id);
        struct rpc_clnt         *clnt = NULL;
        struct rpc_create_args args = {
                .net            = clp->cl_net,
@@ -513,6 +509,7 @@ int nfs_create_rpc_client(struct nfs_client *clp,
                .servername     = clp->cl_hostname,
                .nodename       = cl_init->nodename,
                .program        = &nfs_program,
+               .stats          = &nn->rpcstats,
                .version        = clp->rpc_ops->version,
                .authflavor     = flavor,
                .cred           = cl_init->cred,
@@ -1182,6 +1179,8 @@ void nfs_clients_init(struct net *net)
 #endif
        spin_lock_init(&nn->nfs_client_lock);
        nn->boot_time = ktime_get_real();
+       memset(&nn->rpcstats, 0, sizeof(nn->rpcstats));
+       nn->rpcstats.program = &nfs_program;
 
        nfs_netns_sysfs_setup(nn, net);
 }
index d4a42ce0c7e3dfeef19884be272a8ddd449c143f..6bace5fece04e29fa37839a705b0734a0e0d75ca 100644 (file)
@@ -181,7 +181,6 @@ static int nfs_delegation_claim_opens(struct inode *inode,
        struct nfs_open_context *ctx;
        struct nfs4_state_owner *sp;
        struct nfs4_state *state;
-       unsigned int seq;
        int err;
 
 again:
@@ -202,12 +201,9 @@ again:
                sp = state->owner;
                /* Block nfs4_proc_unlck */
                mutex_lock(&sp->so_delegreturn_mutex);
-               seq = raw_seqcount_begin(&sp->so_reclaim_seqcount);
                err = nfs4_open_delegation_recall(ctx, state, stateid);
                if (!err)
                        err = nfs_delegation_claim_locks(state, stateid);
-               if (!err && read_seqcount_retry(&sp->so_reclaim_seqcount, seq))
-                       err = -EAGAIN;
                mutex_unlock(&sp->so_delegreturn_mutex);
                put_nfs_open_context(ctx);
                if (err != 0)
index 7af5d270de2876270aaf83aecac7d2ee19e17e76..bb2f583eb28bf1de5d96eb1b3ee5d154d718b9a0 100644 (file)
@@ -606,6 +606,7 @@ static void nfs_direct_commit_complete(struct nfs_commit_data *data)
 
        trace_nfs_direct_commit_complete(dreq);
 
+       spin_lock(&dreq->lock);
        if (status < 0) {
                /* Errors in commit are fatal */
                dreq->error = status;
@@ -613,6 +614,7 @@ static void nfs_direct_commit_complete(struct nfs_commit_data *data)
        } else {
                status = dreq->error;
        }
+       spin_unlock(&dreq->lock);
 
        nfs_init_cinfo_from_dreq(&cinfo, dreq);
 
@@ -625,7 +627,10 @@ static void nfs_direct_commit_complete(struct nfs_commit_data *data)
                        spin_unlock(&dreq->lock);
                        nfs_release_request(req);
                } else if (!nfs_write_match_verf(verf, req)) {
-                       dreq->flags = NFS_ODIRECT_RESCHED_WRITES;
+                       spin_lock(&dreq->lock);
+                       if (dreq->flags == 0)
+                               dreq->flags = NFS_ODIRECT_RESCHED_WRITES;
+                       spin_unlock(&dreq->lock);
                        /*
                         * Despite the reboot, the write was successful,
                         * so reset wb_nio.
@@ -667,10 +672,17 @@ static void nfs_direct_commit_schedule(struct nfs_direct_req *dreq)
        LIST_HEAD(mds_list);
 
        nfs_init_cinfo_from_dreq(&cinfo, dreq);
+       nfs_commit_begin(cinfo.mds);
        nfs_scan_commit(dreq->inode, &mds_list, &cinfo);
        res = nfs_generic_commit_list(dreq->inode, &mds_list, 0, &cinfo);
-       if (res < 0) /* res == -ENOMEM */
-               nfs_direct_write_reschedule(dreq);
+       if (res < 0) { /* res == -ENOMEM */
+               spin_lock(&dreq->lock);
+               if (dreq->flags == 0)
+                       dreq->flags = NFS_ODIRECT_RESCHED_WRITES;
+               spin_unlock(&dreq->lock);
+       }
+       if (nfs_commit_end(cinfo.mds))
+               nfs_direct_write_complete(dreq);
 }
 
 static void nfs_direct_write_clear_reqs(struct nfs_direct_req *dreq)
index acf4b88889dc3814ebfe06d3883c96f429415f2a..4fa304fa5bc4b2346458877c39a558936a49317a 100644 (file)
@@ -35,6 +35,7 @@
 #include "../internal.h"
 #include "../nfs4session.h"
 #include "filelayout.h"
+#include "../nfs4trace.h"
 
 #define NFSDBG_FACILITY                NFSDBG_PNFS_LD
 
@@ -172,6 +173,7 @@ nfs4_fl_alloc_deviceid_node(struct nfs_server *server, struct pnfs_device *pdev,
                dsaddr->ds_list[i] = nfs4_pnfs_ds_add(&dsaddrs, gfp_flags);
                if (!dsaddr->ds_list[i])
                        goto out_err_drain_dsaddrs;
+               trace_fl_getdevinfo(server, &pdev->dev_id, dsaddr->ds_list[i]->ds_remotestr);
 
                /* If DS was already in cache, free ds addrs */
                while (!list_empty(&dsaddrs)) {
index ef817a0475ffa6508a0d663b3fa4f7f29ebd58af..3e724cb7ef01d87f3d49c57ab83ca81fd781c4f9 100644 (file)
@@ -2016,7 +2016,7 @@ static void ff_layout_cancel_io(struct pnfs_layout_segment *lseg)
        for (idx = 0; idx < flseg->mirror_array_cnt; idx++) {
                mirror = flseg->mirror_array[idx];
                mirror_ds = mirror->mirror_ds;
-               if (!mirror_ds)
+               if (IS_ERR_OR_NULL(mirror_ds))
                        continue;
                ds = mirror->mirror_ds->ds;
                if (!ds)
index 853e8d609bb3bcc81a505fa7cf03e1658a24ffc8..d0a0956f8a13462ab305e18c437719b0ed612158 100644 (file)
@@ -652,6 +652,7 @@ static int nfs_fs_context_parse_param(struct fs_context *fc,
                ctx->fscache_uniq = NULL;
                break;
        case Opt_fscache:
+               trace_nfs_mount_assign(param->key, param->string);
                ctx->options |= NFS_OPTION_FSCACHE;
                kfree(ctx->fscache_uniq);
                ctx->fscache_uniq = param->string;
index 2d1bfee225c3693d4443c62463944ecf04439bca..ddc1ee0319554cfc381bc920acb248766938bde7 100644 (file)
@@ -301,11 +301,11 @@ static void nfs_netfs_issue_read(struct netfs_io_subrequest *sreq)
        struct inode *inode = sreq->rreq->inode;
        struct nfs_open_context *ctx = sreq->rreq->netfs_priv;
        struct page *page;
+       unsigned long idx;
        int err;
        pgoff_t start = (sreq->start + sreq->transferred) >> PAGE_SHIFT;
        pgoff_t last = ((sreq->start + sreq->len -
                         sreq->transferred - 1) >> PAGE_SHIFT);
-       XA_STATE(xas, &sreq->rreq->mapping->i_pages, start);
 
        nfs_pageio_init_read(&pgio, inode, false,
                             &nfs_async_read_completion_ops);
@@ -316,19 +316,14 @@ static void nfs_netfs_issue_read(struct netfs_io_subrequest *sreq)
 
        pgio.pg_netfs = netfs; /* used in completion */
 
-       xas_lock(&xas);
-       xas_for_each(&xas, page, last) {
+       xa_for_each_range(&sreq->rreq->mapping->i_pages, idx, page, start, last) {
                /* nfs_read_add_folio() may schedule() due to pNFS layout and other RPCs  */
-               xas_pause(&xas);
-               xas_unlock(&xas);
                err = nfs_read_add_folio(&pgio, ctx, page_folio(page));
                if (err < 0) {
                        netfs->error = err;
                        goto out;
                }
-               xas_lock(&xas);
        }
-       xas_unlock(&xas);
 out:
        nfs_pageio_complete_read(&pgio);
        nfs_netfs_put(netfs);
index 93ea49a7eb61b44d217728cf4333db39dfa37871..c709c296ea9a49e0ccecdae975a5287aea5759fe 100644 (file)
@@ -2426,12 +2426,16 @@ EXPORT_SYMBOL_GPL(nfs_net_id);
 
 static int nfs_net_init(struct net *net)
 {
+       struct nfs_net *nn = net_generic(net, nfs_net_id);
+
        nfs_clients_init(net);
+       rpc_proc_register(net, &nn->rpcstats);
        return nfs_fs_proc_net_init(net);
 }
 
 static void nfs_net_exit(struct net *net)
 {
+       rpc_proc_unregister(net, "nfs");
        nfs_fs_proc_net_exit(net);
        nfs_clients_exit(net);
 }
@@ -2486,15 +2490,12 @@ static int __init init_nfs_fs(void)
        if (err)
                goto out1;
 
-       rpc_proc_register(&init_net, &nfs_rpcstat);
-
        err = register_nfs_fs();
        if (err)
                goto out0;
 
        return 0;
 out0:
-       rpc_proc_unregister(&init_net, "nfs");
        nfs_destroy_directcache();
 out1:
        nfs_destroy_writepagecache();
@@ -2524,7 +2525,6 @@ static void __exit exit_nfs_fs(void)
        nfs_destroy_inodecache();
        nfs_destroy_nfspagecache();
        unregister_pernet_subsys(&nfs_net_ops);
-       rpc_proc_unregister(&init_net, "nfs");
        unregister_nfs_fs();
        nfs_fs_proc_exit();
        nfsiod_stop();
index e3722ce6722e247e0da7c55a8bb3dd049c6cbcb6..06253695fe53f01708aed390004cbbd9651c5d57 100644 (file)
@@ -449,8 +449,6 @@ int nfs_try_get_tree(struct fs_context *);
 int nfs_get_tree_common(struct fs_context *);
 void nfs_kill_super(struct super_block *);
 
-extern struct rpc_stat nfs_rpcstat;
-
 extern int __init register_nfs_fs(void);
 extern void __exit unregister_nfs_fs(void);
 extern bool nfs_sb_active(struct super_block *sb);
index c8374f74dce1142289ed717c5281b4600a2a44e5..a68b21603ea9a867ba513e2a667b08fbc6d80dd8 100644 (file)
@@ -9,6 +9,7 @@
 #include <linux/nfs4.h>
 #include <net/net_namespace.h>
 #include <net/netns/generic.h>
+#include <linux/sunrpc/stats.h>
 
 struct bl_dev_msg {
        int32_t status;
@@ -34,6 +35,7 @@ struct nfs_net {
        struct nfs_netns_client *nfs_client;
        spinlock_t nfs_client_lock;
        ktime_t boot_time;
+       struct rpc_stat rpcstats;
 #ifdef CONFIG_PROC_FS
        struct proc_dir_entry *proc_nfsfs;
 #endif
index 674c012868b1a250b869e6586496db24915ce7da..b0c8a39c2bbdeab011a468a6b267d20a8d8ce91e 100644 (file)
@@ -111,6 +111,7 @@ struct nfs_client *nfs3_set_ds_client(struct nfs_server *mds_srv,
        cl_init.hostname = buf;
 
        switch (ds_proto) {
+       case XPRT_TRANSPORT_RDMA:
        case XPRT_TRANSPORT_TCP:
        case XPRT_TRANSPORT_TCP_TLS:
                if (mds_clp->cl_nconnect > 1)
index b59876b01a1e3c15206b7d12528e3e42312d3a42..0282d93c8bccb386d744017e9d2741abcb9a5f13 100644 (file)
@@ -55,11 +55,14 @@ int nfs42_proc_removexattr(struct inode *inode, const char *name);
  * They would be 7 bytes long in the eventual buffer ("user.x\0"), and
  * 8 bytes long XDR-encoded.
  *
- * Include the trailing eof word as well.
+ * Include the trailing eof word as well and make the result a multiple
+ * of 4 bytes.
  */
 static inline u32 nfs42_listxattr_xdrsize(u32 buflen)
 {
-       return ((buflen / (XATTR_USER_PREFIX_LEN + 2)) * 8) + 4;
+       u32 size = 8 * buflen / (XATTR_USER_PREFIX_LEN + 2) + 4;
+
+       return (size + 3) & ~3;
 }
 #endif /* CONFIG_NFS_V4_2 */
 #endif /* __LINUX_FS_NFS_NFS4_2_H */
index 6ff41ceb9f1c770cfe0af2f032bfa3f23d95e290..7024230f0d1db2f2b464ddd1c79a764e389f437e 100644 (file)
@@ -120,7 +120,6 @@ struct nfs4_state_owner {
        unsigned long        so_flags;
        struct list_head     so_states;
        struct nfs_seqid_counter so_seqid;
-       seqcount_spinlock_t  so_reclaim_seqcount;
        struct mutex         so_delegreturn_mutex;
 };
 
index 11e3a285594c231c6b887dc53edbe52ef8519b23..84573df5cf5ae57616efb4d3c1b8c7556d30bc47 100644 (file)
@@ -924,6 +924,7 @@ static int nfs4_set_client(struct nfs_server *server,
        else
                cl_init.max_connect = max_connect;
        switch (proto) {
+       case XPRT_TRANSPORT_RDMA:
        case XPRT_TRANSPORT_TCP:
        case XPRT_TRANSPORT_TCP_TLS:
                cl_init.nconnect = nconnect;
@@ -1000,6 +1001,7 @@ struct nfs_client *nfs4_set_ds_client(struct nfs_server *mds_srv,
        cl_init.hostname = buf;
 
        switch (ds_proto) {
+       case XPRT_TRANSPORT_RDMA:
        case XPRT_TRANSPORT_TCP:
        case XPRT_TRANSPORT_TCP_TLS:
                if (mds_clp->cl_nconnect > 1) {
index 815996cb27fc4589bed01827c086b32e766f0bc0..ea390db94b622f5332f5126ea15f95bc8131344e 100644 (file)
@@ -3069,10 +3069,8 @@ static int _nfs4_open_and_get_state(struct nfs4_opendata *opendata,
        fmode_t acc_mode = _nfs4_ctx_to_accessmode(ctx);
        struct inode *dir = d_inode(opendata->dir);
        unsigned long dir_verifier;
-       unsigned int seq;
        int ret;
 
-       seq = raw_seqcount_begin(&sp->so_reclaim_seqcount);
        dir_verifier = nfs_save_change_attribute(dir);
 
        ret = _nfs4_proc_open(opendata, ctx);
@@ -3125,11 +3123,8 @@ static int _nfs4_open_and_get_state(struct nfs4_opendata *opendata,
        if (ret != 0)
                goto out;
 
-       if (d_inode(dentry) == state->inode) {
+       if (d_inode(dentry) == state->inode)
                nfs_inode_attach_open_context(ctx);
-               if (read_seqcount_retry(&sp->so_reclaim_seqcount, seq))
-                       nfs4_schedule_stateid_recovery(server, state);
-       }
 
 out:
        if (!opendata->cancelled) {
@@ -8973,10 +8968,12 @@ try_again:
                return;
 
        status = task->tk_status;
-       if (status == 0)
+       if (status == 0) {
                status = nfs4_detect_session_trunking(adata->clp,
                                task->tk_msg.rpc_resp, xprt);
-
+               trace_nfs4_trunked_exchange_id(adata->clp,
+                       xprt->address_strings[RPC_DISPLAY_ADDR], status);
+       }
        if (status == 0)
                rpc_clnt_xprt_switch_add_xprt(clnt, xprt);
        else if (status != -NFS4ERR_DELAY && rpc_clnt_xprt_switch_has_addr(clnt,
@@ -10618,29 +10615,33 @@ const struct nfs4_minor_version_ops *nfs_v4_minor_ops[] = {
 static ssize_t nfs4_listxattr(struct dentry *dentry, char *list, size_t size)
 {
        ssize_t error, error2, error3;
+       size_t left = size;
 
-       error = generic_listxattr(dentry, list, size);
+       error = generic_listxattr(dentry, list, left);
        if (error < 0)
                return error;
        if (list) {
                list += error;
-               size -= error;
+               left -= error;
        }
 
-       error2 = nfs4_listxattr_nfs4_label(d_inode(dentry), list, size);
+       error2 = nfs4_listxattr_nfs4_label(d_inode(dentry), list, left);
        if (error2 < 0)
                return error2;
 
        if (list) {
                list += error2;
-               size -= error2;
+               left -= error2;
        }
 
-       error3 = nfs4_listxattr_nfs4_user(d_inode(dentry), list, size);
+       error3 = nfs4_listxattr_nfs4_user(d_inode(dentry), list, left);
        if (error3 < 0)
                return error3;
 
-       return error + error2 + error3;
+       error += error2 + error3;
+       if (size && error > size)
+               return -ERANGE;
+       return error;
 }
 
 static void nfs4_enable_swap(struct inode *inode)
index 8cfabdbda33694912652eeb736126c673bdb745a..662e86ea3a2ddadb7331f9e122c537ca075830e9 100644 (file)
@@ -513,7 +513,6 @@ nfs4_alloc_state_owner(struct nfs_server *server,
        nfs4_init_seqid_counter(&sp->so_seqid);
        atomic_set(&sp->so_count, 1);
        INIT_LIST_HEAD(&sp->so_lru);
-       seqcount_spinlock_init(&sp->so_reclaim_seqcount, &sp->so_lock);
        mutex_init(&sp->so_delegreturn_mutex);
        return sp;
 }
@@ -1667,7 +1666,6 @@ static int nfs4_reclaim_open_state(struct nfs4_state_owner *sp,
         * server that doesn't support a grace period.
         */
        spin_lock(&sp->so_lock);
-       raw_write_seqcount_begin(&sp->so_reclaim_seqcount);
 restart:
        list_for_each_entry(state, &sp->so_states, open_states) {
                if (!test_and_clear_bit(ops->state_flag_bit, &state->flags))
@@ -1735,7 +1733,6 @@ restart:
                spin_lock(&sp->so_lock);
                goto restart;
        }
-       raw_write_seqcount_end(&sp->so_reclaim_seqcount);
        spin_unlock(&sp->so_lock);
 #ifdef CONFIG_NFS_V4_2
        if (found_ssc_copy_state)
@@ -1745,7 +1742,6 @@ restart:
 out_err:
        nfs4_put_open_state(state);
        spin_lock(&sp->so_lock);
-       raw_write_seqcount_end(&sp->so_reclaim_seqcount);
        spin_unlock(&sp->so_lock);
        return status;
 }
@@ -1928,9 +1924,12 @@ static int nfs4_do_reclaim(struct nfs_client *clp, const struct nfs4_state_recov
        struct nfs_server *server;
        struct rb_node *pos;
        LIST_HEAD(freeme);
-       int status = 0;
        int lost_locks = 0;
+       int status;
 
+       status = nfs4_begin_drain_session(clp);
+       if (status < 0)
+               return status;
 restart:
        rcu_read_lock();
        list_for_each_entry_rcu(server, &clp->cl_superblocks, client_link) {
@@ -2694,6 +2693,9 @@ static void nfs4_state_manager(struct nfs_client *clp)
                /* Detect expired delegations... */
                if (test_and_clear_bit(NFS4CLNT_DELEGATION_EXPIRED, &clp->cl_state)) {
                        section = "detect expired delegations";
+                       status = nfs4_begin_drain_session(clp);
+                       if (status < 0)
+                               goto out_error;
                        nfs_reap_expired_delegations(clp);
                        continue;
                }
index d09bcfd7db89488eec9291c4e985e13953f079d3..8da5a9c000f42c3eda0d3b1f35ca45be96a253ae 100644 (file)
@@ -145,6 +145,7 @@ static int do_nfs4_mount(struct nfs_server *server,
                         const char *export_path)
 {
        struct nfs_fs_context *root_ctx;
+       struct nfs_fs_context *ctx;
        struct fs_context *root_fc;
        struct vfsmount *root_mnt;
        struct dentry *dentry;
@@ -157,6 +158,12 @@ static int do_nfs4_mount(struct nfs_server *server,
                .dirfd  = -1,
        };
 
+       struct fs_parameter param_fsc = {
+               .key    = "fsc",
+               .type   = fs_value_is_string,
+               .dirfd  = -1,
+       };
+
        if (IS_ERR(server))
                return PTR_ERR(server);
 
@@ -168,9 +175,26 @@ static int do_nfs4_mount(struct nfs_server *server,
        kfree(root_fc->source);
        root_fc->source = NULL;
 
+       ctx = nfs_fc2context(fc);
        root_ctx = nfs_fc2context(root_fc);
        root_ctx->internal = true;
        root_ctx->server = server;
+
+       if (ctx->fscache_uniq) {
+               len = strlen(ctx->fscache_uniq);
+               param_fsc.size = len;
+               param_fsc.string = kmemdup_nul(ctx->fscache_uniq, len, GFP_KERNEL);
+               if (param_fsc.string == NULL) {
+                       put_fs_context(root_fc);
+                       return -ENOMEM;
+               }
+               ret = vfs_parse_fs_param(root_fc, &param_fsc);
+               kfree(param_fsc.string);
+               if (ret < 0) {
+                       put_fs_context(root_fc);
+                       return ret;
+               }
+       }
        /* We leave export_path unset as it's not used to find the root. */
 
        len = strlen(hostname) + 5;
index d9ac556bebcf685c50a026594823d434202ab903..d22c6670f770f18949ed908e8e64572c174aeb41 100644 (file)
@@ -28,4 +28,6 @@ EXPORT_TRACEPOINT_SYMBOL_GPL(pnfs_mds_fallback_write_pagelist);
 EXPORT_TRACEPOINT_SYMBOL_GPL(ff_layout_read_error);
 EXPORT_TRACEPOINT_SYMBOL_GPL(ff_layout_write_error);
 EXPORT_TRACEPOINT_SYMBOL_GPL(ff_layout_commit_error);
+
+EXPORT_TRACEPOINT_SYMBOL_GPL(fl_getdevinfo);
 #endif
index fd7cb15b08b27628f205cdb4284b9035a7d3172a..10985a4b8259dd543d4b499dde282f15ce7afaab 100644 (file)
@@ -77,6 +77,36 @@ DEFINE_NFS4_CLIENTID_EVENT(nfs4_bind_conn_to_session);
 DEFINE_NFS4_CLIENTID_EVENT(nfs4_sequence);
 DEFINE_NFS4_CLIENTID_EVENT(nfs4_reclaim_complete);
 
+TRACE_EVENT(nfs4_trunked_exchange_id,
+               TP_PROTO(
+                       const struct nfs_client *clp,
+                       const char *addr,
+                       int error
+               ),
+
+               TP_ARGS(clp, addr, error),
+
+               TP_STRUCT__entry(
+                       __string(main_addr, clp->cl_hostname)
+                       __string(trunk_addr, addr)
+                       __field(unsigned long, error)
+               ),
+
+               TP_fast_assign(
+                       __entry->error = error < 0 ? -error : 0;
+                       __assign_str(main_addr, clp->cl_hostname);
+                       __assign_str(trunk_addr, addr);
+               ),
+
+               TP_printk(
+                       "error=%ld (%s) main_addr=%s trunk_addr=%s",
+                       -__entry->error,
+                       show_nfs4_status(__entry->error),
+                       __get_str(main_addr),
+                       __get_str(trunk_addr)
+               )
+);
+
 TRACE_EVENT(nfs4_sequence_done,
                TP_PROTO(
                        const struct nfs4_session *session,
@@ -1991,6 +2021,34 @@ DECLARE_EVENT_CLASS(nfs4_deviceid_status,
 DEFINE_PNFS_DEVICEID_STATUS(nfs4_getdeviceinfo);
 DEFINE_PNFS_DEVICEID_STATUS(nfs4_find_deviceid);
 
+TRACE_EVENT(fl_getdevinfo,
+               TP_PROTO(
+                       const struct nfs_server *server,
+                       const struct nfs4_deviceid *deviceid,
+                       char *ds_remotestr
+               ),
+               TP_ARGS(server, deviceid, ds_remotestr),
+
+               TP_STRUCT__entry(
+                       __string(mds_addr, server->nfs_client->cl_hostname)
+                       __array(unsigned char, deviceid, NFS4_DEVICEID4_SIZE)
+                       __string(ds_ips, ds_remotestr)
+               ),
+
+               TP_fast_assign(
+                       __assign_str(mds_addr, server->nfs_client->cl_hostname);
+                       __assign_str(ds_ips, ds_remotestr);
+                       memcpy(__entry->deviceid, deviceid->data,
+                              NFS4_DEVICEID4_SIZE);
+               ),
+               TP_printk(
+                       "deviceid=%s, mds_addr=%s, ds_ips=%s",
+                       __print_hex(__entry->deviceid, NFS4_DEVICEID4_SIZE),
+                       __get_str(mds_addr),
+                       __get_str(ds_ips)
+               )
+);
+
 DECLARE_EVENT_CLASS(nfs4_flexfiles_io_event,
                TP_PROTO(
                        const struct nfs_pgio_header *hdr
index 7600100ba26f02884812653db5d0231c4e63d0d2..432612d22437423ce5e0d38768c73de47f500074 100644 (file)
@@ -175,10 +175,10 @@ static int __init root_nfs_cat(char *dest, const char *src,
        size_t len = strlen(dest);
 
        if (len && dest[len - 1] != ',')
-               if (strlcat(dest, ",", destlen) > destlen)
+               if (strlcat(dest, ",", destlen) >= destlen)
                        return -1;
 
-       if (strlcat(dest, src, destlen) > destlen)
+       if (strlcat(dest, src, destlen) >= destlen)
                return -1;
        return 0;
 }
index 0c0fed1ecd0bf0d0938dec7b7c8cdca30e65954c..a5cc6199127f5876faae1c27e36c128d9eab9996 100644 (file)
@@ -1999,6 +1999,14 @@ pnfs_update_layout(struct inode *ino,
        }
 
 lookup_again:
+       if (!nfs4_valid_open_stateid(ctx->state)) {
+               trace_pnfs_update_layout(ino, pos, count,
+                                        iomode, lo, lseg,
+                                        PNFS_UPDATE_LAYOUT_INVALID_OPEN);
+               lseg = ERR_PTR(-EIO);
+               goto out;
+       }
+
        lseg = ERR_PTR(nfs4_client_recover_expired_lease(clp));
        if (IS_ERR(lseg))
                goto out;
index afd23910f3bffc52b7d4505e4bb7b6eaa0b632fa..88e061bd711b746afcd46878e518f870fae19b0c 100644 (file)
@@ -919,6 +919,8 @@ static int _nfs4_pnfs_v4_ds_connect(struct nfs_server *mds_srv,
        dprintk("--> %s DS %s\n", __func__, ds->ds_remotestr);
 
        list_for_each_entry(da, &ds->ds_addrs, da_node) {
+               char servername[48];
+
                dprintk("%s: DS %s: trying address %s\n",
                        __func__, ds->ds_remotestr, da->da_remotestr);
 
@@ -929,6 +931,7 @@ static int _nfs4_pnfs_v4_ds_connect(struct nfs_server *mds_srv,
                                .dstaddr = (struct sockaddr *)&da->da_addr,
                                .addrlen = da->da_addrlen,
                                .servername = clp->cl_hostname,
+                               .xprtsec = clp->cl_xprtsec,
                        };
                        struct nfs4_add_xprt_data xprtdata = {
                                .clp = clp,
@@ -938,10 +941,45 @@ static int _nfs4_pnfs_v4_ds_connect(struct nfs_server *mds_srv,
                                .data = &xprtdata,
                        };
 
-                       if (da->da_transport != clp->cl_proto)
+                       if (da->da_transport != clp->cl_proto &&
+                                       clp->cl_proto != XPRT_TRANSPORT_TCP_TLS)
                                continue;
+                       if (da->da_transport == XPRT_TRANSPORT_TCP &&
+                               mds_srv->nfs_client->cl_proto ==
+                                       XPRT_TRANSPORT_TCP_TLS) {
+                               struct sockaddr *addr =
+                                       (struct sockaddr *)&da->da_addr;
+                               struct sockaddr_in *sin =
+                                       (struct sockaddr_in *)&da->da_addr;
+                               struct sockaddr_in6 *sin6 =
+                                       (struct sockaddr_in6 *)&da->da_addr;
+
+                               /* for NFS with TLS we need to supply a correct
+                                * servername of the trunked transport, not the
+                                * servername of the main transport stored in
+                                * clp->cl_hostname. And set the protocol to
+                                * indicate to use TLS
+                                */
+                               servername[0] = '\0';
+                               switch(addr->sa_family) {
+                               case AF_INET:
+                                       snprintf(servername, sizeof(servername),
+                                               "%pI4", &sin->sin_addr.s_addr);
+                                       break;
+                               case AF_INET6:
+                                       snprintf(servername, sizeof(servername),
+                                               "%pI6", &sin6->sin6_addr);
+                                       break;
+                               default:
+                                       /* do not consider this address */
+                                       continue;
+                               }
+                               xprt_args.ident = XPRT_TRANSPORT_TCP_TLS;
+                               xprt_args.servername = servername;
+                       }
                        if (da->da_addr.ss_family != clp->cl_addr.ss_family)
                                continue;
+
                        /**
                        * Test this address for session trunking and
                        * add as an alias
@@ -953,6 +991,10 @@ static int _nfs4_pnfs_v4_ds_connect(struct nfs_server *mds_srv,
                        if (xprtdata.cred)
                                put_cred(xprtdata.cred);
                } else {
+                       if (da->da_transport == XPRT_TRANSPORT_TCP &&
+                               mds_srv->nfs_client->cl_proto ==
+                                       XPRT_TRANSPORT_TCP_TLS)
+                               da->da_transport = XPRT_TRANSPORT_TCP_TLS;
                        clp = nfs4_set_ds_client(mds_srv,
                                                &da->da_addr,
                                                da->da_addrlen,
index 7dc21a48e3e7b6a0b86f06148163450e79564f82..a142287d86f68ed411dce6f9c410e41948c570b2 100644 (file)
@@ -305,6 +305,8 @@ int nfs_read_add_folio(struct nfs_pageio_descriptor *pgio,
        new = nfs_page_create_from_folio(ctx, folio, 0, aligned_len);
        if (IS_ERR(new)) {
                error = PTR_ERR(new);
+               if (nfs_netfs_folio_unlock(folio))
+                       folio_unlock(folio);
                goto out;
        }
 
index 075b31c93f87d0c8a4aa9699187e94bcdba0aeab..dc03f98f7616a8ba4f7c4d65cbfec0aabe98f942 100644 (file)
@@ -516,8 +516,16 @@ static void nfs_show_mount_options(struct seq_file *m, struct nfs_server *nfss,
        else
                nfs_show_nfsv4_options(m, nfss, showdefaults);
 
-       if (nfss->options & NFS_OPTION_FSCACHE)
+       if (nfss->options & NFS_OPTION_FSCACHE) {
+#ifdef CONFIG_NFS_FSCACHE
+               if (nfss->fscache_uniq)
+                       seq_printf(m, ",fsc=%s", nfss->fscache_uniq);
+               else
+                       seq_puts(m, ",fsc");
+#else
                seq_puts(m, ",fsc");
+#endif
+       }
 
        if (nfss->options & NFS_OPTION_MIGRATION)
                seq_puts(m, ",migration");
index 84bb852645728b3edf427c5ac1020e38f329f325..5de85d725fb95fdd19fe814aba607c5249267a6a 100644 (file)
@@ -667,10 +667,6 @@ static int nfs_writepage_locked(struct folio *folio,
        struct inode *inode = folio_file_mapping(folio)->host;
        int err;
 
-       if (wbc->sync_mode == WB_SYNC_NONE &&
-           NFS_SERVER(inode)->write_congested)
-               return AOP_WRITEPAGE_ACTIVATE;
-
        nfs_inc_stats(inode, NFSIOS_VFSWRITEPAGE);
        nfs_pageio_init_write(&pgio, inode, 0, false,
                              &nfs_async_write_completion_ops);
@@ -1650,7 +1646,7 @@ static int wait_on_commit(struct nfs_mds_commit_info *cinfo)
                                       !atomic_read(&cinfo->rpcs_out));
 }
 
-static void nfs_commit_begin(struct nfs_mds_commit_info *cinfo)
+void nfs_commit_begin(struct nfs_mds_commit_info *cinfo)
 {
        atomic_inc(&cinfo->rpcs_out);
 }
index f5ce7b1011461385968723826f4052f3f492a4af..d59116ac82099d0b5985a7f2b57a2e69e9e860dc 100644 (file)
@@ -611,6 +611,7 @@ int nfs_wb_folio_cancel(struct inode *inode, struct folio *folio);
 extern int  nfs_commit_inode(struct inode *, int);
 extern struct nfs_commit_data *nfs_commitdata_alloc(void);
 extern void nfs_commit_free(struct nfs_commit_data *data);
+void nfs_commit_begin(struct nfs_mds_commit_info *cinfo);
 bool nfs_commit_end(struct nfs_mds_commit_info *cinfo);
 
 static inline bool nfs_have_writebacks(const struct inode *inode)
index 539b57fbf3ce397ae80bbe186547f77100830d1b..d09b9773b20c8251f5a2e9232bbed6b22f6bd708 100644 (file)
@@ -1820,13 +1820,6 @@ struct nfs_rpc_ops {
        void    (*disable_swap)(struct inode *inode);
 };
 
-/*
- *     NFS_CALL(getattr, inode, (fattr));
- * into
- *     NFS_PROTO(inode)->getattr(fattr);
- */
-#define NFS_CALL(op, inode, args)      NFS_PROTO(inode)->op args
-
 /*
  * Function vectors etc. for the NFS client
  */
index 5e9d1469c6faea4c8de2f408041ae0c18a75dbfd..5321585c778fcc1fef0e0420cb481786c02a7aac 100644 (file)
@@ -139,6 +139,7 @@ struct rpc_create_args {
        const char              *servername;
        const char              *nodename;
        const struct rpc_program *program;
+       struct rpc_stat         *stats;
        u32                     prognumber;     /* overrides program->number */
        u32                     version;
        rpc_authflavor_t        authflavor;
index 2d61987b354564d4b227e2f4f5ad676ca014814a..0c77ba488bbae9431f7e99f95461869cfe696750 100644 (file)
@@ -197,7 +197,7 @@ struct rpc_wait_queue {
        unsigned char           maxpriority;            /* maximum priority (0 if queue is not a priority queue) */
        unsigned char           priority;               /* current priority */
        unsigned char           nr;                     /* # tasks remaining for cookie */
-       unsigned short          qlen;                   /* total # tasks waiting in queue */
+       unsigned int            qlen;                   /* total # tasks waiting in queue */
        struct rpc_timer        timer_list;
 #if IS_ENABLED(CONFIG_SUNRPC_DEBUG) || IS_ENABLED(CONFIG_TRACEPOINTS)
        const char *            name;
index 464f6a9492ab7e2e3b8e0e5f5edc0d4f456c6636..81b952649d35e3ad4fa8c7e77388ac2ceb44ce60 100644 (file)
@@ -152,6 +152,7 @@ struct rpc_xprt_ops {
        int             (*prepare_request)(struct rpc_rqst *req,
                                           struct xdr_buf *buf);
        int             (*send_request)(struct rpc_rqst *req);
+       void            (*abort_send_request)(struct rpc_rqst *req);
        void            (*wait_for_reply_request)(struct rpc_task *task);
        void            (*timer)(struct rpc_xprt *xprt, struct rpc_task *task);
        void            (*release_request)(struct rpc_task *task);
index cdd3a45e6003aa5791932261757d32f1287747de..4a2abf9daa465b6dd563c5e793df1ed42cd30740 100644 (file)
@@ -639,6 +639,7 @@ TRACE_EVENT(rpc_stats_latency,
                __field(unsigned long, backlog)
                __field(unsigned long, rtt)
                __field(unsigned long, execute)
+               __field(u32, xprt_id)
        ),
 
        TP_fast_assign(
@@ -651,13 +652,16 @@ TRACE_EVENT(rpc_stats_latency,
                __entry->backlog = ktime_to_us(backlog);
                __entry->rtt = ktime_to_us(rtt);
                __entry->execute = ktime_to_us(execute);
+               __entry->xprt_id = task->tk_xprt->id;
        ),
 
        TP_printk(SUNRPC_TRACE_TASK_SPECIFIER
-                 " xid=0x%08x %sv%d %s backlog=%lu rtt=%lu execute=%lu",
+                 " xid=0x%08x %sv%d %s backlog=%lu rtt=%lu execute=%lu"
+                 " xprt_id=%d",
                __entry->task_id, __entry->client_id, __entry->xid,
                __get_str(progname), __entry->version, __get_str(procname),
-               __entry->backlog, __entry->rtt, __entry->execute)
+               __entry->backlog, __entry->rtt, __entry->execute,
+               __entry->xprt_id)
 );
 
 TRACE_EVENT(rpc_xdr_overflow,
index 64ab5dac59ce0c7ea6834e308b307e17e649dc4b..e43e745915618e53762915436cb248cba1a71005 100644 (file)
@@ -239,6 +239,7 @@ TRACE_DEFINE_ENUM(NFS4ERR_RESET_TO_PNFS);
                { EHOSTDOWN,                    "EHOSTDOWN" }, \
                { EPIPE,                        "EPIPE" }, \
                { EPFNOSUPPORT,                 "EPFNOSUPPORT" }, \
+               { EINVAL,                       "EINVAL" }, \
                { EPROTONOSUPPORT,              "EPROTONOSUPPORT" }, \
                { NFS4ERR_ACCESS,               "ACCESS" }, \
                { NFS4ERR_ATTRNOTSUPP,          "ATTRNOTSUPP" }, \
index d435bffc6199978500dc9106ee63cad8a158f87e..97ff11973c49377cbff0ad36f4b266cc54b1c045 100644 (file)
@@ -284,10 +284,10 @@ char *rpc_sockaddr2uaddr(const struct sockaddr *sap, gfp_t gfp_flags)
        }
 
        if (snprintf(portbuf, sizeof(portbuf),
-                    ".%u.%u", port >> 8, port & 0xff) > (int)sizeof(portbuf))
+                    ".%u.%u", port >> 8, port & 0xff) >= (int)sizeof(portbuf))
                return NULL;
 
-       if (strlcat(addrbuf, portbuf, sizeof(addrbuf)) > sizeof(addrbuf))
+       if (strlcat(addrbuf, portbuf, sizeof(addrbuf)) >= sizeof(addrbuf))
                return NULL;
 
        return kstrdup(addrbuf, gfp_flags);
index cda0935a68c9db9462a663de3baad3ed786c0385..28f3749f6dc6cb7393d61c8fc07d9980a374f28b 100644 (file)
@@ -405,7 +405,7 @@ static struct rpc_clnt * rpc_new_client(const struct rpc_create_args *args,
        clnt->cl_maxproc  = version->nrprocs;
        clnt->cl_prog     = args->prognumber ? : program->number;
        clnt->cl_vers     = version->number;
-       clnt->cl_stats    = program->stats;
+       clnt->cl_stats    = args->stats ? : program->stats;
        clnt->cl_metrics  = rpc_alloc_iostats(clnt);
        rpc_init_pipe_dir_head(&clnt->cl_pipedir_objects);
        err = -ENOMEM;
@@ -691,6 +691,7 @@ struct rpc_clnt *rpc_clone_client(struct rpc_clnt *clnt)
                .version        = clnt->cl_vers,
                .authflavor     = clnt->cl_auth->au_flavor,
                .cred           = clnt->cl_cred,
+               .stats          = clnt->cl_stats,
        };
        return __rpc_clone_client(&args, clnt);
 }
@@ -713,6 +714,7 @@ rpc_clone_client_set_auth(struct rpc_clnt *clnt, rpc_authflavor_t flavor)
                .version        = clnt->cl_vers,
                .authflavor     = flavor,
                .cred           = clnt->cl_cred,
+               .stats          = clnt->cl_stats,
        };
        return __rpc_clone_client(&args, clnt);
 }
@@ -1068,6 +1070,7 @@ struct rpc_clnt *rpc_bind_new_program(struct rpc_clnt *old,
                .version        = vers,
                .authflavor     = old->cl_auth->au_flavor,
                .cred           = old->cl_cred,
+               .stats          = old->cl_stats,
        };
        struct rpc_clnt *clnt;
        int err;
index af13fdfa6672146daf1b572aa29a8d4bd3731b1d..09f245cda5262a572c450237419c80b183a83568 100644 (file)
@@ -1398,6 +1398,12 @@ xprt_request_dequeue_transmit_locked(struct rpc_task *task)
        if (!test_and_clear_bit(RPC_TASK_NEED_XMIT, &task->tk_runstate))
                return;
        if (!list_empty(&req->rq_xmit)) {
+               struct rpc_xprt *xprt = req->rq_xprt;
+
+               if (list_is_first(&req->rq_xmit, &xprt->xmit_queue) &&
+                   xprt->ops->abort_send_request)
+                       xprt->ops->abort_send_request(req);
+
                list_del(&req->rq_xmit);
                if (!list_empty(&req->rq_xmit2)) {
                        struct rpc_rqst *next = list_first_entry(&req->rq_xmit2,
@@ -1541,6 +1547,9 @@ xprt_request_transmit(struct rpc_rqst *req, struct rpc_task *snd_task)
        int is_retrans = RPC_WAS_SENT(task);
        int status;
 
+       if (test_bit(XPRT_CLOSE_WAIT, &xprt->state))
+               return -ENOTCONN;
+
        if (!req->rq_bytes_sent) {
                if (xprt_request_data_received(task)) {
                        status = 0;
index d92c13e78a56cf584772fb68783866be75b9bf79..bb9b747d58a1afac3619b80cff3e8196e36d96c3 100644 (file)
@@ -62,6 +62,7 @@
 #include "sunrpc.h"
 
 static void xs_close(struct rpc_xprt *xprt);
+static void xs_reset_srcport(struct sock_xprt *transport);
 static void xs_set_srcport(struct sock_xprt *transport, struct socket *sock);
 static void xs_tcp_set_socket_timeouts(struct rpc_xprt *xprt,
                struct socket *sock);
@@ -883,6 +884,17 @@ static int xs_stream_prepare_request(struct rpc_rqst *req, struct xdr_buf *buf)
        return xdr_alloc_bvec(buf, rpc_task_gfp_mask());
 }
 
+static void xs_stream_abort_send_request(struct rpc_rqst *req)
+{
+       struct rpc_xprt *xprt = req->rq_xprt;
+       struct sock_xprt *transport =
+               container_of(xprt, struct sock_xprt, xprt);
+
+       if (transport->xmit.offset != 0 &&
+           !test_bit(XPRT_CLOSE_WAIT, &xprt->state))
+               xprt_force_disconnect(xprt);
+}
+
 /*
  * Determine if the previous message in the stream was aborted before it
  * could complete transmission.
@@ -1565,8 +1577,10 @@ static void xs_tcp_state_change(struct sock *sk)
                break;
        case TCP_CLOSE:
                if (test_and_clear_bit(XPRT_SOCK_CONNECTING,
-                                       &transport->sock_state))
+                                      &transport->sock_state)) {
+                       xs_reset_srcport(transport);
                        xprt_clear_connecting(xprt);
+               }
                clear_bit(XPRT_CLOSING, &xprt->state);
                /* Trigger the socket release */
                xs_run_error_worker(transport, XPRT_SOCK_WAKE_DISCONNECT);
@@ -1722,6 +1736,11 @@ static void xs_set_port(struct rpc_xprt *xprt, unsigned short port)
        xs_update_peer_port(xprt);
 }
 
+static void xs_reset_srcport(struct sock_xprt *transport)
+{
+       transport->srcport = 0;
+}
+
 static void xs_set_srcport(struct sock_xprt *transport, struct socket *sock)
 {
        if (transport->srcport == 0 && transport->xprt.reuseport)
@@ -3012,6 +3031,7 @@ static const struct rpc_xprt_ops xs_local_ops = {
        .buf_free               = rpc_free,
        .prepare_request        = xs_stream_prepare_request,
        .send_request           = xs_local_send_request,
+       .abort_send_request     = xs_stream_abort_send_request,
        .wait_for_reply_request = xprt_wait_for_reply_request_def,
        .close                  = xs_close,
        .destroy                = xs_destroy,
@@ -3059,6 +3079,7 @@ static const struct rpc_xprt_ops xs_tcp_ops = {
        .buf_free               = rpc_free,
        .prepare_request        = xs_stream_prepare_request,
        .send_request           = xs_tcp_send_request,
+       .abort_send_request     = xs_stream_abort_send_request,
        .wait_for_reply_request = xprt_wait_for_reply_request_def,
        .close                  = xs_tcp_shutdown,
        .destroy                = xs_destroy,