Linux 文件系统与设备文件系统 (一)—— udev 设备文件系统

一、什么是Linux设备文件系统

      首先我们不看定义,定义总是太抽象很难理解,我们先看现象。当我们往开发板上移植了一个新的文件系统之后(假如各种设备驱动也移植好了),启动开发板,我们用串口工具进入开发板,查看系统/dev目录,往往里面没有或者就只有null、console等几个系统必须的设备文件在这儿外,没有任何设备文件了。那我们移植好的各种设备驱动的设备文件怎么没有啊?如果要使用这些设备,那不是要一个一个的去手动的创建这些设备的设备文件节点,这给我们使用设备带来了极为的不便(在之前篇幅中讲的各种设备驱动的移植都是这样)。

      设备文件系统就是给我们解决这一问题的关键,他能够在系统设备初始化时动态的在/dev目录下创建好各种设备的设备文件节点(也就是说,系统启动后/dev目录下就有了各种设备的设备文件,直接就可使用了)。除此之外,他还可以在设备卸载后自动的删除/dev下对应的设备文件节点(这对于一些热插拔设备很有用,插上的时候自动创建,拔掉的时候又自动删除)。还有一个好处就是,在我们编写设备驱动的时候,不必再去为设备指定主设备号,在设备注册时用0来动态的获取可用的主设备号,然后在驱动中来实现创建和销毁设备文件(一般在驱动模块加载和卸载函数中来实现)。


二、关于udev

       2.4 内核使用devfs(设备文件系统)在设备初始化时创建设备文件,设备驱动程序可以指定设备号、所有者、用户空间等信息,devfs 运行在内核环境中,并有不少缺点:可能出现主/辅设备号不够,命名不灵活,不能指定设备名称等问题。

      而自2.6 内核开始,引入了sysfs 文件系统。sysfs 把连接在系统上的设备和总线组织成一个分级的文件,并提供给用户空间存取使用。udev 运行在用户模式,而非内核中udev 的初始化脚本在系统启动时创建设备节点,并且当插入新设备——加入驱动模块——在sysfs上注册新的数据后,udev会创新新的设备节点

     udev 是一个工作在用户空间的工具,它能根据系统中硬件设备的状态动态的更新设备文件,包括设备文件的创建,删除,权限等。这些文件通常都定义在/dev 目录下,但也可以在配置文件中指定。udev 必须内核中的sysfs和tmpfs支持,sysfs 为udev 提供设备入口和uevent 通道,tmpfs 为udev 设备文件提供存放空间

    注意,udev 是通过对内核产生的设备文件修改,或增加别名的方式来达到自定义设备文件的目的。但是,udev 是用户模式程序,其不会更改内核行为。也就是说,内核仍然会创建sda,sdb等设备文件,而udev可根据设备的唯一信息来区分不同的设备,并产生新的设备文件(或链接)。而在用户的应用中,只要使用新产生的设备文件即可。

    

三、udev和devfs设备文件的对比

       提到udev,不能不提的就是devfs,下面看一下udev 与 devfs 的区别:

1、udev能够实现所有devfs实现的功能。但udev运行在用户模式中,而devfs运行在内核中。

2、当一个并不存在的 /dev 节点被打开的时候, devfs一样自动加载驱动程序而udev确不能。udev设计时,是在设备被发现的时候加载模块,而不是当它被访问的时候。 devfs这个功能对于一个配置正确的计算机是多余的。系统中所有的设备都应该产生hotplug 事件、加载恰当的驱动,而 udev 将会注意到这点并且为它创建对应的设备节点。如果你不想让所有的设备驱动停留在内存之中,应该使用其它东西来 管理你的模块 (如脚本, modules.conf, 等等) 。其中devfs 用的方法导致了大量无用的 modprobe 尝试,以此程序探测设备是否存在。每个试探性探测都新建一个运行 modprobe 的进程,而几乎所有这些都是无用的

3、udev是通过对内核产生的设备名增加别名的方式来达到上述目的的。前面说过,udev是用户模式程序,不会更改内核的行为

       因此,内核依然会我行我素地产生设备名如sda,sdb等。但是,udev可以根据设备的其他信息如总线(bus),生产商(vendor)等不同来区分不同的设备,并产生设备文件。udev只要为这个设备文件取一个固定的文件名就可以解决这个问题。在后续对设备的操作中,只要引用新的设备名就可以了。但为了保证最大限度的兼容,一般来说,
