当前位置:   article > 正文

udev设备文件系统_udevadm info

udevadm info


前言

好文:
http://www.wowotech.net/sort/device_model
参考:
https://www.cnblogs.com/fah936861121/p/6496608.html
https://blog.csdn.net/hugerat/article/details/3437099
https://www.binss.me/blog/sysfs-udev-and-Linux-Unified-Device-Model/


设备文件系统有devfs,mdev,udev这三种

udev

1.简介

1.什么是udev
udev 以守护进程的形式运行,通过侦听内核发出来的 uevent 来管理 /dev目录下的设备文件。设备管理器,提供设备事件,(如Windows的设备管理器一样,插入设备,触发设备事件,如果我们了解udev,就可以利用设备事件来做一些事情,可以写脚本,由udev触发。)

如何理解udev是守护进程呢?即系统内核启动后init进程(比如busybox的init程序、sysinit、Upstart或systemd)根据runlevel运行等级进入某种模式,然后解析开启哪些服务进程。其中udev就是哪些服务进程中的一个,服务进程是在后台运行的。可以通过命令ps-aux来获取,比如在ubuntu终端中ps -aux | grep udev:

root 328 0.0 0.0 52220 852 ? Ss 2月23 0:00 /lib/systemd/systemd-udevd --daemon

所以只要有设备插入或删除,守护进程udev就会管理它。
也就是说使用了udev,所有的设备都能在/dev/目录下找到对应的设备文件。

2.使用udev的好处
动态管理:当设备添加 / 删除时,udev 的守护进程侦听来自内核的 uevent,以此添加或者删除 /dev下的设备文件,所以 udev 只为已经连接的设备产生设备文件,而不会在 /dev下产生大量虚无的设备文件。

自定义命名规则:通过 Linux 默认的规则文件,udev 在 /dev/ 里为所有的设备定义了内核设备名称,比如 /dev/sda、/dev/hda、/dev/fd等等。由于 udev 是在用户空间 (user space) 运行,Linux 用户可以通过自定义的规则文件,灵活地产生标识性强的设备文件名,比如 /dev/boot_disk、/dev/root_disk、/dev/color_printer等等。

设定设备的权限和所有者 / 组:udev 可以按一定的条件来设置设备文件的权限和设备文件所有者 / 组

3.udev工作流程
在这里插入图片描述

2.配置和使用udev

1.udev的配置文件
/etc/udev/udev.conf

# udev.conf 
 # The main config file for udev 
 # 
 # This file can be used to override some of udev's default values 
 # for where it looks for files, and where it places device nodes. 
 # 
 # WARNING: changing any value, can cause serious system breakage! 
 # 

 # udev_root - where in the filesystem to place the device nodes 
 udev_root="/dev/"

 # udev_db - The name and location of the udev database. 
 udev_db="/dev/.udev.tdb"

 # udev_rules - The name and location of the udev rules file 
 udev_rules="/etc/udev/rules.d/"

 # udev_permissions - The name and location of the udev permission file 
 udev_permissions="/etc/udev/permissions.d/"

 # default_mode - set the default mode for all nodes that have no 
 #                explicit match in the permissions file 
 default_mode="0600"

 # default_owner - set the default owner for all nodes that have no 
 #                 explicit match in the permissions file 
 default_owner="root"

 # default_group - set the default group for all nodes that have no 
 #                 explicit match in the permissions file 
 default_group="root"

 # udev_log - set to "yes" if you want logging, else "no"
 udev_log="no"
  • 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

Linux 用户可以通过该文件设置以下参数:

udev_root:udev 产生的设备所存放的目录,默认值是 /dev/。建议不要修改该参数,因为很多应用程序默认会从该目录调用设备文件。
udev_db:udev 信息存放的数据库或者所在目录,默认值是 /dev/.udev.tdb。
udev_rules:udev 规则文件的名字或者所在目录,默认值是 /etc/udev/rules.d/或/lib/udev/rules.d。
udev_permissions:udev 权限文件的名字或者所在目录,默认值是 /etc/udev/permissions.d/。
default_mode/ default_owner/ default_group:如果设备文件的权限没有在权限文件里指定,就使用该参数作为默认权限,默认值分别是:0600/root/root。
udev_log:是否需要 syslog记录 udev 日志的开关,默认值是 no。syslog记录日志的级别,默认值是 err。如果改为 info 或者 debug 的话,会有冗长的 udev 日志被记录下来。

其实,在我们的终端上,udev配置文件没有那么复杂,因为大部分都是默认值,所以不用配置

2.udev的规则和规则文件
规则文件是 udev 里最重要的部分,默认是存放在 /etc/udev/rules.d/下。所有的规则文件必须以“.rules”为后缀名。

规则文件里的规则有一系列的键/值对组成,键/值对之间用逗号(,)分割。每一个键或者是用户匹配键,或者是一个赋值键。匹配键确定规则是否被应用,而赋 值键表示分配某值给该键。这些值将影响udev创建的设备文件。赋值键可以处理一个多值列表。匹配键和赋值键操作符解释见下表:

(1)udev 键/值对操作符

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

(2)udev 规则的匹配键

