博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
二十三、uevnet机制和U盘自动挂载
阅读量:4565 次
发布时间:2019-06-08

本文共 5268 字,大约阅读时间需要 17 分钟。

一、uevent机制

在分析之前,我们首先要知道uevent作用是什么。在此我们先来看一个uevent机制的框架图:

该图片来自:

通过图片我们可以确定uevent的作用:设备产生上报事件时会触发uevent接口,uevent则通过netlink和kmod这两种方式把事件上报到用户空间。kmod会直接调用用户空间的程序,netlink只是将事件上报到用户空间。

 

之前我们分析的大部分设备驱动都会在/dev/目录下创建节点给用户使用。那么在我们调用device_create()后内核会做什么呢?

现在我们来分析device_create()的详细调用关系:

device_create()  -> va_start(vargs, fmt);              /* 初始化va_list可变参数变量 */  -> dev = device_create_vargs(class, parent, devt, drvdata, fmt, vargs);    -> dev = kzalloc(sizeof(*dev), GFP_KERNEL);    -> dev->devt = devt;                /* 设置device成员 */    -> retval = device_register(dev);      -> device_initialize(dev);        /* 初始化device链表头 */      -> device_add(dev);               /* 添加device */        -> kobject_uevent(&dev->kobj, KOBJ_ADD);          -> kobject_uevent_env(kobj, action, NULL);            -> env = kzalloc(sizeof(struct kobj_uevent_env), GFP_KERNEL);      /* 分配环境变量 */            -> if (uevent_helper[0] && !kobj_usermode_filter(kobj))              -> argv [0] = uevent_helper;    /* 下面调用的就是uevent_helper程序 */              -> call_usermodehelper(argv[0], argv, env->envp, UMH_WAIT_EXEC); /* 调用应用程序argv[0] */  -> va_end(vargs);

为了确定调用程序,我们可以在代码中添加打印语句,如8-14行:

1 if (uevent_helper[0] && !kobj_usermode_filter(kobj)) { 2     char *argv [3]; 3  4     argv [0] = uevent_helper; 5     argv [1] = (char *)subsystem; 6     argv [2] = NULL; 7  8     int i; 9     for (i = 0; i < 2; ++i) {    /* 参数 */10         printk("device: argv[%d] = %s\n", i, argv[i]);11     }12     for (i = 0; env[i]; ++i) {   /* 环境变量 */13         printk("device: envp[%d] = %s", i, env[i]);14     }15 16     retval = add_uevent_var(env, "HOME=/");17     if (retval)18         goto exit;19     retval = add_uevent_var(env,20                 "PATH=/sbin:/bin:/usr/sbin:/usr/bin");21     if (retval)22         goto exit;23 24     retval = call_usermodehelper(argv[0], argv,25                      env->envp, UMH_WAIT_EXEC);26 }

重新编译烧写内核后,insmod某个模块后可以确定uevent_helper为/sbin/mdev

 

/sbin/mdev定义在busybox的mdev.c中:

我们使用SI4创建busybox工程后,打开mdev.c,分析mdev_main()函数:

1 int mdev_main(int argc, char **argv) 2 { 3     char *action; 4     char *env_path; 5     RESERVE_CONFIG_BUFFER(temp,PATH_MAX); 6  7     xchdir("/dev"); 8  9     if (argc == 2 && !strcmp(argv[1],"-s")) {        /* 判断参数个数,如果不是mdev -s进入if */10         struct stat st;11 12         xstat("/", &st);13         root_major = major(st.st_dev);14         root_minor = minor(st.st_dev);15 16         recursive_action("/sys/block",17             ACTION_RECURSE | ACTION_FOLLOWLINKS,18             fileAction, dirAction, temp, 0);19 20         recursive_action("/sys/class",21             ACTION_RECURSE | ACTION_FOLLOWLINKS,22             fileAction, dirAction, temp, 0);23 24     } else {                                        /* 热拔插mdev -s */25         action = getenv("ACTION");                    /* 设备驱动中ACTION = add */26         env_path = getenv("DEVPATH");                /* DEVPATH = /class/dma_test */27         if (!action || !env_path)28             bb_show_usage();29 30         sprintf(temp, "/sys%s", env_path);            /* temp = /sys/class/dma_test */31         if (!strcmp(action, "remove"))32             make_device(temp, 1);33         else if (!strcmp(action, "add")) {34             make_device(temp, 0);35 36             if (ENABLE_FEATURE_MDEV_LOAD_FIRMWARE)37                 load_firmware(getenv("FIRMWARE"), temp);38         }39     }40 41     if (ENABLE_FEATURE_CLEAN_UP) RELEASE_CONFIG_BUFFER(temp);42     return 0;43 }
View Code

