Skip to content

Commit

Permalink
powerpc/pseries: Rework lppaca_shared_proc() to avoid DEBUG_PREEMPT
Browse files Browse the repository at this point in the history
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: f13c13a ("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
  • Loading branch information
ruscur authored and mpe committed Aug 24, 2023
1 parent 1aa0006 commit eac030b
Show file tree
Hide file tree
Showing 5 changed files with 14 additions and 21 deletions.
11 changes: 9 additions & 2 deletions arch/powerpc/include/asm/lppaca.h
Expand Up @@ -23,6 +23,7 @@
#include <asm/types.h>
#include <asm/mmu.h>
#include <asm/firmware.h>
#include <asm/paca.h>

/*
* The lppaca is the "virtual processor area" registered with the hypervisor,
Expand Down Expand Up @@ -105,14 +106,20 @@ struct lppaca {
*/
#define LPPACA_OLD_SHARED_PROC 2

static inline bool lppaca_shared_proc(struct lppaca *l)
#ifdef CONFIG_PPC_PSERIES
/*
* All CPUs should have the same shared proc value, so directly access the PACA
* to avoid false positives from DEBUG_PREEMPT.
*/
static inline bool lppaca_shared_proc(void)
{
struct lppaca *l = local_paca->lppaca_ptr;

if (!firmware_has_feature(FW_FEATURE_SPLPAR))
return false;
return !!(l->__old_status & LPPACA_OLD_SHARED_PROC);
}

#ifdef CONFIG_PPC_PSERIES
#define get_lppaca() (get_paca()->lppaca_ptr)
#endif

Expand Down
10 changes: 1 addition & 9 deletions arch/powerpc/platforms/pseries/lpar.c
Expand Up @@ -640,16 +640,8 @@ static const struct proc_ops vcpudispatch_stats_freq_proc_ops = {

static int __init vcpudispatch_stats_procfs_init(void)
{
/*
* Avoid smp_processor_id while preemptible. All CPUs should have
* the same value for lppaca_shared_proc.
*/
preempt_disable();
if (!lppaca_shared_proc(get_lppaca())) {
preempt_enable();
if (!lppaca_shared_proc())
return 0;
}
preempt_enable();

if (!proc_create("powerpc/vcpudispatch_stats", 0600, NULL,
&vcpudispatch_stats_proc_ops))
Expand Down
4 changes: 2 additions & 2 deletions arch/powerpc/platforms/pseries/lparcfg.c
Expand Up @@ -206,7 +206,7 @@ static void parse_ppp_data(struct seq_file *m)
ppp_data.active_system_procs);

/* pool related entries are appropriate for shared configs */
if (lppaca_shared_proc(get_lppaca())) {
if (lppaca_shared_proc()) {
unsigned long pool_idle_time, pool_procs;

seq_printf(m, "pool=%d\n", ppp_data.pool_num);
Expand Down Expand Up @@ -560,7 +560,7 @@ static int pseries_lparcfg_data(struct seq_file *m, void *v)
partition_potential_processors);

seq_printf(m, "shared_processor_mode=%d\n",
lppaca_shared_proc(get_lppaca()));
lppaca_shared_proc());

#ifdef CONFIG_PPC_64S_HASH_MMU
if (!radix_enabled())
Expand Down
2 changes: 1 addition & 1 deletion arch/powerpc/platforms/pseries/setup.c
Expand Up @@ -849,7 +849,7 @@ static void __init pSeries_setup_arch(void)
if (firmware_has_feature(FW_FEATURE_LPAR)) {
vpa_init(boot_cpuid);

if (lppaca_shared_proc(get_lppaca())) {
if (lppaca_shared_proc()) {
static_branch_enable(&shared_processor);
pv_spinlocks_init();
#ifdef CONFIG_PARAVIRT_TIME_ACCOUNTING
Expand Down
8 changes: 1 addition & 7 deletions drivers/cpuidle/cpuidle-pseries.c
Expand Up @@ -414,13 +414,7 @@ static int __init pseries_idle_probe(void)
return -ENODEV;

if (firmware_has_feature(FW_FEATURE_SPLPAR)) {
/*
* Use local_paca instead of get_lppaca() since
* preemption is not disabled, and it is not required in
* fact, since lppaca_ptr does not need to be the value
* associated to the current CPU, it can be from any CPU.
*/
if (lppaca_shared_proc(local_paca->lppaca_ptr)) {
if (lppaca_shared_proc()) {
cpuidle_state_table = shared_states;
max_idle_state = ARRAY_SIZE(shared_states);
} else {
Expand Down

0 comments on commit eac030b

Please sign in to comment.