含义
ACTION一个时间活动的名字,比如add,当设备增加的时候
KERNEL在内核里看到的设备名字,比如sd*表示任意SCSI磁盘设备
DEVPATH内核设备录进,比如/devices/*
SUBSYSTEM子系统名字,比如sound,net
BUS总线的名字,比如IDE,USB
DRIVER设备驱动的名字,比如ide-cdrom
ID独立于内核名字的设备名字
SYSFS{ value}sysfs属性值,他可以表示任意
ENV{ key}环境变量,可以表示任意
PROGRAM可执行的外部程序,如果程序返回0值,该键则认为为真(true)
RESULT上一个PROGRAM调用返回的标准输出。
NAME根据这个规则创建的设备文件的文件名。注意:仅仅第一行的NAME描述是有效的,后面的均忽略。 如果你想使用使用两个以上的名字来访问一个设备的话,可以考虑SYMLINK键。
SYMLINK根据规则创建的字符连接名
OWNER设备文件的属组
GROUP设备文件所在的组。
MODE设备文件的权限,采用8进制
RUN为设备而执行的程序列表
LABEL在配置文件里为内部控制而采用的名字标签(下下面的GOTO服务)
GOTO跳到匹配的规则(通过LABEL来标识),有点类似程序语言中的GOTO
IMPORT{ type}导入一个文件或者一个程序执行后而生成的规则集到当前文件
WAIT_FOR_SYSFS等待一个特定的设备文件的创建。主要是用作时序和依赖问题。
PTIONS特定的选项: last_rule 对这类设备终端规则执行; ignore_device 忽略当前规则; ignore_remove 忽略接下来的并移走请求。all_partitions 为所有的磁盘分区创建设备文件。

(3)udev 的重要赋值键

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

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

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

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

(4)udev 的值和可调用的替换操作符

在键值对中的键和操作符都介绍完了,最后是值 (value)。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规则

1.udev规则举例
我们只需添加自己想要的规则,新建规则文件,比如当U盘插入时,我要自动挂载它(或者其他什么动作),其实安装了udev,当U盘插入时,它有相应的.rules规则文件去解析它(即udev会动态管理它),在/dev/目录下产生相应的设备文件,比如/dev/sda4.但现在我需要在U盘插入时,我自动挂载它(比如挂载到/mnt/udisk/目录下),那么我就可以编写自己的udev规则文件automount.rules。该文件如下:

# There are a number of modifiers that are allowed to be used in some
# of the different fields. They provide the following subsitutions:
#
# %n the "kernel number" of the device.
#    For example, 'sda3' has a "kernel number" of '3'
# %e the smallest number for that name which does not matches an existing node
# %k the kernel name for the device
# %M the kernel major number for the device
# %m the kernel minor number for the device
# %b the bus id for the device
# %c the string returned by the PROGRAM
# %s{filename} the content of a sysfs attribute
# %% the '%' char itself
#

# Media automounting
SUBSYSTEM=="block", ACTION=="add"    RUN+="/etc/udev/rules.d/mount.sh"
SUBSYSTEM=="block", ACTION=="remove" RUN+="/etc/udev/rules.d/mount.sh"
SUBSYSTEM=="block", ACTION=="change", ENV{DISK_MEDIA_CHANGE}=="1" RUN+="/etc/udev/rules.d/mount.sh"
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19

说明:当有U盘热插拔时都会去跑/etc/udev/rules.d/mount.sh脚本。其中SUBSYSTEM==“block”,U盘sda的子系统就是block。

mount.sh如下:

MOUNT="/bin/mount"
PMOUNT="/usr/bin/pmount"
UMOUNT="/bin/umount"
for line in `grep -v ^# /etc/udev/mount.blacklist`
do
    name="`basename "$DEVNAME"`"
    if [ ` expr match "$DEVNAME" "$line" ` -gt 0 ] || [ ` expr match "$name" "$line" ` -gt 0 ]
    then
        logger "udev/mount.sh" "[$DEVNAME] is blacklisted, ignoring"
        exit 0
    fi
done

automount() {    
    name="`basename "$DEVNAME"`"

    if [[ $name =~ sd ]];then
        mount_dir=/mnt/udisk
        ! test -d $mount_dir && mkdir -p $mount_dir
    elif [[ $name =~ mmcblk ]];then
        mount_dir=/mnt/sdisk
        ! test -d $mount_dir && mkdir -p $mount_dir
    fi
    
    # Silent util-linux's version of mounting auto
    if [ "x`readlink $MOUNT`" = "x/bin/mount.util-linux" ] ;
    then
        MOUNT="$MOUNT -o silent"
    fi
    
    # If filesystem type is vfat, change the ownership group to 'disk', and
    # grant it with  w/r/x permissions.
    case $ID_FS_TYPE in
    vfat|fat)
        MOUNT="$MOUNT -o umask=007,gid=`awk -F':' '/^disk/{print $3}' /etc/group`"
        ;;
    # TODO
    *)
        ;;
    esac

    if ! $MOUNT -t auto -o iocharset=cp936 $DEVNAME $mount_dir
    then
        logger "mount.sh/automount" "$MOUNT -t auto $DEVNAME $mount_dir failed!"
        rm_dir "/run/media/$name"
    else
        logger "mount.sh/automount" "Auto-mount of [ $mount_dir] successful"
        touch "/tmp/.automount-$name"
        killall -USR1 adas.exe
    fi
}
    
rm_dir() {
    # We do not want to rm -r populated directories
    if test "`find "$1" | wc -l | tr -d " "`" -lt 2 -a -d "$1"
    then
        ! test -z "$1" && rm -r "$1"
        killall -USR1 adas.exe
    else
        logger "mount.sh/automount" "Not removing non-empty directory [$1]"
    fi
}

# No ID_FS_TYPE for cdrom device, yet it should be mounted
name="`basename "$DEVNAME"`"
[ -e /sys/block/$name/device/media ] && media_type=`cat /sys/block/$name/device/media`

if [ "$ACTION" = "add" ] && [ -n "$DEVNAME" ] && [ -n "$ID_FS_TYPE" -o "$media_type" = "cdrom" ]; then
    if [ -x "$PMOUNT" ]; then
        $PMOUNT $DEVNAME 2> /dev/null
    elif [ -x $MOUNT ]; then
            $MOUNT $DEVNAME 2> /dev/null
    fi
    
    # If the device isn't mounted at this point, it isn't
    # configured in fstab (note the root filesystem can show up as
    # /dev/root in /proc/mounts, so check the device number too)
    if expr $MAJOR "*" 256 + $MINOR != `stat -c %d /`; then
        grep -q "^$DEVNAME " /proc/mounts || automount
    fi
fi


if [ "$ACTION" = "remove" ] || [ "$ACTION" = "change" ] && [ -x "$UMOUNT" ] && [ -n "$DEVNAME" ]; then
    for mnt in `cat /proc/mounts | grep "$DEVNAME" | cut -f 2 -d " " `
    do
        $UMOUNT $mnt
    done
    
    # Remove empty directories from auto-mounter
    name="`basename "$DEVNAME"`"
    if [[ $name =~ sd ]];then
        mount_dir=/mnt/udisk
    elif [[ $name =~ mmcblk ]];then
        mount_dir=/mnt/sdisk
    fi
    test -e "/tmp/.automount-$name" && rm_dir $mount_dir
fi
  • 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
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47
  • 48
  • 49
  • 50
  • 51
  • 52
  • 53
  • 54
  • 55
  • 56
  • 57
  • 58
  • 59
  • 60
  • 61
  • 62
  • 63
  • 64
  • 65
  • 66
  • 67
  • 68
  • 69
  • 70
  • 71
  • 72
  • 73
  • 74
  • 75
  • 76
  • 77
  • 78
  • 79
  • 80
  • 81
  • 82
  • 83
  • 84
  • 85
  • 86
  • 87
  • 88
  • 89
  • 90
  • 91
  • 92
  • 93
  • 94
  • 95
  • 96
  • 97
  • 98

2.如何编写规则文件?

其实就是两点:匹配键和赋值键,只需完善这两点就可以编写我们想要的规则文件

比如:KERNEL==“tty”, NAME="%k", GROUP=“tty”, MODE=“0666”, OPTIONS=“last_rule”

该规则说明:如果有一个设备的内核设备名称为tty(KERNEL==“tty”),那么设置新的权限为0600(MODE=“0666”),所在的组是tty(GROUP=“tty”)。它也设置了一个特别的设备文件名:%K。在这里例子里,%k代表设备的内核名字。那也就意味着内核识别出这些设备是什么名字,就创建什么样的设备文件名。

在这里就是要完善两点,匹配键KERNEL==“tty”;赋值键NAME="%k", GROUP=“tty”, MODE=“0666”, OPTIONS=“last_rule”

其实关键是要如何找到设备的属性呢,即拿什么匹配,规则所需要的信息如何获取?

可以利用udev的命令:比如udevadm info -a -p $(udevadm info -q path -n /dev/sda4). 其中udevadm info -q path -n /dev/sda4返回sysfs中的设备路径;
我们echo $(udevadm info -q path -n /dev/sda4)可以得到一串路径:
/devices/pci0000:00/0000:00:10.0/host2/target2:0:0/2:0:0:0/block/sda/sda2,其实是在
/sys/devices/pci0000:00/0000:00:10.0/host2/target2:0:0/2:0:0:0/block/sda/sda2
这个文件夹就是设备管理文件,也就是存储着所有此设备的属性,我们通过udevadm info 打印他,其本质就是遍历此文件夹下的内容,取出设备的属性:
udevadm info -a -p $(设备路径),这将查询这个设备路径,把结果信息输出来,如下:

Udevadm info starts with the device specified by the devpath and then
walks up the chain of parent devices. It prints for every device
found, all possible attributes in the udev rules key format.
A rule to match, can be composed by the attributes of the device
and the attributes from one single parent device.

  looking at device '/devices/pci0000:00/0000:00:14.0/usb1/1-8/1-8:1.0/host18/target18:0:0/18:0:0:0/block/sdb/sdb4':
    KERNEL=="sdb4"
    SUBSYSTEM=="block"
    DRIVER==""
    ATTR{ro}=="0"
    ATTR{size}=="15177600"
    ATTR{stat}=="     202      382     1562      212        0        0        0        0        0      164      212"
    ATTR{partition}=="4"
    ATTR{start}=="14880"
    ATTR{discard_alignment}=="0"
    ATTR{alignment_offset}=="0"
    ATTR{inflight}=="       0        0"

  looking at parent device '/devices/pci0000:00/0000:00:14.0/usb1/1-8/1-8:1.0/host18/target18:0:0/18:0:0:0/block/sdb':
    KERNELS=="sdb"
    SUBSYSTEMS=="block"
    DRIVERS==""
    ATTRS{ro}=="0"
    ATTRS{size}=="15204352"
    ATTRS{stat}=="     295      382     2306     1208        0        0        0        0        0     1156     1204"
    ATTRS{range}=="16"
    ATTRS{discard_alignment}=="0"
    ATTRS{events}=="media_change"
    ATTRS{ext_range}=="256"
    ATTRS{events_poll_msecs}=="2000"
    ATTRS{alignment_offset}=="0"
    ATTRS{inflight}=="       0        0"
    ATTRS{removable}=="1"
    ATTRS{capability}=="51"
    ATTRS{events_async}==""

  looking at parent device '/devices/pci0000:00/0000:00:14.0/usb1/1-8/1-8:1.0/host18/target18:0:0/18:0:0:0':
    KERNELS=="18:0:0:0"
    SUBSYSTEMS=="scsi"
    DRIVERS=="sd"
    ATTRS{rev}=="1.00"
    ATTRS{type}=="0"
    ATTRS{scsi_level}=="3"
    ATTRS{model}=="                "
    ATTRS{state}=="running"
    ATTRS{queue_type}=="none"
    ATTRS{iodone_cnt}=="0x152"
    ATTRS{iorequest_cnt}=="0x152"
    ATTRS{device_busy}=="0"
    ATTRS{evt_capacity_change_reported}=="0"
    ATTRS{timeout}=="30"
    ATTRS{evt_media_change}=="0"
    ATTRS{max_sectors}=="240"
    ATTRS{ioerr_cnt}=="0x1"
    ATTRS{queue_depth}=="1"
    ATTRS{vendor}=="        "
    ATTRS{evt_soft_threshold_reached}=="0"
    ATTRS{device_blocked}=="0"
    ATTRS{evt_mode_parameter_change_reported}=="0"
    ATTRS{evt_lun_change_reported}=="0"
    ATTRS{evt_inquiry_change_reported}=="0"
    ATTRS{iocounterbits}=="32"
    ATTRS{eh_timeout}=="10"

  looking at parent device '/devices/pci0000:00/0000:00:14.0/usb1/1-8/1-8:1.0/host18/target18:0:0':
    KERNELS=="target18:0:0"
    SUBSYSTEMS=="scsi"
    DRIVERS==""

  looking at parent device '/devices/pci0000:00/0000:00:14.0/usb1/1-8/1-8:1.0/host18':
    KERNELS=="host18"
    SUBSYSTEMS=="scsi"
    DRIVERS==""

  looking at parent device '/devices/pci0000:00/0000:00:14.0/usb1/1-8/1-8:1.0':
    KERNELS=="1-8:1.0"
    SUBSYSTEMS=="usb"
    DRIVERS=="usb-storage"
    ATTRS{bInterfaceClass}=="08"
    ATTRS{bInterfaceSubClass}=="06"
    ATTRS{bInterfaceProtocol}=="50"
    ATTRS{bNumEndpoints}=="02"
    ATTRS{supports_autosuspend}=="1"
    ATTRS{bAlternateSetting}==" 0"
    ATTRS{bInterfaceNumber}=="00"

  looking at parent device '/devices/pci0000:00/0000:00:14.0/usb1/1-8':
    KERNELS=="1-8"
    SUBSYSTEMS=="usb"
    DRIVERS=="usb"
    ATTRS{bDeviceSubClass}=="00"
    ATTRS{bDeviceProtocol}=="00"
    ATTRS{devpath}=="8"
    ATTRS{idVendor}=="1516"
    ATTRS{speed}=="480"
    ATTRS{bNumInterfaces}==" 1"
    ATTRS{bConfigurationValue}=="1"
    ATTRS{bMaxPacketSize0}=="64"
    ATTRS{busnum}=="1"
    ATTRS{devnum}=="17"
    ATTRS{configuration}==""
    ATTRS{bMaxPower}=="500mA"
    ATTRS{authorized}=="1"
    ATTRS{bmAttributes}=="80"
    ATTRS{bNumConfigurations}=="1"
    ATTRS{maxchild}=="0"
    ATTRS{bcdDevice}=="0100"
    ATTRS{avoid_reset_quirk}=="0"
    ATTRS{quirks}=="0x0"
    ATTRS{version}==" 2.00"
    ATTRS{urbnum}=="1001"
    ATTRS{ltm_capable}=="no"
    ATTRS{manufacturer}=="SKYMEDI"
    ATTRS{removable}=="removable"
    ATTRS{idProduct}=="1226"
    ATTRS{bDeviceClass}=="00"
    ATTRS{product}=="USB Drive"

  looking at parent device '/devices/pci0000:00/0000:00:14.0/usb1':
    KERNELS=="usb1"
    SUBSYSTEMS=="usb"
    DRIVERS=="usb"
    ATTRS{bDeviceSubClass}=="00"
    ATTRS{bDeviceProtocol}=="01"
    ATTRS{devpath}=="0"
    ATTRS{idVendor}=="1d6b"
    ATTRS{speed}=="480"
    ATTRS{bNumInterfaces}==" 1"
    ATTRS{bConfigurationValue}=="1"
    ATTRS{bMaxPacketSize0}=="64"
    ATTRS{authorized_default}=="1"
    ATTRS{busnum}=="1"
    ATTRS{devnum}=="1"
    ATTRS{configuration}==""
    ATTRS{bMaxPower}=="0mA"
    ATTRS{authorized}=="1"
    ATTRS{bmAttributes}=="e0"
    ATTRS{bNumConfigurations}=="1"
    ATTRS{maxchild}=="15"
    ATTRS{bcdDevice}=="0402"
    ATTRS{avoid_reset_quirk}=="0"
    ATTRS{quirks}=="0x0"
    ATTRS{serial}=="0000:00:14.0"
    ATTRS{version}==" 2.00"
    ATTRS{urbnum}=="348"
    ATTRS{ltm_capable}=="no"
    ATTRS{manufacturer}=="Linux 4.2.0-42-generic xhci-hcd"
    ATTRS{removable}=="unknown"
    ATTRS{idProduct}=="0002"
    ATTRS{bDeviceClass}=="09"
    ATTRS{product}=="xHCI Host Controller"

  looking at parent device '/devices/pci0000:00/0000:00:14.0':
    KERNELS=="0000:00:14.0"
    SUBSYSTEMS=="pci"
    DRIVERS=="xhci_hcd"
    ATTRS{irq}=="27"
    ATTRS{subsystem_vendor}=="0x1028"
    ATTRS{broken_parity_status}=="0"
    ATTRS{class}=="0x0c0330"
    ATTRS{driver_override}=="(null)"
    ATTRS{consistent_dma_mask_bits}=="64"
    ATTRS{dma_mask_bits}=="64"
    ATTRS{local_cpus}=="f"
    ATTRS{device}=="0x8c31"
    ATTRS{enable}=="1"
    ATTRS{msi_bus}=="1"
    ATTRS{local_cpulist}=="0-3"
    ATTRS{vendor}=="0x8086"
    ATTRS{subsystem_device}=="0x05a5"
    ATTRS{numa_node}=="-1"
    ATTRS{d3cold_allowed}=="1"

  looking at parent device '/devices/pci0000:00':
    KERNELS=="pci0000:00"
    SUBSYSTEMS==""
    DRIVERS==""
  • 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
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47
  • 48
  • 49
  • 50
  • 51
  • 52
  • 53
  • 54
  • 55
  • 56
  • 57
  • 58
  • 59
  • 60
  • 61
  • 62
  • 63
  • 64
  • 65
  • 66
  • 67
  • 68
  • 69
  • 70
  • 71
  • 72
  • 73
  • 74
  • 75
  • 76
  • 77
  • 78
  • 79
  • 80
  • 81
  • 82
  • 83
  • 84
  • 85
  • 86
  • 87
  • 88
  • 89
  • 90
  • 91
  • 92
  • 93
  • 94
  • 95
  • 96
  • 97
  • 98
  • 99
  • 100
  • 101
  • 102
  • 103
  • 104
  • 105
  • 106
  • 107
  • 108
  • 109
  • 110
  • 111
  • 112
  • 113
  • 114
  • 115
  • 116
  • 117
  • 118
  • 119
  • 120
  • 121
  • 122
  • 123
  • 124
  • 125
  • 126
  • 127
  • 128
  • 129
  • 130
  • 131
  • 132
  • 133
  • 134
  • 135
  • 136
  • 137
  • 138
  • 139
  • 140
  • 141
  • 142
  • 143
  • 144
  • 145
  • 146
  • 147
  • 148
  • 149
  • 150
  • 151
  • 152
  • 153
  • 154
  • 155
  • 156
  • 157
  • 158
  • 159
  • 160
  • 161
  • 162
  • 163
  • 164
  • 165
  • 166
  • 167
  • 168
  • 169
  • 170
  • 171
  • 172
  • 173
  • 174
  • 175
  • 176
  • 177
  • 178

从中可以得到KERNEL,SUBSYSTEM等信息,这样就可以利用这些属性值去匹配。其实我们可以从那里看到“looking at parent device”是一层往一层打印出该设备的信息。

这样我们就可以KERNEL==“sdb4”, SUBSYSTEM=="block"去匹配,比如写udev规则如下:

KERNEL==“sdb4”, SUBSYSTEM==“block”, RUN+="/etc/udev/rules.d/mount.sh"

ATTR:
ATTR{value}  sysfs设备属性值,可以为任意值,用于匹配

ENV:
ENV{ key}  环境变量,可以表示任意
用于赋值和匹配都可以
例子如下:
先赋值一个ENV,然后再用它来匹配

赋值一个ENV:

KERNEL==“sda4”, ENV{test_value}=“value”, SYMLINK+=“udisk4”

这样就赋值了一个ENV{test_value}为value,那么可以在别的设备匹配时引用那个ENV进行匹配

匹配ENV:

SUBSYSTEM==“block”, ENV{test_value}==“value”, NAME=“hda”
匹配ENV{test_value},并且匹配成功,所以会进行命名

若SUBSYSTEM==“block”, ENV{test_value}==“test”, NAME=“hda”
匹配ENV{test_value},但匹配失败,所以上面这条规则不执行

4.udev主要使用

1.重命名设备节点的缺省名字为其他名字
此时使用NAME赋值键,例子如下:

一个硬盘,它的设备属性KERNEL是hdb,在/dev/目录下是/dev/hdb,那么我们可以给他重命名为

KERNEL==“hdb”, NAME=“my_spare_disk”

执行以下命令:ls /dev/my_spare_disk -l

/dev/my_spare_disk —> /dev/hdb产生一个符号链接指向/dev/hdb

注意:仅仅第一行的NAME描述是有效的,后面的均忽略。即udev按顺序解析udev规则文件时,第一个NAME赋值键的名字有用,假如后面对同一个设备还有NAME赋值键,那么那个赋值的名称将被忽略。如果你想使用使用两个以上的名字来访问一个设备的话,可以考虑SYMLINK键。

如果你想你命名的名字得到实现,你必须把你的规则文件命名顺序在前面。

2.通过创建符号链接到缺省设备节点来提供一个可选的固定的设备节点名字

例子如下:

KERNEL==“hdb”, DRIVER==“ide-disk”, SYMLINK+=“sparedisk”

规则意思是:匹配一个内核命名为hdb以及驱动为ide-disk的设备,命名设备节点为缺省名字并创建一个指向它的sparedisk符号链接,设备节点出现在/dev/sparedisk

注意:符号链接可以是多个,这些符号链接都指向/dev/hdb

3.基于程序的输出命名设备节点

某些情况下你可能要求比udev标准规则提供的更多弹性, 这种情况下你可以请求udev运行一个程序并运用程序的标准输出来提供设备命名.

要使用这个功能,你只需简单的在PROGRAM赋值中指定要运行程序(以及任何阐述)的完整路径, 然后在NAME/SYMLINK赋值中使用一些%c替换.

例子如下:

引用一个位于/bin/device_namer的虚构程序. device_namer带一个表示内核名字的命令行参数, 基于内核名device_namer做一些变化然后输出

KERNEL==“hda”, PROGRAM="/bin/device_namer %k", SYMLINK+="%c"

规则意思是:匹配一个内核命名为hdb的设备,然后运行一个/bin/device_name程序,这个程序需要带一个表示内核名字的命令行参数即%k。然后这个程序运行的结果(即输出)把它赋值给SYMLINK,这样就可以满足要求(使用外部程序来命名设备)

4.改变设备节点的权限和所有权

udev允许你在规则中使用另外的赋值来控制每个设备的所有权和权限属性.

例子如下:

KERNEL==“fb[0-9]*”, NAME=“fb/%n”, SYMLINK+="%k", GROUP=“video”, MODE=“0666”

规则意思是:匹配一个内核命名为fb[0-9]的设备,然后给它命名为fb/%n,符号链接为%k, 属于video组, 权限为0666

比如有一个fb3设备,匹配成功后那么久有一个名为fb/3,符号链接为fb3,属组为video,权限为0666

5.在设备节点被创建或删除时(通常是添加设备或拔出设备时)执行一个脚本

特别针对热插拔的设备,目的是为了在设备连接或者断开时运行一个特定程序. 例如, 你可能想在你的数码相机连到系统时执行一个脚本来自动下载相机里面的所有照片.

例子如下:

KERNEL==“sdb”, ACTION==“add”, RUN+="/usr/bin/my_program"

规则意思是:匹配一个内核名为sdb的设备,当插入时,执行程序/usr/bin/my_program

6.重命名网络接口

在规则中简单的匹配网卡MAC地址是有意义的,因为它们是唯一的.

udevadm info -a -p /sys/class/net/eth0
looking at class device '/sys/class/net/eth0':
KERNEL=="eth0"
ATTR{address}=="00:52:8b:d5:04:48"
  • 1
  • 2
  • 3
  • 4

规则如下:

KERNEL=="eth*", ATTR{address}=="00:52:8b:d5:04:48", NAME="lan"
  • 1

这样就重命名了eth*为lan

mdev

mdev是busybox上的udev的简略版它的作用,就是在系统启动和热插拔或动态加载驱动程序时,自动产生驱动程序所需的节点文件。在以busybox为基础构建嵌入式linux的根文件系统时,使用它是最优的选择。

1.mdev使用

mdev的使用在busybox中的mdev.txt文档已经将得很详细了。

(1)在编译时加上对mdev的支持(我是使用的是busybox1.10.1):
Linux System Utilities —>

mdev
Support /etc/mdev.conf
Support command execution at device addition/removal

(2)在启动时加上使用mdev的命令:
我在自己创建的根文件系统(nfs)中的/linuxrc文件中添加了如下指令:
#挂载/sys为sysfs文件系统
echo “----------mount /sys as sysfs”
/bin/mount -t tmpfs mdev /dev
/bin/mount -t sysfs sysfs /sys
echo “----------Starting mdev…”
/bin/echo /sbin/mdev > /proc/sys/kernel/hotplug
mdev -s
注意:是/bin/echo /sbin/mdev > /proc/sys/kernel/hotplug,
并非/bin/echo /bin/mdev > /proc/sys/kernel/hotplug。

busybox的文档有错!!

(3)在你的驱动中加上对类设备接口的支持:
在驱动程序的初始化函数中,使用下述的类似语句,就能在类设备目录下添加包含设备号的名为“dev”的属性文件。并通过mdev

在/dev目录下产生gpio_dev0的设备节点文件。

  my_class = class_create(THIS_MODULE, "gpio_class");
  if(IS_ERR(my_class)) {undefined
    printk("Err: failed in creating class./n");
    return -1;
  }
  /* register your own device in sysfs, and this will cause mdev to create corresponding device node */
  class_device_create(my_class, MKDEV(gpio_major_number, 0), NULL, "gpio_dev%d" ,0);
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7

