--- include/linux/sunrpc/xprt.h 2004/11/04 23:38:00 1.1 +++ include/linux/sunrpc/xprt.h 2004/11/06 21:01:38 @@ -54,10 +54,11 @@ #define RPC_CONNECT_TIMEOUT (60*HZ) /* - * Delay an arbitrary number of seconds before attempting to reconnect - * after an error. + * Throttle TCP reconnection to once per RPC_RECONNECT_DELAY/HZ seconds, + * with a burst of RPC_RECONNECT_BURST. */ -#define RPC_REESTABLISH_TIMEOUT (15*HZ) +#define RPC_RECONNECT_DELAY (15*HZ) +#define RPC_RECONNECT_BURST 5 /* RPC call and reply header size as number of 32bit words (verifier * size computed separately) @@ -172,6 +173,8 @@ */ struct work_struct sock_connect; unsigned short port; + unsigned long last_connect; + long reconnect_toks; /* * Disconnection of idle sockets */ --- net/sunrpc/xprt.c 2004/11/04 23:39:37 1.1 +++ net/sunrpc/xprt.c 2004/11/06 21:03:43 @@ -560,15 +560,27 @@ task->tk_timeout = RPC_CONNECT_TIMEOUT; rpc_sleep_on(&xprt->pending, task, xprt_connect_status, NULL); if (!test_and_set_bit(XPRT_CONNECTING, &xprt->sockstate)) { - /* Note: if we are here due to a dropped connection - * we delay reconnecting by RPC_REESTABLISH_TIMEOUT/HZ - * seconds + /* Note: if we are here due to a dropped connection, we + * rate-limit reconnecting to an average rate of once + * per RPC_RECONNECT_DELAY/HZ seconds, with a burst + * of RPC_RECONNECT_BURST. Logic is borrowed from + * kernel/printk.c, except tokens can go negative when + * we schedule_delayed_work(). */ - if (xprt->sock != NULL) - schedule_delayed_work(&xprt->sock_connect, - RPC_REESTABLISH_TIMEOUT); - else + static unsigned long max_toks = RPC_RECONNECT_DELAY * + RPC_RECONNECT_BURST; + unsigned long now = jiffies; + xprt->reconnect_toks += min(now - xprt->last_connect, max_toks); + xprt->last_connect = now; + if (xprt->sock == NULL || xprt->reconnect_toks > max_toks) + xprt->reconnect_toks = max_toks; + + xprt->reconnect_toks -= RPC_RECONNECT_DELAY; + if (xprt->reconnect_toks >= 0) schedule_work(&xprt->sock_connect); + else + schedule_delayed_work(&xprt->sock_connect, + RPC_RECONNECT_DELAY); } return; out_write: @@ -1264,7 +1276,7 @@ rpc_delay(task, HZ>>4); return; case -ECONNREFUSED: - task->tk_timeout = RPC_REESTABLISH_TIMEOUT; + task->tk_timeout = RPC_RECONNECT_DELAY; rpc_sleep_on(&xprt->sending, task, NULL, NULL); case -ENOTCONN: return;