linux下udev和mdev的使用
linux下設備文件系統有devfs、udev和mdev這三種。
一、devfs
devfs是由Linux 2.4內核引入的,引入時被許多工程師給予了高度評價,它的出現使得設備驅動程式能自主地管理自己的設備文件。
具體來說,devfs具有如下優點:
1、可以通過程式在設備初始化時在/dev目錄下創建設備文件,卸載設備時將它刪除。
2、設備驅動程式可以指定設備名、所有者和許可權位,用戶空間程式仍可以修改所有者和許可權位。
3、不再需要為設備驅動程式分配主設備號以及處理次設備號。
devfs也存在著一些缺點:
1、不確定的設備映射。
2、沒有足夠的主/輔設備號。
3、/dev目錄下文件太多。
4、命名不夠靈活。
5、存在內核空間。
二、udev與devfs的區別
在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
參考資料:
//blog.csdn.net/qq_31505483/article/details/52866037
//www.cnblogs.com/linhaostudy/archive/2018/07/08/9279041.html
//www.cnblogs.com/fah936861121/p/6496608.html