茫茫網海中的冷日
         
茫茫網海中的冷日
發生過的事,不可能遺忘,只是想不起來而已!
 恭喜您是本站第 1671408 位訪客!  登入  | 註冊
主選單

Google 自訂搜尋

Goole 廣告

隨機相片
Miku_00006.jpg

授權條款

使用者登入
使用者名稱:

密碼:


忘了密碼?

現在就註冊!

小企鵝開談 : [分享]Linux kernel 2.6 udev(CentOS 6.2)

發表者 討論內容
冷日
(冷日)
Webmaster
  • 註冊日: 2008/2/19
  • 來自:
  • 發表數: 15771
[分享]Linux kernel 2.6 udev(CentOS 6.2)
udev 维基百科,自由的百科

udev 開發者 Greg Kroah-Hartman and Kay Sievers
穩定版本 141
作業系統 Linux kernel
類型 device node
網站 kernel.org/pub/linux/utils/kernel/hotplug/udev.html

udev 是Linux kernel 2.6系列的設備管理器。它主要的功能是管理/dev目錄底下的設備節點。它同時也是用來接替devfs及hotplug的功能,這意味著它要在添加/刪除硬體時處理/dev目錄以及所有用戶空間的行為,包括載入firmware時。

udev的最新版本依賴於升級後的Linux kernel 2.6.13的uevent介面的最新版本。使用新版本udev的系統不能在2.6.13以下版本啟動,除非使用noudev參數來禁用udev並使用傳統的/dev來進行設備讀取。



原文出處:udev - 维基百科,自由的百科全书
冷日
(冷日)
Webmaster
  • 註冊日: 2008/2/19
  • 來自:
  • 發表數: 15771
[轉貼]udev-強大的device node管理系統

udev-強大的device node管理系統

作者: Joey  日期: 2009-02-02 20:35

過年前跑去書店打發無聊的時間,看到這個月又出了兩本跟linux device driver相關的書籍,隨手拿起來翻翻,發現其中有一篇寫到udev framework,裡面詳盡解釋device node在insert kernel module時如何自動建立,並且可隨著使用者更改規則而產生persistent node…等不同於devfs的變化

udev的官方網頁有篇不錯的conference paper,裡面有提到幾個重點,udev的出現為了解決目前在devfs上碰到的3個問題
1.udev能夠根據規則建立device node(這可以解決probing時,device node可能會依probing的順序不同而改變)
2.udev動態建立device node,不會像以前在/dev資料夾下擺一堆多而無用的device node
3.提供user更方便的API存取目前device的資訊,在kernel 2.6以上已提供sysfs這個device管理機制

udev運作的原理很簡單,它透過netlink得知目前kernel有那些module新增了,在收到kernel module新增的netlink訊息之後,它會先掃描user是否有指派device node rule,如果沒有,會自動根據module的major和minor number建立device node.有一點比較特殊的地方是,udev用inotify監聽rule變化的event,所以可以即時改變device node的狀態,udev的架構圖可參考如下


那我做個小實驗,看看udev到底是如何運作的,這個實驗分為兩個部份,一個是character kernel module,而另外一個就是udev的user space program(下載 udev-137.tar.gz)

character kernel module寫作的重點在於init時會建立class與create device

  1. charmodule_class = class_create ( THIS_MODULE , DEVICE_NAME ) ;
  2. if   ( IS_ERR ( charmodule_class
    ))  
  3. return - EFAULT ;
  4. device_create ( charmodule_class , NULL , MKDEV ( driver_major , 0 ) , DEVICE_NAME ) ;

character kernel moduel移除時會remove class和destroy device


  1. device_destroy ( charmodule_class , MKDEV ( driver_major , 0 )) ;
  2. class_destroy ( charmodule_class ) ;

我把udevd和udevadm移植到實驗平台,並且執行指令udevd –d,當我insert character kernel module時,udevd會自動幫我建立device node,整個實驗過程如下圖

