diff options
-rw-r--r-- | include/linux/sched.h | 2 | ||||
-rw-r--r-- | include/linux/task_work.h | 14 | ||||
-rw-r--r-- | include/linux/types.h | 9 | ||||
-rw-r--r-- | kernel/irq/manage.c | 4 | ||||
-rw-r--r-- | kernel/task_work.c | 14 | ||||
-rw-r--r-- | security/keys/internal.h | 6 | ||||
-rw-r--r-- | security/keys/keyctl.c | 28 | ||||
-rw-r--r-- | security/keys/process_keys.c | 6 |
8 files changed, 31 insertions, 52 deletions
diff --git a/include/linux/sched.h b/include/linux/sched.h index b9216ebc2789..af3555cc760f 100644 --- a/include/linux/sched.h +++ b/include/linux/sched.h | |||
@@ -1405,7 +1405,7 @@ struct task_struct { | |||
1405 | int (*notifier)(void *priv); | 1405 | int (*notifier)(void *priv); |
1406 | void *notifier_data; | 1406 | void *notifier_data; |
1407 | sigset_t *notifier_mask; | 1407 | sigset_t *notifier_mask; |
1408 | void *task_works; | 1408 | struct callback_head *task_works; |
1409 | 1409 | ||
1410 | struct audit_context *audit_context; | 1410 | struct audit_context *audit_context; |
1411 | #ifdef CONFIG_AUDITSYSCALL | 1411 | #ifdef CONFIG_AUDITSYSCALL |
diff --git a/include/linux/task_work.h b/include/linux/task_work.h index 3b3e2c8d037b..fb46b03b1852 100644 --- a/include/linux/task_work.h +++ b/include/linux/task_work.h | |||
@@ -4,22 +4,16 @@ | |||
4 | #include <linux/list.h> | 4 | #include <linux/list.h> |
5 | #include <linux/sched.h> | 5 | #include <linux/sched.h> |
6 | 6 | ||
7 | struct task_work; | 7 | typedef void (*task_work_func_t)(struct callback_head *); |
8 | typedef void (*task_work_func_t)(struct task_work *); | ||
9 | |||
10 | struct task_work { | ||
11 | struct task_work *next; | ||
12 | task_work_func_t func; | ||
13 | }; | ||
14 | 8 | ||
15 | static inline void | 9 | static inline void |
16 | init_task_work(struct task_work *twork, task_work_func_t func) | 10 | init_task_work(struct callback_head *twork, task_work_func_t func) |
17 | { | 11 | { |
18 | twork->func = func; | 12 | twork->func = func; |
19 | } | 13 | } |
20 | 14 | ||
21 | int task_work_add(struct task_struct *task, struct task_work *twork, bool); | 15 | int task_work_add(struct task_struct *task, struct callback_head *twork, bool); |
22 | struct task_work *task_work_cancel(struct task_struct *, task_work_func_t); | 16 | struct callback_head *task_work_cancel(struct task_struct *, task_work_func_t); |
23 | void task_work_run(void); | 17 | void task_work_run(void); |
24 | 18 | ||
25 | static inline void exit_task_work(struct task_struct *task) | 19 | static inline void exit_task_work(struct task_struct *task) |
diff --git a/include/linux/types.h b/include/linux/types.h index 9c1bd539ea70..bf0dd7524b2a 100644 --- a/include/linux/types.h +++ b/include/linux/types.h | |||
@@ -246,14 +246,15 @@ struct ustat { | |||
246 | }; | 246 | }; |
247 | 247 | ||
248 | /** | 248 | /** |
249 | * struct rcu_head - callback structure for use with RCU | 249 | * struct callback_head - callback structure for use with RCU and task_work |
250 | * @next: next update requests in a list | 250 | * @next: next update requests in a list |
251 | * @func: actual update function to call after the grace period. | 251 | * @func: actual update function to call after the grace period. |
252 | */ | 252 | */ |
253 | struct rcu_head { | 253 | struct callback_head { |
254 | struct rcu_head *next; | 254 | struct callback_head *next; |
255 | void (*func)(struct rcu_head *head); | 255 | void (*func)(struct callback_head *head); |
256 | }; | 256 | }; |
257 | #define rcu_head callback_head | ||
257 | 258 | ||
258 | #endif /* __KERNEL__ */ | 259 | #endif /* __KERNEL__ */ |
259 | #endif /* __ASSEMBLY__ */ | 260 | #endif /* __ASSEMBLY__ */ |
diff --git a/kernel/irq/manage.c b/kernel/irq/manage.c index d1dd54734ce7..814c9ef6bba1 100644 --- a/kernel/irq/manage.c +++ b/kernel/irq/manage.c | |||
@@ -781,7 +781,7 @@ static void wake_threads_waitq(struct irq_desc *desc) | |||
781 | wake_up(&desc->wait_for_threads); | 781 | wake_up(&desc->wait_for_threads); |
782 | } | 782 | } |
783 | 783 | ||
784 | static void irq_thread_dtor(struct task_work *unused) | 784 | static void irq_thread_dtor(struct callback_head *unused) |
785 | { | 785 | { |
786 | struct task_struct *tsk = current; | 786 | struct task_struct *tsk = current; |
787 | struct irq_desc *desc; | 787 | struct irq_desc *desc; |
@@ -813,7 +813,7 @@ static void irq_thread_dtor(struct task_work *unused) | |||
813 | */ | 813 | */ |
814 | static int irq_thread(void *data) | 814 | static int irq_thread(void *data) |
815 | { | 815 | { |
816 | struct task_work on_exit_work; | 816 | struct callback_head on_exit_work; |
817 | static const struct sched_param param = { | 817 | static const struct sched_param param = { |
818 | .sched_priority = MAX_USER_RT_PRIO/2, | 818 | .sched_priority = MAX_USER_RT_PRIO/2, |
819 | }; | 819 | }; |
diff --git a/kernel/task_work.c b/kernel/task_work.c index 9b8948dbdc60..76266fb665dc 100644 --- a/kernel/task_work.c +++ b/kernel/task_work.c | |||
@@ -3,7 +3,7 @@ | |||
3 | #include <linux/tracehook.h> | 3 | #include <linux/tracehook.h> |
4 | 4 | ||
5 | int | 5 | int |
6 | task_work_add(struct task_struct *task, struct task_work *twork, bool notify) | 6 | task_work_add(struct task_struct *task, struct callback_head *twork, bool notify) |
7 | { | 7 | { |
8 | unsigned long flags; | 8 | unsigned long flags; |
9 | int err = -ESRCH; | 9 | int err = -ESRCH; |
@@ -19,8 +19,8 @@ task_work_add(struct task_struct *task, struct task_work *twork, bool notify) | |||
19 | */ | 19 | */ |
20 | raw_spin_lock_irqsave(&task->pi_lock, flags); | 20 | raw_spin_lock_irqsave(&task->pi_lock, flags); |
21 | if (likely(!(task->flags & PF_EXITING))) { | 21 | if (likely(!(task->flags & PF_EXITING))) { |
22 | struct task_work *last = task->task_works; | 22 | struct callback_head *last = task->task_works; |
23 | struct task_work *first = last ? last->next : twork; | 23 | struct callback_head *first = last ? last->next : twork; |
24 | twork->next = first; | 24 | twork->next = first; |
25 | if (last) | 25 | if (last) |
26 | last->next = twork; | 26 | last->next = twork; |
@@ -35,16 +35,16 @@ task_work_add(struct task_struct *task, struct task_work *twork, bool notify) | |||
35 | return err; | 35 | return err; |
36 | } | 36 | } |
37 | 37 | ||
38 | struct task_work * | 38 | struct callback_head * |
39 | task_work_cancel(struct task_struct *task, task_work_func_t func) | 39 | task_work_cancel(struct task_struct *task, task_work_func_t func) |
40 | { | 40 | { |
41 | unsigned long flags; | 41 | unsigned long flags; |
42 | struct task_work *last, *res = NULL; | 42 | struct callback_head *last, *res = NULL; |
43 | 43 | ||
44 | raw_spin_lock_irqsave(&task->pi_lock, flags); | 44 | raw_spin_lock_irqsave(&task->pi_lock, flags); |
45 | last = task->task_works; | 45 | last = task->task_works; |
46 | if (last) { | 46 | if (last) { |
47 | struct task_work *q = last, *p = q->next; | 47 | struct callback_head *q = last, *p = q->next; |
48 | while (1) { | 48 | while (1) { |
49 | if (p->func == func) { | 49 | if (p->func == func) { |
50 | q->next = p->next; | 50 | q->next = p->next; |
@@ -66,7 +66,7 @@ task_work_cancel(struct task_struct *task, task_work_func_t func) | |||
66 | void task_work_run(void) | 66 | void task_work_run(void) |
67 | { | 67 | { |
68 | struct task_struct *task = current; | 68 | struct task_struct *task = current; |
69 | struct task_work *p, *q; | 69 | struct callback_head *p, *q; |
70 | 70 | ||
71 | raw_spin_lock_irq(&task->pi_lock); | 71 | raw_spin_lock_irq(&task->pi_lock); |
72 | p = task->task_works; | 72 | p = task->task_works; |
diff --git a/security/keys/internal.h b/security/keys/internal.h index b510a316874a..c246ba5d43ab 100644 --- a/security/keys/internal.h +++ b/security/keys/internal.h | |||
@@ -148,12 +148,8 @@ extern key_ref_t lookup_user_key(key_serial_t id, unsigned long flags, | |||
148 | #define KEY_LOOKUP_PARTIAL 0x02 | 148 | #define KEY_LOOKUP_PARTIAL 0x02 |
149 | #define KEY_LOOKUP_FOR_UNLINK 0x04 | 149 | #define KEY_LOOKUP_FOR_UNLINK 0x04 |
150 | 150 | ||
151 | struct kludge { /* this will die off very soon */ | ||
152 | struct task_work twork; | ||
153 | struct cred *cred; | ||
154 | }; | ||
155 | extern long join_session_keyring(const char *name); | 151 | extern long join_session_keyring(const char *name); |
156 | extern void key_change_session_keyring(struct task_work *twork); | 152 | extern void key_change_session_keyring(struct callback_head *twork); |
157 | 153 | ||
158 | extern struct work_struct key_gc_work; | 154 | extern struct work_struct key_gc_work; |
159 | extern unsigned key_gc_delay; | 155 | extern unsigned key_gc_delay; |
diff --git a/security/keys/keyctl.c b/security/keys/keyctl.c index 26723caaad05..0291b3f9397c 100644 --- a/security/keys/keyctl.c +++ b/security/keys/keyctl.c | |||
@@ -1456,8 +1456,7 @@ long keyctl_session_to_parent(void) | |||
1456 | { | 1456 | { |
1457 | struct task_struct *me, *parent; | 1457 | struct task_struct *me, *parent; |
1458 | const struct cred *mycred, *pcred; | 1458 | const struct cred *mycred, *pcred; |
1459 | struct kludge *newwork; | 1459 | struct callback_head *newwork, *oldwork; |
1460 | struct task_work *oldwork; | ||
1461 | key_ref_t keyring_r; | 1460 | key_ref_t keyring_r; |
1462 | struct cred *cred; | 1461 | struct cred *cred; |
1463 | int ret; | 1462 | int ret; |
@@ -1467,20 +1466,17 @@ long keyctl_session_to_parent(void) | |||
1467 | return PTR_ERR(keyring_r); | 1466 | return PTR_ERR(keyring_r); |
1468 | 1467 | ||
1469 | ret = -ENOMEM; | 1468 | ret = -ENOMEM; |
1470 | newwork = kmalloc(sizeof(struct kludge), GFP_KERNEL); | ||
1471 | if (!newwork) | ||
1472 | goto error_keyring; | ||
1473 | 1469 | ||
1474 | /* our parent is going to need a new cred struct, a new tgcred struct | 1470 | /* our parent is going to need a new cred struct, a new tgcred struct |
1475 | * and new security data, so we allocate them here to prevent ENOMEM in | 1471 | * and new security data, so we allocate them here to prevent ENOMEM in |
1476 | * our parent */ | 1472 | * our parent */ |
1477 | cred = cred_alloc_blank(); | 1473 | cred = cred_alloc_blank(); |
1478 | if (!cred) | 1474 | if (!cred) |
1479 | goto error_newwork; | 1475 | goto error_keyring; |
1476 | newwork = &cred->rcu; | ||
1480 | 1477 | ||
1481 | cred->tgcred->session_keyring = key_ref_to_ptr(keyring_r); | 1478 | cred->tgcred->session_keyring = key_ref_to_ptr(keyring_r); |
1482 | init_task_work(&newwork->twork, key_change_session_keyring); | 1479 | init_task_work(newwork, key_change_session_keyring); |
1483 | newwork->cred = cred; | ||
1484 | 1480 | ||
1485 | me = current; | 1481 | me = current; |
1486 | rcu_read_lock(); | 1482 | rcu_read_lock(); |
@@ -1529,24 +1525,18 @@ long keyctl_session_to_parent(void) | |||
1529 | 1525 | ||
1530 | /* the replacement session keyring is applied just prior to userspace | 1526 | /* the replacement session keyring is applied just prior to userspace |
1531 | * restarting */ | 1527 | * restarting */ |
1532 | ret = task_work_add(parent, &newwork->twork, true); | 1528 | ret = task_work_add(parent, newwork, true); |
1533 | if (!ret) | 1529 | if (!ret) |
1534 | newwork = NULL; | 1530 | newwork = NULL; |
1535 | unlock: | 1531 | unlock: |
1536 | write_unlock_irq(&tasklist_lock); | 1532 | write_unlock_irq(&tasklist_lock); |
1537 | rcu_read_unlock(); | 1533 | rcu_read_unlock(); |
1538 | if (oldwork) { | 1534 | if (oldwork) |
1539 | put_cred(container_of(oldwork, struct kludge, twork)->cred); | 1535 | put_cred(container_of(oldwork, struct cred, rcu)); |
1540 | kfree(oldwork); | 1536 | if (newwork) |
1541 | } | 1537 | put_cred(cred); |
1542 | if (newwork) { | ||
1543 | put_cred(newwork->cred); | ||
1544 | kfree(newwork); | ||
1545 | } | ||
1546 | return ret; | 1538 | return ret; |
1547 | 1539 | ||
1548 | error_newwork: | ||
1549 | kfree(newwork); | ||
1550 | error_keyring: | 1540 | error_keyring: |
1551 | key_ref_put(keyring_r); | 1541 | key_ref_put(keyring_r); |
1552 | return ret; | 1542 | return ret; |
diff --git a/security/keys/process_keys.c b/security/keys/process_keys.c index c9b07c97d7f2..54339cfd6734 100644 --- a/security/keys/process_keys.c +++ b/security/keys/process_keys.c | |||
@@ -834,13 +834,11 @@ error: | |||
834 | * Replace a process's session keyring on behalf of one of its children when | 834 | * Replace a process's session keyring on behalf of one of its children when |
835 | * the target process is about to resume userspace execution. | 835 | * the target process is about to resume userspace execution. |
836 | */ | 836 | */ |
837 | void key_change_session_keyring(struct task_work *twork) | 837 | void key_change_session_keyring(struct callback_head *twork) |
838 | { | 838 | { |
839 | const struct cred *old = current_cred(); | 839 | const struct cred *old = current_cred(); |
840 | struct kludge *p = container_of(twork, struct kludge, twork); | 840 | struct cred *new = container_of(twork, struct cred, rcu); |
841 | struct cred *new = p->cred; | ||
842 | 841 | ||
843 | kfree(p); | ||
844 | if (unlikely(current->flags & PF_EXITING)) { | 842 | if (unlikely(current->flags & PF_EXITING)) { |
845 | put_cred(new); | 843 | put_cred(new); |
846 | return; | 844 | return; |