Skip to content

Commit 9a9594e

Browse files
committed
Merge branch 'smp-hotplug-for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/tip/tip
Pull SMP hotplug updates from Thomas Gleixner: "This update is primarily a cleanup of the CPU hotplug locking code. The hotplug locking mechanism is an open coded RWSEM, which allows recursive locking. The main problem with that is the recursive nature as it evades the full lockdep coverage and hides potential deadlocks. The rework replaces the open coded RWSEM with a percpu RWSEM and establishes full lockdep coverage that way. The bulk of the changes fix up recursive locking issues and address the now fully reported potential deadlocks all over the place. Some of these deadlocks have been observed in the RT tree, but on mainline the probability was low enough to hide them away." * 'smp-hotplug-for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/tip/tip: (37 commits) cpu/hotplug: Constify attribute_group structures powerpc: Only obtain cpu_hotplug_lock if called by rtasd ARM/hw_breakpoint: Fix possible recursive locking for arch_hw_breakpoint_init cpu/hotplug: Remove unused check_for_tasks() function perf/core: Don't release cred_guard_mutex if not taken cpuhotplug: Link lock stacks for hotplug callbacks acpi/processor: Prevent cpu hotplug deadlock sched: Provide is_percpu_thread() helper cpu/hotplug: Convert hotplug locking to percpu rwsem s390: Prevent hotplug rwsem recursion arm: Prevent hotplug rwsem recursion arm64: Prevent cpu hotplug rwsem recursion kprobes: Cure hotplug lock ordering issues jump_label: Reorder hotplug lock and jump_label_lock perf/tracing/cpuhotplug: Fix locking order ACPI/processor: Use cpu_hotplug_disable() instead of get_online_cpus() PCI: Replace the racy recursion prevention PCI: Use cpu_hotplug_disable() instead of get_online_cpus() perf/x86/intel: Drop get_online_cpus() in intel_snb_check_microcode() x86/perf: Drop EXPORT of perf_check_microcode ...
2 parents 3ad918e + 993647a commit 9a9594e

File tree

40 files changed

+474
-375
lines changed

40 files changed

+474
-375
lines changed

arch/arm/kernel/hw_breakpoint.c

Lines changed: 7 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1090,23 +1090,24 @@ static int __init arch_hw_breakpoint_init(void)
10901090
* driven low on this core and there isn't an architected way to
10911091
* determine that.
10921092
*/
1093-
get_online_cpus();
1093+
cpus_read_lock();
10941094
register_undef_hook(&debug_reg_hook);
10951095

10961096
/*
10971097
* Register CPU notifier which resets the breakpoint resources. We
10981098
* assume that a halting debugger will leave the world in a nice state
10991099
* for us.
11001100
*/
1101-
ret = cpuhp_setup_state(CPUHP_AP_ONLINE_DYN, "arm/hw_breakpoint:online",
1102-
dbg_reset_online, NULL);
1101+
ret = cpuhp_setup_state_cpuslocked(CPUHP_AP_ONLINE_DYN,
1102+
"arm/hw_breakpoint:online",
1103+
dbg_reset_online, NULL);
11031104
unregister_undef_hook(&debug_reg_hook);
11041105
if (WARN_ON(ret < 0) || !cpumask_empty(&debug_err_mask)) {
11051106
core_num_brps = 0;
11061107
core_num_wrps = 0;
11071108
if (ret > 0)
1108-
cpuhp_remove_state_nocalls(ret);
1109-
put_online_cpus();
1109+
cpuhp_remove_state_nocalls_cpuslocked(ret);
1110+
cpus_read_unlock();
11101111
return 0;
11111112
}
11121113

@@ -1124,7 +1125,7 @@ static int __init arch_hw_breakpoint_init(void)
11241125
TRAP_HWBKPT, "watchpoint debug exception");
11251126
hook_ifault_code(FAULT_CODE_DEBUG, hw_breakpoint_pending, SIGTRAP,
11261127
TRAP_HWBKPT, "breakpoint debug exception");
1127-
put_online_cpus();
1128+
cpus_read_unlock();
11281129

11291130
/* Register PM notifiers. */
11301131
pm_init();

