diff options
Diffstat (limited to 'kernel')
-rw-r--r-- | kernel/task_work.c | 10 |
1 files changed, 6 insertions, 4 deletions
diff --git a/kernel/task_work.c b/kernel/task_work.c index 6ab4842b00e8..d513051fcca2 100644 --- a/kernel/task_work.c +++ b/kernel/task_work.c | |||
@@ -29,7 +29,7 @@ task_work_add(struct task_struct *task, struct callback_head *work, bool notify) | |||
29 | struct callback_head *head; | 29 | struct callback_head *head; |
30 | 30 | ||
31 | do { | 31 | do { |
32 | head = ACCESS_ONCE(task->task_works); | 32 | head = READ_ONCE(task->task_works); |
33 | if (unlikely(head == &work_exited)) | 33 | if (unlikely(head == &work_exited)) |
34 | return -ESRCH; | 34 | return -ESRCH; |
35 | work->next = head; | 35 | work->next = head; |
@@ -57,6 +57,9 @@ task_work_cancel(struct task_struct *task, task_work_func_t func) | |||
57 | struct callback_head **pprev = &task->task_works; | 57 | struct callback_head **pprev = &task->task_works; |
58 | struct callback_head *work; | 58 | struct callback_head *work; |
59 | unsigned long flags; | 59 | unsigned long flags; |
60 | |||
61 | if (likely(!task->task_works)) | ||
62 | return NULL; | ||
60 | /* | 63 | /* |
61 | * If cmpxchg() fails we continue without updating pprev. | 64 | * If cmpxchg() fails we continue without updating pprev. |
62 | * Either we raced with task_work_add() which added the | 65 | * Either we raced with task_work_add() which added the |
@@ -64,8 +67,7 @@ task_work_cancel(struct task_struct *task, task_work_func_t func) | |||
64 | * we raced with task_work_run(), *pprev == NULL/exited. | 67 | * we raced with task_work_run(), *pprev == NULL/exited. |
65 | */ | 68 | */ |
66 | raw_spin_lock_irqsave(&task->pi_lock, flags); | 69 | raw_spin_lock_irqsave(&task->pi_lock, flags); |
67 | while ((work = ACCESS_ONCE(*pprev))) { | 70 | while ((work = lockless_dereference(*pprev))) { |
68 | smp_read_barrier_depends(); | ||
69 | if (work->func != func) | 71 | if (work->func != func) |
70 | pprev = &work->next; | 72 | pprev = &work->next; |
71 | else if (cmpxchg(pprev, work, work->next) == work) | 73 | else if (cmpxchg(pprev, work, work->next) == work) |
@@ -95,7 +97,7 @@ void task_work_run(void) | |||
95 | * work_exited unless the list is empty. | 97 | * work_exited unless the list is empty. |
96 | */ | 98 | */ |
97 | do { | 99 | do { |
98 | work = ACCESS_ONCE(task->task_works); | 100 | work = READ_ONCE(task->task_works); |
99 | head = !work && (task->flags & PF_EXITING) ? | 101 | head = !work && (task->flags & PF_EXITING) ? |
100 | &work_exited : NULL; | 102 | &work_exited : NULL; |
101 | } while (cmpxchg(&task->task_works, work, head) != work); | 103 | } while (cmpxchg(&task->task_works, work, head) != work); |