diff options
Diffstat (limited to 'kernel/kthread.c')
-rw-r--r-- | kernel/kthread.c | 124 |
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 | /* | 18 | static DEFINE_SPINLOCK(kthread_create_lock); |
19 | * We dont want to execute off keventd since it might | 19 | static LIST_HEAD(kthread_create_list); |
20 | * hold a semaphore our callers hold too: | 20 | struct task_struct *kthreadd_task; |
21 | */ | ||
22 | static struct workqueue_struct *helper_wq; | ||
23 | 21 | ||
24 | struct kthread_create_info | 22 | struct 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 | ||
38 | struct kthread_stop_info | 36 | struct kthread_stop_info |
@@ -60,42 +58,17 @@ int kthread_should_stop(void) | |||
60 | } | 58 | } |
61 | EXPORT_SYMBOL(kthread_should_stop); | 59 | EXPORT_SYMBOL(kthread_should_stop); |
62 | 60 | ||
63 | static 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 | |||
77 | static int kthread(void *_create) | 61 | static 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. */ | 88 | static void create_kthread(struct kthread_create_info *create) |
116 | static 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 | } |
186 | EXPORT_SYMBOL(kthread_create); | 152 | EXPORT_SYMBOL(kthread_create); |
@@ -245,12 +211,58 @@ int kthread_stop(struct task_struct *k) | |||
245 | } | 211 | } |
246 | EXPORT_SYMBOL(kthread_stop); | 212 | EXPORT_SYMBOL(kthread_stop); |
247 | 213 | ||
248 | static __init int helper_init(void) | 214 | |
215 | static __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 | ||
256 | core_initcall(helper_init); | 238 | int 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 | } | ||