Commit ec11408a authored by Nicholas Piggin's avatar Nicholas Piggin Committed by Linus Torvalds

mm/large system hash: use vmalloc for size > MAX_ORDER when !hashdist

The kernel currently clamps large system hashes to MAX_ORDER when hashdist
is not set, which is rather arbitrary.

vmalloc space is limited on 32-bit machines, but this shouldn't result in
much more used because of small physical memory limiting system hash
sizes.

Include "vmalloc" or "linear" in the kernel log message.

Link: http://lkml.kernel.org/r/20190605144814.29319-1-npiggin@gmail.comSigned-off-by: default avatarNicholas Piggin <npiggin@gmail.com>
Reviewed-by: default avatarAndrew Morton <akpm@linux-foundation.org>
Signed-off-by: default avatarAndrew Morton <akpm@linux-foundation.org>
Signed-off-by: default avatarLinus Torvalds <torvalds@linux-foundation.org>
parent d9009d67
...@@ -7981,6 +7981,7 @@ void *__init alloc_large_system_hash(const char *tablename, ...@@ -7981,6 +7981,7 @@ void *__init alloc_large_system_hash(const char *tablename,
unsigned long log2qty, size; unsigned long log2qty, size;
void *table = NULL; void *table = NULL;
gfp_t gfp_flags; gfp_t gfp_flags;
bool virt;
/* allow the kernel cmdline to have a say */ /* allow the kernel cmdline to have a say */
if (!numentries) { if (!numentries) {
...@@ -8037,6 +8038,7 @@ void *__init alloc_large_system_hash(const char *tablename, ...@@ -8037,6 +8038,7 @@ void *__init alloc_large_system_hash(const char *tablename,
gfp_flags = (flags & HASH_ZERO) ? GFP_ATOMIC | __GFP_ZERO : GFP_ATOMIC; gfp_flags = (flags & HASH_ZERO) ? GFP_ATOMIC | __GFP_ZERO : GFP_ATOMIC;
do { do {
virt = false;
size = bucketsize << log2qty; size = bucketsize << log2qty;
if (flags & HASH_EARLY) { if (flags & HASH_EARLY) {
if (flags & HASH_ZERO) if (flags & HASH_ZERO)
...@@ -8044,26 +8046,26 @@ void *__init alloc_large_system_hash(const char *tablename, ...@@ -8044,26 +8046,26 @@ void *__init alloc_large_system_hash(const char *tablename,
else else
table = memblock_alloc_raw(size, table = memblock_alloc_raw(size,
SMP_CACHE_BYTES); SMP_CACHE_BYTES);
} else if (hashdist) { } else if (get_order(size) >= MAX_ORDER || hashdist) {
table = __vmalloc(size, gfp_flags, PAGE_KERNEL); table = __vmalloc(size, gfp_flags, PAGE_KERNEL);
virt = true;
} else { } else {
/* /*
* If bucketsize is not a power-of-two, we may free * If bucketsize is not a power-of-two, we may free
* some pages at the end of hash table which * some pages at the end of hash table which
* alloc_pages_exact() automatically does * alloc_pages_exact() automatically does
*/ */
if (get_order(size) < MAX_ORDER) { table = alloc_pages_exact(size, gfp_flags);
table = alloc_pages_exact(size, gfp_flags); kmemleak_alloc(table, size, 1, gfp_flags);
kmemleak_alloc(table, size, 1, gfp_flags);
}
} }
} while (!table && size > PAGE_SIZE && --log2qty); } while (!table && size > PAGE_SIZE && --log2qty);
if (!table) if (!table)
panic("Failed to allocate %s hash table\n", tablename); panic("Failed to allocate %s hash table\n", tablename);
pr_info("%s hash table entries: %ld (order: %d, %lu bytes)\n", pr_info("%s hash table entries: %ld (order: %d, %lu bytes, %s)\n",
tablename, 1UL << log2qty, ilog2(size) - PAGE_SHIFT, size); tablename, 1UL << log2qty, ilog2(size) - PAGE_SHIFT, size,
virt ? "vmalloc" : "linear");
if (_hash_shift) if (_hash_shift)
*_hash_shift = log2qty; *_hash_shift = log2qty;
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment