1. 程式人生 > 實用技巧 >新建一個裝置如何確保在/dev/及時的建立好對應的節點?

新建一個裝置如何確保在/dev/及時的建立好對應的節點?

原始碼:4.19.128

背景

在平常開發中偶爾會有這樣的場景: 業務指令碼中插入一個核心ko模組, 這個核心模組建立一個裝置; 然後使用者態程式立刻去訪問這個核心模組建立的裝置檔案。 簡而言之就是

insmod xxx.ko;
open("/dev/xxx");

但是在一般的嵌入式系統中往往存在一個這樣的情況:即核心建立裝置節點後根檔案系統/dev/目錄下並不是會立刻建立好對應的裝置節點,此時open("/dev/xxx")就會失敗B並返回-ENOENT。

如何應對這種情況呢?

對於嵌入式系統而言,一般又兩類方法(udev個人覺得比較適用於PC或者伺服器系統,使用busybox的嵌入式系統個人沒有部署起來),一個是基於mdev 一個是基於devtmpfs。

一、mdev

在核心建立好裝置後,可以呼叫手動呼叫mdev 來掃描/sys目錄下所建立的裝置,並在/dev目錄下建立對應的節點。所以可以在 insmod xxx.ko執行後,使用者態呼叫mdev -s即可在/dev/目錄下生成相應的裝置節點。

此外,如果希望在核心中就完成/dev/目錄下的裝置節點的建立可以藉助核心配置 CONFIG_UEVENT_HELPER和CONFIG_UEVENT_HELPER_PATH來完成。

圖1 uvent helper

圖2 hotplug程式

原理:核心使能CONFIG_UEVENT_HELPER=y後,核心在裝置建立的關鍵函式device_add()中呼叫call_usermodehelper_exec(info, UMH_NO_WAIT)函式去啟用call_usermodehelper_exec_work工作佇列執行緒,然後依賴去call_usermodehelper_exec_work工作佇列執行緒去執行/proc/sys/kernel/hotplug中存放的使用者態程式。由於這裡call_usermodehelper_exec(info, UMH_NO_WAIT)函式的第二個入參是UMH_NO_WAIT,因而這個流程是非同步的,即並不會確保hotplug程式執行完畢後才返回。

而/proc/sys/kernel/hotplug中的程式預設為/sbin/hotplug,也可以通過CONFIG_UEVENT_HELPER_PATH在menuconfig中進行修改,例如 上圖2 中就修改為/sbin/mdev; 也可以在系統啟動後通過echo寫入到/proc/sys/kernel/hotplug中。

二、devtmpfs

上面的CONFIG_UEVENT_HELPER雖然可以通過核心工作佇列執行緒去執行hotplug程式來完成/dev/目錄下裝置節點的建立,但是這個過程是非同步的----也就是說即使核心使能CONFIG_UEVENT_HELPER、配置了CONFIG_UEVENT_HELPER_PATH,但並不能夠保證device_add()函式返回後/dev/目錄就一定建立了對應的裝置節點。 對於一些應用場景來說這個非同步過程的不確定性是不友好的。

另外一種解決方案就是devtmpfs,這是一種以同步方式建立裝置節點的方案。

使用方法:核心使能CONFIG_DEVTMPFS,同時確保系統掛載devtmpfs(可以通過DEVTMPFS_MOUNT [=y]來自動掛)。

圖3 DEVTMPFS

原理:devtmpfs的原理是在device_add()函式中呼叫devtmpfs_create_node()喚醒kdevtmpfs核心執行緒, 然後kdevtmpfs核心執行緒完成裝置節點的建立。

需要注意的是,在devtmpfs_create_node()喚醒kdevtmpfs核心執行緒完成裝置節點的建立時會去等待其執行完畢(等待完成量)方可繼續允許,所以這個流程是同步有的。 一旦device_add()-->devtmpfs_create_node()函式執行成功並返回後,就能夠確保/dev/目錄下建立了對應的裝置節點。