Merge tag 'fixes-for-v4.1-rc2' of https://github.com/rjarzmik/linux into fixes
[linux-2.6-block.git] / kernel / task_work.c
CommitLineData
e73f8959
ON
1#include <linux/spinlock.h>
2#include <linux/task_work.h>
3#include <linux/tracehook.h>
4
9da33de6
ON
5static struct callback_head work_exited; /* all we need is ->next == NULL */
6
892f6668
ON
7/**
8 * task_work_add - ask the @task to execute @work->func()
9 * @task: the task which should run the callback
10 * @work: the callback to run
11 * @notify: send the notification if true
12 *
13 * Queue @work for task_work_run() below and notify the @task if @notify.
14 * Fails if the @task is exiting/exited and thus it can't process this @work.
15 * Otherwise @work->func() will be called when the @task returns from kernel
16 * mode or exits.
17 *
18 * This is like the signal handler which runs in kernel mode, but it doesn't
19 * try to wake up the @task.
20 *
21 * RETURNS:
22 * 0 if succeeds or -ESRCH.
23 */
e73f8959 24int
ac3d0da8 25task_work_add(struct task_struct *task, struct callback_head *work, bool notify)
e73f8959 26{
ac3d0da8 27 struct callback_head *head;
9da33de6 28
ac3d0da8
ON
29 do {
30 head = ACCESS_ONCE(task->task_works);
9da33de6
ON
31 if (unlikely(head == &work_exited))
32 return -ESRCH;
ac3d0da8
ON
33 work->next = head;
34 } while (cmpxchg(&task->task_works, head, work) != head);
e73f8959 35
ed3e694d 36 if (notify)
e73f8959 37 set_notify_resume(task);
ed3e694d 38 return 0;
e73f8959
ON
39}
40
892f6668
ON
41/**
42 * task_work_cancel - cancel a pending work added by task_work_add()
43 * @task: the task which should execute the work
44 * @func: identifies the work to remove
45 *
46 * Find the last queued pending work with ->func == @func and remove
47 * it from queue.
48 *
49 * RETURNS:
50 * The found work or NULL if not found.
51 */
67d12145 52struct callback_head *
e73f8959
ON
53task_work_cancel(struct task_struct *task, task_work_func_t func)
54{
ac3d0da8 55 struct callback_head **pprev = &task->task_works;
205e550a 56 struct callback_head *work;
e73f8959 57 unsigned long flags;
ac3d0da8
ON
58 /*
59 * If cmpxchg() fails we continue without updating pprev.
60 * Either we raced with task_work_add() which added the
61 * new entry before this work, we will find it again. Or
9da33de6 62 * we raced with task_work_run(), *pprev == NULL/exited.
ac3d0da8 63 */
e73f8959 64 raw_spin_lock_irqsave(&task->pi_lock, flags);
ac3d0da8 65 while ((work = ACCESS_ONCE(*pprev))) {
205e550a 66 smp_read_barrier_depends();
ac3d0da8
ON
67 if (work->func != func)
68 pprev = &work->next;
69 else if (cmpxchg(pprev, work, work->next) == work)
70 break;
e73f8959 71 }
e73f8959 72 raw_spin_unlock_irqrestore(&task->pi_lock, flags);
ac3d0da8
ON
73
74 return work;
e73f8959
ON
75}
76
892f6668
ON
77/**
78 * task_work_run - execute the works added by task_work_add()
79 *
80 * Flush the pending works. Should be used by the core kernel code.
81 * Called before the task returns to the user-mode or stops, or when
82 * it exits. In the latter case task_work_add() can no longer add the
83 * new work after task_work_run() returns.
84 */
e73f8959
ON
85void task_work_run(void)
86{
87 struct task_struct *task = current;
ac3d0da8 88 struct callback_head *work, *head, *next;
e73f8959 89
ac3d0da8 90 for (;;) {
9da33de6
ON
91 /*
92 * work->func() can do task_work_add(), do not set
93 * work_exited unless the list is empty.
94 */
95 do {
96 work = ACCESS_ONCE(task->task_works);
97 head = !work && (task->flags & PF_EXITING) ?
98 &work_exited : NULL;
99 } while (cmpxchg(&task->task_works, work, head) != work);
100
ac3d0da8
ON
101 if (!work)
102 break;
103 /*
104 * Synchronize with task_work_cancel(). It can't remove
105 * the first entry == work, cmpxchg(task_works) should
106 * fail, but it can play with *work and other entries.
107 */
108 raw_spin_unlock_wait(&task->pi_lock);
109 smp_mb();
e73f8959 110
ac3d0da8
ON
111 /* Reverse the list to run the works in fifo order */
112 head = NULL;
113 do {
114 next = work->next;
115 work->next = head;
116 head = work;
117 work = next;
118 } while (work);
e73f8959 119
ac3d0da8
ON
120 work = head;
121 do {
122 next = work->next;
123 work->func(work);
124 work = next;
f341861f 125 cond_resched();
ac3d0da8 126 } while (work);
e73f8959
ON
127 }
128}