arch/arm/kernel/patch.c

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -124,5 +124,5 @@ void __kprobes patch_text(void *addr, unsigned int insn)
124124
.insn = insn,
125125
};
126126

127-
stop_machine(patch_text_stop_machine, &patch, NULL);
127+
stop_machine_cpuslocked(patch_text_stop_machine, &patch, NULL);
128128
}

arch/arm/probes/kprobes/core.c

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -182,7 +182,8 @@ void __kprobes kprobes_remove_breakpoint(void *addr, unsigned int insn)
182182
.addr = addr,
183183
.insn = insn,
184184
};
185-
stop_machine(__kprobes_remove_breakpoint, &p, cpu_online_mask);
185+
stop_machine_cpuslocked(__kprobes_remove_breakpoint, &p,
186+
cpu_online_mask);
186187
}
187188

188189
void __kprobes arch_disarm_kprobe(struct kprobe *p)

arch/arm64/include/asm/insn.h

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -433,7 +433,6 @@ u32 aarch64_set_branch_offset(u32 insn, s32 offset);
433433
bool aarch64_insn_hotpatch_safe(u32 old_insn, u32 new_insn);
434434

435435
int aarch64_insn_patch_text_nosync(void *addr, u32 insn);
436-
int aarch64_insn_patch_text_sync(void *addrs[], u32 insns[], int cnt);
437436
int aarch64_insn_patch_text(void *addrs[], u32 insns[], int cnt);
438437

439438
s32 aarch64_insn_adrp_get_offset(u32 insn);

arch/arm64/kernel/insn.c

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -255,6 +255,7 @@ static int __kprobes aarch64_insn_patch_text_cb(void *arg)
255255
return ret;
256256
}
257257

258+
static
258259
int __kprobes aarch64_insn_patch_text_sync(void *addrs[], u32 insns[], int cnt)
259260
{
260261
struct aarch64_insn_patch patch = {
@@ -267,8 +268,8 @@ int __kprobes aarch64_insn_patch_text_sync(void *addrs[], u32 insns[], int cnt)
267268
if (cnt <= 0)
268269
return -EINVAL;
269270

270-
return stop_machine(aarch64_insn_patch_text_cb, &patch,
271-
cpu_online_mask);
271+
return stop_machine_cpuslocked(aarch64_insn_patch_text_cb, &patch,
272+
cpu_online_mask);
272273
}
273274

274275
int __kprobes aarch64_insn_patch_text(void *addrs[], u32 insns[], int cnt)

arch/mips/kernel/jump_label.c

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -58,7 +58,6 @@ void arch_jump_label_transform(struct jump_entry *e,
5858
insn.word = 0; /* nop */
5959
}
6060

61-
get_online_cpus();
6261
mutex_lock(&text_mutex);
6362
if (IS_ENABLED(CONFIG_CPU_MICROMIPS)) {
6463
insn_p->halfword[0] = insn.word >> 16;
@@ -70,7 +69,6 @@ void arch_jump_label_transform(struct jump_entry *e,
7069
(unsigned long)insn_p + sizeof(*insn_p));
7170

7271
mutex_unlock(&text_mutex);
73-
put_online_cpus();
7472
}
7573

7674
#endif /* HAVE_JUMP_LABEL */

arch/powerpc/include/asm/topology.h

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -43,6 +43,7 @@ extern void __init dump_numa_cpu_topology(void);
4343

4444
extern int sysfs_add_device_to_node(struct device *dev, int nid);
4545
extern void sysfs_remove_device_from_node(struct device *dev, int nid);
46+
extern int numa_update_cpu_topology(bool cpus_locked);
4647

4748
static inline int early_cpu_to_node(int cpu)
4849
{
@@ -71,6 +72,11 @@ static inline void sysfs_remove_device_from_node(struct device *dev,
7172
int nid)
7273
{
7374
}
75+
76+
static inline int numa_update_cpu_topology(bool cpus_locked)
77+
{
78+
return 0;
79+
}
7480
#endif /* CONFIG_NUMA */
7581

7682
#if defined(CONFIG_NUMA) && defined(CONFIG_PPC_SPLPAR)

arch/powerpc/kernel/rtasd.c

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -283,7 +283,7 @@ static void prrn_work_fn(struct work_struct *work)
283283
* the RTAS event.
284284
*/
285285
pseries_devicetree_update(-prrn_update_scope);
286-
arch_update_cpu_topology();
286+
numa_update_cpu_topology(false);
287287
}
288288

289289
static DECLARE_WORK(prrn_work, prrn_work_fn);

arch/powerpc/kvm/book3s_hv.c

Lines changed: 7 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -3368,7 +3368,7 @@ void kvmppc_alloc_host_rm_ops(void)
33683368
return;
33693369
}
33703370

