zoukankan      html  css  js  c++  java
  • linux下udev和mdev的使用

    linux下设备文件系统有devfs、udev和mdev这三种。

    一、devfs

    devfs是由Linux 2.4内核引入的,引入时被许多工程师给予了高度评价,它的出现使得设备驱动程序能自主地管理自己的设备文件。

    具体来说,devfs具有如下优点:

    1、可以通过程序在设备初始化时在/dev目录下创建设备文件,卸载设备时将它删除。

    2、设备驱动程序可以指定设备名、所有者和权限位,用户空间程序仍可以修改所有者和权限位。

    3、不再需要为设备驱动程序分配主设备号以及处理次设备号。

    devfs也存在着一些缺点:

    1、不确定的设备映射。

    2、没有足够的主/辅设备号。

    3、/dev目录下文件太多。

    4、命名不够灵活。

    5、存在内核空间。

    二、udevdevfs的区别

    在Linux 2.6内核中,devfs被认为是过时的方法,并最终被抛弃了,udev取代了它。udev取代devfs的几个原因:

    1、devfs所做的工作被确信可以在用户态来完成。

    2、发现devfs有一些无法修复的bug。

    3、devfs的维护者和作者对它感到失望并且已经停止了对代码的维护工作。

    4、udev完全在用户态工作,利用设备加入或移除内核所发送的热插拔事件来工作。在热插拔时,设备的详细信息会由内核输入到位于/sys的sysfs文件系统。udev的设备名策略、权限控制和事件处理都是在用户态下完成的,它利用sysfs中的信息来进行创建设备文件节点工作。

    5、由于udev根据系统中硬件设备的状态动态更新设备文件、进行设备文件的创建和删除等,因此,在使用udev后,在/dev目录下就只包含系统中真正存在的设备了。

    6、devfs与udev的另一个显著区别在于:采用devfs,当一个并不存在的/dev节点被打开的时候,devfs能自动加载对应的驱动,而udev则不能。这是因为udev的设计者认为Linux应该在设备被发现的时候加载驱动模块,而不是当它被访问的时候。udev的设计者认为devfs所提供的打开/dev节点时自动加载驱动的功能对于一个配置正确的计算机是多余的。系统中所有的设备都应该产生热插拔事件并加载恰当的驱动,而udev能注意到这点并且为它创建对应的设备节点。

    三、udev

    udev是使用uevent机制处理热插拔问题的用户空间程序。udev是基于netlink机制的,它在系统启动时运行了一个deamon程序udevd,通过监听内核发送的uevent来执行相应的热拔插动作,包括创建/删除设备节点,加载/卸载驱动模块等等。udev使用的netlink机制在有大量uevent的场合效率高,适合用在PC机上。

    1、udev配置文件

    udev的配置文件是/etc/udev/udev.conf。内容如下:

    udev_root="/dev/"
    udev_rules="/etc/udev/rules.d"
    udev_log="err"

    udev_rules表示udev规则存储的目录,这个目录存储的是以.rules结束的文件。这些规则文件的文件名通常是两个数字开头,它表示系统应用该规则的顺序。比如:96-disk_mounts.rules、98-disk_umounts.rules。

    2、udev规则

    udev规则文件以行为单位,以“#”开头的代表注释行,其余的一行代表一个规则。规则分为匹配和赋值两部分,两部分皆有自己的关键字。

    udev键/值对操作符:

    操作符   匹配或赋值   解释
    ----------------------------------------
    ==               匹配                相等比较
    !=                匹配                不等比较
    =                 赋值                分配一个特定的值给该键,他可以覆盖之前的赋值。
    +=               赋值                追加特定的值给已经存在的键
    :=                赋值                分配一个特定的值给该键,后面的规则不可能覆盖它。

    udev规则的匹配键:

    ACTION: 事件 (uevent) 的行为,例如:add( 添加设备 )、remove( 删除设备 )。

    KERNEL: 内核设备名称,例如:sda, cdrom。

    DEVPATH:设备的 devpath 路径。

    SUBSYSTEM: 设备的子系统名称,例如:sda 的子系统为 block。

    BUS: 设备在 devpath 里的总线名称,例如:usb。

    DRIVER: 设备在 devpath 里的设备驱动名称,例如:ide-cdrom。

    ID: 设备在 devpath 里的识别号。

    SYSFS{filename}: 设备的 devpath 路径下,设备的属性文件“filename”里的内容。

    例如:SYSFS{model}==“ST936701SS”表示:如果设备的型号为 ST936701SS,则该设备匹配该 匹配键。

    在一条规则中,可以设定最多五条 SYSFS 的 匹配键。

    ENV{key}: 环境变量。在一条规则中,可以设定最多五条环境变量的 匹配键。

    PROGRAM:调用外部命令。

    RESULT: 外部命令 PROGRAM 的返回结果。例如:

    PROGRAM=="/lib/udev/scsi_id -g -s $devpath", RESULT=="35000c50000a7ef67"

    调用外部命令 /lib/udev/scsi_id查询设备的 SCSI ID,如果返回结果为 35000c50000a7ef67,则该设备匹配该 匹配键。

    udev的重要赋值键:

    NAME:在 /dev下产生的设备文件名。只有第一次对某个设备的 NAME 的赋值行为生效,之后匹配的规则再对该设备的 NAME 赋值行为将被忽略。如果没有任何规则对设备的 NAME 赋值,udev 将使用内核设备名称来产生设备文件。

    SYMLINK:为 /dev/下的设备文件产生符号链接。由于 udev 只能为某个设备产生一个设备文件,所以为了不覆盖系统默认的 udev 规则所产生的文件,推荐使用符号链接。

    OWNER, GROUP, MODE:为设备设定权限。

    ENV{key}:导入一个环境变量。

    RUN:执行设备的程序。

    udev的值和可调用的替换操作符:

    Linux用户可以随意地定制udev规则文件的值。例如:my_root_disk, my_printer。同时也可以引用下面的替换操作符:

    $kernel, %k:设备的内核设备名称,例如:sda、cdrom。

    $number, %n:设备的内核号码,例如:sda3 的内核号码是 3。

    $devpath, %p:设备的 devpath路径。

    $id, %b:设备在 devpath里的 ID 号。

    $sysfs{file}, %s{file}:设备的 sysfs里 file 的内容。其实就是设备的属性值。
    例如:$sysfs{size} 表示该设备 ( 磁盘 ) 的大小。

    $env{key}, %E{key}:一个环境变量的值。

    $major, %M:设备的 major 号。

    $minor %m:设备的 minor 号。

    $result, %c:PROGRAM 返回的结果。

    $parent, %P:父设备的设备文件名。

    $root, %r:udev_root的值,默认是 /dev/。

    $tempnode, %N:临时设备名。

    %%:符号 % 本身。

    $$:符号 $ 本身。

    3、udev示例

    96-disk_mounts.rules内容如下:

    # sdisk case a
    KERNEL=="sd?[0-9]", SUBSYSTEM=="block", ATTRS{vendor}=="Generic ", ATTRS{scsi_level}=="3" , ACTION=="add" , \
    RUN+="/usr/local/bin/sdisk_mounts.sh %k %n -k"
    KERNEL=="sd?[0-9]", SUBSYSTEM=="block", ATTRS{vendor}=="Generic ", ATTRS{scsi_level}=="0" , ACTION=="add" , \
    RUN+="/usr/local/bin/sdisk_mounts.sh %k %n -k"
    
    # sdisk case b
    KERNEL=="sd??[0-9]", SUBSYSTEM=="block", ATTRS{vendor}=="Generic ", ATTRS{scsi_level}=="3" , ACTION=="add" , \
    RUN+="/usr/local/bin/sdisk_mounts.sh %k %n -k"
    KERNEL=="sd??[0-9]", SUBSYSTEM=="block", ATTRS{vendor}=="Generic ", ATTRS{scsi_level}=="0" , ACTION=="add" , \
    RUN+="/usr/local/bin/sdisk_mounts.sh %k %n -k"
    
    # other disk case a
    KERNEL=="sd?[0-9]", SUBSYSTEM=="block", ATTRS{vendor}!="Generic ", ACTION=="add" , \
    RUN+="/usr/local/bin/confirm_disk_and_mounts.sh %k %n"
    KERNEL=="sd?[0-9]", SUBSYSTEM=="block", ATTRS{vendor}!="Generic ", ACTION=="add" , \
    RUN+="/usr/local/bin/confirm_disk_and_mounts.sh %k %n"
    
    # other disk case b
    KERNEL=="sd??[0-9]", SUBSYSTEM=="block", ATTRS{vendor}!="Generic ", ACTION=="add" , \
    RUN+="/usr/local/bin/confirm_disk_and_mounts.sh %k %n"
    KERNEL=="sd??[0-9]", SUBSYSTEM=="block", ATTRS{vendor}!="Generic ",ACTION=="add" , \
    RUN+="/usr/local/bin/confirm_disk_and_mounts.sh %k %n"

    四、mdev

    mdev是busybox自带的一个简化版的udev。mdev也是使用uevent机制处理热插拔问题的用户空间程序。mdev是基于uevent_helper机制的,它在系统启动时修改了内核中的uevnet_helper变量(通过写/proc/sys/kernel/hotplug),值为“/sbin/mdev”。这样内核产生uevent时会调用uevent_helper所指的用户级程序,也就是mdev,来执行相应的热拔插动作。mdev使用的uevent_helper机制实现简单,适合用在嵌入式系统中。

    busybox中的mdev.txt文档详细介绍了mdev的使用。示例:

    mount -t tmpfs tmpfs /dev  -o size=64k,mode=0755
    mkdir /dev/pts /dev/shm
    chmod 777 /dev/shm
    mount -t devpts devpts /dev/pts
    touch /dev/mdev.seq
    echo "/sbin/mdev" > /proc/sys/kernel/hotplug
    mdev -s

    1、mdev配置文件

    mdev的配置文件是/etc/mdev.conf。内容如下:

    console 0:0 0600 
    cpu_dma_latency 0:0 0660 
    fb0:0 44 0660 
    full 0:0 0666 
    initctl 0:0 0600 
    ircomm[0-9].* 0:20 0660 
    kmem 0:15 0640 
    kmsg 0:0 0660 
    log 0:0 0666 
    loop[0-9].* 0:6 0640 
    mem 0:15 0640 
    network_latency 0:0 0660 
    network_throughput 0:0 0660 
    null 0:0 0666 
    port 0:15 0640 
    ptmx 0:5 0666 
    ram[0-9].* 0:6 0640 
    random 0:0 0666 
    sd[a-z]* 0:6 0660
    sd[a-z]*[0-9]* 0:6 0660  */etc/mdev/automountusbstorage.sh
    tty 0:5 0666 
    tty.* 0:0 0620 
    urandom 0:0 0666 
    sda* 0:6 0660
    sd[a-z][0-9] 0:6 0660 */etc/mdev/automountusb.sh
    vcs.* 0:5 0660 
    zero 0:0 0666 
    
    hwrng 10:183 0660 =hw_random
    pcm.* 0:0 0660 =snd/ 
    control.* 0:0 0660 =snd/ 
    timer 0:0 0660 =snd/ 
    
    event.* 0:0 0660 =input/ @/etc/mdev/find-touchscreen.sh
    mice 0:0 0660 =input/ 
    mouse.* 0:0 0660 =input/
    
    tun[0-9]* 0:0 0660 =net/
    
    mmcblk[0-9]*        0:6     660 */etc/mdev/autoformat.sh 
    mmcblk[0-9]*p[0-9]* 0:6     660 */etc/mdev/automountsdcard.sh

    2、mdev规则

    格式如下:

    <device regex> <uid>:<gid> <octal permissions> [<@$*><cmd>]
        @ 创建节点后执行的
        $ 删除节点前执行的
        * 创建后和删除前都运行的

    3、mdev示例

    automountusb.sh内容如下:

    #!/bin/sh
    
    usb_mount="/media/usb"
    if [ -d $usb_mount ]
    then
        echo "$usb_mount exist!"
    else
        mkdir -p $usb_mount
    fi
    
    umount_usb()
    {
        grep -qs "^/dev/$1" /proc/mounts
        [ $? -eq 0 ] && umount $usb_mount
    }
    
    mount_usb()
    {
        if [ `fsck.ext4 -a /dev/$1` -a `fsck.fat -a /dev/$1` ]
        then
            echo "Error: Unsupported FS!!!"
            exit 1
        fi
        mount -t auto "/dev/$1" "$usb_mount"
        [ $? -ne 0 ] && echo "mount /dev/$1 fail!" && exit 1
    }
    
    case "${ACTION}" in
        add|"")
            umount_usb ${MDEV}
            mount_usb ${MDEV}
            ;;
        remove)
            umount_usb ${MDEV}
            ;;
    esac

     

     

    参考资料:

    https://blog.csdn.net/qq_31505483/article/details/52866037

    https://www.cnblogs.com/linhaostudy/archive/2018/07/08/9279041.html

    https://www.cnblogs.com/fah936861121/p/6496608.html

  • 相关阅读:
    mac c++编译出现segmentation fault :11错误
    ssh 连接缓慢解决方法
    237. Delete Node in a Linked List
    203. Remove Linked List Elements
    Inversion of Control Containers and the Dependency Injection pattern
    82. Remove Duplicates from Sorted List II
    83. Remove Duplicates from Sorted List
    SxsTrace
    使用CCleaner卸载chrome
    decimal and double ToString problem
  • 原文地址:https://www.cnblogs.com/wmate/p/13518444.html
Copyright © 2011-2022 走看看