此函数最终调用make_device(temp, 0)创建设备,调用层次如下:

make_device(temp, 0);  -> device_name = bb_basename(path);  -> if (ENABLE_FEATURE_MDEV_CONF)                            /* 如果配置了支持mdev.conf选项 */    -> fd = open("/etc/mdev.conf", O_RDONLY);                 /* 操作mdev.conf文件 */  -> if (!delete)                                             /* 如果是创建设备节点 */    -> mknod(device_name, mode | type, makedev(major, minor)  /* 创建节点 */

 

下面我们来看看如何使用mdev.conf,参考工程中mdev.txt文件:

如设置初始化脚本/etc/init.d/rcS:

Here's a typical code snippet from the init script:[1] mount -t sysfs sysfs /sys[2] echo /bin/mdev > /proc/sys/kernel/hotplug[3] mdev -sOf course, a more "full" setup would entail executing this before the previouscode snippet:[4] mount -t tmpfs mdev /dev[5] mkdir /dev/pts[6] mount -t devpts devpts /dev/pts

/etc/ndev.conf文件格式:

the format:     
:
[<@|$|*>
]The special characters have the meaning: @ Run after creating the device. $ Run before removing the device. * Run both after creating and before removing the device.
the format:     
:
[<@|$|*>
]The special characters have the meaning: @ Run after creating the device. $ Run before removing the device. * Run both after creating and before removing the device.

其中,

<device regex>:正则表达式,可参考:

<uid>:用户ID

<gid>:组ID

<octal permissions>:/dev/dma_test的权限

<command>:命令

 

了解上面知识后,下一节开始编辑mdev.conf实现U盘自动挂载

 

 

二、编辑mdev.conf实现U盘自动挂载

在网络文件系统根目录中执行:

# vim etc/mdev.conf

添加一行:

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

其中,

sda[1-9]+表示重复匹配1-9的数字多次

*表示创建设备节点之后和删除设备节点之前执行命令

命令表示如果ACTION是add,则挂载,否则取消挂载

 

效果如下图,乱码是由于开发板不支持中文:

 

转载于:https://www.cnblogs.com/Lioker/p/11306891.html

你可能感兴趣的文章
Group by子句和空值
查看>>
计算字符的相似度【转】
查看>>
更新centos7的kernel
查看>>
day05
查看>>
EFI环境下的Ubuntu&Win10双系统安装
查看>>
oracle 的三个主要内存结构SGA,PGA,UGA
查看>>
PHP大批量插入数据库的3种方法和速度对比
查看>>
Apache Spark大数据分析入门(一)
查看>>
java8使用stream的collect进行list转map注意事项
查看>>
部分和问题
查看>>
进程,线程
查看>>
[。。。]不知道是事故还是故事的东西
查看>>
AtCoder Beginner Contest 073
查看>>
链表的回文结构
查看>>
slqmap简单使用
查看>>
如何禁用或重新启用计算机的休眠功能
查看>>
window函数 resetAccumulator
查看>>
AKKA好文
查看>>
hdu - 1728逃离迷宫 && hdu - 1175 连连看 (普通bfs)
查看>>
python环境下xgboost的安装与使用
查看>>