Message ID | 20101122225421.GA7372@core2.telecom.by |
---|---|
State | Accepted, archived |
Delegated to: | David Miller |
Headers | show |
From: Alexey Dobriyan <adobriyan@gmail.com> Date: Tue, 23 Nov 2010 00:54:21 +0200 > tcp_win_from_space() does the following: > > if (sysctl_tcp_adv_win_scale <= 0) > return space >> (-sysctl_tcp_adv_win_scale); > else > return space - (space >> sysctl_tcp_adv_win_scale); > > "space" is int. > > As per C99 6.5.7 (3) shifting int for 32 or more bits is > undefined behaviour. > > Indeed, if sysctl_tcp_adv_win_scale is exactly 32, > space >> 32 equals space and function returns 0. > > Which means we busyloop in tcp_fixup_rcvbuf(). > > Restrict net.ipv4.tcp_adv_win_scale to [-31, 31]. > > Fix https://bugzilla.kernel.org/show_bug.cgi?id=20312 > > Steps to reproduce: > > echo 32 >/proc/sys/net/ipv4/tcp_adv_win_scale > wget www.kernel.org > [softlockup] > > Signed-off-by: Alexey Dobriyan <adobriyan@gmail.com> I'll aply this, thanks Alexey. -- To unsubscribe from this list: send the line "unsubscribe netdev" in the body of a message to majordomo@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html
--- a/Documentation/networking/ip-sysctl.txt +++ b/Documentation/networking/ip-sysctl.txt @@ -144,6 +144,7 @@ tcp_adv_win_scale - INTEGER Count buffering overhead as bytes/2^tcp_adv_win_scale (if tcp_adv_win_scale > 0) or bytes-bytes/2^(-tcp_adv_win_scale), if it is <= 0. + Possible values are [-31, 31], inclusive. Default: 2 tcp_allowed_congestion_control - STRING --- a/net/ipv4/sysctl_net_ipv4.c +++ b/net/ipv4/sysctl_net_ipv4.c @@ -26,6 +26,8 @@ static int zero; static int tcp_retr1_max = 255; static int ip_local_port_range_min[] = { 1, 1 }; static int ip_local_port_range_max[] = { 65535, 65535 }; +static int tcp_adv_win_scale_min = -31; +static int tcp_adv_win_scale_max = 31; /* Update system visible IP port range */ static void set_local_port_range(int range[2]) @@ -426,7 +428,9 @@ static struct ctl_table ipv4_table[] = { .data = &sysctl_tcp_adv_win_scale, .maxlen = sizeof(int), .mode = 0644, - .proc_handler = proc_dointvec + .proc_handler = proc_dointvec_minmax, + .extra1 = &tcp_adv_win_scale_min, + .extra2 = &tcp_adv_win_scale_max, }, { .procname = "tcp_tw_reuse",
tcp_win_from_space() does the following: if (sysctl_tcp_adv_win_scale <= 0) return space >> (-sysctl_tcp_adv_win_scale); else return space - (space >> sysctl_tcp_adv_win_scale); "space" is int. As per C99 6.5.7 (3) shifting int for 32 or more bits is undefined behaviour. Indeed, if sysctl_tcp_adv_win_scale is exactly 32, space >> 32 equals space and function returns 0. Which means we busyloop in tcp_fixup_rcvbuf(). Restrict net.ipv4.tcp_adv_win_scale to [-31, 31]. Fix https://bugzilla.kernel.org/show_bug.cgi?id=20312 Steps to reproduce: echo 32 >/proc/sys/net/ipv4/tcp_adv_win_scale wget www.kernel.org [softlockup] Signed-off-by: Alexey Dobriyan <adobriyan@gmail.com> --- Documentation/networking/ip-sysctl.txt | 1 + net/ipv4/sysctl_net_ipv4.c | 6 +++++- 2 files changed, 6 insertions(+), 1 deletion(-) -- To unsubscribe from this list: send the line "unsubscribe netdev" in the body of a message to majordomo@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html