Linux设备模型(3)_Uevent

作者:wowo 发布于:2014-3-10 20:39 分类:统一设备模型

1. Uevent的功能

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

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

2. Uevent在kernel中的位置

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

由此可知,Uevent的机制是比较简单的,设备模型中任何设备有事件需要上报时,会触发Uevent提供的接口。Uevent模块准备好上报事件的格式后,可以通过两个途径把事件上报到用户空间:一种是通过kmod模块,直接调用用户空间的可执行文件;另一种是通过netlink通信机制,将事件从内核空间传递给用户空间。

注1:有关kmod和netlink,会在其它文章中描述,因此本文就不再详细说明了。

3. Uevent的内部逻辑解析

3.1 Source Code位置

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

  • include/linux/kobject.h
  • lib/kobject_uevent.c
3.2 数据结构描述

kobject.h定义了uevent相关的常量和数据结构,如下:

  • kobject_action
 1: /* include/linux/kobject.h, line 50 */
 2: enum kobject_action {   
 3:     KOBJ_ADD,
 4:     KOBJ_REMOVE,    
 5:     KOBJ_CHANGE, 
 6:     KOBJ_MOVE,
 7:     KOBJ_ONLINE, 
 8:     KOBJ_OFFLINE,
 9:     KOBJ_MAX 
 10: };

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

ADD/REMOVE,Kobject(或上层数据结构)的添加/移除事件。

ONLINE/OFFLINE,Kobject(或上层数据结构)的上线/下线事件,其实是是否使能。

CHANGE,Kobject(或上层数据结构)的状态或者内容发生改变。

MOVE,Kobject(或上层数据结构)更改名称或者更改Parent(意味着在sysfs中更改了目录结构)。

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

  • kobj_uevent_env
 1: /* include/linux/kobject.h, line 31 */
 2: #define UEVENT_NUM_ENVP         32 /* number of env pointers */
 3: #define UEVENT_BUFFER_SIZE      2048 /* buffer for the variables */
 4:  
 5: /* include/linux/kobject.h, line 116 */
 6: struct kobj_uevent_env {
 7:     char *envp[UEVENT_NUM_ENVP];
 8:     int envp_idx;
 9:     char buf[UEVENT_BUFFER_SIZE];
 10:    int buflen;
 11: };

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

envp,指针数组,用于保存每个环境变量的地址,最多可支持的环境变量数量为UEVENT_NUM_ENVP。

envp_idx,用于访问环境变量指针数组的index。

buf,保存环境变量的buffer,最大为UEVENT_BUFFER_SIZE。

buflen,访问buf的变量。

  • kset_uevent_ops
 1: /* include/linux/kobject.h, line 123 */
 2: struct kset_uevent_ops {
 3:     int (* const filter)(struct kset *kset, struct kobject *kobj);
 4:     const char *(* const name)(struct kset *kset, struct kobject *kobj);
 5:     int (* const uevent)(struct kset *kset, struct kobject *kobj,
 6:                         struct kobj_uevent_env *env);
 7: };

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

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

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

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

3.3 内部动作

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

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

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

  • 查找kobj本身或者其parent是否从属于某个kset,如果不是,则报错返回(注2:由此可以说明,如果一个kobject没有加入kset,是不允许上报uevent的)
  • 查看kobj->uevent_suppress是否设置,如果设置,则忽略所有的uevent上报并返回(注3:由此可知,可以通过Kobject的uevent_suppress标志,管控Kobject的uevent的上报)
  • 如果所属的kset有uevent_ops->filter函数,则调用该函数,过滤此次上报(注4:这佐证了3.2小节有关filter接口的说明,kset可以通过filter接口过滤不希望上报的event,从而达到整体的管理效果)
  • 判断所属的kset是否有合法的名称(称作subsystem,和前期的内核版本有区别),否则不允许上报uevent
  • 分配一个用于此次上报的、存储环境变量的buffer(结果保存在env指针中),并获得该Kobject在sysfs中路径信息(用户空间软件需要依据该路径信息在sysfs中访问它)
  • 调用add_uevent_var接口(下面会介绍),将Action、路径信息、subsystem等信息,添加到env指针中
  • 如果传入的envp不空,则解析传入的环境变量中,同样调用add_uevent_var接口,添加到env指针中
  • 如果所属的kset存在uevent_ops->uevent接口,调用该接口,添加kset统一的环境变量到env指针
  • 根据ACTION的类型,设置kobj->state_add_uevent_sent和kobj->state_remove_uevent_sent变量,以记录正确的状态
  • 调用add_uevent_var接口,添加格式为"SEQNUM=%llu”的序列号
  • 如果定义了"CONFIG_NET”,则使用netlink发送该uevent
  • 以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的用户空间程序(简称uevent helper)?