在驱动程序的清除程序段,加入以下语句,以完成清除工作。

  class_device_destroy(my_class, MKDEV(gpio_major_number, 0));
  class_destroy(my_class);
  • 1
  • 2

需要的头文件是linux/device.h,因此程序的开始应加入下句
#include <linux/device.h>
另外,my_class是class类型的结构体指针,要在程序开始时声明成全局变量。
struct class *my_class;
上述程序中的gpio_major_number是设备的主节点号。可以换成需要的节点号。gpio_dev是最终生成的设备节点文件的名子。%d是用于以相同设备自动编号的。gpio_class是建立的class的名称,当驱动程序加载后,可以在/sys/class的目录下看到它。
上述语句也不一定要在初始化和清除阶段使用,可以根据需要在其它地方使用。

(4)至于/etc/mdev.conf文件,可有可无,不影响使用,只是添加了些功能。

2.mdev的原理

要想真正用好mdev,适当知道一下原理是必不可少的。现在简单介绍一下mdev的原理:

执行mdev -s
:以‘-s’为参数调用位于/sbin目录写的mdev(其实是个链接,作用是传递参数给/bin目录下的busybox程序并调用它),mdev扫描 /sys/class 和/sys/block中所有的类设备目录,如果在目录中含有名为“dev”的文件,且文件中包含的是设备号,则mdev就利用这些信息为这个设备在/dev下创建设备节点文件。一般只在启动时才执行一次 “mdev -s”。

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

