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 | * Send stuff | 239 | * Send stuff |
| 240 | */ | 240 | */ |
| 241 | atomic_long_t queuelen; | ||
| 241 | spinlock_t transport_lock; /* lock transport info */ | 242 | spinlock_t transport_lock; /* lock transport info */ |
| 242 | spinlock_t reserve_lock; /* lock slot table */ | 243 | spinlock_t reserve_lock; /* lock slot table */ |
| 243 | spinlock_t queue_lock; /* send/receive queue lock */ | 244 | spinlock_t queue_lock; /* send/receive queue lock */ |
| @@ -15,6 +15,8 @@ struct rpc_xprt_switch { · 14 unmodified lines | |||
| 15 | struct kref xps_kref; | 15 | struct kref xps_kref; |
| 16 | 16 | ||
| 17 | unsigned int xps_nxprts; | 17 | unsigned int xps_nxprts; |
| 18 | unsigned int xps_nactive; | ||
| 19 | atomic_long_t xps_queuelen; | ||
| 18 | struct list_head xps_xprt_list; | 20 | struct list_head xps_xprt_list; |
| 19 | 21 | ||
| 20 | struct net * xps_net; | 22 | struct net * xps_net; |
| @@ -968,13 +968,47 @@ out: · 967 unmodified lines | |||
| 968 | } | 968 | } |
| 969 | EXPORT_SYMBOL_GPL(rpc_bind_new_program); | 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 | void rpc_task_release_transport(struct rpc_task *task) | 1002 | void rpc_task_release_transport(struct rpc_task *task) |
| 972 | { | 1003 | { |
| 973 | struct rpc_xprt *xprt = task->tk_xprt; | 1004 | struct rpc_xprt *xprt = task->tk_xprt; |
| 974 | 1005 | ||
| 975 | if (xprt) { | 1006 | if (xprt) { |
| 976 | task->tk_xprt = NULL; | 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 | EXPORT_SYMBOL_GPL(rpc_task_release_transport); | 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 | struct rpc_clnt *clnt = task->tk_client; | 1018 | struct rpc_clnt *clnt = task->tk_client; |
| 985 | 1019 | ||
| 1020 | rpc_task_release_transport(task); | ||
| 986 | if (clnt != NULL) { | 1021 | if (clnt != NULL) { |
| 987 | /* Remove from client task list */ | 1022 | /* Remove from client task list */ |
| 988 | spin_lock(&clnt->cl_lock); | 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 | rpc_release_client(clnt); | 1028 | rpc_release_client(clnt); |
| 994 | } | 1029 | } |
| 995 | rpc_task_release_transport(task); | ||
| 996 | } | 1030 | } |
| 997 | 1031 | ||
| 998 | static | 1032 | static |
| 999 | void rpc_task_set_transport(struct rpc_task *task, struct rpc_clnt *clnt) | 1033 | void rpc_task_set_transport(struct rpc_task *task, struct rpc_clnt *clnt) |
| 1000 | { | 1034 | { |
| 1001 | if (!task->tk_xprt) | 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 | static | 1039 | static |
| @@ -36,6 +36,7 @@ static void xprt_switch_add_xprt_locked(struct rpc_xprt_switch *xps, · 35 unmodified lines | |||
| 36 | if (xps->xps_nxprts == 0) | 36 | if (xps->xps_nxprts == 0) |
| 37 | xps->xps_net = xprt->xprt_net; | 37 | xps->xps_net = xprt->xprt_net; |
| 38 | xps->xps_nxprts++; | 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 | if (unlikely(xprt == NULL)) | 64 | if (unlikely(xprt == NULL)) |
| 64 | return; | 65 | return; |
| 66 | xps->xps_nactive--; | ||
| 65 | xps->xps_nxprts--; | 67 | xps->xps_nxprts--; |
| 66 | if (xps->xps_nxprts == 0) | 68 | if (xps->xps_nxprts == 0) |
| 67 | xps->xps_net = NULL; | 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 | static | 319 | static |
| 318 | struct rpc_xprt *xprt_iter_next_entry_roundrobin(struct rpc_xprt_iter *xpi) | 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 | xprt_switch_find_next_entry_roundrobin); | 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 | static | 342 | static |