套用至 SUSE Linux Enterprise Server 11 SP4

15 使用 udev 進行動態核心裝置管理

核心可以新增或移除執行中系統內幾乎所有的裝置。裝置狀態的變更 (已插入或移除裝置) 必須傳播至使用者空間。一旦插入並辨識出裝置,就必須立刻進行設定。如果辨識到的裝置狀態發生任何變更,必須通知該裝置的使用者。udev 會提供所需的基礎結構,以便動態維護 /dev 目錄中的裝置節點檔案和符號連結。udev 規則能將外部工具插入核心裝置事件處理。如此,您可以自定 udev 裝置處理,例如,新增特定的程序檔以在核心裝置處理過程中執行,或是在裝置處理過程中要求並輸入其他資料進行評估。

15.1 /dev 目錄

/dev 中的裝置節點可用來存取對應的核心裝置。透過 udev/dev 目錄會反映核心的目前狀態。每個核心裝置都有一個對應的裝置檔案。如果裝置與系統的連接中斷,該裝置節點就會遭到移除。

/dev 目錄的內容保存在暫存檔案系統中,而且所有檔案都會在每次系統開機時顯示。根據系統設計,手動建立或修改的檔案在重新開機後都將遺失。無論可存放於 /lib/udev/devices 目錄的對應核心裝置狀態為何,靜態檔案和目錄都必須存在於 /dev 目錄中。在系統啟動時,該目錄內容將複製到 /dev 目錄,並具備與 /lib/udev/devices 中檔案相同的擁有權和許可權。

15.2 核心 ueventudev

sysfs 檔案系統會輸出必要的裝置資訊。每個核心已偵測和啟始化的裝置,都會建立包含其裝置名稱的目錄。其中會包含裝置特定的屬性內容。

