日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問(wèn) 生活随笔!

生活随笔

當(dāng)前位置: 首頁(yè) > 编程资源 > 编程问答 >内容正文

编程问答

mdev详解

發(fā)布時(shí)間:2023/12/9 编程问答 35 豆豆
生活随笔 收集整理的這篇文章主要介紹了 mdev详解 小編覺(jué)得挺不錯(cuò)的,現(xiàn)在分享給大家,幫大家做個(gè)參考.

mdev是busybox提供的一個(gè)工具,用在嵌入式系統(tǒng)中,相當(dāng)于簡(jiǎn)化版的udev,作用是在系統(tǒng)啟動(dòng)和熱插拔或動(dòng)態(tài)加載驅(qū)動(dòng)程序時(shí),
自動(dòng)創(chuàng)建設(shè)備節(jié)點(diǎn)。文件系統(tǒng)中的/dev目錄下的設(shè)備節(jié)點(diǎn)都是由mdev創(chuàng)建的。

在加載驅(qū)動(dòng)過(guò)程中,根據(jù)驅(qū)動(dòng)程序,在/dev下自動(dòng)創(chuàng)建設(shè)備節(jié)點(diǎn)。

以下內(nèi)容摘自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 -sAlternatively, without procfs the above becomes: [1] mount -t sysfs sysfs /sys [2] sysctl -w kernel.hotplug=/sbin/mdev [3] mdev -sOf 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
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29

二、用法

這篇博文所涉及到的用法很簡(jiǎn)單:

1、在/etc/init.d/rcS腳本里有“mdev -s”
解釋:在系統(tǒng)啟動(dòng)時(shí),通過(guò)執(zhí)行“mdev -s”掃描/sys/class和/sys/block,在目錄中查找dev文件。例如:/sys/class/tty/tty0/dev,
它的內(nèi)容為”4:0”,即主設(shè)備號(hào)是4,次設(shè)備號(hào)是0,dev的上一級(jí)目錄為設(shè)備名,這里是tty0。/sys/class/下的每個(gè)文件夾都代表
著一個(gè)子系統(tǒng)。

2、在/etc/init.d/rcS腳本里有“echo /sbin/mdev > /proc/sys/kernel/hotplug”,即是把/sbin/mdev寫到/proc/sys/kernel/hotplug文件里
解釋:當(dāng)有熱插拔事件產(chǎn)生時(shí),內(nèi)核會(huì)調(diào)用/proc/sys/kernel/hotplug文件里指定的應(yīng)用程序來(lái)處理熱插拔事件

根據(jù)mdev.txt的說(shuō)明可知在使用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

說(shuō)明:所有的設(shè)備都可以在/sys/class下找到,這個(gè)文件夾下的每一個(gè)文件夾下代表了一類設(shè)備,表示類設(shè)備的文件夾下也有
文件夾,這些文件夾代表設(shè)備。如:/sys/class/test/test_dev/ ,test代表類,如net、tty、sound;test_dev代表某個(gè)
設(shè)備,它的名字和/dev下的設(shè)備節(jié)點(diǎn)名字是一樣的


三、內(nèi)核源碼分析

分析一下相關(guān)內(nèi)核源碼,看上面提到的功能是如何實(shí)現(xiàn)的。
平時(shí)我們添加驅(qū)動(dòng)時(shí),如果想自動(dòng)創(chuàng)建設(shè)備節(jié)點(diǎn)調(diào)用的函數(shù)是class_create和device_create。class_create是創(chuàng)建類設(shè)備,
就是在/sys/class/創(chuàng)建一個(gè)文件夾,這個(gè)文件夾代表一類設(shè)備,這個(gè)文件夾里會(huì)包含device_create創(chuàng)建的設(shè)備,也是一個(gè)
文件夾。
下面就從device_create入手,看是怎么實(shí)現(xiàn)自動(dòng)創(chuàng)建設(shè)備節(jié)點(diǎn)的。源碼基于linux-2.6.30.4內(nèi)核

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_ADDconst char *action_string = kobject_actions[action]; // action_string = "add"……//把相關(guān)信息存到環(huán)境變量里,ACTION代表操作類型,DEVPATH為設(shè)備在class下存在的路徑,SUBSYSTEM為class_create創(chuàng)建的設(shè)備類//ACTION=add , DEVPATH=/class/test/test_dev , SUBSYSTEM=testretval = 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;//內(nèi)核空間調(diào)用用戶空間程序,調(diào)用的程序由argv [0] = uevent_helper指定retval = call_usermodehelper(argv[0], argv,env->envp, UMH_WAIT_EXEC);
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31

下面看看uevent_helper是誰(shuí)
定義如下:

char uevent_helper[UEVENT_HELPER_PATH_LEN] = CONFIG_UEVENT_HELPER_PATH;
  • 1
  • 2

去.config中查看:
CONFIG_UEVENT_HELPER_PATH=”/sbin/hotplug”
但是去/sbin目錄下查看,并沒(méi)有hotplug這個(gè)文件,所以肯定不是這個(gè)文件起作用,于是在上面的if (uevent_helper[0])
里加了一句調(diào)試信息,打印uevent_helper,內(nèi)核啟動(dòng)相關(guān)打印信息如下:

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
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14

