diff options
Diffstat (limited to 'kernel/stop_machine.c')
| -rw-r--r-- | kernel/stop_machine.c | 55 | 
1 files changed, 45 insertions, 10 deletions
| diff --git a/kernel/stop_machine.c b/kernel/stop_machine.c index 286c41722e8..0cd415ee62a 100644 --- a/kernel/stop_machine.c +++ b/kernel/stop_machine.c @@ -38,7 +38,10 @@ struct stop_machine_data {  static unsigned int num_threads;  static atomic_t thread_ack;  static DEFINE_MUTEX(lock); - +/* setup_lock protects refcount, stop_machine_wq and stop_machine_work. */ +static DEFINE_MUTEX(setup_lock); +/* Users of stop_machine. */ +static int refcount;  static struct workqueue_struct *stop_machine_wq;  static struct stop_machine_data active, idle;  static const cpumask_t *active_cpus; @@ -109,6 +112,43 @@ static int chill(void *unused)  	return 0;  } +int stop_machine_create(void) +{ +	mutex_lock(&setup_lock); +	if (refcount) +		goto done; +	stop_machine_wq = create_rt_workqueue("kstop"); +	if (!stop_machine_wq) +		goto err_out; +	stop_machine_work = alloc_percpu(struct work_struct); +	if (!stop_machine_work) +		goto err_out; +done: +	refcount++; +	mutex_unlock(&setup_lock); +	return 0; + +err_out: +	if (stop_machine_wq) +		destroy_workqueue(stop_machine_wq); +	mutex_unlock(&setup_lock); +	return -ENOMEM; +} +EXPORT_SYMBOL_GPL(stop_machine_create); + +void stop_machine_destroy(void) +{ +	mutex_lock(&setup_lock); +	refcount--; +	if (refcount) +		goto done; +	destroy_workqueue(stop_machine_wq); +	free_percpu(stop_machine_work); +done: +	mutex_unlock(&setup_lock); +} +EXPORT_SYMBOL_GPL(stop_machine_destroy); +  int __stop_machine(int (*fn)(void *), void *data, const struct cpumask *cpus)  {  	struct work_struct *sm_work; @@ -146,19 +186,14 @@ int stop_machine(int (*fn)(void *), void *data, const struct cpumask *cpus)  {  	int ret; +	ret = stop_machine_create(); +	if (ret) +		return ret;  	/* No CPUs can come up or down during this. */  	get_online_cpus();  	ret = __stop_machine(fn, data, cpus);  	put_online_cpus(); - +	stop_machine_destroy();  	return ret;  }  EXPORT_SYMBOL_GPL(stop_machine); - -static int __init stop_machine_init(void) -{ -	stop_machine_wq = create_rt_workqueue("kstop"); -	stop_machine_work = alloc_percpu(struct work_struct); -	return 0; -} -core_initcall(stop_machine_init); | 