最后,附上我在工作中编写的一段简单的gpio控制驱动程序。此程序没有什么功能,主要是做一些测试用的。有兴趣的朋友可以用

它测试一下上述的mdev的使用方法。我用的是友善公司的mini2440开发板。

#include <linux/config.h>
#include <linux/module.h>
#include <linux/moduleparam.h>
#include <linux/init.h>

#include <linux/kernel.h>       /* printk() */
#include <linux/fs.h>           /* everything... */
#include <linux/cdev.h>
#include <linux/interrupt.h>    /* request_irq() */
#include <asm/arch/regs-gpio.h>
#include <asm/arch/regs-irq.h>
#include <asm/io.h>
#include <asm/uaccess.h>        /* copy_to_user() */
#include <linux/delay.h>        /* mdelay() */
#include <linux/device.h>       /*class_create()*/
#include <asm/arch-s3c2410/regs-gpio.h>
#include <asm/arch-s3c2410/regs-timer.h>


#define VERSION_STRING  "gpio driver for JM_Xcontrol"

#define DEVICE_NAME "JM_Xcontrol_gpio"

/* Use 0xE0 as magic number */
#define XRAY_IOC_MAGIC  0xE0

#define XRAY_IOCLCDBACKLIGHT    _IO(XRAY_IOC_MAGIC, 0)
#define XRAY_IOC485REC    _IO(XRAY_IOC_MAGIC, 1)
#define XRAY_IOC485TRC    _IO(XRAY_IOC_MAGIC, 2)
#define XRAY_IOCBUZZER    _IO(XRAY_IOC_MAGIC, 3)
#define XRAY_IOC_MAXNR 12

