forked from Minki/linux
mm: add a low limit to alloc_large_system_hash
UDP stack needs a minimum hash size value for proper operation and also uses alloc_large_system_hash() for proper NUMA distribution of its hash tables and automatic sizing depending on available system memory. On some low memory situations, udp_table_init() must ignore the alloc_large_system_hash() result and reallocs a bigger memory area. As we cannot easily free old hash table, we leak it and kmemleak can issue a warning. This patch adds a low limit parameter to alloc_large_system_hash() to solve this problem. We then specify UDP_HTABLE_SIZE_MIN for UDP/UDPLite hash table allocation. Reported-by: Mark Asselstine <mark.asselstine@windriver.com> Reported-by: Tim Bird <tim.bird@am.sony.com> Signed-off-by: Eric Dumazet <eric.dumazet@gmail.com> Cc: Paul Gortmaker <paul.gortmaker@windriver.com> Signed-off-by: David S. Miller <davem@davemloft.net>
This commit is contained in:
parent
d0a24a3516
commit
31fe62b958
@ -3093,6 +3093,7 @@ static void __init dcache_init_early(void)
|
||||
HASH_EARLY,
|
||||
&d_hash_shift,
|
||||
&d_hash_mask,
|
||||
0,
|
||||
0);
|
||||
|
||||
for (loop = 0; loop < (1U << d_hash_shift); loop++)
|
||||
@ -3123,6 +3124,7 @@ static void __init dcache_init(void)
|
||||
0,
|
||||
&d_hash_shift,
|
||||
&d_hash_mask,
|
||||
0,
|
||||
0);
|
||||
|
||||
for (loop = 0; loop < (1U << d_hash_shift); loop++)
|
||||
|
@ -1647,6 +1647,7 @@ void __init inode_init_early(void)
|
||||
HASH_EARLY,
|
||||
&i_hash_shift,
|
||||
&i_hash_mask,
|
||||
0,
|
||||
0);
|
||||
|
||||
for (loop = 0; loop < (1U << i_hash_shift); loop++)
|
||||
@ -1677,6 +1678,7 @@ void __init inode_init(void)
|
||||
0,
|
||||
&i_hash_shift,
|
||||
&i_hash_mask,
|
||||
0,
|
||||
0);
|
||||
|
||||
for (loop = 0; loop < (1U << i_hash_shift); loop++)
|
||||
|
@ -154,7 +154,8 @@ extern void *alloc_large_system_hash(const char *tablename,
|
||||
int flags,
|
||||
unsigned int *_hash_shift,
|
||||
unsigned int *_hash_mask,
|
||||
unsigned long limit);
|
||||
unsigned long low_limit,
|
||||
unsigned long high_limit);
|
||||
|
||||
#define HASH_EARLY 0x00000001 /* Allocating during early boot? */
|
||||
#define HASH_SMALL 0x00000002 /* sub-page allocation allowed, min
|
||||
|
@ -547,7 +547,8 @@ void __init pidhash_init(void)
|
||||
|
||||
pid_hash = alloc_large_system_hash("PID", sizeof(*pid_hash), 0, 18,
|
||||
HASH_EARLY | HASH_SMALL,
|
||||
&pidhash_shift, NULL, 4096);
|
||||
&pidhash_shift, NULL,
|
||||
0, 4096);
|
||||
pidhash_size = 1U << pidhash_shift;
|
||||
|
||||
for (i = 0; i < pidhash_size; i++)
|
||||
|
@ -5242,9 +5242,10 @@ void *__init alloc_large_system_hash(const char *tablename,
|
||||
int flags,
|
||||
unsigned int *_hash_shift,
|
||||
unsigned int *_hash_mask,
|
||||
unsigned long limit)
|
||||
unsigned long low_limit,
|
||||
unsigned long high_limit)
|
||||
{
|
||||
unsigned long long max = limit;
|
||||
unsigned long long max = high_limit;
|
||||
unsigned long log2qty, size;
|
||||
void *table = NULL;
|
||||
|
||||
@ -5282,6 +5283,8 @@ void *__init alloc_large_system_hash(const char *tablename,
|
||||
}
|
||||
max = min(max, 0x80000000ULL);
|
||||
|
||||
if (numentries < low_limit)
|
||||
numentries = low_limit;
|
||||
if (numentries > max)
|
||||
numentries = max;
|
||||
|
||||
|
@ -3452,6 +3452,7 @@ int __init ip_rt_init(void)
|
||||
0,
|
||||
&rt_hash_log,
|
||||
&rt_hash_mask,
|
||||
0,
|
||||
rhash_entries ? 0 : 512 * 1024);
|
||||
memset(rt_hash_table, 0, (rt_hash_mask + 1) * sizeof(struct rt_hash_bucket));
|
||||
rt_hash_lock_init();
|
||||
|
@ -3514,6 +3514,7 @@ void __init tcp_init(void)
|
||||
0,
|
||||
NULL,
|
||||
&tcp_hashinfo.ehash_mask,
|
||||
0,
|
||||
thash_entries ? 0 : 512 * 1024);
|
||||
for (i = 0; i <= tcp_hashinfo.ehash_mask; i++) {
|
||||
INIT_HLIST_NULLS_HEAD(&tcp_hashinfo.ehash[i].chain, i);
|
||||
@ -3530,6 +3531,7 @@ void __init tcp_init(void)
|
||||
0,
|
||||
&tcp_hashinfo.bhash_size,
|
||||
NULL,
|
||||
0,
|
||||
64 * 1024);
|
||||
tcp_hashinfo.bhash_size = 1U << tcp_hashinfo.bhash_size;
|
||||
for (i = 0; i < tcp_hashinfo.bhash_size; i++) {
|
||||
|
@ -2192,26 +2192,16 @@ void __init udp_table_init(struct udp_table *table, const char *name)
|
||||
{
|
||||
unsigned int i;
|
||||
|
||||
if (!CONFIG_BASE_SMALL)
|
||||
table->hash = alloc_large_system_hash(name,
|
||||
2 * sizeof(struct udp_hslot),
|
||||
uhash_entries,
|
||||
21, /* one slot per 2 MB */
|
||||
0,
|
||||
&table->log,
|
||||
&table->mask,
|
||||
64 * 1024);
|
||||
/*
|
||||
* Make sure hash table has the minimum size
|
||||
*/
|
||||
if (CONFIG_BASE_SMALL || table->mask < UDP_HTABLE_SIZE_MIN - 1) {
|
||||
table->hash = kmalloc(UDP_HTABLE_SIZE_MIN *
|
||||
2 * sizeof(struct udp_hslot), GFP_KERNEL);
|
||||
if (!table->hash)
|
||||
panic(name);
|
||||
table->log = ilog2(UDP_HTABLE_SIZE_MIN);
|
||||
table->mask = UDP_HTABLE_SIZE_MIN - 1;
|
||||
}
|
||||
table->hash = alloc_large_system_hash(name,
|
||||
2 * sizeof(struct udp_hslot),
|
||||
uhash_entries,
|
||||
21, /* one slot per 2 MB */
|
||||
0,
|
||||
&table->log,
|
||||
&table->mask,
|
||||
UDP_HTABLE_SIZE_MIN,
|
||||
64 * 1024);
|
||||
|
||||
table->hash2 = table->hash + (table->mask + 1);
|
||||
for (i = 0; i <= table->mask; i++) {
|
||||
INIT_HLIST_NULLS_HEAD(&table->hash[i].head, i);
|
||||
|
Loading…
Reference in New Issue
Block a user