mirror of
https://github.com/AuxXxilium/linux_dsm_epyc7002.git
synced 2025-04-12 19:48:14 +07:00
workqueue: allow work_on_cpu() to be called recursively
If the @fn call work_on_cpu() again, the lockdep will complain: > [ INFO: possible recursive locking detected ] > 3.11.0-rc1-lockdep-fix-a #6 Not tainted > --------------------------------------------- > kworker/0:1/142 is trying to acquire lock: > ((&wfc.work)){+.+.+.}, at: [<ffffffff81077100>] flush_work+0x0/0xb0 > > but task is already holding lock: > ((&wfc.work)){+.+.+.}, at: [<ffffffff81075dd9>] process_one_work+0x169/0x610 > > other info that might help us debug this: > Possible unsafe locking scenario: > > CPU0 > ---- > lock((&wfc.work)); > lock((&wfc.work)); > > *** DEADLOCK *** It is false-positive lockdep report. In this sutiation, the two "wfc"s of the two work_on_cpu() are different, they are both on stack. flush_work() can't be deadlock. To fix this, we need to avoid the lockdep checking in this case, thus we instroduce a internal __flush_work() which skip the lockdep. tj: Minor comment adjustment. Signed-off-by: Lai Jiangshan <laijs@cn.fujitsu.com> Reported-by: "Srivatsa S. Bhat" <srivatsa.bhat@linux.vnet.ibm.com> Reported-by: Alexander Duyck <alexander.h.duyck@intel.com> Signed-off-by: Tejun Heo <tj@kernel.org>
This commit is contained in:
parent
ad81f0545e
commit
c2fda50966
@ -2817,6 +2817,19 @@ static bool start_flush_work(struct work_struct *work, struct wq_barrier *barr)
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static bool __flush_work(struct work_struct *work)
|
||||||
|
{
|
||||||
|
struct wq_barrier barr;
|
||||||
|
|
||||||
|
if (start_flush_work(work, &barr)) {
|
||||||
|
wait_for_completion(&barr.done);
|
||||||
|
destroy_work_on_stack(&barr.work);
|
||||||
|
return true;
|
||||||
|
} else {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* flush_work - wait for a work to finish executing the last queueing instance
|
* flush_work - wait for a work to finish executing the last queueing instance
|
||||||
* @work: the work to flush
|
* @work: the work to flush
|
||||||
@ -2830,18 +2843,10 @@ static bool start_flush_work(struct work_struct *work, struct wq_barrier *barr)
|
|||||||
*/
|
*/
|
||||||
bool flush_work(struct work_struct *work)
|
bool flush_work(struct work_struct *work)
|
||||||
{
|
{
|
||||||
struct wq_barrier barr;
|
|
||||||
|
|
||||||
lock_map_acquire(&work->lockdep_map);
|
lock_map_acquire(&work->lockdep_map);
|
||||||
lock_map_release(&work->lockdep_map);
|
lock_map_release(&work->lockdep_map);
|
||||||
|
|
||||||
if (start_flush_work(work, &barr)) {
|
return __flush_work(work);
|
||||||
wait_for_completion(&barr.done);
|
|
||||||
destroy_work_on_stack(&barr.work);
|
|
||||||
return true;
|
|
||||||
} else {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
EXPORT_SYMBOL_GPL(flush_work);
|
EXPORT_SYMBOL_GPL(flush_work);
|
||||||
|
|
||||||
@ -4756,7 +4761,14 @@ long work_on_cpu(int cpu, long (*fn)(void *), void *arg)
|
|||||||
|
|
||||||
INIT_WORK_ONSTACK(&wfc.work, work_for_cpu_fn);
|
INIT_WORK_ONSTACK(&wfc.work, work_for_cpu_fn);
|
||||||
schedule_work_on(cpu, &wfc.work);
|
schedule_work_on(cpu, &wfc.work);
|
||||||
flush_work(&wfc.work);
|
|
||||||
|
/*
|
||||||
|
* The work item is on-stack and can't lead to deadlock through
|
||||||
|
* flushing. Use __flush_work() to avoid spurious lockdep warnings
|
||||||
|
* when work_on_cpu()s are nested.
|
||||||
|
*/
|
||||||
|
__flush_work(&wfc.work);
|
||||||
|
|
||||||
return wfc.ret;
|
return wfc.ret;
|
||||||
}
|
}
|
||||||
EXPORT_SYMBOL_GPL(work_on_cpu);
|
EXPORT_SYMBOL_GPL(work_on_cpu);
|
||||||
|
Loading…
Reference in New Issue
Block a user