Heim  >  Artikel  >  System-Tutorial  >  Linux-Gerätemodell (3)_Uevent

Linux-Gerätemodell (3)_Uevent

WBOY
WBOYnach vorne
2024-02-11 13:06:171010Durchsuche

1. Funktionen von Uevent

Uevent ist ein Teil von Kobject und wird verwendet, um Benutzerraumprogramme zu benachrichtigen, wenn sich der Status von Kobject ändert (z. B. Hinzufügung, Entfernung usw.). Nach dem Empfang eines solchen Ereignisses wird das User-Space-Programm entsprechend damit umgehen.

Normalerweise wird dieser Mechanismus zur Unterstützung von Hot-Plug-fähigen Geräten verwendet. Wenn beispielsweise ein USB-Flash-Laufwerk eingesteckt wird, erstellt der USB-bezogene Treiber dynamisch eine Gerätestruktur (einschließlich des entsprechenden Kobjects), die zur Darstellung des USB-Flash-Laufwerks und zur Information des User-Space-Programms verwendet wird. Dadurch können Geräteknoten dynamisch im Verzeichnis /dev/ erstellt werden. Darüber hinaus kann dieser Mechanismus auch andere Anwendungen benachrichtigen, das USB-Flash-Laufwerk in das System einzubinden, wodurch eine dynamische Unterstützung für das Gerät realisiert wird.

2. Der Speicherort von Uevent im Kernel

Das folgende Bild beschreibt die Position des Uevent-Moduls im Kernel:

Linux-Gerätemodell (3)_Uevent

Es ist ersichtlich, dass der Mechanismus von Uevent relativ einfach ist. Wenn bei einem Gerät im Gerätemodell ein Ereignis auftritt, das gemeldet werden muss, wird die von Uevent bereitgestellte Schnittstelle ausgelöst. Nachdem das Uevent-Modul das Format für die Meldung des Ereignisses vorbereitet hat, kann es das Ereignis auf zwei Arten an den Benutzerbereich melden: Zum einen wird die ausführbare Datei des Benutzerbereichs direkt über das kmod-Modul aufgerufen, zum anderen wird die Netlink-Kommunikation verwendet Der Mechanismus zum Übertragen des Ereignisses vom Kernel-Space wird an den User-Space übergeben.

Hinweis 1: Kmod und Netlink werden in anderen Artikeln beschrieben, daher wird sie in diesem Artikel nicht im Detail erläutert.

3. Interne Logikanalyse von Uevent

3.1 Speicherort des Quellcodes

Der Code von Uevent ist relativ einfach und umfasst hauptsächlich zwei Dateien: kobject.h und kobject_uevent.c, wie folgt:

  • include/linux/kobject.h
  • lib/kobject_uevent.c
3.2 Beschreibung der Datenstruktur

kobject.h definiert uevent-bezogene Konstanten und Datenstrukturen wie folgt:

  • 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 definiert die Art des Ereignisses, einschließlich:

ADD/REMOVE, Kobject (oder obere Datenstruktur) Ereignisse hinzufügen/entfernen.

ONLINE/OFFLINE, das Online/Offline-Ereignis von Kobject (oder der Datenstruktur der oberen Schicht), hängt tatsächlich davon ab, ob es aktiviert ist oder nicht.

CHANGE, der Zustand oder Inhalt von Kobject (oder der oberen Datenstruktur) ändert sich.

MOVE, Kobject (oder die obere Datenstruktur) ändert den Namen oder das übergeordnete Element (was bedeutet, dass die Verzeichnisstruktur in sysfs geändert wird).

ÄNDERUNG: Wenn das Ereignis, das der Gerätetreiber melden muss, nicht mehr im Rahmen der oben genannten Ereignisse liegt oder ein benutzerdefiniertes Ereignis ist, können Sie dieses Ereignis verwenden und die entsprechenden Parameter übertragen.

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

