mdev详解

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

在加载驱动过程中,根据驱动程序,在/dev下自动创建设备节点。

以下内容摘自busybox-1.23.1的mdev.txt文件:

Mdev has two primary uses: initial population and dynamic updates.  Both 
require sysfs support in the kernel and have it mounted at /sys.  For dynamic 
updates, you also need to have hotplugging enabled in your kernel.Here's a typical code snippet from the init script: 
[0] mount -t proc proc /proc 
[1] mount -t sysfs sysfs /sys 
[2] echo /sbin/mdev > /proc/sys/kernel/hotplug 
[3] mdev -sAlternatively, without procfs the above becomes: 
[1] mount -t sysfs sysfs /sys 
[2] sysctl -w kernel.hotplug=/sbin/mdev 
[3] mdev -sOf course, a more "full" setup would entail executing this before the previous 
code snippet: 
[4] mount -t tmpfs -o size=64k,mode=0755 tmpfs /dev 
[5] mkdir /dev/pts 
[6] mount -t devpts devpts /dev/pts
The simple explanation here is that [1] you need to have /sys mounted before 
executing mdev.  Then you [2] instruct the kernel to execute /sbin/mdev whenever 
a device is added or removed so that the device node can be created or destroyed.  
Then you [3] seed /dev with all the device nodes that were created while the system 
was booting.For the "full" setup, you want to [4] make sure /dev is a tmpfs filesystem 
(assuming you're running out of flash).  Then you want to [5] create the 
/dev/pts mount point and finally [6] mount the devpts filesystem on it.
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29

二、用法

这篇博文所涉及到的用法很简单:

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.txt的说明可知在使用mdev之前要满足下面的条件:
mount -t proc proc /proc
mount -t sysfs sysfs /sys
mount -t tmpfs -o size=64k,mode=0755 tmpfs /dev
mkdir /dev/pts
mount -t devpts devpts /dev/pts

说明:所有的设备都可以在/sys/class下找到,这个文件夹下的每一个文件夹下代表了一类设备,表示类设备的文件夹下也有
文件夹,这些文件夹代表设备。如:/sys/class/test/test_dev/ ,test代表类,如net、tty、sound;test_dev代表某个
设备,它的名字和/dev下的设备节点名字是一样的


三、内核源码分析

分析一下相关内核源码,看上面提到的功能是如何实现的。
平时我们添加驱动时,如果想自动创建设备节点调用的函数是class_create和device_create。class_create是创建类设备,
就是在/sys/class/创建一个文件夹,这个文件夹代表一类设备,这个文件夹里会包含device_create创建的设备,也是一个
文件夹。
下面就从device_create入手,看是怎么实现自动创建设备节点的。源码基于linux-2.6.30.4内核

struct device *device_create(struct class *class, struct device *parent,dev_t devt, void *drvdata, const char *fmt, ...)dev = device_create_vargs(class, parent, devt, drvdata, fmt, vargs);retval = device_register(dev);return device_add(dev);kobject_uevent(&dev->kobj, KOBJ_ADD);return kobject_uevent_env(kobj, action, NULL);   // action = KOBJ_ADDconst char *action_string = kobject_actions[action];    // action_string = "add"……//把相关信息存到环境变量里,ACTION代表操作类型,DEVPATH为设备在class下存在的路径,SUBSYSTEM为class_create创建的设备类//ACTION=add , DEVPATH=/class/test/test_dev , SUBSYSTEM=testretval = add_uevent_var(env, "ACTION=%s", action_string);if (retval)goto exit;retval = add_uevent_var(env, "DEVPATH=%s", devpath);if (retval)goto exit;retval = add_uevent_var(env, "SUBSYSTEM=%s", subsystem);if (retval)goto exit;……if (uevent_helper[0]){argv [0] = uevent_helper;argv [1] = (char *)subsystem;argv [2] = NULL;//内核空间调用用户空间程序,调用的程序由argv [0] = uevent_helper指定retval = call_usermodehelper(argv[0], argv,env->envp, UMH_WAIT_EXEC);
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31

下面看看uevent_helper是谁
定义如下:

char uevent_helper[UEVENT_HELPER_PATH_LEN] = CONFIG_UEVENT_HELPER_PATH;
  • 1
  • 2

去.config中查看:
CONFIG_UEVENT_HELPER_PATH=”/sbin/hotplug”
但是去/sbin目录下查看,并没有hotplug这个文件,所以肯定不是这个文件起作用,于是在上面的if (uevent_helper[0])
里加了一句调试信息,打印uevent_helper,内核启动相关打印信息如下:

uevent_helper is /sbin/hotplug 
uevent_helper is /sbin/hotplug 
s3c2410-rtc s3c2410-rtc: setting system clock to 2015-04-30 08:12:15 UTC (1430381535)
yaffs: dev is 32505858 name is "mtdblock2"
yaffs: passed flags ""
yaffs: Attempting MTD mount on 31.2, "mtdblock2"
yaffs: auto selecting yaffs2
block 646 is bad
yaffs_read_super: isCheckpointed 0
VFS: Mounted root (yaffs filesystem) on device 31:2.
Freeing init memory: 240K
Start Qtopia-2.2.0
uevent_helper is /sbin/mdev 
uevent_helper is /sbin/mdev 
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14

看到没,刚开始确实是/sbin/hotplug,但后来就变成了/sbin/mdev。很据上面信息,我们知道是在文件系统启动的过程中
发生改变的。文件系统启动过程中,改变mdev的只有“echo /sbin/mdev > /proc/sys/kernel/hotplug”,也确实是这个
导致了uevent_helper的改变。

涉及到的数据在/kernel/sysctl.c下

至于为什么“echo /sbin/mdev > /proc/sys/kernel/hotplug”能改变uevent_helper就是proc虚拟文件系统的内容了,
这里不讨论。

#if defined(CONFIG_HOTPLUG) && defined(CONFIG_NET)
{
.ctl_name   = KERN_HOTPLUG,
.procname   = "hotplug",
.data   = &uevent_helper,
.maxlen = UEVENT_HELPER_PATH_LEN,
.mode   = 0644,
.proc_handler   = &proc_dostring,
.strategy   = &sysctl_string,
},
#endif
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11

其实设置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,所以谁在后面谁起作用


三、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 的动作是创建设备节点,所以为addif (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);}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41

