From 666bda46d733bc4a3f6ff72b3589ccbdd0be3fc4 Mon Sep 17 00:00:00 2001 From: Shubhraprakash Das Date: Tue, 14 Aug 2012 00:25:43 -0700 Subject: 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 Signed-off-by: Shubhraprakash Das (cherry picked from commit e461457b134e55c3ca68b91b70b8796e3f3dba69) Change-Id: I576fed3dd33fdfa9742f0c91bea72417c4f0086f Signed-off-by: Sudhir Sharma --- lib/genalloc.c | 16 ++++++++++++++-- 1 file changed, 14 insertions(+), 2 deletions(-) (limited to 'lib') diff --git a/lib/genalloc.c b/lib/genalloc.c index ac5fba950..e4ac53328 100644 --- a/lib/genalloc.c +++ b/lib/genalloc.c @@ -36,6 +36,7 @@ #include #include #include +#include static inline size_t chunk_size(const struct gen_pool_chunk *chunk) { @@ -187,9 +188,14 @@ int gen_pool_add_virt(struct gen_pool *pool, unsigned long virt, phys_addr_t phy int nbytes = sizeof(struct gen_pool_chunk) + BITS_TO_LONGS(nbits) * sizeof(long); - 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; @@ -244,14 +250,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_size(chunk) >> 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; -- cgit v1.2.3