Uevent는 Kobject의 일부이며 Kobject의 상태가 변경(예: 추가, 제거 등)될 때 사용자 공간 프로그램에 알리는 데 사용됩니다. 이러한 이벤트를 수신한 후 사용자 공간 프로그램은 그에 따라 이를 처리합니다.
일반적으로 이 메커니즘은 핫 플러그 가능 장치를 지원하는 데 사용됩니다. 예를 들어, USB 플래시 드라이브가 삽입되면 USB 관련 드라이버는 USB 플래시 드라이브를 나타내는 데 사용되는 장치 구조(해당 kobject 포함)를 동적으로 생성하고 사용자 공간 프로그램에 알립니다. 이렇게 하면 장치 노드가 /dev/ 디렉터리에 동적으로 생성될 수 있습니다. 또한 이 메커니즘은 USB 플래시 드라이브 장치를 시스템에 마운트하도록 다른 응용 프로그램에 알릴 수도 있으므로 장치에 대한 동적 지원을 실현할 수 있습니다.
다음 그림은 커널에서 Uevent 모듈의 위치를 설명합니다.
Uevent의 메커니즘은 비교적 간단하다는 것을 알 수 있습니다. 장치 모델의 모든 장치에 보고해야 할 이벤트가 있으면 Uevent에서 제공하는 인터페이스가 트리거됩니다. Uevent 모듈이 이벤트 보고 형식을 준비한 후 두 가지 방법을 통해 사용자 공간에 이벤트를 보고할 수 있습니다. 하나는 kmod 모듈을 통해 사용자 공간의 실행 파일을 직접 호출하는 것이고, 다른 하나는 netlink 통신을 사용하는 것입니다. 커널 공간에서 이벤트를 전송하는 메커니즘이 사용자 공간으로 전달됩니다.
참고 1: Kmod와 netlink에 대해서는 다른 글에서 설명할 예정이므로 이 글에서는 자세히 설명하지 않습니다.
Uevent의 코드는 비교적 간단하며 주로 다음과 같이 kobject.h 및 kobject_uevent.c라는 두 파일을 포함합니다.
kobject.h는 uevent 관련 상수 및 데이터 구조를 다음과 같이 정의합니다.
kobject_action은 다음을 포함하여 이벤트 유형을 정의합니다.
“
ADD/REMOVE, Kobject(또는 상위 데이터 구조) 이벤트 추가/제거.
ONLINE/OFFLINE, Kobject(또는 상위 계층 데이터 구조)의 온라인/오프라인 이벤트는 실제로 활성화 여부입니다.
CHANGE, Kobject(또는 상위 데이터 구조)의 상태나 내용이 변경됩니다.
MOVE, Kobject(또는 상위 데이터 구조)는 이름을 변경하거나 상위를 변경합니다(sysfs에서 디렉터리 구조가 변경됨을 의미).
CHANGE, 장치 드라이버가 보고해야 하는 이벤트가 더 이상 위 이벤트 범위에 속하지 않거나 맞춤 이벤트인 경우 이 이벤트를 사용하고 해당 매개변수를 전달할 수 있습니다.
”
앞서 언급한 것처럼 Kmod를 사용하여 사용자 공간에 이벤트를 보고하면 사용자 공간 실행 파일이 직접 실행됩니다. Linux 시스템에서는 실행 파일의 실행이 환경 변수에 따라 달라지므로 이 이벤트를 보고할 때 kobj_uevent_env를 사용하여 환경 변수를 구성합니다.
“
envp,指针数组,用于保存每个环境变量的地址,最多可支持的环境变量数量为UEVENT_NUM_ENVP。
envp_idx,用于访问环境变量指针数组的index。
buf,保存环境变量的buffer,最大为UEVENT_BUFFER_SIZE。
buflen,访问buf的变量。
”
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独自添加了。
”
通过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 자체 또는 그 부모가 kset에 속하는지 확인합니다. 그렇지 않으면 오류가 보고됩니다(참고 2: kobject가 kset에 참여하지 않으면 uevent 보고가 허용되지 않음을 설명할 수 있음)
- kobj->uevent_suppress가 설정되어 있는지 확인하세요. 설정되어 있으면 모든 uevent 보고서를 무시하고 반환하세요. (참고 3: Kobject의 uevent 보고는 Kobject의 uevent_suppress 플래그를 통해 제어할 수 있음을 알 수 있습니다.)
- kset이 속한 kset에 uevent_ops->filter 함수가 있는 경우 이 함수를 호출하여 이 보고서를 필터링합니다(참고 4: 이는 섹션 3.2의 필터 인터페이스에 대한 설명을 지원합니다. kset는 보고를 원하지 않는 이벤트를 필터링할 수 있습니다. 전체적인 목표를 달성하기 위한 필터 인터페이스)
- kset이 속한 kset에 합법적인 이름(이전 커널 버전과 다른 하위 시스템이라고 함)이 있는지 확인하세요. 그렇지 않으면 uevent
보고가 허용되지 않습니다.- 이 보고서에 대한 환경 변수를 저장하기 위해 버퍼를 할당하고(결과는 env 포인터에 저장됨) sysfs에서 Kobject의 경로 정보를 얻습니다(사용자 공간 소프트웨어는 경로 정보를 기반으로 sysfs에서 액세스해야 합니다)
- add_uevent_var 인터페이스(아래 설명 참조)를 호출하여 작업, 경로 정보, 하위 시스템 및 기타 정보를 env 포인터에 추가하세요
- 들어오는 envp가 비어 있지 않으면 들어오는 환경 변수를 구문 분석하고 add_uevent_var 인터페이스도 호출하여 env 포인터에 추가하세요
- kset이 속한 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, 하위 시스템 및 표준 환경 변수(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, 32행 참조). 이 구성 항목은 사용자 공간 프로그램(또는 스크립트)을 지정합니다. "/sbin/hotplug"와 같이 보고된 uevent를 구문 분석하는 데 사용됩니다.
call_usermodehelper의 기능은 프로세스를 분기하고, uevent를 매개변수로 사용하고, uevent_helper를 실행하는 것입니다.kobject_uevent는 환경 변수가 지정되지 않는다는 점을 제외하면 kobject_uevent_env와 동일한 기능을 갖습니다.
add_uevent_var, 환경 변수를 서식 지정 문자 형식(printf, printk 등과 유사)으로 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”中相应的代码,这里不再详细描述。
위 내용은 Linux 장치 모델(3)_Uevent의 상세 내용입니다. 자세한 내용은 PHP 중국어 웹사이트의 기타 관련 기사를 참조하세요!