由以上代码分析可知,无论对于何种操作,最后都是调用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/devlen = 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); 
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26

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


本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/403889.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

ibatis--百度百科

iBATIS一词来源于“internet”和“abatis”的组合&#xff0c;是一个由Clinton Begin在2002年发起的开放源代码项目。于2010年6月16号被谷歌托管&#xff0c;改名为MyBatis。是一个基于SQL映射支持Java和NET的持久层框架。外文名iBATIS来 源"internet"和"aba…

vue-cli3项目通过vue如何引入第三方js包完成登陆功能

注意&#xff1a;本次登陆&#xff0c;前后端分离&#xff1b;前端通过引入第三方的js包&#xff0c;调用js包里的初始化方法和提交方法完成登陆以及退出&#xff1b; 流程1.引入第三方包 1.1在index.html文件下引入 流程2.完成初始化 在组件的created下完成初始化 问题2.1因…

理解和配置 Linux 下的 OOM Killer

From: http://www.vpsee.com/2013/10/how-to-configure-the-linux-oom-killer/ 最近有位 VPS 客户抱怨 MySQL 无缘无故挂掉&#xff0c;还有位客户抱怨 VPS 经常死机&#xff0c;登陆到终端看了一下&#xff0c;都是常见的 Out of memory 问题。这通常是因为某时刻应用程序大量…

python 里面的单下划线与双下划线的区别

python 里面的单下划线与双下划线的区别 Python 用下划线作为变量前缀和后缀指定特殊变量。 _xxx 不能用from moduleimport *导入 __xxx__ 系统定义名字 __xxx 类中的私有变量名 核心风格&#xff1a;避免用下划线作为变量名的开始。 因为下划线对解释器有特殊的意义&#x…

前端vscode插件合集

工欲善其事必先利其器 安装步骤 . . . . . . . . . 1.中文包Chinese (Simplified) Language Pack for Visual Studio Code 2.自动闭合标签Auto Close Tag 3.同步修改标签Auto Rename Tag 4.高亮代码的回调&#xff0c;括号的区域范围Bracket Pair Colorizer 4.支持多中…

无法加载安装安装程序:Wbemupgd.dll

今天打开添加/删除程序 ,准备安装几个windows组件,结果出现下面的错误:无法加载安装安装程序&#xff1a;Wbemupgd.dll&#xff0c;或是找不到函数0cEntry.请与您的系统管理员联系。特定错误码是0x7e于是,搜索一下,原来是path环境变量中,缺少指向System32/wbem目录的指向...OK.…

Android卷一全文 第一章 阅读前的准备工作

本章主要内容本章简单介绍Android系统架构、编译环境的搭建以及一些工具的使用。1.1 系统架构 1.1.1 Android系统架构 Android是Google公司推出的一款手机开发平台。该平台本身是基于Linux内核的&#xff0c;图1-1展示了这个系统的架构&#xff1a;图1-1 Android系统架构 从…

/etc/fstab详解

From: http://blog.csdn.net/clozxy/article/details/5603222 fstab(/etc/fstab)是Linux下比较重要的配置文件&#xff0c;它包含了系统在启动时挂载文件系统和存储设备的详细信息。下面是我机子上的 fstab文件&#xff1a; LABEL/ / …

