作者:wowo

发布于:2014-3-10 20:39

分类:统一设备模型

http://www.wowotech.net/device_model/uevent.html

Uevent

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

该机制通常是用来支持热拔插设备的,例如U盘插入后,USB相关的驱动软件会动态创建用于表示该U盘的device结构(相应的也包括其中的kobject),并告知用户空间程序,为该U盘动态的创建/dev/目录下的设备节点,更进一步,可以通知其它的应用程序,将该U盘设备mount到系统中,从而动态的支持该设备。

Uevent在kernel中的位置

下面图片描述了Uevent模块在内核中的位置:

由此可知,Uevent的机制是比较简单的,设备模型中任何设备有事件需要上报时,会触发Uevent提供的接口。Uevent模块准备好上报事件的格式后,可以通过两个途径把事件上报到用户空间:

  • 一种是通过kmod模块,直接调用用户空间的可执行文件;
  • 另一种是通过netlink通信机制,将事件从内核空间传递给用户空间。

Uevent的内部逻辑解析

Source Code位置

Uevent的代码比较简单,主要涉及kobject.h和kobject_uevent.c两个文件,如下:

  • include/linux/kobject.h
  • lib/kobject_uevent.c

数据结构描述

kobject.h定义了uevent相关的常量和数据结构。

kobject_action

/* include/linux/kobject.h, line 50 */
enum kobject_action {
KOBJ_ADD,
KOBJ_REMOVE,
KOBJ_CHANGE,
KOBJ_MOVE,
KOBJ_ONLINE,
KOBJ_OFFLINE,
KOBJ_MAX
};

kobject_action定义了event的类型,包括:

  • ADD/REMOVE:Kobject(或上层数据结构)的添加/移除事件。
  • ONLINE/OFFLINE:Kobject(或上层数据结构)的上线/下线事件,其实是是否使能。
  • CHANGE:Kobject(或上层数据结构)的状态或者内容发生改变。
  • MOVE:Kobject(或上层数据结构)更改名称或者更改Parent(意味着在sysfs中更改了目录结构)。

CHANGE,如果设备驱动需要上报的事件不再上面事件的范围内,或者是自定义的事件,可以使用该event,并携带相应的参数。

kobj_uevent_env

/* include/linux/kobject.h, line 31 */
#define UEVENT_NUM_ENVP 32 /* number of env pointers */
#define UEVENT_BUFFER_SIZE 2048 /* buffer for the variables */ /* include/linux/kobject.h, line 116 */
struct kobj_uevent_env {
char *envp[UEVENT_NUM_ENVP];
int envp_idx;
char buf[UEVENT_BUFFER_SIZE];
int buflen;
};

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

  • envp:指针数组,用于保存每个环境变量的地址,最多可支持的环境变量数量为UEVENT_NUM_ENVP。
  • envp_idx:用于访问环境变量指针数组的index。
  • buf:保存环境变量的buffer,最大为UEVENT_BUFFER_SIZE。
  • buflen:访问buf的变量。

kset_uevent_ops

/* include/linux/kobject.h, line 123 */
struct kset_uevent_ops {
int (* const filter)(struct kset *kset, struct kobject *kobj);
const char *(* const name)(struct kset *kset, struct kobject *kobj);
int (* const uevent)(struct kset *kset, struct kobject *kobj,
struct kobj_uevent_env *env);
};

kset_uevent_ops是为kset量身订做的一个数据结构,里面包含filter和uevent两个回调函数,用处如下:

filter,当任何Kobject需要上报uevent时,它所属的kset可以通过该接口过滤,阻止不希望上报的event,从而达到从整体上管理的目的。

name,该接口可以返回kset的名称。如果一个kset没有合法的名称,则其下的所有Kobject将不允许上报uvent

uevent,当任何Kobject需要上报uevent时,它所属的kset可以通过该接口统一为这些event添加环境变量。因为很多时候上报uevent时的环境变量都是相同的,因此可以由kset统一处理,就不需要让每个Kobject独自添加了。

内部动作

