Skip to content

Commit

Permalink
Merge branch 'smp-hotplug-for-linus' of git://git.kernel.org/pub/scm/…
Browse files Browse the repository at this point in the history
…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
  ...
  • Loading branch information
Linus Torvalds committed Jul 4, 2017
2 parents 3ad918e + 993647a commit 9a9594e
Showing 40 changed files with 474 additions and 375 deletions.
13 changes: 7 additions & 6 deletions arch/arm/kernel/hw_breakpoint.c
Original file line number Diff line number Diff line change
@@ -1090,23 +1090,24 @@ static int __init arch_hw_breakpoint_init(void)
* driven low on this core and there isn't an architected way to
* determine that.
*/
get_online_cpus();
cpus_read_lock();
register_undef_hook(&debug_reg_hook);

/*
* Register CPU notifier which resets the breakpoint resources. We
* assume that a halting debugger will leave the world in a nice state
* for us.
*/
ret = cpuhp_setup_state(CPUHP_AP_ONLINE_DYN, "arm/hw_breakpoint:online",
dbg_reset_online, NULL);
ret = cpuhp_setup_state_cpuslocked(CPUHP_AP_ONLINE_DYN,
"arm/hw_breakpoint:online",
dbg_reset_online, NULL);
unregister_undef_hook(&debug_reg_hook);
if (WARN_ON(ret < 0) || !cpumask_empty(&debug_err_mask)) {
core_num_brps = 0;
core_num_wrps = 0;
if (ret > 0)
cpuhp_remove_state_nocalls(ret);
put_online_cpus();
cpuhp_remove_state_nocalls_cpuslocked(ret);
cpus_read_unlock();
return 0;
}

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

/* Register PM notifiers. */
pm_init();
2 changes: 1 addition & 1 deletion arch/arm/kernel/patch.c
Original file line number Diff line number Diff line change
@@ -124,5 +124,5 @@ void __kprobes patch_text(void *addr, unsigned int insn)
.insn = insn,
};

stop_machine(patch_text_stop_machine, &patch, NULL);
stop_machine_cpuslocked(patch_text_stop_machine, &patch, NULL);
}
3 changes: 2 additions & 1 deletion arch/arm/probes/kprobes/core.c
Original file line number Diff line number Diff line change
@@ -182,7 +182,8 @@ void __kprobes kprobes_remove_breakpoint(void *addr, unsigned int insn)
.addr = addr,
.insn = insn,
};
stop_machine(__kprobes_remove_breakpoint, &p, cpu_online_mask);
stop_machine_cpuslocked(__kprobes_remove_breakpoint, &p,
cpu_online_mask);
}

void __kprobes arch_disarm_kprobe(struct kprobe *p)
1 change: 0 additions & 1 deletion arch/arm64/include/asm/insn.h
Original file line number Diff line number Diff line change
@@ -433,7 +433,6 @@ u32 aarch64_set_branch_offset(u32 insn, s32 offset);
bool aarch64_insn_hotpatch_safe(u32 old_insn, u32 new_insn);

int aarch64_insn_patch_text_nosync(void *addr, u32 insn);
int aarch64_insn_patch_text_sync(void *addrs[], u32 insns[], int cnt);
int aarch64_insn_patch_text(void *addrs[], u32 insns[], int cnt);

s32 aarch64_insn_adrp_get_offset(u32 insn);
5 changes: 3 additions & 2 deletions arch/arm64/kernel/insn.c
Original file line number Diff line number Diff line change
@@ -255,6 +255,7 @@ static int __kprobes aarch64_insn_patch_text_cb(void *arg)
return ret;
}

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

return stop_machine(aarch64_insn_patch_text_cb, &patch,
cpu_online_mask);
return stop_machine_cpuslocked(aarch64_insn_patch_text_cb, &patch,
cpu_online_mask);
}

int __kprobes aarch64_insn_patch_text(void *addrs[], u32 insns[], int cnt)
2 changes: 0 additions & 2 deletions arch/mips/kernel/jump_label.c
Original file line number Diff line number Diff line change
@@ -58,7 +58,6 @@ void arch_jump_label_transform(struct jump_entry *e,
insn.word = 0; /* nop */
}

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

mutex_unlock(&text_mutex);
put_online_cpus();
}

#endif /* HAVE_JUMP_LABEL */
6 changes: 6 additions & 0 deletions arch/powerpc/include/asm/topology.h
Original file line number Diff line number Diff line change
@@ -43,6 +43,7 @@ extern void __init dump_numa_cpu_topology(void);

extern int sysfs_add_device_to_node(struct device *dev, int nid);
extern void sysfs_remove_device_from_node(struct device *dev, int nid);
extern int numa_update_cpu_topology(bool cpus_locked);

static inline int early_cpu_to_node(int cpu)
{
@@ -71,6 +72,11 @@ static inline void sysfs_remove_device_from_node(struct device *dev,
int nid)
{
}

static inline int numa_update_cpu_topology(bool cpus_locked)
{
return 0;
}
#endif /* CONFIG_NUMA */

#if defined(CONFIG_NUMA) && defined(CONFIG_PPC_SPLPAR)
2 changes: 1 addition & 1 deletion arch/powerpc/kernel/rtasd.c
Original file line number Diff line number Diff line change
@@ -283,7 +283,7 @@ static void prrn_work_fn(struct work_struct *work)
* the RTAS event.
*/
pseries_devicetree_update(-prrn_update_scope);
arch_update_cpu_topology();
numa_update_cpu_topology(false);
}

