merge task_work and rcu_head, get rid of separate allocation for keyring case
task_work and rcu_head are identical now; merge them (calling the result struct callback_head, rcu_head #define'd to it), kill separate allocation in security/keys since we can just use cred->rcu now. Signed-off-by: Al Viro <viro@zeniv.linux.org.uk>
This commit is contained in:
		
							parent
							
								
									158e1645e0
								
							
						
					
					
						commit
						67d1214551
					
				| @ -1405,7 +1405,7 @@ struct task_struct { | ||||
| 	int (*notifier)(void *priv); | ||||
| 	void *notifier_data; | ||||
| 	sigset_t *notifier_mask; | ||||
| 	void *task_works; | ||||
| 	struct callback_head *task_works; | ||||
| 
 | ||||
| 	struct audit_context *audit_context; | ||||
| #ifdef CONFIG_AUDITSYSCALL | ||||
|  | ||||
| @ -4,22 +4,16 @@ | ||||
| #include <linux/list.h> | ||||
| #include <linux/sched.h> | ||||
| 
 | ||||
| struct task_work; | ||||
| typedef void (*task_work_func_t)(struct task_work *); | ||||
| 
 | ||||
| struct task_work { | ||||
| 	struct task_work *next; | ||||
| 	task_work_func_t func; | ||||
| }; | ||||
| typedef void (*task_work_func_t)(struct callback_head *); | ||||
| 
 | ||||
| static inline void | ||||
| init_task_work(struct task_work *twork, task_work_func_t func) | ||||
| init_task_work(struct callback_head *twork, task_work_func_t func) | ||||
| { | ||||
| 	twork->func = func; | ||||
| } | ||||
| 
 | ||||
| int task_work_add(struct task_struct *task, struct task_work *twork, bool); | ||||
| struct task_work *task_work_cancel(struct task_struct *, task_work_func_t); | ||||
| int task_work_add(struct task_struct *task, struct callback_head *twork, bool); | ||||
| struct callback_head *task_work_cancel(struct task_struct *, task_work_func_t); | ||||
| void task_work_run(void); | ||||
| 
 | ||||
| static inline void exit_task_work(struct task_struct *task) | ||||
|  | ||||
| @ -246,14 +246,15 @@ struct ustat { | ||||
| }; | ||||
| 
 | ||||
| /**
 | ||||
|  * struct rcu_head - callback structure for use with RCU | ||||
|  * struct callback_head - callback structure for use with RCU and task_work | ||||
|  * @next: next update requests in a list | ||||
|  * @func: actual update function to call after the grace period. | ||||
|  */ | ||||
| struct rcu_head { | ||||
| 	struct rcu_head *next; | ||||
| 	void (*func)(struct rcu_head *head); | ||||
| struct callback_head { | ||||
| 	struct callback_head *next; | ||||
| 	void (*func)(struct callback_head *head); | ||||
| }; | ||||
| #define rcu_head callback_head | ||||
| 
 | ||||
| #endif	/* __KERNEL__ */ | ||||
| #endif /*  __ASSEMBLY__ */ | ||||
|  | ||||
| @ -781,7 +781,7 @@ static void wake_threads_waitq(struct irq_desc *desc) | ||||
| 		wake_up(&desc->wait_for_threads); | ||||
| } | ||||
| 
 | ||||
| static void irq_thread_dtor(struct task_work *unused) | ||||
| static void irq_thread_dtor(struct callback_head *unused) | ||||
| { | ||||
| 	struct task_struct *tsk = current; | ||||
| 	struct irq_desc *desc; | ||||
| @ -813,7 +813,7 @@ static void irq_thread_dtor(struct task_work *unused) | ||||
|  */ | ||||
| static int irq_thread(void *data) | ||||
| { | ||||
| 	struct task_work on_exit_work; | ||||
| 	struct callback_head on_exit_work; | ||||
| 	static const struct sched_param param = { | ||||
| 		.sched_priority = MAX_USER_RT_PRIO/2, | ||||
| 	}; | ||||
|  | ||||
| @ -3,7 +3,7 @@ | ||||
| #include <linux/tracehook.h> | ||||
| 
 | ||||
| int | ||||
| task_work_add(struct task_struct *task, struct task_work *twork, bool notify) | ||||
| task_work_add(struct task_struct *task, struct callback_head *twork, bool notify) | ||||
| { | ||||
| 	unsigned long flags; | ||||
| 	int err = -ESRCH; | ||||
| @ -19,8 +19,8 @@ task_work_add(struct task_struct *task, struct task_work *twork, bool notify) | ||||
| 	 */ | ||||
| 	raw_spin_lock_irqsave(&task->pi_lock, flags); | ||||
| 	if (likely(!(task->flags & PF_EXITING))) { | ||||
| 		struct task_work *last = task->task_works; | ||||
| 		struct task_work *first = last ? last->next : twork; | ||||
| 		struct callback_head *last = task->task_works; | ||||
| 		struct callback_head *first = last ? last->next : twork; | ||||
| 		twork->next = first; | ||||
| 		if (last) | ||||
| 			last->next = twork; | ||||
| @ -35,16 +35,16 @@ task_work_add(struct task_struct *task, struct task_work *twork, bool notify) | ||||
| 	return err; | ||||
| } | ||||
| 
 | ||||
| struct task_work * | ||||
| struct callback_head * | ||||
| task_work_cancel(struct task_struct *task, task_work_func_t func) | ||||
| { | ||||
| 	unsigned long flags; | ||||
| 	struct task_work *last, *res = NULL; | ||||
| 	struct callback_head *last, *res = NULL; | ||||
| 
 | ||||
| 	raw_spin_lock_irqsave(&task->pi_lock, flags); | ||||
| 	last = task->task_works; | ||||
| 	if (last) { | ||||
| 		struct task_work *q = last, *p = q->next; | ||||
| 		struct callback_head *q = last, *p = q->next; | ||||
| 		while (1) { | ||||
| 			if (p->func == func) { | ||||
| 				q->next = p->next; | ||||
| @ -66,7 +66,7 @@ task_work_cancel(struct task_struct *task, task_work_func_t func) | ||||
| void task_work_run(void) | ||||
| { | ||||
| 	struct task_struct *task = current; | ||||
| 	struct task_work *p, *q; | ||||
| 	struct callback_head *p, *q; | ||||
| 
 | ||||
| 	raw_spin_lock_irq(&task->pi_lock); | ||||
| 	p = task->task_works; | ||||
|  | ||||
| @ -148,12 +148,8 @@ extern key_ref_t lookup_user_key(key_serial_t id, unsigned long flags, | ||||
| #define KEY_LOOKUP_PARTIAL	0x02 | ||||
| #define KEY_LOOKUP_FOR_UNLINK	0x04 | ||||
| 
 | ||||
| struct kludge {	/* this will die off very soon */ | ||||
| 	struct task_work twork; | ||||
| 	struct cred *cred; | ||||
| }; | ||||
| extern long join_session_keyring(const char *name); | ||||
| extern void key_change_session_keyring(struct task_work *twork); | ||||
| extern void key_change_session_keyring(struct callback_head *twork); | ||||
| 
 | ||||
| extern struct work_struct key_gc_work; | ||||
| extern unsigned key_gc_delay; | ||||
|  | ||||
| @ -1456,8 +1456,7 @@ long keyctl_session_to_parent(void) | ||||
| { | ||||
| 	struct task_struct *me, *parent; | ||||
| 	const struct cred *mycred, *pcred; | ||||
| 	struct kludge *newwork; | ||||
| 	struct task_work *oldwork; | ||||
| 	struct callback_head *newwork, *oldwork; | ||||
| 	key_ref_t keyring_r; | ||||
| 	struct cred *cred; | ||||
| 	int ret; | ||||
| @ -1467,20 +1466,17 @@ long keyctl_session_to_parent(void) | ||||
| 		return PTR_ERR(keyring_r); | ||||
| 
 | ||||
| 	ret = -ENOMEM; | ||||
| 	newwork = kmalloc(sizeof(struct kludge), GFP_KERNEL); | ||||
| 	if (!newwork) | ||||
| 		goto error_keyring; | ||||
| 
 | ||||
| 	/* our parent is going to need a new cred struct, a new tgcred struct
 | ||||
| 	 * and new security data, so we allocate them here to prevent ENOMEM in | ||||
| 	 * our parent */ | ||||
| 	cred = cred_alloc_blank(); | ||||
| 	if (!cred) | ||||
| 		goto error_newwork; | ||||
| 		goto error_keyring; | ||||
| 	newwork = &cred->rcu; | ||||
| 
 | ||||
| 	cred->tgcred->session_keyring = key_ref_to_ptr(keyring_r); | ||||
| 	init_task_work(&newwork->twork, key_change_session_keyring); | ||||
| 	newwork->cred = cred; | ||||
| 	init_task_work(newwork, key_change_session_keyring); | ||||
| 
 | ||||
| 	me = current; | ||||
| 	rcu_read_lock(); | ||||
| @ -1529,24 +1525,18 @@ long keyctl_session_to_parent(void) | ||||
| 
 | ||||
| 	/* the replacement session keyring is applied just prior to userspace
 | ||||
| 	 * restarting */ | ||||
| 	ret = task_work_add(parent, &newwork->twork, true); | ||||
| 	ret = task_work_add(parent, newwork, true); | ||||
| 	if (!ret) | ||||
| 		newwork = NULL; | ||||
| unlock: | ||||
| 	write_unlock_irq(&tasklist_lock); | ||||
| 	rcu_read_unlock(); | ||||
| 	if (oldwork) { | ||||
| 		put_cred(container_of(oldwork, struct kludge, twork)->cred); | ||||
| 		kfree(oldwork); | ||||
| 	} | ||||
| 	if (newwork) { | ||||
| 		put_cred(newwork->cred); | ||||
| 		kfree(newwork); | ||||
| 	} | ||||
| 	if (oldwork) | ||||
| 		put_cred(container_of(oldwork, struct cred, rcu)); | ||||
| 	if (newwork) | ||||
| 		put_cred(cred); | ||||
| 	return ret; | ||||
| 
 | ||||
| error_newwork: | ||||
| 	kfree(newwork); | ||||
| error_keyring: | ||||
| 	key_ref_put(keyring_r); | ||||
| 	return ret; | ||||
|  | ||||
| @ -834,13 +834,11 @@ error: | ||||
|  * Replace a process's session keyring on behalf of one of its children when | ||||
|  * the target  process is about to resume userspace execution. | ||||
|  */ | ||||
| void key_change_session_keyring(struct task_work *twork) | ||||
| void key_change_session_keyring(struct callback_head *twork) | ||||
| { | ||||
| 	const struct cred *old = current_cred(); | ||||
| 	struct kludge *p = container_of(twork, struct kludge, twork); | ||||
| 	struct cred *new = p->cred; | ||||
| 	struct cred *new = container_of(twork, struct cred, rcu); | ||||
| 
 | ||||
| 	kfree(p); | ||||
| 	if (unlikely(current->flags & PF_EXITING)) { | ||||
| 		put_cred(new); | ||||
| 		return; | ||||
|  | ||||
		Loading…
	
		Reference in New Issue
	
	Block a user