通过kobject.h,uevent模块提供了如下的API(这些API的实现是在"lib/kobject_uevent.c”文件中):

/* include/linux/kobject.h, line 206 */
int kobject_uevent(struct kobject *kobj, enum kobject_action action);
int kobject_uevent_env(struct kobject *kobj, enum kobject_action action,
char *envp[]); __printf(2, 3)
int add_uevent_var(struct kobj_uevent_env *env, const char *format, ...); int kobject_action_type(const char *buf, size_t count,
enum kobject_action *type);

kobject_uevent_env

以envp为环境变量,上报一个指定action的uevent。环境变量的作用是为执行用户空间程序指定运行环境。具体动作如下:

1、查找kobj本身或者其parent是否从属于某个kset,如果不是,则报错返回(注2:由此可以说明,如果一个kobject没有加入kset,是不允许上报uevent的)

2、查看kobj->uevent_suppress是否设置,如果设置,则忽略所有的uevent上报并返回(注3:由此可知,可以通过Kobject的uevent_suppress标志,管控Kobject的uevent的上报)

3、如果所属的kset有uevent_ops->filter函数,则调用该函数,过滤此次上报(注4:这佐证了3.2小节有关filter接口的说明,kset可以通过filter接口过滤不希望上报的event,从而达到整体的管理效果)

4、判断所属的kset是否有合法的名称(称作subsystem,和前期的内核版本有区别),否则不允许上报uevent

5、分配一个用于此次上报的、存储环境变量的buffer(结果保存在env指针中),并获得该Kobject在sysfs中路径信息(用户空间软件需要依据该路径信息在sysfs中访问它)

6、调用add_uevent_var接口(下面会介绍),将Action、路径信息、subsystem等信息,添加到env指针中

7、如果传入的envp不空,则解析传入的环境变量中,同样调用add_uevent_var接口,添加到env指针中

8、如果所属的kset存在uevent_ops->uevent接口,调用该接口,添加kset统一的环境变量到env指针

9、根据ACTION的类型,设置kobj->state_add_uevent_sent和kobj->state_remove_uevent_sent变量,以记录正确的状态

10、调用add_uevent_var接口,添加格式为"SEQNUM=%llu”的序列号

11、如果定义了"CONFIG_NET”,则使用netlink发送该uevent

12、以uevent_helper、subsystem以及添加了标准环境变量(HOME=/,PATH=/sbin:/bin:/usr/sbin:/usr/bin)的env指针为参数,调用kmod模块提供的call_usermodehelper函数,上报uevent。

其中uevent_helper的内容是由内核配置项CONFIG_UEVENT_HELPER_PATH(位于./drivers/base/Kconfig)决定的(可参考lib/kobject_uevent.c, line 32),该配置项指定了一个用户空间程序(或者脚本),用于解析上报的uevent,例如"/sbin/hotplug”。

call_usermodehelper的作用,就是fork一个进程,以uevent为参数,执行uevent_helper。

kobject_uevent

和kobject_uevent_env功能一样,只是没有指定任何的环境变量。

add_uevent_var

以格式化字符的形式(类似printf、printk等),将环境变量copy到env指针中。

kobject_action_type

将enum kobject_action类型的Action,转换为字符串。

指定处理uevent的用户空间程序

上面介绍kobject_uevent_env的内部动作时,有提到:Uevent模块通过Kmod上报Uevent时,会通过call_usermodehelper函数,调用用户空间的可执行文件(或者脚本,简称uevent helper )处理该event。而该uevent helper的路径保存在uevent_helper数组中。

可以在编译内核时,通过CONFIG_UEVENT_HELPER_PATH配置项,静态指定uevent helper。但这种方式会为每个event fork一个进程,随着内核支持的设备数量的增多,这种方式在系统启动时将会是致命的(可以导致内存溢出等)。

因此只有在早期的内核版本中会使用这种方式,现在内核不再推荐使用该方式。因此内核编译时,需要把该配置项留空。

在系统启动后,大部分的设备已经ready,可以根据需要,重新指定一个uevent helper,以便检测系统运行过程中的热拔插事件。这可以通过把helper的路径写入到/sys/kernel/uevent_helper文件中实现。实际上,内核通过sysfs文件系统的形式,将uevent_helper数组开放到用户空间,供用户空间程序修改访问。

具体可参考"./kernel/ksysfs.c”中相应的代码,这里不再详细描述。

Linux设备模型:3、Uevent的更多相关文章

  1. Linux 设备模型浅析之 uevent 篇(2)

    Linux 设备模型浅析之 uevent 篇 本文属本人原创,欢迎转载,转载请注明出处.由于个人的见识和能力有限,不可能面 面俱到,也可能存在谬误,敬请网友指出,本人的邮箱是 yzq.seen@gma ...

  2. Linux设备模型(总线、设备、驱动程序和类)

    Linux设备驱动程序学习(13) -Linux设备模型(总线.设备.驱动程序和类)[转] 文章的例子和实验使用<LDD3>所配的lddbus模块(稍作修改). 提示:在学习这部分内容是一 ...

  3. Linux设备模型 学习总结

    看LDD3中设备模型一章,觉得思维有些混乱.这里从整体的角度来理理思路.本文从四个方面来总结一些内容: 1.底层数据结构:kobject,kset.2.linux设备模型层次关系:bus_type,d ...

  4. Linux设备模型——设备驱动模型和sysfs文件系统解读

    本文将对Linux系统中的sysfs进行简单的分析,要分析sysfs就必须分析内核的driver-model(驱动模型),两者是紧密联系的.在分析过程中,本文将以platform总线和spi主控制器的 ...

  5. linux设备模型:扩展篇

    Linux设备模型组件:总线  一.定义:总线是不同IC器件之间相互通讯的通道;在计算机中,一个总线就是处理器与一个或多个不同外设之间的通讯通道;为了设备模型的目的,所有的设备都通过总线相互连接,甚至 ...

  6. Linux设备模型:基础篇

    linux提供了新的设备模型:总线(bus).设备(device).驱动(driver).其中总线是处理器与设备之间通道,在设备模型中,所有的设备都通过总线相连:设备是对于一个设备的详细信息描述,驱动 ...

  7. Linux设备模型(总结)

    转:http://www.360doc.com/content/11/1219/16/1299815_173418267.shtml 看了一段时间的驱动编程,从LDD3的hello wrod到后来的字 ...

  8. Linux设备模型(热插拔、mdev 与 firmware)【转】

    转自:http://www.cnblogs.com/hnrainll/archive/2011/06/10/2077469.html 转自:http://blog.chinaunix.net/spac ...

  9. 【原创】linux设备模型之kset/kobj/ktype分析

    背 景 Read the fucking source code! --By 鲁迅 A picture is worth a thousand words. --By 高尔基 说明: Kernel版本 ...

  10. linux设备模型_转

    建议原博文查看,效果更佳. 转自:http://www.cnblogs.com/wwang/category/269350.html Linux设备模型 (1) 随着计算机的周边外设越来越丰富,设备管 ...

随机推荐

  1. vue点击旋转,再点击复原

    效果: 1.html.通过绑定t值控制不同的class名, 原图是右边方向的箭头 <img class="right" v-if="item.t" src ...

  2. 【GUI软件】小红书详情数据批量采集,含笔记内容、转评赞藏等,支持多笔记同时采集!

    目录 一.背景介绍 1.1 爬取目标 1.2 演示视频 1.3 软件说明 二.代码讲解 2.1 爬虫采集模块 2.2 软件界面模块 2.3 日志模块 三.获取源码及软件 一.背景介绍 1.1 爬取目标 ...

  3. 2019年最新前端面试题,js程序设计题

    都说机会是留给有准备的人的. 一年之计在于春,面对众多的前端技术,需要时刻充电自己. 我现在整理一些前端js面试程序题. 1.判断一个字符串中出现最多的字符,并计算出现的次数? 2.用css伪类实现下 ...

  4. js原生小知识

    new Array(3).fill(0) 就会生成3个元素为0的数组

  5. IDEA社区版(IDEA Community Edition)创建Springboot父子项目

    1. 因为社区办不支持使用spring Spring Initializr 的方式创建项目, 但是我们可以考虑使用别的方式达到效果: 创建方式有3种: 第一种:使用https://start.spri ...

  6. prometheus使用3

    不错链接 60.Prometheus-alertmanager.邮件告警配置   https://www.cnblogs.com/ygbh/p/17306539.html 服务发现 基于文件的服务发现 ...

  7. go goroutine pool设计

    推荐一遍由浅入深简绍goroutine pool设计的方案.https://strikefreedom.top/high-performance-implementation-of-goroutine ...

  8. WPF 实现触摸滑动功能

    自定义ScrollViewer的Touch事件--触摸上下移动ScrollViewer滚动到指定位置   1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 ...

  9. 【WPF】 BasedOn的用法

    BasedOn 用于样式的继承. 这里的已经继承了一个样式 此时,我们想在Resource中让他附加新的样式,但是这样不成功 修改如下: 去掉了之前的样式选择 我们使用BasedOn让其叠加样式

  10. 互联网软件的安装包界面设计-Inno setup

    https://blog.csdn.net/oceanlucy/article/details/50033773 "安装界面太丑了,不堪入目!" "这界面应该属于20年代 ...