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
參考資料:
https://blog.csdn.net/qq_31505483/article/details/52866037
https://www.cnblogs.com/linhaostudy/archive/2018/07/08/9279041.html