class_device_create
class_device_register
class_device_add
kobject_uevent(&class_dev->kobj, KOBJ_ADD);
kobject_uevent_env
action_string = action_to_string(action);
uevent_ops->filter
subsystem = uevent_ops->name(kset, kobj);
envp = kzalloc(NUM_ENVP * sizeof (char *), GFP_KERNEL);
buffer = kmalloc(BUFFER_SIZE, GFP_KERNEL);
devpath = kobject_get_path(kobj, GFP_KERNEL);
envp[i++] = "HOME=/";...
#if defined(CONFIG_NET)
/* send netlink message */
if (uevent_helper[0]) {
char *argv [3];
argv [0] = uevent_helper;
argv [1] = (char *)subsystem;
argv [2] = NULL;
call_usermodehelper (argv[0], argv, envp, 0);
}
关于uevent_helper(在Source Insight中搜索)
1.对/sys/kernel/uevent_helper 文件的读写就是对uevent_helper的读写
linux/kernel/ksysfs.c
static ssize_t uevent_helper_show(struct kset *kset, char *page)
{
return sprintf(page, "%s\n", uevent_helper);
}
static ssize_t uevent_helper_store(struct kset *kset, const char *page, size_t count)
{
if (count+1 > UEVENT_HELPER_PATH_LEN)
return -ENOENT;
memcpy(uevent_helper, page, count);
uevent_helper[count] = '\0';
if (count && uevent_helper[count-1] == '\n')
uevent_helper[count-1] = '\0';
return count;
}
KERNEL_ATTR_RW(uevent_helper);//声明一个subsys_attribute变量 uevent_helper_attr
//它对应sysfs 中的一个文件,文件名是uevent_helper
//它的读写函数分别是uevent_helper_show,uevent_helper_store
#define KERNEL_ATTR_RW(_name) \
static struct subsys_attribute _name##_attr = __ATTR(_name, 0644, _name##_show, _name##_store)
#define __ATTR(_name,_mode,_show,_store) { \
.attr = {.name = __stringify(_name), .mode = _mode, .owner = THIS_MODULE }, \
.show = _show, \
.store = _store, \
}
int error = subsystem_register(&kernel_subsys);//注册子系统
//kernel_subsys的创建使用decl_subsys宏
decl_subsys(kernel, NULL, NULL);//创建了/sys/kernel目录
error = sysfs_create_group(&kernel_subsys.kobj,&kernel_attr_group);//在子系统中创建一组文件
static struct attribute_group kernel_attr_group = {
.attrs = kernel_attrs,
};
static struct attribute * kernel_attrs[] = {
#if defined(CONFIG_HOTPLUG) && defined(CONFIG_NET)
&uevent_seqnum_attr.attr,
&uevent_helper_attr.attr,//uevent_helper文件
#endif
#ifdef CONFIG_KEXEC
&kexec_loaded_attr.attr,
&kexec_crash_loaded_attr.attr,
#endif
NULL
};
2.对/proc/sys/kernel/hotplug 文件的读写就是对uevent_helper的读写
/linux/kernel/sysctl.c
#if defined(CONFIG_HOTPLUG) && defined(CONFIG_NET)
{
.ctl_name = KERN_HOTPLUG,
.procname = "hotplug",//创建/proc/sys/kernel/hotplug文件
.data = &uevent_helper,//对文件读写的数据对象,读写/proc/sys/kernel/hotplug就是对uevent_helper的读写
.maxlen = UEVENT_HELPER_PATH_LEN,
.mode = 0644,
.proc_handler = &proc_dostring,
.strategy = &sysctl_string,
},
所以,在使用mdev时,在/etc/init.d/rc.S 写入 echo "/sbin/mdev" > /proc/sys/kernel/hotplug
和 写入 echo "/sbin/mdev" > /sys/kernel/uevent_helper作用应该是相同的