MODULE_AUTHOR("hugerat");
MODULE_LICENSE("Dual BSD/GPL");
MODULE_DESCRIPTION(VERSION_STRING);

unsigned int gpio_major_number=0;
struct cdev gpio_dev;

struct class *my_class;

static int gpio_ioctl(struct inode *inode, struct file *file, unsigned int cmd, unsigned long arg)
{undefined
  int err=0;
  unsigned long tmp;
  //-------以下检查命令---------//

  if (_IOC_TYPE(cmd) != XRAY_IOC_MAGIC) return -ENOTTY;
  if (_IOC_NR(cmd) > XRAY_IOC_MAXNR) return -ENOTTY;

  if (_IOC_DIR(cmd) & _IOC_READ)
    err = !access_ok(VERIFY_WRITE, (void __user *)arg, _IOC_SIZE(cmd));
  else if (_IOC_DIR(cmd) & _IOC_WRITE)
    err =  !access_ok(VERIFY_READ, (void __user *)arg, _IOC_SIZE(cmd));
  if (err)
    return -EFAULT;
  //--------------------------//
  switch ( cmd )
  {undefined
    case XRAY_IOCLCDBACKLIGHT: //控制LCD背光开关
      if(arg==0)
      {undefined
        s3c2410_gpio_setpin(S3C2410_GPB1, 1);
      }
      else
      {undefined
        s3c2410_gpio_setpin(S3C2410_GPB1, 0);
      }
      break;
    case XRAY_IOC485REC:
      if(arg==0)
      {undefined
        s3c2410_gpio_setpin(S3C2410_GPG10, 1);
      }
      else
      {undefined
        s3c2410_gpio_setpin(S3C2410_GPG10, 0);
      }
      break;
    case XRAY_IOC485TRC:
      if(arg==0)
      {undefined
        s3c2410_gpio_setpin(S3C2410_GPG12, 0);
      }
      else
      {undefined
        s3c2410_gpio_setpin(S3C2410_GPG12, 1);
      }
      break;
    case XRAY_IOCBUZZER:
      if(arg==0)
      {undefined
        s3c2410_gpio_setpin(S3C2410_GPB0, 0);
      }
      else
      {undefined
        s3c2410_gpio_setpin(S3C2410_GPB0, 1);
      }
      break;
    default:
      break;
  }
  return 0;
}

