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

powerpc/pseries: Rework lppaca_shared_proc() to avoid DEBUG_PREEMPT

lppaca_shared_proc() takes a pointer to the lppaca which is typically
accessed through get_lppaca(). With DEBUG_PREEMPT enabled, this leads
to checking if preemption is enabled, for example:

BUG: using smp_processor_id() in preemptible [00000000] code: grep/10693
caller is lparcfg_data+0x408/0x19a0
CPU: 4 PID: 10693 Comm: grep Not tainted 6.5.0-rc3 #2
Call Trace:
dump_stack_lvl+0x154/0x200 (unreliable)
check_preemption_disabled+0x214/0x220
lparcfg_data+0x408/0x19a0
...

This isn't actually a problem however, as it does not matter which
lppaca is accessed, the shared proc state will be the same.
vcpudispatch_stats_procfs_init() already works around this by disabling
preemption, but the lparcfg code does not, erroring any time
/proc/powerpc/lparcfg is accessed with DEBUG_PREEMPT enabled.

Instead of disabling preemption on the caller side, rework
lppaca_shared_proc() to not take a pointer and instead directly access
the lppaca, bypassing any potential preemption checks.

Fixes: f13c13a00512 ("powerpc: Stop using non-architected shared_proc field in lppaca")
Signed-off-by: Russell Currey <ruscur@russell.cc>
[mpe: Rework to avoid needing a definition in paca.h and lppaca.h]
Signed-off-by: Michael Ellerman <mpe@ellerman.id.au>
Link: https://msgid.link/20230823055317.751786-4-mpe@ellerman.id.au

authored by

Russell Currey and committed by
Michael Ellerman
eac030b2 1aa00066

+14 -21
+9 -2
arch/powerpc/include/asm/lppaca.h
··· 23 23 #include <asm/types.h> 24 24 #include <asm/mmu.h> 25 25 #include <asm/firmware.h> 26 + #include <asm/paca.h> 26 27 27 28 /* 28 29 * The lppaca is the "virtual processor area" registered with the hypervisor, ··· 106 105 */ 107 106 #define LPPACA_OLD_SHARED_PROC 2 108 107 109 - static inline bool lppaca_shared_proc(struct lppaca *l) 108 + #ifdef CONFIG_PPC_PSERIES 109 + /* 110 + * All CPUs should have the same shared proc value, so directly access the PACA 111 + * to avoid false positives from DEBUG_PREEMPT. 112 + */ 113 + static inline bool lppaca_shared_proc(void) 110 114 { 115 + struct lppaca *l = local_paca->lppaca_ptr; 116 + 111 117 if (!firmware_has_feature(FW_FEATURE_SPLPAR)) 112 118 return false; 113 119 return !!(l->__old_status & LPPACA_OLD_SHARED_PROC); 114 120 } 115 121 116 - #ifdef CONFIG_PPC_PSERIES 117 122 #define get_lppaca() (get_paca()->lppaca_ptr) 118 123 #endif 119 124
+1 -9
arch/powerpc/platforms/pseries/lpar.c
··· 640 640 641 641 static int __init vcpudispatch_stats_procfs_init(void) 642 642 { 643 - /* 644 - * Avoid smp_processor_id while preemptible. All CPUs should have 645 - * the same value for lppaca_shared_proc. 646 - */ 647 - preempt_disable(); 648 - if (!lppaca_shared_proc(get_lppaca())) { 649 - preempt_enable(); 643 + if (!lppaca_shared_proc()) 650 644 return 0; 651 - } 652 - preempt_enable(); 653 645 654 646 if (!proc_create("powerpc/vcpudispatch_stats", 0600, NULL, 655 647 &vcpudispatch_stats_proc_ops))
+2 -2
arch/powerpc/platforms/pseries/lparcfg.c
··· 206 206 ppp_data.active_system_procs); 207 207 208 208 /* pool related entries are appropriate for shared configs */ 209 - if (lppaca_shared_proc(get_lppaca())) { 209 + if (lppaca_shared_proc()) { 210 210 unsigned long pool_idle_time, pool_procs; 211 211 212 212 seq_printf(m, "pool=%d\n", ppp_data.pool_num); ··· 560 560 partition_potential_processors); 561 561 562 562 seq_printf(m, "shared_processor_mode=%d\n", 563 - lppaca_shared_proc(get_lppaca())); 563 + lppaca_shared_proc()); 564 564 565 565 #ifdef CONFIG_PPC_64S_HASH_MMU 566 566 if (!radix_enabled())
+1 -1
arch/powerpc/platforms/pseries/setup.c
··· 849 849 if (firmware_has_feature(FW_FEATURE_LPAR)) { 850 850 vpa_init(boot_cpuid); 851 851 852 - if (lppaca_shared_proc(get_lppaca())) { 852 + if (lppaca_shared_proc()) { 853 853 static_branch_enable(&shared_processor); 854 854 pv_spinlocks_init(); 855 855 #ifdef CONFIG_PARAVIRT_TIME_ACCOUNTING
+1 -7
drivers/cpuidle/cpuidle-pseries.c
··· 414 414 return -ENODEV; 415 415 416 416 if (firmware_has_feature(FW_FEATURE_SPLPAR)) { 417 - /* 418 - * Use local_paca instead of get_lppaca() since 419 - * preemption is not disabled, and it is not required in 420 - * fact, since lppaca_ptr does not need to be the value 421 - * associated to the current CPU, it can be from any CPU. 422 - */ 423 - if (lppaca_shared_proc(local_paca->lppaca_ptr)) { 417 + if (lppaca_shared_proc()) { 424 418 cpuidle_state_table = shared_states; 425 419 max_idle_state = ARRAY_SIZE(shared_states); 426 420 } else {