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