summaryrefslogtreecommitdiff
path: root/kernel/task_work.c
diff options
context:
space:
mode:
authorDmitry Torokhov <dmitry.torokhov@gmail.com>2020-07-21 19:02:33 -0700
committerDmitry Torokhov <dmitry.torokhov@gmail.com>2020-07-21 19:02:33 -0700
commit9b031c86506cef9acae45e61339fcf9deaabb793 (patch)
tree9095d638ba9384f86df8d61dcf1f129c082481e1 /kernel/task_work.c
parent53aab92dec447f93489e07924e310d605a389dea (diff)
parent04d5ce620f794f1df69b5f1b9ad62910fea547f1 (diff)
Merge branch 'elan-i2c' into next
Bring in update to Elan touchpad driver to support newer touchpads with higher resolution.
Diffstat (limited to 'kernel/task_work.c')
-rw-r--r--kernel/task_work.c18
1 files changed, 14 insertions, 4 deletions
diff --git a/kernel/task_work.c b/kernel/task_work.c
index 0fef395662a6..825f28259a19 100644
--- a/kernel/task_work.c
+++ b/kernel/task_work.c
@@ -97,16 +97,26 @@ void task_work_run(void)
* work->func() can do task_work_add(), do not set
* work_exited unless the list is empty.
*/
- raw_spin_lock_irq(&task->pi_lock);
do {
+ head = NULL;
work = READ_ONCE(task->task_works);
- head = !work && (task->flags & PF_EXITING) ?
- &work_exited : NULL;
+ if (!work) {
+ if (task->flags & PF_EXITING)
+ head = &work_exited;
+ else
+ break;
+ }
} while (cmpxchg(&task->task_works, work, head) != work);
- raw_spin_unlock_irq(&task->pi_lock);
if (!work)
break;
+ /*
+ * Synchronize with task_work_cancel(). It can not remove
+ * the first entry == work, cmpxchg(task_works) must fail.
+ * But it can remove another entry from the ->next list.
+ */
+ raw_spin_lock_irq(&task->pi_lock);
+ raw_spin_unlock_irq(&task->pi_lock);
do {
next = work->next;