看到?jīng)],剛開(kāi)始確實(shí)是/sbin/hotplug,但后來(lái)就變成了/sbin/mdev。很據(jù)上面信息,我們知道是在文件系統(tǒng)啟動(dòng)的過(guò)程中
發(fā)生改變的。文件系統(tǒng)啟動(dòng)過(guò)程中,改變mdev的只有“echo /sbin/mdev > /proc/sys/kernel/hotplug”,也確實(shí)是這個(gè)
導(dǎo)致了uevent_helper的改變。

涉及到的數(shù)據(jù)在/kernel/sysctl.c下

至于為什么“echo /sbin/mdev > /proc/sys/kernel/hotplug”能改變uevent_helper就是proc虛擬文件系統(tǒng)的內(nèi)容了,
這里不討論。

#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
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11

其實(shí)設(shè)置mdev有三種方法,總結(jié)如下:
1、編譯內(nèi)核的時(shí)候直接配置CONFIG_UEVENT_HELPER_PATH,并且在之后的啟動(dòng)中不去修改uevent_helper,那么
uevent_helper代表的程序就是CONFIG_UEVENT_HELPER_PATH指定的程序

2、不管CONFIG_UEVENT_HELPER_PATH配置與否或如何設(shè)置,通過(guò)echo /sbin/mdev > /sys/kernel/uevent_helper
修改uevent_helper的內(nèi)容,這個(gè)指令將會(huì)調(diào)用內(nèi)核函數(shù)uevent_helper_store。過(guò)程涉及sysfs虛擬文件系統(tǒng)的
內(nèi)容,這里不討論。改變之后,/proc/sys/kernel/hotplug里的內(nèi)容也會(huì)立即發(fā)生改變

3、不管CONFIG_UEVENT_HELPER_PATH配置與否或如何設(shè)置,通過(guò)echo /sbin/mdev > /proc/sys/kernel/hotplug
修改uevent_helper的內(nèi)容.它的修改也會(huì)導(dǎo)致/sys/kernel/uevent_helper里的內(nèi)容立即改變

對(duì)于上述的2、3兩種方法,都是通過(guò)用戶層的接口直接uevent_helper,所以誰(shuí)在后面誰(shuí)起作用


三、busybox源碼分析

內(nèi)核源碼的最后是調(diào)用uevent_helper指定的用戶程序,這個(gè)用戶程序通常是mdev,那么mdev如何做的呢,來(lái)看一下
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) { // 在文件系統(tǒng)啟動(dòng)的時(shí)候會(huì)調(diào)用 mdev -s,創(chuàng)建所有驅(qū)動(dòng)設(shè)備節(jié)點(diǎn)putenv((char*)"ACTION=add"); // mdev -s 的動(dòng)作是創(chuàng)建設(shè)備節(jié)點(diǎn),所以為addif (access("/sys/class/block", F_OK) != 0) { // 當(dāng)/sys/class/block目錄不存在時(shí),才掃描/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);}/* * 這個(gè)函數(shù)是遞歸函數(shù),它會(huì)掃描/sys/class目錄下的所有文件,如果發(fā)現(xiàn)dev文件,將按照 * /etc/mdev.conf文件進(jìn)行相應(yīng)的配置。如果沒(méi)有配置文件,那么直接創(chuàng)建設(shè)備節(jié)點(diǎn) * 最終調(diào)用的創(chuàng)建函數(shù)是 make_device */recursive_action("/sys/class", ACTION_RECURSE | ACTION_FOLLOWLINKS,fileAction, dirAction, temp, 0);}else{// 獲得環(huán)境變量,環(huán)境變量是內(nèi)核在調(diào)用mdev之前設(shè)置的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);}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41

由以上代碼分析可知,無(wú)論對(duì)于何種操作,最后都是調(diào)用make_device來(lái)創(chuàng)建節(jié)點(diǎn),看一下這個(gè)函數(shù)

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結(jié)尾處major = -1;if (operation == OP_add) {strcpy(path_end, "/dev"); // 往path結(jié)尾處拷貝“/dev”,這時(shí)path=/sys/class/test/test_dev/devlen = open_read_close(path, path_end + 1, SCRATCH_SIZE - 1); // 打開(kāi)并讀取/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獲得主次設(shè)備號(hào)dbg1("dev %u,%u", major, minor);} else {major = -1;}}if (operation == OP_add && major >= 0) // 如果是add,即創(chuàng)建節(jié)點(diǎn)mknod(node_name, rule->mode | type, makedev(major, minor)) // 最終用mknod函數(shù)在/dev下創(chuàng)建設(shè)備節(jié)點(diǎn)if (operation == OP_remove && major >= -1) // 如果是remove,即刪除節(jié)點(diǎn)unlink(node_name);
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26

創(chuàng)建節(jié)點(diǎn)最后無(wú)非還是調(diào)用mknod,當(dāng)然在class_create和device_create自動(dòng)創(chuàng)建設(shè)備節(jié)點(diǎn)時(shí),也會(huì)在/sys/class下自動(dòng)創(chuàng)建
和刪除相關(guān)設(shè)備類和設(shè)備,這是sysfs的驅(qū)動(dòng)內(nèi)容,這里不講


總結(jié)

以上是生活随笔為你收集整理的mdev详解的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問(wèn)題。

如果覺(jué)得生活随笔網(wǎng)站內(nèi)容還不錯(cuò),歡迎將生活随笔推薦給好友。