diff options
author | Trond Myklebust <Trond.Myklebust@netapp.com> | 2011-07-17 18:11:30 -0400 |
---|---|---|
committer | Trond Myklebust <Trond.Myklebust@netapp.com> | 2011-07-17 18:11:30 -0400 |
commit | d9ba131d8f58c0d2ff5029e7002ab43f913b36f9 (patch) | |
tree | f2ed7330c72077bf84954b989cbe1ff47522a115 /net | |
parent | 21de0a955f3af29fa1100d96f66e6adade89e77a (diff) |
SUNRPC: Support dynamic slot allocation for TCP connections
Allow the number of available slots to grow with the TCP window size.
Signed-off-by: Trond Myklebust <Trond.Myklebust@netapp.com>
Diffstat (limited to 'net')
-rw-r--r-- | net/sunrpc/xprt.c | 70 | ||||
-rw-r--r-- | net/sunrpc/xprtrdma/transport.c | 1 | ||||
-rw-r--r-- | net/sunrpc/xprtsock.c | 49 |
3 files changed, 102 insertions, 18 deletions
diff --git a/net/sunrpc/xprt.c b/net/sunrpc/xprt.c index ea7b3c16cddd..be85cf04a479 100644 --- a/net/sunrpc/xprt.c +++ b/net/sunrpc/xprt.c | |||
@@ -935,25 +935,66 @@ void xprt_transmit(struct rpc_task *task) | |||
935 | spin_unlock_bh(&xprt->transport_lock); | 935 | spin_unlock_bh(&xprt->transport_lock); |
936 | } | 936 | } |
937 | 937 | ||
938 | static struct rpc_rqst *xprt_dynamic_alloc_slot(struct rpc_xprt *xprt, gfp_t gfp_flags) | ||
939 | { | ||
940 | struct rpc_rqst *req = ERR_PTR(-EAGAIN); | ||
941 | |||
942 | if (!atomic_add_unless(&xprt->num_reqs, 1, xprt->max_reqs)) | ||
943 | goto out; | ||
944 | req = kzalloc(sizeof(struct rpc_rqst), gfp_flags); | ||
945 | if (req != NULL) | ||
946 | goto out; | ||
947 | atomic_dec(&xprt->num_reqs); | ||
948 | req = ERR_PTR(-ENOMEM); | ||
949 | out: | ||
950 | return req; | ||
951 | } | ||
952 | |||
953 | static bool xprt_dynamic_free_slot(struct rpc_xprt *xprt, struct rpc_rqst *req) | ||
954 | { | ||
955 | if (atomic_add_unless(&xprt->num_reqs, -1, xprt->min_reqs)) { | ||
956 | kfree(req); | ||
957 | return true; | ||
958 | } | ||
959 | return false; | ||
960 | } | ||
961 | |||
938 | static void xprt_alloc_slot(struct rpc_task *task) | 962 | static void xprt_alloc_slot(struct rpc_task *task) |
939 | { | 963 | { |
940 | struct rpc_xprt *xprt = task->tk_xprt; | 964 | struct rpc_xprt *xprt = task->tk_xprt; |
965 | struct rpc_rqst *req; | ||
941 | 966 | ||
942 | task->tk_status = 0; | ||
943 | if (!list_empty(&xprt->free)) { | 967 | if (!list_empty(&xprt->free)) { |
944 | struct rpc_rqst *req = list_entry(xprt->free.next, struct rpc_rqst, rq_list); | 968 | req = list_entry(xprt->free.next, struct rpc_rqst, rq_list); |
945 | list_del_init(&req->rq_list); | 969 | list_del(&req->rq_list); |
946 | task->tk_rqstp = req; | 970 | goto out_init_req; |
947 | xprt_request_init(task, xprt); | 971 | } |
948 | return; | 972 | req = xprt_dynamic_alloc_slot(xprt, GFP_NOWAIT); |
973 | if (!IS_ERR(req)) | ||
974 | goto out_init_req; | ||
975 | switch (PTR_ERR(req)) { | ||
976 | case -ENOMEM: | ||
977 | rpc_delay(task, HZ >> 2); | ||
978 | dprintk("RPC: dynamic allocation of request slot " | ||
979 | "failed! Retrying\n"); | ||
980 | break; | ||
981 | case -EAGAIN: | ||
982 | rpc_sleep_on(&xprt->backlog, task, NULL); | ||
983 | dprintk("RPC: waiting for request slot\n"); | ||
949 | } | 984 | } |
950 | dprintk("RPC: waiting for request slot\n"); | ||
951 | task->tk_status = -EAGAIN; | 985 | task->tk_status = -EAGAIN; |
952 | rpc_sleep_on(&xprt->backlog, task, NULL); | 986 | return; |
987 | out_init_req: | ||
988 | task->tk_status = 0; | ||
989 | task->tk_rqstp = req; | ||
990 | xprt_request_init(task, xprt); | ||
953 | } | 991 | } |
954 | 992 | ||
955 | static void xprt_free_slot(struct rpc_xprt *xprt, struct rpc_rqst *req) | 993 | static void xprt_free_slot(struct rpc_xprt *xprt, struct rpc_rqst *req) |
956 | { | 994 | { |
995 | if (xprt_dynamic_free_slot(xprt, req)) | ||
996 | return; | ||
997 | |||
957 | memset(req, 0, sizeof(*req)); /* mark unused */ | 998 | memset(req, 0, sizeof(*req)); /* mark unused */ |
958 | 999 | ||
959 | spin_lock(&xprt->reserve_lock); | 1000 | spin_lock(&xprt->reserve_lock); |
@@ -972,7 +1013,9 @@ static void xprt_free_all_slots(struct rpc_xprt *xprt) | |||
972 | } | 1013 | } |
973 | } | 1014 | } |
974 | 1015 | ||
975 | struct rpc_xprt *xprt_alloc(struct net *net, int size, int num_prealloc) | 1016 | struct rpc_xprt *xprt_alloc(struct net *net, size_t size, |
1017 | unsigned int num_prealloc, | ||
1018 | unsigned int max_alloc) | ||
976 | { | 1019 | { |
977 | struct rpc_xprt *xprt; | 1020 | struct rpc_xprt *xprt; |
978 | struct rpc_rqst *req; | 1021 | struct rpc_rqst *req; |
@@ -992,7 +1035,12 @@ struct rpc_xprt *xprt_alloc(struct net *net, int size, int num_prealloc) | |||
992 | } | 1035 | } |
993 | if (i < num_prealloc) | 1036 | if (i < num_prealloc) |
994 | goto out_free; | 1037 | goto out_free; |
995 | xprt->max_reqs = num_prealloc; | 1038 | if (max_alloc > num_prealloc) |
1039 | xprt->max_reqs = max_alloc; | ||
1040 | else | ||
1041 | xprt->max_reqs = num_prealloc; | ||
1042 | xprt->min_reqs = num_prealloc; | ||
1043 | atomic_set(&xprt->num_reqs, num_prealloc); | ||
996 | 1044 | ||
997 | return xprt; | 1045 | return xprt; |
998 | 1046 | ||
@@ -1036,7 +1084,6 @@ void xprt_reserve(struct rpc_task *task) | |||
1036 | if (!xprt_lock_write(xprt, task)) | 1084 | if (!xprt_lock_write(xprt, task)) |
1037 | return; | 1085 | return; |
1038 | 1086 | ||
1039 | task->tk_status = -EIO; | ||
1040 | spin_lock(&xprt->reserve_lock); | 1087 | spin_lock(&xprt->reserve_lock); |
1041 | xprt_alloc_slot(task); | 1088 | xprt_alloc_slot(task); |
1042 | spin_unlock(&xprt->reserve_lock); | 1089 | spin_unlock(&xprt->reserve_lock); |
@@ -1057,6 +1104,7 @@ static void xprt_request_init(struct rpc_task *task, struct rpc_xprt *xprt) | |||
1057 | { | 1104 | { |
1058 | struct rpc_rqst *req = task->tk_rqstp; | 1105 | struct rpc_rqst *req = task->tk_rqstp; |
1059 | 1106 | ||
1107 | INIT_LIST_HEAD(&req->rq_list); | ||
1060 | req->rq_timeout = task->tk_client->cl_timeout->to_initval; | 1108 | req->rq_timeout = task->tk_client->cl_timeout->to_initval; |
1061 | req->rq_task = task; | 1109 | req->rq_task = task; |
1062 | req->rq_xprt = xprt; | 1110 | req->rq_xprt = xprt; |
diff --git a/net/sunrpc/xprtrdma/transport.c b/net/sunrpc/xprtrdma/transport.c index 674a49224450..b446e100286f 100644 --- a/net/sunrpc/xprtrdma/transport.c +++ b/net/sunrpc/xprtrdma/transport.c | |||
@@ -283,6 +283,7 @@ xprt_setup_rdma(struct xprt_create *args) | |||
283 | } | 283 | } |
284 | 284 | ||
285 | xprt = xprt_alloc(args->net, sizeof(struct rpcrdma_xprt), | 285 | xprt = xprt_alloc(args->net, sizeof(struct rpcrdma_xprt), |
286 | xprt_rdma_slot_table_entries, | ||
286 | xprt_rdma_slot_table_entries); | 287 | xprt_rdma_slot_table_entries); |
287 | if (xprt == NULL) { | 288 | if (xprt == NULL) { |
288 | dprintk("RPC: %s: couldn't allocate rpcrdma_xprt\n", | 289 | dprintk("RPC: %s: couldn't allocate rpcrdma_xprt\n", |
diff --git a/net/sunrpc/xprtsock.c b/net/sunrpc/xprtsock.c index adaa54c6a09a..d7f97ef26590 100644 --- a/net/sunrpc/xprtsock.c +++ b/net/sunrpc/xprtsock.c | |||
@@ -54,7 +54,8 @@ static void xs_close(struct rpc_xprt *xprt); | |||
54 | * xprtsock tunables | 54 | * xprtsock tunables |
55 | */ | 55 | */ |
56 | unsigned int xprt_udp_slot_table_entries = RPC_DEF_SLOT_TABLE; | 56 | unsigned int xprt_udp_slot_table_entries = RPC_DEF_SLOT_TABLE; |
57 | unsigned int xprt_tcp_slot_table_entries = RPC_DEF_SLOT_TABLE; | 57 | unsigned int xprt_tcp_slot_table_entries = RPC_MIN_SLOT_TABLE; |
58 | unsigned int xprt_max_tcp_slot_table_entries = RPC_MAX_SLOT_TABLE; | ||
58 | 59 | ||
59 | unsigned int xprt_min_resvport = RPC_DEF_MIN_RESVPORT; | 60 | unsigned int xprt_min_resvport = RPC_DEF_MIN_RESVPORT; |
60 | unsigned int xprt_max_resvport = RPC_DEF_MAX_RESVPORT; | 61 | unsigned int xprt_max_resvport = RPC_DEF_MAX_RESVPORT; |
@@ -75,6 +76,7 @@ static unsigned int xs_tcp_fin_timeout __read_mostly = XS_TCP_LINGER_TO; | |||
75 | 76 | ||
76 | static unsigned int min_slot_table_size = RPC_MIN_SLOT_TABLE; | 77 | static unsigned int min_slot_table_size = RPC_MIN_SLOT_TABLE; |
77 | static unsigned int max_slot_table_size = RPC_MAX_SLOT_TABLE; | 78 | static unsigned int max_slot_table_size = RPC_MAX_SLOT_TABLE; |
79 | static unsigned int max_tcp_slot_table_limit = RPC_MAX_SLOT_TABLE_LIMIT; | ||
78 | static unsigned int xprt_min_resvport_limit = RPC_MIN_RESVPORT; | 80 | static unsigned int xprt_min_resvport_limit = RPC_MIN_RESVPORT; |
79 | static unsigned int xprt_max_resvport_limit = RPC_MAX_RESVPORT; | 81 | static unsigned int xprt_max_resvport_limit = RPC_MAX_RESVPORT; |
80 | 82 | ||
@@ -104,6 +106,15 @@ static ctl_table xs_tunables_table[] = { | |||
104 | .extra2 = &max_slot_table_size | 106 | .extra2 = &max_slot_table_size |
105 | }, | 107 | }, |
106 | { | 108 | { |
109 | .procname = "tcp_max_slot_table_entries", | ||
110 | .data = &xprt_max_tcp_slot_table_entries, | ||
111 | .maxlen = sizeof(unsigned int), | ||
112 | .mode = 0644, | ||
113 | .proc_handler = proc_dointvec_minmax, | ||
114 | .extra1 = &min_slot_table_size, | ||
115 | .extra2 = &max_tcp_slot_table_limit | ||
116 | }, | ||
117 | { | ||
107 | .procname = "min_resvport", | 118 | .procname = "min_resvport", |
108 | .data = &xprt_min_resvport, | 119 | .data = &xprt_min_resvport, |
109 | .maxlen = sizeof(unsigned int), | 120 | .maxlen = sizeof(unsigned int), |
@@ -2491,7 +2502,8 @@ static int xs_init_anyaddr(const int family, struct sockaddr *sap) | |||
2491 | } | 2502 | } |
2492 | 2503 | ||
2493 | static struct rpc_xprt *xs_setup_xprt(struct xprt_create *args, | 2504 | static struct rpc_xprt *xs_setup_xprt(struct xprt_create *args, |
2494 | unsigned int slot_table_size) | 2505 | unsigned int slot_table_size, |
2506 | unsigned int max_slot_table_size) | ||
2495 | { | 2507 | { |
2496 | struct rpc_xprt *xprt; | 2508 | struct rpc_xprt *xprt; |
2497 | struct sock_xprt *new; | 2509 | struct sock_xprt *new; |
@@ -2501,7 +2513,8 @@ static struct rpc_xprt *xs_setup_xprt(struct xprt_create *args, | |||
2501 | return ERR_PTR(-EBADF); | 2513 | return ERR_PTR(-EBADF); |
2502 | } | 2514 | } |
2503 | 2515 | ||
2504 | xprt = xprt_alloc(args->net, sizeof(*new), slot_table_size); | 2516 | xprt = xprt_alloc(args->net, sizeof(*new), slot_table_size, |
2517 | max_slot_table_size); | ||
2505 | if (xprt == NULL) { | 2518 | if (xprt == NULL) { |
2506 | dprintk("RPC: xs_setup_xprt: couldn't allocate " | 2519 | dprintk("RPC: xs_setup_xprt: couldn't allocate " |
2507 | "rpc_xprt\n"); | 2520 | "rpc_xprt\n"); |
@@ -2543,7 +2556,8 @@ static struct rpc_xprt *xs_setup_local(struct xprt_create *args) | |||
2543 | struct rpc_xprt *xprt; | 2556 | struct rpc_xprt *xprt; |
2544 | struct rpc_xprt *ret; | 2557 | struct rpc_xprt *ret; |
2545 | 2558 | ||
2546 | xprt = xs_setup_xprt(args, xprt_tcp_slot_table_entries); | 2559 | xprt = xs_setup_xprt(args, xprt_tcp_slot_table_entries, |
2560 | xprt_max_tcp_slot_table_entries); | ||
2547 | if (IS_ERR(xprt)) | 2561 | if (IS_ERR(xprt)) |
2548 | return xprt; | 2562 | return xprt; |
2549 | transport = container_of(xprt, struct sock_xprt, xprt); | 2563 | transport = container_of(xprt, struct sock_xprt, xprt); |
@@ -2607,7 +2621,8 @@ static struct rpc_xprt *xs_setup_udp(struct xprt_create *args) | |||
2607 | struct sock_xprt *transport; | 2621 | struct sock_xprt *transport; |
2608 | struct rpc_xprt *ret; | 2622 | struct rpc_xprt *ret; |
2609 | 2623 | ||
2610 | xprt = xs_setup_xprt(args, xprt_udp_slot_table_entries); | 2624 | xprt = xs_setup_xprt(args, xprt_udp_slot_table_entries, |
2625 | xprt_udp_slot_table_entries); | ||
2611 | if (IS_ERR(xprt)) | 2626 | if (IS_ERR(xprt)) |
2612 | return xprt; | 2627 | return xprt; |
2613 | transport = container_of(xprt, struct sock_xprt, xprt); | 2628 | transport = container_of(xprt, struct sock_xprt, xprt); |
@@ -2683,7 +2698,8 @@ static struct rpc_xprt *xs_setup_tcp(struct xprt_create *args) | |||
2683 | struct sock_xprt *transport; | 2698 | struct sock_xprt *transport; |
2684 | struct rpc_xprt *ret; | 2699 | struct rpc_xprt *ret; |
2685 | 2700 | ||
2686 | xprt = xs_setup_xprt(args, xprt_tcp_slot_table_entries); | 2701 | xprt = xs_setup_xprt(args, xprt_tcp_slot_table_entries, |
2702 | xprt_max_tcp_slot_table_entries); | ||
2687 | if (IS_ERR(xprt)) | 2703 | if (IS_ERR(xprt)) |
2688 | return xprt; | 2704 | return xprt; |
2689 | transport = container_of(xprt, struct sock_xprt, xprt); | 2705 | transport = container_of(xprt, struct sock_xprt, xprt); |
@@ -2762,7 +2778,8 @@ static struct rpc_xprt *xs_setup_bc_tcp(struct xprt_create *args) | |||
2762 | */ | 2778 | */ |
2763 | return args->bc_xprt->xpt_bc_xprt; | 2779 | return args->bc_xprt->xpt_bc_xprt; |
2764 | } | 2780 | } |
2765 | xprt = xs_setup_xprt(args, xprt_tcp_slot_table_entries); | 2781 | xprt = xs_setup_xprt(args, xprt_tcp_slot_table_entries, |
2782 | xprt_tcp_slot_table_entries); | ||
2766 | if (IS_ERR(xprt)) | 2783 | if (IS_ERR(xprt)) |
2767 | return xprt; | 2784 | return xprt; |
2768 | transport = container_of(xprt, struct sock_xprt, xprt); | 2785 | transport = container_of(xprt, struct sock_xprt, xprt); |
@@ -2949,8 +2966,26 @@ static struct kernel_param_ops param_ops_slot_table_size = { | |||
2949 | #define param_check_slot_table_size(name, p) \ | 2966 | #define param_check_slot_table_size(name, p) \ |
2950 | __param_check(name, p, unsigned int); | 2967 | __param_check(name, p, unsigned int); |
2951 | 2968 | ||
2969 | static int param_set_max_slot_table_size(const char *val, | ||
2970 | const struct kernel_param *kp) | ||
2971 | { | ||
2972 | return param_set_uint_minmax(val, kp, | ||
2973 | RPC_MIN_SLOT_TABLE, | ||
2974 | RPC_MAX_SLOT_TABLE_LIMIT); | ||
2975 | } | ||
2976 | |||
2977 | static struct kernel_param_ops param_ops_max_slot_table_size = { | ||
2978 | .set = param_set_max_slot_table_size, | ||
2979 | .get = param_get_uint, | ||
2980 | }; | ||
2981 | |||
2982 | #define param_check_max_slot_table_size(name, p) \ | ||
2983 | __param_check(name, p, unsigned int); | ||
2984 | |||
2952 | module_param_named(tcp_slot_table_entries, xprt_tcp_slot_table_entries, | 2985 | module_param_named(tcp_slot_table_entries, xprt_tcp_slot_table_entries, |
2953 | slot_table_size, 0644); | 2986 | slot_table_size, 0644); |
2987 | module_param_named(tcp_max_slot_table_entries, xprt_max_tcp_slot_table_entries, | ||
2988 | max_slot_table_size, 0644); | ||
2954 | module_param_named(udp_slot_table_entries, xprt_udp_slot_table_entries, | 2989 | module_param_named(udp_slot_table_entries, xprt_udp_slot_table_entries, |
2955 | slot_table_size, 0644); | 2990 | slot_table_size, 0644); |
2956 | 2991 | ||