Wie bereits erwähnt, wird bei Verwendung von Kmod zum Melden eines Ereignisses an den Benutzerbereich die ausführbare Datei des Benutzerbereichs direkt ausgeführt. In Linux-Systemen hängt die Ausführung ausführbarer Dateien von Umgebungsvariablen ab. Daher wird kobj_uevent_env zum Organisieren der Umgebungsvariablen bei der Meldung dieses Ereignisses verwendet.

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

  • Finden Sie heraus, ob kobj selbst oder sein übergeordnetes Objekt zu einem Kset gehört. Andernfalls wird ein Fehler gemeldet (Hinweis 2: Dies kann dadurch erklärt werden, dass ein Kobject kein Uevent melden darf.) Überprüfen Sie, ob kobj->uevent_suppress gesetzt ist, alle uevent-Berichte ignorieren und zurückgeben (Hinweis 3: Daraus ist ersichtlich, dass die uevent-Berichte von Kobject über das uevent_suppress-Flag von Kobject gesteuert werden können)
  • Wenn das Kset, zu dem es gehört, über die Funktion uevent_ops->filter verfügt, rufen Sie diese Funktion auf, um den Bericht zu filtern (Hinweis 4: Dies unterstützt die Beschreibung der Filterschnittstelle in Abschnitt 3.2. Das Kset kann Ereignisse filtern, über die nicht berichtet werden soll die Filterschnittstelle, um den Gesamtzieleffekt zu erreichen)
  • Stellen Sie fest, ob das Kset, zu dem es gehört, einen zulässigen Namen hat (Subsystem genannt, der sich von der vorherigen Kernel-Version unterscheidet), andernfalls ist es nicht zulässig, uevent
  • zu melden Weisen Sie einen Puffer zum Speichern von Umgebungsvariablen für diesen Bericht zu (das Ergebnis wird im Env-Zeiger gespeichert) und rufen Sie die Pfadinformationen des Kobject in sysfs ab (Benutzerraumsoftware muss basierend auf den Pfadinformationen in sysfs darauf zugreifen)
  • Rufen Sie die Schnittstelle add_uevent_var (unten beschrieben) auf, um Aktion, Pfadinformationen, Subsystem und andere Informationen zum Env-Zeiger hinzuzufügen
  • Wenn die eingehende Umgebungsvariable nicht leer ist, analysieren Sie die eingehende Umgebungsvariable, rufen Sie auch die Schnittstelle add_uevent_var auf und fügen Sie sie dem Umgebungszeiger hinzu
  • Wenn das Kset, zu dem es gehört, über die Schnittstelle uevent_ops->uevent verfügt, rufen Sie diese Schnittstelle auf und fügen Sie die einheitlichen Umgebungsvariablen des Ksets zum Env-Zeiger hinzu
  • Legen Sie entsprechend der Art der AKTION die Variablen kobj->state_add_uevent_sent und kobj->state_remove_uevent_sent fest, um den korrekten Status aufzuzeichnen
  • Rufen Sie die Schnittstelle add_uevent_var auf und fügen Sie die Seriennummer im Format „SEQNUM=%llu“
  • hinzu Wenn „CONFIG_NET“ definiert ist, verwenden Sie Netlink, um das uevent
  • zu senden Rufen Sie unter Verwendung von uevent_helper, Subsystem und dem Env-Zeiger mit Standardumgebungsvariablen (HOME=/, PATH=/sbin:/bin:/usr/sbin:/usr/bin) als Parameter die Funktion call_usermodehelper auf, die vom kmod-Modul bereitgestellt wird, und melden Sie uevent .
  • Der Inhalt von uevent_helper wird durch das Kernel-Konfigurationselement CONFIG_UEVENT_HELPER_PATH (in ./drivers/base/Kconfig) bestimmt (siehe lib/kobject_uevent.c, Zeile 32). Wird zum Parsen des gemeldeten UE-Ereignisses verwendet, z. B. „/sbin/hotplug“.
  • Die Funktion von call_usermodehelper besteht darin, einen Prozess zu forken, uevent als Parameter zu übernehmen und uevent_helper auszuführen.

  • kobject_uevent hat die gleiche Funktion wie kobject_uevent_env, außer dass keine Umgebungsvariablen angegeben werden.

add_uevent_var kopiert die Umgebungsvariable in Form von Formatierungszeichen auf den Env-Zeiger (ähnlich wie printf, printk usw.).

kobject_action_type, konvertiert die Aktion des Enum-Typs kobject_action in eine Zeichenfolge.

说明:怎么指定处理uevent的用户空间程序(简称uevent helper)?

上面介绍kobject_uevent_env的内部动作时,有提到,Uevent模块通过Kmod上报Uevent时,会通过call_usermodehelper函数,调用用户空间的可执行文件(或者脚本,简称**uevent helper** )处理该event。而该uevent helper的路径保存在**uevent_helper数组中。

在系统启动后,大部分的设备已经ready,可以根据需要,重新指定一个uevent helper,以便检测系统运行过程中的热拔插事件。这可以通过把helper的路径写入到"/sys/kernel/uevent_helper”文件中实现。实际上,内核通过sysfs文件系统的形式,将uevent_helper数组开放到用户空间,供用户空间程序修改访问,具体可参考"****./kernel/ksysfs.c”中相应的代码,这里不再详细描述。

Das obige ist der detaillierte Inhalt vonLinux-Gerätemodell (3)_Uevent. Für weitere Informationen folgen Sie bitte anderen verwandten Artikeln auf der PHP chinesischen Website!

Stellungnahme:
Dieser Artikel ist reproduziert unter:lxlinux.net. Bei Verstößen wenden Sie sich bitte an admin@php.cn löschen