Linux 设备模型之 Uevent

前言

此文始于 2019-04-02,这是在的第一篇文章,目的是为了练习 markdown语法。先选择一篇文章进行 copy to write,结合目前正在看的内容 android ueventd,选一篇对 uevent 的描述来进行练习。

进展

Linux 设备模型之 Uevent

1. Uevent的功能

uevent 是 Kobject 的一部分,用于在 Kobject 状态发生改变时,例如增加、移除等,通知用户空间程序,用户空间程序接收到这样的时间后,会做出相应的处理。该机制通常是用来支持热插拔设备的,例如U盘插入后,USB相关 的驱动软件会动态创建用于表示该 U盘的 device 结构(相应的也包括其中的 kobject),并告知用户空间程序,为该 U盘动态的创建/dev/目录下的设备节点,更进一步,可以通知其他应用程序,将该 U盘 mount 到系统中,从而动态的支持该设备。

2. sysfs 概述

设备节点是为设备驱动所创建的,而设备device和驱动driver都是以链表的形式连接在总线bus上的,而设备——驱动——总线的更上一层就是sysfs层。
sysfs是一个内存文件系统,它把连接在系统上的设备和总线组织成为一个分级的文件,用户空间的程序同样可以利用这些信息,以实现和内核的交互。sysfs文件系统是当前系统上实际设备树的一个直观反映,用mount命令查看可以得知其挂载在“/sys”下 sysfs on /sys type sysfs (rw,seclabel,relatime))。当一个kobject被创建的时候,对应的sys文件和目录也就被创建了;其主要文件目录如下:

  • /sys/block 存放块设备,提供以设备名(如sda)到/sys/devices的符号链接
  • /sys/bus 按总线类型分类,在某个总线目录之下可以找到连接该总线的设备的符号链接,指向/sys/devices。某个总线目录之下的 drivers 目录包含了该总线所需的所有驱动的符号链接对应kernel中的 struct bus_type
  • /sys/class 按设备功能分类,如输入设备在 /sys/class/input 之下,图形设备在 /sys/class/graphics 之下,是指向 /sys/devices 目录下对应设备的符号链接对应kernel中的 struct class
  • /sys/dev 按设备驱动程序分层(字符设备/块设备),提供以major:minor为名到 /sys/devices 的符号链接对应kernel中的 struct device_driver
  • /sys/devices 包含所有被发现的注册在各种总线上的各种物理设备。
    所有的物理设备都按其在总线上的拓扑结构来显示,除了 platform devices 和 system devices 。platform devices一般是挂在芯片内部高速或者低速总线上的各种控制器和外设,能被CPU直接寻址。system devices不是外设,他是芯片内部的核心结构,比如CPU,timer等,他们一般没有相关的driver,但是会有一些体系结构相关的代码来配置他们对应kernel中的 struct device
    上面展现了在sys目录下总线,设备,驱动和类所对应的文件,而他们的区别为:
  • device用于描述各种设备,其保存了所有的设备信息
  • driver 用于驱动 device ,其保存了所有能够被它所驱动的设备链表。
  • bus 是连接 CPU 和 device 的桥梁,其保存了所有挂载在它上面的设备链表和驱动这些设备的驱动链表。
  • class 用于描述一类 device ,其保存了所有该类 device 的设备链表。

创建设备节点文件的过程

下图描述了设备节点文件的创建过程:


Linux 设备模型之 Uevent_第1张图片
创建设备节点文件的整个过程

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

  • 通过 kmod 模块,直接调动用户空间的可执行文件
  • 通过 netlink 通信机制,将事件从内核空间传递给用户空间
    PS: 目前多采用 netlink 通信机制,ueventd 也是采用 netlink机制创建 socket 与 kernel 进行通信。
    netlink基本概念
    用户空间程序接收到上报的uevent之后就可以根据其event类型进行相应操作了。

uevent的数据结构描述

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

kernel/lib/kobject_uevent.c  
/* the strings here must match the enum in include/linux/kobject.h */  
static const char *kobject_actions[] = {  
    [KOBJ_ADD] =        "add",  
    [KOBJ_REMOVE] =     "remove",  
    [KOBJ_CHANGE] =     "change",  
    [KOBJ_MOVE] =       "move", //暂未看到ueventd有具体处理  
    [KOBJ_ONLINE] =     "online",  
    [KOBJ_OFFLINE] =    "offline",//暂未看到ueventd有具体处理  
};  
/* 
 * The actions here must match the index to the string array 
 * in lib/kobject_uevent.c 
 * 
 * Do not add new actions here without checking with the driver-core 
 * maintainers. Action strings are not meant to express subsystem 
 * or device specific properties. In most cases you want to send a 
 * kobject_uevent_env(kobj, KOBJ_CHANGE, env) with additional event 
 * specific variables added to the event environment. 
 */  
kernel/include/linux/kobject.h  
 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,并携带相应的参数。

小结

以上就是 uevent 的基础知识,作为了解 ueventd 前的准备。

期望

在后续日子可以完全使用 markdown 语言誊写文档

参考的文章

Linux设备模型之 Uevent

你可能感兴趣的:(Linux 设备模型之 Uevent)