每次新增或移除裝置時,核心都會傳送 uevent 來通知 udev 此變更。udev 精靈會在啟動時從 /etc/udev/rules.d/*.rules 檔案中讀取並剖析一次所有指定的規則,然後將剖析結果保留在記憶體中。如果變更、新增或移除了規則檔案,精靈可以使用指令 udevadm control reload_rules 重新載入所有規則在記憶體內部的表示。此動作也可以在執行 /etc/init.d/boot.udev reload 時完成。如需有關 udev 規則及其語法的詳細資訊,請參閱第 15.6 節 「透過 udev 規則影響核心裝置事件的處理」

每個收到的事件都將與提供的規則集合進行比對。這些規則可新增或變更事件環境識別碼、要求要建立之裝置節點的特定名稱、新增指向該節點的符號連結,或是新增要在裝置節點建立後執行的程式。驅動程式核心 uevent 是從核心網路連結插槽接收。

15.3 驅動程式、核心模組和裝置

核心匯流排驅動程式會查探裝置。核心 (kernel) 會為每個偵測到的裝置建立一個內部裝置結構,而驅動程式核心 (core) 會向 udev 精靈傳送一個 uevent。匯流排裝置會以特殊格式的 ID 識別本身,表明其為何種裝置。通常這些 ID 會包含廠商和產品 ID,以及其他子系統特定值。每個匯流排都會指定自己的 ID 配置,即所謂的 MODALIAS。核心會接收這些裝置資訊,並根據這些資訊設定 MODALIAS ID 字串,然後隨事件一起傳送該字串。例如,USB 滑鼠的 ID 字串將如下所示:

MODALIAS=usb:v046DpC03Ed2000dc00dsc00dp00ic03isc01ip02

每個裝置驅動程式都包含有裝置可處理的已知別名清單。清單會包含在核心模組檔案本身。depmod 程式會讀取 ID 清單,並且為目前所有可用模組在核心的 /lib/modules 目錄中建立 modules.alias 檔案。透過此基礎結構,模組載入方式就會像在每次出現帶有 MODALIAS 識別碼的事件時呼叫 modprobe 一樣容易。如果是呼叫 modprobe $MODALIAS,此次呼叫就會比對裝置的已組織裝置別名和模組指定別名。如果有找到符合項目,該模組就可載入。以上這一切都是由 udev 自動觸發。

15.4 開機和初始裝置設定

udev 精靈執行之前,於開機過程中發生的所有裝置事件都會遺失,這是因為處理這些事件的基礎結構位於根檔案系統中,在該階段無法使用。為彌補這一損失,核心在 sysfs 檔案系統中之每部裝置的裝置目錄中都提供了一份 uevent 檔案。使用 add 寫入該檔案,核心便可重新傳送與開機期間所遺失的相同事件。負責 /sys 中所有 uevent 檔案的簡易迴圈,可以再次觸發所有事件,建立裝置節點並執行裝置設定。

例如,開機期間出現的 USB 滑鼠可能無法由早期的開機邏輯啟始化,這是因為當時尚無法使用驅動程式。裝置探查事件遺失,而且無法找到裝置的核心模組。udev 只需在根檔案系統可用後向核心要求所有裝置事件,這樣 USB 滑鼠裝置的事件就會再次執行,因此並不需要手動搜尋可能連接的裝置。現在,它會在已掛接根檔案系統中找到核心模組,並讓 USB 滑鼠完成啟始化。

從使用者空間的角度,執行期間的裝置冷插拔 (ColdPlud) 順序和裝置探查並沒有明顯的不同。這兩種情況都會使用相同規則來進行比對,而且會執行相同的設定程式。

15.5 監控執行中的 udev 精靈

udevadm monitor 程式可用來視覺化驅動程式核心事件以及 udev 事件程序的時間。

UEVENT[1185238505.276660] add   /devices/pci0000:00/0000:00:1d.2/usb3/3-1 (usb)
UDEV  [1185238505.279198] add   /devices/pci0000:00/0000:00:1d.2/usb3/3-1 (usb)
UEVENT[1185238505.279527] add   /devices/pci0000:00/0000:00:1d.2/usb3/3-1/3-1:1.0 (usb)
UDEV  [1185238505.285573] add   /devices/pci0000:00/0000:00:1d.2/usb3/3-1/3-1:1.0 (usb)
UEVENT[1185238505.298878] add   /devices/pci0000:00/0000:00:1d.2/usb3/3-1/3-1:1.0/input/input10 (input)
UDEV  [1185238505.305026] add   /devices/pci0000:00/0000:00:1d.2/usb3/3-1/3-1:1.0/input/input10 (input)
UEVENT[1185238505.305442] add   /devices/pci0000:00/0000:00:1d.2/usb3/3-1/3-1:1.0/input/input10/mouse2 (input)
UEVENT[1185238505.306440] add   /devices/pci0000:00/0000:00:1d.2/usb3/3-1/3-1:1.0/input/input10/event4 (input)
UDEV  [1185238505.325384] add   /devices/pci0000:00/0000:00:1d.2/usb3/3-1/3-1:1.0/input/input10/event4 (input)
UDEV  [1185238505.342257] add   /devices/pci0000:00/0000:00:1d.2/usb3/3-1/3-1:1.0/input/input10/mouse2 (input)

UEVENT 行會顯示核心已透過網路連結傳送的事件。UDEV 行會顯示已完成的 udev 事件處理常式。列印時間是百萬分之一秒。介於 UEVENTUDEV 之間的時間是指 udev 處理此事件所耗費的時間,或者是 udev 精靈延遲執行以便此事件能與執行中相關事件同步的時間。例如,硬碟分割區的事件始終會等待主要磁碟裝置事件完成,因為分割區事件可能與主要磁碟事件向硬體查詢的資料有關。

udevadm monitor --env 會顯示完整的事件環境:

ACTION=add
DEVPATH=/devices/pci0000:00/0000:00:1d.2/usb3/3-1/3-1:1.0/input/input10
SUBSYSTEM=input
SEQNUM=1181
NAME="Logitech USB-PS/2 Optical Mouse"
PHYS="usb-0000:00:1d.2-1/input0"
UNIQ=""
EV=7
KEY=70000 0 0 0 0
REL=103
MODALIAS=input:b0003v046DpC03Ee0110-e0,1,2,k110,111,112,r0,1,8,amlsfw

udev 也會將訊息傳送到 syslog。控制哪些訊息要傳送到 syslog 的預設 syslog 優先程度是在 udev 的組態檔 /etc/udev/udev.conf 中指定。執行精靈的記錄優先程度可使用 udevadm control log_priority= level/number 來變更。

15.6 透過 udev 規則影響核心裝置事件的處理

udev 規則可以比對核心新增至事件本身的任何內容,或者核心輸出到 sysfs 的任何資訊。規則也可向外部程式要求其他資訊。每個事件都會與所有指定規則進行比對。所有規則都位於 /etc/udev/rules.d 目錄中。

規則檔案中的每一行都包含至少一個鍵值組合。鍵類型共有兩種,包括比對和指定鍵。當所有比對鍵都與指定值相符時就會套用規則,而該指定值就會指定給指定鍵。相符規則可以指定裝置節點的名稱、新增指向該節點的符號連結,或是在事件處理過程中執行指定的程式。如果找不到任何符合規則,就會使用預設的裝置節點名稱來建立裝置節點。如需有關規則語法和系統提供之用於比對或輸入資料的鍵的詳細資訊,請參閱 udev man 頁面。以下範例規則提供了對 udev 規則語法的基本介紹。這些範例規則摘自 /etc/udev/rules.d/50-udev-default.rules 下的 udev 預設規則集。

範例 15.1︰ 範例 udev 規則
# console
KERNEL=="console", MODE="0600", OPTIONS="last_rule"

# serial devices
KERNEL=="ttyUSB*", ATTRS{product}=="[Pp]alm*Handheld*", SYMLINK+="pilot"

# printer
SUBSYSTEM=="usb", KERNEL=="lp*", NAME="usb/%k", SYMLINK+="usb%k", GROUP="lp"

# kernel firmware loader
SUBSYSTEM=="firmware", ACTION=="add", RUN+="firmware.sh"

主控台規則包含三個鍵︰一個比對鍵 (KERNEL) 以及兩個指定鍵 (MODEOPTIONS)。KERNEL 比對規則用於搜尋類型為主控台的所有項目的裝置清單。只有完全符合的項目才有效,才會觸發此規則讓其執行。MODE 鍵用於將特殊權限指派給裝置節點,在此案例中,僅此裝置的擁有者才會被指派讀取與寫入權限。OPTIONS 鍵用於將此規則做為要套用至所有此類型裝置的最後一條規則。符合此特殊裝置類型的任何後續規則都不會生效。

序列裝置規則在 50-udev-default.rules 中雖已不再可用,但仍值得瞭解一下。它包含兩個比對鍵 (KERNELATTRS) 與一個指派鍵 (SYMLINK)。KERNEL 鍵用於搜尋類型為 ttyUSB 的所有裝置。使用 * 萬用字元時,此鍵可比對多部此類裝置。第二個比對鍵 ATTRS 用於檢查 sysfs 中針對 ttyUSB 裝置的 product 屬性檔案是否包含特定字串。指派鍵 (SYMLINK) 用於觸發將符號連結新增至 /dev/pilot 下的此裝置。此鍵中使用的運算子 (+=) 將告知 udev 額外執行此動作,即使先前或之後的規則會新增其他符號連結也是如此。由於此規則包含兩個比對鍵,因此僅當兩個條件均滿足時才適用。

印表機規則可處理 USB 印表機,它包含兩個比對鍵,必須同時套用這兩個鍵才能套用整個規則 (SUBSYSTEMKERNEL)。三個指定鍵用於命名此裝置類型 (NAME)、建立符號裝置連結 (SYMLINK) 以及對此裝置類型的成員進行分組 (GROUP)。在 KERNEL 鍵中使用 * 萬用字元可使其符合多部 lp 印表機裝置。可以在 NAMESYMLINK 鍵中使用替代項,透過內部裝置名稱延伸這些字串。例如,第一部 lp USB 印表機的符號連結會讀取 /dev/usblp0

核心韌體載入程式規則可讓 udev 在執行時期透過外部輔助程式程序檔載入其他韌體。SUBSYSTEM 比對鍵可搜尋韌體子系統。ACTION 鍵可檢查是否已新增任何屬於韌體子系統的裝置。RUN+= 鍵可觸發執行 firmware.sh 程序檔以查找要載入的韌體。

某些一般特性適用於所有規則︰

  • 每條規則都包含一個或多個以逗號分隔的鍵值對。

  • 鍵的操作由運算子決定。udev 規則支援多種不同的運算子。

  • 每個指定值必須括在引號中。

  • 規則檔案中的每一行都表示一條規則。如果某規則的長度超出一行,請將 \ 加入到不同行中,就如同在外圍程序語法中一樣。

  • udev 規則支援符合 *?[] 模式的外圍程序式模式。

  • udev 規則支援替代項。

15.6.1 udev 規則中使用運算子

建立鍵時,您可以根據要建立的鍵類型從多個不同的運算子中進行選擇。比對鍵通常僅用於尋找符合或明顯不符合搜尋值的值。比對鍵可包含以下運算子︰

==

比較是否相等。如果鍵包含搜尋模式,則所有符合此模式的結果均有效。

!=

比較是否不相等。如果鍵包含搜尋模式,則所有符合此模式的結果均有效。

指派鍵可使用以下運算子︰

=

將某個值指派給鍵。如果鍵先前包含值清單,則此鍵將重設並僅指派單一值。

+=

將某個值新增至包含項目清單的鍵。

:=

指派最終值。不允許後續規則再做任何變更。

15.6.2 udev 規則中使用替代項

udev 規則支援使用佔位符與替代項。使用方式與任何其他程序檔中的方式類似。在 udev 規則中可以使用以下替代項︰

%r, $root

依預設為裝置目錄 /dev

%p, $devpath

DEVPATH 的值。

%k, $kernel

KERNEL 的值或內部裝置名稱。

%n, $number

裝置編號。

%N, $tempnode

裝置檔案的暫存名稱。

%M, $major

裝置的主要編號。

%m, $minor

裝置的次要編號。

%s{屬性}, $attr{屬性}

sysfs 屬性的值 (由屬性指定)。

%E{變數}, $attr{變數}

環境變數的值 (由變數指定)。

%c, $result

PROGRAM 的輸出。

%%

% 字元。

$$

$ 字元。

15.6.3 使用 udev 比對鍵

比對鍵定義要套用 udev 規則所必須滿足的條件。以下為可用的比對鍵:

ACTION

事件動作的名稱,例如新增或移除裝置時的 addremove

DEVPATH

事件裝置的裝置路徑,例如 DEVPATH=/bus/pci/drivers/ipw3945,用於搜尋與 ipw3945 驅動程式相關的所有事件。

KERNEL

事件裝置的內部 (核心) 名稱。

SUBSYSTEM

事件裝置的子系統,例如 SUBSYSTEM=usb,適用於與 USB 裝置相關的所有事件。

ATTR{檔案名稱}

事件裝置的 sysfs 屬性。例如,若要比對 vendor 屬性檔案名稱中包含的字串,可以使用 ATTR{vendor}=="On[sS]tream"

KERNELS

udev 向上搜尋符合裝置名稱的裝置路徑。

SUBSYSTEMS

udev 向上搜尋相符裝置子系統名稱的裝置路徑。

DRIVERS

udev 向上搜尋相符裝置驅動程式名稱的裝置路徑。

ATTRS{檔案名稱}

udev 向上搜尋與 sysfs 屬性值相符之裝置的裝置路徑。

ENV{}

環境變數的值,例如 ENV{ID_BUS}="ieee1394,用於搜尋與 FireWire 匯流排 ID 相關的所有事件。

PROGRAM

udev 執行外部程式。若要成功執行,程式必須以離開碼零返回。RESULT 鍵可使用程式的輸出 (列印至 stdout)。

RESULT

比對上次 PROGRAM 呼叫的輸出字串。即可將此鍵包含於相同規則中 (如 PROGRAM 鍵),也可含於後續規則中。

15.6.4 使用 udev 指定鍵

與上述比對鍵不同,指定鍵不會說明必須滿足的條件,而是將值、名稱和動作指定給 udev 維護的裝置節點。

NAME

要建立之裝置節點的名稱。如果規則已設定了節點名稱,則將忽略適用於此節點的所有其他含 NAME 鍵的規則。

SYMLINK

與要建立的節點相關聯之符號連結的名稱。可以為多項比對規則新增符號連結以便使用裝置節點進行建立。您還可以使用空格字元分隔符號連結名稱,從而為一項規則中的一個節點指定多個符號連結。

OWNER、GROUP、MODE

新裝置節點的權限。在此處指定的值將覆寫已編譯的任何項目。

ATTR{}

指定要寫入事件裝置之 sysfs 屬性的值。如果使用運算子 ==,也會使用此鍵來比對 sysfs 屬性的值。

ENV{}

告知 udev 將某變數輸出到環境中。如果使用運算子 ==,也會使用此鍵來比對環境變數。

RUN

告知 udev 將某程式新增至要為此裝置執行的程式清單。對極短任務套用此項時要格外小心,以免封鎖此裝置的其他事件。

LABEL

GOTO 可以跳轉之處新增一個標籤。

GOTO

告知 udev 跳過多項規則並根據 GOTO 鍵所參考之標籤對應的規則繼續。

IMPORT{類型}

將變數載入事件環境,如外部程式的輸出。udev 可輸入多種不同類型的變數。如果未指定任何類型,udev 會根據檔案權限的可執行位元嘗試自行決定類型。

  • program 可告知 udev 執行外部程式並輸入其輸出。

  • file 可告知 udev 輸入文字檔。

  • parent 可告知 udev 輸入父代裝置中儲存的鍵。

WAIT_FOR_SYSFS

告知 udev 等待系統為特定裝置建立指定的 sysfs 檔案。例如,WAIT_FOR_SYSFS="ioerr_cnt" 通知 udev 等待,直到 ioerr_cnt 檔案建立。

OPTIONS

OPTION 鍵可以包含多個值︰

  • last_rule 告知 udev 忽略所有後續規則。

  • ignore_device 告知 udev 完全忽略此事件。

  • ignore_remove 告知 udev 忽略針對該裝置的所有後續移除事件。

  • all_partitions 告知 udev 為區塊裝置上的所有可用分割區建立裝置節點。

15.7 永久裝置命名

動態裝置目錄和 udev 規則基礎架構讓系統可以為所有磁碟裝置提供固定名稱,無論裝置的辨識順序或所使用的連接為何。核心所建立的每個相應區塊裝置,都會採用針對特定匯流排、磁碟類型或檔案系統所設計的工具進行檢查。udev 會根據核心動態提供的裝置節點名稱,維護指向裝置的永久符號連結類別:

/dev/disk
|-- by-id
|   |-- scsi-SATA_HTS726060M9AT00_MRH453M4HWHG7B -> ../../sda
|   |-- scsi-SATA_HTS726060M9AT00_MRH453M4HWHG7B-part1 -> ../../sda1
|   |-- scsi-SATA_HTS726060M9AT00_MRH453M4HWHG7B-part6 -> ../../sda6
|   |-- scsi-SATA_HTS726060M9AT00_MRH453M4HWHG7B-part7 -> ../../sda7
|   |-- usb-Generic_STORAGE_DEVICE_02773 -> ../../sdd
|   `-- usb-Generic_STORAGE_DEVICE_02773-part1 -> ../../sdd1
|-- by-label
|   |-- Photos -> ../../sdd1
|   |-- SUSE10 -> ../../sda7
|   `-- devel -> ../../sda6
|-- by-path
|   |-- pci-0000:00:1f.2-scsi-0:0:0:0 -> ../../sda
|   |-- pci-0000:00:1f.2-scsi-0:0:0:0-part1 -> ../../sda1
|   |-- pci-0000:00:1f.2-scsi-0:0:0:0-part6 -> ../../sda6
|   |-- pci-0000:00:1f.2-scsi-0:0:0:0-part7 -> ../../sda7
|   |-- pci-0000:00:1f.2-scsi-1:0:0:0 -> ../../sr0
|   |-- usb-02773:0:0:2 -> ../../sdd
|   |-- usb-02773:0:0:2-part1 -> ../../sdd1
`-- by-uuid
    |-- 159a47a4-e6e6-40be-a757-a629991479ae -> ../../sda7
    |-- 3e999973-00c9-4917-9442-b7633bd95b9e -> ../../sda6
    `-- 4210-8F8C -> ../../sdd1

15.8 udev 使用的檔案

/sys/*

由 Linux 核心提供的虛擬檔案系統,可輸出所有目前已知裝置。udev 用此資訊在 /dev 中建立裝置節點。

/dev/*

動態建立的裝置節點和開機時從 /lib/udev/devices/* 複製的靜態內容。

下列檔案和目錄包含了 udev 基礎結構的重要元件:

/etc/udev/udev.conf

udev 主組態檔。

/etc/udev/rules.d/*

udev 事件符合規則.

/lib/udev/devices/*

靜態 /dev 內容。

/lib/udev/*

udev 規則中呼叫的協助程式。

15.9 更多資訊

如需關於 udev 基礎結構的詳細資訊,請參閱下列 man 頁面:

udev

關於 udev、鍵、規則和其他重要組態問題的一般資訊。

udevadm

udevadm 可用於控制 udev 的執行時期行為、要求核心事件、管理事件佇列以及提供簡單的除錯機制。

udevd

關於 udev 事件管理精靈的資訊。

列印此頁面