For now, just count the queue length. It is less accurate than counting number of bytes queued, but easier to implement.
Unified · Split
| @@ -238,6 +238,7 @@ struct rpc_xprt { · 237 unmodified lines | ||
| 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 */ |
| @@ -15,6 +15,8 @@ struct rpc_xprt_switch { · 14 unmodified lines | ||
| 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; |
| @@ -968,13 +968,47 @@ out: · 967 unmodified lines | ||
| 968 | 968 | } |
| 969 | 969 | EXPORT_SYMBOL_GPL(rpc_bind_new_program); |
| 970 | 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 void | |
| 989 | +rpc_task_release_xprt(struct rpc_clnt *clnt, struct rpc_xprt *xprt) | |
| 990 | +{ | |
| 991 | + struct rpc_xprt_switch *xps; | |
| 992 | + | |
| 993 | + atomic_long_dec(&xprt->queuelen); | |
| 994 | + rcu_read_lock(); | |
| 995 | + xps = rcu_dereference(clnt->cl_xpi.xpi_xpswitch); | |
| 996 | + atomic_long_dec(&xps->xps_queuelen); | |
| 997 | + rcu_read_unlock(); | |
| 998 | + | |
| 999 | + xprt_put(xprt); | |
| 1000 | +} | |
| 1001 | + | |
| 971 | 1002 | void rpc_task_release_transport(struct rpc_task *task) |
| 972 | 1003 | { |
| 973 | 1004 | struct rpc_xprt *xprt = task->tk_xprt; |
| 974 | 1005 | |
| 975 | 1006 | if (xprt) { |
| 976 | 1007 | task->tk_xprt = NULL; |
| 977 | − xprt_put(xprt); | |
| 1008 | + if (task->tk_client) | |
| 1009 | + rpc_task_release_xprt(task->tk_client, xprt); | |
| 1010 | + else | |
| 1011 | + xprt_put(xprt); | |
| 978 | 1012 | } |
| 979 | 1013 | } |
| 980 | 1014 | EXPORT_SYMBOL_GPL(rpc_task_release_transport); |
| @@ -983,6 +1017,7 @@ void rpc_task_release_client(struct rpc_task *task) · 2 unmodified lines | ||
| 983 | 1017 | { |
| 984 | 1018 | struct rpc_clnt *clnt = task->tk_client; |
| 985 | 1019 | |
| 1020 | + rpc_task_release_transport(task); | |
| 986 | 1021 | if (clnt != NULL) { |
| 987 | 1022 | /* Remove from client task list */ |
| 988 | 1023 | spin_lock(&clnt->cl_lock); |
| @@ -992,14 +1027,13 @@ void rpc_task_release_client(struct rpc_task *task) · 3 unmodified lines | ||
| 992 | 1027 | |
| 993 | 1028 | rpc_release_client(clnt); |
| 994 | 1029 | } |
| 995 | − rpc_task_release_transport(task); | |
| 996 | 1030 | } |
| 997 | 1031 | |
| 998 | 1032 | static |
| 999 | 1033 | void rpc_task_set_transport(struct rpc_task *task, struct rpc_clnt *clnt) |
| 1000 | 1034 | { |
| 1001 | 1035 | if (!task->tk_xprt) |
| 1002 | − task->tk_xprt = xprt_iter_get_next(&clnt->cl_xpi); | |
| 1036 | + task->tk_xprt = rpc_task_get_xprt(clnt); | |
| 1003 | 1037 | } |
| 1004 | 1038 | |
| 1005 | 1039 | static |
| @@ -36,6 +36,7 @@ static void xprt_switch_add_xprt_locked(struct rpc_xprt_switch *xps, · 35 unmodified lines | ||
| 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 | /** |
| @@ -62,6 +63,7 @@ static void xprt_switch_remove_xprt_locked(struct rpc_xprt_switch *xps, · 20 unmodified lines | ||
| 62 | 63 | { |
| 63 | 64 | if (unlikely(xprt == NULL)) |
| 64 | 65 | return; |
| 66 | + xps->xps_nactive--; | |
| 65 | 67 | xps->xps_nxprts--; |
| 66 | 68 | if (xps->xps_nxprts == 0) |
| 67 | 69 | xps->xps_net = NULL; |
| @@ -317,8 +319,24 @@ struct rpc_xprt *xprt_switch_find_next_entry_roundrobin(struct list_head *head, · 249 unmodified lines | ||
| 317 | 319 | static |
| 318 | 320 | struct rpc_xprt *xprt_iter_next_entry_roundrobin(struct rpc_xprt_iter *xpi) |
| 319 | 321 | { |
| 320 | − return xprt_iter_next_entry_multiple(xpi, | |
| 322 | + struct rpc_xprt_switch *xps = rcu_dereference(xpi->xpi_xpswitch); | |
| 323 | + struct rpc_xprt *xprt; | |
| 324 | + unsigned long xprt_queuelen; | |
| 325 | + unsigned long xps_queuelen; | |
| 326 | + unsigned long xps_avglen; | |
| 327 | + | |
| 328 | + do { | |
| 329 | + xprt = xprt_iter_next_entry_multiple(xpi, | |
| 321 | 330 | xprt_switch_find_next_entry_roundrobin); |
| 331 | + if (xprt == NULL) | |
| 332 | + break; | |
| 333 | + xprt_queuelen = atomic_long_read(&xprt->queuelen); | |
| 334 | + if (xprt_queuelen <= 2) | |
| 335 | + break; | |
| 336 | + xps_queuelen = atomic_long_read(&xps->xps_queuelen); | |
| 337 | + xps_avglen = DIV_ROUND_UP(xps_queuelen, xps->xps_nactive); | |
| 338 | + } while (xprt_queuelen > xps_avglen); | |
| 339 | + return xprt; | |
| 322 | 340 | } |
| 323 | 341 | |
| 324 | 342 | static |