Skip to content

Commit

Permalink
stop_machine: Provide stop_machine_cpuslocked()
Browse files Browse the repository at this point in the history
Some call sites of stop_machine() are within a get_online_cpus() protected
region.

stop_machine() calls get_online_cpus() as well, which is possible in the
current implementation but prevents converting the hotplug locking to a
percpu rwsem.

Provide stop_machine_cpuslocked() to avoid nested calls to get_online_cpus().

Signed-off-by: Sebastian Andrzej Siewior <[email protected]>
Signed-off-by: Thomas Gleixner <[email protected]>
Tested-by: Paul E. McKenney <[email protected]>
Acked-by: Paul E. McKenney <[email protected]>
Acked-by: Ingo Molnar <[email protected]>
Cc: Peter Zijlstra <[email protected]>
Cc: Steven Rostedt <[email protected]>
Link: http://lkml.kernel.org/r/[email protected]
  • Loading branch information
Sebastian Andrzej Siewior authored and KAGA-KOKO committed May 26, 2017
1 parent 9805c67 commit fe5595c
Show file tree
Hide file tree
Showing 2 changed files with 30 additions and 7 deletions.
26 changes: 23 additions & 3 deletions include/linux/stop_machine.h
Original file line number Diff line number Diff line change
Expand Up @@ -116,15 +116,29 @@ static inline int try_stop_cpus(const struct cpumask *cpumask,
* @fn() runs.
*
* This can be thought of as a very heavy write lock, equivalent to
* grabbing every spinlock in the kernel. */
* grabbing every spinlock in the kernel.
*
* Protects against CPU hotplug.
*/
int stop_machine(cpu_stop_fn_t fn, void *data, const struct cpumask *cpus);

/**
* stop_machine_cpuslocked: freeze the machine on all CPUs and run this function
* @fn: the function to run
* @data: the data ptr for the @fn()
* @cpus: the cpus to run the @fn() on (NULL = any online cpu)
*
* Same as above. Must be called from with in a cpus_read_lock() protected
* region. Avoids nested calls to cpus_read_lock().
*/
int stop_machine_cpuslocked(cpu_stop_fn_t fn, void *data, const struct cpumask *cpus);

int stop_machine_from_inactive_cpu(cpu_stop_fn_t fn, void *data,
const struct cpumask *cpus);
#else /* CONFIG_SMP || CONFIG_HOTPLUG_CPU */

static inline int stop_machine(cpu_stop_fn_t fn, void *data,
const struct cpumask *cpus)
static inline int stop_machine_cpuslocked(cpu_stop_fn_t fn, void *data,
const struct cpumask *cpus)
{
unsigned long flags;
int ret;
Expand All @@ -134,6 +148,12 @@ static inline int stop_machine(cpu_stop_fn_t fn, void *data,
return ret;
}

static inline int stop_machine(cpu_stop_fn_t fn, void *data,
const struct cpumask *cpus)
{
return stop_machine_cpuslocked(fn, data, cpus);
}

static inline int stop_machine_from_inactive_cpu(cpu_stop_fn_t fn, void *data,
const struct cpumask *cpus)
{
Expand Down
11 changes: 7 additions & 4 deletions kernel/stop_machine.c
Original file line number Diff line number Diff line change
Expand Up @@ -552,7 +552,8 @@ static int __init cpu_stop_init(void)
}
early_initcall(cpu_stop_init);

static int __stop_machine(cpu_stop_fn_t fn, void *data, const struct cpumask *cpus)
int stop_machine_cpuslocked(cpu_stop_fn_t fn, void *data,
const struct cpumask *cpus)
{
struct multi_stop_data msdata = {
.fn = fn,
Expand All @@ -561,6 +562,8 @@ static int __stop_machine(cpu_stop_fn_t fn, void *data, const struct cpumask *cp
.active_cpus = cpus,
};

lockdep_assert_cpus_held();

if (!stop_machine_initialized) {
/*
* Handle the case where stop_machine() is called
Expand Down Expand Up @@ -590,9 +593,9 @@ int stop_machine(cpu_stop_fn_t fn, void *data, const struct cpumask *cpus)
int ret;

/* No CPUs can come up or down during this. */
get_online_cpus();
ret = __stop_machine(fn, data, cpus);
put_online_cpus();
cpus_read_lock();
ret = stop_machine_cpuslocked(fn, data, cpus);
cpus_read_unlock();
return ret;
}
EXPORT_SYMBOL_GPL(stop_machine);
Expand Down

0 comments on commit fe5595c

Please sign in to comment.