Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 18608255 authored by Osvaldo Banuelos's avatar Osvaldo Banuelos
Browse files

Merge cpuhp-registration-fixes into msm-3.10

CPU hotplug callback registration takes the locks cpu_hotplug
and cpu_add_remove_lock in one order whereas the hotplug
procedure takes the same locks in the opposite order. Patch
series address a race condition when registering these callbacks
and prevents an ABBA deadlock. See LKML[0].

The fix is split into two main parts:
1- Add support for cpu_notifier_register_begin and
   cpu_notifier_register_done()
2- Update driver-specific cpu hotplug call back registration
   to use newly added APIs in 1 and drop get/put_online_cpus()

[0]: https://lkml.org/lkml/2014/2/14/59



* (13 commits):
  cpu: fix section mismatch warnings with __hotcpu_register
  net/core/flow.c: Fix CPU hotplug callback registration
  mm, zswap: Fix CPU hotplug callback registration
  mm, vmstat: Fix CPU hotplug callback registration
  profile: Fix CPU hotplug callback registration
  trace, ring-buffer: Fix CPU hotplug callback registration
  drivers/base/topology.c: Fix CPU hotplug callback registration
  arm64, debug-monitors: Fix CPU hotplug callback registration
  arm64, hw_breakpoint.c: Fix CPU hotplug callback registration
  arm, hw-breakpoint: Fix CPU hotplug callback registration
  CPU hotplug, perf: Fix CPU hotplug callback registration
  Doc/cpu-hotplug: Specify race-free way to register CPU hotplug callbacks
  CPU hotplug: Provide lockless versions of callback registration functions

Change-Id: I875178564d7eb77bc2acf1fceeacb03bf64ffb2c
Signed-off-by: default avatarOsvaldo Banuelos <osvaldob@codeaurora.org>
parents b2493d05 9a43ce11
Loading
Loading
Loading
Loading
+45 −0
Original line number Diff line number Diff line
@@ -312,12 +312,57 @@ things will happen if a notifier in path sent a BAD notify code.
Q: I don't see my action being called for all CPUs already up and running?
A: Yes, CPU notifiers are called only when new CPUs are on-lined or offlined.
   If you need to perform some action for each cpu already in the system, then
   do this:

	for_each_online_cpu(i) {
		foobar_cpu_callback(&foobar_cpu_notifier, CPU_UP_PREPARE, i);
		foobar_cpu_callback(&foobar_cpu_notifier, CPU_ONLINE, i);
	}

   However, if you want to register a hotplug callback, as well as perform
   some initialization for CPUs that are already online, then do this:

   Version 1: (Correct)
   ---------

   	cpu_notifier_register_begin();

		for_each_online_cpu(i) {
			foobar_cpu_callback(&foobar_cpu_notifier,
					    CPU_UP_PREPARE, i);
			foobar_cpu_callback(&foobar_cpu_notifier,
					    CPU_ONLINE, i);
		}

	/* Note the use of the double underscored version of the API */
	__register_cpu_notifier(&foobar_cpu_notifier);

	cpu_notifier_register_done();

   Note that the following code is *NOT* the right way to achieve this,
   because it is prone to an ABBA deadlock between the cpu_add_remove_lock
   and the cpu_hotplug.lock.

   Version 2: (Wrong!)
   ---------

	get_online_cpus();

		for_each_online_cpu(i) {
			foobar_cpu_callback(&foobar_cpu_notifier,
					    CPU_UP_PREPARE, i);
			foobar_cpu_callback(&foobar_cpu_notifier,
					    CPU_ONLINE, i);
		}

	register_cpu_notifier(&foobar_cpu_notifier);

	put_online_cpus();

    So always use the first version shown above when you want to register
    callbacks as well as initialize the already online CPUs.


Q: If i would like to develop cpu hotplug support for a new architecture,
   what do i need at a minimum?
A: The following are what is required for CPU hotplug infrastructure to work
+7 −1
Original line number Diff line number Diff line
@@ -1094,6 +1094,8 @@ static int __init arch_hw_breakpoint_init(void)
	core_num_brps = get_num_brps();
	core_num_wrps = get_num_wrps();

	cpu_notifier_register_begin();

	/*
	 * We need to tread carefully here because DBGSWENABLE may be
	 * driven low on this core and there isn't an architected way to
@@ -1110,6 +1112,7 @@ static int __init arch_hw_breakpoint_init(void)
	if (!cpumask_empty(&debug_err_mask)) {
		core_num_brps = 0;
		core_num_wrps = 0;
		cpu_notifier_register_done();
		return 0;
	}

@@ -1129,7 +1132,10 @@ static int __init arch_hw_breakpoint_init(void)
			TRAP_HWBKPT, "breakpoint debug exception");

	/* Register hotplug and PM notifiers. */
	register_cpu_notifier(&dbg_reset_nb);
	__register_cpu_notifier(&dbg_reset_nb);

	cpu_notifier_register_done();

	pm_init();
	return 0;
}
+5 −1
Original line number Diff line number Diff line
@@ -155,12 +155,16 @@ static struct notifier_block __cpuinitdata os_lock_nb = {

static int __cpuinit debug_monitors_init(void)
{
	cpu_notifier_register_begin();

	/* Clear the OS lock. */
	smp_call_function(clear_os_lock, NULL, 1);
	clear_os_lock(NULL);

	/* Register hotplug handler. */
	register_cpu_notifier(&os_lock_nb);
	__register_cpu_notifier(&os_lock_nb);

	cpu_notifier_register_done();
	return 0;
}
postcore_initcall(debug_monitors_init);
+6 −1
Original line number Diff line number Diff line
@@ -913,6 +913,8 @@ static int __init arch_hw_breakpoint_init(void)
	pr_info("found %d breakpoint and %d watchpoint registers.\n",
		core_num_brps, core_num_wrps);

	cpu_notifier_register_begin();

	/*
	 * Reset the breakpoint resources. We assume that a halting
	 * debugger will leave the world in a nice state for us.
@@ -927,7 +929,10 @@ static int __init arch_hw_breakpoint_init(void)
			      TRAP_HWBKPT, "hw-watchpoint handler");

	/* Register hotplug notifier. */
	register_cpu_notifier(&hw_breakpoint_reset_nb);
	__register_cpu_notifier(&hw_breakpoint_reset_nb);

	cpu_notifier_register_done();

	/* Register cpu_suspend hw breakpoint restore hook */
	cpu_suspend_set_dbg_restorer(hw_breakpoint_reset);

+8 −4
Original line number Diff line number Diff line
@@ -181,16 +181,20 @@ static int __cpuinit topology_cpu_callback(struct notifier_block *nfb,
static int __cpuinit topology_sysfs_init(void)
{
	int cpu;
	int rc;
	int rc = 0;

	cpu_notifier_register_begin();

	for_each_online_cpu(cpu) {
		rc = topology_add_dev(cpu);
		if (rc)
			return rc;
			goto out;
	}
	hotcpu_notifier(topology_cpu_callback, 0);
	__hotcpu_notifier(topology_cpu_callback, 0);

	return 0;
out:
	cpu_notifier_register_done();
	return rc;
}

device_initcall(topology_sysfs_init);
Loading