上面介绍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”中相应的代码,这里不再详细描述。

原创文章,转发请注明出处。蜗窝科技,www.wowotech.net。

Linux设备模型(3)_Uevent相关推荐

  1. linux设备模型的主要功能,Linux设备模型(3)

    Linux设备模型(3)_Uevent 作者:蜗蜗 发布于:2014-3-10 20:39 分类:统一设备模型 1. Uevent的功能 Uevent是Kobject的一部分,用于在Kobject状态 ...

  2. Linux设备模型_导航篇

    Linux设备模型_导航篇 1. Linux设备模型系列文章说明 2. Linux设备模型系列文章目录 2.0 [Linux内核的整体架构](https://zhuanlan.zhihu.com/p/ ...

  3. Linux设备模型剖析系列之二(uevent、sysfs)

    CSDN链接: Linux设备模型剖析系列一(基本概念.kobject.kset.kobj_type) Linux设备模型剖析系列之二(uevent.sysfs) Linux设备模型剖析系列之三(de ...

  4. 学习《Linux设备模型浅析之设备篇》笔记(一)

    最近在学习Linux设备模型,前面几篇文章也是读这篇的时候遇到问题,然后为了搞清楚先转去摸索才写出来的. 当然了,刚开始是先读到<Linux那些事儿之我是Sysfs>,搞不清楚才去读的&l ...

  5. Linux设备模型(热插拔、mdev 与 firmware)

    转自:http://blog.chinaunix.net/space.php?uid=20543672&do=blog&cuid=460882 热插拔 有 2 个不同角度来看待热插拔: ...

  6. Linux通常把设备对象抽象为,linux 设备模型(1)

    设备模型(一) 一.概述 从2.6内核引入了sysfs文件系统,与proc, devfs, devpty同类别,属于虚拟的文件系统.目的是展示设备驱动模型中各组件的层次关系,第一层目录:block, ...

  7. Linux 设备模型之 (kobject、kset 和 Subsystem)(二)

    1.kobject 结构 在Linux内核里,kobject是组成Linux设备模型的基础,一个kobject对应sysfs里的一个目录.从面向对象的角度来说,kobject可以看作是所有设备对象的基 ...

  8. Linux设备模型组件-类设备-设备类及subsystem

    Linux设备模型   一.sysfs文件系统: sysfs文件系统是Linux2.6内核引入的,它被看成是与proc.devfs和devpty等同类别的文件系统,sysfs文件系统也是一个虚拟文件系 ...

  9. Linux设备模型(总结)

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

最新文章

  1. bread是可数还是不可数_不可数名词用法详解,小小名词大作用,英语想打好基础必学的词性...
  2. nebual的图数据结构
  3. JVM-程序计数器02
  4. Madgwick算法详细解读
  5. Map接口与学习系列(一)
  6. python 将数组转化8位整数_int对象,永不溢出的整数
  7. Jan 12 - Delete Node in a Linked List; Data Structure; Linked List; Pointer;
  8. AGC004(A~E)
  9. aliyun gradle 代理_android studio gradle国内代理设置
  10. C# 泛型2---排序
  11. 顺序容器和关联容器添加新元素方法详解
  12. php时间格式转换成时间戳,php把时间格式转换为时间戳的案例
  13. 流程图中的实线_教你如何正确看懂工艺流程图
  14. 国家药品不良反应监测中心 ADR 电子传输EDI解决方案
  15. java回忆录—神奇的进制世界
  16. 如何保证用log4J 写log 的时间和系统设置的timezone 保持一致
  17. 图像滤镜艺术---保留细节的磨皮滤镜之PS实现
  18. YOLOV3 网络结构学习笔记
  19. Caused by: java.lang.ClassNotFoundException: org.aspectj.weaver.reflect.ReflectionWorld$ReflectionWo
  20. 浅谈getaddrinfo

热门文章

  1. 用python发送put请求
  2. 中毒了 电脑都是.php,Linux_电脑中毒Linux find命令快速查找中毒文件教程,  电脑中毒是不可避免的,L - phpStudy...
  3. 扫码支付(原生支付)-模式一和模式二
  4. 两个向量构成的平行四边形面积的求解 ————简单技巧
  5. 金融信贷风控实战(二)
  6. swift 学习资料大全
  7. 关于VC中删除非空文件夹
  8. 用 Python 打扑克牌——炸金花
  9. 湖北省教育考试院湖北省人事考试网报名入口报名时间软考报名
  10. 软考的证书含金量高吗?