aboutsummaryrefslogtreecommitdiffstats
path: root/kernel
diff options
context:
space:
mode:
authorEric W. Biederman <ebiederm@xmission.com>2007-05-09 05:34:32 -0400
committerLinus Torvalds <torvalds@woody.linux-foundation.org>2007-05-09 15:30:53 -0400
commit73c279927f89561ecb45b2dfdf9314bafcfd9f67 (patch)
tree2186e28c92c6f8229ea20eb9856714186bf77a4c /kernel
parentc93465181fed0f8f5942a41108943dadea0aa345 (diff)
kthread: don't depend on work queues
Currently there is a circular reference between work queue initialization and kthread initialization. This prevents the kthread infrastructure from initializing until after work queues have been initialized. We want the properties of tasks created with kthread_create to be as close as possible to the init_task and to not be contaminated by user processes. The later we start our kthreadd that creates these tasks the harder it is to avoid contamination from user processes and the more of a mess we have to clean up because the defaults have changed on us. So this patch modifies the kthread support to not use work queues but to instead use a simple list of structures, and to have kthreadd start from init_task immediately after our kernel thread that execs /sbin/init. By being a true child of init_task we only have to change those process settings that we want to have different from init_task, such as our process name, the cpus that are allowed, blocking all signals and setting SIGCHLD to SIG_IGN so that all of our children are reaped automatically. By being a true child of init_task we also naturally get our ppid set to 0 and do not wind up as a child of PID == 1. Ensuring that tasks generated by kthread_create will not slow down the functioning of the wait family of functions. [akpm@linux-foundation.org: use interruptible sleeps] Signed-off-by: Eric W. Biederman <ebiederm@xmission.com> Cc: Oleg Nesterov <oleg@tv-sign.ru> Signed-off-by: Andrew Morton <akpm@linux-foundation.org> Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
Diffstat (limited to 'kernel')
-rw-r--r--kernel/kthread.c124
1 files changed, 68 insertions, 56 deletions
diff --git a/kernel/kthread.c b/kernel/kthread.c
index 87c50ccd1d4e..0eb0070a3c57 100644
--- a/kernel/kthread.c
+++ b/kernel/kthread.c
@@ -1,7 +1,7 @@
1/* Kernel thread helper functions. 1/* Kernel thread helper functions.
2 * Copyright (C) 2004 IBM Corporation, Rusty Russell. 2 * Copyright (C) 2004 IBM Corporation, Rusty Russell.
3 * 3 *
4 * Creation is done via keventd, so that we get a clean environment 4 * Creation is done via kthreadd, so that we get a clean environment
5 * even if we're invoked from userspace (think modprobe, hotplug cpu, 5 * even if we're invoked from userspace (think modprobe, hotplug cpu,
6 * etc.). 6 * etc.).
7 */ 7 */
@@ -15,24 +15,22 @@
15#include <linux/mutex.h> 15#include <linux/mutex.h>
16#include <asm/semaphore.h> 16#include <asm/semaphore.h>
17 17
18/* 18static DEFINE_SPINLOCK(kthread_create_lock);
19 * We dont want to execute off keventd since it might 19static LIST_HEAD(kthread_create_list);
20 * hold a semaphore our callers hold too: 20struct task_struct *kthreadd_task;
21 */
22static struct workqueue_struct *helper_wq;
23 21
24struct kthread_create_info 22struct kthread_create_info
25{ 23{
26 /* Information passed to kthread() from keventd. */ 24 /* Information passed to kthread() from kthreadd. */
27 int (*threadfn)(void *data); 25 int (*threadfn)(void *data);
28 void *data; 26 void *data;
29 struct completion started; 27 struct completion started;
30 28
31 /* Result passed back to kthread_create() from keventd. */ 29 /* Result passed back to kthread_create() from kthreadd. */
32 struct task_struct *result; 30 struct task_struct *result;
33 struct completion done; 31 struct completion done;
34 32
35 struct work_struct work; 33 struct list_head list;
36}; 34};
37 35
38struct kthread_stop_info 36struct kthread_stop_info
@@ -60,42 +58,17 @@ int kthread_should_stop(void)
60} 58}
61EXPORT_SYMBOL(kthread_should_stop); 59EXPORT_SYMBOL(kthread_should_stop);
62 60
63static void kthread_exit_files(void)
64{
65 struct fs_struct *fs;
66 struct task_struct *tsk = current;
67
68 exit_fs(tsk); /* current->fs->count--; */
69 fs = init_task.fs;
70 tsk->fs = fs;
71 atomic_inc(&fs->count);
72 exit_files(tsk);
73 current->files = init_task.files;
74 atomic_inc(&tsk->files->count);
75}
76
77static int kthread(void *_create) 61static int kthread(void *_create)
78{ 62{
79 struct kthread_create_info *create = _create; 63 struct kthread_create_info *create = _create;
80 int (*threadfn)(void *data); 64 int (*threadfn)(void *data);
81 void *data; 65 void *data;
82 sigset_t blocked;
83 int ret = -EINTR; 66 int ret = -EINTR;
84 67
85 kthread_exit_files(); 68 /* Copy data: it's on kthread's stack */
86
87 /* Copy data: it's on keventd's stack */
88 threadfn = create->threadfn; 69 threadfn = create->threadfn;
89 data = create->data; 70 data = create->data;
90 71
91 /* Block and flush all signals (in case we're not from keventd). */
92 sigfillset(&blocked);
93 sigprocmask(SIG_BLOCK, &blocked, NULL);
94 flush_signals(current);
95
96 /* By default we can run anywhere, unlike keventd. */
97 set_cpus_allowed(current, CPU_MASK_ALL);
98
99 /* OK, tell user we're spawned, wait for stop or wakeup */ 72 /* OK, tell user we're spawned, wait for stop or wakeup */
100 __set_current_state(TASK_INTERRUPTIBLE); 73 __set_current_state(TASK_INTERRUPTIBLE);
101 complete(&create->started); 74 complete(&create->started);
@@ -112,11 +85,8 @@ static int kthread(void *_create)
112 return 0; 85 return 0;
113} 86}
114 87
115/* We are keventd: create a thread. */ 88static void create_kthread(struct kthread_create_info *create)
116static void keventd_create_kthread(struct work_struct *work)
117{ 89{
118 struct kthread_create_info *create =
119 container_of(work, struct kthread_create_info, work);
120 int pid; 90 int pid;
121 91
122 /* We want our own signal handler (we take no signals by default). */ 92 /* We want our own signal handler (we take no signals by default). */
@@ -162,17 +132,14 @@ struct task_struct *kthread_create(int (*threadfn)(void *data),
162 create.data = data; 132 create.data = data;
163 init_completion(&create.started); 133 init_completion(&create.started);
164 init_completion(&create.done); 134 init_completion(&create.done);
165 INIT_WORK(&create.work, keventd_create_kthread); 135
166 136 spin_lock(&kthread_create_lock);
167 /* 137 list_add_tail(&create.list, &kthread_create_list);
168 * The workqueue needs to start up first: 138 wake_up_process(kthreadd_task);
169 */ 139 spin_unlock(&kthread_create_lock);
170 if (!helper_wq) 140
171 create.work.func(&create.work); 141 wait_for_completion(&create.done);
172 else { 142
173 queue_work(helper_wq, &create.work);
174 wait_for_completion(&create.done);
175 }
176 if (!IS_ERR(create.result)) { 143 if (!IS_ERR(create.result)) {
177 va_list args; 144 va_list args;
178 va_start(args, namefmt); 145 va_start(args, namefmt);
@@ -180,7 +147,6 @@ struct task_struct *kthread_create(int (*threadfn)(void *data),
180 namefmt, args); 147 namefmt, args);
181 va_end(args); 148 va_end(args);
182 } 149 }
183
184 return create.result; 150 return create.result;
185} 151}
186EXPORT_SYMBOL(kthread_create); 152EXPORT_SYMBOL(kthread_create);
@@ -245,12 +211,58 @@ int kthread_stop(struct task_struct *k)
245} 211}
246EXPORT_SYMBOL(kthread_stop); 212EXPORT_SYMBOL(kthread_stop);
247 213
248static __init int helper_init(void) 214
215static __init void kthreadd_setup(void)
249{ 216{
250 helper_wq = create_singlethread_workqueue("kthread"); 217 struct task_struct *tsk = current;
251 BUG_ON(!helper_wq); 218 struct k_sigaction sa;
219 sigset_t blocked;
252 220
253 return 0; 221 set_task_comm(tsk, "kthreadd");
222
223 /* Block and flush all signals */
224 sigfillset(&blocked);
225 sigprocmask(SIG_BLOCK, &blocked, NULL);
226 flush_signals(tsk);
227
228 /* SIG_IGN makes children autoreap: see do_notify_parent(). */
229 sa.sa.sa_handler = SIG_IGN;
230 sa.sa.sa_flags = 0;
231 siginitset(&sa.sa.sa_mask, sigmask(SIGCHLD));
232 do_sigaction(SIGCHLD, &sa, (struct k_sigaction *)0);
233
234 set_user_nice(current, -5);
235 set_cpus_allowed(current, CPU_MASK_ALL);
254} 236}
255 237
256core_initcall(helper_init); 238int kthreadd(void *unused)
239{
240 /* Setup a clean context for our children to inherit. */
241 kthreadd_setup();
242
243 current->flags |= PF_NOFREEZE;
244
245 for (;;) {
246 set_current_state(TASK_INTERRUPTIBLE);
247 if (list_empty(&kthread_create_list))
248 schedule();
249 __set_current_state(TASK_RUNNING);
250
251 spin_lock(&kthread_create_lock);
252 while (!list_empty(&kthread_create_list)) {
253 struct kthread_create_info *create;
254
255 create = list_entry(kthread_create_list.next,
256 struct kthread_create_info, list);
257 list_del_init(&create->list);
258 spin_unlock(&kthread_create_lock);
259
260 create_kthread(create);
261
262 spin_lock(&kthread_create_lock);
263 }
264 spin_unlock(&kthread_create_lock);
265 }
266
267 return 0;
268}