workqueue: add missing wmb() in clear_work_data()
Tejun Heo
maintainerPATCH 1/1 workqueue: add missing wmb() in clear_work_data()
Quoted 1 line
From
23657bb192f14b789e4c478def8f11ecc95b4f6cMon Sep 17 00:00:00 2001
From: Tejun Heo <[email protected]>
Date: Mon, 13 Aug 2012 17:08:19 -0700
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.
---
Fix for another theoretical wmb problem. Will push through wq/for-3.7.
Thanks.
kernel/workqueue.c | 19 ++++++++++++------- 1 files changed, 12 insertions(+), 7 deletions(-)
kernel/workqueue.c +12 -7
@@ -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,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 ); }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 ); }
@@ -2182,14 +2190,11 @@ __acquires(&gcwq->lock)wake_up_worker (pool);/* -* Record the last CPU and clear PENDING. 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. Also, clear -* PENDING inside @gcwq->lock so that PENDING and queued state -* changes happen together while IRQ is disabled. +* Record the last CPU and clear PENDING which should be the last +* update to @work. Also, do this 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);spin_unlock_irq (&gcwq->lock);
Signature · 1 line
1.7.7.3