Linux设备模型分析之(五):uevent

Linux设备模型分析之(一):设备模型核心
Linux设备模型分析之(二):设备模型的基石
Linux设备模型分析之(三):sysfs
Linux设备模型分析之(四):class
Linux设备模型分析之(五):uevent

uevent是kobject的一部分,用于在kobject状态发生改变时,例如增加、移除等,通知用户空间程序。用户空间程序收到这样的事件后,会做相应的处理。

该机制通常是用来支持热拔插设备的,例如鼠标插入后,鼠标相关的驱动软件会动态创建用于表示该鼠标的device结构(相应的也包括其中的kobject),并告知用户空间程序,为该鼠标动态的创建设备节点。
在这里插入图片描述
uevent的机制是比较简单的,设备模型中任何设备有事件需要上报时,调用uevent提供的接口。uevent模块准备好上报事件的格式后,可以通过两个途径把事件上报到用户空间:一种是通过kmod模块,直接调用用户空间的可执行文件;另一种是通过netlink通信机制,将事件从内核空间传递给用户空间。
在这里插入图片描述
其中,netlink是一种socket,专门用来进行内核空间和用户空间的通信;kmod是管理内核模块的工具集,类似busybox,我们熟悉的lsmod,insmod等是指向kmod的链接。

kobject事件有:

enum kobject_action {
	KOBJ_ADD,    //kobject的增添事件
	KOBJ_REMOVE, //kobject的移除事件
	KOBJ_CHANGE, 
	KOBJ_MOVE,
	KOBJ_ONLINE,
	KOBJ_OFFLINE,
	KOBJ_MAX
};

任何kobject需要上报事件时,都要调用它所从属的kset的uevent_ops操作接口,因此,如果一个kobject不属于任何kset时,是不允许发送事件。

struct kset {
	......

	//该kset的uevent操作函数集,
	const struct kset_uevent_ops *uevent_ops;  
};


struct kset_uevent_ops {
	/* 当任何kobject需要上报uevent时,它所属的kset可以通过该接口过滤,阻止不希望上报的event,
     从而达到从整体上管理的目的 
   */
	int (* const filter)(struct kset *kset, struct kobject *kobj);

	//该接口可以返回kset的名称
	const char *(* const name)(struct kset *kset, struct kobject *kobj);

	//当任何kobject需要上报uevent时,调用该接口
	int (* const uevent)(struct kset *kset, struct kobject *kobj,
		      struct kobj_uevent_env *env);
};

前面有提到过,在利用kmod向用户空间上报event事件时,会直接执行用户空间的可执行文件。而在Linux系统,可执行文件的执行,依赖于环境变量,因此kobj_uevent_env用于组织此次事件上报时的环境变量。

struct kobj_uevent_env {
	char *argv[3];                // argv[0]指向用户空间的可执行文件的路径
	char *envp[UEVENT_NUM_ENVP];  //指针数组,用于保存每个环境变量的地址
	int envp_idx;                 //用于访问环境变量指针数组的index
	char buf[UEVENT_BUFFER_SIZE]; //保存环境变量的buffer
	int buflen;
};

kobject_uevent函数执行流程如下:
在这里插入图片描述
怎么指定处理uevent的用户空间程序?在kobject_uevent函数中,会调用到init_uevent_argv函数:

#ifdef CONFIG_UEVENT_HELPER
char uevent_helper[UEVENT_HELPER_PATH_LEN] = CONFIG_UEVENT_HELPER_PATH;
#endif


static int init_uevent_argv(struct kobj_uevent_env *env, const char *subsystem)
{
	int len;

	......
	
	env->argv[0] = uevent_helper;    //用户空间程序程序路径
	env->argv[1] = &env->buf[env->buflen];
	env->argv[2] = NULL;

	......

	return 0;
}

可见,可在编译内核时,通过CONFIG_UEVENT_HELPER_PATH配置项,静态指定。
也可以动态指定如(/sbin/mdev为用户空间程序):

echo /sbin/mdev > /sys/kernel/uevent_helper 
或
echo /sbin/mdev > /proc/sys/kernel/hotplug

mdev

mdev是构建在linux的sysfs之上的,是一个用户程序,它能够根据系统中的硬件设备的状态动态更新设备文件。mdev是busybox自带的一个简化版的udev,它比udev占用的内存更小,因此更适合嵌入式系统的应用。

mdev原理
(1)执行mdev -s命令时,mdev会扫描/sys/class这个目录下所有class,如/sys/class/block。block class下的设备有dev属性文件的话,则以包含该dev属性文件的目录名为设备文件名,在/dev目录下创建相应的设备文件。

如下图,block class下有多个设备:
在这里插入图片描述
看看loop0这个设备有没dev属性文件:
在这里插入图片描述
dev属性文件保存着主次设备号,7为主设备号,0为次设备号,如果执行mdev -s命令,那么在/dev目录下会生成name为loop0的设备文件:
在这里插入图片描述
(2)当mdev因uevnet事件被调用时,mdev通过由uevent事件传递给它的环境变量获取到:引起该uevent事件的设备action及该设备所在的路径device path(对于上面举动例子,路径为sys/class/block/loop0/)。

然后判断引起该uevent事件的action是什么。若该action是add,即有新设备加入到系统中,不管该设备是虚拟设备还是实际物理设备,mdev都会通过device path路径下的dev属性文件获取到设备编号,然后以device path路径最后一个目录(即包含该dev属性文件的目录)作为设备名,在/dev目录下创建相应的设备文件。若该action是remove,即设备已从系统中移除,则删除/dev目录下以device path路径最后一个目录名称作为文件名的设备文件。如果该action既不是add也不是remove,mdev则什么都不做。

由上面可知,如果我们想在设备加入到系统中或从系统中移除时,由mdev自动地创建和删除设备文件,那么就必须做到以下两点:

  1. 在/sys/class 的某class目录下,创建一个以设备名device_name作为名称的目录
  2. 并且在该device_name目录下还必须包含一个dev属性文件,该dev属性文件以”major:minor\n”形式保存设备号。

回想起驱动程序中想自动创建设备文件,那么:

  1. 调用class_create函数在/sys/class目录下创建一个class;
  2. 在这个class下调用device_create函数创建设备

如下一个例子:
在这里插入图片描述

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值