浅析request_module内核驱动直接引用用户空间程序/sbin/modprobe
对initramfs文件系统和busybox之间暧昧关系的分析理解在soundcore_open打开/dev/dsp节点函数中会调用到下面的:
request_module("sound-slot-%i", unit>>4);
函数,这表示,让linux系统的用户空间调用/sbin/modprobe函数加载名为sound-slot-0.ko模块
#define request_module(mod...) __request_module(true, mod)
#define request_module_nowait(mod...) __request_module(false, mod)
luther@gliethttp:~$ cat /proc/sys/kernel/modprobe
/sbin/modprobe
我们也可以向/proc/sys/kernel/modprobe添加新的modprobe应用程序路径,这里的/sbin/modprobe是内核默认路径.
/**
* __request_module - try to load a kernel module // 尝试加载一个ko模块[luther.gliethttp]
* @wait: wait (or not) for the operation to complete
* @fmt: printf style format string for the name of the module
* @...: arguments as specified in the format string
*
* Load a module using the user mode module loader. The function returns
* zero on success or a negative errno code on failure. Note that a
* successful module load does not mean the module did not then unload
* and exit on an error of its own. Callers must check that the service
* they requested is now available not blindly invoke it.
*
* If module auto-loading support is disabled then this function
* becomes a no-operation.
*/
int __request_module(bool wait, const char *fmt, ...)
{
va_list args;
char module_name[MODULE_NAME_LEN];
unsigned int max_modprobes;
int ret;
// char modprobe_path[KMOD_PATH_LEN] = "/sbin/modprobe";
char *argv[] = { modprobe_path, "-q", "--", module_name, NULL };
static char *envp[] = { "HOME=/",
"TERM=linux",
"PATH=/sbin:/usr/sbin:/bin:/usr/bin",
NULL }; // 环境变量.
static atomic_t kmod_concurrent = ATOMIC_INIT(0);
#define MAX_KMOD_CONCURRENT 50 /* Completely arbitrary value - KAO */
static int kmod_loop_msg;
va_start(args, fmt);
ret = vsnprintf(module_name, MODULE_NAME_LEN, fmt, args); // 生成module名,这里就是sound-slot-0
va_end(args);
if (ret >= MODULE_NAME_LEN)
return -ENAMETOOLONG;
/* If modprobe needs a service that is in a module, we get a recursive // 对递归循环的一个硬性限制
* loop. Limit the number of running kmod threads to max_threads/2 or // 最多同时运行max_modprobes个modprobe用户程序
* MAX_KMOD_CONCURRENT, whichever is the smaller. A cleaner method // 如果超过,那么__request_module返回-ENOMEM
* would be to run the parents of this process, counting how many times // [luther.gliethttp]
* kmod was invoked. That would mean accessing the internals of the
* process tables to get the command line, proc_pid_cmdline is static
* and it is not worth changing the proc code just to handle this case.
* KAO.
*
* "trace the ppid" is simple, but will fail if someone's
* parent exits. I think this is as good as it gets. --RR
*/
max_modprobes = min(max_threads/2, MAX_KMOD_CONCURRENT); // 最多同时运行max_modprobes个modprobe用户程序
atomic_inc(&kmod_concurrent);
if (atomic_read(&kmod_concurrent) > max_modprobes) {
/* We may be blaming an innocent here, but unlikely */
if (kmod_loop_msg++ < 5)
printk(KERN_ERR
"request_module: runaway loop modprobe %s\n",
module_name);
atomic_dec(&kmod_concurrent); // 消除前面atomic_inc产生的引用
return -ENOMEM; // 返回错误[luther.gliethttp]
}
ret = call_usermodehelper(modprobe_path, argv, envp, // 执行用户空间的应用程序/sbin/modprobe
wait ? UMH_WAIT_PROC : UMH_WAIT_EXEC);
atomic_dec(&kmod_concurrent); // 消除atomic_inc产生的引用
return ret;
}
EXPORT_SYMBOL(__request_module);