]> git.proxmox.com Git - mirror_ubuntu-jammy-kernel.git/commitdiff
Merge tag 'nfs-for-5.15-1' of git://git.linux-nfs.org/projects/anna/linux-nfs
authorLinus Torvalds <torvalds@linux-foundation.org>
Sat, 4 Sep 2021 17:25:26 +0000 (10:25 -0700)
committerLinus Torvalds <torvalds@linux-foundation.org>
Sat, 4 Sep 2021 17:25:26 +0000 (10:25 -0700)
Pull NFS client updates from Anna Schumaker:
 "New Features:
   - Better client responsiveness when server isn't replying
   - Use refcount_t in sunrpc rpc_client refcount tracking
   - Add srcaddr and dst_port to the sunrpc sysfs info files
   - Add basic support for connection sharing between servers with multiple NICs`

  Bugfixes and Cleanups:
   - Sunrpc tracepoint cleanups
   - Disconnect after ib_post_send() errors to avoid deadlocks
   - Fix for tearing down rpcrdma_reps
   - Fix a potential pNFS layoutget livelock loop
   - pNFS layout barrier fixes
   - Fix a potential memory corruption in rpc_wake_up_queued_task_set_status()
   - Fix reconnection locking
   - Fix return value of get_srcport()
   - Remove rpcrdma_post_sends()
   - Remove pNFS dead code
   - Remove copy size restriction for inter-server copies
   - Overhaul the NFS callback service
   - Clean up sunrpc TCP socket shutdowns
   - Always provide aligned buffers to RPC read layers"

* tag 'nfs-for-5.15-1' of git://git.linux-nfs.org/projects/anna/linux-nfs: (39 commits)
  NFS: Always provide aligned buffers to the RPC read layers
  NFSv4.1 add network transport when session trunking is detected
  SUNRPC enforce creation of no more than max_connect xprts
  NFSv4 introduce max_connect mount options
  SUNRPC add xps_nunique_destaddr_xprts to xprt_switch_info in sysfs
  SUNRPC keep track of number of transports to unique addresses
  NFSv3: Delete duplicate judgement in nfs3_async_handle_jukebox
  SUNRPC: Tweak TCP socket shutdown in the RPC client
  SUNRPC: Simplify socket shutdown when not reusing TCP ports
  NFSv4.2: remove restriction of copy size for inter-server copy.
  NFS: Clean up the synopsis of callback process_op()
  NFS: Extract the xdr_init_encode/decode() calls from decode_compound
  NFS: Remove unused callback void decoder
  NFS: Add a private local dispatcher for NFSv4 callback operations
  SUNRPC: Eliminate the RQ_AUTHERR flag
  SUNRPC: Set rq_auth_stat in the pg_authenticate() callout
  SUNRPC: Add svc_rqst::rq_auth_stat
  SUNRPC: Add dst_port to the sysfs xprt info file
  SUNRPC: Add srcaddr as a file in sysfs
  sunrpc: Fix return value of get_srcport()
  ...

38 files changed:
fs/lockd/svc.c
fs/nfs/callback.c
fs/nfs/callback_xdr.c
fs/nfs/client.c
fs/nfs/fs_context.c
fs/nfs/internal.h
fs/nfs/nfs3proc.c
fs/nfs/nfs4client.c
fs/nfs/nfs4file.c
fs/nfs/pnfs.c
fs/nfs/read.c
fs/nfs/super.c
include/linux/nfs_fs.h
include/linux/nfs_fs_sb.h
include/linux/sunrpc/clnt.h
include/linux/sunrpc/svc.h
include/linux/sunrpc/svcauth.h
include/linux/sunrpc/xprt.h
include/linux/sunrpc/xprtmultipath.h
include/trace/events/rpcrdma.h
include/trace/events/sunrpc.h
net/sunrpc/auth_gss/gss_rpc_upcall.c
net/sunrpc/auth_gss/svcauth_gss.c
net/sunrpc/clnt.c
net/sunrpc/debugfs.c
net/sunrpc/rpc_pipe.c
net/sunrpc/svc.c
net/sunrpc/svcauth.c
net/sunrpc/svcauth_unix.c
net/sunrpc/sysfs.c
net/sunrpc/xprt.c
net/sunrpc/xprtmultipath.c
net/sunrpc/xprtrdma/backchannel.c
net/sunrpc/xprtrdma/frwr_ops.c
net/sunrpc/xprtrdma/transport.c
net/sunrpc/xprtrdma/verbs.c
net/sunrpc/xprtrdma/xprt_rdma.h
net/sunrpc/xprtsock.c

index 0ab9756ed2359f69efbda3d473acbe8946455b43..b632be3ad57b2840b528de2de4811d19e54d76ef 100644 (file)
@@ -649,6 +649,7 @@ static int lockd_authenticate(struct svc_rqst *rqstp)
        switch (rqstp->rq_authop->flavour) {
                case RPC_AUTH_NULL:
                case RPC_AUTH_UNIX:
+                       rqstp->rq_auth_stat = rpc_auth_ok;
                        if (rqstp->rq_proc == 0)
                                return SVC_OK;
                        if (is_callback(rqstp->rq_proc)) {
@@ -659,6 +660,7 @@ static int lockd_authenticate(struct svc_rqst *rqstp)
                        }
                        return svc_set_client(rqstp);
        }
+       rqstp->rq_auth_stat = rpc_autherr_badcred;
        return SVC_DENIED;
 }
 
index 7817ad94a6bae5417b3aa7dcfe631b61870b32f8..86d856de1389b18583f5db9842be133c6a19a6a0 100644 (file)
@@ -429,6 +429,8 @@ check_gss_callback_principal(struct nfs_client *clp, struct svc_rqst *rqstp)
  */
 static int nfs_callback_authenticate(struct svc_rqst *rqstp)
 {
+       rqstp->rq_auth_stat = rpc_autherr_badcred;
+
        switch (rqstp->rq_authop->flavour) {
        case RPC_AUTH_NULL:
                if (rqstp->rq_proc != CB_NULL)
@@ -439,6 +441,8 @@ static int nfs_callback_authenticate(struct svc_rqst *rqstp)
                 if (svc_is_backchannel(rqstp))
                        return SVC_DENIED;
        }
+
+       rqstp->rq_auth_stat = rpc_auth_ok;
        return SVC_OK;
 }
 
index c5348ba811297839d14e429904a0f42eced487ad..4c48d85f651707a683ccbdd3dd7d1d26eeec7359 100644 (file)
@@ -63,11 +63,10 @@ static __be32 nfs4_callback_null(struct svc_rqst *rqstp)
        return htonl(NFS4_OK);
 }
 
-static int nfs4_decode_void(struct svc_rqst *rqstp, __be32 *p)
-{
-       return xdr_argsize_check(rqstp, p);
-}
-
+/*
+ * svc_process_common() looks for an XDR encoder to know when
+ * not to drop a Reply.
+ */
 static int nfs4_encode_void(struct svc_rqst *rqstp, __be32 *p)
 {
        return xdr_ressize_check(rqstp, p);
@@ -864,17 +863,16 @@ preprocess_nfs4_op(unsigned int op_nr, struct callback_op **op)
 }
 
 static __be32 process_op(int nop, struct svc_rqst *rqstp,
-               struct xdr_stream *xdr_in, void *argp,
-               struct xdr_stream *xdr_out, void *resp,
-               struct cb_process_state *cps)
+                        struct cb_process_state *cps)
 {
+       struct xdr_stream *xdr_out = &rqstp->rq_res_stream;
        struct callback_op *op = &callback_ops[0];
        unsigned int op_nr;
        __be32 status;
        long maxlen;
        __be32 res;
 
-       status = decode_op_hdr(xdr_in, &op_nr);
+       status = decode_op_hdr(&rqstp->rq_arg_stream, &op_nr);
        if (unlikely(status))
                return status;
 
@@ -904,9 +902,11 @@ static __be32 process_op(int nop, struct svc_rqst *rqstp,
 
        maxlen = xdr_out->end - xdr_out->p;
        if (maxlen > 0 && maxlen < PAGE_SIZE) {
-               status = op->decode_args(rqstp, xdr_in, argp);
+               status = op->decode_args(rqstp, &rqstp->rq_arg_stream,
+                                        rqstp->rq_argp);
                if (likely(status == 0))
-                       status = op->process_op(argp, resp, cps);
+                       status = op->process_op(rqstp->rq_argp, rqstp->rq_resp,
+                                               cps);
        } else
                status = htonl(NFS4ERR_RESOURCE);
 
@@ -915,7 +915,7 @@ encode_hdr:
        if (unlikely(res))
                return res;
        if (op->encode_res != NULL && status == 0)
-               status = op->encode_res(rqstp, xdr_out, resp);
+               status = op->encode_res(rqstp, xdr_out, rqstp->rq_resp);
        return status;
 }
 
@@ -926,22 +926,15 @@ static __be32 nfs4_callback_compound(struct svc_rqst *rqstp)
 {
        struct cb_compound_hdr_arg hdr_arg = { 0 };
        struct cb_compound_hdr_res hdr_res = { NULL };
-       struct xdr_stream xdr_in, xdr_out;
-       __be32 *p, status;
        struct cb_process_state cps = {
                .drc_status = 0,
                .clp = NULL,
                .net = SVC_NET(rqstp),
        };
        unsigned int nops = 0;
+       __be32 status;
 
-       xdr_init_decode(&xdr_in, &rqstp->rq_arg,
-                       rqstp->rq_arg.head[0].iov_base, NULL);
-
-       p = (__be32*)((char *)rqstp->rq_res.head[0].iov_base + rqstp->rq_res.head[0].iov_len);
-       xdr_init_encode(&xdr_out, &rqstp->rq_res, p, NULL);
-
-       status = decode_compound_hdr_arg(&xdr_in, &hdr_arg);
+       status = decode_compound_hdr_arg(&rqstp->rq_arg_stream, &hdr_arg);
        if (status == htonl(NFS4ERR_RESOURCE))
                return rpc_garbage_args;
 
@@ -961,15 +954,13 @@ static __be32 nfs4_callback_compound(struct svc_rqst *rqstp)
        cps.minorversion = hdr_arg.minorversion;
        hdr_res.taglen = hdr_arg.taglen;
        hdr_res.tag = hdr_arg.tag;
-       if (encode_compound_hdr_res(&xdr_out, &hdr_res) != 0) {
+       if (encode_compound_hdr_res(&rqstp->rq_res_stream, &hdr_res) != 0) {
                if (cps.clp)
                        nfs_put_client(cps.clp);
                return rpc_system_err;
        }
        while (status == 0 && nops != hdr_arg.nops) {
-               status = process_op(nops, rqstp, &xdr_in,
-                                   rqstp->rq_argp, &xdr_out, rqstp->rq_resp,
-                                   &cps);
+               status = process_op(nops, rqstp, &cps);
                nops++;
        }
 
@@ -988,7 +979,20 @@ static __be32 nfs4_callback_compound(struct svc_rqst *rqstp)
 
 out_invalidcred:
        pr_warn_ratelimited("NFS: NFSv4 callback contains invalid cred\n");
-       return svc_return_autherr(rqstp, rpc_autherr_badcred);
+       rqstp->rq_auth_stat = rpc_autherr_badcred;
+       return rpc_success;
+}
+
+static int
+nfs_callback_dispatch(struct svc_rqst *rqstp, __be32 *statp)
+{
+       const struct svc_procedure *procp = rqstp->rq_procinfo;
+
+       svcxdr_init_decode(rqstp);
+       svcxdr_init_encode(rqstp);
+
+       *statp = procp->pc_func(rqstp);
+       return 1;
 }
 
 /*
@@ -1057,7 +1061,6 @@ static struct callback_op callback_ops[] = {
 static const struct svc_procedure nfs4_callback_procedures1[] = {
        [CB_NULL] = {
                .pc_func = nfs4_callback_null,
-               .pc_decode = nfs4_decode_void,
                .pc_encode = nfs4_encode_void,
                .pc_xdrressize = 1,
                .pc_name = "NULL",
@@ -1079,7 +1082,7 @@ const struct svc_version nfs4_callback_version1 = {
        .vs_proc = nfs4_callback_procedures1,
        .vs_count = nfs4_callback_count1,
        .vs_xdrsize = NFS4_CALLBACK_XDRSIZE,
-       .vs_dispatch = NULL,
+       .vs_dispatch = nfs_callback_dispatch,
        .vs_hidden = true,
        .vs_need_cong_ctrl = true,
 };
@@ -1091,7 +1094,7 @@ const struct svc_version nfs4_callback_version4 = {
        .vs_proc = nfs4_callback_procedures1,
        .vs_count = nfs4_callback_count4,
        .vs_xdrsize = NFS4_CALLBACK_XDRSIZE,
-       .vs_dispatch = NULL,
+       .vs_dispatch = nfs_callback_dispatch,
        .vs_hidden = true,
        .vs_need_cong_ctrl = true,
 };
index 330f65727c4543e68abec9adb2953c2005e88c50..23e165d5ec9cabfe7297f1f5158f73ef6e16f184 100644 (file)
@@ -179,6 +179,7 @@ struct nfs_client *nfs_alloc_client(const struct nfs_client_initdata *cl_init)
 
        clp->cl_proto = cl_init->proto;
        clp->cl_nconnect = cl_init->nconnect;
+       clp->cl_max_connect = cl_init->max_connect ? cl_init->max_connect : 1;
        clp->cl_net = get_net(cl_init->net);
 
        clp->cl_principal = "*";
@@ -540,6 +541,7 @@ int nfs_create_rpc_client(struct nfs_client *clp,
 
        clnt->cl_principal = clp->cl_principal;
        clp->cl_rpcclient = clnt;
+       clnt->cl_max_connect = clp->cl_max_connect;
        return 0;
 }
 EXPORT_SYMBOL_GPL(nfs_create_rpc_client);
index d95c9a39bc70b14d3d576281368933025ddfebdb..0d444a90f513a9fa6d2cef1748a7218575a38d84 100644 (file)
@@ -60,6 +60,7 @@ enum nfs_param {
        Opt_mountvers,
        Opt_namelen,
        Opt_nconnect,
+       Opt_max_connect,
        Opt_port,
        Opt_posix,
        Opt_proto,
@@ -158,6 +159,7 @@ static const struct fs_parameter_spec nfs_fs_parameters[] = {
        fsparam_u32   ("mountvers",     Opt_mountvers),
        fsparam_u32   ("namlen",        Opt_namelen),
        fsparam_u32   ("nconnect",      Opt_nconnect),
+       fsparam_u32   ("max_connect",   Opt_max_connect),
        fsparam_string("nfsvers",       Opt_vers),
        fsparam_u32   ("port",          Opt_port),
        fsparam_flag_no("posix",        Opt_posix),
@@ -770,6 +772,11 @@ static int nfs_fs_context_parse_param(struct fs_context *fc,
                        goto out_of_bounds;
                ctx->nfs_server.nconnect = result.uint_32;
                break;
+       case Opt_max_connect:
+               if (result.uint_32 < 1 || result.uint_32 > NFS_MAX_TRANSPORTS)
+                       goto out_of_bounds;
+               ctx->nfs_server.max_connect = result.uint_32;
+               break;
        case Opt_lookupcache:
                switch (result.uint_32) {
                case Opt_lookupcache_all:
index a36af04188c22cca5ee0df42351a403dac4ec72b..66fc936834f23ae5be012ec8d8caeab81724c08c 100644 (file)
@@ -67,6 +67,7 @@ struct nfs_client_initdata {
        int proto;
        u32 minorversion;
        unsigned int nconnect;
+       unsigned int max_connect;
        struct net *net;
        const struct rpc_timeout *timeparms;
        const struct cred *cred;
@@ -121,6 +122,7 @@ struct nfs_fs_context {
                int                     port;
                unsigned short          protocol;
                unsigned short          nconnect;
+               unsigned short          max_connect;
                unsigned short          export_path_len;
        } nfs_server;
 
index 2299446b3b89bb7ef1c9274abbfbc3c9634ae4ef..f7524310ddf4b0b04a1bd2244b274e2fb4d6d19c 100644 (file)
@@ -49,8 +49,7 @@ nfs3_async_handle_jukebox(struct rpc_task *task, struct inode *inode)
 {
        if (task->tk_status != -EJUKEBOX)
                return 0;
-       if (task->tk_status == -EJUKEBOX)
-               nfs_inc_stats(inode, NFSIOS_DELAY);
+       nfs_inc_stats(inode, NFSIOS_DELAY);
        task->tk_status = 0;
        rpc_restart_call(task);
        rpc_delay(task, NFS_JUKEBOX_RETRY_TIME);
index 28431acd1230b105330d0135d6b634979cdfa802..af57332503bed2ff671340fb03d6045362ea5178 100644 (file)
@@ -402,6 +402,33 @@ static int nfs4_init_client_minor_version(struct nfs_client *clp)
        return nfs4_init_callback(clp);
 }
 
+static void nfs4_add_trunk(struct nfs_client *clp, struct nfs_client *old)
+{
+       struct sockaddr_storage clp_addr, old_addr;
+       struct sockaddr *clp_sap = (struct sockaddr *)&clp_addr;
+       struct sockaddr *old_sap = (struct sockaddr *)&old_addr;
+       size_t clp_salen;
+       struct xprt_create xprt_args = {
+               .ident = old->cl_proto,
+               .net = old->cl_net,
+               .servername = old->cl_hostname,
+       };
+
+       if (clp->cl_proto != old->cl_proto)
+               return;
+       clp_salen = rpc_peeraddr(clp->cl_rpcclient, clp_sap, sizeof(clp_addr));
+       rpc_peeraddr(old->cl_rpcclient, old_sap, sizeof(old_addr));
+
+       if (clp_addr.ss_family != old_addr.ss_family)
+               return;
+
+       xprt_args.dstaddr = clp_sap;
+       xprt_args.addrlen = clp_salen;
+
+       rpc_clnt_add_xprt(old->cl_rpcclient, &xprt_args,
+                         rpc_clnt_test_and_add_xprt, NULL);
+}
+
 /**
  * nfs4_init_client - Initialise an NFS4 client record
  *
@@ -436,6 +463,8 @@ struct nfs_client *nfs4_init_client(struct nfs_client *clp,
                 * won't try to use it.
                 */
                nfs_mark_client_ready(clp, -EPERM);
+               if (old->cl_mvops->session_trunk)
+                       nfs4_add_trunk(clp, old);
        }
        clear_bit(NFS_CS_TSM_POSSIBLE, &clp->cl_flags);
        nfs_put_client(clp);
@@ -865,6 +894,7 @@ static int nfs4_set_client(struct nfs_server *server,
                const char *ip_addr,
                int proto, const struct rpc_timeout *timeparms,
                u32 minorversion, unsigned int nconnect,
+               unsigned int max_connect,
                struct net *net)
 {
        struct nfs_client_initdata cl_init = {
@@ -883,6 +913,8 @@ static int nfs4_set_client(struct nfs_server *server,
 
        if (minorversion == 0)
                __set_bit(NFS_CS_REUSEPORT, &cl_init.init_flags);
+       else
+               cl_init.max_connect = max_connect;
        if (proto == XPRT_TRANSPORT_TCP)
                cl_init.nconnect = nconnect;
 
@@ -952,8 +984,10 @@ struct nfs_client *nfs4_set_ds_client(struct nfs_server *mds_srv,
                return ERR_PTR(-EINVAL);
        cl_init.hostname = buf;
 
-       if (mds_clp->cl_nconnect > 1 && ds_proto == XPRT_TRANSPORT_TCP)
+       if (mds_clp->cl_nconnect > 1 && ds_proto == XPRT_TRANSPORT_TCP) {
                cl_init.nconnect = mds_clp->cl_nconnect;
+               cl_init.max_connect = NFS_MAX_TRANSPORTS;
+       }
 
        if (mds_srv->flags & NFS_MOUNT_NORESVPORT)
                __set_bit(NFS_CS_NORESVPORT, &cl_init.init_flags);
@@ -1122,6 +1156,7 @@ static int nfs4_init_server(struct nfs_server *server, struct fs_context *fc)
                                &timeparms,
                                ctx->minorversion,
                                ctx->nfs_server.nconnect,
+                               ctx->nfs_server.max_connect,
                                fc->net_ns);
        if (error < 0)
                return error;
@@ -1211,6 +1246,7 @@ struct nfs_server *nfs4_create_referral_server(struct fs_context *fc)
                                parent_server->client->cl_timeout,
                                parent_client->cl_mvops->minor_version,
                                parent_client->cl_nconnect,
+                               parent_client->cl_max_connect,
                                parent_client->cl_net);
        if (!error)
                goto init_server;
@@ -1226,6 +1262,7 @@ struct nfs_server *nfs4_create_referral_server(struct fs_context *fc)
                                parent_server->client->cl_timeout,
                                parent_client->cl_mvops->minor_version,
                                parent_client->cl_nconnect,
+                               parent_client->cl_max_connect,
                                parent_client->cl_net);
        if (error < 0)
                goto error;
@@ -1323,7 +1360,7 @@ int nfs4_update_server(struct nfs_server *server, const char *hostname,
        error = nfs4_set_client(server, hostname, sap, salen, buf,
                                clp->cl_proto, clnt->cl_timeout,
                                clp->cl_minorversion,
-                               clp->cl_nconnect, net);
+                               clp->cl_nconnect, clp->cl_max_connect, net);
        clear_bit(NFS_MIG_TSM_POSSIBLE, &server->mig_status);
        if (error != 0) {
                nfs_server_insert_lists(server);
index c820de58a661520aee268cebd55725f5761f32ba..c91565227ea2ab372aae379939bd918999b75d75 100644 (file)
@@ -158,13 +158,11 @@ static ssize_t __nfs4_copy_file_range(struct file *file_in, loff_t pos_in,
                sync = true;
 retry:
        if (!nfs42_files_from_same_server(file_in, file_out)) {
-               /* for inter copy, if copy size if smaller than 12 RPC
-                * payloads, fallback to traditional copy. There are
-                * 14 RPCs during an NFSv4.x mount between source/dest
-                * servers.
+               /*
+                * for inter copy, if copy size is too small
+                * then fallback to generic copy.
                 */
-               if (sync ||
-                       count <= 14 * NFS_SERVER(file_inode(file_in))->rsize)
+               if (sync)
                        return -EOPNOTSUPP;
                cn_resp = kzalloc(sizeof(struct nfs42_copy_notify_res),
                                GFP_NOFS);
index ef14ea0b6ab8dc7b331792c73278d6439fa399ba..7c9090a28e5c3d07247ff189349757706e88f784 100644 (file)
@@ -335,7 +335,7 @@ static bool pnfs_seqid_is_newer(u32 s1, u32 s2)
 
 static void pnfs_barrier_update(struct pnfs_layout_hdr *lo, u32 newseq)
 {
-       if (pnfs_seqid_is_newer(newseq, lo->plh_barrier))
+       if (pnfs_seqid_is_newer(newseq, lo->plh_barrier) || !lo->plh_barrier)
                lo->plh_barrier = newseq;
 }
 
@@ -347,11 +347,15 @@ pnfs_set_plh_return_info(struct pnfs_layout_hdr *lo, enum pnfs_iomode iomode,
                iomode = IOMODE_ANY;
        lo->plh_return_iomode = iomode;
        set_bit(NFS_LAYOUT_RETURN_REQUESTED, &lo->plh_flags);
-       if (seq != 0) {
-               WARN_ON_ONCE(lo->plh_return_seq != 0 && lo->plh_return_seq != seq);
+       /*
+        * We must set lo->plh_return_seq to avoid livelocks with
+        * pnfs_layout_need_return()
+        */
+       if (seq == 0)
+               seq = be32_to_cpu(lo->plh_stateid.seqid);
+       if (!lo->plh_return_seq || pnfs_seqid_is_newer(seq, lo->plh_return_seq))
                lo->plh_return_seq = seq;
-               pnfs_barrier_update(lo, seq);
-       }
+       pnfs_barrier_update(lo, seq);
 }
 
 static void
@@ -592,10 +596,6 @@ pnfs_put_lseg(struct pnfs_layout_segment *lseg)
        inode = lo->plh_inode;
 
        if (refcount_dec_and_lock(&lseg->pls_refcount, &inode->i_lock)) {
-               if (test_bit(NFS_LSEG_VALID, &lseg->pls_flags)) {
-                       spin_unlock(&inode->i_lock);
-                       return;
-               }
                pnfs_get_layout_hdr(lo);
                pnfs_layout_remove_lseg(lo, lseg);
                if (pnfs_cache_lseg_for_layoutreturn(lo, lseg))
@@ -1000,7 +1000,7 @@ pnfs_layout_stateid_blocked(const struct pnfs_layout_hdr *lo,
 {
        u32 seqid = be32_to_cpu(stateid->seqid);
 
-       return !pnfs_seqid_is_newer(seqid, lo->plh_barrier) && lo->plh_barrier;
+       return lo->plh_barrier && pnfs_seqid_is_newer(lo->plh_barrier, seqid);
 }
 
 /* lget is set to 1 if called from inside send_layoutget call chain */
index 9f39e0a1a38bd17de21ef5a675f3c4cae8a1df05..08d6cc57cbc37e6429d2c7c36e6b8dc0a76f2abf 100644 (file)
@@ -293,15 +293,19 @@ static int
 readpage_async_filler(void *data, struct page *page)
 {
        struct nfs_readdesc *desc = data;
+       struct inode *inode = page_file_mapping(page)->host;
+       unsigned int rsize = NFS_SERVER(inode)->rsize;
        struct nfs_page *new;
-       unsigned int len;
+       unsigned int len, aligned_len;
        int error;
 
        len = nfs_page_length(page);
        if (len == 0)
                return nfs_return_empty_page(page);
 
-       new = nfs_create_request(desc->ctx, page, 0, len);
+       aligned_len = min_t(unsigned int, ALIGN(len, rsize), PAGE_SIZE);
+
+       new = nfs_create_request(desc->ctx, page, 0, aligned_len);
        if (IS_ERR(new))
                goto out_error;
 
index fe58525cfed48388364bc04ea97119d79b6409bb..e65c83494c052758cf6e321647a2ee54ca0b8256 100644 (file)
@@ -480,6 +480,8 @@ static void nfs_show_mount_options(struct seq_file *m, struct nfs_server *nfss,
        if (clp->cl_nconnect > 0)
                seq_printf(m, ",nconnect=%u", clp->cl_nconnect);
        if (version == 4) {
+               if (clp->cl_max_connect > 1)
+                       seq_printf(m, ",max_connect=%u", clp->cl_max_connect);
                if (nfss->port != NFS_PORT)
                        seq_printf(m, ",port=%u", nfss->port);
        } else
index ce647459487220a2ec777fc08d9d6260de722f2c..b9a8b925db430da699c85366751c1bcc4b8adf3c 100644 (file)
 
 #include <linux/mempool.h>
 
+/*
+ * These are the default for number of transports to different server IPs
+ */
+#define NFS_MAX_TRANSPORTS 16
+
 /*
  * These are the default flags for swap requests
  */
index d71a0e90faebf2acbd9892f88fafac400c1a0ab6..2a9acbfe00f0f35e84e5a65d59b5eb25acae6150 100644 (file)
@@ -62,6 +62,7 @@ struct nfs_client {
 
        u32                     cl_minorversion;/* NFSv4 minorversion */
        unsigned int            cl_nconnect;    /* Number of connections */
+       unsigned int            cl_max_connect; /* max number of xprts allowed */
        const char *            cl_principal;  /* used for machine cred */
 
 #if IS_ENABLED(CONFIG_NFS_V4)
index 8b5d5c97553e88a38544e603d55fb10d4ed9defb..a4661646adc9c665ff0b9f5cceb5307ecb30a7d5 100644 (file)
@@ -14,6 +14,7 @@
 #include <linux/socket.h>
 #include <linux/in.h>
 #include <linux/in6.h>
+#include <linux/refcount.h>
 
 #include <linux/sunrpc/msg_prot.h>
 #include <linux/sunrpc/sched.h>
@@ -35,7 +36,7 @@ struct rpc_sysfs_client;
  * The high-level client handle
  */
 struct rpc_clnt {
-       atomic_t                cl_count;       /* Number of references */
+       refcount_t              cl_count;       /* Number of references */
        unsigned int            cl_clid;        /* client id */
        struct list_head        cl_clients;     /* Global list of clients */
        struct list_head        cl_tasks;       /* List of tasks */
@@ -81,6 +82,7 @@ struct rpc_clnt {
                struct work_struct      cl_work;
        };
        const struct cred       *cl_cred;
+       unsigned int            cl_max_connect; /* max number of transports not to the same IP */
 };
 
 /*
@@ -135,6 +137,7 @@ struct rpc_create_args {
        char                    *client_name;
        struct svc_xprt         *bc_xprt;       /* NFSv4.1 backchannel */
        const struct cred       *cred;
+       unsigned int            max_connect;
 };
 
 struct rpc_add_xprt_test {
index f0f846fa396e62bb3633b827130843030415d08b..064c96157d1f0b6a8444a233c9cd9469813eeaf7 100644 (file)
@@ -277,13 +277,13 @@ struct svc_rqst {
 #define        RQ_VICTIM       (5)                     /* about to be shut down */
 #define        RQ_BUSY         (6)                     /* request is busy */
 #define        RQ_DATA         (7)                     /* request has data */
-#define RQ_AUTHERR     (8)                     /* Request status is auth error */
        unsigned long           rq_flags;       /* flags field */
        ktime_t                 rq_qtime;       /* enqueue time */
 
        void *                  rq_argp;        /* decoded arguments */
        void *                  rq_resp;        /* xdr'd results */
        void *                  rq_auth_data;   /* flavor-specific data */
+       __be32                  rq_auth_stat;   /* authentication status */
        int                     rq_auth_slack;  /* extra space xdr code
                                                 * should leave in head
                                                 * for krb5i, krb5p.
@@ -537,7 +537,6 @@ unsigned int           svc_fill_write_vector(struct svc_rqst *rqstp,
 char             *svc_fill_symlink_pathname(struct svc_rqst *rqstp,
                                             struct kvec *first, void *p,
                                             size_t total);
-__be32            svc_return_autherr(struct svc_rqst *rqstp, __be32 auth_err);
 __be32            svc_generic_init_request(struct svc_rqst *rqstp,
                                            const struct svc_program *progp,
                                            struct svc_process_info *procinfo);
index b0003866a2497ead52a910c2502abedaf7ff21de..6d9cc9080aca7ca9abb68a830df9e5aa4fb83ca2 100644 (file)
@@ -127,7 +127,7 @@ struct auth_ops {
        char *  name;
        struct module *owner;
        int     flavour;
-       int     (*accept)(struct svc_rqst *rq, __be32 *authp);
+       int     (*accept)(struct svc_rqst *rq);
        int     (*release)(struct svc_rqst *rq);
        void    (*domain_release)(struct auth_domain *);
        int     (*set_client)(struct svc_rqst *rq);
@@ -149,7 +149,7 @@ struct auth_ops {
 
 struct svc_xprt;
 
-extern int     svc_authenticate(struct svc_rqst *rqstp, __be32 *authp);
+extern int     svc_authenticate(struct svc_rqst *rqstp);
 extern int     svc_authorise(struct svc_rqst *rqstp);
 extern int     svc_set_client(struct svc_rqst *rqstp);
 extern int     svc_auth_register(rpc_authflavor_t flavor, struct auth_ops *aops);
index b15c1f07162d0975188bb394885f9b84084b498b..955ea4d7af0b2fea1300a46fad963df35f25810c 100644 (file)
@@ -431,6 +431,7 @@ void                        xprt_release_write(struct rpc_xprt *, struct rpc_task *);
 #define XPRT_CONGESTED         (9)
 #define XPRT_CWND_WAIT         (10)
 #define XPRT_WRITE_SPACE       (11)
+#define XPRT_SND_IS_COOKIE     (12)
 
 static inline void xprt_set_connected(struct rpc_xprt *xprt)
 {
index b19addc8b7159b099fc73f536cf751ae6c5e31ee..bbb8a5fa08163a3ace88e0b23c384075d99117ac 100644 (file)
@@ -18,6 +18,7 @@ struct rpc_xprt_switch {
        unsigned int            xps_id;
        unsigned int            xps_nxprts;
        unsigned int            xps_nactive;
+       unsigned int            xps_nunique_destaddr_xprts;
        atomic_long_t           xps_queuelen;
        struct list_head        xps_xprt_list;
 
index bd55908c1bef9557c0c6915765bafc1da6e93be8..de41954995926de1ff021f7d16ffecd174779ddf 100644 (file)
@@ -793,6 +793,39 @@ TRACE_EVENT(xprtrdma_post_send,
        )
 );
 
+TRACE_EVENT(xprtrdma_post_send_err,
+       TP_PROTO(
+               const struct rpcrdma_xprt *r_xprt,
+               const struct rpcrdma_req *req,
+               int rc
+       ),
+
+       TP_ARGS(r_xprt, req, rc),
+
+       TP_STRUCT__entry(
+               __field(u32, cq_id)
+               __field(unsigned int, task_id)
+               __field(unsigned int, client_id)
+               __field(int, rc)
+       ),
+
+       TP_fast_assign(
+               const struct rpc_rqst *rqst = &req->rl_slot;
+               const struct rpcrdma_ep *ep = r_xprt->rx_ep;
+
+               __entry->cq_id = ep ? ep->re_attr.recv_cq->res.id : 0;
+               __entry->task_id = rqst->rq_task->tk_pid;
+               __entry->client_id = rqst->rq_task->tk_client ?
+                                    rqst->rq_task->tk_client->cl_clid : -1;
+               __entry->rc = rc;
+       ),
+
+       TP_printk("task:%u@%u cq.id=%u rc=%d",
+               __entry->task_id, __entry->client_id,
+               __entry->cq_id, __entry->rc
+       )
+);
+
 TRACE_EVENT(xprtrdma_post_recv,
        TP_PROTO(
                const struct rpcrdma_rep *rep
@@ -818,16 +851,14 @@ TRACE_EVENT(xprtrdma_post_recv,
 TRACE_EVENT(xprtrdma_post_recvs,
        TP_PROTO(
                const struct rpcrdma_xprt *r_xprt,
-               unsigned int count,
-               int status
+               unsigned int count
        ),
 
-       TP_ARGS(r_xprt, count, status),
+       TP_ARGS(r_xprt, count),
 
        TP_STRUCT__entry(
                __field(u32, cq_id)
                __field(unsigned int, count)
-               __field(int, status)
                __field(int, posted)
                __string(addr, rpcrdma_addrstr(r_xprt))
                __string(port, rpcrdma_portstr(r_xprt))
@@ -838,15 +869,44 @@ TRACE_EVENT(xprtrdma_post_recvs,
 
                __entry->cq_id = ep->re_attr.recv_cq->res.id;
                __entry->count = count;
-               __entry->status = status;
                __entry->posted = ep->re_receive_count;
                __assign_str(addr, rpcrdma_addrstr(r_xprt));
                __assign_str(port, rpcrdma_portstr(r_xprt));
        ),
 
-       TP_printk("peer=[%s]:%s cq.id=%d %u new recvs, %d active (rc %d)",
+       TP_printk("peer=[%s]:%s cq.id=%d %u new recvs, %d active",
+               __get_str(addr), __get_str(port), __entry->cq_id,
+               __entry->count, __entry->posted
+       )
+);
+
+TRACE_EVENT(xprtrdma_post_recvs_err,
+       TP_PROTO(
+               const struct rpcrdma_xprt *r_xprt,
+               int status
+       ),
+
+       TP_ARGS(r_xprt, status),
+
+       TP_STRUCT__entry(
+               __field(u32, cq_id)
+               __field(int, status)
+               __string(addr, rpcrdma_addrstr(r_xprt))
+               __string(port, rpcrdma_portstr(r_xprt))
+       ),
+
+       TP_fast_assign(
+               const struct rpcrdma_ep *ep = r_xprt->rx_ep;
+
+               __entry->cq_id = ep->re_attr.recv_cq->res.id;
+               __entry->status = status;
+               __assign_str(addr, rpcrdma_addrstr(r_xprt));
+               __assign_str(port, rpcrdma_portstr(r_xprt));
+       ),
+
+       TP_printk("peer=[%s]:%s cq.id=%d rc=%d",
                __get_str(addr), __get_str(port), __entry->cq_id,
-               __entry->count, __entry->posted, __entry->status
+               __entry->status
        )
 );
 
index d323f5a049c885a56669954a419f112cf8915f78..2d04eb96d41838bbc57613b73816bee92a4028d5 100644 (file)
@@ -295,25 +295,11 @@ TRACE_EVENT(rpc_request,
                )
 );
 
-TRACE_DEFINE_ENUM(RPC_TASK_ASYNC);
-TRACE_DEFINE_ENUM(RPC_TASK_SWAPPER);
-TRACE_DEFINE_ENUM(RPC_TASK_NULLCREDS);
-TRACE_DEFINE_ENUM(RPC_CALL_MAJORSEEN);
-TRACE_DEFINE_ENUM(RPC_TASK_ROOTCREDS);
-TRACE_DEFINE_ENUM(RPC_TASK_DYNAMIC);
-TRACE_DEFINE_ENUM(RPC_TASK_NO_ROUND_ROBIN);
-TRACE_DEFINE_ENUM(RPC_TASK_SOFT);
-TRACE_DEFINE_ENUM(RPC_TASK_SOFTCONN);
-TRACE_DEFINE_ENUM(RPC_TASK_SENT);
-TRACE_DEFINE_ENUM(RPC_TASK_TIMEOUT);
-TRACE_DEFINE_ENUM(RPC_TASK_NOCONNECT);
-TRACE_DEFINE_ENUM(RPC_TASK_NO_RETRANS_TIMEOUT);
-TRACE_DEFINE_ENUM(RPC_TASK_CRED_NOREF);
-
 #define rpc_show_task_flags(flags)                                     \
        __print_flags(flags, "|",                                       \
                { RPC_TASK_ASYNC, "ASYNC" },                            \
                { RPC_TASK_SWAPPER, "SWAPPER" },                        \
+               { RPC_TASK_MOVEABLE, "MOVEABLE" },                      \
                { RPC_TASK_NULLCREDS, "NULLCREDS" },                    \
                { RPC_CALL_MAJORSEEN, "MAJORSEEN" },                    \
                { RPC_TASK_ROOTCREDS, "ROOTCREDS" },                    \
@@ -327,14 +313,6 @@ TRACE_DEFINE_ENUM(RPC_TASK_CRED_NOREF);
                { RPC_TASK_NO_RETRANS_TIMEOUT, "NORTO" },               \
                { RPC_TASK_CRED_NOREF, "CRED_NOREF" })
 
-TRACE_DEFINE_ENUM(RPC_TASK_RUNNING);
-TRACE_DEFINE_ENUM(RPC_TASK_QUEUED);
-TRACE_DEFINE_ENUM(RPC_TASK_ACTIVE);
-TRACE_DEFINE_ENUM(RPC_TASK_NEED_XMIT);
-TRACE_DEFINE_ENUM(RPC_TASK_NEED_RECV);
-TRACE_DEFINE_ENUM(RPC_TASK_MSG_PIN_WAIT);
-TRACE_DEFINE_ENUM(RPC_TASK_SIGNALLED);
-
 #define rpc_show_runstate(flags)                                       \
        __print_flags(flags, "|",                                       \
                { (1UL << RPC_TASK_RUNNING), "RUNNING" },               \
@@ -945,17 +923,6 @@ TRACE_EVENT(rpc_socket_nospace,
        )
 );
 
-TRACE_DEFINE_ENUM(XPRT_LOCKED);
-TRACE_DEFINE_ENUM(XPRT_CONNECTED);
-TRACE_DEFINE_ENUM(XPRT_CONNECTING);
-TRACE_DEFINE_ENUM(XPRT_CLOSE_WAIT);
-TRACE_DEFINE_ENUM(XPRT_BOUND);
-TRACE_DEFINE_ENUM(XPRT_BINDING);
-TRACE_DEFINE_ENUM(XPRT_CLOSING);
-TRACE_DEFINE_ENUM(XPRT_CONGESTED);
-TRACE_DEFINE_ENUM(XPRT_CWND_WAIT);
-TRACE_DEFINE_ENUM(XPRT_WRITE_SPACE);
-
 #define rpc_show_xprt_state(x)                                         \
        __print_flags(x, "|",                                           \
                { (1UL << XPRT_LOCKED),         "LOCKED"},              \
@@ -965,6 +932,8 @@ TRACE_DEFINE_ENUM(XPRT_WRITE_SPACE);
                { (1UL << XPRT_BOUND),          "BOUND"},               \
                { (1UL << XPRT_BINDING),        "BINDING"},             \
                { (1UL << XPRT_CLOSING),        "CLOSING"},             \
+               { (1UL << XPRT_OFFLINE),        "OFFLINE"},             \
+               { (1UL << XPRT_REMOVE),         "REMOVE"},              \
                { (1UL << XPRT_CONGESTED),      "CONGESTED"},           \
                { (1UL << XPRT_CWND_WAIT),      "CWND_WAIT"},           \
                { (1UL << XPRT_WRITE_SPACE),    "WRITE_SPACE"})
@@ -1092,10 +1061,10 @@ TRACE_EVENT(xprt_retransmit,
                __field(u32, xid)
                __field(int, ntrans)
                __field(int, version)
+               __field(unsigned long, timeout)
                __string(progname,
                         rqst->rq_task->tk_client->cl_program->name)
-               __string(procedure,
-                        rqst->rq_task->tk_msg.rpc_proc->p_name)
+               __string(procname, rpc_proc_name(rqst->rq_task))
        ),
 
        TP_fast_assign(
@@ -1106,17 +1075,19 @@ TRACE_EVENT(xprt_retransmit,
                        task->tk_client->cl_clid : -1;
                __entry->xid = be32_to_cpu(rqst->rq_xid);
                __entry->ntrans = rqst->rq_ntrans;
+               __entry->timeout = task->tk_timeout;
                __assign_str(progname,
                             task->tk_client->cl_program->name);
                __entry->version = task->tk_client->cl_vers;
-               __assign_str(procedure, task->tk_msg.rpc_proc->p_name);
+               __assign_str(procname, rpc_proc_name(task));
        ),
 
        TP_printk(
-               "task:%u@%u xid=0x%08x %sv%d %s ntrans=%d",
+               "task:%u@%u xid=0x%08x %sv%d %s ntrans=%d timeout=%lu",
                __entry->task_id, __entry->client_id, __entry->xid,
-               __get_str(progname), __entry->version, __get_str(procedure),
-               __entry->ntrans)
+               __get_str(progname), __entry->version, __get_str(procname),
+               __entry->ntrans, __entry->timeout
+       )
 );
 
 TRACE_EVENT(xprt_ping,
@@ -1568,8 +1539,7 @@ DEFINE_SVCXDRBUF_EVENT(sendto);
        svc_rqst_flag(SPLICE_OK)                                        \
        svc_rqst_flag(VICTIM)                                           \
        svc_rqst_flag(BUSY)                                             \
-       svc_rqst_flag(DATA)                                             \
-       svc_rqst_flag_end(AUTHERR)
+       svc_rqst_flag_end(DATA)
 
 #undef svc_rqst_flag
 #undef svc_rqst_flag_end
@@ -1611,9 +1581,9 @@ TRACE_DEFINE_ENUM(SVC_COMPLETE);
                { SVC_COMPLETE, "SVC_COMPLETE" })
 
 TRACE_EVENT(svc_authenticate,
-       TP_PROTO(const struct svc_rqst *rqst, int auth_res, __be32 auth_stat),
+       TP_PROTO(const struct svc_rqst *rqst, int auth_res),
 
-       TP_ARGS(rqst, auth_res, auth_stat),
+       TP_ARGS(rqst, auth_res),
 
        TP_STRUCT__entry(
                __field(u32, xid)
@@ -1624,7 +1594,7 @@ TRACE_EVENT(svc_authenticate,
        TP_fast_assign(
                __entry->xid = be32_to_cpu(rqst->rq_xid);
                __entry->svc_status = auth_res;
-               __entry->auth_stat = be32_to_cpu(auth_stat);
+               __entry->auth_stat = be32_to_cpu(rqst->rq_auth_stat);
        ),
 
        TP_printk("xid=0x%08x auth_res=%s auth_stat=%s",
index d1c003a25b0fe9167e8a1e04e192ee1f9c2790c8..61c276bddaf2531c20afa9eb83261dc25c89690a 100644 (file)
@@ -160,7 +160,7 @@ static struct rpc_clnt *get_gssp_clnt(struct sunrpc_net *sn)
        mutex_lock(&sn->gssp_lock);
        clnt = sn->gssp_clnt;
        if (clnt)
-               atomic_inc(&clnt->cl_count);
+               refcount_inc(&clnt->cl_count);
        mutex_unlock(&sn->gssp_lock);
        return clnt;
 }
index 3d685fe328fad0c69f009b1a8b8095e336782271..9de41e7f2d0738ec09d57566226fc6127d688f31 100644 (file)
@@ -707,11 +707,11 @@ svc_safe_putnetobj(struct kvec *resv, struct xdr_netobj *o)
 /*
  * Verify the checksum on the header and return SVC_OK on success.
  * Otherwise, return SVC_DROP (in the case of a bad sequence number)
- * or return SVC_DENIED and indicate error in authp.
+ * or return SVC_DENIED and indicate error in rqstp->rq_auth_stat.
  */
 static int
 gss_verify_header(struct svc_rqst *rqstp, struct rsc *rsci,
-                 __be32 *rpcstart, struct rpc_gss_wire_cred *gc, __be32 *authp)
+                 __be32 *rpcstart, struct rpc_gss_wire_cred *gc)
 {
        struct gss_ctx          *ctx_id = rsci->mechctx;
        struct xdr_buf          rpchdr;
@@ -725,7 +725,7 @@ gss_verify_header(struct svc_rqst *rqstp, struct rsc *rsci,
        iov.iov_len = (u8 *)argv->iov_base - (u8 *)rpcstart;
        xdr_buf_from_iov(&iov, &rpchdr);
 
-       *authp = rpc_autherr_badverf;
+       rqstp->rq_auth_stat = rpc_autherr_badverf;
        if (argv->iov_len < 4)
                return SVC_DENIED;
        flavor = svc_getnl(argv);
@@ -737,13 +737,13 @@ gss_verify_header(struct svc_rqst *rqstp, struct rsc *rsci,
        if (rqstp->rq_deferred) /* skip verification of revisited request */
                return SVC_OK;
        if (gss_verify_mic(ctx_id, &rpchdr, &checksum) != GSS_S_COMPLETE) {
-               *authp = rpcsec_gsserr_credproblem;
+               rqstp->rq_auth_stat = rpcsec_gsserr_credproblem;
                return SVC_DENIED;
        }
 
        if (gc->gc_seq > MAXSEQ) {
                trace_rpcgss_svc_seqno_large(rqstp, gc->gc_seq);
-               *authp = rpcsec_gsserr_ctxproblem;
+               rqstp->rq_auth_stat = rpcsec_gsserr_ctxproblem;
                return SVC_DENIED;
        }
        if (!gss_check_seq_num(rqstp, rsci, gc->gc_seq))
@@ -1038,6 +1038,8 @@ svcauth_gss_set_client(struct svc_rqst *rqstp)
        struct rpc_gss_wire_cred *gc = &svcdata->clcred;
        int stat;
 
+       rqstp->rq_auth_stat = rpc_autherr_badcred;
+
        /*
         * A gss export can be specified either by:
         *      export  *(sec=krb5,rw)
@@ -1053,6 +1055,8 @@ svcauth_gss_set_client(struct svc_rqst *rqstp)
        stat = svcauth_unix_set_client(rqstp);
        if (stat == SVC_DROP || stat == SVC_CLOSE)
                return stat;
+
+       rqstp->rq_auth_stat = rpc_auth_ok;
        return SVC_OK;
 }
 
@@ -1142,7 +1146,7 @@ static void gss_free_in_token_pages(struct gssp_in_token *in_token)
 }
 
 static int gss_read_proxy_verf(struct svc_rqst *rqstp,
-                              struct rpc_gss_wire_cred *gc, __be32 *authp,
+                              struct rpc_gss_wire_cred *gc,
                               struct xdr_netobj *in_handle,
                               struct gssp_in_token *in_token)
 {
@@ -1151,7 +1155,7 @@ static int gss_read_proxy_verf(struct svc_rqst *rqstp,
        int pages, i, res, pgto, pgfrom;
        size_t inlen, to_offs, from_offs;
 
-       res = gss_read_common_verf(gc, argv, authp, in_handle);
+       res = gss_read_common_verf(gc, argv, &rqstp->rq_auth_stat, in_handle);
        if (res)
                return res;
 
@@ -1227,7 +1231,7 @@ gss_write_resv(struct kvec *resv, size_t size_limit,
  * Otherwise, drop the request pending an answer to the upcall.
  */
 static int svcauth_gss_legacy_init(struct svc_rqst *rqstp,
-                       struct rpc_gss_wire_cred *gc, __be32 *authp)
+                                  struct rpc_gss_wire_cred *gc)
 {
        struct kvec *argv = &rqstp->rq_arg.head[0];
        struct kvec *resv = &rqstp->rq_res.head[0];
@@ -1236,7 +1240,7 @@ static int svcauth_gss_legacy_init(struct svc_rqst *rqstp,
        struct sunrpc_net *sn = net_generic(SVC_NET(rqstp), sunrpc_net_id);
 
        memset(&rsikey, 0, sizeof(rsikey));
-       ret = gss_read_verf(gc, argv, authp,
+       ret = gss_read_verf(gc, argv, &rqstp->rq_auth_stat,
                            &rsikey.in_handle, &rsikey.in_token);
        if (ret)
                return ret;
@@ -1339,7 +1343,7 @@ out:
 }
 
 static int svcauth_gss_proxy_init(struct svc_rqst *rqstp,
-                       struct rpc_gss_wire_cred *gc, __be32 *authp)
+                                 struct rpc_gss_wire_cred *gc)
 {
        struct kvec *resv = &rqstp->rq_res.head[0];
        struct xdr_netobj cli_handle;
@@ -1351,8 +1355,7 @@ static int svcauth_gss_proxy_init(struct svc_rqst *rqstp,
        struct sunrpc_net *sn = net_generic(net, sunrpc_net_id);
 
        memset(&ud, 0, sizeof(ud));
-       ret = gss_read_proxy_verf(rqstp, gc, authp,
-                                 &ud.in_handle, &ud.in_token);
+       ret = gss_read_proxy_verf(rqstp, gc, &ud.in_handle, &ud.in_token);
        if (ret)
                return ret;
 
@@ -1525,7 +1528,7 @@ static void destroy_use_gss_proxy_proc_entry(struct net *net) {}
  * response here and return SVC_COMPLETE.
  */
 static int
-svcauth_gss_accept(struct svc_rqst *rqstp, __be32 *authp)
+svcauth_gss_accept(struct svc_rqst *rqstp)
 {
        struct kvec     *argv = &rqstp->rq_arg.head[0];
        struct kvec     *resv = &rqstp->rq_res.head[0];
@@ -1538,7 +1541,7 @@ svcauth_gss_accept(struct svc_rqst *rqstp, __be32 *authp)
        int             ret;
        struct sunrpc_net *sn = net_generic(SVC_NET(rqstp), sunrpc_net_id);
 
-       *authp = rpc_autherr_badcred;
+       rqstp->rq_auth_stat = rpc_autherr_badcred;
        if (!svcdata)
                svcdata = kmalloc(sizeof(*svcdata), GFP_KERNEL);
        if (!svcdata)
@@ -1575,22 +1578,22 @@ svcauth_gss_accept(struct svc_rqst *rqstp, __be32 *authp)
        if ((gc->gc_proc != RPC_GSS_PROC_DATA) && (rqstp->rq_proc != 0))
                goto auth_err;
 
-       *authp = rpc_autherr_badverf;
+       rqstp->rq_auth_stat = rpc_autherr_badverf;
        switch (gc->gc_proc) {
        case RPC_GSS_PROC_INIT:
        case RPC_GSS_PROC_CONTINUE_INIT:
                if (use_gss_proxy(SVC_NET(rqstp)))
-                       return svcauth_gss_proxy_init(rqstp, gc, authp);
+                       return svcauth_gss_proxy_init(rqstp, gc);
                else
-                       return svcauth_gss_legacy_init(rqstp, gc, authp);
+                       return svcauth_gss_legacy_init(rqstp, gc);
        case RPC_GSS_PROC_DATA:
        case RPC_GSS_PROC_DESTROY:
                /* Look up the context, and check the verifier: */
-               *authp = rpcsec_gsserr_credproblem;
+               rqstp->rq_auth_stat = rpcsec_gsserr_credproblem;
                rsci = gss_svc_searchbyctx(sn->rsc_cache, &gc->gc_ctx);
                if (!rsci)
                        goto auth_err;
-               switch (gss_verify_header(rqstp, rsci, rpcstart, gc, authp)) {
+               switch (gss_verify_header(rqstp, rsci, rpcstart, gc)) {
                case SVC_OK:
                        break;
                case SVC_DENIED:
@@ -1600,7 +1603,7 @@ svcauth_gss_accept(struct svc_rqst *rqstp, __be32 *authp)
                }
                break;
        default:
-               *authp = rpc_autherr_rejectedcred;
+               rqstp->rq_auth_stat = rpc_autherr_rejectedcred;
                goto auth_err;
        }
 
@@ -1616,13 +1619,13 @@ svcauth_gss_accept(struct svc_rqst *rqstp, __be32 *authp)
                svc_putnl(resv, RPC_SUCCESS);
                goto complete;
        case RPC_GSS_PROC_DATA:
-               *authp = rpcsec_gsserr_ctxproblem;
+               rqstp->rq_auth_stat = rpcsec_gsserr_ctxproblem;
                svcdata->verf_start = resv->iov_base + resv->iov_len;
                if (gss_write_verf(rqstp, rsci->mechctx, gc->gc_seq))
                        goto auth_err;
                rqstp->rq_cred = rsci->cred;
                get_group_info(rsci->cred.cr_group_info);
-               *authp = rpc_autherr_badcred;
+               rqstp->rq_auth_stat = rpc_autherr_badcred;
                switch (gc->gc_svc) {
                case RPC_GSS_SVC_NONE:
                        break;
index 8b4de70e8ead40aa8a4dfb005a0af074e5c74ae0..f056ff93144427da8f9dcf5c74da2629b1f66b0a 100644 (file)
@@ -167,7 +167,7 @@ static int rpc_clnt_skip_event(struct rpc_clnt *clnt, unsigned long event)
        case RPC_PIPEFS_MOUNT:
                if (clnt->cl_pipedir_objects.pdh_dentry != NULL)
                        return 1;
-               if (atomic_read(&clnt->cl_count) == 0)
+               if (refcount_read(&clnt->cl_count) == 0)
                        return 1;
                break;
        case RPC_PIPEFS_UMOUNT:
@@ -419,7 +419,7 @@ static struct rpc_clnt * rpc_new_client(const struct rpc_create_args *args,
        clnt->cl_rtt = &clnt->cl_rtt_default;
        rpc_init_rtt(&clnt->cl_rtt_default, clnt->cl_timeout->to_initval);
 
-       atomic_set(&clnt->cl_count, 1);
+       refcount_set(&clnt->cl_count, 1);
 
        if (nodename == NULL)
                nodename = utsname()->nodename;
@@ -431,7 +431,7 @@ static struct rpc_clnt * rpc_new_client(const struct rpc_create_args *args,
        if (err)
                goto out_no_path;
        if (parent)
-               atomic_inc(&parent->cl_count);
+               refcount_inc(&parent->cl_count);
 
        trace_rpc_clnt_new(clnt, xprt, program->name, args->servername);
        return clnt;
@@ -918,18 +918,16 @@ rpc_free_client(struct rpc_clnt *clnt)
 static struct rpc_clnt *
 rpc_free_auth(struct rpc_clnt *clnt)
 {
-       if (clnt->cl_auth == NULL)
-               return rpc_free_client(clnt);
-
        /*
         * Note: RPCSEC_GSS may need to send NULL RPC calls in order to
         *       release remaining GSS contexts. This mechanism ensures
         *       that it can do so safely.
         */
-       atomic_inc(&clnt->cl_count);
-       rpcauth_release(clnt->cl_auth);
-       clnt->cl_auth = NULL;
-       if (atomic_dec_and_test(&clnt->cl_count))
+       if (clnt->cl_auth != NULL) {
+               rpcauth_release(clnt->cl_auth);
+               clnt->cl_auth = NULL;
+       }
+       if (refcount_dec_and_test(&clnt->cl_count))
                return rpc_free_client(clnt);
        return NULL;
 }
@@ -943,7 +941,7 @@ rpc_release_client(struct rpc_clnt *clnt)
        do {
                if (list_empty(&clnt->cl_tasks))
                        wake_up(&destroy_wait);
-               if (!atomic_dec_and_test(&clnt->cl_count))
+               if (refcount_dec_not_one(&clnt->cl_count))
                        break;
                clnt = rpc_free_auth(clnt);
        } while (clnt != NULL);
@@ -1082,7 +1080,7 @@ void rpc_task_set_client(struct rpc_task *task, struct rpc_clnt *clnt)
        if (clnt != NULL) {
                rpc_task_set_transport(task, clnt);
                task->tk_client = clnt;
-               atomic_inc(&clnt->cl_count);
+               refcount_inc(&clnt->cl_count);
                if (clnt->cl_softrtry)
                        task->tk_flags |= RPC_TASK_SOFT;
                if (clnt->cl_softerr)
@@ -2694,17 +2692,18 @@ static const struct rpc_procinfo rpcproc_null = {
        .p_decode = rpcproc_decode_null,
 };
 
-static int rpc_ping(struct rpc_clnt *clnt)
+static void
+rpc_null_call_prepare(struct rpc_task *task, void *data)
 {
-       struct rpc_message msg = {
-               .rpc_proc = &rpcproc_null,
-       };
-       int err;
-       err = rpc_call_sync(clnt, &msg, RPC_TASK_SOFT | RPC_TASK_SOFTCONN |
-                           RPC_TASK_NULLCREDS);
-       return err;
+       task->tk_flags &= ~RPC_TASK_NO_RETRANS_TIMEOUT;
+       rpc_call_start(task);
 }
 
+static const struct rpc_call_ops rpc_null_ops = {
+       .rpc_call_prepare = rpc_null_call_prepare,
+       .rpc_call_done = rpc_default_callback,
+};
+
 static
 struct rpc_task *rpc_call_null_helper(struct rpc_clnt *clnt,
                struct rpc_xprt *xprt, struct rpc_cred *cred, int flags,
@@ -2718,7 +2717,7 @@ struct rpc_task *rpc_call_null_helper(struct rpc_clnt *clnt,
                .rpc_xprt = xprt,
                .rpc_message = &msg,
                .rpc_op_cred = cred,
-               .callback_ops = (ops != NULL) ? ops : &rpc_default_ops,
+               .callback_ops = ops ?: &rpc_null_ops,
                .callback_data = data,
                .flags = flags | RPC_TASK_SOFT | RPC_TASK_SOFTCONN |
                         RPC_TASK_NULLCREDS,
@@ -2733,6 +2732,19 @@ struct rpc_task *rpc_call_null(struct rpc_clnt *clnt, struct rpc_cred *cred, int
 }
 EXPORT_SYMBOL_GPL(rpc_call_null);
 
+static int rpc_ping(struct rpc_clnt *clnt)
+{
+       struct rpc_task *task;
+       int status;
+
+       task = rpc_call_null_helper(clnt, NULL, NULL, 0, NULL, NULL);
+       if (IS_ERR(task))
+               return PTR_ERR(task);
+       status = task->tk_status;
+       rpc_put_task(task);
+       return status;
+}
+
 struct rpc_cb_add_xprt_calldata {
        struct rpc_xprt_switch *xps;
        struct rpc_xprt *xprt;
@@ -2756,6 +2768,7 @@ static void rpc_cb_add_xprt_release(void *calldata)
 }
 
 static const struct rpc_call_ops rpc_cb_add_xprt_call_ops = {
+       .rpc_call_prepare = rpc_null_call_prepare,
        .rpc_call_done = rpc_cb_add_xprt_done,
        .rpc_release = rpc_cb_add_xprt_release,
 };
@@ -2774,6 +2787,15 @@ int rpc_clnt_test_and_add_xprt(struct rpc_clnt *clnt,
        struct rpc_cb_add_xprt_calldata *data;
        struct rpc_task *task;
 
+       if (xps->xps_nunique_destaddr_xprts + 1 > clnt->cl_max_connect) {
+               rcu_read_lock();
+               pr_warn("SUNRPC: reached max allowed number (%d) did not add "
+                       "transport to server: %s\n", clnt->cl_max_connect,
+                       rpc_peeraddr2str(clnt, RPC_DISPLAY_ADDR));
+               rcu_read_unlock();
+               return -EINVAL;
+       }
+
        data = kmalloc(sizeof(*data), GFP_NOFS);
        if (!data)
                return -ENOMEM;
@@ -2786,7 +2808,7 @@ int rpc_clnt_test_and_add_xprt(struct rpc_clnt *clnt,
 
        task = rpc_call_null_helper(clnt, xprt, NULL, RPC_TASK_ASYNC,
                        &rpc_cb_add_xprt_call_ops, data);
-
+       data->xps->xps_nunique_destaddr_xprts++;
        rpc_put_task(task);
 success:
        return 1;
index 827bf3a2817888f022f6d0fe75bd74e7458f19f1..7dc9cc929bfd7185b1c73bd766f02cb34c80b64b 100644 (file)
@@ -90,7 +90,7 @@ static int tasks_open(struct inode *inode, struct file *filp)
                struct seq_file *seq = filp->private_data;
                struct rpc_clnt *clnt = seq->private = inode->i_private;
 
-               if (!atomic_inc_not_zero(&clnt->cl_count)) {
+               if (!refcount_inc_not_zero(&clnt->cl_count)) {
                        seq_release(inode, filp);
                        ret = -EINVAL;
                }
index 09c000d490a1dbff7f827d15c8a11d7e4fff1c66..ee5336d73fddc5965753afef1f41ac6a153b30cb 100644 (file)
@@ -423,7 +423,7 @@ rpc_info_open(struct inode *inode, struct file *file)
                spin_lock(&file->f_path.dentry->d_lock);
                if (!d_unhashed(file->f_path.dentry))
                        clnt = RPC_I(inode)->private;
-               if (clnt != NULL && atomic_inc_not_zero(&clnt->cl_count)) {
+               if (clnt != NULL && refcount_inc_not_zero(&clnt->cl_count)) {
                        spin_unlock(&file->f_path.dentry->d_lock);
                        m->private = clnt;
                } else {
index bfcbaf7b3822fbdcf5e5138938bcf44210ac5b0d..a3bbe5ce4570fb7d7cdefd7bc8c24cff00d3f5c0 100644 (file)
@@ -1186,22 +1186,6 @@ void svc_printk(struct svc_rqst *rqstp, const char *fmt, ...)
 static __printf(2,3) void svc_printk(struct svc_rqst *rqstp, const char *fmt, ...) {}
 #endif
 
-__be32
-svc_return_autherr(struct svc_rqst *rqstp, __be32 auth_err)
-{
-       set_bit(RQ_AUTHERR, &rqstp->rq_flags);
-       return auth_err;
-}
-EXPORT_SYMBOL_GPL(svc_return_autherr);
-
-static __be32
-svc_get_autherr(struct svc_rqst *rqstp, __be32 *statp)
-{
-       if (test_and_clear_bit(RQ_AUTHERR, &rqstp->rq_flags))
-               return *statp;
-       return rpc_auth_ok;
-}
-
 static int
 svc_generic_dispatch(struct svc_rqst *rqstp, __be32 *statp)
 {
@@ -1225,7 +1209,7 @@ svc_generic_dispatch(struct svc_rqst *rqstp, __be32 *statp)
            test_bit(RQ_DROPME, &rqstp->rq_flags))
                return 0;
 
-       if (test_bit(RQ_AUTHERR, &rqstp->rq_flags))
+       if (rqstp->rq_auth_stat != rpc_auth_ok)
                return 1;
 
        if (*statp != rpc_success)
@@ -1306,7 +1290,7 @@ svc_process_common(struct svc_rqst *rqstp, struct kvec *argv, struct kvec *resv)
        struct svc_process_info process;
        __be32                  *statp;
        u32                     prog, vers;
-       __be32                  auth_stat, rpc_stat;
+       __be32                  rpc_stat;
        int                     auth_res;
        __be32                  *reply_statp;
 
@@ -1349,14 +1333,12 @@ svc_process_common(struct svc_rqst *rqstp, struct kvec *argv, struct kvec *resv)
         * We do this before anything else in order to get a decent
         * auth verifier.
         */
-       auth_res = svc_authenticate(rqstp, &auth_stat);
+       auth_res = svc_authenticate(rqstp);
        /* Also give the program a chance to reject this call: */
-       if (auth_res == SVC_OK && progp) {
-               auth_stat = rpc_autherr_badcred;
+       if (auth_res == SVC_OK && progp)
                auth_res = progp->pg_authenticate(rqstp);
-       }
        if (auth_res != SVC_OK)
-               trace_svc_authenticate(rqstp, auth_res, auth_stat);
+               trace_svc_authenticate(rqstp, auth_res);
        switch (auth_res) {
        case SVC_OK:
                break;
@@ -1415,15 +1397,15 @@ svc_process_common(struct svc_rqst *rqstp, struct kvec *argv, struct kvec *resv)
                        goto release_dropit;
                if (*statp == rpc_garbage_args)
                        goto err_garbage;
-               auth_stat = svc_get_autherr(rqstp, statp);
-               if (auth_stat != rpc_auth_ok)
-                       goto err_release_bad_auth;
        } else {
                dprintk("svc: calling dispatcher\n");
                if (!process.dispatch(rqstp, statp))
                        goto release_dropit; /* Release reply info */
        }
 
+       if (rqstp->rq_auth_stat != rpc_auth_ok)
+               goto err_release_bad_auth;
+
        /* Check RPC status result */
        if (*statp != rpc_success)
                resv->iov_len = ((void*)statp)  - resv->iov_base + 4;
@@ -1473,13 +1455,14 @@ err_release_bad_auth:
        if (procp->pc_release)
                procp->pc_release(rqstp);
 err_bad_auth:
-       dprintk("svc: authentication failed (%d)\n", ntohl(auth_stat));
+       dprintk("svc: authentication failed (%d)\n",
+               be32_to_cpu(rqstp->rq_auth_stat));
        serv->sv_stats->rpcbadauth++;
        /* Restore write pointer to location of accept status: */
        xdr_ressize_check(rqstp, reply_statp);
        svc_putnl(resv, 1);     /* REJECT */
        svc_putnl(resv, 1);     /* AUTH_ERROR */
-       svc_putnl(resv, ntohl(auth_stat));      /* status */
+       svc_putu32(resv, rqstp->rq_auth_stat);  /* status */
        goto sendit;
 
 err_bad_prog:
index 998b196b6176744af28f54f4219b56ffd1713e3e..5a8b8e03fdd42b14e38a4fd561f8076589845d15 100644 (file)
@@ -59,12 +59,12 @@ svc_put_auth_ops(struct auth_ops *aops)
 }
 
 int
-svc_authenticate(struct svc_rqst *rqstp, __be32 *authp)
+svc_authenticate(struct svc_rqst *rqstp)
 {
        rpc_authflavor_t        flavor;
        struct auth_ops         *aops;
 
-       *authp = rpc_auth_ok;
+       rqstp->rq_auth_stat = rpc_auth_ok;
 
        flavor = svc_getnl(&rqstp->rq_arg.head[0]);
 
@@ -72,7 +72,7 @@ svc_authenticate(struct svc_rqst *rqstp, __be32 *authp)
 
        aops = svc_get_auth_ops(flavor);
        if (aops == NULL) {
-               *authp = rpc_autherr_badcred;
+               rqstp->rq_auth_stat = rpc_autherr_badcred;
                return SVC_DENIED;
        }
 
@@ -80,7 +80,7 @@ svc_authenticate(struct svc_rqst *rqstp, __be32 *authp)
        init_svc_cred(&rqstp->rq_cred);
 
        rqstp->rq_authop = aops;
-       return aops->accept(rqstp, authp);
+       return aops->accept(rqstp);
 }
 EXPORT_SYMBOL_GPL(svc_authenticate);
 
index 35b7966ac3b3bff13e2a87c2af5a36625e34b16a..d7ed7d49115ac607cf4677bdd60bb03dd5b4f9e3 100644 (file)
@@ -681,8 +681,9 @@ svcauth_unix_set_client(struct svc_rqst *rqstp)
 
        rqstp->rq_client = NULL;
        if (rqstp->rq_proc == 0)
-               return SVC_OK;
+               goto out;
 
+       rqstp->rq_auth_stat = rpc_autherr_badcred;
        ipm = ip_map_cached_get(xprt);
        if (ipm == NULL)
                ipm = __ip_map_lookup(sn->ip_map_cache, rqstp->rq_server->sv_program->pg_class,
@@ -719,13 +720,16 @@ svcauth_unix_set_client(struct svc_rqst *rqstp)
                put_group_info(cred->cr_group_info);
                cred->cr_group_info = gi;
        }
+
+out:
+       rqstp->rq_auth_stat = rpc_auth_ok;
        return SVC_OK;
 }
 
 EXPORT_SYMBOL_GPL(svcauth_unix_set_client);
 
 static int
-svcauth_null_accept(struct svc_rqst *rqstp, __be32 *authp)
+svcauth_null_accept(struct svc_rqst *rqstp)
 {
        struct kvec     *argv = &rqstp->rq_arg.head[0];
        struct kvec     *resv = &rqstp->rq_res.head[0];
@@ -736,12 +740,12 @@ svcauth_null_accept(struct svc_rqst *rqstp, __be32 *authp)
 
        if (svc_getu32(argv) != 0) {
                dprintk("svc: bad null cred\n");
-               *authp = rpc_autherr_badcred;
+               rqstp->rq_auth_stat = rpc_autherr_badcred;
                return SVC_DENIED;
        }
        if (svc_getu32(argv) != htonl(RPC_AUTH_NULL) || svc_getu32(argv) != 0) {
                dprintk("svc: bad null verf\n");
-               *authp = rpc_autherr_badverf;
+               rqstp->rq_auth_stat = rpc_autherr_badverf;
                return SVC_DENIED;
        }
 
@@ -785,7 +789,7 @@ struct auth_ops svcauth_null = {
 
 
 static int
-svcauth_unix_accept(struct svc_rqst *rqstp, __be32 *authp)
+svcauth_unix_accept(struct svc_rqst *rqstp)
 {
        struct kvec     *argv = &rqstp->rq_arg.head[0];
        struct kvec     *resv = &rqstp->rq_res.head[0];
@@ -827,7 +831,7 @@ svcauth_unix_accept(struct svc_rqst *rqstp, __be32 *authp)
        }
        groups_sort(cred->cr_group_info);
        if (svc_getu32(argv) != htonl(RPC_AUTH_NULL) || svc_getu32(argv) != 0) {
-               *authp = rpc_autherr_badverf;
+               rqstp->rq_auth_stat = rpc_autherr_badverf;
                return SVC_DENIED;
        }
 
@@ -839,7 +843,7 @@ svcauth_unix_accept(struct svc_rqst *rqstp, __be32 *authp)
        return SVC_OK;
 
 badcred:
-       *authp = rpc_autherr_badcred;
+       rqstp->rq_auth_stat = rpc_autherr_badcred;
        return SVC_DENIED;
 }
 
index 64da3bfd28e6c2ab30e51b2459dc3bb0f22f2ce6..9a6f17e18f73b00476ad951870c551eb9afc3ba5 100644 (file)
@@ -100,6 +100,28 @@ static ssize_t rpc_sysfs_xprt_dstaddr_show(struct kobject *kobj,
        return ret + 1;
 }
 
+static ssize_t rpc_sysfs_xprt_srcaddr_show(struct kobject *kobj,
+                                          struct kobj_attribute *attr,
+                                          char *buf)
+{
+       struct rpc_xprt *xprt = rpc_sysfs_xprt_kobj_get_xprt(kobj);
+       struct sockaddr_storage saddr;
+       struct sock_xprt *sock;
+       ssize_t ret = -1;
+
+       if (!xprt)
+               return 0;
+
+       sock = container_of(xprt, struct sock_xprt, xprt);
+       if (kernel_getsockname(sock->sock, (struct sockaddr *)&saddr) < 0)
+               goto out;
+
+       ret = sprintf(buf, "%pISc\n", &saddr);
+out:
+       xprt_put(xprt);
+       return ret + 1;
+}
+
 static ssize_t rpc_sysfs_xprt_info_show(struct kobject *kobj,
                                        struct kobj_attribute *attr,
                                        char *buf)
@@ -114,14 +136,16 @@ static ssize_t rpc_sysfs_xprt_info_show(struct kobject *kobj,
                       "max_num_slots=%u\nmin_num_slots=%u\nnum_reqs=%u\n"
                       "binding_q_len=%u\nsending_q_len=%u\npending_q_len=%u\n"
                       "backlog_q_len=%u\nmain_xprt=%d\nsrc_port=%u\n"
-                      "tasks_queuelen=%ld\n",
+                      "tasks_queuelen=%ld\ndst_port=%s\n",
                       xprt->last_used, xprt->cong, xprt->cwnd, xprt->max_reqs,
                       xprt->min_reqs, xprt->num_reqs, xprt->binding.qlen,
                       xprt->sending.qlen, xprt->pending.qlen,
                       xprt->backlog.qlen, xprt->main,
                       (xprt->xprt_class->ident == XPRT_TRANSPORT_TCP) ?
                       get_srcport(xprt) : 0,
-                      atomic_long_read(&xprt->queuelen));
+                      atomic_long_read(&xprt->queuelen),
+                      (xprt->xprt_class->ident == XPRT_TRANSPORT_TCP) ?
+                               xprt->address_strings[RPC_DISPLAY_PORT] : "0");
        xprt_put(xprt);
        return ret + 1;
 }
@@ -183,8 +207,10 @@ static ssize_t rpc_sysfs_xprt_switch_info_show(struct kobject *kobj,
 
        if (!xprt_switch)
                return 0;
-       ret = sprintf(buf, "num_xprts=%u\nnum_active=%u\nqueue_len=%ld\n",
+       ret = sprintf(buf, "num_xprts=%u\nnum_active=%u\n"
+                     "num_unique_destaddr=%u\nqueue_len=%ld\n",
                      xprt_switch->xps_nxprts, xprt_switch->xps_nactive,
+                     xprt_switch->xps_nunique_destaddr_xprts,
                      atomic_long_read(&xprt_switch->xps_queuelen));
        xprt_switch_put(xprt_switch);
        return ret + 1;
@@ -376,6 +402,9 @@ static const void *rpc_sysfs_xprt_namespace(struct kobject *kobj)
 static struct kobj_attribute rpc_sysfs_xprt_dstaddr = __ATTR(dstaddr,
        0644, rpc_sysfs_xprt_dstaddr_show, rpc_sysfs_xprt_dstaddr_store);
 
+static struct kobj_attribute rpc_sysfs_xprt_srcaddr = __ATTR(srcaddr,
+       0644, rpc_sysfs_xprt_srcaddr_show, NULL);
+
 static struct kobj_attribute rpc_sysfs_xprt_info = __ATTR(xprt_info,
        0444, rpc_sysfs_xprt_info_show, NULL);
 
@@ -384,6 +413,7 @@ static struct kobj_attribute rpc_sysfs_xprt_change_state = __ATTR(xprt_state,
 
 static struct attribute *rpc_sysfs_xprt_attrs[] = {
        &rpc_sysfs_xprt_dstaddr.attr,
+       &rpc_sysfs_xprt_srcaddr.attr,
        &rpc_sysfs_xprt_info.attr,
        &rpc_sysfs_xprt_change_state.attr,
        NULL,
index 05abe344a269b7cfe1958ccb23aaa467293fb83b..cfd681700d1a1ce720b266d17ece4873851f750f 100644 (file)
@@ -761,6 +761,20 @@ void xprt_disconnect_done(struct rpc_xprt *xprt)
 }
 EXPORT_SYMBOL_GPL(xprt_disconnect_done);
 
+/**
+ * xprt_schedule_autoclose_locked - Try to schedule an autoclose RPC call
+ * @xprt: transport to disconnect
+ */
+static void xprt_schedule_autoclose_locked(struct rpc_xprt *xprt)
+{
+       set_bit(XPRT_CLOSE_WAIT, &xprt->state);
+       if (test_and_set_bit(XPRT_LOCKED, &xprt->state) == 0)
+               queue_work(xprtiod_workqueue, &xprt->task_cleanup);
+       else if (xprt->snd_task && !test_bit(XPRT_SND_IS_COOKIE, &xprt->state))
+               rpc_wake_up_queued_task_set_status(&xprt->pending,
+                                                  xprt->snd_task, -ENOTCONN);
+}
+
 /**
  * xprt_force_disconnect - force a transport to disconnect
  * @xprt: transport to disconnect
@@ -772,13 +786,7 @@ void xprt_force_disconnect(struct rpc_xprt *xprt)
 
        /* Don't race with the test_bit() in xprt_clear_locked() */
        spin_lock(&xprt->transport_lock);
-       set_bit(XPRT_CLOSE_WAIT, &xprt->state);
-       /* Try to schedule an autoclose RPC call */
-       if (test_and_set_bit(XPRT_LOCKED, &xprt->state) == 0)
-               queue_work(xprtiod_workqueue, &xprt->task_cleanup);
-       else if (xprt->snd_task)
-               rpc_wake_up_queued_task_set_status(&xprt->pending,
-                               xprt->snd_task, -ENOTCONN);
+       xprt_schedule_autoclose_locked(xprt);
        spin_unlock(&xprt->transport_lock);
 }
 EXPORT_SYMBOL_GPL(xprt_force_disconnect);
@@ -818,11 +826,7 @@ void xprt_conditional_disconnect(struct rpc_xprt *xprt, unsigned int cookie)
                goto out;
        if (test_bit(XPRT_CLOSING, &xprt->state))
                goto out;
-       set_bit(XPRT_CLOSE_WAIT, &xprt->state);
-       /* Try to schedule an autoclose RPC call */
-       if (test_and_set_bit(XPRT_LOCKED, &xprt->state) == 0)
-               queue_work(xprtiod_workqueue, &xprt->task_cleanup);
-       xprt_wake_pending_tasks(xprt, -EAGAIN);
+       xprt_schedule_autoclose_locked(xprt);
 out:
        spin_unlock(&xprt->transport_lock);
 }
@@ -880,12 +884,14 @@ bool xprt_lock_connect(struct rpc_xprt *xprt,
                goto out;
        if (xprt->snd_task != task)
                goto out;
+       set_bit(XPRT_SND_IS_COOKIE, &xprt->state);
        xprt->snd_task = cookie;
        ret = true;
 out:
        spin_unlock(&xprt->transport_lock);
        return ret;
 }
+EXPORT_SYMBOL_GPL(xprt_lock_connect);
 
 void xprt_unlock_connect(struct rpc_xprt *xprt, void *cookie)
 {
@@ -895,12 +901,14 @@ void xprt_unlock_connect(struct rpc_xprt *xprt, void *cookie)
        if (!test_bit(XPRT_LOCKED, &xprt->state))
                goto out;
        xprt->snd_task =NULL;
+       clear_bit(XPRT_SND_IS_COOKIE, &xprt->state);
        xprt->ops->release_xprt(xprt, NULL);
        xprt_schedule_autodisconnect(xprt);
 out:
        spin_unlock(&xprt->transport_lock);
        wake_up_bit(&xprt->state, XPRT_LOCKED);
 }
+EXPORT_SYMBOL_GPL(xprt_unlock_connect);
 
 /**
  * xprt_connect - schedule a transport connect operation
index c60820e45082c0474cd1452bf774de6130a17484..1693f81aae376342660f4b2da08ae32b40355298 100644 (file)
@@ -139,6 +139,7 @@ struct rpc_xprt_switch *xprt_switch_alloc(struct rpc_xprt *xprt,
                xps->xps_iter_ops = &rpc_xprt_iter_singular;
                rpc_sysfs_xprt_switch_setup(xps, xprt, gfp_flags);
                xprt_switch_add_xprt_locked(xps, xprt);
+               xps->xps_nunique_destaddr_xprts = 1;
                rpc_sysfs_xprt_setup(xps, xprt, gfp_flags);
        }
 
index 1151efd09b274da4edd86a3ca65df356ae6040b0..17f174d6ea3b9b29c26ea93987d8c593d132c4ef 100644 (file)
@@ -115,7 +115,7 @@ int xprt_rdma_bc_send_reply(struct rpc_rqst *rqst)
        if (rc < 0)
                goto failed_marshal;
 
-       if (rpcrdma_post_sends(r_xprt, req))
+       if (frwr_send(r_xprt, req))
                goto drop_connection;
        return 0;
 
index 229fcc9a906491846a5d0a35ffef166efbc84c0d..f700b34a5bfd24d8260b0b3641a29195368ef48c 100644 (file)
@@ -394,6 +394,7 @@ int frwr_send(struct rpcrdma_xprt *r_xprt, struct rpcrdma_req *req)
        struct rpcrdma_ep *ep = r_xprt->rx_ep;
        struct rpcrdma_mr *mr;
        unsigned int num_wrs;
+       int ret;
 
        num_wrs = 1;
        post_wr = send_wr;
@@ -420,7 +421,10 @@ int frwr_send(struct rpcrdma_xprt *r_xprt, struct rpcrdma_req *req)
        }
 
        trace_xprtrdma_post_send(req);
-       return ib_post_send(ep->re_id->qp, post_wr, NULL);
+       ret = ib_post_send(ep->re_id->qp, post_wr, NULL);
+       if (ret)
+               trace_xprtrdma_post_send_err(r_xprt, req, ret);
+       return ret;
 }
 
 /**
@@ -557,6 +561,10 @@ void frwr_unmap_sync(struct rpcrdma_xprt *r_xprt, struct rpcrdma_req *req)
 
        /* On error, the MRs get destroyed once the QP has drained. */
        trace_xprtrdma_post_linv_err(req, rc);
+
+       /* Force a connection loss to ensure complete recovery.
+        */
+       rpcrdma_force_disconnect(ep);
 }
 
 /**
@@ -653,4 +661,8 @@ void frwr_unmap_async(struct rpcrdma_xprt *r_xprt, struct rpcrdma_req *req)
         * retransmission.
         */
        rpcrdma_unpin_rqst(req->rl_reply);
+
+       /* Force a connection loss to ensure complete recovery.
+        */
+       rpcrdma_force_disconnect(ep);
 }
index 9c2ffc67c0fde1940ac69dd9f76ed379637da1b7..16e5696314a4f31cba124612f800d7e5b1daf00c 100644 (file)
@@ -250,12 +250,9 @@ xprt_rdma_connect_worker(struct work_struct *work)
                                           xprt->stat.connect_start;
                xprt_set_connected(xprt);
                rc = -EAGAIN;
-       } else {
-               /* Force a call to xprt_rdma_close to clean up */
-               spin_lock(&xprt->transport_lock);
-               set_bit(XPRT_CLOSE_WAIT, &xprt->state);
-               spin_unlock(&xprt->transport_lock);
-       }
+       } else
+               rpcrdma_xprt_disconnect(r_xprt);
+       xprt_unlock_connect(xprt, r_xprt);
        xprt_wake_pending_tasks(xprt, rc);
 }
 
@@ -489,6 +486,8 @@ xprt_rdma_connect(struct rpc_xprt *xprt, struct rpc_task *task)
        struct rpcrdma_ep *ep = r_xprt->rx_ep;
        unsigned long delay;
 
+       WARN_ON_ONCE(!xprt_lock_connect(xprt, task, r_xprt));
+
        delay = 0;
        if (ep && ep->re_connect_status != 0) {
                delay = xprt_reconnect_delay(xprt);
@@ -661,7 +660,7 @@ xprt_rdma_send_request(struct rpc_rqst *rqst)
                goto drop_connection;
        rqst->rq_xtime = ktime_get();
 
-       if (rpcrdma_post_sends(r_xprt, req))
+       if (frwr_send(r_xprt, req))
                goto drop_connection;
 
        rqst->rq_xmit_bytes_sent += rqst->rq_snd_buf.len;
index 649c23518ec042285a12159b498c06359ffc49f2..aaec3c9be8db62d28a7d76bdc408d1e4678a9695 100644 (file)
@@ -124,7 +124,7 @@ static void rpcrdma_xprt_drain(struct rpcrdma_xprt *r_xprt)
  * connection is closed or lost. (The important thing is it needs
  * to be invoked "at least" once).
  */
-static void rpcrdma_force_disconnect(struct rpcrdma_ep *ep)
+void rpcrdma_force_disconnect(struct rpcrdma_ep *ep)
 {
        if (atomic_add_unless(&ep->re_force_disconnect, 1, 1))
                xprt_force_disconnect(ep->re_xprt);
@@ -1349,21 +1349,6 @@ static void rpcrdma_regbuf_free(struct rpcrdma_regbuf *rb)
        kfree(rb);
 }
 
-/**
- * rpcrdma_post_sends - Post WRs to a transport's Send Queue
- * @r_xprt: controlling transport instance
- * @req: rpcrdma_req containing the Send WR to post
- *
- * Returns 0 if the post was successful, otherwise -ENOTCONN
- * is returned.
- */
-int rpcrdma_post_sends(struct rpcrdma_xprt *r_xprt, struct rpcrdma_req *req)
-{
-       if (frwr_send(r_xprt, req))
-               return -ENOTCONN;
-       return 0;
-}
-
 /**
  * rpcrdma_post_recvs - Refill the Receive Queue
  * @r_xprt: controlling transport instance
@@ -1416,12 +1401,8 @@ void rpcrdma_post_recvs(struct rpcrdma_xprt *r_xprt, int needed, bool temp)
 
        rc = ib_post_recv(ep->re_id->qp, wr,
                          (const struct ib_recv_wr **)&bad_wr);
-       if (atomic_dec_return(&ep->re_receiving) > 0)
-               complete(&ep->re_done);
-
-out:
-       trace_xprtrdma_post_recvs(r_xprt, count, rc);
        if (rc) {
+               trace_xprtrdma_post_recvs_err(r_xprt, rc);
                for (wr = bad_wr; wr;) {
                        struct rpcrdma_rep *rep;
 
@@ -1431,6 +1412,11 @@ out:
                        --count;
                }
        }
+       if (atomic_dec_return(&ep->re_receiving) > 0)
+               complete(&ep->re_done);
+
+out:
+       trace_xprtrdma_post_recvs(r_xprt, count);
        ep->re_receive_count += count;
        return;
 }
index 5d231d94e94402bf6718701152719b4e994ab77d..d91f54eae00b37c1312746958cf59009f0b719d8 100644 (file)
@@ -454,11 +454,11 @@ extern unsigned int xprt_rdma_memreg_strategy;
 /*
  * Endpoint calls - xprtrdma/verbs.c
  */
+void rpcrdma_force_disconnect(struct rpcrdma_ep *ep);
 void rpcrdma_flush_disconnect(struct rpcrdma_xprt *r_xprt, struct ib_wc *wc);
 int rpcrdma_xprt_connect(struct rpcrdma_xprt *r_xprt);
 void rpcrdma_xprt_disconnect(struct rpcrdma_xprt *r_xprt);
 
-int rpcrdma_post_sends(struct rpcrdma_xprt *r_xprt, struct rpcrdma_req *req);
 void rpcrdma_post_recvs(struct rpcrdma_xprt *r_xprt, int needed, bool temp);
 
 /*
index b7dbdcbdeb6c7353246f01877b843b63bec7a366..04f1b78bcbca3d3e0f7203c59c46774b1b35fe3e 100644 (file)
@@ -1656,7 +1656,7 @@ static int xs_get_srcport(struct sock_xprt *transport)
 unsigned short get_srcport(struct rpc_xprt *xprt)
 {
        struct sock_xprt *sock = container_of(xprt, struct sock_xprt, xprt);
-       return sock->srcport;
+       return xs_sock_getport(sock->sock);
 }
 EXPORT_SYMBOL(get_srcport);
 
@@ -2099,13 +2099,20 @@ static void xs_tcp_shutdown(struct rpc_xprt *xprt)
 
        if (sock == NULL)
                return;
+       if (!xprt->reuseport) {
+               xs_close(xprt);
+               return;
+       }
        switch (skst) {
-       default:
+       case TCP_FIN_WAIT1:
+       case TCP_FIN_WAIT2:
+               break;
+       case TCP_ESTABLISHED:
+       case TCP_CLOSE_WAIT:
                kernel_sock_shutdown(sock, SHUT_RDWR);
                trace_rpc_socket_shutdown(xprt, sock);
                break;
-       case TCP_CLOSE:
-       case TCP_TIME_WAIT:
+       default:
                xs_reset_transport(transport);
        }
 }