aboutsummaryrefslogtreecommitdiffstats
path: root/lib/genalloc.c
diff options
context:
space:
mode:
authorAlexey Skidanov <alexey.skidanov@intel.com>2019-01-03 18:26:44 -0500
committerLinus Torvalds <torvalds@linux-foundation.org>2019-01-04 16:13:46 -0500
commit52fbf1134d479234d7e64ba9dcbaea23405f229e (patch)
treeab1629a6b81d70f85237d365c66bbf173c7309a6 /lib/genalloc.c
parent3fc2579e6f162fcff964f5aa01c8a29438ca5c05 (diff)
lib/genalloc.c: fix allocation of aligned buffer from non-aligned chunk
gen_pool_alloc_algo() uses different allocation functions implementing different allocation algorithms. With gen_pool_first_fit_align() allocation function, the returned address should be aligned on the requested boundary. If chunk start address isn't aligned on the requested boundary, the returned address isn't aligned too. The only way to get properly aligned address is to initialize the pool with chunks aligned on the requested boundary. If want to have an ability to allocate buffers aligned on different boundaries (for example, 4K, 1MB, ...), the chunk start address should be aligned on the max possible alignment. This happens because gen_pool_first_fit_align() looks for properly aligned memory block without taking into account the chunk start address alignment. To fix this, we provide chunk start address to gen_pool_first_fit_align() and change its implementation such that it starts looking for properly aligned block with appropriate offset (exactly as is done in CMA). Link: https://lkml.kernel.org/lkml/a170cf65-6884-3592-1de9-4c235888cc8a@intel.com Link: http://lkml.kernel.org/r/1541690953-4623-1-git-send-email-alexey.skidanov@intel.com Signed-off-by: Alexey Skidanov <alexey.skidanov@intel.com> Reviewed-by: Andrew Morton <akpm@linux-foundation.org> Cc: Logan Gunthorpe <logang@deltatee.com> Cc: Daniel Mentz <danielmentz@google.com> Cc: Mathieu Desnoyers <mathieu.desnoyers@efficios.com> Cc: Laura Abbott <labbott@redhat.com> Signed-off-by: Andrew Morton <akpm@linux-foundation.org> Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
Diffstat (limited to 'lib/genalloc.c')
-rw-r--r--lib/genalloc.c20
1 files changed, 12 insertions, 8 deletions
diff --git a/lib/genalloc.c b/lib/genalloc.c
index ca06adc4f445..5deb25c40a5a 100644
--- a/lib/genalloc.c
+++ b/lib/genalloc.c
@@ -311,7 +311,7 @@ unsigned long gen_pool_alloc_algo(struct gen_pool *pool, size_t size,
311 end_bit = chunk_size(chunk) >> order; 311 end_bit = chunk_size(chunk) >> order;
312retry: 312retry:
313 start_bit = algo(chunk->bits, end_bit, start_bit, 313 start_bit = algo(chunk->bits, end_bit, start_bit,
314 nbits, data, pool); 314 nbits, data, pool, chunk->start_addr);
315 if (start_bit >= end_bit) 315 if (start_bit >= end_bit)
316 continue; 316 continue;
317 remain = bitmap_set_ll(chunk->bits, start_bit, nbits); 317 remain = bitmap_set_ll(chunk->bits, start_bit, nbits);
@@ -525,7 +525,7 @@ EXPORT_SYMBOL(gen_pool_set_algo);
525 */ 525 */
526unsigned long gen_pool_first_fit(unsigned long *map, unsigned long size, 526unsigned long gen_pool_first_fit(unsigned long *map, unsigned long size,
527 unsigned long start, unsigned int nr, void *data, 527 unsigned long start, unsigned int nr, void *data,
528 struct gen_pool *pool) 528 struct gen_pool *pool, unsigned long start_addr)
529{ 529{
530 return bitmap_find_next_zero_area(map, size, start, nr, 0); 530 return bitmap_find_next_zero_area(map, size, start, nr, 0);
531} 531}
@@ -543,16 +543,19 @@ EXPORT_SYMBOL(gen_pool_first_fit);
543 */ 543 */
544unsigned long gen_pool_first_fit_align(unsigned long *map, unsigned long size, 544unsigned long gen_pool_first_fit_align(unsigned long *map, unsigned long size,
545 unsigned long start, unsigned int nr, void *data, 545 unsigned long start, unsigned int nr, void *data,
546 struct gen_pool *pool) 546 struct gen_pool *pool, unsigned long start_addr)
547{ 547{
548 struct genpool_data_align *alignment; 548 struct genpool_data_align *alignment;
549 unsigned long align_mask; 549 unsigned long align_mask, align_off;
550 int order; 550 int order;
551 551
552 alignment = data; 552 alignment = data;
553 order = pool->min_alloc_order; 553 order = pool->min_alloc_order;
554 align_mask = ((alignment->align + (1UL << order) - 1) >> order) - 1; 554 align_mask = ((alignment->align + (1UL << order) - 1) >> order) - 1;
555 return bitmap_find_next_zero_area(map, size, start, nr, align_mask); 555 align_off = (start_addr & (alignment->align - 1)) >> order;
556
557 return bitmap_find_next_zero_area_off(map, size, start, nr,
558 align_mask, align_off);
556} 559}
557EXPORT_SYMBOL(gen_pool_first_fit_align); 560EXPORT_SYMBOL(gen_pool_first_fit_align);
558 561
@@ -567,7 +570,7 @@ EXPORT_SYMBOL(gen_pool_first_fit_align);
567 */ 570 */
568unsigned long gen_pool_fixed_alloc(unsigned long *map, unsigned long size, 571unsigned long gen_pool_fixed_alloc(unsigned long *map, unsigned long size,
569 unsigned long start, unsigned int nr, void *data, 572 unsigned long start, unsigned int nr, void *data,
570 struct gen_pool *pool) 573 struct gen_pool *pool, unsigned long start_addr)
571{ 574{
572 struct genpool_data_fixed *fixed_data; 575 struct genpool_data_fixed *fixed_data;
573 int order; 576 int order;
@@ -601,7 +604,8 @@ EXPORT_SYMBOL(gen_pool_fixed_alloc);
601 */ 604 */
602unsigned long gen_pool_first_fit_order_align(unsigned long *map, 605unsigned long gen_pool_first_fit_order_align(unsigned long *map,
603 unsigned long size, unsigned long start, 606 unsigned long size, unsigned long start,
604 unsigned int nr, void *data, struct gen_pool *pool) 607 unsigned int nr, void *data, struct gen_pool *pool,
608 unsigned long start_addr)
605{ 609{
606 unsigned long align_mask = roundup_pow_of_two(nr) - 1; 610 unsigned long align_mask = roundup_pow_of_two(nr) - 1;
607 611
@@ -624,7 +628,7 @@ EXPORT_SYMBOL(gen_pool_first_fit_order_align);
624 */ 628 */
625unsigned long gen_pool_best_fit(unsigned long *map, unsigned long size, 629unsigned long gen_pool_best_fit(unsigned long *map, unsigned long size,
626 unsigned long start, unsigned int nr, void *data, 630 unsigned long start, unsigned int nr, void *data,
627 struct gen_pool *pool) 631 struct gen_pool *pool, unsigned long start_addr)
628{ 632{
629 unsigned long start_bit = size; 633 unsigned long start_bit = size;
630 unsigned long len = size + 1; 634 unsigned long len = size + 1;