uevent, user space event. 内核与用户空间的一种通信机制,基于netlink机制,主要用于设备驱动模型,例如热插拔。

1、调用/sbin/mdev的流程分析

在驱动程序中经常出现class_device_create这个函数,它用来在/dev目录下创建各个设备的设备节点,那么,这个是怎么实现的呢?下面就来分析这个过程的实现,直接进到class_device_create函数中层层分析它。

class_device_create
    class_device_register
        class_device_add
            kobject_uevent(&class_dev->kobj, KOBJ_ADD);
                kobject_uevent_env(kobj, action, NULL);
                    // action_string  = "add";
                    action_string = action_to_string(action);
                    /* 分配、保存环境变量的内存 */
                    /* environment values */
                    buffer = kmalloc(BUFFER_SIZE, GFP_KERNEL);
                    
                    /* 设置环境变量 */
                    nvp [i++] = scratch;
                    scratch += sprintf(scratch, "ACTION=%s", action_string) + 1;
                    envp [i++] = scratch;
                    scratch += sprintf (scratch, "DEVPATH=%s", devpath) + 1;
                    envp [i++] = scratch;
                    scratch += sprintf(scratch, "SUBSYSTEM=%s", subsystem) + 1;

                    /* 调用应用程序:比如mdev */
                    /* 在/etc/init.d/rcS 中的echo /sbin/mdev > /proc/sys/kernel/hotplug指定了应用程序*/
                    argv [0] = uevent_helper;    // = "/sbin/mdev"
                    argv [1] = (char *)subsystem;
                    argv [2] = NULL;
                    call_usermodehelper (argv[0], argv, envp, 0);

从上面的调用关系可以看出,最终内核会调用用户空间的/sbin/mdev程序,并且使用该程序的环境变量。

 

2、mdev源码分析

接下来看到busy_box下的mdev机制的实现,直接看到mdev.c文件,列出调用关系:

mdev_main
    temp = "/sys/class/buttons/buttons"
    make_device(temp, 0);
        /* 确定设备文件名,类型,主设备号,次设备号 */
        path = "/sys/class/buttons/buttons"
        device_name = bb_basename(path); = "buttons"
        type = path[5]=='c' ? S_IFCHR : S_IFBLK;  // ='c'是字符设备节点
        
        根据 "/sys/class/buttons/buttons/dev"的内容确定主次设备号
        mknod(device_name, mode | type, makedev(major, minor)

从上面的调用关系可以看出mdev最终通过mknod生成了设备节点

 

3、利用mdev机制实现U盘的挂接

分析mdev源码可以知道,它还可以根据/etc/mdev.conf这个配置文件来执行某个命令,这个文件的格式如下:

mdev.conf的格式:
<device regex> <uid>:<gid> <octal permissions> [<@|$|*> <command>]

每个字段的含义如下:

device regex:正则表达式,表示哪一个设备
uid:owner
gid:组id
octal permissions:以八进制表示的属性
@ :创建设备节点之后执行命令    
$: 删除设备节点之前执行命令
* :创建设备节点之后执行命令    和   删除设备节点之前执行命令
command:要执行的命令

正则表达式的介绍如下:

正则表达式:
1、在电脑上查文件,*.c(*表示通配符,表示任意字符)
2、用正则表达式
    .表示任意字符(换行符除外)
    *表示重复0次或更多次
    +重复1次或更多次
    ?重复0次或1次
    [...]表示中括号里面的字符的某一个

假设需要自动挂载U盘,它的/etc/mdev.conf可以这么写:

sda[1-9]+ 0:0 777 * if [ $ACTION = "add" ]; then mount /dev/$MDEV /mnt;else umount /mnt; fi

其中sda[1-9]+表示sda1-sda9中的一个或多个。后面跟着shell命令,如果是有U盘加载的话,那么挂接到/mnt上,否则的话,就卸载。

当然也可以把shell命令写成脚本的形式,脚本存放在/bin/add_remove_udisk.sh

sda[1-9]+ 0:0 777 * /bin/add_remove_udisk.sh

/bin/add_remove_udisk.sh
#!/bin/sh
if [ $ACTION = "add" ]; 
then 
    mount /dev/$MDEV /mnt;
else 
    umount /mnt; 
fi

 

posted on 2019-08-05 20:48  andy_fly  阅读(1257)  评论(0编辑  收藏  举报