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

SUNRPC: Allow changing of the TCP timeout parameters on the fly

When the NFSv4 server tells us the lease period, we usually want
to adjust down the timeout parameters on the TCP connection to
ensure that we don't miss lease renewals due to a faulty connection.

Signed-off-by: Trond Myklebust <trond.myklebust@primarydata.com>
Signed-off-by: Anna Schumaker <Anna.Schumaker@Netapp.com>

authored by

Trond Myklebust and committed by
Anna Schumaker
7196dbb0 8d1b8c62

+77 -11
+4
include/linux/sunrpc/xprt.h
··· 137 137 void (*release_request)(struct rpc_task *task); 138 138 void (*close)(struct rpc_xprt *xprt); 139 139 void (*destroy)(struct rpc_xprt *xprt); 140 + void (*set_connect_timeout)(struct rpc_xprt *xprt, 141 + unsigned long connect_timeout, 142 + unsigned long reconnect_timeout); 140 143 void (*print_stats)(struct rpc_xprt *xprt, struct seq_file *seq); 141 144 int (*enable_swap)(struct rpc_xprt *xprt); 142 145 void (*disable_swap)(struct rpc_xprt *xprt); ··· 224 221 struct timer_list timer; 225 222 unsigned long last_used, 226 223 idle_timeout, 224 + connect_timeout, 227 225 max_reconnect_timeout; 228 226 229 227 /*
+3
include/linux/sunrpc/xprtsock.h
··· 55 55 size_t rcvsize, 56 56 sndsize; 57 57 58 + struct rpc_timeout tcp_timeout; 59 + 58 60 /* 59 61 * Saved socket callback addresses 60 62 */ ··· 83 81 84 82 #define XPRT_SOCK_CONNECTING 1U 85 83 #define XPRT_SOCK_DATA_READY (2) 84 + #define XPRT_SOCK_UPD_TIMEOUT (3) 86 85 87 86 #endif /* __KERNEL__ */ 88 87
+23 -7
net/sunrpc/clnt.c
··· 2684 2684 { 2685 2685 struct rpc_xprt_switch *xps; 2686 2686 struct rpc_xprt *xprt; 2687 + unsigned long connect_timeout; 2687 2688 unsigned long reconnect_timeout; 2688 2689 unsigned char resvport; 2689 2690 int ret = 0; ··· 2697 2696 return -EAGAIN; 2698 2697 } 2699 2698 resvport = xprt->resvport; 2699 + connect_timeout = xprt->connect_timeout; 2700 2700 reconnect_timeout = xprt->max_reconnect_timeout; 2701 2701 rcu_read_unlock(); 2702 2702 ··· 2707 2705 goto out_put_switch; 2708 2706 } 2709 2707 xprt->resvport = resvport; 2710 - xprt->max_reconnect_timeout = reconnect_timeout; 2708 + if (xprt->ops->set_connect_timeout != NULL) 2709 + xprt->ops->set_connect_timeout(xprt, 2710 + connect_timeout, 2711 + reconnect_timeout); 2711 2712 2712 2713 rpc_xprt_switch_set_roundrobin(xps); 2713 2714 if (setup) { ··· 2727 2722 } 2728 2723 EXPORT_SYMBOL_GPL(rpc_clnt_add_xprt); 2729 2724 2725 + struct connect_timeout_data { 2726 + unsigned long connect_timeout; 2727 + unsigned long reconnect_timeout; 2728 + }; 2729 + 2730 2730 static int 2731 - rpc_xprt_cap_max_reconnect_timeout(struct rpc_clnt *clnt, 2731 + rpc_xprt_set_connect_timeout(struct rpc_clnt *clnt, 2732 2732 struct rpc_xprt *xprt, 2733 2733 void *data) 2734 2734 { 2735 - unsigned long timeout = *((unsigned long *)data); 2735 + struct connect_timeout_data *timeo = data; 2736 2736 2737 - if (timeout < xprt->max_reconnect_timeout) 2738 - xprt->max_reconnect_timeout = timeout; 2737 + if (xprt->ops->set_connect_timeout) 2738 + xprt->ops->set_connect_timeout(xprt, 2739 + timeo->connect_timeout, 2740 + timeo->reconnect_timeout); 2739 2741 return 0; 2740 2742 } 2741 2743 2742 2744 void 2743 2745 rpc_cap_max_reconnect_timeout(struct rpc_clnt *clnt, unsigned long timeo) 2744 2746 { 2747 + struct connect_timeout_data timeout = { 2748 + .connect_timeout = timeo, 2749 + .reconnect_timeout = timeo, 2750 + }; 2745 2751 rpc_clnt_iterate_for_each_xprt(clnt, 2746 - rpc_xprt_cap_max_reconnect_timeout, 2747 - &timeo); 2752 + rpc_xprt_set_connect_timeout, 2753 + &timeout); 2748 2754 } 2749 2755 EXPORT_SYMBOL_GPL(rpc_cap_max_reconnect_timeout); 2750 2756
+47 -4
net/sunrpc/xprtsock.c
··· 52 52 #include "sunrpc.h" 53 53 54 54 static void xs_close(struct rpc_xprt *xprt); 55 + static void xs_tcp_set_socket_timeouts(struct rpc_xprt *xprt, 56 + struct socket *sock); 55 57 56 58 /* 57 59 * xprtsock tunables ··· 667 665 */ 668 666 if (task->tk_flags & RPC_TASK_SENT) 669 667 zerocopy = false; 668 + 669 + if (test_bit(XPRT_SOCK_UPD_TIMEOUT, &transport->sock_state)) 670 + xs_tcp_set_socket_timeouts(xprt, transport->sock); 670 671 671 672 /* Continue transmitting the packet/record. We must be careful 672 673 * to cope with writespace callbacks arriving _after_ we have ··· 2243 2238 static void xs_tcp_set_socket_timeouts(struct rpc_xprt *xprt, 2244 2239 struct socket *sock) 2245 2240 { 2246 - unsigned int keepidle = DIV_ROUND_UP(xprt->timeout->to_initval, HZ); 2247 - unsigned int keepcnt = xprt->timeout->to_retries + 1; 2241 + struct sock_xprt *transport = container_of(xprt, struct sock_xprt, xprt); 2242 + unsigned int keepidle; 2243 + unsigned int keepcnt; 2248 2244 unsigned int opt_on = 1; 2249 2245 unsigned int timeo; 2246 + 2247 + spin_lock_bh(&xprt->transport_lock); 2248 + keepidle = DIV_ROUND_UP(xprt->timeout->to_initval, HZ); 2249 + keepcnt = xprt->timeout->to_retries + 1; 2250 + timeo = jiffies_to_msecs(xprt->timeout->to_initval) * 2251 + (xprt->timeout->to_retries + 1); 2252 + clear_bit(XPRT_SOCK_UPD_TIMEOUT, &transport->sock_state); 2253 + spin_unlock_bh(&xprt->transport_lock); 2250 2254 2251 2255 /* TCP Keepalive options */ 2252 2256 kernel_setsockopt(sock, SOL_SOCKET, SO_KEEPALIVE, ··· 2268 2254 (char *)&keepcnt, sizeof(keepcnt)); 2269 2255 2270 2256 /* TCP user timeout (see RFC5482) */ 2271 - timeo = jiffies_to_msecs(xprt->timeout->to_initval) * 2272 - (xprt->timeout->to_retries + 1); 2273 2257 kernel_setsockopt(sock, SOL_TCP, TCP_USER_TIMEOUT, 2274 2258 (char *)&timeo, sizeof(timeo)); 2259 + } 2260 + 2261 + static void xs_tcp_set_connect_timeout(struct rpc_xprt *xprt, 2262 + unsigned long connect_timeout, 2263 + unsigned long reconnect_timeout) 2264 + { 2265 + struct sock_xprt *transport = container_of(xprt, struct sock_xprt, xprt); 2266 + struct rpc_timeout to; 2267 + unsigned long initval; 2268 + 2269 + spin_lock_bh(&xprt->transport_lock); 2270 + if (reconnect_timeout < xprt->max_reconnect_timeout) 2271 + xprt->max_reconnect_timeout = reconnect_timeout; 2272 + if (connect_timeout < xprt->connect_timeout) { 2273 + memcpy(&to, xprt->timeout, sizeof(to)); 2274 + initval = DIV_ROUND_UP(connect_timeout, to.to_retries + 1); 2275 + /* Arbitrary lower limit */ 2276 + if (initval < XS_TCP_INIT_REEST_TO << 1) 2277 + initval = XS_TCP_INIT_REEST_TO << 1; 2278 + to.to_initval = initval; 2279 + to.to_maxval = initval; 2280 + memcpy(&transport->tcp_timeout, &to, 2281 + sizeof(transport->tcp_timeout)); 2282 + xprt->timeout = &transport->tcp_timeout; 2283 + xprt->connect_timeout = connect_timeout; 2284 + } 2285 + set_bit(XPRT_SOCK_UPD_TIMEOUT, &transport->sock_state); 2286 + spin_unlock_bh(&xprt->transport_lock); 2275 2287 } 2276 2288 2277 2289 static int xs_tcp_finish_connecting(struct rpc_xprt *xprt, struct socket *sock) ··· 2768 2728 .set_retrans_timeout = xprt_set_retrans_timeout_def, 2769 2729 .close = xs_tcp_shutdown, 2770 2730 .destroy = xs_destroy, 2731 + .set_connect_timeout = xs_tcp_set_connect_timeout, 2771 2732 .print_stats = xs_tcp_print_stats, 2772 2733 .enable_swap = xs_enable_swap, 2773 2734 .disable_swap = xs_disable_swap, ··· 3055 3014 xprt->timeout = &xs_tcp_default_timeout; 3056 3015 3057 3016 xprt->max_reconnect_timeout = xprt->timeout->to_maxval; 3017 + xprt->connect_timeout = xprt->timeout->to_initval * 3018 + (xprt->timeout->to_retries + 1); 3058 3019 3059 3020 INIT_WORK(&transport->recv_worker, xs_tcp_data_receive_workfn); 3060 3021 INIT_DELAYED_WORK(&transport->connect_worker, xs_tcp_setup_socket);