Home  >  Article  >  System Tutorial  >  Linux device model (3)_Uevent

Linux device model (3)_Uevent

WBOY
WBOYforward
2024-02-11 13:06:17958browse

1. Functions of Uevent

Uevent is part of Kobject and is used to notify user space programs when the state of Kobject changes (such as addition, removal, etc.). After receiving such an event, the user space program will handle it accordingly.

Normally, this mechanism is used to support hot-pluggable devices. For example, when a USB flash drive is inserted, the USB-related driver will dynamically create a device structure (including the corresponding kobject) used to represent the USB flash drive and inform the user space program. This will enable device nodes to be dynamically created in the /dev/ directory. Furthermore, this mechanism can also notify other applications to mount the USB flash drive device into the system, thereby realizing dynamic support for the device.

2. The location of Uevent in the kernel

The following picture describes the location of the Uevent module in the kernel:

Linux device model (3)_Uevent

It can be seen that the mechanism of Uevent is relatively simple. When any device in the device model has an event that needs to be reported, the interface provided by Uevent will be triggered. After the Uevent module prepares the format for reporting the event, it can report the event to the user space through two ways: one is to directly call the executable file of the user space through the kmod module; the other is to use the netlink communication mechanism to transfer the event from Kernel space is passed to user space.

Note 1: Kmod and netlink will be described in other articles, so this article will not explain them in detail.

3. Uevent’s internal logic analysis

3.1 Source Code location

The code of Uevent is relatively simple, mainly involving two files: kobject.h and kobject_uevent.c, as follows:

  • include/linux/kobject.h
  • lib/kobject_uevent.c
3.2 Data structure description

kobject.h defines uevent-related constants and data structures, as follows:

  • 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 defines the type of event, including:

ADD/REMOVE, Kobject (or upper data structure) add/remove event.

ONLINE/OFFLINE, the online/offline event of Kobject (or upper-layer data structure), is actually whether it is enabled or not.

CHANGE, the state or content of Kobject (or upper data structure) changes.

MOVE, Kobject (or upper data structure) changes the name or changes the Parent (meaning the directory structure is changed in sysfs).

CHANGE, if the event that the device driver needs to report is no longer within the scope of the above events, or is a custom event, you can use this event and carry the corresponding parameters.

  • 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: };

As mentioned earlier, when using Kmod to report events to user space, the executable file in user space will be executed directly. In Linux systems, the execution of executable files depends on environment variables, so kobj_uevent_env is used to organize the environment variables when reporting this event.

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。环境变量的作用是为执行用户空间程序指定运行环境。具体动作如下:

  • Find whether kobj itself or its parent belongs to a kset. If not, an error will be reported (Note 2: This can explain that if a kobject does not join a kset, it is not allowed to report uevent)
  • Check whether kobj->uevent_suppress is set. If set, ignore all uevent reports and return (Note 3: It can be seen that the uevent reporting of Kobject can be controlled through the uevent_suppress flag of Kobject)
  • If the kset it belongs to has the uevent_ops->filter function, call this function to filter this report (Note 4: This supports the description of the filter interface in section 3.2. The kset can filter events that do not want to be reported through the filter interface, so as to achieve the overall goal. management effect)
  • Determine whether the kset it belongs to has a legal name (called subsystem, which is different from the previous kernel version), otherwise it is not allowed to report uevent
  • Allocate a buffer to store environment variables for this report (the result is saved in the env pointer), and obtain the path information of the Kobject in sysfs (user space software needs to access it in sysfs based on the path information)
  • Call the add_uevent_var interface (described below) to add Action, path information, subsystem and other information to the env pointer
  • If the incoming envp is not empty, parse the incoming environment variable, also call the add_uevent_var interface, and add it to the env pointer
  • If the kset it belongs to has the uevent_ops->uevent interface, call this interface and add the kset unified environment variables to the env pointer
  • According to the type of ACTION, set the kobj->state_add_uevent_sent and kobj->state_remove_uevent_sent variables to record the correct status
  • Call the add_uevent_var interface and add the serial number in the format of "SEQNUM=%llu"
  • If "CONFIG_NET" is defined, use netlink to send the uevent
  • Taking uevent_helper, subsystem and the env pointer with standard environment variables (HOME=/, PATH=/sbin:/bin:/usr/sbin:/usr/bin) as parameters, call the call_usermodehelper function provided by the kmod module and report uevent.
    The content of uevent_helper is determined by the kernel configuration item CONFIG_UEVENT_HELPER_PATH (located in ./drivers/base/Kconfig) (refer to lib/kobject_uevent.c, line 32). This configuration item specifies a user space program (or script). Use Used to parse the reported uevent, such as "/sbin/hotplug".
    The function of call_usermodehelper is to fork a process, take uevent as a parameter, and execute uevent_helper.

kobject_uevent has the same function as kobject_uevent_env, except that no environment variables are specified.

add_uevent_var, copies the environment variable to the env pointer in the form of formatting characters (similar to printf, printk, etc.).

kobject_action_type, convert the Action of enum kobject_action type into a string.

Explanation: How to specify the user space program (uevent helper for short) that handles uevent?

When introducing the internal actions of kobject_uevent_env above, it was mentioned that when the Uevent module reports Uevent through Kmod, it will call the user space executable file (or script, referred to as \**uevent helper\* through the call_usermodehelper function *) handle the event. The path of the uevent helper is stored in the \**uevent_helper array.

You can statically specify the uevent helper through the CONFIG_UEVENT_HELPER_PATH configuration item when compiling the kernel. However, this method will fork a process for each event. As the number of devices supported by the kernel increases, this method will be fatal when the system starts (can cause memory overflow, etc.). Therefore, this method is only used in early kernel versions, and it is no longer recommended by the kernel. Therefore, when compiling the kernel, you need to leave this configuration item blank.

After the system starts, most of the devices are ready. You can reassign a uevent helper as needed to detect hot plug events during system operation. This can be achieved by writing the helper path to the "/sys/kernel/uevent_helper" file. In fact, the kernel opens the uevent_helper array to user space through the sysfs file system for user space program modification and access. For details, please refer to the corresponding code in "\*\*\*\*./kernel/ksysfs.c" , will not be described in detail here.

The above is the detailed content of Linux device model (3)_Uevent. For more information, please follow other related articles on the PHP Chinese website!

Statement:
This article is reproduced at:lxlinux.net. If there is any infringement, please contact admin@php.cn delete