diff options
Diffstat (limited to 'kernel/task_work.c')
| -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); |
