lib: genalloc: Change chunk allocation to vmalloc
Change the chunk allocation from kmalloc to vmalloc for
allocations greater than a page. This allows large
chunks to be allocated from physically non-contiguous
memory and increases the chance of the allocation
succeeding.
CRs-fixed: 387655
Change-Id: I75cd0d1634c6f8ff4d91e615122fdcfada00ec69
Signed-off-by: Shubhraprakash Das <sadas@codeaurora.org>
diff --git a/lib/genalloc.c b/lib/genalloc.c
index 188df2c..9cf1b8b 100644
--- a/lib/genalloc.c
+++ b/lib/genalloc.c
@@ -34,6 +34,7 @@
#include <linux/rculist.h>
#include <linux/interrupt.h>
#include <linux/genalloc.h>
+#include <linux/vmalloc.h>
static int set_bits_ll(unsigned long *addr, unsigned long mask_to_set)
{
@@ -178,9 +179,14 @@
int nbytes = sizeof(struct gen_pool_chunk) +
(nbits + BITS_PER_BYTE - 1) / BITS_PER_BYTE;
- chunk = kmalloc_node(nbytes, GFP_KERNEL | __GFP_ZERO, nid);
+ if (nbytes <= PAGE_SIZE)
+ chunk = kmalloc_node(nbytes, __GFP_ZERO, nid);
+ else
+ chunk = vmalloc(nbytes);
if (unlikely(chunk == NULL))
return -ENOMEM;
+ if (nbytes > PAGE_SIZE)
+ memset(chunk, 0, nbytes);
chunk->phys_addr = phys;
chunk->start_addr = virt;
@@ -235,14 +241,20 @@
int bit, end_bit;
list_for_each_safe(_chunk, _next_chunk, &pool->chunks) {
+ int nbytes;
chunk = list_entry(_chunk, struct gen_pool_chunk, next_chunk);
list_del(&chunk->next_chunk);
end_bit = (chunk->end_addr - chunk->start_addr) >> order;
+ nbytes = sizeof(struct gen_pool_chunk) +
+ (end_bit + BITS_PER_BYTE - 1) / BITS_PER_BYTE;
bit = find_next_bit(chunk->bits, end_bit, 0);
BUG_ON(bit < end_bit);
- kfree(chunk);
+ if (nbytes <= PAGE_SIZE)
+ kfree(chunk);
+ else
+ vfree(chunk);
}
kfree(pool);
return;