static struct file_operations gpio_fops = {undefined
  .owner   = THIS_MODULE,
  //.open    = xray_open,
  //.release = xray_release,
  //.read    = xray_read,
  //.write   = xray_write,
  .ioctl   = gpio_ioctl,
  //.fasync  = xray_fasync,
};

static int __init gpio_init(void)
{undefined
  int ret,devno;
  dev_t dev;
  unsigned long tmp;
  ret = alloc_chrdev_region(&dev,0,1,DEVICE_NAME);
  gpio_major_number = MAJOR(dev);
  printk(KERN_INFO "Initial jm_xcontrol_gpio driver!/n");
  if (ret<0) {undefined
    printk(KERN_WARNING "gpio:can't get major number %d/n",gpio_major_number);
    return ret;
  }

  devno = MKDEV(gpio_major_number,0);
  cdev_init(&gpio_dev,&gpio_fops);
  gpio_dev.owner = THIS_MODULE;
  gpio_dev.ops   = &gpio_fops;

  ret = cdev_add(&gpio_dev,devno,1);
  if (ret) {undefined
    unregister_chrdev_region(dev,1);
    printk(KERN_NOTICE "Error %d adding gpio device/n",ret);
    return ret;
  }
  my_class = class_create(THIS_MODULE, "gpio_class");
  if(IS_ERR(my_class)) {undefined
    printk("Err: failed in creating class./n");
    return -1;
  }
  /* register your own device in sysfs, and this will cause mdev to create corresponding device node */
  class_device_create(my_class, MKDEV(gpio_major_number, 0), NULL, "gpio_dev%d" ,0);
 
  //LCD背光
  s3c2410_gpio_cfgpin(S3C2410_GPB1, S3C2410_GPB1_OUTP);
  s3c2410_gpio_setpin(S3C2410_GPB1, 0);
  //蜂鸣器
  s3c2410_gpio_cfgpin(S3C2410_GPB0, S3C2410_GPB0_OUTP);
  s3c2410_gpio_setpin(S3C2410_GPB0, 0);
 
  //485收发控制
  s3c2410_gpio_cfgpin(S3C2410_GPG10, S3C2410_GPG10_OUTP); //收
  s3c2410_gpio_setpin(S3C2410_GPG10, 0);
  s3c2410_gpio_cfgpin(S3C2410_GPG12, S3C2410_GPG12_OUTP);   //发
  s3c2410_gpio_setpin(S3C2410_GPG12, 0);
  return 0;
}

