Udev相關的文章很多,本文的主要目的不是提供一個完整的教學文檔,對其使用,只是給出網上現有的主要資源。著重分析其基本工作原理以及在使用中遇到的一些README文檔沒有明確說明的問題。
1?????????基本概念
udev文件系統是針對2.6內核,提供一個基于用戶空間的動態設備節點管理和命名的解決方案,網上關于為什么要使用udev文件系統,udev文件系統和devfs文件系統的比較,等等的文章已經很多了,如果你想了解這方面的內容,請直接搜索相關的關鍵字。
udev的官方網址:http://www.kernel.org/pub/linux/utils/kernel/hotplug/udev.html
src code的下載地址:http://www.us.kernel.org/pub/linux/utils/kernel/hotplug/
此外,關于udev的rules規則的撰寫,網上也有很多文章,如果要獲得最準確的版本,可以在src code的代碼樹里找到writing_udev_rules的幫助文檔,這個文檔其實沒有逐條介紹rules的所有關鍵字,可以結合man udev 和 udev自帶的一些rules文件來理解如何撰寫你所需要的規則文件。
2?????????安裝和啟動
2.1????????安裝
Udev的代碼樹里的版本很多,我下載的最新的版本是udev-117,配合2.6.21版本的內核能夠正常使用。網上很多文章介紹的可能都是稍微早期一些的版本,有些步驟包括udev的README文檔似乎描述的不是很準確。
基本上這個版本的udev需要注意的是,安裝時只需要udevd,udevadm兩個文件,其它必需的包括udevtrigger等只是udevadm的一個符號鏈接。udevstart不是必需的。當然Udev.conf等配置文件還是一樣。
2.2????????啟動
你可以在啟動腳本中用udevd –d 參數啟動udev文件系統的守護進程,然后使用udevtrigger將buildin的設備驅動的節點創建出來,以后模塊插入移除時節點的管理會自動處理。
能夠正常加載udev的前提,基本包括如下操作:
????????設置路徑變量
????????加載sysfs文件系統
????????加載一個基于ram的可寫的/dev目錄(其實,只要提供一個可寫的目錄即可,目錄路徑本身也是可以配置的)
????????/dev目錄下需要有已經創建好的 console節點和null節點
腳本類似:
# Set the path
PATH=/bin:/sbin:/usr/bin:/usr/sbin
export PATH
# mount proc and devpts filesystem
/bin/mount -a
mknod /dev/console c 5 1
mknod /dev/null c 1 3
/sbin/udevd -d
/sbin/udevtrigger
Mount使用的fstab文件類似:
none??????????????????? /tmp??????????????????? ramfs?? defaults??????? 0 0
udev??????????????????? /dev??????????????????? ramfs?? defaults??????? 0 0
none??????????????????? /proc?????????????????? proc??? defaults??????? 0 0
sysfs?????????????????? /sys??????????????????? sysfs?? defaults??????? 0 0
當然,你的系統上可能還會需要預先創建一些其它的設備節點,比如串口的ttySx 才能正常啟動shell,完成以上腳本的執行,那就要看具體情況了。
3?????????使用中的一些問題的思考
3.1????????關于規則的多次匹配
幫助文檔中說一個設備可以被多條規則多次匹配,不過,需要明確的一點是:
多次匹配只能添加多個Symlink,不能創建多個Name:
例如:
KERNEL=="mtdblock4", NAME+="mtdbb4"
KERNEL=="mtdblock4", NAME+="%k"
就只會創建 /dev/mtdbb4 而不會創建/dev/mtdblock4
而類似:
KERNEL=="mtdblock4", NAME+="mtdbb4"
KERNEL=="mtdblock4", SYMLINK+="mtdbb4link"
是可以正常工作的。
3.2????????關于udev.conf的語法
可能大家會發現,似乎沒有什么詳細文檔描述udev.conf的寫法,實際上從udevd的代碼里可以看出:
udev.conf文件里面只會解析這三個參數:
udev_root 定義udev的目錄路徑
udev_rules 定義udev的規則文件的目錄路徑
udev_log 定義log的級別
也許以后會添加一些別的配置參數?
4?????????基本工作原理方面的問題
這部分主要是分析了一下udev的source code,對一些自己關心的問題的理解
4.1????????Udevd如何獲取內核的這些模塊動態變化的信息
設備節點的創建,是通過sysfs接口分析dev文件取得設備節點號,這個很顯而易見。那么udevd是通過什么機制來得知內核里模塊的變化情況,如何得知設備的插入移除情況呢?當然是通過hotplug機制了,那hotplug又是怎么實現的?或者說內核是如何通知用戶空間一個事件的發生的呢?
答案是通過netlink socket通訊,在內核和用戶空間之間傳遞信息。
內核調用kobject_uevent函數發送netlink message給用戶空間,這部分工作通常不需要驅動去自己處理,在統一設備模型里面,在子系統這一層面,已經將這部分代碼處理好了,包括在設備對應的特定的Kobject創建和移除的時候都會發送相應add和remove消息,當然前提是你在內核中配置了hotplug的支持。
Netlink socket作為一種內核與用戶空間的通信方式,不僅僅用在hotplug機制中,同樣還應用在其它很多真正和網絡相關的內核子系統中。
Udevd通過標準的socket機制,創建socket連接來獲取內核廣播的uevent事件 并解析這些uevent事件。
4.2????????Udevd如何監控規則文件的變更
如果內核版本足夠新的話,在規則文件發生變化的時候,udev也能夠自動的重新應用這些規則,這得益于內核的inotify機制, inotify是一種文件系統的變化通知機制,如文件增加、刪除等事件可以立刻讓用戶態得知。
在udevd中,對inotify和udev的netlink socket文件描述符都進行了select的等待操作。有事件發生以后再進一步處理。
4.3????????Udevtrigger的工作機制?
運行udevd以后,使用udevtrigger的時候,會把內核中已經存在的設備的節點創建出來,那么他是怎么做到這一點的? 分析udevtrigger的代碼可以看出:
udevtrigger通過向/sysfs 文件系統下現有設備的uevent節點寫"add"字符串,從而觸發uevent事件,使得udevd能夠接收到這些事件,并創建buildin的設備驅動的設備節點以及所有已經insmod的模塊的設備節點。
所以,我們也可以手工用命令行來模擬這一過程:
/ # echo "add" > /sys/block/mtdblock2/uevent
/ #
/ # UEVENT[178.415520] add????? /block/mtdblock2 (block)
但是,進一步看代碼,你會發現,實際上,不管你往uevent里面寫什么,都會觸發add事件,這個從kernel內部對uevent屬性的實現函數可以看出來,默認的實現是:
static ssize_t store_uevent(struct device *dev, struct device_attribute *attr,
const char *buf, size_t count)
{
kobject_uevent(&dev->kobj, KOBJ_ADD);
return count;
}
所以不管寫的內容是什么,都是觸發add操作,真遺憾,我還想通過這個屬性實驗remove的操作。 不知道這樣限制的原因是什么。
而udevstart的實現方式和udevtrigger就不同了,它基本上是重復實現了udevd里面的機制,通過遍歷sysfs,自己完成設備節點的創建,不通過udevd來完成。
4.4????????其它
????????udevd創建每一個節點的時候,都會fork出一個新的進程來單獨完成這個節點的創建工作。
????????Uevent_seqnum 用來標識當前的uevent事件的序號(已經產生了多少uevent事件),你可以通過如下操作來查看:
$ cat /sys/kernel/uevent_seqnum
2673
?
評論
查看更多