Linux file system and device file system (1) - udev device file system

First, what is the Linux device file system

      First of all, let's not look at the definition. The definition is always too abstract and difficult to understand. Let's look at the phenomenon first. When we transplant a new file system to the development board (if various device drivers are also transplanted), start the development board, we use the serial port tool to enter the development board, and check the system /dev directory, often there is no or only There are no device files other than null, console and other necessary device files for the system. Then why don't we have the device files of various device drivers that we transplanted? If you want to use these devices, it is not necessary to manually create the device file nodes of these devices one by one, which brings great inconvenience to us in using the devices (this is the case for the transplantation of various device drivers mentioned in the previous chapters). ).

      The device file system is the key to solving this problem. It can dynamically create device file nodes of various devices in the /dev directory when the system device is initialized (that is, after the system is started, there are The device files of various devices can be used directly). In addition, it can also automatically delete the corresponding device file node under /dev after the device is unmounted (this is useful for some hot-plug devices , which are automatically created when they are plugged in, and automatically deleted when they are unplugged). Another advantage is that when we write a device driver, we don't have to specify the major device number for the device, use 0 to dynamically obtain the available major device number when the device is registered, and then create and destroy the device in the driver. file (usually implemented in the driver module loading and unloading functions).


2. About udev

       2.4 The kernel uses devfs (device file system) to create device files when the device is initialized. The device driver can specify information such as device number, owner, user space, etc. devfs runs in the kernel environment and has many disadvantages: there may be main / The auxiliary device number is not enough, the naming is inflexible, and the device name cannot be specified.

      Since the 2.6 kernel, the sysfs file system has been introduced . sysfs organizes the devices and buses connected to the system into a hierarchical file and provides it for user space access. udev runs in user mode, not in the kernel . udev's init script creates device nodes at system startup, and when new devices are inserted—add driver modules—and new data is registered on sysfs, udev innovates new device nodes .

     udev is a tool that works in user space. It can dynamically update device files according to the status of hardware devices in the system, including device file creation, deletion, permissions, etc. These files are usually defined in the /dev directory, but can also be specified in configuration files. udev must be supported by sysfs and tmpfs in the kernel. sysfs provides device entry and uevent channel for udev, and tmpfs provides storage space for udev device files .

    Note that udev achieves the purpose of customizing device files by modifying the device files generated by the kernel or adding aliases. However, udev is a user-mode program that does not change kernel behavior. That is to say, the kernel will still create device files such as sda and sdb, and udev can distinguish different devices according to the unique information of the device, and generate new device files (or links). In the user's application, just use the newly generated device file.

    

3. Comparison of udev and devfs device files

       When it comes to udev, we can't help but mention devfs. Let's take a look at the difference between udev and devfs:

1. udev can implement all the functions implemented by devfs. But udev runs in user mode, and devfs runs in the kernel .

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. We should understand that whether it is udev or mdev, they are an application , just like other applications (such as: Boa service), they can be used after configuration. For the sake of convenience, we use an mdev that comes with busybox, so when configuring and compiling busybox, as long as the mdev support option is selected, the application of the mdev device file system will be included after compilation (of course, you can also do not use busybox to automatically Bring it, go to download the source code of udev to compile and transplant.

#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 or mdev needs the support of the kernel sysfs and tmpfs virtual file system. sysfs provides device entry and uevent channel for udev, and tmpfs provides storage space for udev device files. So add the following to the /etc/fstab configuration file (in red):

# 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. Mount the sysfs file system and tmpfs file system used by mdev in the system initialization configuration file /etc/init.d/rcS , which we have seen when we introduced the root file system:



     Then start the mdev application in the /sbin directory to search for the system's devices (the red part).

# 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  " means to scan all device-like directories in /sys. If there is a file named "dev" in the directory, and the file contains the device number, mdev will use this information Create a device node file under /dev for the device;

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

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

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

[cpp]  view plain  copy
  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.     // log out of the character device  
  35.     unregister_chrdev(device_major, DEVICE_NAME);  
  36.   
  37.     //Delete the device node, note that the function name of the earlier version of the 2.6 kernel is class_device_destroy, now it should be device_destroy  
  38.     device_destroy(button_class,MKDEV(device_major,0));  
  39.   
  40.     //logout class  
  41.     class_destroy(button_class);  
  42. }  


5. As for mdev's configuration file /etc/mdev.conf, this is optional, just set some rules for device files. I don't care about him here, let him be empty.
 
6. After completing the above steps, recompile the file system, download it to the development board, start the development board and enter the /dev directory of the development board to view, there will be many system device nodes generated here, and we can use these devices directly node.

Guess you like

Origin http://43.154.161.224:23101/article/api/json?id=324673360&siteId=291194637