linux mdev -s没有运行,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 -s

Alternatively, without procfs the above becomes:

[1] mount -t sysfs sysfs /sys

[2] sysctl -w kernel.hotplug=/sbin/mdev

[3] mdev -s

Of 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、在/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_ADD

const char *action_string = kobject_actions[action];    // action_string = "add"

……

//把相关信息存到环境变量里,ACTION代表操作类型,DEVPATH为设备在class下存在的路径,SUBSYSTEM为class_create创建的设备类

//ACTION=add , DEVPATH=/class/test/test_dev , SUBSYSTEM=test

retval = 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);

下面看看uevent_helper是谁

定义如下:

char uevent_helper[UEVENT_HELPER_PATH_LEN] = CONFIG_UEVENT_HELPER_PATH;

去.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

看到没,刚开始确实是/sbin/hotplug,但后来就变成了/sbin/mdev。很据上面信息,我们知道是在文件系统启动的过程中

发生改变的。文件系统启动过程中,改变mdev的只有“echo /sbin/mdev > /proc/sys/kernel/hotplug”,也确实是这个

导致了uevent_helper的改变。

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

#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

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

这里不讨论。

其实设置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 的动作是创建设备节点,所以为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的驱动内容,这里不讲

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

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

相关文章

linux x86-64下,Linux x86_64下安装Flash Player 9

家里 Linux 安装已经有几天了&#xff0c;可是用 Firefox 浏览网页总是看不到 Flash。到了 Adobe 官方去下载了 Flash 插件&#xff0c;结果安装的时候说它不支持 x86_64&#xff0c;安装计划就一直搁浅。天天上网看见“缺失插件”的框框&#xff0c;非常不爽&#xff0c;所以就…

window连接树莓派linux桌面,远程连接Raspberry Pi(树莓派)图形用户界面(X Window)

背景&#xff1a;有的时候&#xff0c;我们希望能远程连接一台linux的图形界面用来管理机器,这里需要用到tightvncserver和xtightvncviewer两个工具我的树莓派的ip是10.141.247.134 另一台机器为作client去链接树莓派的ip为10.141.247.121. 先在树莓派的机器上安装tightvncs…

linux小红帽系统能用微信,小红帽腾讯QQ微信登录版-小红帽腾讯版v1.0.3 安卓版-腾牛安卓网...

小红帽腾讯版是一款专为广大喜爱玩童话类手游的玩家打造的欧美风游戏&#xff0c;这款游戏有着最为精致的游戏画面&#xff0c;黑色风格的童话故事&#xff0c;带领玩家领略不一样的童年世界&#xff0c;给您带来最佳的游戏体验&#xff01;小红帽腾讯版简介《小红帽》是一款改…

在linux实现公平队列,多级反馈队列调度策略在Linux中的应用和实现.pdf

多级反馈队列调度策略在Linux中的应用和实现.pdf第30卷第20期 计算机工程 2004年10月I&#xff0f;01&#xff0e;30^矗2口 ComputerEngineering October2004文t标识码tA 中强分娄号I TP311&#xff0e;52软件技术与数据库 文章-号tlooo-3428(2004)20—&#xff0e;008l—_03多…

c语言第五章作业,《C语言程序设计》第五章作业.doc

《C语言程序设计》第五章作业窗体顶端《C语言程序设计》第5章作业布置日期&#xff1a;2012-3-15?????截止日期&#xff1a;2012-3-22一、单选题 (每小题6分&#xff0c;共102分)?1、以下说法中正确的是&#xff3f;&#xff3f;&#xff3f;&#xff3f;。????A、C语…

i7 5500u linux,i7 5500u相当于什么cpu

大家好&#xff0c;我是时间财富网智能客服时间君&#xff0c;上述问题将由我为大家进行解答。i7 5500u相当酷睿i5CPU&#xff0c;I7 5500U是酷睿笔记本专用CPU&#xff0c;是双核四线程的一款处理器&#xff0c;严格来说不算第五代的I7&#xff0c;而是全新一代的I7型号。酷睿…

c语言字符串用for语句去重,C# 实现字符串去重

方法一 注&#xff1a;需要.net 3.5框架的支持string s "101,102,103,104,105,101,102,103,104,105,106,107,101,108";s string.Join(",", s.Split(,).Distinct().ToArray());方法二class Program{static void Main(string[] args){string result"&…

c语言利用遍历求树高的程序,用C语言实现二叉树的遍历极其应用

用C语言实现二叉树的遍历极其应用[1]〔摘要〕&#xff1a;《数据结构》是计算机系学生的一门专业技术基础课程&#xff0c;计算机科学各领域及有关的应用软件都要用到各种数据结构。C语言有较丰富的数据类型、运算符以及函数&#xff0c;能直接与内存打交道&#xff0c;使修改、…

c语言编程出彩色告白,C语言告白代码,一闪一闪亮晶晶~

