mirror of
https://github.com/AuxXxilium/linux_dsm_epyc7002.git
synced 2025-04-02 04:05:22 +07:00
workqueue: add missing wmb() in clear_work_data()
Any operation which clears PENDING should be preceded by a wmb to guarantee that the next PENDING owner sees all the changes made before PENDING release. There are only two places where PENDING is cleared - set_work_cpu_and_clear_pending() and clear_work_data(). The caller of the former already does smp_wmb() but the latter doesn't have any. Move the wmb above set_work_cpu_and_clear_pending() into it and add one to clear_work_data(). There hasn't been any report related to this issue, and, given how clear_work_data() is used, it is extremely unlikely to have caused any actual problems on any architecture. Signed-off-by: Tejun Heo <tj@kernel.org> Cc: Oleg Nesterov <oleg@redhat.com>
This commit is contained in:
parent
1265057fa0
commit
23657bb192
@ -570,11 +570,19 @@ static void set_work_cwq(struct work_struct *work,
|
|||||||
static void set_work_cpu_and_clear_pending(struct work_struct *work,
|
static void set_work_cpu_and_clear_pending(struct work_struct *work,
|
||||||
unsigned int cpu)
|
unsigned int cpu)
|
||||||
{
|
{
|
||||||
|
/*
|
||||||
|
* The following wmb is paired with the implied mb in
|
||||||
|
* test_and_set_bit(PENDING) and ensures all updates to @work made
|
||||||
|
* here are visible to and precede any updates by the next PENDING
|
||||||
|
* owner.
|
||||||
|
*/
|
||||||
|
smp_wmb();
|
||||||
set_work_data(work, (unsigned long)cpu << WORK_OFFQ_CPU_SHIFT, 0);
|
set_work_data(work, (unsigned long)cpu << WORK_OFFQ_CPU_SHIFT, 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void clear_work_data(struct work_struct *work)
|
static void clear_work_data(struct work_struct *work)
|
||||||
{
|
{
|
||||||
|
smp_wmb(); /* see set_work_cpu_and_clear_pending() */
|
||||||
set_work_data(work, WORK_STRUCT_NO_CPU, 0);
|
set_work_data(work, WORK_STRUCT_NO_CPU, 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -2182,14 +2190,11 @@ __acquires(&gcwq->lock)
|
|||||||
wake_up_worker(pool);
|
wake_up_worker(pool);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Record the last CPU and clear PENDING. The following wmb is
|
* Record the last CPU and clear PENDING which should be the last
|
||||||
* paired with the implied mb in test_and_set_bit(PENDING) and
|
* update to @work. Also, do this inside @gcwq->lock so that
|
||||||
* ensures all updates to @work made here are visible to and
|
* PENDING and queued state changes happen together while IRQ is
|
||||||
* precede any updates by the next PENDING owner. Also, clear
|
* disabled.
|
||||||
* PENDING inside @gcwq->lock so that PENDING and queued state
|
|
||||||
* changes happen together while IRQ is disabled.
|
|
||||||
*/
|
*/
|
||||||
smp_wmb();
|
|
||||||
set_work_cpu_and_clear_pending(work, gcwq->cpu);
|
set_work_cpu_and_clear_pending(work, gcwq->cpu);
|
||||||
|
|
||||||
spin_unlock_irq(&gcwq->lock);
|
spin_unlock_irq(&gcwq->lock);
|
||||||
|
Loading…
Reference in New Issue
Block a user