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
torvalds committed Jul 4, 2017
2 parents 3ad918e + 993647a commit 9a9594e
Show file tree
Hide file tree
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
Expand Up @@ -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;
}

Expand All @@ -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();
Expand Down
2 changes: 1 addition & 1 deletion arch/arm/kernel/patch.c
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Up @@ -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)
Expand Down
1 change: 0 additions & 1 deletion arch/arm64/include/asm/insn.h
Original file line number Diff line number Diff line change
Expand Up @@ -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);
Expand Down
5 changes: 3 additions & 2 deletions arch/arm64/kernel/insn.c
Original file line number Diff line number Diff line change
Expand Up @@ -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 = {
Expand All @@ -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)
Expand Down
2 changes: 0 additions & 2 deletions arch/mips/kernel/jump_label.c
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand All @@ -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
Expand Up @@ -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)
{
Expand Down Expand Up @@ -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)
Expand Down
2 changes: 1 addition & 1 deletion arch/powerpc/kernel/rtasd.c
Original file line number Diff line number Diff line change
Expand Up @@ -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);
Expand Down
14 changes: 7 additions & 7 deletions arch/powerpc/kvm/book3s_hv.c
Original file line number Diff line number Diff line change
Expand Up @@ -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))
Expand All @@ -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)
Expand Down
22 changes: 19 additions & 3 deletions arch/powerpc/mm/numa.c
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down Expand Up @@ -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);
Expand All @@ -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();
Expand Down
7 changes: 4 additions & 3 deletions arch/powerpc/platforms/powernv/subcore.c
Original file line number Diff line number Diff line change
Expand Up @@ -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;
}
Expand Down
2 changes: 1 addition & 1 deletion arch/s390/kernel/jump_label.c
Original file line number Diff line number Diff line change
Expand Up @@ -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,
Expand Down
4 changes: 2 additions & 2 deletions arch/s390/kernel/kprobes.c
Original file line number Diff line number Diff line change
Expand Up @@ -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);

Expand Down
6 changes: 3 additions & 3 deletions arch/s390/kernel/time.c
Original file line number Diff line number Diff line change
Expand Up @@ -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())
/*
Expand Down
2 changes: 0 additions & 2 deletions arch/sparc/kernel/jump_label.c
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Up @@ -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,
Expand Down
1 change: 0 additions & 1 deletion arch/x86/events/core.c
Original file line number Diff line number Diff line change
Expand Up @@ -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,
Expand Down
11 changes: 5 additions & 6 deletions arch/x86/events/intel/core.c
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down Expand Up @@ -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 = {
Expand Down Expand Up @@ -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;
}
Expand Down
16 changes: 8 additions & 8 deletions arch/x86/events/intel/cqm.c
Original file line number Diff line number Diff line change
Expand Up @@ -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);

Expand Down Expand Up @@ -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);
Expand Down
2 changes: 0 additions & 2 deletions arch/x86/kernel/cpu/mtrr/main.c
Original file line number Diff line number Diff line change
Expand Up @@ -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)
Expand Down
Loading

0 comments on commit 9a9594e

Please sign in to comment.