105static inline int
106call_usermodehelper(char *path, char **argv, char **envp, enum umh_wait wait)
107{
108 return call_usermodehelper_fns(path, argv, envp, wait,
109 NULL, NULL, NULL);
110}
111
50enum umh_wait {
51 UMH_NO_WAIT = -1, /* don't wait at all */
52 UMH_WAIT_EXEC = 0, /* wait for the exec, but not the process */
53 UMH_WAIT_PROC = 1, /* wait for the process to complete */
54};
55
56struct subprocess_info {
57 struct work_struct work;
58 struct completion *complete;
59 char *path;
60 char **argv;
61 char **envp;
62 enum umh_wait wait;
63 int retval;
64 int (*init)(struct subprocess_info *info);
65 void (*cleanup)(struct subprocess_info *info);
66 void *data;
67};
68
377/**
378 * call_usermodehelper_exec - start a usermode application
379 * @sub_info: information about the subprocessa 子进程的信息
380 * @wait: wait for the application to finish and return status.等待用户空间子进程的完成,并返回结果。
381 * when -1 don't wait at all, but you get no useful error back when
382 * the program couldn't be exec'ed. This makes it safe to call
383 * from interrupt context.
-1表示根本不等待子进程的结束。 但这样你就无法对程序出错进行处理。
如果使用中断上下文,那么应该使用-1。
384 *
385 * Runs a user-space application. The application is started
386 * asynchronously if wait is not set, and runs as a child of keventd.
387 * (ie. it runs with full root capabilities).
call_usermodehelper_exec函数,启动一个用户模式应用程序。
如果不设置wait,那么用户空间应用程序会被异步启动。 它在root权限下运行。是keventd进程的子进程。
388 */
389int call_usermodehelper_exec(struct subprocess_info *sub_info,
390 enum umh_wait wait)
391{
392 DECLARE_COMPLETION_ONSTACK(done);
393 int retval = 0;
394
395 helper_lock();
396 if (sub_info->path[0] == '\0')
397 goto out;
398
399 if (!khelper_wq || usermodehelper_disabled) {
400 retval = -EBUSY;
401 goto out;
402 }
403
404 sub_info->complete = &done;
405 sub_info->wait = wait;
406把用户空间进程挂到一个内核工作队列。
407 queue_work(khelper_wq, &sub_info->work);
408 if (wait == UMH_NO_WAIT) /* task has freed sub_info */
409 goto unlock;
如果等待子进程完成,那么执行等待完成的 事件通知和唤醒。就是说当前进程sleep。
410 wait_for_completion(&done);
411 retval = sub_info->retval;
412
413out:
414 call_usermodehelper_freeinfo(sub_info);
415unlock:
416 helper_unlock();
417 return retval;
418}
419EXPORT_SYMBOL(call_usermodehelper_exec);
420
421void __init usermodehelper_init(void)
422{
423 khelper_wq = create_singlethread_workqueue("khelper");
424 BUG_ON(!khelper_wq);
425}