Skip to content

Commit e5e179a

Browse files
Scott Chelohampe
authored andcommitted
pseries/drmem: don't cache node id in drmem_lmb struct
At memory hot-remove time we can retrieve an LMB's nid from its corresponding memory_block. There is no need to store the nid in multiple locations. Note that lmb_to_memblock() uses find_memory_block() to get the corresponding memory_block. As find_memory_block() runs in sub-linear time this approach is negligibly slower than what we do at present. In exchange for this lookup at hot-remove time we no longer need to call memory_add_physaddr_to_nid() during drmem_init() for each LMB. On powerpc, memory_add_physaddr_to_nid() is a linear search, so this spares us an O(n^2) initialization during boot. On systems with many LMBs that initialization overhead is palpable and disruptive. For example, on a box with 249854 LMBs we're seeing drmem_init() take upwards of 30 seconds to complete: [ 53.721639] drmem: initializing drmem v2 [ 80.604346] watchdog: BUG: soft lockup - CPU#65 stuck for 23s! [swapper/0:1] [ 80.604377] Modules linked in: [ 80.604389] CPU: 65 PID: 1 Comm: swapper/0 Not tainted 5.6.0-rc2+ #4 [ 80.604397] NIP: c0000000000a4980 LR: c0000000000a4940 CTR: 0000000000000000 [ 80.604407] REGS: c0002dbff8493830 TRAP: 0901 Not tainted (5.6.0-rc2+) [ 80.604412] MSR: 8000000002009033 <SF,VEC,EE,ME,IR,DR,RI,LE> CR: 44000248 XER: 0000000d [ 80.604431] CFAR: c0000000000a4a38 IRQMASK: 0 [ 80.604431] GPR00: c0000000000a4940 c0002dbff8493ac0 c000000001904400 c0003cfffffede30 [ 80.604431] GPR04: 0000000000000000 c000000000f4095a 000000000000002f 0000000010000000 [ 80.604431] GPR08: c0000bf7ecdb7fb8 c0000bf7ecc2d3c8 0000000000000008 c00c0002fdfb2001 [ 80.604431] GPR12: 0000000000000000 c00000001e8ec200 [ 80.604477] NIP [c0000000000a4980] hot_add_scn_to_nid+0xa0/0x3e0 [ 80.604486] LR [c0000000000a4940] hot_add_scn_to_nid+0x60/0x3e0 [ 80.604492] Call Trace: [ 80.604498] [c0002dbff8493ac0] [c0000000000a4940] hot_add_scn_to_nid+0x60/0x3e0 (unreliable) [ 80.604509] [c0002dbff8493b20] [c000000000087c10] memory_add_physaddr_to_nid+0x20/0x60 [ 80.604521] [c0002dbff8493b40] [c0000000010d4880] drmem_init+0x25c/0x2f0 [ 80.604530] [c0002dbff8493c10] [c000000000010154] do_one_initcall+0x64/0x2c0 [ 80.604540] [c0002dbff8493ce0] [c0000000010c4aa0] kernel_init_freeable+0x2d8/0x3a0 [ 80.604550] [c0002dbff8493db0] [c000000000010824] kernel_init+0x2c/0x148 [ 80.604560] [c0002dbff8493e20] [c00000000000b648] ret_from_kernel_thread+0x5c/0x74 [ 80.604567] Instruction dump: [ 80.604574] 392918e8 e9490000 e90a000a e92a0000 80ea000c 1d080018 3908ffe8 7d094214 [ 80.604586] 7fa94040 419d00dc e9490010 714a0088 <2faa0008> 409e00ac e9490000 7fbe5040 [ 89.047390] drmem: 249854 LMB(s) With a patched kernel on the same machine we're no longer seeing the soft lockup. drmem_init() now completes in negligible time, even when the LMB count is large. Fixes: b2d3b5e ("powerpc/pseries: Track LMB nid instead of using device tree") Signed-off-by: Scott Cheloha <[email protected]> Reviewed-by: Nathan Lynch <[email protected]> Signed-off-by: Michael Ellerman <[email protected]> Link: https://lore.kernel.org/r/[email protected]
1 parent 704dfe9 commit e5e179a

3 files changed

Lines changed: 17 additions & 34 deletions

File tree

arch/powerpc/include/asm/drmem.h

Lines changed: 0 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -15,9 +15,6 @@ struct drmem_lmb {
1515
u32 drc_index;
1616
u32 aa_index;
1717
u32 flags;
18-
#ifdef CONFIG_MEMORY_HOTPLUG
19-
int nid;
20-
#endif
2118
};
2219

2320
struct drmem_lmb_info {
@@ -121,22 +118,4 @@ static inline void invalidate_lmb_associativity_index(struct drmem_lmb *lmb)
121118
lmb->aa_index = 0xffffffff;
122119
}
123120