3371-
get_online_cpus();
3371+
cpus_read_lock();
33723372

33733373
for (cpu = 0; cpu < nr_cpu_ids; cpu += threads_per_core) {
33743374
if (!cpu_online(cpu))
@@ -3390,17 +3390,17 @@ void kvmppc_alloc_host_rm_ops(void)
33903390
l_ops = (unsigned long) ops;
33913391

33923392
if (cmpxchg64((unsigned long *)&kvmppc_host_rm_ops_hv, 0, l_ops)) {
3393-
put_online_cpus();
3393+
cpus_read_unlock();
33943394
kfree(ops->rm_core);
33953395
kfree(ops);
33963396
return;
33973397
}
33983398

3399-
cpuhp_setup_state_nocalls(CPUHP_KVM_PPC_BOOK3S_PREPARE,
3400-
"ppc/kvm_book3s:prepare",
3401-
kvmppc_set_host_core,
3402-
kvmppc_clear_host_core);
3403-
put_online_cpus();
3399+
cpuhp_setup_state_nocalls_cpuslocked(CPUHP_KVM_PPC_BOOK3S_PREPARE,
3400+
"ppc/kvm_book3s:prepare",
3401+
kvmppc_set_host_core,
3402+
kvmppc_clear_host_core);
3403+
cpus_read_unlock();
34043404
}
34053405

34063406
void kvmppc_free_host_rm_ops(void)

arch/powerpc/mm/numa.c