web安全字体

webfont解剖 Unicode字体可以包含数以千计字形有四个字体格式&#xff1a; WOFF2, WOFF, EOT, TTF一些字体格式需要使用GZIP压缩 一个web字体是字形的集合&#xff0c;且每个字形是一个描述了一个字母亦或符号的矢量图。 所以&#xff0c;一个字体文件的大小由两个因素决定&…

vue如何引入ant部分组件

官网ant 在marn.js下 import Vue from vue; import { Button, message } from ant-design-vue; import App from ./App;Vue.config.productionTip false;/* v1.1.2 */ Vue.component(Button.name, Button); Vue.component(Button.Group.name, Button.Group);/* v1.1.3 自动注…

各个行业纷纷瞅准了这块大蛋糕

今年以来&#xff0c;新疆民生工程和各援疆项目不断加大建设力度&#xff0c;钢材、石料等建筑上必不可少的材料需求见涨&#xff0c;钢铁行业和砂石行业纷纷进驻新疆市场&#xff0c;建厂投资&#xff0c;使新疆展现出一派向着繁荣发展的热火景象。黎明重工是矿山机械行业的领…

关于头文件中的 static inline函数

关于头文件中的 static inline函数头文件中常见static inline函数&#xff0c;于是思考有可能遇到的问题&#xff0c;如头文件经常会被包含会不会产生很多副本&#xff1f;网上说法不一。于是自己验证。经过arm-none-eabi-gcc下测试后得出结论。inline 关键字实际上仅是建议内联…

sql中问号是干什么的??

第一次在后台 程序中遇到sql语句中的问号&#xff1a; /*** * 方法描述 : 通过账号id更新该账号状态* param state 状态* param id 账号id*/ModifyingQuery("update LabAccount t set t.userState ?1 where t.userAcctId ?2")void updateState(String state, Stri…

linux下挂载windows上的共享目录,并设置所有者为非root用户

参考了很多文章&#xff0c;这里总结下我得出来的最优答案(针对我的需求而言)吧&#xff0c;但是还是存在bug&#xff0c;稍后指出&#xff01; 以下是我的bash脚本&#xff0c;防止多次重复挂载&#xff0c;相信看了就能明白&#xff1a; [zcmvm-fedora20 share]$ cat m.sh #…

vue项目登录及token验证 vue-ant

在前后端完全分离的情况下&#xff0c;Vue项目中实现token验证大致思路如下&#xff1a; 1、第一次登录的时候&#xff0c;前端调后端的登陆接口&#xff0c;发送用户名和密码 2、后端收到请求&#xff0c;验证用户名和密码&#xff0c;验证成功&#xff0c;就给前端返回一个…

广告狂人 第1季

《Mad Men/广告狂人》是由American Movie Classics公司出品的美剧。故事背景设定在上世纪六十年代的纽约&#xff0c;大胆地描述了美国广告业黄金时代残酷的商业竞争。该剧曾获得第65届、第66届、第67届美国电影电视金球奖最佳电视剧。并连续四年夺得艾美奖剧情类最佳电视剧奖。…

设置Clover默认进入Windows,按快捷键F8可选择不同的引导

系统情况&#xff1a; Win7 Mac10.9.5 Clover 我要达到的目标是&#xff1a;默认进入Windows系统&#xff0c;如果有需要&#xff0c;可以选择进入其他系统&#xff0c;如Mac OS X 我原以为可以在clover中配置&#xff0c;达到这个目标&#xff0c;可是我经过多次实践&am…

适配器和外观模式

结构型&#xff1a;Adapter与Facade&#xff08;适配器和外观模式&#xff09;   一般作为阅读材料&#xff0c;首先想要明确的是我现在了解的设计模式的初衷&#xff0c;即为了解决什么问题。 适配器&#xff0c;如果有买过港版Iphone在内地使用的人应该会有三角大插头必须接…

js获取cookie获取不到问题 vue获取cookie以及获取不到问题

1.下载依赖包 npm i js-cookie -S2.在使用cookie的页面上进行引入 import Cookies from js-cookie3.使用 创建一个在整个网站上有效的CookieCookies.set(name, value);创建一个从现在起7天后过期的cookie&#xff0c;在整个站点上有效&#xff1a;Cookies.set(name, value, …

smarty二维foreach示例[顺代一维数组],再次加强版

2019独角兽企业重金招聘Python工程师标准>>> smarty二维foreach示例[顺代一维数组],再次加强版 WEB2.0 root 2009-4-9 10:46 评论(0) 阅读(682) 大 | 中 | 小 WEB2.0 | 评论(0) | 引用(0) | 阅读(682) view plain print ? {foreach itemrec from$result…