新设备名总是作为一个对内核自动产生的设备名的符号链接(link)来使用的。

     例如:内核产生了sda设备名,而根据信息,这个设备对应于是我的内置硬盘,那我就可以制定udev规则,让udev除了产生/dev/sda设备文件 外,另外创建一个符号链接叫/dev/internalHD。这样,我在fstab文件中,就可以用/dev/internalHD来代替原来的 /dev/sda了。下次,由于某些原因,这个硬盘在内核中变成了sdb设备名了,那也不用着急,udev还会自动产生/dev/internalHD这 个链接,并指向正确的/dev/sdb设备。所有其他的文件像fstab等都不用修改。

    而在在2.6内核以前一直使用的是 devfs,devfs挂载于/dev目录下,提供了一种类似于文件的方法来管理位于/dev目录下的所有设备,但是devfs文件系统有一些缺点,例 如:不确定的设备映射,有时一个设备映射的设备文件可能不同,例如我的U盘可能对应sda有可能对应sdb 。


四、udev 的工作流程图

       下面先看一张流程图:


        前面提到设备文件系统udev的工作过程依赖于sysfs文件系统udev文件系统在用户空间工作,它可以根据sysfs文件系统导出的信息(设备号(dev)等),动态建立和删除设备文件

        sysfs文件系统特点:sysfs把连接在系统上的设备和总线组织成为一个分级的目录及文件,它们可以由用户空间存取,向用户空间导出内核数据结构以及它们的属性,这其中就包括设备的主次设备号

       

      那么udev 是如何建立设备文件的呢?

a -- 对于已经编入内核的驱动程序

   当被内核检测到的时候,会直接在 sysfs 中注册其对象;对于编译成模块的驱动程序,当模块载入的时候才会这样做。一旦挂载了 sysfs 文件系统(挂载到 /sys),内建的驱动程序在 sysfs 注册的数据就可以被用户空间的进程使用,并提供给 udev 以创建设备节点

    udev 初始化脚本负责在 Linux 启动的时候创建设备节点,该脚本首先将 /sbin/udevsend 注册为热插拔事件处理程序。热插拔事件本不应该在这个阶段发生,注册 udev 只是为了以防万一。

   然后 udevstart 遍历 /sys 文件系统(其属性文件dev中记录这设备的主设备号,与次设备号),并在 /dev 目录下创建符合描述的设备文件。

  例如,/sys/class/tty/vcs/dev 里含有"7:0"字符串,udevstart 就根据这个字符串创建主设备号为 7 、次设备号为 0 的 /dev/vcs 设备。udevstart 创建的每个设备的名字和权限由 /etc/udev/rules.d/ 目录下的文件指定的规则来设置。如果 udev 找不到所创建设备的权限文件,就将其权限设置为缺省的 660 ,所有者为 root:root 。


b -- 编译成模块的驱动程序

      前面我们提到了"热插拔事件处理程序"的概念,当内核检测到一个新设备连接时,内核会产生一个热插拔事件,并在 /proc/sys/kernel/hotplug 文件里查找处理设备连接的用户空间程序。udev 初始化脚本将 udevsend 注册为该处理程序。当产生热插拔事件的时候,内核让 udev 在 /sys 文件系统里检测与新设备的有关信息,并为新设备在 /dev 里创建项目

     大多数 Linux 发行版通过 /etc/modules.conf 配置文件来处理模块加载,对某个设备节点的访问导致相应的内核模块被加载。对 udev 这个方法就行不通了,因为在模块加载前,设备节点根本不存在。为了解决这个问题,在 LFS-Bootscripts 软件包里加入了 modules 启动脚本,以及 /etc/sysconfig/modules 文件。通过在 modules 文件里添加模块名,就可以在系统启动的时候加载这些模块,这样 udev 就可以检测到设备,并创建相应的设备节点了。如果插入的设备有一个驱动程序模块但是尚未加载,Hotplug 软件包就有用了,它就会响应上述的内核总线驱动热插拔事件并加载相应的模块,为其创建设备节点,这样设备就可以使用了。



五、创建和配置mdev

         mdev是udev的简化版本,是busybox中所带的程序,最适合用在嵌入式系统,而udev一般都用在PC上的Linux中,相对mdev来说要复杂些;

