From e461457b134e55c3ca68b91b70b8796e3f3dba69 Mon Sep 17 00:00:00 2001 From: Shubhraprakash Das Date: Tue, 14 Aug 2012 00:25:43 -0700 Subject: [PATCH] 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 --- lib/genalloc.c | 16 ++++++++++++++-- 1 file changed, 14 insertions(+), 2 deletions(-) diff --git a/lib/genalloc.c b/lib/genalloc.c index 188df2cf29e..9cf1b8b51ac 100644 --- a/lib/genalloc.c +++ b/lib/genalloc.c @@ -34,6 +34,7 @@ #include #include #include +#include static int set_bits_ll(unsigned long *addr, unsigned long mask_to_set) { @@ -178,9 +179,14 @@ int gen_pool_add_virt(struct gen_pool *pool, unsigned long virt, phys_addr_t phy 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 @@ void gen_pool_destroy(struct gen_pool *pool) 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;