124-
#ifdef CONFIG_MEMORY_HOTPLUG
125-
static inline void lmb_set_nid(struct drmem_lmb *lmb)
126-
{
127-
lmb->nid = memory_add_physaddr_to_nid(lmb->base_addr);
128-
}
129-
static inline void lmb_clear_nid(struct drmem_lmb *lmb)
130-
{
131-
lmb->nid = -1;
132-
}
133-
#else
134-
static inline void lmb_set_nid(struct drmem_lmb *lmb)
135-
{
136-
}
137-
static inline void lmb_clear_nid(struct drmem_lmb *lmb)
138-
{
139-
}
140-
#endif
141-
142121
#endif /* _ASM_POWERPC_LMB_H */

arch/powerpc/mm/drmem.c

Lines changed: 1 addition & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -389,10 +389,8 @@ static void __init init_drmem_v1_lmbs(const __be32 *prop)
389389
if (!drmem_info->lmbs)
390390
return;
391391

392-
for_each_drmem_lmb(lmb) {
392+
for_each_drmem_lmb(lmb)
393393
read_drconf_v1_cell(lmb, &prop);
394-
lmb_set_nid(lmb);
395-
}
396394
}
397395

398396
static void __init init_drmem_v2_lmbs(const __be32 *prop)
@@ -437,8 +435,6 @@ static void __init init_drmem_v2_lmbs(const __be32 *prop)
437435

438436
lmb->aa_index = dr_cell.aa_index;
439437
lmb->flags = dr_cell.flags;
440-
441-
lmb_set_nid(lmb);
442438
}
443439
}
444440
}

arch/powerpc/platforms/pseries/hotplug-memory.c

Lines changed: 16 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -354,25 +354,32 @@ static int dlpar_add_lmb(struct drmem_lmb *);
354354

355355
static int dlpar_remove_lmb(struct drmem_lmb *lmb)
356356
{
357+
struct memory_block *mem_block;
357358
unsigned long block_sz;
358359
int rc;
359360

360361
if (!lmb_is_removable(lmb))
361362
return -EINVAL;
362363

364+
mem_block = lmb_to_memblock(lmb);
365+
if (mem_block == NULL)
366+
return -EINVAL;
367+
363368
rc = dlpar_offline_lmb(lmb);
364-
if (rc)
369+
if (rc) {
370+
put_device(&mem_block->dev);
365371
return rc;
372+
}
366373

367374
block_sz = pseries_memory_block_size();
368375

369-
__remove_memory(lmb->nid, lmb->base_addr, block_sz);
376+
__remove_memory(mem_block->nid, lmb->base_addr, block_sz);
377+
put_device(&mem_block->dev);
370378

371379
/* Update memory regions for memory remove */
372380
memblock_remove(lmb->base_addr, block_sz);
373381

374382
invalidate_lmb_associativity_index(lmb);
375-
lmb_clear_nid(lmb);
376383
lmb->flags &= ~DRCONF_MEM_ASSIGNED;
377384

378385
return 0;
@@ -591,7 +598,7 @@ static int dlpar_memory_remove_by_ic(u32 lmbs_to_remove, u32 drc_index)
591598
static int dlpar_add_lmb(struct drmem_lmb *lmb)
592599
{
593600
unsigned long block_sz;
594-
int rc;
601+
int nid, rc;
595602

596603
if (lmb->flags & DRCONF_MEM_ASSIGNED)
597604
return -EINVAL;
@@ -602,21 +609,22 @@ static int dlpar_add_lmb(struct drmem_lmb *lmb)
602609
return rc;
603610
}
604611

605-
lmb_set_nid(lmb);
606612
block_sz = memory_block_size_bytes();
607613

614+
/* Find the node id for this address. */
615+
nid = memory_add_physaddr_to_nid(lmb->base_addr);
616+
608617
/* Add the memory */
609-
rc = __add_memory(lmb->nid, lmb->base_addr, block_sz);
618+
rc = __add_memory(nid, lmb->base_addr, block_sz);
610619
if (rc) {
611620
invalidate_lmb_associativity_index(lmb);
612621
return rc;
613622
}
614623

615624
rc = dlpar_online_lmb(lmb);
616625
if (rc) {
617-
__remove_memory(lmb->nid, lmb->base_addr, block_sz);
626+
__remove_memory(nid, lmb->base_addr, block_sz);
618627
invalidate_lmb_associativity_index(lmb);
619-
lmb_clear_nid(lmb);
620628
} else {
621629
lmb->flags |= DRCONF_MEM_ASSIGNED;
622630
}

0 commit comments

Comments
 (0)