static void __exit gpio_cleanup(void)
{undefined
  unsigned long tmp;
  dev_t dev=MKDEV(gpio_major_number,0);
  cdev_del(&gpio_dev);
  class_device_destroy(my_class, MKDEV(gpio_major_number, 0));
  class_destroy(my_class);
  unregister_chrdev_region(dev,1);
  s3c2410_gpio_setpin(S3C2410_GPB1, 1); //关背光
  s3c2410_gpio_setpin(S3C2410_GPB0, 0); //关蜂鸣器
 
  s3c2410_gpio_setpin(S3C2410_GPG10, 1); //关485收
  s3c2410_gpio_setpin(S3C2410_GPG12, 0); //关485发
  printk(KERN_INFO "unregistered the %s/n",DEVICE_NAME);
}

module_init(gpio_init);
module_exit(gpio_cleanup);                          
  • 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
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47
  • 48
  • 49
  • 50
  • 51
  • 52
  • 53
  • 54
  • 55
  • 56
  • 57
  • 58
  • 59
  • 60
  • 61
  • 62
  • 63
  • 64
  • 65
  • 66
  • 67
  • 68
  • 69
  • 70
  • 71
  • 72
  • 73
  • 74
  • 75
  • 76
  • 77
  • 78
  • 79
  • 80
  • 81
  • 82
  • 83
  • 84
  • 85
  • 86
  • 87
  • 88
  • 89
  • 90
  • 91
  • 92
  • 93
  • 94
  • 95
  • 96
  • 97
  • 98
  • 99
  • 100
  • 101
  • 102
  • 103
  • 104
  • 105
  • 106
  • 107
  • 108
  • 109
  • 110
  • 111
  • 112
  • 113
  • 114
  • 115
  • 116
  • 117
  • 118
  • 119
  • 120
  • 121
  • 122
  • 123
  • 124
  • 125
  • 126
  • 127
  • 128
  • 129
  • 130
  • 131
  • 132
  • 133
  • 134
  • 135
  • 136
  • 137
  • 138
  • 139
  • 140
  • 141
  • 142
  • 143
  • 144
  • 145
  • 146
  • 147
  • 148
  • 149
  • 150
  • 151
  • 152
  • 153
  • 154
  • 155
  • 156
  • 157
  • 158
  • 159
  • 160
  • 161
  • 162
  • 163
  • 164
  • 165
  • 166
  • 167
  • 168
  • 169
  • 170
  • 171
  • 172
  • 173
  • 174
  • 175
  • 176
  • 177
  • 178
  • 179
  • 180

sysfs

