echo /sbin/mdev > /proc/sys/kernel/hotplug 作用解析

参见:https://zhidao.baidu.com/question/1606465593857998667.html

linux系统对于热插拔事件的产生默认都是调用/sbin/hotplug,该程序通过加载驱动程序,创建设备节点,挂载分区等。如果系统中不是/sbin/hotplug来执行,而是mdev,那么用户应当在早期启动的时候将该执行档(包含绝对位置)设置进去,于是有了上面的echo /sbin/mdev> /proc/sys/kernel/hotplug。我们可以在脚本中注释掉该命令行,重新开机后cat /proc/sys/kernel/hotplug就会发现返回来的是/sbin/hotplug说明系统默认都是调用这个。这个的配置在内核编译的时候写好的,在内核目录下的.config可以看到有个配置叫做CONFIG_UEVENT_HELPER_PATH="/sbin/hotplug",如果你编译的时候修改这个也是可以更改到的。

参见:https://blog.csdn.net/qq_21435127/article/details/80689577

mdev是busybox提供的一个工具,用在嵌入式系统中,相当于简化版的udev,作用是在系统启动和热插拔或动态加载驱动程序时,
自动创建设备节点。文件系统中的/dev目录下的设备节点都是由mdev创建的。在加载驱动过程中,根据驱动程序,在/dev下自动创建设备节点。

1、在/etc/init.d/rcS脚本里有“mdev -s”
解释:系统启动时,通过执行“mdev -s”扫描/sys/class和/sys/block,在目录中查找dev文件。例如:/sys/class/tty/tty0/dev,

它的内容为”4:0”,即主设备号是4,次设备号是0,dev的上一级目录为设备名,这里是tty0。/sys/class/下的每个文件夹都代表
着一个子系统。

2、在/etc/init.d/rcS脚本里有“echo /sbin/mdev > /proc/sys/kernel/hotplug”

解释:把/sbin/mdev写到/proc/sys/kernel/hotplug文件里。当有热插拔事件产生时,内核会调用/proc/sys/kernel/hotplug文件里指定的应用程序来处理热插拔事件。

设置mdev有三种方法,总结如下:
1、编译内核的时候直接配置CONFIG_UEVENT_HELPER_PATH,并且在之后的启动中不去修改uevent_helper,那么
uevent_helper代表的程序就是CONFIG_UEVENT_HELPER_PATH指定的程序

2、不管CONFIG_UEVENT_HELPER_PATH配置与否或如何设置,通过echo /sbin/mdev > /sys/kernel/uevent_helper
修改uevent_helper的内容,这个指令将会调用内核函数uevent_helper_store。过程涉及sysfs虚拟文件系统的
内容,这里不讨论。改变之后,/proc/sys/kernel/hotplug里的内容也会立即发生改变

3、不管CONFIG_UEVENT_HELPER_PATH配置与否或如何设置,通过echo /sbin/mdev > /proc/sys/kernel/hotplug
修改uevent_helper的内容.它的修改也会导致/sys/kernel/uevent_helper里的内容立即改变

对于上述的2、3两种方法,都是通过用户层的接口直接uevent_helper,所以谁在后面谁起作用。
————————————————
版权声明:本文为CSDN博主「蓝天居士」的原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接及本声明。
原文链接:https://blog.csdn.net/phmatthaus/article/details/107180696

三、busybox源码分析

内核源码的最后是调用uevent_helper指定的用户程序,这个用户程序通常是mdev,那么mdev如何做的呢,来看一下
busybox的源码。源码基于busybox-1.23.1

int mdev_main(int argc UNUSED_PARAM, char **argv)
xchdir("/dev"); // 先把目录改变到/dev下

if (argv[1] && strcmp(argv[1], "-s") == 0) {  // 在文件系统启动的时候会调用 mdev -s,创建所有驱动设备节点
    putenv((char*)"ACTION=add"); // mdev -s 的动作是创建设备节点,所以为add

    if (access("/sys/class/block", F_OK) != 0) { // 当/sys/class/block目录不存在时,才扫描/sys/block
 /* Scan obsolete /sys/block only if /sys/class/block
  * doesn't exist. Otherwise we'll have dupes.
  * Also, do not complain if it doesn't exist.
  * Some people configure kernel to have no blockdevs.
  */
 recursive_action("/sys/block",
 ACTION_RECURSE | ACTION_FOLLOWLINKS | ACTION_QUIET,
 fileAction, dirAction, temp, 0);

}

/*
* 这个函数是递归函数,它会扫描/sys/class目录下的所有文件,如果发现dev文件,将按照
* /etc/mdev.conf文件进行相应的配置。如果没有配置文件,那么直接创建设备节点
* 最终调用的创建函数是 make_device
*/
recursive_action("/sys/class",
ACTION_RECURSE | ACTION_FOLLOWLINKS,
fileAction, dirAction, temp, 0);

}

else{
    // 获得环境变量,环境变量是内核在调用mdev之前设置的
    env_devname = getenv("DEVNAME"); /* can be NULL */

G.subsystem = getenv(“SUBSYSTEM”);
action = getenv(“ACTION”);
env_devpath = getenv(“DEVPATH”);

    snprintf(temp, PATH_MAX, "/sys%s", env_devpath);

    make_device(env_devname, temp, op);
}

由以上代码分析可知,无论对于何种操作,最后都是调用make_device来创建节点,看一下这个函数

static void make_device(char *device_name, char *path, int operation)
int major, minor, type, len;
char *path_end = path + strlen(path); //path_end指定path结尾处

major = -1;
if (operation == OP_add) {
    strcpy(path_end, "/dev");  // 往path结尾处拷贝“/dev”,这时path=/sys/class/test/test_dev/dev
    len = open_read_close(path, path_end + 1, SCRATCH_SIZE - 1); // 打开并读取/sys/class/test/test_dev/dev
    *path_end = '\0';
    if (len < 1) {
        if (!ENABLE_FEATURE_MDEV_EXEC)
            return;
    } else if (sscanf(path_end + 1, "%u:%u", &major, &minor) == 2) { //从/sys/class/test/test_dev/dev获得主次设备号
        dbg1("dev %u,%u", major, minor);
    } else {
        major = -1;
    }
}

if (operation == OP_add && major >= 0) // 如果是add,即创建节点
    mknod(node_name, rule->mode | type, makedev(major, minor)) // 最终用mknod函数在/dev下创建设备节点
    
if (operation == OP_remove && major >= -1)  // 如果是remove,即删除节点
    unlink(node_name); 

创建节点最后无非还是调用mknod,当然在class_create和device_create自动创建设备节点时,也会在/sys/class下自动创建
和删除相关设备类和设备,这是sysfs的驱动内容,这里不讲

上一篇:linux安装nginx


下一篇:从0开始学习shell---文本处理grep工具