static DECLARE_WORK(prrn_work, prrn_work_fn);
14 changes: 7 additions & 7 deletions arch/powerpc/kvm/book3s_hv.c
Original file line number Diff line number Diff line change
@@ -3368,7 +3368,7 @@ void kvmppc_alloc_host_rm_ops(void)
return;
}

get_online_cpus();
cpus_read_lock();

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

if (cmpxchg64((unsigned long *)&kvmppc_host_rm_ops_hv, 0, l_ops)) {
put_online_cpus();
cpus_read_unlock();
kfree(ops->rm_core);
kfree(ops);
return;
}

cpuhp_setup_state_nocalls(CPUHP_KVM_PPC_BOOK3S_PREPARE,
"ppc/kvm_book3s:prepare",
kvmppc_set_host_core,
kvmppc_clear_host_core);
put_online_cpus();
cpuhp_setup_state_nocalls_cpuslocked(CPUHP_KVM_PPC_BOOK3S_PREPARE,
"ppc/kvm_book3s:prepare",
kvmppc_set_host_core,
kvmppc_clear_host_core);
cpus_read_unlock();
}

void kvmppc_free_host_rm_ops(void)
22 changes: 19 additions & 3 deletions arch/powerpc/mm/numa.c
Original file line number Diff line number Diff line change
@@ -1311,8 +1311,10 @@ static int update_lookup_table(void *data)
/*
* Update the node maps and sysfs entries for each cpu whose home node
* has changed. Returns 1 when the topology has changed, and 0 otherwise.
*
* cpus_locked says whether we already hold cpu_hotplug_lock.
*/
int arch_update_cpu_topology(void)
int numa_update_cpu_topology(bool cpus_locked)
{
unsigned int cpu, sibling, changed = 0;
struct topology_update_data *updates, *ud;
@@ -1400,15 +1402,23 @@ int arch_update_cpu_topology(void)
if (!cpumask_weight(&updated_cpus))
goto out;

stop_machine(update_cpu_topology, &updates[0], &updated_cpus);
if (cpus_locked)
stop_machine_cpuslocked(update_cpu_topology, &updates[0],
&updated_cpus);
else
stop_machine(update_cpu_topology, &updates[0], &updated_cpus);

/*
* Update the numa-cpu lookup table with the new mappings, even for
* offline CPUs. It is best to perform this update from the stop-
* machine context.
*/
stop_machine(update_lookup_table, &updates[0],
if (cpus_locked)
stop_machine_cpuslocked(update_lookup_table, &updates[0],
cpumask_of(raw_smp_processor_id()));
else
stop_machine(update_lookup_table, &updates[0],
cpumask_of(raw_smp_processor_id()));

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

int arch_update_cpu_topology(void)
{
lockdep_assert_cpus_held();
return numa_update_cpu_topology(true);
}

static void topology_work_fn(struct work_struct *work)
{
rebuild_sched_domains();
7 changes: 4 additions & 3 deletions arch/powerpc/platforms/powernv/subcore.c
Original file line number Diff line number Diff line change
@@ -348,17 +348,18 @@ static int set_subcores_per_core(int new_mode)
state->master = 0;
}

get_online_cpus();
cpus_read_lock();

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

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

stop_machine(cpu_update_split_mode, &new_mode, cpu_online_mask);
stop_machine_cpuslocked(cpu_update_split_mode, &new_mode,
cpu_online_mask);

put_online_cpus();
cpus_read_unlock();

return 0;
}
2 changes: 1 addition & 1 deletion arch/s390/kernel/jump_label.c
Original file line number Diff line number Diff line change
@@ -93,7 +93,7 @@ void arch_jump_label_transform(struct jump_entry *entry,
args.entry = entry;
args.type = type;

stop_machine(__sm_arch_jump_label_transform, &args, NULL);
stop_machine_cpuslocked(__sm_arch_jump_label_transform, &args, NULL);
}

void arch_jump_label_transform_static(struct jump_entry *entry,
4 changes: 2 additions & 2 deletions arch/s390/kernel/kprobes.c
Original file line number Diff line number Diff line change
@@ -196,15 +196,15 @@ void arch_arm_kprobe(struct kprobe *p)
{
struct swap_insn_args args = {.p = p, .arm_kprobe = 1};

stop_machine(swap_instruction, &args, NULL);
stop_machine_cpuslocked(swap_instruction, &args, NULL);
}
NOKPROBE_SYMBOL(arch_arm_kprobe);

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

stop_machine(swap_instruction, &args, NULL);
stop_machine_cpuslocked(swap_instruction, &args, NULL);
}
NOKPROBE_SYMBOL(arch_disarm_kprobe);

6 changes: 3 additions & 3 deletions arch/s390/kernel/time.c
Original file line number Diff line number Diff line change
@@ -636,10 +636,10 @@ static void stp_work_fn(struct work_struct *work)
goto out_unlock;

memset(&stp_sync, 0, sizeof(stp_sync));
get_online_cpus();
cpus_read_lock();
atomic_set(&stp_sync.cpus, num_online_cpus() - 1);
stop_machine(stp_sync_clock, &stp_sync, cpu_online_mask);
put_online_cpus();
stop_machine_cpuslocked(stp_sync_clock, &stp_sync, cpu_online_mask);
cpus_read_unlock();

if (!check_sync_clock())
/*
2 changes: 0 additions & 2 deletions arch/sparc/kernel/jump_label.c
Original file line number Diff line number Diff line change
@@ -41,12 +41,10 @@ void arch_jump_label_transform(struct jump_entry *entry,
val = 0x01000000;
}

get_online_cpus();
mutex_lock(&text_mutex);
*insn = val;
flushi(insn);
mutex_unlock(&text_mutex);
put_online_cpus();
}

#endif
2 changes: 0 additions & 2 deletions arch/tile/kernel/jump_label.c
Original file line number Diff line number Diff line change
@@ -45,14 +45,12 @@ static void __jump_label_transform(struct jump_entry *e,
void arch_jump_label_transform(struct jump_entry *e,
enum jump_label_type type)
{
get_online_cpus();
mutex_lock(&text_mutex);

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

mutex_unlock(&text_mutex);
put_online_cpus();
}

__init_or_module void arch_jump_label_transform_static(struct jump_entry *e,
1 change: 0 additions & 1 deletion arch/x86/events/core.c
Original file line number Diff line number Diff line change
@@ -2233,7 +2233,6 @@ void perf_check_microcode(void)
if (x86_pmu.check_microcode)
x86_pmu.check_microcode();
}
EXPORT_SYMBOL_GPL(perf_check_microcode);

static struct pmu pmu = {
.pmu_enable = x86_pmu_enable,
11 changes: 5 additions & 6 deletions arch/x86/events/intel/core.c
Original file line number Diff line number Diff line change
@@ -3425,12 +3425,10 @@ static void intel_snb_check_microcode(void)
int pebs_broken = 0;
int cpu;

get_online_cpus();
for_each_online_cpu(cpu) {
if ((pebs_broken = intel_snb_pebs_broken(cpu)))
break;
}
put_online_cpus();

if (pebs_broken == x86_pmu.pebs_broken)
return;
@@ -3503,7 +3501,9 @@ static bool check_msr(unsigned long msr, u64 mask)
static __init void intel_sandybridge_quirk(void)
{
x86_pmu.check_microcode = intel_snb_check_microcode;
cpus_read_lock();
intel_snb_check_microcode();
cpus_read_unlock();
}

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

lockup_detector_resume();

get_online_cpus();
cpus_read_lock();

for_each_online_cpu(c) {
for_each_online_cpu(c)
free_excl_cntrs(c);
}

put_online_cpus();
cpus_read_unlock();
pr_info("PMU erratum BJ122, BV98, HSD29 workaround disabled, HT off\n");
return 0;
}
16 changes: 8 additions & 8 deletions arch/x86/events/intel/cqm.c
Original file line number Diff line number Diff line change
@@ -1682,7 +1682,7 @@ static int __init intel_cqm_init(void)
*
* Also, check that the scales match on all cpus.
*/
get_online_cpus();
cpus_read_lock();
for_each_online_cpu(cpu) {
struct cpuinfo_x86 *c = &cpu_data(cpu);

@@ -1746,14 +1746,14 @@ static int __init intel_cqm_init(void)
* Setup the hot cpu notifier once we are sure cqm
* is enabled to avoid notifier leak.
*/
cpuhp_setup_state(CPUHP_AP_PERF_X86_CQM_STARTING,
"perf/x86/cqm:starting",
intel_cqm_cpu_starting, NULL);
cpuhp_setup_state(CPUHP_AP_PERF_X86_CQM_ONLINE, "perf/x86/cqm:online",
NULL, intel_cqm_cpu_exit);

cpuhp_setup_state_cpuslocked(CPUHP_AP_PERF_X86_CQM_STARTING,
"perf/x86/cqm:starting",
intel_cqm_cpu_starting, NULL);
cpuhp_setup_state_cpuslocked(CPUHP_AP_PERF_X86_CQM_ONLINE,
"perf/x86/cqm:online",
NULL, intel_cqm_cpu_exit);
out:
put_online_cpus();
cpus_read_unlock();

if (ret) {
kfree(str);
2 changes: 0 additions & 2 deletions arch/x86/kernel/cpu/mtrr/main.c
Original file line number Diff line number Diff line change
@@ -807,10 +807,8 @@ void mtrr_save_state(void)
if (!mtrr_enabled())
return;

get_online_cpus();
first_cpu = cpumask_first(cpu_online_mask);
smp_call_function_single(first_cpu, mtrr_save_fixed_ranges, NULL, 1);
put_online_cpus();
}

void set_mtrr_aps_delayed_init(void)
Loading

0 comments on commit 9a9594e

Please sign in to comment.