作者: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. 第一章 Jenkins安装配置

    Jenkins官网 # 官网: https://www.jenkins.iohttps://www.jenkins.io/zh/ # docker安装: https://www.jenkins.io/ ...

  2. Codeforces Round 934 2D/1B

    Link 场上思路出的最快的一题,但没调出来. 反着考虑全为回文串需满足哪些情况. 若 \(k = 1\),没有限制条件. 若 \(k = 2\),对于任意三个位置 _ _ _,先填 \(x\) \( ...

  3. 最好用的AI换脸软件,rope下载介绍(支持cpu)

    随着AI技术的广泛运用,市面上的换脸软件也多了起来,今天给各位介绍其中的王者Rope! 先上两个动图,给大伙看看效果 rope是如何实现这种自然的效果呢?这得益于机器学习技术的不断发展,rope经过深 ...

  4. 微信小程序使用微信云托管添加自定义域名并转发到pexels.com

    背景:我要在小程序上显示pexels.com上的图片,然后我得先把pexels.com的域名添加到小程序的request合法域名中,但是pexels.com是国外的,在国内没有备案所以添加不了.解决方 ...

  5. 前端 PM 分享:PM 需要做的事情

    个人经验分享 PM PM( Project Manager ) PM( Product Manager ) 一.什么情况下需要前端担任 PM? 在我之前遇到的项目中,大多数项目的 PM 是由后端/产品 ...

  6. 4G 信令中的 PCO 字段

    目录 文章目录 目录 Protocol Configuration Option Protocol Configuration Option PCO(Protocol Configuration Op ...

  7. Java RMI遇到的Connection refused to Host: 127.x.x.x/192.x.x.x/10.x.x.x问题解决方法

    问题故障解决记录 -- Java RMI Connection refused to host: x.x.x.x .... 在学习JavaRMI时,我遇到了以下情况 问题原因:可能大家的host是10 ...

  8. Java应用的优雅停机

    一. 优雅停机的概念 优雅停机一直是一个非常严谨的话题,但由于其仅仅存在于重启.下线这样的部署阶段,导致很多人忽视了它的重要性,但没有它,你永远不能得到一个完整的应用生命周期,永远会对系统的健壮性持怀 ...

  9. Visual Studio编程效率提升技巧集(提高.NET编程效率)

    前言 本文大姚将为你介绍一些Visual Studio的使用技巧和建议,旨在帮助.NET开发者更加高效地利用Visual Studio进行编程工作.无论你是.NET初学者还是经验丰富的.NET开发者, ...

  10. numpy基础--通用函数:快速的元素级数组函数

    以下代码的前提:import numpy as np 通用函数(即ufunc)是一种对narray中的数组执行元素级运算的函数.可以看作简单函数(接受一个或多个标量值,并产生一个或多个标量值)的矢量化 ...