1. sysfs 诞生之前
一切皆文件,这是 Linux 的哲学之一。设备当然也不例外,它们往往被抽象成文件,存放在 /dev 目录下供用户进程进行操作。用户通过这些设备文件,可以实现对硬件进行相应的操作。而这些设备文件,需要由对应的设备文件系统来负责管理。
在 kernel 2.6 之前,完成这一使命的是 devfs。devfs 是 Linux 2.4 引入的一个虚拟的文件系统,挂载在 /dev 目录下。可以动态地为设备在 /dev 下创建或删除相应的设备文件,只生成存在设备的节点。
然而它存在以下缺点:

可分配的设备号数目 (major / minor) 受到限制
设备映射不确定,一个设备所对应的设备文件可能发生改变
设备名称在内核或模块中写死,违反了内核开发的原则
缺乏热插拔机制
随着 kernel 的发展,从 Linux 2.6 起,devfs 被 sysfs + udev 所取代。sysfs + udev 在设计哲学和现实中的易用性都比 devfs 更优,自此 sysfs + udev 的组合走上 mainline ,直至目前,依然作为 Linux 的设备管理手段。

2. sysfs
sysfs 是一个基于内存的虚拟的文件系统,由 kernel 提供,挂载到 /sys 目录下(用 mount 查看得到 sysfs on /sys type sysfs (rw,nosuid,nodev,noexec,relatime)),或者findmnt 命令查,负责以设备树的形式向 user space 提供直观的设备和驱动信息。

sysfs 以不同的视角展示当前系统接入的设备:

/sys/block 历史遗留问题,存放块设备,提供以设备名 (如 sda) 到 / sys/devices 的符号链接

/sys/bus(对应kernel中的 struct bus_type) 按总线类型分类,在某个总线目录之下可以找到连接该总线的设备的符号链接,指向 / sys/devices。某个总线目录之下的 drivers 目录包含了该总线所需的所有驱动的符号链接。

/sys/class(对应kernel中的struct class) 按设备功能分类,如输入设备在 /sys/class/input 之下,图形设备在 /sys/class/graphics 之下,是指向 /sys/devices 目录下对应设备的符号链接。

/sys/dev(对应kernel中的struct device_driver)按设备驱动程序分层(字符设备/块设备),提供以 major:minor 为名到/sys/devices 的符号链接。

/sys/devices(对应kernel中的struct device) 包含所有被发现的注册在各种总线上的各种物理设备。
所有的物理设备都按其在总线上的拓扑结构来显示,除了 platform devices 和 system devices:

platform devices 一般是挂在芯片内部高速或者低速总线上的各种控制器和外设,能被 CPU 直接寻址。
system devices 不是外设,他是芯片内部的核心结构,比如 CPU,timer 等,他们一般没有相关的 driver,但是会有一些体系结构相关的代码来配置他们。
/sys/firmware 提供对固件的查询和操作接口(关于固件有专用于固件加载的一套API)。

/sys/fs 描述当前加载的文件系统,提供文件系统和文件系统已挂载设备信息。

/sys/hypervisor 如果开启了 Xen,这个目录下会提供相关属性文件。

/sys/kernel 提供 kernel 所有可调整参数,但大多数可调整参数依然存放在 sysctl(/proc/sys/kernel)。

/sys/module 所有加载模块 (包括内联、编译进 kernel、外部的模块) 的信息,按模块类型分类。

/sys/power 电源选项,可用于控制整个机器的电源状态,如写入控制命令进行关机、重启等。

sysfs 支持多视角查看,通过符号链接,同样的信息可以出现在多个目录下。

以硬盘 sda 为例,既可以在块设备目录/sys/block/下找到,又可以在所有设备目录/sys/devices/pci0000:00/0000:00:10.0/host32/target32:0:0/ 下找到。

查看 sda1 设备目录下的内容:

$ ll /sys/block/sda/
drwxr-xr-x 11 root root    0 Feb  3 04:32 ./
drwxr-xr-x  3 root root    0 Feb  3 04:32 ../
-r--r--r--  1 root root 4096 Feb  3 04:32 alignment_offset
lrwxrwxrwx  1 root root    0 Feb  3 04:32 bdi -> ../../../../../../../virtual/bdi/8:0/
-r--r--r--  1 root root 4096 Feb  3 04:32 capability
-r--r--r--  1 root root 4096 Feb  3 04:32 dev
lrwxrwxrwx  1 root root    0 Feb  3 04:32 device -> ../../../2:0:0:0/
-r--r--r--  1 root root 4096 Feb  3 04:32 discard_alignment
-r--r--r--  1 root root 4096 Feb  3 04:32 events
-r--r--r--  1 root root 4096 Feb  3 04:32 events_async
-rw-r--r--  1 root root 4096 Feb  3 04:32 events_poll_msecs
-r--r--r--  1 root root 4096 Feb  3 04:32 ext_range
drwxr-xr-x  2 root root    0 Feb  3 04:32 holders/
-r--r--r--  1 root root 4096 Feb  3 04:32 inflight
drwxr-xr-x  2 root root    0 Feb  3 04:32 integrity/
drwxr-xr-x  2 root root    0 Feb  3 04:32 power/
drwxr-xr-x  3 root root    0 Feb  3 04:32 queue/
-r--r--r--  1 root root 4096 Feb  3 04:32 range
-r--r--r--  1 root root 4096 Feb  3 04:32 removable
-r--r--r--  1 root root 4096 Feb  3 04:32 ro
drwxr-xr-x  5 root root    0 Feb  3 04:32 sda1/
drwxr-xr-x  5 root root    0 Feb  3 04:32 sda2/
drwxr-xr-x  5 root root    0 Feb  3 04:32 sda5/
-r--r--r--  1 root root 4096 Feb  3 04:32 size
drwxr-xr-x  2 root root    0 Feb  3 04:32 slaves/
-r--r--r--  1 root root 4096 Feb  3 04:32 stat
lrwxrwxrwx  1 root root    0 Feb  3 04:32 subsystem -> ../../../../../../../../class/block/
drwxr-xr-x  2 root root    0 Feb  3 04:32 trace/
-rw-r--r--  1 root root 4096 Feb  3 04:32 uevent
  • 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

未更新完,后续看第三篇参考文章(开头给了链接)

声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/weixin_40725706/article/detail/888750
推荐阅读
相关标签
  

闽ICP备14008679号