Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

Merge branch 'multipath_tcp'

+186 -43
+3
fs/nfs/client.c
··· 176 176 clp->cl_rpcclient = ERR_PTR(-EINVAL); 177 177 178 178 clp->cl_proto = cl_init->proto; 179 + clp->cl_nconnect = cl_init->nconnect; 179 180 clp->cl_net = get_net(cl_init->net); 180 181 181 182 clp->cl_principal = "*"; ··· 495 494 struct rpc_create_args args = { 496 495 .net = clp->cl_net, 497 496 .protocol = clp->cl_proto, 497 + .nconnect = clp->cl_nconnect, 498 498 .address = (struct sockaddr *)&clp->cl_addr, 499 499 .addrsize = clp->cl_addrlen, 500 500 .timeout = cl_init->timeparms, ··· 661 659 .net = data->net, 662 660 .timeparms = &timeparms, 663 661 .cred = server->cred, 662 + .nconnect = data->nfs_server.nconnect, 664 663 }; 665 664 struct nfs_client *clp; 666 665 int error;
+2
fs/nfs/internal.h
··· 82 82 struct nfs_subversion *nfs_mod; 83 83 int proto; 84 84 u32 minorversion; 85 + unsigned int nconnect; 85 86 struct net *net; 86 87 const struct rpc_timeout *timeparms; 87 88 const struct cred *cred; ··· 124 123 char *export_path; 125 124 int port; 126 125 unsigned short protocol; 126 + unsigned short nconnect; 127 127 } nfs_server; 128 128 129 129 void *lsm_opts;
+3
fs/nfs/nfs3client.c
··· 102 102 return ERR_PTR(-EINVAL); 103 103 cl_init.hostname = buf; 104 104 105 + if (mds_clp->cl_nconnect > 1 && ds_proto == XPRT_TRANSPORT_TCP) 106 + cl_init.nconnect = mds_clp->cl_nconnect; 107 + 105 108 if (mds_srv->flags & NFS_MOUNT_NORESVPORT) 106 109 set_bit(NFS_CS_NORESVPORT, &cl_init.init_flags); 107 110
+12 -2
fs/nfs/nfs4client.c
··· 859 859 const size_t addrlen, 860 860 const char *ip_addr, 861 861 int proto, const struct rpc_timeout *timeparms, 862 - u32 minorversion, struct net *net) 862 + u32 minorversion, unsigned int nconnect, 863 + struct net *net) 863 864 { 864 865 struct nfs_client_initdata cl_init = { 865 866 .hostname = hostname, ··· 876 875 }; 877 876 struct nfs_client *clp; 878 877 878 + if (minorversion > 0 && proto == XPRT_TRANSPORT_TCP) 879 + cl_init.nconnect = nconnect; 879 880 if (server->flags & NFS_MOUNT_NORESVPORT) 880 881 set_bit(NFS_CS_NORESVPORT, &cl_init.init_flags); 881 882 if (server->options & NFS_OPTION_MIGRATION) ··· 943 940 if (rpc_ntop(ds_addr, buf, sizeof(buf)) <= 0) 944 941 return ERR_PTR(-EINVAL); 945 942 cl_init.hostname = buf; 943 + 944 + if (mds_clp->cl_nconnect > 1 && ds_proto == XPRT_TRANSPORT_TCP) 945 + cl_init.nconnect = mds_clp->cl_nconnect; 946 946 947 947 if (mds_srv->flags & NFS_MOUNT_NORESVPORT) 948 948 __set_bit(NFS_CS_NORESVPORT, &cl_init.init_flags); ··· 1080 1074 data->nfs_server.protocol, 1081 1075 &timeparms, 1082 1076 data->minorversion, 1077 + data->nfs_server.nconnect, 1083 1078 data->net); 1084 1079 if (error < 0) 1085 1080 return error; ··· 1170 1163 XPRT_TRANSPORT_RDMA, 1171 1164 parent_server->client->cl_timeout, 1172 1165 parent_client->cl_mvops->minor_version, 1166 + parent_client->cl_nconnect, 1173 1167 parent_client->cl_net); 1174 1168 if (!error) 1175 1169 goto init_server; ··· 1184 1176 XPRT_TRANSPORT_TCP, 1185 1177 parent_server->client->cl_timeout, 1186 1178 parent_client->cl_mvops->minor_version, 1179 + parent_client->cl_nconnect, 1187 1180 parent_client->cl_net); 1188 1181 if (error < 0) 1189 1182 goto error; ··· 1280 1271 set_bit(NFS_MIG_TSM_POSSIBLE, &server->mig_status); 1281 1272 error = nfs4_set_client(server, hostname, sap, salen, buf, 1282 1273 clp->cl_proto, clnt->cl_timeout, 1283 - clp->cl_minorversion, net); 1274 + clp->cl_minorversion, 1275 + clp->cl_nconnect, net); 1284 1276 clear_bit(NFS_MIG_TSM_POSSIBLE, &server->mig_status); 1285 1277 if (error != 0) { 1286 1278 nfs_server_insert_lists(server);
+13 -9
fs/nfs/nfs4proc.c
··· 5992 5992 .rpc_message = &msg, 5993 5993 .callback_ops = &nfs4_setclientid_ops, 5994 5994 .callback_data = &setclientid, 5995 - .flags = RPC_TASK_TIMEOUT, 5995 + .flags = RPC_TASK_TIMEOUT | RPC_TASK_NO_ROUND_ROBIN, 5996 5996 }; 5997 5997 int status; 5998 5998 ··· 6058 6058 dprintk("NFS call setclientid_confirm auth=%s, (client ID %llx)\n", 6059 6059 clp->cl_rpcclient->cl_auth->au_ops->au_name, 6060 6060 clp->cl_clientid); 6061 - status = rpc_call_sync(clp->cl_rpcclient, &msg, RPC_TASK_TIMEOUT); 6061 + status = rpc_call_sync(clp->cl_rpcclient, &msg, 6062 + RPC_TASK_TIMEOUT | RPC_TASK_NO_ROUND_ROBIN); 6062 6063 trace_nfs4_setclientid_confirm(clp, status); 6063 6064 dprintk("NFS reply setclientid_confirm: %d\n", status); 6064 6065 return status; ··· 7640 7639 NFS_SP4_MACH_CRED_SECINFO, &clnt, &msg); 7641 7640 7642 7641 status = nfs4_call_sync(clnt, NFS_SERVER(dir), &msg, &args.seq_args, 7643 - &res.seq_res, 0); 7642 + &res.seq_res, RPC_TASK_NO_ROUND_ROBIN); 7644 7643 dprintk("NFS reply secinfo: %d\n", status); 7645 7644 7646 7645 put_cred(cred); ··· 7978 7977 .rpc_client = clp->cl_rpcclient, 7979 7978 .callback_ops = &nfs4_exchange_id_call_ops, 7980 7979 .rpc_message = &msg, 7981 - .flags = RPC_TASK_TIMEOUT, 7980 + .flags = RPC_TASK_TIMEOUT | RPC_TASK_NO_ROUND_ROBIN, 7982 7981 }; 7983 7982 struct nfs41_exchange_id_data *calldata; 7984 7983 int status; ··· 8203 8202 }; 8204 8203 int status; 8205 8204 8206 - status = rpc_call_sync(clp->cl_rpcclient, &msg, RPC_TASK_TIMEOUT); 8205 + status = rpc_call_sync(clp->cl_rpcclient, &msg, 8206 + RPC_TASK_TIMEOUT | RPC_TASK_NO_ROUND_ROBIN); 8207 8207 trace_nfs4_destroy_clientid(clp, status); 8208 8208 if (status) 8209 8209 dprintk("NFS: Got error %d from the server %s on " ··· 8483 8481 nfs4_init_channel_attrs(&args, clp->cl_rpcclient); 8484 8482 args.flags = (SESSION4_PERSIST | SESSION4_BACK_CHAN); 8485 8483 8486 - status = rpc_call_sync(session->clp->cl_rpcclient, &msg, RPC_TASK_TIMEOUT); 8484 + status = rpc_call_sync(session->clp->cl_rpcclient, &msg, 8485 + RPC_TASK_TIMEOUT | RPC_TASK_NO_ROUND_ROBIN); 8487 8486 trace_nfs4_create_session(clp, status); 8488 8487 8489 8488 switch (status) { ··· 8560 8557 if (!test_and_clear_bit(NFS4_SESSION_ESTABLISHED, &session->session_state)) 8561 8558 return 0; 8562 8559 8563 - status = rpc_call_sync(session->clp->cl_rpcclient, &msg, RPC_TASK_TIMEOUT); 8560 + status = rpc_call_sync(session->clp->cl_rpcclient, &msg, 8561 + RPC_TASK_TIMEOUT | RPC_TASK_NO_ROUND_ROBIN); 8564 8562 trace_nfs4_destroy_session(session->clp, status); 8565 8563 8566 8564 if (status) ··· 8815 8811 .rpc_client = clp->cl_rpcclient, 8816 8812 .rpc_message = &msg, 8817 8813 .callback_ops = &nfs4_reclaim_complete_call_ops, 8818 - .flags = RPC_TASK_ASYNC, 8814 + .flags = RPC_TASK_ASYNC | RPC_TASK_NO_ROUND_ROBIN, 8819 8815 }; 8820 8816 int status = -ENOMEM; 8821 8817 ··· 9334 9330 9335 9331 dprintk("--> %s\n", __func__); 9336 9332 status = nfs4_call_sync(clnt, server, &msg, &args.seq_args, 9337 - &res.seq_res, 0); 9333 + &res.seq_res, RPC_TASK_NO_ROUND_ROBIN); 9338 9334 dprintk("<-- %s status=%d\n", __func__, status); 9339 9335 9340 9336 put_cred(cred);
+12
fs/nfs/super.c
··· 77 77 #define NFS_DEFAULT_VERSION 2 78 78 #endif 79 79 80 + #define NFS_MAX_CONNECTIONS 16 81 + 80 82 enum { 81 83 /* Mount options that take no arguments */ 82 84 Opt_soft, Opt_softerr, Opt_hard, ··· 110 108 Opt_nfsvers, 111 109 Opt_sec, Opt_proto, Opt_mountproto, Opt_mounthost, 112 110 Opt_addr, Opt_mountaddr, Opt_clientaddr, 111 + Opt_nconnect, 113 112 Opt_lookupcache, 114 113 Opt_fscache_uniq, 115 114 Opt_local_lock, ··· 183 180 { Opt_clientaddr, "clientaddr=%s" }, 184 181 { Opt_mounthost, "mounthost=%s" }, 185 182 { Opt_mountaddr, "mountaddr=%s" }, 183 + 184 + { Opt_nconnect, "nconnect=%s" }, 186 185 187 186 { Opt_lookupcache, "lookupcache=%s" }, 188 187 { Opt_fscache_uniq, "fsc=%s" }, ··· 678 673 seq_printf(m, ",proto=%s", 679 674 rpc_peeraddr2str(nfss->client, RPC_DISPLAY_NETID)); 680 675 rcu_read_unlock(); 676 + if (clp->cl_nconnect > 0) 677 + seq_printf(m, ",nconnect=%u", clp->cl_nconnect); 681 678 if (version == 4) { 682 679 if (nfss->port != NFS_PORT) 683 680 seq_printf(m, ",port=%u", nfss->port); ··· 1555 1548 kfree(string); 1556 1549 if (mnt->mount_server.addrlen == 0) 1557 1550 goto out_invalid_address; 1551 + break; 1552 + case Opt_nconnect: 1553 + if (nfs_get_option_ul_bound(args, &option, 1, NFS_MAX_CONNECTIONS)) 1554 + goto out_invalid_value; 1555 + mnt->nfs_server.nconnect = option; 1558 1556 break; 1559 1557 case Opt_lookupcache: 1560 1558 string = match_strdup(args);
+1
include/linux/nfs_fs_sb.h
··· 58 58 struct nfs_subversion * cl_nfs_mod; /* pointer to nfs version module */ 59 59 60 60 u32 cl_minorversion;/* NFSv4 minorversion */ 61 + unsigned int cl_nconnect; /* Number of connections */ 61 62 const char * cl_principal; /* used for machine cred */ 62 63 63 64 #if IS_ENABLED(CONFIG_NFS_V4)
+1
include/linux/sunrpc/clnt.h
··· 124 124 u32 prognumber; /* overrides program->number */ 125 125 u32 version; 126 126 rpc_authflavor_t authflavor; 127 + u32 nconnect; 127 128 unsigned long flags; 128 129 char *client_name; 129 130 struct svc_xprt *bc_xprt; /* NFSv4.1 backchannel */
+1
include/linux/sunrpc/sched.h
··· 126 126 #define RPC_CALL_MAJORSEEN 0x0020 /* major timeout seen */ 127 127 #define RPC_TASK_ROOTCREDS 0x0040 /* force root creds */ 128 128 #define RPC_TASK_DYNAMIC 0x0080 /* task was kmalloc'ed */ 129 + #define RPC_TASK_NO_ROUND_ROBIN 0x0100 /* send requests on "main" xprt */ 129 130 #define RPC_TASK_SOFT 0x0200 /* Use soft timeouts */ 130 131 #define RPC_TASK_SOFTCONN 0x0400 /* Fail if can't connect */ 131 132 #define RPC_TASK_SENT 0x0800 /* message was sent */
+1
include/linux/sunrpc/xprt.h
··· 238 238 /* 239 239 * Send stuff 240 240 */ 241 + atomic_long_t queuelen; 241 242 spinlock_t transport_lock; /* lock transport info */ 242 243 spinlock_t reserve_lock; /* lock slot table */ 243 244 spinlock_t queue_lock; /* send/receive queue lock */
+2
include/linux/sunrpc/xprtmultipath.h
··· 15 15 struct kref xps_kref; 16 16 17 17 unsigned int xps_nxprts; 18 + unsigned int xps_nactive; 19 + atomic_long_t xps_queuelen; 18 20 struct list_head xps_xprt_list; 19 21 20 22 struct net * xps_net;
+76 -5
net/sunrpc/clnt.c
··· 528 528 .bc_xprt = args->bc_xprt, 529 529 }; 530 530 char servername[48]; 531 + struct rpc_clnt *clnt; 532 + int i; 531 533 532 534 if (args->bc_xprt) { 533 535 WARN_ON_ONCE(!(args->protocol & XPRT_TRANSPORT_BC)); ··· 592 590 if (args->flags & RPC_CLNT_CREATE_NONPRIVPORT) 593 591 xprt->resvport = 0; 594 592 595 - return rpc_create_xprt(args, xprt); 593 + clnt = rpc_create_xprt(args, xprt); 594 + if (IS_ERR(clnt) || args->nconnect <= 1) 595 + return clnt; 596 + 597 + for (i = 0; i < args->nconnect - 1; i++) { 598 + if (rpc_clnt_add_xprt(clnt, &xprtargs, NULL, NULL) < 0) 599 + break; 600 + } 601 + return clnt; 596 602 } 597 603 EXPORT_SYMBOL_GPL(rpc_create); 598 604 ··· 978 968 } 979 969 EXPORT_SYMBOL_GPL(rpc_bind_new_program); 980 970 971 + static struct rpc_xprt * 972 + rpc_task_get_xprt(struct rpc_clnt *clnt) 973 + { 974 + struct rpc_xprt_switch *xps; 975 + struct rpc_xprt *xprt= xprt_iter_get_next(&clnt->cl_xpi); 976 + 977 + if (!xprt) 978 + return NULL; 979 + rcu_read_lock(); 980 + xps = rcu_dereference(clnt->cl_xpi.xpi_xpswitch); 981 + atomic_long_inc(&xps->xps_queuelen); 982 + rcu_read_unlock(); 983 + atomic_long_inc(&xprt->queuelen); 984 + 985 + return xprt; 986 + } 987 + 988 + static struct rpc_xprt * 989 + rpc_task_get_first_xprt(struct rpc_clnt *clnt) 990 + { 991 + struct rpc_xprt_switch *xps; 992 + struct rpc_xprt *xprt; 993 + 994 + rcu_read_lock(); 995 + xprt = xprt_get(rcu_dereference(clnt->cl_xprt)); 996 + if (xprt) { 997 + atomic_long_inc(&xprt->queuelen); 998 + xps = rcu_dereference(clnt->cl_xpi.xpi_xpswitch); 999 + atomic_long_inc(&xps->xps_queuelen); 1000 + } 1001 + rcu_read_unlock(); 1002 + 1003 + return xprt; 1004 + } 1005 + 1006 + static void 1007 + rpc_task_release_xprt(struct rpc_clnt *clnt, struct rpc_xprt *xprt) 1008 + { 1009 + struct rpc_xprt_switch *xps; 1010 + 1011 + atomic_long_dec(&xprt->queuelen); 1012 + rcu_read_lock(); 1013 + xps = rcu_dereference(clnt->cl_xpi.xpi_xpswitch); 1014 + atomic_long_dec(&xps->xps_queuelen); 1015 + rcu_read_unlock(); 1016 + 1017 + xprt_put(xprt); 1018 + } 1019 + 981 1020 void rpc_task_release_transport(struct rpc_task *task) 982 1021 { 983 1022 struct rpc_xprt *xprt = task->tk_xprt; 984 1023 985 1024 if (xprt) { 986 1025 task->tk_xprt = NULL; 987 - xprt_put(xprt); 1026 + if (task->tk_client) 1027 + rpc_task_release_xprt(task->tk_client, xprt); 1028 + else 1029 + xprt_put(xprt); 988 1030 } 989 1031 } 990 1032 EXPORT_SYMBOL_GPL(rpc_task_release_transport); ··· 1045 983 { 1046 984 struct rpc_clnt *clnt = task->tk_client; 1047 985 986 + rpc_task_release_transport(task); 1048 987 if (clnt != NULL) { 1049 988 /* Remove from client task list */ 1050 989 spin_lock(&clnt->cl_lock); ··· 1055 992 1056 993 rpc_release_client(clnt); 1057 994 } 1058 - rpc_task_release_transport(task); 1059 995 } 1060 996 1061 997 static 1062 998 void rpc_task_set_transport(struct rpc_task *task, struct rpc_clnt *clnt) 1063 999 { 1064 - if (!task->tk_xprt) 1065 - task->tk_xprt = xprt_iter_get_next(&clnt->cl_xpi); 1000 + if (task->tk_xprt) 1001 + return; 1002 + if (task->tk_flags & RPC_TASK_NO_ROUND_ROBIN) 1003 + task->tk_xprt = rpc_task_get_first_xprt(clnt); 1004 + else 1005 + task->tk_xprt = rpc_task_get_xprt(clnt); 1066 1006 } 1067 1007 1068 1008 static ··· 2762 2696 return -ENOMEM; 2763 2697 data->xps = xprt_switch_get(xps); 2764 2698 data->xprt = xprt_get(xprt); 2699 + if (rpc_xprt_switch_has_addr(data->xps, (struct sockaddr *)&xprt->addr)) { 2700 + rpc_cb_add_xprt_release(data); 2701 + goto success; 2702 + } 2765 2703 2766 2704 task = rpc_call_null_helper(clnt, xprt, NULL, 2767 2705 RPC_TASK_SOFT|RPC_TASK_SOFTCONN|RPC_TASK_ASYNC|RPC_TASK_NULLCREDS, ··· 2773 2703 if (IS_ERR(task)) 2774 2704 return PTR_ERR(task); 2775 2705 rpc_put_task(task); 2706 + success: 2776 2707 return 1; 2777 2708 } 2778 2709 EXPORT_SYMBOL_GPL(rpc_clnt_test_and_add_xprt);
+30 -18
net/sunrpc/debugfs.c
··· 1 1 // SPDX-License-Identifier: GPL-2.0 2 - /** 2 + /* 3 3 * debugfs interface for sunrpc 4 4 * 5 5 * (c) 2014 Jeff Layton <jlayton@primarydata.com> ··· 118 118 .release = tasks_release, 119 119 }; 120 120 121 + static int do_xprt_debugfs(struct rpc_clnt *clnt, struct rpc_xprt *xprt, void *numv) 122 + { 123 + int len; 124 + char name[24]; /* enough for "../../rpc_xprt/ + 8 hex digits + NULL */ 125 + char link[9]; /* enough for 8 hex digits + NULL */ 126 + int *nump = numv; 127 + 128 + if (IS_ERR_OR_NULL(xprt->debugfs)) 129 + return 0; 130 + len = snprintf(name, sizeof(name), "../../rpc_xprt/%s", 131 + xprt->debugfs->d_name.name); 132 + if (len > sizeof(name)) 133 + return -1; 134 + if (*nump == 0) 135 + strcpy(link, "xprt"); 136 + else { 137 + len = snprintf(link, sizeof(link), "xprt%d", *nump); 138 + if (len > sizeof(link)) 139 + return -1; 140 + } 141 + if (!debugfs_create_symlink(link, clnt->cl_debugfs, name)) 142 + return -1; 143 + (*nump)++; 144 + return 0; 145 + } 146 + 121 147 void 122 148 rpc_clnt_debugfs_register(struct rpc_clnt *clnt) 123 149 { 124 150 int len; 125 - char name[24]; /* enough for "../../rpc_xprt/ + 8 hex digits + NULL */ 126 - struct rpc_xprt *xprt; 151 + char name[9]; /* enough for 8 hex digits + NULL */ 152 + int xprtnum = 0; 127 153 128 154 /* Already registered? */ 129 155 if (clnt->cl_debugfs || !rpc_clnt_dir) ··· 169 143 clnt, &tasks_fops)) 170 144 goto out_err; 171 145 172 - rcu_read_lock(); 173 - xprt = rcu_dereference(clnt->cl_xprt); 174 - /* no "debugfs" dentry? Don't bother with the symlink. */ 175 - if (IS_ERR_OR_NULL(xprt->debugfs)) { 176 - rcu_read_unlock(); 177 - return; 178 - } 179 - len = snprintf(name, sizeof(name), "../../rpc_xprt/%s", 180 - xprt->debugfs->d_name.name); 181 - rcu_read_unlock(); 182 - 183 - if (len >= sizeof(name)) 184 - goto out_err; 185 - 186 - if (!debugfs_create_symlink("xprt", clnt->cl_debugfs, name)) 146 + if (rpc_clnt_iterate_for_each_xprt(clnt, do_xprt_debugfs, &xprtnum) < 0) 187 147 goto out_err; 188 148 189 149 return;
+9 -6
net/sunrpc/stats.c
··· 240 240 stats->om_error_status); 241 241 } 242 242 243 + static int do_print_stats(struct rpc_clnt *clnt, struct rpc_xprt *xprt, void *seqv) 244 + { 245 + struct seq_file *seq = seqv; 246 + 247 + xprt->ops->print_stats(xprt, seq); 248 + return 0; 249 + } 250 + 243 251 void rpc_clnt_show_stats(struct seq_file *seq, struct rpc_clnt *clnt) 244 252 { 245 - struct rpc_xprt *xprt; 246 253 unsigned int op, maxproc = clnt->cl_maxproc; 247 254 248 255 if (!clnt->cl_metrics) ··· 259 252 seq_printf(seq, "p/v: %u/%u (%s)\n", 260 253 clnt->cl_prog, clnt->cl_vers, clnt->cl_program->name); 261 254 262 - rcu_read_lock(); 263 - xprt = rcu_dereference(clnt->cl_xprt); 264 - if (xprt) 265 - xprt->ops->print_stats(xprt, seq); 266 - rcu_read_unlock(); 255 + rpc_clnt_iterate_for_each_xprt(clnt, do_print_stats, seq); 267 256 268 257 seq_printf(seq, "\tper-op statistics\n"); 269 258 for (op = 0; op < maxproc; op++) {
+20 -3
net/sunrpc/xprtmultipath.c
··· 36 36 if (xps->xps_nxprts == 0) 37 37 xps->xps_net = xprt->xprt_net; 38 38 xps->xps_nxprts++; 39 + xps->xps_nactive++; 39 40 } 40 41 41 42 /** ··· 52 51 if (xprt == NULL) 53 52 return; 54 53 spin_lock(&xps->xps_lock); 55 - if ((xps->xps_net == xprt->xprt_net || xps->xps_net == NULL) && 56 - !rpc_xprt_switch_has_addr(xps, (struct sockaddr *)&xprt->addr)) 54 + if (xps->xps_net == xprt->xprt_net || xps->xps_net == NULL) 57 55 xprt_switch_add_xprt_locked(xps, xprt); 58 56 spin_unlock(&xps->xps_lock); 59 57 } ··· 62 62 { 63 63 if (unlikely(xprt == NULL)) 64 64 return; 65 + xps->xps_nactive--; 65 66 xps->xps_nxprts--; 66 67 if (xps->xps_nxprts == 0) 67 68 xps->xps_net = NULL; ··· 318 317 static 319 318 struct rpc_xprt *xprt_iter_next_entry_roundrobin(struct rpc_xprt_iter *xpi) 320 319 { 321 - return xprt_iter_next_entry_multiple(xpi, 320 + struct rpc_xprt_switch *xps = rcu_dereference(xpi->xpi_xpswitch); 321 + struct rpc_xprt *xprt; 322 + unsigned long xprt_queuelen; 323 + unsigned long xps_queuelen; 324 + unsigned long xps_avglen; 325 + 326 + do { 327 + xprt = xprt_iter_next_entry_multiple(xpi, 322 328 xprt_switch_find_next_entry_roundrobin); 329 + if (xprt == NULL) 330 + break; 331 + xprt_queuelen = atomic_long_read(&xprt->queuelen); 332 + if (xprt_queuelen <= 2) 333 + break; 334 + xps_queuelen = atomic_long_read(&xps->xps_queuelen); 335 + xps_avglen = DIV_ROUND_UP(xps_queuelen, xps->xps_nactive); 336 + } while (xprt_queuelen > xps_avglen); 337 + return xprt; 323 338 } 324 339 325 340 static