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

Configure Feed

Select the types of activity you want to include in your feed.

bootmem: fix aligning of node-relative indexes and offsets

Absolute alignment requirements may never be applied to node-relative
offsets. Andreas Herrmann spotted this flaw when a bootmem allocation on
an unaligned node was itself not aligned because the combination of an
unaligned node with an aligned offset into that node is not garuanteed to
be aligned itself.

This patch introduces two helper functions that align a node-relative
index or offset with respect to the node's starting address so that the
absolute PFN or virtual address that results from combining the two
satisfies the requested alignment.

Then all the broken ALIGN()s in alloc_bootmem_core() are replaced by these
helpers.

Signed-off-by: Johannes Weiner <hannes@saeurebad.de>
Reported-by: Andreas Herrmann <andreas.herrmann3@amd.com>
Debugged-by: Andreas Herrmann <andreas.herrmann3@amd.com>
Reviewed-by: Andreas Herrmann <andreas.herrmann3@amd.com>
Tested-by: Andreas Herrmann <andreas.herrmann3@amd.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
481ebd0d a09f4855

+29 -6
+29 -6
mm/bootmem.c
··· 405 405 } 406 406 #endif /* !CONFIG_HAVE_ARCH_BOOTMEM_NODE */ 407 407 408 + static unsigned long align_idx(struct bootmem_data *bdata, unsigned long idx, 409 + unsigned long step) 410 + { 411 + unsigned long base = bdata->node_min_pfn; 412 + 413 + /* 414 + * Align the index with respect to the node start so that the 415 + * combination of both satisfies the requested alignment. 416 + */ 417 + 418 + return ALIGN(base + idx, step) - base; 419 + } 420 + 421 + static unsigned long align_off(struct bootmem_data *bdata, unsigned long off, 422 + unsigned long align) 423 + { 424 + unsigned long base = PFN_PHYS(bdata->node_min_pfn); 425 + 426 + /* Same as align_idx for byte offsets */ 427 + 428 + return ALIGN(base + off, align) - base; 429 + } 430 + 408 431 static void * __init alloc_bootmem_core(struct bootmem_data *bdata, 409 432 unsigned long size, unsigned long align, 410 433 unsigned long goal, unsigned long limit) ··· 464 441 else 465 442 start = ALIGN(min, step); 466 443 467 - sidx = start - bdata->node_min_pfn;; 444 + sidx = start - bdata->node_min_pfn; 468 445 midx = max - bdata->node_min_pfn; 469 446 470 447 if (bdata->hint_idx > sidx) { ··· 473 450 * catch the fallback below. 474 451 */ 475 452 fallback = sidx + 1; 476 - sidx = ALIGN(bdata->hint_idx, step); 453 + sidx = align_idx(bdata, bdata->hint_idx, step); 477 454 } 478 455 479 456 while (1) { ··· 482 459 unsigned long eidx, i, start_off, end_off; 483 460 find_block: 484 461 sidx = find_next_zero_bit(bdata->node_bootmem_map, midx, sidx); 485 - sidx = ALIGN(sidx, step); 462 + sidx = align_idx(bdata, sidx, step); 486 463 eidx = sidx + PFN_UP(size); 487 464 488 465 if (sidx >= midx || eidx > midx) ··· 490 467 491 468 for (i = sidx; i < eidx; i++) 492 469 if (test_bit(i, bdata->node_bootmem_map)) { 493 - sidx = ALIGN(i, step); 470 + sidx = align_idx(bdata, i, step); 494 471 if (sidx == i) 495 472 sidx += step; 496 473 goto find_block; ··· 498 475 499 476 if (bdata->last_end_off & (PAGE_SIZE - 1) && 500 477 PFN_DOWN(bdata->last_end_off) + 1 == sidx) 501 - start_off = ALIGN(bdata->last_end_off, align); 478 + start_off = align_off(bdata, bdata->last_end_off, align); 502 479 else 503 480 start_off = PFN_PHYS(sidx); 504 481 ··· 522 499 } 523 500 524 501 if (fallback) { 525 - sidx = ALIGN(fallback - 1, step); 502 + sidx = align_idx(bdata, fallback - 1, step); 526 503 fallback = 0; 527 504 goto find_block; 528 505 }