Lines changed: 19 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1311,8 +1311,10 @@ static int update_lookup_table(void *data)
13111311
/*
13121312
* Update the node maps and sysfs entries for each cpu whose home node
13131313
* has changed. Returns 1 when the topology has changed, and 0 otherwise.
1314+
*
1315+
* cpus_locked says whether we already hold cpu_hotplug_lock.
13141316
*/
1315-
int arch_update_cpu_topology(void)
1317+
int numa_update_cpu_topology(bool cpus_locked)
13161318
{
13171319
unsigned int cpu, sibling, changed = 0;
13181320
struct topology_update_data *updates, *ud;
@@ -1400,15 +1402,23 @@ int arch_update_cpu_topology(void)
14001402
if (!cpumask_weight(&updated_cpus))
14011403
goto out;
14021404

1403-
stop_machine(update_cpu_topology, &updates[0], &updated_cpus);
1405+
if (cpus_locked)
1406+
stop_machine_cpuslocked(update_cpu_topology, &updates[0],
1407+
&updated_cpus);
1408+
else
1409+
stop_machine(update_cpu_topology, &updates[0], &updated_cpus);
14041410

14051411
/*
14061412
* Update the numa-cpu lookup table with the new mappings, even for
14071413
* offline CPUs. It is best to perform this update from the stop-
14081414
* machine context.
14091415
*/
1410-
stop_machine(update_lookup_table, &updates[0],
1416+
if (cpus_locked)
1417+
stop_machine_cpuslocked(update_lookup_table, &updates[0],
14111418
cpumask_of(raw_smp_processor_id()));
1419+
else
1420+
stop_machine(update_lookup_table, &updates[0],
1421+
cpumask_of(raw_smp_processor_id()));
14121422

14131423
for (ud = &updates[0]; ud; ud = ud->next) {
14141424
unregister_cpu_under_node(ud->cpu, ud->old_nid);
@@ -1426,6 +1436,12 @@ int arch_update_cpu_topology(void)
14261436
return changed;
14271437
}
14281438

1439+
int arch_update_cpu_topology(void)
1440+
{
1441+
lockdep_assert_cpus_held();
1442+
return numa_update_cpu_topology(true);
1443+
}
1444+
14291445
static void topology_work_fn(struct work_struct *work)
14301446
{
14311447
rebuild_sched_domains();

arch/powerpc/platforms/powernv/subcore.c

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -348,17 +348,18 @@ static int set_subcores_per_core(int new_mode)
348348
state->master = 0;
349349
}
350350

351-
get_online_cpus();
351+
cpus_read_lock();
352352

353353
/* This cpu will update the globals before exiting stop machine */
354354
this_cpu_ptr(&split_state)->master = 1;
355355

356356
/* Ensure state is consistent before we call the other cpus */
357357
mb();
358358

359-
stop_machine(cpu_update_split_mode, &new_mode, cpu_online_mask);
359+
stop_machine_cpuslocked(cpu_update_split_mode, &new_mode,
360+
cpu_online_mask);
360361

361-
put_online_cpus();
362+
cpus_read_unlock();
362363

363364
return 0;
364365
}

arch/s390/kernel/jump_label.c

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -93,7 +93,7 @@ void arch_jump_label_transform(struct jump_entry *entry,
9393
args.entry = entry;
9494
args.type = type;
9595

96-
stop_machine(__sm_arch_jump_label_transform, &args, NULL);
96+
stop_machine_cpuslocked(__sm_arch_jump_label_transform, &args, NULL);
9797
}
9898

9999
void arch_jump_label_transform_static(struct jump_entry *entry,

arch/s390/kernel/kprobes.c

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -196,15 +196,15 @@ void arch_arm_kprobe(struct kprobe *p)
196196
{
197197
struct swap_insn_args args = {.p = p, .arm_kprobe = 1};
198198

199-
stop_machine(swap_instruction, &args, NULL);
199+
stop_machine_cpuslocked(swap_instruction, &args, NULL);
200200
}
201201
NOKPROBE_SYMBOL(arch_arm_kprobe);
202202

203203
void arch_disarm_kprobe(struct kprobe *p)
204204
{
205205
struct swap_insn_args args = {.p = p, .arm_kprobe = 0};
206206

207-
stop_machine(swap_instruction, &args, NULL);
207+
stop_machine_cpuslocked(swap_instruction, &args, NULL);
208208
}
209209
NOKPROBE_SYMBOL(arch_disarm_kprobe);
210210

arch/s390/kernel/time.c

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -636,10 +636,10 @@ static void stp_work_fn(struct work_struct *work)
636636
goto out_unlock;
637637

638638
memset(&stp_sync, 0, sizeof(stp_sync));
639-
get_online_cpus();
639+
cpus_read_lock();
640640
atomic_set(&stp_sync.cpus, num_online_cpus() - 1);
641-
stop_machine(stp_sync_clock, &stp_sync, cpu_online_mask);
642-
put_online_cpus();
641+
stop_machine_cpuslocked(stp_sync_clock, &stp_sync, cpu_online_mask);
642+
cpus_read_unlock();
643643

644644
if (!check_sync_clock())
645645
/*

arch/sparc/kernel/jump_label.c

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -41,12 +41,10 @@ void arch_jump_label_transform(struct jump_entry *entry,
4141
val = 0x01000000;
4242
}
4343

44-
get_online_cpus();
4544
mutex_lock(&text_mutex);
4645
*insn = val;
4746
flushi(insn);
4847
mutex_unlock(&text_mutex);
49-
put_online_cpus();
5048
}
5149

5250
#endif

arch/tile/kernel/jump_label.c

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -45,14 +45,12 @@ static void __jump_label_transform(struct jump_entry *e,
4545
void arch_jump_label_transform(struct jump_entry *e,
4646
enum jump_label_type type)
4747
{
48-
get_online_cpus();
4948
mutex_lock(&text_mutex);
5049

5150
__jump_label_transform(e, type);
5251
flush_icache_range(e->code, e->code + sizeof(tilegx_bundle_bits));
5352

5453
mutex_unlock(&text_mutex);
55-
put_online_cpus();
5654
}
5755

5856
__init_or_module void arch_jump_label_transform_static(struct jump_entry *e,

arch/x86/events/core.c

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2233,7 +2233,6 @@ void perf_check_microcode(void)
22332233
if (x86_pmu.check_microcode)
22342234
x86_pmu.check_microcode();
22352235
}
2236-
EXPORT_SYMBOL_GPL(perf_check_microcode);
22372236

22382237
static struct pmu pmu = {
22392238
.pmu_enable = x86_pmu_enable,

arch/x86/events/intel/core.c

Lines changed: 5 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -3425,12 +3425,10 @@ static void intel_snb_check_microcode(void)
34253425
int pebs_broken = 0;
34263426
int cpu;
34273427

3428-
get_online_cpus();
34293428
for_each_online_cpu(cpu) {
34303429
if ((pebs_broken = intel_snb_pebs_broken(cpu)))
34313430
break;
34323431
}
3433-
put_online_cpus();
34343432

34353433
if (pebs_broken == x86_pmu.pebs_broken)
34363434
return;
@@ -3503,7 +3501,9 @@ static bool check_msr(unsigned long msr, u64 mask)
35033501
static __init void intel_sandybridge_quirk(void)
35043502
{
35053503
x86_pmu.check_microcode = intel_snb_check_microcode;
3504+
cpus_read_lock();
35063505
intel_snb_check_microcode();
3506+
cpus_read_unlock();
35073507
}
35083508

35093509
static const struct { int id; char *name; } intel_arch_events_map[] __initconst = {
@@ -4175,13 +4175,12 @@ static __init int fixup_ht_bug(void)
41754175

41764176
lockup_detector_resume();
41774177

4178-
get_online_cpus();
4178+
cpus_read_lock();
41794179

4180-
for_each_online_cpu(c) {
4180+
for_each_online_cpu(c)
41814181
free_excl_cntrs(c);
4182-
}
41834182

4184-
put_online_cpus();
4183+
cpus_read_unlock();
41854184
pr_info("PMU erratum BJ122, BV98, HSD29 workaround disabled, HT off\n");
41864185
return 0;
41874186
}

arch/x86/events/intel/cqm.c

Lines changed: 8 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1682,7 +1682,7 @@ static int __init intel_cqm_init(void)
16821682
*
16831683
* Also, check that the scales match on all cpus.
16841684
*/
1685-
get_online_cpus();
1685+
cpus_read_lock();
16861686
for_each_online_cpu(cpu) {
16871687
struct cpuinfo_x86 *c = &cpu_data(cpu);
16881688

@@ -1746,14 +1746,14 @@ static int __init intel_cqm_init(void)
17461746
* Setup the hot cpu notifier once we are sure cqm
17471747
* is enabled to avoid notifier leak.
17481748
*/
1749-
cpuhp_setup_state(CPUHP_AP_PERF_X86_CQM_STARTING,
1750-
"perf/x86/cqm:starting",
1751-
intel_cqm_cpu_starting, NULL);
1752-
cpuhp_setup_state(CPUHP_AP_PERF_X86_CQM_ONLINE, "perf/x86/cqm:online",
1753-
NULL, intel_cqm_cpu_exit);
1754-
1749+
cpuhp_setup_state_cpuslocked(CPUHP_AP_PERF_X86_CQM_STARTING,
1750+
"perf/x86/cqm:starting",
1751+
intel_cqm_cpu_starting, NULL);
1752+
cpuhp_setup_state_cpuslocked(CPUHP_AP_PERF_X86_CQM_ONLINE,
1753+
"perf/x86/cqm:online",
1754+
NULL, intel_cqm_cpu_exit);
17551755
out:
1756-
put_online_cpus();
1756+
cpus_read_unlock();
17571757

17581758
if (ret) {
17591759
kfree(str);

arch/x86/kernel/cpu/mtrr/main.c

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -807,10 +807,8 @@ void mtrr_save_state(void)
807807
if (!mtrr_enabled())
808808
return;
809809

810-
get_online_cpus();
811810
first_cpu = cpumask_first(cpu_online_mask);
812811
smp_call_function_single(first_cpu, mtrr_save_fixed_ranges, NULL, 1);
813-
put_online_cpus();
814812
}
815813

816814
void set_mtrr_aps_delayed_init(void)

0 commit comments

Comments
 (0)