linux mdev -s没有运行,mdev详解
一、概述
mdev是busybox提供的一個工具,用在嵌入式系統中,相當于簡化版的udev,作用是在系統啟動和熱插拔或動態加載驅動程序時,
自動創建設備節點。文件系統中的/dev目錄下的設備節點都是由mdev創建的。
在加載驅動過程中,根據驅動程序,在/dev下自動創建設備節點。
以下內容摘自busybox-1.23.1的mdev.txt文件:
Mdev has two primary uses: initial population and dynamic updates. ?Both
require sysfs support in the kernel and have it mounted at /sys. ?For dynamic
updates, you also need to have hotplugging enabled in your kernel.
Here's a typical code snippet from the init script:
[0] mount -t proc proc /proc
[1] mount -t sysfs sysfs /sys
[2] echo /sbin/mdev > /proc/sys/kernel/hotplug
[3] mdev -s
Alternatively, without procfs the above becomes:
[1] mount -t sysfs sysfs /sys
[2] sysctl -w kernel.hotplug=/sbin/mdev
[3] mdev -s
Of course, a more "full" setup would entail executing this before the previous
code snippet:
[4] mount -t tmpfs -o size=64k,mode=0755 tmpfs /dev
[5] mkdir /dev/pts
[6] mount -t devpts devpts /dev/pts
The simple explanation here is that [1] you need to have /sys mounted before
executing mdev. ?Then you [2] instruct the kernel to execute /sbin/mdev whenever
a device is added or removed so that the device node can be created or destroyed.
Then you [3] seed /dev with all the device nodes that were created while the system
was booting.
For the "full" setup, you want to [4] make sure /dev is a tmpfs filesystem
(assuming you're running out of flash). ?Then you want to [5] create the
/dev/pts mount point and finally [6] mount the devpts filesystem on it.
二、用法
這篇博文所涉及到的用法很簡單:
1、在/etc/init.d/rcS腳本里有“mdev -s”
解釋:在系統啟動時,通過執行“mdev -s”掃描/sys/class和/sys/block,在目錄中查找dev文件。例如:/sys/class/tty/tty0/dev,
它的內容為"4:0",即主設備號是4,次設備號是0,dev的上一級目錄為設備名,這里是tty0。/sys/class/下的每個文件夾都代表
著一個子系統。
2、在/etc/init.d/rcS腳本里有“echo /sbin/mdev > /proc/sys/kernel/hotplug”,即是把/sbin/mdev寫到/proc/sys/kernel/hotplug文件里
解釋:當有熱插拔事件產生時,內核會調用/proc/sys/kernel/hotplug文件里指定的應用程序來處理熱插拔事件
根據mdev.txt的說明可知在使用mdev之前要滿足下面的條件:
mount -t proc proc /proc
mount -t sysfs sysfs /sys
mount -t tmpfs -o size=64k,mode=0755 tmpfs /dev
mkdir /dev/pts
mount -t devpts devpts /dev/pts
說明:所有的設備都可以在/sys/class下找到,這個文件夾下的每一個文件夾下代表了一類設備,表示類設備的文件夾下也有
文件夾,這些文件夾代表設備。如:/sys/class/test/test_dev/ ,test代表類,如net、tty、sound;test_dev代表某個
設備,它的名字和/dev下的設備節點名字是一樣的
三、內核源碼分析
分析一下相關內核源碼,看上面提到的功能是如何實現的。
平時我們添加驅動時,如果想自動創建設備節點調用的函數是class_create和device_create。class_create是創建類設備,
就是在/sys/class/創建一個文件夾,這個文件夾代表一類設備,這個文件夾里會包含device_create創建的設備,也是一個
文件夾。
下面就從device_create入手,看是怎么實現自動創建設備節點的。源碼基于linux-2.6.30.4內核
struct device *device_create(struct class *class, struct device *parent,
dev_t devt, void *drvdata, const char *fmt, ...)
dev = device_create_vargs(class, parent, devt, drvdata, fmt, vargs);
retval = device_register(dev);
return device_add(dev);
kobject_uevent(&dev->kobj, KOBJ_ADD);
return kobject_uevent_env(kobj, action, NULL); ? // action = KOBJ_ADD
const char *action_string = kobject_actions[action]; ? ?// action_string = "add"
……
//把相關信息存到環境變量里,ACTION代表操作類型,DEVPATH為設備在class下存在的路徑,SUBSYSTEM為class_create創建的設備類
//ACTION=add , DEVPATH=/class/test/test_dev , SUBSYSTEM=test
retval = add_uevent_var(env, "ACTION=%s", action_string);
if (retval)
goto exit;
retval = add_uevent_var(env, "DEVPATH=%s", devpath);
if (retval)
goto exit;
retval = add_uevent_var(env, "SUBSYSTEM=%s", subsystem);
if (retval)
goto exit;
……
if (uevent_helper[0]){
argv [0] = uevent_helper;
argv [1] = (char *)subsystem;
argv [2] = NULL;
//內核空間調用用戶空間程序,調用的程序由argv [0] = uevent_helper指定
retval = call_usermodehelper(argv[0], argv,
env->envp, UMH_WAIT_EXEC);
下面看看uevent_helper是誰
定義如下:
char uevent_helper[UEVENT_HELPER_PATH_LEN] = CONFIG_UEVENT_HELPER_PATH;
去.config中查看:
CONFIG_UEVENT_HELPER_PATH="/sbin/hotplug"
但是去/sbin目錄下查看,并沒有hotplug這個文件,所以肯定不是這個文件起作用,于是在上面的if (uevent_helper[0])
里加了一句調試信息,打印uevent_helper,內核啟動相關打印信息如下:
uevent_helper is /sbin/hotplug
uevent_helper is /sbin/hotplug
s3c2410-rtc s3c2410-rtc: setting system clock to 2015-04-30 08:12:15 UTC (1430381535)
yaffs: dev is 32505858 name is "mtdblock2"
yaffs: passed flags ""
yaffs: Attempting MTD mount on 31.2, "mtdblock2"
yaffs: auto selecting yaffs2
block 646 is bad
yaffs_read_super: isCheckpointed 0
VFS: Mounted root (yaffs filesystem) on device 31:2.
Freeing init memory: 240K
Start Qtopia-2.2.0
uevent_helper is /sbin/mdev
uevent_helper is /sbin/mdev
看到沒,剛開始確實是/sbin/hotplug,但后來就變成了/sbin/mdev。很據上面信息,我們知道是在文件系統啟動的過程中
發生改變的。文件系統啟動過程中,改變mdev的只有“echo /sbin/mdev > /proc/sys/kernel/hotplug”,也確實是這個
導致了uevent_helper的改變。
涉及到的數據在/kernel/sysctl.c下
#if defined(CONFIG_HOTPLUG) && defined(CONFIG_NET)
{
.ctl_name= KERN_HOTPLUG,
.procname= "hotplug",
.data= &uevent_helper,
.maxlen= UEVENT_HELPER_PATH_LEN,
.mode= 0644,
.proc_handler= &proc_dostring,
.strategy= &sysctl_string,
},
#endif
至于為什么“echo /sbin/mdev > /proc/sys/kernel/hotplug”能改變uevent_helper就是proc虛擬文件系統的內容了,
這里不討論。
其實設置mdev有三種方法,總結如下:
1、編譯內核的時候直接配置CONFIG_UEVENT_HELPER_PATH,并且在之后的啟動中不去修改uevent_helper,那么
uevent_helper代表的程序就是CONFIG_UEVENT_HELPER_PATH指定的程序
2、不管CONFIG_UEVENT_HELPER_PATH配置與否或如何設置,通過echo /sbin/mdev > /sys/kernel/uevent_helper
修改uevent_helper的內容,這個指令將會調用內核函數uevent_helper_store。過程涉及sysfs虛擬文件系統的
內容,這里不討論。改變之后,/proc/sys/kernel/hotplug里的內容也會立即發生改變
3、不管CONFIG_UEVENT_HELPER_PATH配置與否或如何設置,通過echo /sbin/mdev > /proc/sys/kernel/hotplug
修改uevent_helper的內容.它的修改也會導致/sys/kernel/uevent_helper里的內容立即改變
對于上述的2、3兩種方法,都是通過用戶層的接口直接uevent_helper,所以誰在后面誰起作用
三、busybox源碼分析
內核源碼的最后是調用uevent_helper指定的用戶程序,這個用戶程序通常是mdev,那么mdev如何做的呢,來看一下
busybox的源碼。源碼基于busybox-1.23.1
int mdev_main(int argc UNUSED_PARAM, char **argv)
xchdir("/dev"); ?// 先把目錄改變到/dev下
if (argv[1] && strcmp(argv[1], "-s") == 0) { ?// 在文件系統啟動的時候會調用 mdev -s,創建所有驅動設備節點
putenv((char*)"ACTION=add"); // mdev -s 的動作是創建設備節點,所以為add
if (access("/sys/class/block", F_OK) != 0) { // 當/sys/class/block目錄不存在時,才掃描/sys/block
/* Scan obsolete /sys/block only if /sys/class/block
* doesn't exist. Otherwise we'll have dupes.
* Also, do not complain if it doesn't exist.
* Some people configure kernel to have no blockdevs.
*/
recursive_action("/sys/block",
ACTION_RECURSE | ACTION_FOLLOWLINKS | ACTION_QUIET,
fileAction, dirAction, temp, 0);
}
/*
* 這個函數是遞歸函數,它會掃描/sys/class目錄下的所有文件,如果發現dev文件,將按照
* /etc/mdev.conf文件進行相應的配置。如果沒有配置文件,那么直接創建設備節點
* 最終調用的創建函數是 make_device
*/
recursive_action("/sys/class",
ACTION_RECURSE | ACTION_FOLLOWLINKS,
fileAction, dirAction, temp, 0);
}
else{
// 獲得環境變量,環境變量是內核在調用mdev之前設置的
env_devname = getenv("DEVNAME"); /* can be NULL */
G.subsystem = getenv("SUBSYSTEM");
action = getenv("ACTION");
env_devpath = getenv("DEVPATH");
snprintf(temp, PATH_MAX, "/sys%s", env_devpath);
make_device(env_devname, temp, op);
}
由以上代碼分析可知,無論對于何種操作,最后都是調用make_device來創建節點,看一下這個函數
static void make_device(char *device_name, char *path, int operation)
int major, minor, type, len;
char *path_end = path + strlen(path); ?//path_end指定path結尾處
major = -1;
if (operation == OP_add) {
strcpy(path_end, "/dev"); ?// 往path結尾處拷貝“/dev”,這時path=/sys/class/test/test_dev/dev
len = open_read_close(path, path_end + 1, SCRATCH_SIZE - 1); // 打開并讀取/sys/class/test/test_dev/dev
*path_end = '\0';
if (len < 1) {
if (!ENABLE_FEATURE_MDEV_EXEC)
return;
} else if (sscanf(path_end + 1, "%u:%u", &major, &minor) == 2) { //從/sys/class/test/test_dev/dev獲得主次設備號
dbg1("dev %u,%u", major, minor);
} else {
major = -1;
}
}
if (operation == OP_add && major >= 0) // 如果是add,即創建節點
mknod(node_name, rule->mode | type, makedev(major, minor)) // 最終用mknod函數在/dev下創建設備節點
if (operation == OP_remove && major >= -1) ?// 如果是remove,即刪除節點
unlink(node_name);
創建節點最后無非還是調用mknod,當然在class_create和device_create自動創建設備節點時,也會在/sys/class下自動創建
和刪除相關設備類和設備,這是sysfs的驅動內容,這里不講
總結
以上是生活随笔為你收集整理的linux mdev -s没有运行,mdev详解的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 中国航空航天博物馆有歼20吗?
- 下一篇: 淘宝商家态度不好如何处理