diff options
Diffstat (limited to 'kernel/workqueue.c')
| -rw-r--r-- | kernel/workqueue.c | 37 | 
1 files changed, 18 insertions, 19 deletions
diff --git a/kernel/workqueue.c b/kernel/workqueue.c index 1e1373bcb3e..3c5a79e2134 100644 --- a/kernel/workqueue.c +++ b/kernel/workqueue.c @@ -1349,8 +1349,16 @@ static void busy_worker_rebind_fn(struct work_struct *work)  	struct worker *worker = container_of(work, struct worker, rebind_work);  	struct global_cwq *gcwq = worker->pool->gcwq; -	if (worker_maybe_bind_and_lock(worker)) -		worker_clr_flags(worker, WORKER_REBIND); +	worker_maybe_bind_and_lock(worker); + +	/* +	 * %WORKER_REBIND must be cleared even if the above binding failed; +	 * otherwise, we may confuse the next CPU_UP cycle or oops / get +	 * stuck by calling idle_worker_rebind() prematurely.  If CPU went +	 * down again inbetween, %WORKER_UNBOUND would be set, so clearing +	 * %WORKER_REBIND is always safe. +	 */ +	worker_clr_flags(worker, WORKER_REBIND);  	spin_unlock_irq(&gcwq->lock);  } @@ -3568,18 +3576,17 @@ static int __devinit workqueue_cpu_down_callback(struct notifier_block *nfb,  #ifdef CONFIG_SMP  struct work_for_cpu { -	struct completion completion; +	struct work_struct work;  	long (*fn)(void *);  	void *arg;  	long ret;  }; -static int do_work_for_cpu(void *_wfc) +static void work_for_cpu_fn(struct work_struct *work)  { -	struct work_for_cpu *wfc = _wfc; +	struct work_for_cpu *wfc = container_of(work, struct work_for_cpu, work); +  	wfc->ret = wfc->fn(wfc->arg); -	complete(&wfc->completion); -	return 0;  }  /** @@ -3594,19 +3601,11 @@ static int do_work_for_cpu(void *_wfc)   */  long work_on_cpu(unsigned int cpu, long (*fn)(void *), void *arg)  { -	struct task_struct *sub_thread; -	struct work_for_cpu wfc = { -		.completion = COMPLETION_INITIALIZER_ONSTACK(wfc.completion), -		.fn = fn, -		.arg = arg, -	}; +	struct work_for_cpu wfc = { .fn = fn, .arg = arg }; -	sub_thread = kthread_create(do_work_for_cpu, &wfc, "work_for_cpu"); -	if (IS_ERR(sub_thread)) -		return PTR_ERR(sub_thread); -	kthread_bind(sub_thread, cpu); -	wake_up_process(sub_thread); -	wait_for_completion(&wfc.completion); +	INIT_WORK_ONSTACK(&wfc.work, work_for_cpu_fn); +	schedule_work_on(cpu, &wfc.work); +	flush_work(&wfc.work);  	return wfc.ret;  }  EXPORT_SYMBOL_GPL(work_on_cpu);  |