character kernel module程式如下

  1. #include
    < linux/module.h >  
  2. #include < linux/kernel.h >  
  3. #include < linux/init.h >  
  4. #include < linux/major.h >  
  5. #include < linux/device.h >  
  6. #include < linux/poll.h
    >  
  7.  
  8. #define   dbg ( fmt , args ... ) printk ( " [%s]:%d => " fmt , __FUNCTION__ , __LINE__ ,## args )
  9. #define DBG () printk ( " [%s]:%d => \ n " , __FUNCTION__ , __LINE__ )
  10. #define DEVICE_NAME " charmodule "
  11. #define STRING_SIZE 256
  12. #define STRING_CHANGE_TIME 2 //seconds
  13.  
  14. static   int driver_major ;
  15. static int string_counter =
    1 ;
  16. static struct class * charmodule_class ;
  17.  
  18. typedef   struct _driver_private_data  
  19. {  
  20. wait_queue_head_t   wait ;
  21. struct fasync_struct *
    fasync ;
  22. struct timer_list char_timer ;
  23. char my_string [ 256 ] ;
  24. int flag ;
  25.  
  26. } driver_private_data ;
  27.  
  28. driver_private_data
    * gpd ;
  29. void   MyTimerFunction ( unsigned long data ) ;
  30.  
  31. static   ssize_t char_read ( struct file * file , char
    __user * buffer , size_t count , loff_t * ppos )  
  32. {  
  33. int   retval = 0 ;
  34. driver_private_data * dpd =
    file -> private_data ;
  35.  
  36. DBG () ;
  37. if   ( count < STRING_SIZE ) return - EINVAL ;
  38. while   (( retval +
    STRING_SIZE ) <= count )  
  39. {  
  40. if   ( copy_to_user ( buffer , dpd -> my_string , STRING_SIZE ))  
  41. return - EFAULT
    ;
  42. retval += STRING_SIZE ;
  43. }  
  44. dpd -> flag = 0 ;
  45. return   retval ;
  46. }  
  47.  
  48. static   ssize_t
    char_write ( struct file * file , const char __user * buffer , size_t count , loff_t * ppos )  
  49. {  

  50. return   STRING_SIZE ; //just a demo, I dont implement this
  51. }  
  52.  
  53. static   int char_open ( struct inode * inode , struct file * file )
     
  54. {  
  55.  
  56. driver_private_data * dpd ;
  57.  
  58. DBG () ;
  59. dpd = ( driver_private_data * ) file -> private_data ;
  60. if  
    ( ! dpd )  
  61. {  
  62. dpd = ( driver_private_data * ) kmalloc ( sizeof ( driver_private_data ) , GFP_ATOMIC ) ;
  63. file ->
    private_data = dpd ;
  64. sprintf ( dpd -> my_string , " string_counter %d \ n " , string_counter ) ;
  65. dpd -> flag = 0 ;

  66. string_counter ++;
  67. init_waitqueue_head ( & dpd -> wait ) ;
  68. gpd = dpd ;
  69. init_timer ( & dpd -> char_timer ) ;
  70. dpd ->
    char_timer . function = MyTimerFunction ;
  71. dpd -> char_timer . expires = jiffies + STRING_CHANGE_TIME * HZ ;
  72. dpd -> char_timer . data = (
    unsigned   long ) gpd ;
  73. add_timer ( & dpd -> char_timer ) ;
  74. }  
  75. return   0 ;
  76. }  
  77. static   unsigned
    int char_poll ( struct file * file , poll_table * wait )  
  78. {  
  79. driver_private_data * dpd = file -> private_data ;
  80. int
      mask = 0 ;
  81.  
  82. DBG () ;
  83. poll_wait ( file , & dpd -> wait , wait ) ;
  84. if   ( dpd ->
    flag == 1 )  
  85. mask |= POLLIN | POLLRDNORM ;
  86. return   mask ;
  87. }  
  88.  
  89. static   int char_release ( struct
    inode * inode , struct file * file )  
  90. {  
  91. driver_private_data * dpd ;
  92.  
  93. DBG () ;
  94. dpd = ( driver_private_data
    * ) file -> private_data ;
  95. del_timer ( & dpd -> char_timer ) ;
  96. return   0 ;
  97. }  
  98.  
  99.  
  100.  
  101.  
  102. static   const struct file_operations chardev_fops =
  103. {  
  104. . owner = THIS_MODULE ,
  105. . read = char_read ,
  106. . write = char_write
    ,
  107. . poll = char_poll ,
  108. . open = char_open ,
  109. . release = char_release ,
  110. } ;
  111.  
  112. void   MyTimerFunction ( unsigned long
    data )  
  113. {  
  114. driver_private_data * dpd = ( driver_private_data * ) data ;
  115. if   ( dpd )  
  116. {  

  117. sprintf ( dpd -> my_string , " string_counter %d \ n " , string_counter ) ;
  118. string_counter ++;
  119. //wake_up_interruptible(&dpd->wait);
  120. dpd -> flag = 1 ;
  121. init_timer ( & dpd -> char_timer ) ;
  122. dpd -> char_timer . function = MyTimerFunction ;
  123. dpd -> char_timer . expires = jiffies +
    STRING_CHANGE_TIME * HZ ;
  124. dpd -> char_timer . data = ( unsigned   long ) dpd ;
  125. add_timer ( & dpd -> char_timer ) ;

  126. }  
  127. }  
  128.  
  129. static   int __init charmodule_init ( void )  
  130. {  
  131.  
  132. dbg ( " char module demo \ n
    " ) ;
  133. driver_major = register_chrdev ( 0 , DEVICE_NAME , & chardev_fops ) ;
  134. if   ( driver_major < 0 )  
  135. {  

  136. dbg ( " Register character device failed \ n " ) ;
  137. return - EFAULT ;
  138. }  
  139. else   dbg ( " mknod /dev/%s c %d 0 \ n "
    , DEVICE_NAME , driver_major ) ;
  140. charmodule_class = class_create ( THIS_MODULE , DEVICE_NAME ) ;
  141. if   ( IS_ERR ( charmodule_class ))  
  142. return
    - EFAULT ;
  143. device_create ( charmodule_class , NULL , MKDEV ( driver_major , 0 ) , DEVICE_NAME ) ;
  144.  
  145. return   0 ;
  146. }
     
  147.  
  148. static   void __exit charmodule_exit ( void )  
  149. {  
  150. unregister_chrdev ( driver_major , DEVICE_NAME ) ;
  151. device_destroy ( charmodule_class
    , MKDEV ( driver_major , 0 )) ;
  152. class_destroy ( charmodule_class ) ;
  153. dbg ( " remove driver successfully \ n " ) ;
  154. }  

  155. module_init ( charmodule_init ) ;
  156. module_exit ( charmodule_exit ) ;
  157.  
  158. MODULE_DESCRIPTION ( " led module " ) ;
  159. MODULE_AUTHOR ( " Joey Cheng<jemicheng@gmail.com> "
    ) ;
  160. MODULE_LICENSE ( " GPL " ) ;
  161. MODULE_ALIAS ( " QT2410:char module " ) ;


原文出處: udev-強大的device node管理系統 - 程式設計 - 愛做夢的蘆薈
冷日
(冷日)
Webmaster
  • 註冊日: 2008/2/19
  • 來自:
  • 發表數: 15771
[分享]理解和認識udev

理解和認識udev

去論壇討論 來源: 作者: 發佈時間:2007-10-08

因為本身從事存儲行業,在工作中多次碰到用戶有這樣的要求:我的linux系統中原來有一塊SCSI硬盤,系統分配的設備文件是/dev/sda。現在新增加了一個外置的磁盤陣列,通過SCSI卡連接。但接上這個磁盤陣列後,/dev/sda變成了磁盤陣列的硬盤了,原來內置的SCSI硬盤變成了 /dev/sdb,我希望將設備文件固定下來。
    過去,我總是對用戶說,這個比較麻煩,因為/dev/sda等文件都是linux內核自動分配的。很難固定下來,除非你更改加載SCSI卡驅動程序的順序,讓內置硬盤連接的SCSI卡比外接磁盤陣列連接的SCSI卡的驅動模塊先加載到內核,這樣就能保證/dev/sda總是指向內置的硬盤。但這種解決方法畢竟不太完美,而且對於其他的即插即用設備,如USB設備等都不適用。
    近來,通過安裝和升級linux-2.6內核,發現這個問題已經可以通過2.6內核新的sysfs文件系統和udev程序得到解決。下面就是我在學習了udev配置後的一點心得。我喜歡用FAQ的形式來說明。

問:什麼是udev?
答:udev是一種工具,它能夠根據系統中的硬件設備的狀態動態更新設備文件,包括設備文件的創建,刪除等。設備文件通常放在/dev目錄下。使用udev後,在/dev目錄下就只包含系統中真正存在的設備。

問:udev支持什麼內核?
答:udev只支持linux-2.6內核,因為udev嚴重依賴於sysfs文件系統提供的信息,而sysfs文件系統只在linux-2.6內核中才有。

問:udev是一個內核程序還是用戶程序?
答:udev是一個用戶程序(user-mode daemon)。

問:udev和devfs有什麼差別?
答:udev能夠實現所有devfs實現的功能。但udev運行在用戶模式中,而devfs運行在內核中。據稱:devfs具有一些不太容易解決的先天缺陷。

問:udev的配置文件放在哪裡?
答:udev是一個用戶模式程序。它的配置文件是/etc/udev/udev.conf。這個文件一般缺省有這樣幾項:


udev_root="/dev" ; udev產生的設備文件的根目錄是/dev
udev_db="/dev/.udevdb" ; 通過udev產生的設備文件形成的數據庫
udev_rules="/etc/udev/rules.d" ;用於指導udev工作的規則所在目錄。
udev_log="err" ;當出現錯誤時,用syslog記錄錯誤信息。

問:udev的工作過程是怎樣的?
答:由於沒有研究過udev的源程序,不敢貿然就說udev的工作過程。我只是通過一些網上的資料和udev的說明文檔,大致猜測它的工作過程可能是這樣的。

  1. 當內核檢測到在系統中出現了新設備後,內核會在sysfs文件系統中為該新設備生成一項新的記錄,一般sysfs文件系統會被mount到 /sys目錄中。新記錄是以一個或多個文件或目錄的方式來表示。每個文件都包含有特定的信息。(信息是如何表述的,還要另外研究?)
  2. udev在系統中是以守護進程的方式udevd在運行,它通過某種途徑(到底什麼途徑,目前還沒搞懂。)檢測到新設備的出現,通過查找設備對應的sysfs中的記錄得到設備的一些信息。
  3. udev會根據/etc/udev/udev.conf文件中的udev_rules指定的目錄,逐個檢查該目錄下的文件,這個目錄下的文件都是針對某類或某個設備應該施行什麼措施的規則文件。udev讀取文件是按照文件名的ASCII字母順序來讀取的,如果udev一旦找到了與新加入的設備匹配的規則,udev就會根據規則定義的措施對新設備進行配置。同時不再讀後續的規則文件。

問:udev的規則文件的語法是怎樣的?
答:udev的規則文件以行為單位,以"#"開頭的行代表註釋行。其餘的每一行代表一個規則。每個規則分成一個或多個“匹配”和“賦值”部分。“匹配”部分用“匹配“專用的關鍵字來表示,相應的“賦值”部分用“賦值”專用的關鍵字來表示。“匹配”關鍵字包括:ACTION,KERNEL,BUS, SYSFS等等,“賦值”關鍵字包括:NAME,SYMLINK,OWNER等等。具體詳細的描述可以閱讀udev的man文檔。

    下面舉個例子來說明一下,有這樣一條規則:
SUBSYSTEM=="net", ACTION=="add", SYSFS{address}=="00:0d:87:f6:59:f3", IMPORT="/sbin/rename_netiface %k eth0"
    這個規則中的“匹配”部分有三項,分別是SUBSYSTEM,ACTION和SYSFS。而"賦值"部分有一項,是IMPORT。這個規則就是說,當系統中出現的新硬件屬於net子系統範疇,系統對該硬件採取的動作是加入這個硬件,且這個硬件在SYSFS文件系統中的“address”信息等於“00: 0d..."時,對這個硬件在udev層次施行的動作是調用外部程序/sbin/rename_netiface,傳遞的參數有兩個,一個是“%k”,代表內核對該新設備定義的名稱。另一個是”eth0“。
    從上面這個例子中可以看出,udev的規則的寫法比較靈活的,尤其在“匹配”部分中,可以通過諸如”*“, ”?“,[a-c],[1-9]等shell通配符來靈活匹配多個匹配項。具體的語法可以參考udev的man文檔。

問:udev怎樣做到不管設備連接的順序而維持一個統一的設備名?
答:實際上,udev是通過對內核產生的設備名增加別名的方式來達到上述目的的。前面說過,udev是用戶模式程序,不會更改內核的行為。因此,內核依然會我行我素地產生設備名如sda,sdb等。但是,udev可以根據設備的其他信息如總線(bus),生產商(vendor)等不同來區分不同的設備,並產生設備文件。udev只要為這個設備文件取一個固定的文件名就可以解決這個問題。在後續對設備的操作中,只要引用新的設備名就可以了。但為了保證最大限度的兼容,一般來說,新設備名總是作為一個對內核自動產生的設備名的符號鏈接(link)來使用的。

    例如:內核產生了sda設備名,而根據信息,這個設備對應於是我的內置硬盤,那我就可以制定udev規則,讓udev除了產生/dev/sda設備文件外,另外創建一個符號鏈接叫/dev/internalHD。這樣,我在fstab文件中,就可以用/dev/internalHD來代替原來的 /dev/sda了。下次,由於某些原因,這個硬盤在內核中變成了sdb設備名了,那也不用著急,udev還會自動產生/dev/internalHD這個鏈接,並指向正確的/dev/sdb設備。所有其他的文件像fstab等都不用修改。

問:怎樣才能找到這些設備信息,並把他們放到udev的規則文件中來匹配呢?
答:這個問題比較難,網上資料不多,我只找到一篇文章來介紹如何寫udev的規則。他的基本方法是通過udevinfo這個實用程序來找到那些可以作為規則文件裡的匹配項的項目。有這樣兩種情況可以使用這個工具:
    第一種情況是,當你把設備插入系統後,系統為設備產生了設備名(如/dev/sda)。那樣的話,你先用udevinfo -q path -n /dev/sda,命令會產生一個該設備名對應的在sysfs下的路徑,如/block/sda。然後,你再用udevinfo -a -p /sys/block/sda,這個命令會顯示一堆信息,信息分成很多塊。這些信息實際來自於操作系統維護的sysfs鏈表,不同的塊對應不同的路徑。你就可以用這些信息來作為udev規則文件中的匹配項。但需要注意的是,同一個規則只能使用同一塊中顯示的信息,不能跨塊書寫規則。
    第二種情況是,不知道系統產生的設備名,那就只有到/sys目錄下去逐個目錄查找了,反覆用udevinfo -a -p /sys/path...這個命令看信息,如果對應的信息是這個設備的,那就恭喜你。否則就再換個目錄。當然,在這種情況下,成功的可能性比較小。


原文出處:理解和认识udev - Linux天空
冷日
(冷日)
Webmaster
  • 註冊日: 2008/2/19
  • 來自:
  • 發表數: 15771
[分享]udev的實現原理

udev實現原理

             

轉載時請註明出處和作者聯繫方式: http://blog.csdn.net/absurd

作者聯繫方式: 李先靜<xianjimli at hotmail dot com>

更新時間: 2007-4-29

 

相對於
linux 來說, udev 還是一個新事物。然而,儘管它 03 年才出現,儘管它很低調 ( J ) ,但它無疑已經成為 linux 下不可或缺的組件了。 udev 是什麼?它是如何實現的?最近研究 Linux 設備管理時,花了一些時間去研究 udev 的實現。

 


udev
是什麼? u 是指 user space dev 是指 device udev 是用戶空間的設備驅動程序嗎?最初我也這樣認為,調試內核空間的程序要比調試用戶空間的程序複雜得多,內核空間的程序的 BUG 所引起的後果也嚴重得多, device driver 是內核空間中所佔比較最大的代碼,如果把這些 device driver 中硬件無關的代碼,從內核空間移動到用戶空間,自然是一個不錯的想法。

 


但我的想法並不正確, udev 的文檔是這樣說的,

1.          dynamic replacement for /dev 。作為 devfs 的替代者,傳統的 devfs 不能動態分配 major minor 的值,而 major minor 非常有限,很快就會用完了。 udev 能夠像
DHCP 動態分配 IP 地址一樣去動態分配 major minor

 

2.          device naming 。提供設備命名持久化的機制。傳統設備命名方式不具直觀性,像 /dev/hda1 這樣的名字肯定沒有 boot_disk 這樣的名字直觀。 udev 能夠像
DNS 解析域名一樣去給設備指定一個有意義的名稱。

 

3.          API to access info about current system devices 。提供了一組易用的 API 去操作 sysfs ,避免重複實現同樣的代碼,這沒有什麼好說的。

 

我們知道,用戶空間的程序與設備通信的方法,主要有以下幾種方式,

1.         
通過 ioperm 獲取操作 IO 端口的權限,然後用 inb/inw/ inl/ outb/outw/outl 等函數,避開設備驅動程序,直接去操作 IO 端口。(沒有用過)

2.          ioctl 函數去操作 /dev 目錄下對應的設備,這是設備驅動程序提供的接口。像鍵盤、鼠標和觸摸屏等輸入設備一般都是這樣做的。

3.         
write/read/mmap 去操作 /dev 目錄下對應的設備,這也是設備驅動程序提供的接口。像 framebuffer 等都是這樣做的。

 

上面的方法在大多數情況下,都可以正常工作,但是對於熱插撥 (hotplug) 的設備,比如像 U 盤,就有點困難了,因為你不知道:什麼時候設備插上了,什麼時候設備拔掉了。這就是所謂的 hotplug 問題了。

 

處理
hotplug
傳統的方法是,在內核中執行一個稱為 hotplug 的程序,相關參數通過環境變量傳遞過來,再由 hotplug 通知其它關注 hotplug 事件的應用程序。這樣做不但效率低下,而且感覺也不那麼優雅。新的方法是採用 NETLINK 實現的,這是一種特殊類型的 socket ,專門用於內核空間與用戶空間的異步通信。下面的這個簡單的例子,可以監聽來自內核 hotplug 的事件。

#include < stdio .h>

#include
<stdlib.h>

#include < string .h>

#include < ctype .h>

#include <sys/un.h>

#include <sys/ioctl.h>

#include <sys/ socket .h>

#include <linux/types.h>


#include <linux/netlink.h>

#include < errno .h>

 

static int init_hotplug_sock ( void )

{

    struct sockaddr_nl snl ;


    const int buffersize = 16 * 1024 * 1024;

    int retval ;

 

    memset (& snl , 0x00, sizeof ( struct sockaddr_nl));


   
snl .nl_family = AF_NETLINK;

    snl .nl_pid = getpid ();

    snl .nl_groups = 1;

 

    int hotplug_sock = socket (PF_NETLINK, SOCK_DGRAM , NETLINK_KOBJECT_UEVENT);

    if ( hotplug_sock == -1) {

        printf ( "error getting socket: %s" , strerror ( errno ));

        return -1;

   }


 

    /* set receive buffersize */

    setsockopt ( hotplug_sock , SOL_SOCKET , SO_RCVBUFFORCE, & buffersize , sizeof ( buffersize ));

 

    retval =
bind ( hotplug_sock , ( struct sockaddr *) & snl , sizeof ( struct sockaddr_nl));

    if ( retval < 0) {

        printf ( "bind failed: %s" , strerror
( errno ));

        close ( hotplug_sock );

        hotplug_sock = -1;

        return -1;

   }

 


   
return hotplug_sock ;

}

 

#define UEVENT_BUFFER_SIZE      2048

 

int main ( int argc , char * argv [])

{

         int hotplug_sock       = init_hotplug_sock ();

        

         while (1)

        {


                  
char buf [ UEVENT_BUFFER_SIZE *2] = {0};

                   recv ( hotplug_sock , & buf , sizeof ( buf ), 0);  


                  
printf ( "%s/n" , buf );

        }

 

         return 0;

}

 

編譯:


gcc -g hotplug.c -o hotplug_monitor

 

運行後插 / U 盤,可以看到:

add@/devices/pci0000:00/0000:00:1d.1/usb2/2-1

add@/devices/pci0000:00/0000:00:1d.1/usb2/2-1/usbdev2.2_ep00

add@/devices/pci0000:00/0000:00:1d.1/usb2/2-1/2-1:1.0

add@/class/scsi_host/host2


add@/devices/pci0000:00/0000:00:1d.1/usb2/2-1/2-1:1.0/usbdev2.2_ep81

add@/devices/pci0000:00/0000:00:1d.1/usb2/2-1/2-1:1.0/usbdev2.2_ep02

add@/devices/pci0000:00/0000:00:1d.1/usb2/2-1/2-1:1.0/usbdev2.2_ep83

add@/class/usb_device/usbdev2.2

add@/devices/pci0000:00/0000:00:1d.1/usb2/2-1/2-1:1.0/host2/target2:0:0/2:0:0:0

add@/class/scsi_disk/2:0:0:0

add@/block/sda

add@/block/sda/sda1


add@/class/scsi_device/2:0:0:0

add@/class/scsi_generic/sg0

remove@/devices/pci0000:00/0000:00:1d.1/usb2/2-1/2-1:1.0/usbdev2.2_ep81

remove@/devices/pci0000:00/0000:00:1d.1/usb2/2-1/2-1:1.0/usbdev2.2_ep02

remove@/devices/pci0000:00/0000:00:1d.1/usb2/2-1/2-1:1.0/usbdev2.2_ep83

remove@/class/scsi_generic/sg0

remove@/class/scsi_device/2:0:0:0

remove@/class/scsi_disk/2:0:0:0


remove@/block/sda/sda1

remove@/block/sda

remove@/devices/pci0000:00/0000:00:1d.1/usb2/2-1/2-1:1.0/host2/target2:0:0/2:0:0:0

remove@/class/scsi_host/host2

remove@/devices/pci0000:00/0000:00:1d.1/usb2/2-1/2-1:1.0

remove@/class/usb_device/usbdev2.2

remove@/devices/pci0000:00/0000:00:1d.1/usb2/2-1/usbdev2.2_ep00

remove@/devices/pci0000:00/0000:00:1d.1/usb2/2-1


 

udev 的主體部分在 udevd.c 文件中,它主要監控來自 4 個文件描述符的事件 / 消息,並做出處理:

1.          來自客戶端的控制消息。這通常由 udevcontrol 命令通過地址為 /org/kernel/udev/udevd 的本地 socket ,向
udevd
發送的控制消息。其中消息類型有:

l          UDEVD_CTRL_STOP_EXEC_QUEUE 停止處理消息隊列。

l          UDEVD_CTRL_START_EXEC_QUEUE 開始處理消息隊列。

l          UDEVD_CTRL_SET_LOG_LEVEL 設置 LOG 的級別。

l
        
UDEVD_CTRL_SET_MAX_CHILDS 設置最大子進程數限制。好像沒有用。

l          UDEVD_CTRL_SET_MAX_CHILDS_RUNNING 設置最大運行子進程數限制 ( 遍歷 proc 目錄下所有進程,根據 session 的值判斷 )

l         
UDEVD_CTRL_RELOAD_RULES
重新加載配置文件。

2.          來自內核的 hotplug 事件。如果有事件來源於 hotplug ,它讀取該事件,創建一個 udevd_uevent_msg 對象,記錄當前的消息序列號,設置消息的狀態為 EVENT_QUEUED, 然後並放入 running_list exec_list 兩個隊列中,稍後再進行處理。

3.
        
來自 signal handler 中的事件。 signal handler 是異步執行的,即使有 signal 產生,主進程的 select 並不會喚醒,為了喚醒主進程的 select ,它建立了一個管道,在 signal handler 中,向該管道寫入長度為 1 個子節的數據,這樣就可以喚醒主進程的 select 了。

4.
        
來自配置文件變化的事件。 udev 通過文件系統 inotify 功能,監控其配置文件目錄 /etc/udev/rules.d ,一旦該目錄中文件有變化,它就重新加載配置文件。

 

其中最主要的事件,當然是來自內核的 hotplug 事件,如何處理這些事件是 udev 的關鍵。 udev 本身並不知道如何處理這些事件,也沒有必要知道,因為它只實現機制,而不實現策略。事件的處理是由配置文件決定的,這些配置文件即所謂的 rule


 

關於 rule 的編寫方法可以參考《 writing_udev_rules 》, udev_rules.c 實現了對規則的解析。

 

在規則中,可以讓外部應用程序處理某個事件,這有兩種方式,一種是直接執行命令,通常是讓 modprobe 去加載驅動程序,或者讓 mount 去加載分區。另外一種是通過本地 socket 發送消息給某個應用程序。

 


udevd.c:udev_event_process 函數中,我們可以看到,如果 RUN 參數以 ”socket:” 開頭則認為是發到 socket ,否則認為是執行指定的程序。

 

下面的規則是執行指定程序:

60-pcmcia.rules:                RUN+="/sbin/modprobe pcmcia"

 

下面的規則是通過
socket
發送消息:

90-hal.rules:RUN+="socket:/org/freedesktop/hal/udev_event"

 

hal 正是我們下一步要關心的,接下來我會分析 HAL 的實現原理。

 

~~end~~

 


原文出處:udev的实现原理 - Linux mobile development - 博客频道 - CSDN.NET
冷日
(冷日)
Webmaster
  • 註冊日: 2008/2/19
  • 來自:
  • 發表數: 15771
[轉貼]hotplug 舊時代的產物?udev 才有未來!

hotplug 舊時代的產物?udev 才有未來!


什麼是 hotplug ﹝熱插拔﹞?傳統的 PCI 、 ISA ,都需要在電腦處於冷機的時候,才能插上裝置,因為這些規格都不具備 hotplug 的能力。hotplug 意味著不必讓電腦關機、切斷電源後就能插上你的裝置。我們常見的隨身碟就是最好的例子。

常常我們文件完後想要儲存帶走,就會拿起隨身碟插入 USB 連接孔,一般狀況下,系統馬上就能偵測到新的儲存裝置,並做新增配置,讓你可以立刻將資料存放於隨身碟裡。用完後,只要將隨身碟拔起,就可將資料帶走。這種在電腦熱機狀態就增減硬體的機制就是 hotplug。

在 Linux 裡,過去大家都是用 hotplug 套件包來達成動態增減裝置的功能,還必須設定 /proc/sys/kernel/hotplug ,讓核心在偵測到有新的 hotplug 裝置時,會通知 hotplug 套件包去做相關配置。

稍微有注意的人都知道,Linux 2.6 版核心後,全面採用 udev 取代過去的 devfs ,裝置檔現在都改用 udev 自動產生。原因是 udev 在設計理念上比過去的 devfs 擁有更大的格局,他不只是一個設備檔產生器,而是一個核心訊息的監聽器,它總在隨時監聽核心是否有新增裝置或是載入新的模組,並做出相對應的處理。在 udev 發展的過渡時期,由於對新裝置的對應處理機制並沒有設計的很完善,暫時只能充當設備檔產生器,而在 hotplug 機制的部份,設計了一個小程式 udevsend 與過去的 hotplug 套件包做整合。

udev 發展到今天,已逐漸成熟,hotplug 機制已不必過度仰賴舊的 hotplug 套件包,udevsend 這支程式已經在新版的 udev 中拿掉了,關於這部份可以在 Fedora Core 5 的系統中看到實作。


原文出處:Fred's blog: hotplug 舊時代的產物?udev 才有未來!
前一個主題 | 下一個主題 | 頁首 | | |



Powered by XOOPS 2.0 © 2001-2008 The XOOPS Project|