1、我们应该明白,不管是udev还是mdev,他们就是一个应用程序,就跟其他应用程序一样(比如:Boa服务),配置了就可以使用了。为了方便起见,我们就使用busybox自带的一个mdev,这样在配置编译busybox时,只要将mdev的支持选项选上,编译后就包含了mdev设备文件系统的应用(当然你也可以不使用busybox自带的,去下载udev的源码进行编译移植。

#cd busybox-1.13.0/
#make menuconfig

Linux System Utilities --->
    [*] mdev 
    [*]   Support /etc/mdev.conf 
    [*]     Support subdirs/symlinks 
    [*]       Support regular expressions substitutions when renaming device 
    [*]     Support command execution at device addition/removal


2、 udev或者mdev需要内核sysfs和tmpfs虚拟文件系统的支持,sysfs为udev提供设备入口和uevent通道,tmpfs为udev设备文件提供存放空间。所以在/etc/fstab配置文件中添加如下内容(红色部分):

# device  mount-point     type      options    dump    fsck order
#----------------------------------------------------------------
procfs    /proc           proc      defaults    0      0
sysfs     /sys            sysfs     defaults    0      0
tmpfs     /dev/shm        tmpfs     defaults    0      0

usbfs     /proc/bus/usb   usbfs     defaults    0      0
ramfs     /dev            ramfs     defaults    0      0
none      /dev/pts        devpts    mode=0622   0      0


3.、在系统初始化配置文件/etc/init.d/rcS中挂载mdev要用到的sysfs文件系统和tmpfs文件系统,这个在我们介绍根文件系统时已经看到:



     然后启动/sbin目录下的mdev应用对系统的设备进行搜索(红色部分)。

# Mount virtual filesystem
/bin/mount -t     proc     procfs    /proc
/bin/mount -n -t  sysfs    sysfs     /sys
/bin/mount -n -t  usbfs    usbfs     /proc/bus/usb
/bin/mount -t     ramfs    ramfs     /dev

# Make dir
/bin/mkdir -p /dev/pts
/bin/mkdir -p /dev/shm
/bin/mkdir -p /var/log
/bin/mount -n -t devpts none     /dev/pts -o mode=0622
/bin/mount -n -t tmpfs tmpfs     /dev/shm

# Make device node
echo /sbin/mdev > /proc/sys/kernel/hotplug
/sbin/mdev -s


a -- " mdev -s " 的含义是扫描 /sys 中所有的类设备目录,如果在目录中有含有名为“dev”的文件,且文件中包含的是设备号,则mdev就利用这些信息为该设备在/dev下创建设备节点文件;

b -- "echo /sbin/mdev > /proc/sys/kernel/hotplug" 的含义是当有热插拔事件产生时,内核就会调用位于 /sbin 目录的 mdev 。这时 mdev 通过环境变量中的 ACTION 和DEVPATH,来确定此次热插拔事件的动作以及影响了 /sys 中的那个目录。接着,会看这个目录中是否有“dev”的属性文件。如果有就利用这些信息为这个设备在 /dev 下创建设备节点文件。

4、在设备驱动程序中加上对类设备接口的支持,即在驱动程序加载和卸载函数中实现设备文件的创建与销毁,这个在我们前面Linux 字符设备驱动结构(二)—— 自动创建设备节点 可以看到实例,下面在介绍一个

     例如在之前篇幅的按键驱动中添加(红色部分):

[cpp] view plaincopy
在CODE上查看代码片派生到我的代码片
  1. #include <linux/device.h> //设备类用到的头文件  
  2. staticint device_major = DEVICE_MAJOR; //用于保存系统动态生成的主设备号  
  3. staticstruct class *button_class; //定义一个类  
  4.   
  5. static int __init button_init(void)  
  6. {  
  7.     //注册字符设备,这里定义DEVICE_MAJOR=0,让系统去分配,注册成功后将返回动态分配的主设备号  
  8.     device_major = register_chrdev(DEVICE_MAJOR, DEVICE_NAME,&buttons_fops);  
  9.   
  10.     if(device_major< 0)  
  11.     {  
  12.         printk(DEVICE_NAME " register faild!/n");  
  13.         return device_major;  
  14.     }  
  15.   
  16.     //注册一个设备类,使mdev可以在/dev/目录下建立设备节点  
  17.     button_class =class_create(THIS_MODULE, DEVICE_NAME);  
  18.   
  19.     if(IS_ERR(button_class))  
  20.     {  
  21.         printk(DEVICE_NAME" create class faild!/n");  
  22.         return-1;  
  23.     }  
  24.   
  25.     //创建一个设备节点,取名为DEVICE_NAME(即my2440_buttons)  
  26.     //注意2.6内核较早版本的函数名是class_device_create,现该为device_create  
  27.     device_create(button_class,NULL,MKDEV(device_major,0),NULL,DEVICE_NAME);  
  28.   
  29.     return 0;  
  30. }  
  31.   
  32. static void __exit button_exit(void)  
  33. {  
  34.     //注销字符设备  
  35.     unregister_chrdev(device_major, DEVICE_NAME);  
  36.   
  37.     //删除设备节点,注意2.6内核较早版本的函数名是class_device_destroy,现该为device_destroy  
  38.     device_destroy(button_class,MKDEV(device_major,0));  
  39.   
  40.     //注销类  
  41.     class_destroy(button_class);  
  42. }  


5、至于mdev的配置文件/etc/mdev.conf,这个可有可无,只是设定设备文件的一些规则。我这里就不管他了,让他为空好了。
 
6、完成以上步骤后,重新编译文件系统,下载到开发板上,启动开发板后进入开发板的/dev目录查看,就会有很多系统设备节点在这里产生了,我们就可以直接使用这些设备节点了。

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

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

相关文章

情人节,教大家使用css画出一朵玫瑰花。

情人节到了&#xff0c;给大家来一朵高端的玫瑰花。 在网上看到的一个canvas实现的玫瑰花&#xff0c;效果很好&#xff0c;但是代码被压缩过&#xff0c;也没有注释&#xff0c;看的云里雾里的。 今天我教大脚用CSS来实现一朵玫瑰花。 先看效果 首先我们画出一个花瓣 1、画出一…

Linux 字符设备驱动开发基础(六)—— VFS 虚拟文件系统解析

一、VFS 虚拟文件系统基础概念 Linux 允许众多不同的文件系统共存&#xff0c;并支持跨文件系统的文件操作&#xff0c;这是因为有虚拟文件系统的存在。虚拟文件系统&#xff0c;即VFS&#xff08;Virtual File System&#xff09;是 Linux 内核中的一个软件抽象层。它通过一些…

vim使用—实现程序的自动补齐(C语言)

使用过Source Insight的人一定对它的自动补全功能印象深刻&#xff0c;在很多的集成开发环境中&#xff0c;也都支持自动补全。vim做为一个出色的编辑器&#xff0c;这样的功能当然少不了。至于如何实现程序自动补全&#xff0c;网上教程很多。这里&#xff0c;我将自己配置过程…

[C#]Attribute特性(3)——AttributeUsage特性和特性标识符

相关文章 [C#]Attribute特性 [C#]Attribute特性(2)——方法的特性及特性参数 AttributeUsage特性 除了可以定制自己的特性来注释常用的C#类型外&#xff0c;您可以用AttributeUsage特性来定义您想怎样使用这些特性。AttributeUsage特性采用如下的调用惯例&#xff1a; 1 [Attri…

Linux 命令 ——less命令

less 工具也是对文件或其它输出进行分页显示的工具&#xff0c;应该说是linux正统查看文件内容的工具&#xff0c;功能极其强大。less 的用法比起 more 更加的有弹性。在 more 的时候&#xff0c;我们并没有办法向前面翻&#xff0c; 只能往后面看&#xff0c;但若使用了 less …

android闹钟实现原理

闹钟的原理可用下面我自己画的一幅图来概括&#xff1a;&#xff08;不对的地方&#xff0c;尽管吐槽&#xff09; 我们来看看新建闹钟到闹钟响铃的步骤&#xff1a; 1、新建一个闹钟&#xff1a; ? 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22…

将openstack的Token认证信息存储在memcache中

公司线上的openstack环境运行了5个多月的时间&#xff0c;keystone库的token表已经增长到了31GB&#xff0c;这个数据量还是很大的&#xff0c;对于以后的数据库备份很不方便。每次管理openstack的时候&#xff0c;都会产生一个新的token验证&#xff0c;而历史token信息其实都…

Linux 下shell编程

什么是shell?Shell是一个命令解析器&#xff0c;是介于Linux操作系统的内核(kernel)与用户之间的一个绝缘层。shell脚本就是讲各类命令预先放入其中&#xff0c;方便一次性执行的一个程序文件&#xff0c;主要用于方便管理员进行设置或者管理。 序员的角度来看&#xff0c; Sh…

linux 目录/sys 解析

今天学习Linux目录时&#xff0c;遇到/sys这个目录&#xff0c;老师怎么讲的&#xff0c;不太清楚&#xff0c;先对/sys目录知识进行一个整理 首先&#xff0c;对 /sys目录下的各个子目录进行具体说明&#xff1a; /sys下的子目录 内容 /sys/devices 该目录下…

南下事业篇——深圳 深圳(回顾)

2019独角兽企业重金招聘Python工程师标准>>> 二0一二年三月二十三号记录了下面的一篇日志&#xff0c;现在回味一下觉得自己有点惭愧&#xff0c;但不后悔&#xff0c;知道的越多就越了解自己的无知&#xff0c;工作之后渐渐磨灭了许多锐气&#xff0c;变得平滑低调…

php中花括号的使用

一、界定变量名 注&#xff1a;花括号内若左侧出现空格&#xff0c;则会当做普通花括号来解析。 二、界定表达式 1.获取字符串中某个字符 如&#xff1a;$strabcdefg; echo $str{0};//a 效果等同于$str[0]; 2.作为表示下标的方法定义数组 如&#xff1a;$arr []; $arr{10}4;…

游戏开发--开源软件8--cyclone2D(手机引擎+设计工具)

2019独角兽企业重金招聘Python工程师标准>>> Cyclone2D (飓风软件)是集成的手机游戏设计工具以及开源的引擎&#xff0c;工具提供了强大的动画、地图、数值、脚本等设计功能&#xff0c;开源引擎提供了一体化的模块加载与管理&#xff0c;并提供了详细的API文档以及…

python编码

https://www.cnblogs.com/xiao-xue-di/p/11283496.html 《Python中的Unicode编码和UTF-8编码》 《字符串和编码》 《python编码转换(unicode / utf8 / gbk / 内部编码)》 字符编码 最早127个字母被编码到计算机里&#xff0c;也就是大小写英文字母、数字和一些符号&#xff0…

Linux中vi显示中文乱码的问题

linux 下编程&#xff0c;用到的编程工具是VI&#xff0c;编辑编译都方便&#xff0c;但经常出现中文乱码问题&#xff0c;下面可完美解决这个问题 由于在windows下默认是gb编码&#xff0c;而我的vim默认是utf-8&#xff08;gedit默认也是utf-8&#xff09;&#xff0c;所以打…

WIFI vs 无线网

大家好多人都在使用无线设备上网&#xff0c;好多人对一些名词充满了好奇&#xff0c;比如WLAN和WIFI的区别是什么? WIFI无线上网和WLAN无线上网是什么意思? 这篇文章中我们为大家介绍什么是WIFI无线上网?大家可能会有这样的疑问&#xff0c;听说最多的应该是WLAN无线上网&a…

[转]jQuery Validate使用说明

本文转自&#xff1a;http://www.cnblogs.com/gimin/p/4757064.html jQuery Validate 导入 js 库 <script src"./jquery-validation/lib/jquery-1.8.3.js" type"text/javascript"></script> <script src"./jquery-validation/dist/jqu…

Linux 设备驱动开发 —— Tasklets 机制浅析

一 、Tasklets 机制基础知识点 1、Taklets 机制概念 Tasklets 机制是linux中断处理机制中的软中断延迟机制。通常用于减少中断处理的时间&#xff0c;将本应该是在中断服务程序中完成的任务转化成软中断完成。 为了最大程度的避免中断处理时间过长而导致中断丢失&#xff0c;有…

验证码(一)

需要验证码的地方还真不少&#xff0c;这主要是为了确保用户信息的安全。这里我做了一个纯字母的验证码。Random rnew Random ();string all "";private void btnCreatAuthCode_Click(object sender, EventArgs e){GetAuthCodes();}private void GetAuthCodes(){//定…

Linux 设备驱动开发 —— platform 设备驱动

一、platform总线、设备与驱动 在Linux 2.6 的设备驱动模型中&#xff0c;关心总线、设备和驱动3个实体&#xff0c;总线将设备和驱动绑定。在系统每注册一个设备的时候&#xff0c;会寻找与之匹配的驱动&#xff1b;相反的&#xff0c;在系统每注册一个驱动的时候&#xff0c;…

HTML5本地存储——IndexedDB(二:索引)

在HTML5本地存储——IndexedDB&#xff08;一&#xff1a;基本使用&#xff09;中介绍了关于IndexedDB的基本使用方法&#xff0c;很不过瘾&#xff0c;这篇我们来看看indexedDB的杀器——索引。 熟悉数据库的同学都知道索引的一个好处就是可以迅速定位数据&#xff0c;提高搜索…