drivers/base/memory: Avoid overhead from for_each_present_section_nr()

for_each_present_section_nr() was introduced to add_boot_memory_block()
by commit 61659efdb3 ("drivers/base/memory: improve add_boot_memory_block()").
It causes unnecessary overhead when the present sections are really
sparse. next_present_section_nr() called by the macro to find the next
present section, which is far away from the spanning sections in the
specified block. Too much time consumed by next_present_section_nr()
in this case, which can lead to softlockup as observed by Aditya Gupta
on IBM Power10 machine.

  watchdog: BUG: soft lockup - CPU#248 stuck for 22s! [swapper/248:1]
  Modules linked in:
  CPU: 248 UID: 0 PID: 1 Comm: swapper/248 Not tainted 6.15.0-rc1-next-20250408 #1 VOLUNTARY
  Hardware name: 9105-22A POWER10 (raw) 0x800200 opal:v7.1-107-gfda75d121942 PowerNV
  NIP:  c00000000209218c LR: c000000002092204 CTR: 0000000000000000
  REGS: c00040000418fa30 TRAP: 0900   Not tainted  (6.15.0-rc1-next-20250408)
  MSR:  9000000002009033 <SF,HV,VEC,EE,ME,IR,DR,RI,LE>  CR: 28000428  XER: 00000000
  CFAR: 0000000000000000 IRQMASK: 0
  GPR00: c000000002092204 c00040000418fcd0 c000000001b08100 0000000000000040
  GPR04: 0000000000013e00 c000c03ffebabb00 0000000000c03fff c000400fff587f80
  GPR08: 0000000000000000 00000000001196f7 0000000000000000 0000000028000428
  GPR12: 0000000000000000 c000000002e80000 c00000000001007c 0000000000000000
  GPR16: 0000000000000000 0000000000000000 0000000000000000 0000000000000000
  GPR20: 0000000000000000 0000000000000000 0000000000000000 0000000000000000
  GPR24: 0000000000000000 0000000000000000 0000000000000000 0000000000000000
  GPR28: c000000002df7f70 0000000000013dc0 c0000000011dd898 0000000008000000
  NIP [c00000000209218c] memory_dev_init+0x114/0x1e0
  LR [c000000002092204] memory_dev_init+0x18c/0x1e0
  Call Trace:
  [c00040000418fcd0] [c000000002092204] memory_dev_init+0x18c/0x1e0 (unreliable)
  [c00040000418fd50] [c000000002091348] driver_init+0x78/0xa4
  [c00040000418fd70] [c0000000020063ac] kernel_init_freeable+0x22c/0x370
  [c00040000418fde0] [c0000000000100a8] kernel_init+0x34/0x25c
  [c00040000418fe50] [c00000000000cd94] ret_from_kernel_user_thread+0x14/0x1c

Avoid the overhead by folding for_each_present_section_nr() to the outer
loop. add_boot_memory_block() is dropped after that.

Fixes: 61659efdb3 ("drivers/base/memory: improve add_boot_memory_block()")
Closes: https://lore.kernel.org/linux-mm/20250409180344.477916-1-adityag@linux.ibm.com
Reported-by: Aditya Gupta <adityag@linux.ibm.com>
Signed-off-by: Gavin Shan <gshan@redhat.com>
Acked-by: Oscar Salvador <osalvador@suse.de>
Tested-by: Aditya Gupta <adityag@linux.ibm.com>
Acked-by: David Hildenbrand <david@redhat.com>
Link: https://lore.kernel.org/r/20250410125110.1232329-1-gshan@redhat.com
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
This commit is contained in:
Gavin Shan 2025-04-10 22:51:10 +10:00 committed by Greg Kroah-Hartman
parent bc2c46426f
commit b9792abb76

View File

@ -816,21 +816,6 @@ static int add_memory_block(unsigned long block_id, unsigned long state,
return 0; return 0;
} }
static int __init add_boot_memory_block(unsigned long base_section_nr)
{
unsigned long nr;
for_each_present_section_nr(base_section_nr, nr) {
if (nr >= (base_section_nr + sections_per_block))
break;
return add_memory_block(memory_block_id(base_section_nr),
MEM_ONLINE, NULL, NULL);
}
return 0;
}
static int add_hotplug_memory_block(unsigned long block_id, static int add_hotplug_memory_block(unsigned long block_id,
struct vmem_altmap *altmap, struct vmem_altmap *altmap,
struct memory_group *group) struct memory_group *group)
@ -957,7 +942,7 @@ static const struct attribute_group *memory_root_attr_groups[] = {
void __init memory_dev_init(void) void __init memory_dev_init(void)
{ {
int ret; int ret;
unsigned long block_sz, nr; unsigned long block_sz, block_id, nr;
/* Validate the configured memory block size */ /* Validate the configured memory block size */
block_sz = memory_block_size_bytes(); block_sz = memory_block_size_bytes();
@ -970,15 +955,23 @@ void __init memory_dev_init(void)
panic("%s() failed to register subsystem: %d\n", __func__, ret); panic("%s() failed to register subsystem: %d\n", __func__, ret);
/* /*
* Create entries for memory sections that were found * Create entries for memory sections that were found during boot
* during boot and have been initialized * and have been initialized. Use @block_id to track the last
* handled block and initialize it to an invalid value (ULONG_MAX)
* to bypass the block ID matching check for the first present
* block so that it can be covered.
*/ */
for (nr = 0; nr <= __highest_present_section_nr; block_id = ULONG_MAX;
nr += sections_per_block) { for_each_present_section_nr(0, nr) {
ret = add_boot_memory_block(nr); if (block_id != ULONG_MAX && memory_block_id(nr) == block_id)
if (ret) continue;
panic("%s() failed to add memory block: %d\n", __func__,
ret); block_id = memory_block_id(nr);
ret = add_memory_block(block_id, MEM_ONLINE, NULL, NULL);
if (ret) {
panic("%s() failed to add memory block: %d\n",
__func__, ret);
}
} }
} }