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

sctp: Fix port hash table size computation

Dmitry Vyukov noted recently that the sctp_port_hashtable had an error in
its size computation, observing that the current method never guaranteed
that the hashsize (measured in number of entries) would be a power of two,
which the input hash function for that table requires. The root cause of
the problem is that two values need to be computed (one, the allocation
order of the storage requries, as passed to __get_free_pages, and two the
number of entries for the hash table). Both need to be ^2, but for
different reasons, and the existing code is simply computing one order
value, and using it as the basis for both, which is wrong (i.e. it assumes
that ((1<<order)*PAGE_SIZE)/sizeof(bucket) is still ^2 when its not).

To fix this, we change the logic slightly. We start by computing a goal
allocation order (which is limited by the maximum size hash table we want
to support. Then we attempt to allocate that size table, decreasing the
order until a successful allocation is made. Then, with the resultant
successful order we compute the number of buckets that hash table supports,
which we then round down to the nearest power of two, giving us the number
of entries the table actually supports.

I've tested this locally here, using non-debug and spinlock-debug kernels,
and the number of entries in the hashtable consistently work out to be
powers of two in all cases.

Signed-off-by: Neil Horman <nhorman@tuxdriver.com>
Reported-by: Dmitry Vyukov <dvyukov@google.com>
CC: Dmitry Vyukov <dvyukov@google.com>
CC: Vladislav Yasevich <vyasevich@gmail.com>
CC: "David S. Miller" <davem@davemloft.net>
Signed-off-by: David S. Miller <davem@davemloft.net>

authored by

Neil Horman and committed by
David S. Miller
d9749fb5 d07c0278

+38 -8
+38 -8
net/sctp/protocol.c
··· 60 60 #include <net/inet_common.h> 61 61 #include <net/inet_ecn.h> 62 62 63 + #define MAX_SCTP_PORT_HASH_ENTRIES (64 * 1024) 64 + 63 65 /* Global data structures. */ 64 66 struct sctp_globals sctp_globals __read_mostly; 65 67 ··· 1357 1355 unsigned long limit; 1358 1356 int max_share; 1359 1357 int order; 1358 + int num_entries; 1359 + int max_entry_order; 1360 1360 1361 1361 sock_skb_cb_check_size(sizeof(struct sctp_ulpevent)); 1362 1362 ··· 1411 1407 1412 1408 /* Size and allocate the association hash table. 1413 1409 * The methodology is similar to that of the tcp hash tables. 1410 + * Though not identical. Start by getting a goal size 1414 1411 */ 1415 1412 if (totalram_pages >= (128 * 1024)) 1416 1413 goal = totalram_pages >> (22 - PAGE_SHIFT); 1417 1414 else 1418 1415 goal = totalram_pages >> (24 - PAGE_SHIFT); 1419 1416 1420 - for (order = 0; (1UL << order) < goal; order++) 1421 - ; 1417 + /* Then compute the page order for said goal */ 1418 + order = get_order(goal); 1419 + 1420 + /* Now compute the required page order for the maximum sized table we 1421 + * want to create 1422 + */ 1423 + max_entry_order = get_order(MAX_SCTP_PORT_HASH_ENTRIES * 1424 + sizeof(struct sctp_bind_hashbucket)); 1425 + 1426 + /* Limit the page order by that maximum hash table size */ 1427 + order = min(order, max_entry_order); 1422 1428 1423 1429 /* Allocate and initialize the endpoint hash table. */ 1424 1430 sctp_ep_hashsize = 64; ··· 1444 1430 INIT_HLIST_HEAD(&sctp_ep_hashtable[i].chain); 1445 1431 } 1446 1432 1447 - /* Allocate and initialize the SCTP port hash table. */ 1433 + /* Allocate and initialize the SCTP port hash table. 1434 + * Note that order is initalized to start at the max sized 1435 + * table we want to support. If we can't get that many pages 1436 + * reduce the order and try again 1437 + */ 1448 1438 do { 1449 - sctp_port_hashsize = (1UL << order) * PAGE_SIZE / 1450 - sizeof(struct sctp_bind_hashbucket); 1451 - if ((sctp_port_hashsize > (64 * 1024)) && order > 0) 1452 - continue; 1453 1439 sctp_port_hashtable = (struct sctp_bind_hashbucket *) 1454 1440 __get_free_pages(GFP_KERNEL | __GFP_NOWARN, order); 1455 1441 } while (!sctp_port_hashtable && --order > 0); 1442 + 1456 1443 if (!sctp_port_hashtable) { 1457 1444 pr_err("Failed bind hash alloc\n"); 1458 1445 status = -ENOMEM; 1459 1446 goto err_bhash_alloc; 1460 1447 } 1448 + 1449 + /* Now compute the number of entries that will fit in the 1450 + * port hash space we allocated 1451 + */ 1452 + num_entries = (1UL << order) * PAGE_SIZE / 1453 + sizeof(struct sctp_bind_hashbucket); 1454 + 1455 + /* And finish by rounding it down to the nearest power of two 1456 + * this wastes some memory of course, but its needed because 1457 + * the hash function operates based on the assumption that 1458 + * that the number of entries is a power of two 1459 + */ 1460 + sctp_port_hashsize = rounddown_pow_of_two(num_entries); 1461 + 1461 1462 for (i = 0; i < sctp_port_hashsize; i++) { 1462 1463 spin_lock_init(&sctp_port_hashtable[i].lock); 1463 1464 INIT_HLIST_HEAD(&sctp_port_hashtable[i].chain); ··· 1481 1452 if (sctp_transport_hashtable_init()) 1482 1453 goto err_thash_alloc; 1483 1454 1484 - pr_info("Hash tables configured (bind %d)\n", sctp_port_hashsize); 1455 + pr_info("Hash tables configured (bind %d/%d)\n", sctp_port_hashsize, 1456 + num_entries); 1485 1457 1486 1458 sctp_sysctl_register(); 1487 1459