Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

bootmem: respect goal more likely

The old node-agnostic code tried allocating on all nodes starting from the
one with the lowest range. alloc_bootmem_core retried without the goal if
it could not satisfy it and so the goal was only respected at all when it
happened to be on the first (lowest page numbers) node (or theoretically
if allocations failed on all nodes before to the one holding the goal).

Introduce a non-panicking helper that starts allocating from the node
holding the goal and falls back only after all thes tries failed, thus
moving the goal fallback code out of alloc_bootmem_core.

Make all other allocation functions benefit from this new helper.

Signed-off-by: Johannes Weiner <hannes@saeurebad.de>
Cc: Ingo Molnar <mingo@elte.hu>
Cc: Yinghai Lu <yhlu.kernel@gmail.com>
Cc: Andi Kleen <andi@firstfloor.org>
Cc: Yasunori Goto <y-goto@jp.fujitsu.com>
Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>

authored by

Johannes Weiner and committed by
Linus Torvalds
0f3caba2 e2bf3cae

+54 -38
+54 -38
mm/bootmem.c
··· 408 408 unsigned long size, unsigned long align, 409 409 unsigned long goal, unsigned long limit) 410 410 { 411 + unsigned long fallback = 0; 411 412 unsigned long min, max, start, sidx, midx, step; 412 413 413 414 BUG_ON(!size); ··· 444 443 midx = max - PFN_DOWN(bdata->node_boot_start); 445 444 446 445 if (bdata->hint_idx > sidx) { 447 - /* Make sure we retry on failure */ 448 - goal = 1; 446 + /* 447 + * Handle the valid case of sidx being zero and still 448 + * catch the fallback below. 449 + */ 450 + fallback = sidx + 1; 449 451 sidx = ALIGN(bdata->hint_idx, step); 450 452 } 451 453 ··· 496 492 return region; 497 493 } 498 494 495 + if (fallback) { 496 + sidx = ALIGN(fallback - 1, step); 497 + fallback = 0; 498 + goto find_block; 499 + } 500 + 501 + return NULL; 502 + } 503 + 504 + static void * __init ___alloc_bootmem_nopanic(unsigned long size, 505 + unsigned long align, 506 + unsigned long goal, 507 + unsigned long limit) 508 + { 509 + bootmem_data_t *bdata; 510 + 511 + restart: 512 + list_for_each_entry(bdata, &bdata_list, list) { 513 + void *region; 514 + 515 + if (goal && bdata->node_low_pfn <= PFN_DOWN(goal)) 516 + continue; 517 + if (limit && bdata->node_boot_start >= limit) 518 + break; 519 + 520 + region = alloc_bootmem_core(bdata, size, align, goal, limit); 521 + if (region) 522 + return region; 523 + } 524 + 499 525 if (goal) { 500 526 goal = 0; 501 - sidx = 0; 502 - goto find_block; 527 + goto restart; 503 528 } 504 529 505 530 return NULL; ··· 548 515 * Returns NULL on failure. 549 516 */ 550 517 void * __init __alloc_bootmem_nopanic(unsigned long size, unsigned long align, 551 - unsigned long goal) 518 + unsigned long goal) 552 519 { 553 - bootmem_data_t *bdata; 554 - void *ptr; 520 + return ___alloc_bootmem_nopanic(size, align, goal, 0); 521 + } 555 522 556 - list_for_each_entry(bdata, &bdata_list, list) { 557 - ptr = alloc_bootmem_core(bdata, size, align, goal, 0); 558 - if (ptr) 559 - return ptr; 560 - } 523 + static void * __init ___alloc_bootmem(unsigned long size, unsigned long align, 524 + unsigned long goal, unsigned long limit) 525 + { 526 + void *mem = ___alloc_bootmem_nopanic(size, align, goal, limit); 527 + 528 + if (mem) 529 + return mem; 530 + /* 531 + * Whoops, we cannot satisfy the allocation request. 532 + */ 533 + printk(KERN_ALERT "bootmem alloc of %lu bytes failed!\n", size); 534 + panic("Out of memory"); 561 535 return NULL; 562 536 } 563 537 ··· 584 544 void * __init __alloc_bootmem(unsigned long size, unsigned long align, 585 545 unsigned long goal) 586 546 { 587 - void *mem = __alloc_bootmem_nopanic(size,align,goal); 588 - 589 - if (mem) 590 - return mem; 591 - /* 592 - * Whoops, we cannot satisfy the allocation request. 593 - */ 594 - printk(KERN_ALERT "bootmem alloc of %lu bytes failed!\n", size); 595 - panic("Out of memory"); 596 - return NULL; 547 + return ___alloc_bootmem(size, align, goal, 0); 597 548 } 598 549 599 550 /** ··· 684 653 void * __init __alloc_bootmem_low(unsigned long size, unsigned long align, 685 654 unsigned long goal) 686 655 { 687 - bootmem_data_t *bdata; 688 - void *ptr; 689 - 690 - list_for_each_entry(bdata, &bdata_list, list) { 691 - ptr = alloc_bootmem_core(bdata, size, align, goal, 692 - ARCH_LOW_ADDRESS_LIMIT); 693 - if (ptr) 694 - return ptr; 695 - } 696 - 697 - /* 698 - * Whoops, we cannot satisfy the allocation request. 699 - */ 700 - printk(KERN_ALERT "low bootmem alloc of %lu bytes failed!\n", size); 701 - panic("Out of low memory"); 702 - return NULL; 656 + return ___alloc_bootmem(size, align, goal, ARCH_LOW_ADDRESS_LIMIT); 703 657 } 704 658 705 659 /**