提交 31fe62b9 编写于 作者: T Tim Bird 提交者: David S. Miller

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: NMark Asselstine <mark.asselstine@windriver.com>
Reported-by: NTim Bird <tim.bird@am.sony.com>
Signed-off-by: NEric Dumazet <eric.dumazet@gmail.com>
Cc: Paul Gortmaker <paul.gortmaker@windriver.com>
Signed-off-by: NDavid S. Miller <davem@davemloft.net>
上级 d0a24a35
...@@ -3093,6 +3093,7 @@ static void __init dcache_init_early(void) ...@@ -3093,6 +3093,7 @@ static void __init dcache_init_early(void)
HASH_EARLY, HASH_EARLY,
&d_hash_shift, &d_hash_shift,
&d_hash_mask, &d_hash_mask,
0,
0); 0);
for (loop = 0; loop < (1U << d_hash_shift); loop++) for (loop = 0; loop < (1U << d_hash_shift); loop++)
...@@ -3123,6 +3124,7 @@ static void __init dcache_init(void) ...@@ -3123,6 +3124,7 @@ static void __init dcache_init(void)
0, 0,
&d_hash_shift, &d_hash_shift,
&d_hash_mask, &d_hash_mask,
0,
0); 0);
for (loop = 0; loop < (1U << d_hash_shift); loop++) for (loop = 0; loop < (1U << d_hash_shift); loop++)
......
...@@ -1647,6 +1647,7 @@ void __init inode_init_early(void) ...@@ -1647,6 +1647,7 @@ void __init inode_init_early(void)
HASH_EARLY, HASH_EARLY,
&i_hash_shift, &i_hash_shift,
&i_hash_mask, &i_hash_mask,
0,
0); 0);
for (loop = 0; loop < (1U << i_hash_shift); loop++) for (loop = 0; loop < (1U << i_hash_shift); loop++)
...@@ -1677,6 +1678,7 @@ void __init inode_init(void) ...@@ -1677,6 +1678,7 @@ void __init inode_init(void)
0, 0,
&i_hash_shift, &i_hash_shift,
&i_hash_mask, &i_hash_mask,
0,
0); 0);
for (loop = 0; loop < (1U << i_hash_shift); loop++) for (loop = 0; loop < (1U << i_hash_shift); loop++)
......
...@@ -154,7 +154,8 @@ extern void *alloc_large_system_hash(const char *tablename, ...@@ -154,7 +154,8 @@ extern void *alloc_large_system_hash(const char *tablename,
int flags, int flags,
unsigned int *_hash_shift, unsigned int *_hash_shift,
unsigned int *_hash_mask, 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_EARLY 0x00000001 /* Allocating during early boot? */
#define HASH_SMALL 0x00000002 /* sub-page allocation allowed, min #define HASH_SMALL 0x00000002 /* sub-page allocation allowed, min
......
...@@ -547,7 +547,8 @@ void __init pidhash_init(void) ...@@ -547,7 +547,8 @@ void __init pidhash_init(void)
pid_hash = alloc_large_system_hash("PID", sizeof(*pid_hash), 0, 18, pid_hash = alloc_large_system_hash("PID", sizeof(*pid_hash), 0, 18,
HASH_EARLY | HASH_SMALL, HASH_EARLY | HASH_SMALL,
&pidhash_shift, NULL, 4096); &pidhash_shift, NULL,
0, 4096);
pidhash_size = 1U << pidhash_shift; pidhash_size = 1U << pidhash_shift;
for (i = 0; i < pidhash_size; i++) for (i = 0; i < pidhash_size; i++)
......
...@@ -5242,9 +5242,10 @@ void *__init alloc_large_system_hash(const char *tablename, ...@@ -5242,9 +5242,10 @@ void *__init alloc_large_system_hash(const char *tablename,
int flags, int flags,
unsigned int *_hash_shift, unsigned int *_hash_shift,
unsigned int *_hash_mask, 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; unsigned long log2qty, size;
void *table = NULL; void *table = NULL;
...@@ -5282,6 +5283,8 @@ void *__init alloc_large_system_hash(const char *tablename, ...@@ -5282,6 +5283,8 @@ void *__init alloc_large_system_hash(const char *tablename,
} }
max = min(max, 0x80000000ULL); max = min(max, 0x80000000ULL);
if (numentries < low_limit)
numentries = low_limit;
if (numentries > max) if (numentries > max)
numentries = max; numentries = max;
......
...@@ -3452,6 +3452,7 @@ int __init ip_rt_init(void) ...@@ -3452,6 +3452,7 @@ int __init ip_rt_init(void)
0, 0,
&rt_hash_log, &rt_hash_log,
&rt_hash_mask, &rt_hash_mask,
0,
rhash_entries ? 0 : 512 * 1024); rhash_entries ? 0 : 512 * 1024);
memset(rt_hash_table, 0, (rt_hash_mask + 1) * sizeof(struct rt_hash_bucket)); memset(rt_hash_table, 0, (rt_hash_mask + 1) * sizeof(struct rt_hash_bucket));
rt_hash_lock_init(); rt_hash_lock_init();
......
...@@ -3514,6 +3514,7 @@ void __init tcp_init(void) ...@@ -3514,6 +3514,7 @@ void __init tcp_init(void)
0, 0,
NULL, NULL,
&tcp_hashinfo.ehash_mask, &tcp_hashinfo.ehash_mask,
0,
thash_entries ? 0 : 512 * 1024); thash_entries ? 0 : 512 * 1024);
for (i = 0; i <= tcp_hashinfo.ehash_mask; i++) { for (i = 0; i <= tcp_hashinfo.ehash_mask; i++) {
INIT_HLIST_NULLS_HEAD(&tcp_hashinfo.ehash[i].chain, i); INIT_HLIST_NULLS_HEAD(&tcp_hashinfo.ehash[i].chain, i);
...@@ -3530,6 +3531,7 @@ void __init tcp_init(void) ...@@ -3530,6 +3531,7 @@ void __init tcp_init(void)
0, 0,
&tcp_hashinfo.bhash_size, &tcp_hashinfo.bhash_size,
NULL, NULL,
0,
64 * 1024); 64 * 1024);
tcp_hashinfo.bhash_size = 1U << tcp_hashinfo.bhash_size; tcp_hashinfo.bhash_size = 1U << tcp_hashinfo.bhash_size;
for (i = 0; i < tcp_hashinfo.bhash_size; i++) { 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) ...@@ -2192,26 +2192,16 @@ void __init udp_table_init(struct udp_table *table, const char *name)
{ {
unsigned int i; unsigned int i;
if (!CONFIG_BASE_SMALL) table->hash = alloc_large_system_hash(name,
table->hash = alloc_large_system_hash(name, 2 * sizeof(struct udp_hslot),
2 * sizeof(struct udp_hslot), uhash_entries,
uhash_entries, 21, /* one slot per 2 MB */
21, /* one slot per 2 MB */ 0,
0, &table->log,
&table->log, &table->mask,
&table->mask, UDP_HTABLE_SIZE_MIN,
64 * 1024); 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->hash2 = table->hash + (table->mask + 1); table->hash2 = table->hash + (table->mask + 1);
for (i = 0; i <= table->mask; i++) { for (i = 0; i <= table->mask; i++) {
INIT_HLIST_NULLS_HEAD(&table->hash[i].head, i); INIT_HLIST_NULLS_HEAD(&table->hash[i].head, i);
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册