]> git.proxmox.com Git - mirror_ubuntu-zesty-kernel.git/blame - kernel/task_work.c
merge task_work and rcu_head, get rid of separate allocation for keyring case
[mirror_ubuntu-zesty-kernel.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
5int
67d12145 6task_work_add(struct task_struct *task, struct callback_head *twork, bool notify)
e73f8959
ON
7{
8 unsigned long flags;
9 int err = -ESRCH;
10
11#ifndef TIF_NOTIFY_RESUME
12 if (notify)
13 return -ENOTSUPP;
14#endif
15 /*
16 * We must not insert the new work if the task has already passed
17 * exit_task_work(). We rely on do_exit()->raw_spin_unlock_wait()
18 * and check PF_EXITING under pi_lock.
19 */
20 raw_spin_lock_irqsave(&task->pi_lock, flags);
21 if (likely(!(task->flags & PF_EXITING))) {
67d12145
AV
22 struct callback_head *last = task->task_works;
23 struct callback_head *first = last ? last->next : twork;
158e1645
AV
24 twork->next = first;
25 if (last)
26 last->next = twork;
27 task->task_works = twork;
e73f8959
ON
28 err = 0;
29 }
30 raw_spin_unlock_irqrestore(&task->pi_lock, flags);
31
32 /* test_and_set_bit() implies mb(), see tracehook_notify_resume(). */
33 if (likely(!err) && notify)
34 set_notify_resume(task);
35 return err;
36}
37
67d12145 38struct callback_head *
e73f8959
ON
39task_work_cancel(struct task_struct *task, task_work_func_t func)
40{
41 unsigned long flags;
67d12145 42 struct callback_head *last, *res = NULL;
e73f8959
ON
43
44 raw_spin_lock_irqsave(&task->pi_lock, flags);
158e1645
AV
45 last = task->task_works;
46 if (last) {
67d12145 47 struct callback_head *q = last, *p = q->next;
158e1645
AV
48 while (1) {
49 if (p->func == func) {
50 q->next = p->next;
51 if (p == last)
52 task->task_works = q == p ? NULL : q;
53 res = p;
54 break;
55 }
56 if (p == last)
57 break;
58 q = p;
59 p = q->next;
e73f8959
ON
60 }
61 }
e73f8959 62 raw_spin_unlock_irqrestore(&task->pi_lock, flags);
158e1645 63 return res;
e73f8959
ON
64}
65
66void task_work_run(void)
67{
68 struct task_struct *task = current;
67d12145 69 struct callback_head *p, *q;
e73f8959
ON
70
71 raw_spin_lock_irq(&task->pi_lock);
158e1645
AV
72 p = task->task_works;
73 task->task_works = NULL;
e73f8959
ON
74 raw_spin_unlock_irq(&task->pi_lock);
75
158e1645 76 if (unlikely(!p))
e73f8959 77 return;
e73f8959 78
158e1645
AV
79 q = p->next; /* head */
80 p->next = NULL; /* cut it */
81 while (q) {
82 p = q->next;
83 q->func(q);
84 q = p;
e73f8959
ON
85 }
86}