diff options
Diffstat (limited to 'kernel')
-rw-r--r-- | kernel/auditfilter.c | 12 | ||||
-rw-r--r-- | kernel/cpu.c | 16 | ||||
-rw-r--r-- | kernel/cpuset.c | 5 | ||||
-rw-r--r-- | kernel/kmod.c | 216 | ||||
-rw-r--r-- | kernel/sys.c | 58 | ||||
-rw-r--r-- | kernel/sysctl.c | 10 |
6 files changed, 240 insertions, 77 deletions
diff --git a/kernel/auditfilter.c b/kernel/auditfilter.c index ce61f42354..1bf093dcff 100644 --- a/kernel/auditfilter.c +++ b/kernel/auditfilter.c | |||
@@ -1210,8 +1210,8 @@ static inline int audit_add_rule(struct audit_entry *entry, | |||
1210 | struct audit_entry *e; | 1210 | struct audit_entry *e; |
1211 | struct audit_field *inode_f = entry->rule.inode_f; | 1211 | struct audit_field *inode_f = entry->rule.inode_f; |
1212 | struct audit_watch *watch = entry->rule.watch; | 1212 | struct audit_watch *watch = entry->rule.watch; |
1213 | struct nameidata *ndp, *ndw; | 1213 | struct nameidata *ndp = NULL, *ndw = NULL; |
1214 | int h, err, putnd_needed = 0; | 1214 | int h, err; |
1215 | #ifdef CONFIG_AUDITSYSCALL | 1215 | #ifdef CONFIG_AUDITSYSCALL |
1216 | int dont_count = 0; | 1216 | int dont_count = 0; |
1217 | 1217 | ||
@@ -1239,7 +1239,6 @@ static inline int audit_add_rule(struct audit_entry *entry, | |||
1239 | err = audit_get_nd(watch->path, &ndp, &ndw); | 1239 | err = audit_get_nd(watch->path, &ndp, &ndw); |
1240 | if (err) | 1240 | if (err) |
1241 | goto error; | 1241 | goto error; |
1242 | putnd_needed = 1; | ||
1243 | } | 1242 | } |
1244 | 1243 | ||
1245 | mutex_lock(&audit_filter_mutex); | 1244 | mutex_lock(&audit_filter_mutex); |
@@ -1269,14 +1268,11 @@ static inline int audit_add_rule(struct audit_entry *entry, | |||
1269 | #endif | 1268 | #endif |
1270 | mutex_unlock(&audit_filter_mutex); | 1269 | mutex_unlock(&audit_filter_mutex); |
1271 | 1270 | ||
1272 | if (putnd_needed) | 1271 | audit_put_nd(ndp, ndw); /* NULL args OK */ |
1273 | audit_put_nd(ndp, ndw); | ||
1274 | |||
1275 | return 0; | 1272 | return 0; |
1276 | 1273 | ||
1277 | error: | 1274 | error: |
1278 | if (putnd_needed) | 1275 | audit_put_nd(ndp, ndw); /* NULL args OK */ |
1279 | audit_put_nd(ndp, ndw); | ||
1280 | if (watch) | 1276 | if (watch) |
1281 | audit_put_watch(watch); /* tmp watch, matches initial get */ | 1277 | audit_put_watch(watch); /* tmp watch, matches initial get */ |
1282 | return err; | 1278 | return err; |
diff --git a/kernel/cpu.c b/kernel/cpu.c index 208cf3497c..181ae70860 100644 --- a/kernel/cpu.c +++ b/kernel/cpu.c | |||
@@ -103,11 +103,19 @@ static inline void check_for_tasks(int cpu) | |||
103 | write_unlock_irq(&tasklist_lock); | 103 | write_unlock_irq(&tasklist_lock); |
104 | } | 104 | } |
105 | 105 | ||
106 | struct take_cpu_down_param { | ||
107 | unsigned long mod; | ||
108 | void *hcpu; | ||
109 | }; | ||
110 | |||
106 | /* Take this CPU down. */ | 111 | /* Take this CPU down. */ |
107 | static int take_cpu_down(void *unused) | 112 | static int take_cpu_down(void *_param) |
108 | { | 113 | { |
114 | struct take_cpu_down_param *param = _param; | ||
109 | int err; | 115 | int err; |
110 | 116 | ||
117 | raw_notifier_call_chain(&cpu_chain, CPU_DYING | param->mod, | ||
118 | param->hcpu); | ||
111 | /* Ensure this CPU doesn't handle any more interrupts. */ | 119 | /* Ensure this CPU doesn't handle any more interrupts. */ |
112 | err = __cpu_disable(); | 120 | err = __cpu_disable(); |
113 | if (err < 0) | 121 | if (err < 0) |
@@ -127,6 +135,10 @@ static int _cpu_down(unsigned int cpu, int tasks_frozen) | |||
127 | cpumask_t old_allowed, tmp; | 135 | cpumask_t old_allowed, tmp; |
128 | void *hcpu = (void *)(long)cpu; | 136 | void *hcpu = (void *)(long)cpu; |
129 | unsigned long mod = tasks_frozen ? CPU_TASKS_FROZEN : 0; | 137 | unsigned long mod = tasks_frozen ? CPU_TASKS_FROZEN : 0; |
138 | struct take_cpu_down_param tcd_param = { | ||
139 | .mod = mod, | ||
140 | .hcpu = hcpu, | ||
141 | }; | ||
130 | 142 | ||
131 | if (num_online_cpus() == 1) | 143 | if (num_online_cpus() == 1) |
132 | return -EBUSY; | 144 | return -EBUSY; |
@@ -153,7 +165,7 @@ static int _cpu_down(unsigned int cpu, int tasks_frozen) | |||
153 | set_cpus_allowed(current, tmp); | 165 | set_cpus_allowed(current, tmp); |
154 | 166 | ||
155 | mutex_lock(&cpu_bitmask_lock); | 167 | mutex_lock(&cpu_bitmask_lock); |
156 | p = __stop_machine_run(take_cpu_down, NULL, cpu); | 168 | p = __stop_machine_run(take_cpu_down, &tcd_param, cpu); |
157 | mutex_unlock(&cpu_bitmask_lock); | 169 | mutex_unlock(&cpu_bitmask_lock); |
158 | 170 | ||
159 | if (IS_ERR(p) || cpu_online(cpu)) { | 171 | if (IS_ERR(p) || cpu_online(cpu)) { |
diff --git a/kernel/cpuset.c b/kernel/cpuset.c index 824b1c01f4..57e6448b17 100644 --- a/kernel/cpuset.c +++ b/kernel/cpuset.c | |||
@@ -516,7 +516,7 @@ static void cpuset_release_agent(const char *pathbuf) | |||
516 | envp[i++] = "PATH=/sbin:/bin:/usr/sbin:/usr/bin"; | 516 | envp[i++] = "PATH=/sbin:/bin:/usr/sbin:/usr/bin"; |
517 | envp[i] = NULL; | 517 | envp[i] = NULL; |
518 | 518 | ||
519 | call_usermodehelper(argv[0], argv, envp, 0); | 519 | call_usermodehelper(argv[0], argv, envp, UMH_WAIT_EXEC); |
520 | kfree(pathbuf); | 520 | kfree(pathbuf); |
521 | } | 521 | } |
522 | 522 | ||
@@ -2138,6 +2138,9 @@ static void common_cpu_mem_hotplug_unplug(void) | |||
2138 | static int cpuset_handle_cpuhp(struct notifier_block *nb, | 2138 | static int cpuset_handle_cpuhp(struct notifier_block *nb, |
2139 | unsigned long phase, void *cpu) | 2139 | unsigned long phase, void *cpu) |
2140 | { | 2140 | { |
2141 | if (phase == CPU_DYING || phase == CPU_DYING_FROZEN) | ||
2142 | return NOTIFY_DONE; | ||
2143 | |||
2141 | common_cpu_mem_hotplug_unplug(); | 2144 | common_cpu_mem_hotplug_unplug(); |
2142 | return 0; | 2145 | return 0; |
2143 | } | 2146 | } |
diff --git a/kernel/kmod.c b/kernel/kmod.c index 4d32eb0771..78d365c524 100644 --- a/kernel/kmod.c +++ b/kernel/kmod.c | |||
@@ -119,9 +119,10 @@ struct subprocess_info { | |||
119 | char **argv; | 119 | char **argv; |
120 | char **envp; | 120 | char **envp; |
121 | struct key *ring; | 121 | struct key *ring; |
122 | int wait; | 122 | enum umh_wait wait; |
123 | int retval; | 123 | int retval; |
124 | struct file *stdin; | 124 | struct file *stdin; |
125 | void (*cleanup)(char **argv, char **envp); | ||
125 | }; | 126 | }; |
126 | 127 | ||
127 | /* | 128 | /* |
@@ -180,6 +181,14 @@ static int ____call_usermodehelper(void *data) | |||
180 | do_exit(0); | 181 | do_exit(0); |
181 | } | 182 | } |
182 | 183 | ||
184 | void call_usermodehelper_freeinfo(struct subprocess_info *info) | ||
185 | { | ||
186 | if (info->cleanup) | ||
187 | (*info->cleanup)(info->argv, info->envp); | ||
188 | kfree(info); | ||
189 | } | ||
190 | EXPORT_SYMBOL(call_usermodehelper_freeinfo); | ||
191 | |||
183 | /* Keventd can't block, but this (a child) can. */ | 192 | /* Keventd can't block, but this (a child) can. */ |
184 | static int wait_for_helper(void *data) | 193 | static int wait_for_helper(void *data) |
185 | { | 194 | { |
@@ -216,8 +225,8 @@ static int wait_for_helper(void *data) | |||
216 | sub_info->retval = ret; | 225 | sub_info->retval = ret; |
217 | } | 226 | } |
218 | 227 | ||
219 | if (sub_info->wait < 0) | 228 | if (sub_info->wait == UMH_NO_WAIT) |
220 | kfree(sub_info); | 229 | call_usermodehelper_freeinfo(sub_info); |
221 | else | 230 | else |
222 | complete(sub_info->complete); | 231 | complete(sub_info->complete); |
223 | return 0; | 232 | return 0; |
@@ -229,34 +238,122 @@ static void __call_usermodehelper(struct work_struct *work) | |||
229 | struct subprocess_info *sub_info = | 238 | struct subprocess_info *sub_info = |
230 | container_of(work, struct subprocess_info, work); | 239 | container_of(work, struct subprocess_info, work); |
231 | pid_t pid; | 240 | pid_t pid; |
232 | int wait = sub_info->wait; | 241 | enum umh_wait wait = sub_info->wait; |
233 | 242 | ||
234 | /* CLONE_VFORK: wait until the usermode helper has execve'd | 243 | /* CLONE_VFORK: wait until the usermode helper has execve'd |
235 | * successfully We need the data structures to stay around | 244 | * successfully We need the data structures to stay around |
236 | * until that is done. */ | 245 | * until that is done. */ |
237 | if (wait) | 246 | if (wait == UMH_WAIT_PROC || wait == UMH_NO_WAIT) |
238 | pid = kernel_thread(wait_for_helper, sub_info, | 247 | pid = kernel_thread(wait_for_helper, sub_info, |
239 | CLONE_FS | CLONE_FILES | SIGCHLD); | 248 | CLONE_FS | CLONE_FILES | SIGCHLD); |
240 | else | 249 | else |
241 | pid = kernel_thread(____call_usermodehelper, sub_info, | 250 | pid = kernel_thread(____call_usermodehelper, sub_info, |
242 | CLONE_VFORK | SIGCHLD); | 251 | CLONE_VFORK | SIGCHLD); |
243 | 252 | ||
244 | if (wait < 0) | 253 | switch (wait) { |
245 | return; | 254 | case UMH_NO_WAIT: |
255 | break; | ||
246 | 256 | ||
247 | if (pid < 0) { | 257 | case UMH_WAIT_PROC: |
258 | if (pid > 0) | ||
259 | break; | ||
248 | sub_info->retval = pid; | 260 | sub_info->retval = pid; |
261 | /* FALLTHROUGH */ | ||
262 | |||
263 | case UMH_WAIT_EXEC: | ||
249 | complete(sub_info->complete); | 264 | complete(sub_info->complete); |
250 | } else if (!wait) | 265 | } |
251 | complete(sub_info->complete); | 266 | } |
267 | |||
268 | /** | ||
269 | * call_usermodehelper_setup - prepare to call a usermode helper | ||
270 | * @path - path to usermode executable | ||
271 | * @argv - arg vector for process | ||
272 | * @envp - environment for process | ||
273 | * | ||
274 | * Returns either NULL on allocation failure, or a subprocess_info | ||
275 | * structure. This should be passed to call_usermodehelper_exec to | ||
276 | * exec the process and free the structure. | ||
277 | */ | ||
278 | struct subprocess_info *call_usermodehelper_setup(char *path, | ||
279 | char **argv, char **envp) | ||
280 | { | ||
281 | struct subprocess_info *sub_info; | ||
282 | sub_info = kzalloc(sizeof(struct subprocess_info), GFP_ATOMIC); | ||
283 | if (!sub_info) | ||
284 | goto out; | ||
285 | |||
286 | INIT_WORK(&sub_info->work, __call_usermodehelper); | ||
287 | sub_info->path = path; | ||
288 | sub_info->argv = argv; | ||
289 | sub_info->envp = envp; | ||
290 | |||
291 | out: | ||
292 | return sub_info; | ||
252 | } | 293 | } |
294 | EXPORT_SYMBOL(call_usermodehelper_setup); | ||
253 | 295 | ||
254 | /** | 296 | /** |
255 | * call_usermodehelper_keys - start a usermode application | 297 | * call_usermodehelper_setkeys - set the session keys for usermode helper |
256 | * @path: pathname for the application | 298 | * @info: a subprocess_info returned by call_usermodehelper_setup |
257 | * @argv: null-terminated argument list | 299 | * @session_keyring: the session keyring for the process |
258 | * @envp: null-terminated environment list | 300 | */ |
259 | * @session_keyring: session keyring for process (NULL for an empty keyring) | 301 | void call_usermodehelper_setkeys(struct subprocess_info *info, |
302 | struct key *session_keyring) | ||
303 | { | ||
304 | info->ring = session_keyring; | ||
305 | } | ||
306 | EXPORT_SYMBOL(call_usermodehelper_setkeys); | ||
307 | |||
308 | /** | ||
309 | * call_usermodehelper_setcleanup - set a cleanup function | ||
310 | * @info: a subprocess_info returned by call_usermodehelper_setup | ||
311 | * @cleanup: a cleanup function | ||
312 | * | ||
313 | * The cleanup function is just befor ethe subprocess_info is about to | ||
314 | * be freed. This can be used for freeing the argv and envp. The | ||
315 | * Function must be runnable in either a process context or the | ||
316 | * context in which call_usermodehelper_exec is called. | ||
317 | */ | ||
318 | void call_usermodehelper_setcleanup(struct subprocess_info *info, | ||
319 | void (*cleanup)(char **argv, char **envp)) | ||
320 | { | ||
321 | info->cleanup = cleanup; | ||
322 | } | ||
323 | EXPORT_SYMBOL(call_usermodehelper_setcleanup); | ||
324 | |||
325 | /** | ||
326 | * call_usermodehelper_stdinpipe - set up a pipe to be used for stdin | ||
327 | * @sub_info: a subprocess_info returned by call_usermodehelper_setup | ||
328 | * @filp: set to the write-end of a pipe | ||
329 | * | ||
330 | * This constructs a pipe, and sets the read end to be the stdin of the | ||
331 | * subprocess, and returns the write-end in *@filp. | ||
332 | */ | ||
333 | int call_usermodehelper_stdinpipe(struct subprocess_info *sub_info, | ||
334 | struct file **filp) | ||
335 | { | ||
336 | struct file *f; | ||
337 | |||
338 | f = create_write_pipe(); | ||
339 | if (IS_ERR(f)) | ||
340 | return PTR_ERR(f); | ||
341 | *filp = f; | ||
342 | |||
343 | f = create_read_pipe(f); | ||
344 | if (IS_ERR(f)) { | ||
345 | free_write_pipe(*filp); | ||
346 | return PTR_ERR(f); | ||
347 | } | ||
348 | sub_info->stdin = f; | ||
349 | |||
350 | return 0; | ||
351 | } | ||
352 | EXPORT_SYMBOL(call_usermodehelper_stdinpipe); | ||
353 | |||
354 | /** | ||
355 | * call_usermodehelper_exec - start a usermode application | ||
356 | * @sub_info: information about the subprocessa | ||
260 | * @wait: wait for the application to finish and return status. | 357 | * @wait: wait for the application to finish and return status. |
261 | * when -1 don't wait at all, but you get no useful error back when | 358 | * when -1 don't wait at all, but you get no useful error back when |
262 | * the program couldn't be exec'ed. This makes it safe to call | 359 | * the program couldn't be exec'ed. This makes it safe to call |
@@ -265,81 +362,68 @@ static void __call_usermodehelper(struct work_struct *work) | |||
265 | * Runs a user-space application. The application is started | 362 | * Runs a user-space application. The application is started |
266 | * asynchronously if wait is not set, and runs as a child of keventd. | 363 | * asynchronously if wait is not set, and runs as a child of keventd. |
267 | * (ie. it runs with full root capabilities). | 364 | * (ie. it runs with full root capabilities). |
268 | * | ||
269 | * Must be called from process context. Returns a negative error code | ||
270 | * if program was not execed successfully, or 0. | ||
271 | */ | 365 | */ |
272 | int call_usermodehelper_keys(char *path, char **argv, char **envp, | 366 | int call_usermodehelper_exec(struct subprocess_info *sub_info, |
273 | struct key *session_keyring, int wait) | 367 | enum umh_wait wait) |
274 | { | 368 | { |
275 | DECLARE_COMPLETION_ONSTACK(done); | 369 | DECLARE_COMPLETION_ONSTACK(done); |
276 | struct subprocess_info *sub_info; | ||
277 | int retval; | 370 | int retval; |
278 | 371 | ||
279 | if (!khelper_wq) | 372 | if (sub_info->path[0] == '\0') { |
280 | return -EBUSY; | 373 | retval = 0; |
281 | 374 | goto out; | |
282 | if (path[0] == '\0') | 375 | } |
283 | return 0; | ||
284 | 376 | ||
285 | sub_info = kzalloc(sizeof(struct subprocess_info), GFP_ATOMIC); | 377 | if (!khelper_wq) { |
286 | if (!sub_info) | 378 | retval = -EBUSY; |
287 | return -ENOMEM; | 379 | goto out; |
380 | } | ||
288 | 381 | ||
289 | INIT_WORK(&sub_info->work, __call_usermodehelper); | ||
290 | sub_info->complete = &done; | 382 | sub_info->complete = &done; |
291 | sub_info->path = path; | ||
292 | sub_info->argv = argv; | ||
293 | sub_info->envp = envp; | ||
294 | sub_info->ring = session_keyring; | ||
295 | sub_info->wait = wait; | 383 | sub_info->wait = wait; |
296 | 384 | ||
297 | queue_work(khelper_wq, &sub_info->work); | 385 | queue_work(khelper_wq, &sub_info->work); |
298 | if (wait < 0) /* task has freed sub_info */ | 386 | if (wait == UMH_NO_WAIT) /* task has freed sub_info */ |
299 | return 0; | 387 | return 0; |
300 | wait_for_completion(&done); | 388 | wait_for_completion(&done); |
301 | retval = sub_info->retval; | 389 | retval = sub_info->retval; |
302 | kfree(sub_info); | 390 | |
391 | out: | ||
392 | call_usermodehelper_freeinfo(sub_info); | ||
303 | return retval; | 393 | return retval; |
304 | } | 394 | } |
305 | EXPORT_SYMBOL(call_usermodehelper_keys); | 395 | EXPORT_SYMBOL(call_usermodehelper_exec); |
306 | 396 | ||
397 | /** | ||
398 | * call_usermodehelper_pipe - call a usermode helper process with a pipe stdin | ||
399 | * @path: path to usermode executable | ||
400 | * @argv: arg vector for process | ||
401 | * @envp: environment for process | ||
402 | * @filp: set to the write-end of a pipe | ||
403 | * | ||
404 | * This is a simple wrapper which executes a usermode-helper function | ||
405 | * with a pipe as stdin. It is implemented entirely in terms of | ||
406 | * lower-level call_usermodehelper_* functions. | ||
407 | */ | ||
307 | int call_usermodehelper_pipe(char *path, char **argv, char **envp, | 408 | int call_usermodehelper_pipe(char *path, char **argv, char **envp, |
308 | struct file **filp) | 409 | struct file **filp) |
309 | { | 410 | { |
310 | DECLARE_COMPLETION(done); | 411 | struct subprocess_info *sub_info; |
311 | struct subprocess_info sub_info = { | 412 | int ret; |
312 | .work = __WORK_INITIALIZER(sub_info.work, | ||
313 | __call_usermodehelper), | ||
314 | .complete = &done, | ||
315 | .path = path, | ||
316 | .argv = argv, | ||
317 | .envp = envp, | ||
318 | .retval = 0, | ||
319 | }; | ||
320 | struct file *f; | ||
321 | 413 | ||
322 | if (!khelper_wq) | 414 | sub_info = call_usermodehelper_setup(path, argv, envp); |
323 | return -EBUSY; | 415 | if (sub_info == NULL) |
416 | return -ENOMEM; | ||
324 | 417 | ||
325 | if (path[0] == '\0') | 418 | ret = call_usermodehelper_stdinpipe(sub_info, filp); |
326 | return 0; | 419 | if (ret < 0) |
420 | goto out; | ||
327 | 421 | ||
328 | f = create_write_pipe(); | 422 | return call_usermodehelper_exec(sub_info, 1); |
329 | if (IS_ERR(f)) | ||
330 | return PTR_ERR(f); | ||
331 | *filp = f; | ||
332 | |||
333 | f = create_read_pipe(f); | ||
334 | if (IS_ERR(f)) { | ||
335 | free_write_pipe(*filp); | ||
336 | return PTR_ERR(f); | ||
337 | } | ||
338 | sub_info.stdin = f; | ||
339 | 423 | ||
340 | queue_work(khelper_wq, &sub_info.work); | 424 | out: |
341 | wait_for_completion(&done); | 425 | call_usermodehelper_freeinfo(sub_info); |
342 | return sub_info.retval; | 426 | return ret; |
343 | } | 427 | } |
344 | EXPORT_SYMBOL(call_usermodehelper_pipe); | 428 | EXPORT_SYMBOL(call_usermodehelper_pipe); |
345 | 429 | ||
diff --git a/kernel/sys.c b/kernel/sys.c index 4d141ae3e8..18987c7f6a 100644 --- a/kernel/sys.c +++ b/kernel/sys.c | |||
@@ -2286,3 +2286,61 @@ asmlinkage long sys_getcpu(unsigned __user *cpup, unsigned __user *nodep, | |||
2286 | } | 2286 | } |
2287 | return err ? -EFAULT : 0; | 2287 | return err ? -EFAULT : 0; |
2288 | } | 2288 | } |
2289 | |||
2290 | char poweroff_cmd[POWEROFF_CMD_PATH_LEN] = "/sbin/poweroff"; | ||
2291 | |||
2292 | static void argv_cleanup(char **argv, char **envp) | ||
2293 | { | ||
2294 | argv_free(argv); | ||
2295 | } | ||
2296 | |||
2297 | /** | ||
2298 | * orderly_poweroff - Trigger an orderly system poweroff | ||
2299 | * @force: force poweroff if command execution fails | ||
2300 | * | ||
2301 | * This may be called from any context to trigger a system shutdown. | ||
2302 | * If the orderly shutdown fails, it will force an immediate shutdown. | ||
2303 | */ | ||
2304 | int orderly_poweroff(bool force) | ||
2305 | { | ||
2306 | int argc; | ||
2307 | char **argv = argv_split(GFP_ATOMIC, poweroff_cmd, &argc); | ||
2308 | static char *envp[] = { | ||
2309 | "HOME=/", | ||
2310 | "PATH=/sbin:/bin:/usr/sbin:/usr/bin", | ||
2311 | NULL | ||
2312 | }; | ||
2313 | int ret = -ENOMEM; | ||
2314 | struct subprocess_info *info; | ||
2315 | |||
2316 | if (argv == NULL) { | ||
2317 | printk(KERN_WARNING "%s failed to allocate memory for \"%s\"\n", | ||
2318 | __func__, poweroff_cmd); | ||
2319 | goto out; | ||
2320 | } | ||
2321 | |||
2322 | info = call_usermodehelper_setup(argv[0], argv, envp); | ||
2323 | if (info == NULL) { | ||
2324 | argv_free(argv); | ||
2325 | goto out; | ||
2326 | } | ||
2327 | |||
2328 | call_usermodehelper_setcleanup(info, argv_cleanup); | ||
2329 | |||
2330 | ret = call_usermodehelper_exec(info, UMH_NO_WAIT); | ||
2331 | |||
2332 | out: | ||
2333 | if (ret && force) { | ||
2334 | printk(KERN_WARNING "Failed to start orderly shutdown: " | ||
2335 | "forcing the issue\n"); | ||
2336 | |||
2337 | /* I guess this should try to kick off some daemon to | ||
2338 | sync and poweroff asap. Or not even bother syncing | ||
2339 | if we're doing an emergency shutdown? */ | ||
2340 | emergency_sync(); | ||
2341 | kernel_power_off(); | ||
2342 | } | ||
2343 | |||
2344 | return ret; | ||
2345 | } | ||
2346 | EXPORT_SYMBOL_GPL(orderly_poweroff); | ||
diff --git a/kernel/sysctl.c b/kernel/sysctl.c index 7063ebc6db..44a1d699aa 100644 --- a/kernel/sysctl.c +++ b/kernel/sysctl.c | |||
@@ -46,6 +46,7 @@ | |||
46 | #include <linux/syscalls.h> | 46 | #include <linux/syscalls.h> |
47 | #include <linux/nfs_fs.h> | 47 | #include <linux/nfs_fs.h> |
48 | #include <linux/acpi.h> | 48 | #include <linux/acpi.h> |
49 | #include <linux/reboot.h> | ||
49 | 50 | ||
50 | #include <asm/uaccess.h> | 51 | #include <asm/uaccess.h> |
51 | #include <asm/processor.h> | 52 | #include <asm/processor.h> |
@@ -705,6 +706,15 @@ static ctl_table kern_table[] = { | |||
705 | .proc_handler = &proc_dointvec, | 706 | .proc_handler = &proc_dointvec, |
706 | }, | 707 | }, |
707 | #endif | 708 | #endif |
709 | { | ||
710 | .ctl_name = CTL_UNNUMBERED, | ||
711 | .procname = "poweroff_cmd", | ||
712 | .data = &poweroff_cmd, | ||
713 | .maxlen = POWEROFF_CMD_PATH_LEN, | ||
714 | .mode = 0644, | ||
715 | .proc_handler = &proc_dostring, | ||
716 | .strategy = &sysctl_string, | ||
717 | }, | ||
708 | 718 | ||
709 | { .ctl_name = 0 } | 719 | { .ctl_name = 0 } |
710 | }; | 720 | }; |