该楼层疑似违规已被系统折叠 隐藏此楼查看此楼#include #include #include #define I 20#define R 340int main(){int i,j,e;int a;for(i1,aI;ifor(j(int) ( I-sqrt(I*I-(a-i)*(a-i)) );j>0;j--)printf(" ");for(e1;e<2*sqrt(I*I-(a-i)*(a-i));e)printf("…

计算机二级c语言2021年重点内容,2021年5月计算机二级C语言试题(总)

一个考生的快乐&#xff0c;不是因为他备考的时间多&#xff0c;而是因为他的选择对。选择考无忧题库&#xff0c;做二级C语言试题&#xff0c;助你备考轻松&#xff01;二级C语言试题【1】1.若有以下数组说明&#xff0c;则i10;a[a[i]]元素数值是(C)。int a[12]{1,4,7,10,2,5,…

c语言case key pres,C#程序设计B-中国大学mooc-题库零氪

第2讲 C#语言基础2.1 数据类型、变量与常量 —— 语言中的单词随堂测验1、(加号)可以表示A、算术的加法B、正号C、字符串的连接D、事件的注册()2、int是引用类型3、string是引用类型4、double在内存中占8个字节5、int占2个字节6、Person p1 new Person(18); //Person是引用类型…

c语言递归求差分方程,如何使这个简单的递推关系(差分方程)尾递归?

bytebuster的解决方案很好&#xff0c;但他没有解释他是如何创建它的&#xff0c;所以它只会帮助解决这个特定的问题。顺便说一句&#xff0c;你的公式看起来有点像斐波纳契(但不完全)&#xff0c;它可以是calculated analytically without any looping(即使没有循环隐藏在Seq.…

android text 字体设置,Android TextView个别字体格式设置小结

android 在同一个TextView中如何展现出不同的字体和颜色总结一下1.主要是痛通过String.xml使用html标签静态配置然后动态引用Html.fromHtml(getResources().getString(R.string.myHeadStr));2.textView 动态设置//创建一个 SpannableString对象 msp new SpannableString("…

android 图片合成pdf文件,教你怎么把多张图片合成一个pdf文件

当你遇到需要把多张图片合并成一个pdf文件时&#xff0c;你需要怎么做?可能有些朋友会说下载一个pdf格式转换工具&#xff0c;其实不必这么麻烦&#xff0c;你只要把文件上传到在线迅捷pdf转换器&#xff0c;就可以一站式帮你搞定pdf文件的格式转换以及一些常用的功能操作(如p…

android中的xml布局文件如何引用另一个xml布局文件,引用另一个layout.xml文件而不复制它...

如果我理解正确提问者对XLARGE和SW-600dp的一个布局文件&#xff0c;另一个用于所有的休息。无论如何&#xff0c;当我偶然发现这个问题时&#xff0c;就是这样。可以通过创建文件夹layout-xlarge和layout-s600dp来解决这个问题&#xff0c;并在每个文件夹中放置一个布局文件&a…

华为系统鸿蒙优势,华为鸿蒙2.0可以替代安卓吗,华为鸿蒙2.0优势在哪

在华为开发者大会上&#xff0c;华为消费业务CEO 余承东&#xff0c;正式发布鸿蒙OS2.0&#xff0c;并宣布华为鸿蒙OS将全面启用全场景生态&#xff0c;并将于2020年12月发布手机版。余承东还表示&#xff0c;明年&#xff0c;华为的智能手机将全面升级&#xff0c;以支持鸿蒙操…

网页自动关机代码HTML,win10系统打开邮件显示网页html源代码如何解决

有不少win10系统用户在打开邮件的时候&#xff0c;发现内容全是显示网页的html源代码&#xff0c;无法看到内容&#xff0c;遇到这样的问题该怎么办呢&#xff0c;通常是自带的"邮件和日历"应用暂时不支持查看HTML格式的邮件&#xff0c;下面给大家分享一下具体的解决…

android 界面长按,Android 主界面长按创建快捷方式

Android中创建快捷方式主要有两种方式。一是在代码中直接加入生成桌面快捷方式的代码&#xff1b;二是通过小部件加入;这篇文章主要讲另外一种方法&#xff01;1、通过在AndroidManifest文件里为Activity加入加入之后。长按桌面&#xff0c;小部件中会有你应用的图标出现&#…

android+fastboot+命令,Android手机fastboot刷机命令

先进入fastboot文件所在目录连接硬件命令fastboot devices删除recover、boot,system同理Fastboot erase recovery重刷&#xff0c;boot,system同理Fastboot flash recovery cn170.img只需将boot.img和system.img刷入系统即可完成系统的刷新恶补:FASTBOOT命令有加载驱动 | fastb…

retrofit 2.0 android 教程,初识Retrofit2.0

Retrofit无疑是当下最流行的Android网络请求框架了&#xff0c;是Square提供的开源产品。官方网站是这样介绍Retrofit的—-A type-safe HTTP client for Android and Java&#xff0c;为Android平台的应用提供一个类型安全的HTTP客户端。Retrofit 是一套注解形式的网络请求封装…