Patchwork nfs broken in net-next? -- now in mainline -- bisected: d9f5950f90292f7cc42834338dfd5f44dc4cc4ca

login
register
mail settings
Submitter Eric Dumazet
Date Dec. 13, 2009, 4:57 p.m.
Message ID <4B251CE4.9080401@gmail.com>
Download mbox | patch
Permalink /patch/41042/
State Accepted
Delegated to: David Miller
Headers show

Comments

Eric Dumazet - Dec. 13, 2009, 4:57 p.m.
Le 13/12/2009 03:41, Yinghai Lu a écrit :
>
>>> cause the problem: nfs mount fail.
>>>
>>> the setup is:
>>> 64bit kernel, have all needed drivers in kernel, and boot with
>>> ip=dhcp, root disk is 256M ramdisk.
>>> then try to mount nfs....
>>>
>>
>> change entries default value from 65536 to 256,
>> nfs mount will work.
>>
> interesting:
> 
> m:~/dump # grep UDP dmesg.txt
> [   28.996034] UDP hash table entries: 65536 (order: 11, 10485760 bytes)
> [   29.032364] UDP-Lite hash table entries: 65536 (order: 11, 10485760 bytes)
> 
> will not work
> 
> but 32768 will work.

Thanks a lot for this work Yinghai !
This last bit helped me a lot ...

Hmm, udp_lib_get_port() assumes it can loop at least one time in :

for (last = first + udptable->mask + 1;
	first != last;
	first++) {
// unit_work
}

but if udptable->mask == 65535, loop is not entered at all (since last == first)

We should convert it to a do { } while(...); construct, or use 32bit variables
and (u16) casts.

Thanks

[PATCH] udp: udp_lib_get_port() fix

Now we can have a large udp hash table, udp_lib_get_port() loop
should be converted to a do {} while (cond) form,
or we dont enter it at all if hash table size is exactly 65536.

Reported-by: Yinghai Lu <yinghai@kernel.org>
Signed-off-by: Eric Dumazet <eric.dumazet@gmail.com>
---
--
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
Yinghai Lu - Dec. 13, 2009, 10:28 p.m.
Eric Dumazet wrote:
> Le 13/12/2009 03:41, Yinghai Lu a écrit :
>>>> cause the problem: nfs mount fail.
>>>>
>>>> the setup is:
>>>> 64bit kernel, have all needed drivers in kernel, and boot with
>>>> ip=dhcp, root disk is 256M ramdisk.
>>>> then try to mount nfs....
>>>>
>>> change entries default value from 65536 to 256,
>>> nfs mount will work.
>>>
>> interesting:
>>
>> m:~/dump # grep UDP dmesg.txt
>> [   28.996034] UDP hash table entries: 65536 (order: 11, 10485760 bytes)
>> [   29.032364] UDP-Lite hash table entries: 65536 (order: 11, 10485760 bytes)
>>
>> will not work
>>
>> but 32768 will work.
> 
> Thanks a lot for this work Yinghai !
> This last bit helped me a lot ...
> 
> Hmm, udp_lib_get_port() assumes it can loop at least one time in :
> 
> for (last = first + udptable->mask + 1;
> 	first != last;
> 	first++) {
> // unit_work
> }
> 
> but if udptable->mask == 65535, loop is not entered at all (since last == first)
> 
> We should convert it to a do { } while(...); construct, or use 32bit variables
> and (u16) casts.
> 
> Thanks
> 
> [PATCH] udp: udp_lib_get_port() fix
> 
> Now we can have a large udp hash table, udp_lib_get_port() loop
> should be converted to a do {} while (cond) form,
> or we dont enter it at all if hash table size is exactly 65536.
> 
> Reported-by: Yinghai Lu <yinghai@kernel.org>
> Signed-off-by: Eric Dumazet <eric.dumazet@gmail.com>
> ---
> diff --git a/net/ipv4/udp.c b/net/ipv4/udp.c
> index 1f95348..f0126fd 100644
> --- a/net/ipv4/udp.c
> +++ b/net/ipv4/udp.c
> @@ -216,9 +216,8 @@ int udp_lib_get_port(struct sock *sk, unsigned short snum,
>  		 * force rand to be an odd multiple of UDP_HTABLE_SIZE
>  		 */
>  		rand = (rand | 1) * (udptable->mask + 1);
> -		for (last = first + udptable->mask + 1;
> -		     first != last;
> -		     first++) {
> +		last = first + udptable->mask + 1;
> +		do {
>  			hslot = udp_hashslot(udptable, net, first);
>  			bitmap_zero(bitmap, PORTS_PER_CHAIN);
>  			spin_lock_bh(&hslot->lock);
> @@ -238,7 +237,7 @@ int udp_lib_get_port(struct sock *sk, unsigned short snum,
>  				snum += rand;
>  			} while (snum != first);
>  			spin_unlock_bh(&hslot->lock);
> -		}
> +		} while (++first != last);
>  		goto fail;
>  	} else {
>  		hslot = udp_hashslot(udptable, net, snum);

thanks. that fix the problem.

YH
--
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
David Miller - Dec. 14, 2009, 3:33 a.m.
From: Yinghai Lu <yinghai@kernel.org>
Date: Sun, 13 Dec 2009 14:28:14 -0800

> Eric Dumazet wrote:
>> [PATCH] udp: udp_lib_get_port() fix
>> 
>> Now we can have a large udp hash table, udp_lib_get_port() loop
>> should be converted to a do {} while (cond) form,
>> or we dont enter it at all if hash table size is exactly 65536.
>> 
>> Reported-by: Yinghai Lu <yinghai@kernel.org>
>> Signed-off-by: Eric Dumazet <eric.dumazet@gmail.com>
 ...
> thanks. that fix the problem.

Applied, thanks everyone.
--
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

Patch

diff --git a/net/ipv4/udp.c b/net/ipv4/udp.c
index 1f95348..f0126fd 100644
--- a/net/ipv4/udp.c
+++ b/net/ipv4/udp.c
@@ -216,9 +216,8 @@  int udp_lib_get_port(struct sock *sk, unsigned short snum,
 		 * force rand to be an odd multiple of UDP_HTABLE_SIZE
 		 */
 		rand = (rand | 1) * (udptable->mask + 1);
-		for (last = first + udptable->mask + 1;
-		     first != last;
-		     first++) {
+		last = first + udptable->mask + 1;
+		do {
 			hslot = udp_hashslot(udptable, net, first);
 			bitmap_zero(bitmap, PORTS_PER_CHAIN);
 			spin_lock_bh(&hslot->lock);
@@ -238,7 +237,7 @@  int udp_lib_get_port(struct sock *sk, unsigned short snum,
 				snum += rand;
 			} while (snum != first);
 			spin_unlock_bh(&hslot->lock);
-		}
+		} while (++first != last);
 		goto fail;
 	} else {
 		hslot = udp_hashslot(udptable, net, snum);