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