要約:
何本論文の主要なメカニズムであると、コード解析を通じてUEVENT機構生成装置ノードを使用してUEVENTおよびプロセスを導入することです。第二の部分ながら用紙は、二つの部分、我々は原則とUEVENTのいくつかの事前知識を導入する最初の部分に分割する - コードの導入を通じてデバイスUEVENT機構ノードを作成します。
Linuxカーネル:のlinux-2.6.22.6
プレートを開発した:JZ2440 V3(S3C2440A)
声明:
この記事では、いくつかのビデオと書かれたブログの内容と組み合わせ魏東山先生を見ているので、テキストの内容は、あなたが私の記事があなたの違反を構成している、あなたは私に言うことができると思うならば、私が記事になり、他の記事もあり正しい、および本文中の適切な場所がないことがあれば、私を修正してください。ありがとうございます。
パート1:事前知識とUEVENTの原則
ここでは、予選を説明し始めます。説明する前に、チャートのプレゼンテーションフレームワークUEVENTメカニズムでは、見てみましょう:
私たちの多くは知らないかもしれない:UEVENTメカニズム、最後にUEVENTメカニズムは何をされていますか?彼は私たちの研究のこれらの側面の価値がありますか?
私たちは、プログラムで使用していないことを、ドライバーがちょうど学んでいるUEVENTメカニズムを使用していませんでしたclass_createとclass_device_create自動的にデバイスドライバのユーザ空間でのデバイスノードを作成する機能。その後、我々は手動でユーザ空間でのmknodコマンドを使用してデバイスノードを作成する必要があります。私たちはclass_createとclass_device_create機能を使用する場合と、彼らは私たちは手動で私たちが仕事を取りに行くことなく、ユーザ空間のデバイスノードを作成します。そして、これは私たちがマクロUEVENTメカニズムのために知っているものです。そして、我々は我々のデバイスノードは、デバイスドライバのために作成されていることを知っているし、デバイス間、デバイスドライバやデバイスドライバは、リストの形でバスのバスに接続されている-ドライバ-次のレベルへのバスは、sysfsの層があります。このリードは、したがって、我々はの組み合わせ紹介しますsysfsの+ MDEVを。この組み合わせは、私たちの原則のUEVENTを説明するためのメカニズムを提供します。私たちは、SYSFSを理解するために開始します。
sysfsのメモリベースの仮想ファイルシステムは、カーネルが提供され、ある/ SYSディレクトリの下にマウント(マウント取得するビューと タイプのsysfsの/ SYS(RW、もしnosuid、NODEV、NOEXEC、ONのsysfsをがrelatime)) 、デバイスツリーの責任フォームと名前空間の視覚情報をユーザに提供する駆動装置。一方、私たちのために現在のデバイスアクセスシステムを示すために、異なる視点をsysfsの:
- / SYS /ブロック 歴史問題、記憶ブロック・デバイスのシンボリックリンク/ SYS /デバイスに(例えばSDAなど)デバイス名を備え、
- / SYS /バスタイプ分類によってバスは、バスのディレクトリの下にシンボリックバス・デバイスを接続するリンク、ポイント/ SYS /デバイスを検索します。ディレクトリの下にバスの運転手のディレクトリには、構造体bus_typeカーネルの対応に必要なシンボリックリンクバスの運転手の全てが含まれています
- シンボリックリンクのような入力装置として機能デバイスによって分類/ SYS /クラスは、/ SYS /クラス/グラフィック下/ SYS /クラス/入力、グラフィックス・デバイスの下に、対応するデバイスは、対応するカーネル内の次の/ SYS /デバイスを指しています構造体クラス
- / SYS / devの成層プレスデバイスドライバ(キャラクタデバイス/ブロックデバイス)、主要な提供:マイナー名構造体のdevice_driverカーネルにシンボリックリンクに対応する/ SYS /デバイスに
- / SYS /デバイスは、種々の物理的バスの様々な検出されたすべての登録装置を含みます。バス上でのデバイスのすべての物理トポロジーは、プラットフォームのデバイスとシステムデバイスに加えて、表示します。チップ上のプラットフォームのデバイスをぶら下げすることは、CPUが直接対処することができ、一般的に高いまたは低い内部バスと、様々な周辺コントローラです。システム・デバイスは、周辺ではありません、彼はなどCPU、タイマー、などのチップの内部構造の中核である、彼らは一般的に、関連するドライバを持っていないが、その中に対応するカーネル構造体デバイスを設定するには、いくつかのアーキテクチャ依存のコードが存在します
上記のsysディレクトリ実証ファイルバス、デバイス、ドライバおよび対応するクラス、およびそれらの関係を:
- デバイスは、すべてのデバイス情報を格納するさまざまな装置を記述するために使用しました
- それによって駆動されることが可能な全てのデバイスのリストを保持しているデバイスを駆動するドライバ。
- CPUバスを接続するブリッジは、すべてのデバイスがリストにこれらのデバイスを駆動することと、駆動チェーンに取り付けられた保持装置です。
- クラスは、すべてのそのようなデバイスデバイスのリストを保持しているデバイスのクラスを記述するために使用されます。
ここでは、バス、デバイス、構造および駆動まだ下のクラスをご紹介します。たkobject、KSET、ktype:sysfsの機能統一Linuxベースのデバイスモデル、彼が構成以下の構造を有しています。上の図は、UEVENTたkobject構造に基づいて実装されているから、私たちは見ることができます。
たkobject:統一デバイスモデル最も基本的なオブジェクト。
struct kobject {
const char *name; //name,该Kobject的名称,同时也是sysfs中的目录名称。
//由于Kobject添加到Kernel时,需要根据名字注册到sysfs中,之后就不能再直接修改该字段。
//如果需要修改Kobject的名字,需要调用kobject_rename接口,该接口会主动处理sysfs的相关事宜。
struct list_head entry; //entry,用于将Kobject加入到Kset中的list_head。
struct kobject *parent; //parent,指向parent kobject,以此形成层次结构(在sysfs就表现为目录结构)。
struct kset *kset; //kset,该kobject属于的Kset。可以为NULL。
//如果存在,且没有指定parent,则会把Kset作为parent
//(别忘了Kset是一个特殊的Kobject)。
struct kobj_type *ktype; //ktype,该Kobject属于的kobj_type。每个Kobject必须有一个ktype,或者Kernel会提示错误。
struct sysfs_dirent *sd; //sd,该Kobject在sysfs中的表示。
struct kref kref; //kref,"struct kref”类型(在include/linux/kref.h中定义)的变量,为一个可用于原子操作的引用计数。
unsigned int state_initialized:1; //state_initialized,指示该Kobject是否已经初始化,
//以在Kobject的Init,Put,Add等操作时进行异常校验。
unsigned int state_in_sysfs:1; //state_in_sysfs,指示该Kobject是否已在sysfs中呈现,以便在自动注销时从sysfs中移除。
unsigned int state_add_uevent_sent:1; // state_add_uevent_sent/state_remove_uevent_sent,记录是否已经向用户空间发送ADD uevent,
//如果有,且没有发送remove uevent,则在自动注销时,补发REMOVE uevent,
//以便让用户空间正确处理。
unsigned int state_remove_uevent_sent:1;
unsigned int uevent_suppress:1; //uevent_suppress,如果该字段为1,则表示忽略所有上报的uevent事件。
};
注: UEVENTは、カーネルが、kobコectを増加させ、削除、変更、およびその他のアクションは、ユーザ空間に通知しますしているとき、この機能によって、達成するための「ユーザースペース通知」機能を提供します。
Ktype:代表たkobject(kobコectを含む厳密に言えば、データ構造)操作のセットの特性(これは汎用性、操作の複数たkobjectが同じ特性を共有し、したがってktypeの独立できる設定)。
struct kobj_type {
void (*release)(struct kobject *kobj); //release,通过该回调函数,可以将包含该种类型kobject的数据结构的内存空间释放掉。
const struct sysfs_ops *sysfs_ops; //sysfs_ops,该种类型的Kobject的sysfs文件系统接口。
struct attribute **default_attrs; //default_attrs,该种类型的Kobject的atrribute列表
//(所谓attribute,就是sysfs文件系统中的一个文件)。
//将会在Kobject添加到内核时,一并注册到sysfs中。
const struct kobj_ns_type_operations *(*child_ns_type)(struct kobject *kobj);
//child_ns_type/namespace,和文件系统(sysfs)的命名空间有关
const void *(*namespace)(struct kobject *kobj);
};
実際に、ここで実施たkobjectに類似しているたkobjectの異なるkobj_typeが異なるサブクラスとして見ることができる含む、派生。これは、同じ機能の多型を実施することによって達成されます。この設計で、各埋め込まれたkobjectデータ構造(例えばKSET、デバイス、device_driverへ等)において、そのkobj_typeを達成し、ここで、コールバック関数を定義しなければなりません。
KSET:セット類似したkobjectに使用される特殊なたkobject(それがディレクトリに表示される「/ SYS /」ファイルシステム)、(kobコectこれらのプロパティは、同じであってもよいし、異なる属性することができます)。
struct kset {
struct list_head list; //list用于保存该kset下所有的kobject的链表。
spinlock_t list_lock; //list自旋锁
struct kobject kobj; //kobj,该kset自己的kobject(kset是一个特殊的kobject,也会在sysfs中以目录的形式体现)。
const struct kset_uevent_ops *uevent_ops; //uevent_ops,该kset的uevent操作函数集。
//当任何Kobject需要上报uevent时,都要调用它所从属的kset的uevent_ops,添加环境变量,
//或者过滤event(kset可以决定哪些event可以上报)。
//因此,如果一个kobject不属于任何kset时,是不允许发送uevent的。
};
UEVENT操作コールバック関数のKSETは次のとおりです。
struct kset_uevent_ops {
int (* const filter)(struct kset *kset, struct kobject *kobj);
//filter,当任何Kobject需要上报uevent时,它所属的kset可以通过该接口过滤,
//阻止不希望上报的event,从而达到从整体上管理的目的。
const char *(* const name)(struct kset *kset, struct kobject *kobj);
//name,该接口可以返回kset的名称。如果一个kset没有合法的名称,
//则其下的所有Kobject将不允许上报uvent
int (* const uevent)(struct kset *kset, struct kobject *kobj,
struct kobj_uevent_env *env);
//uevent,当任何Kobject需要上报uevent时,它所属的kset可以通过该接口统一为这些event添加环境变量。
//因为很多时候上报uevent时的环境变量都是相同的,因此可以由kset统一处理,就不需要让每个Kobject独自添加了。
};
関連KSETとktypeことに注意してください、kobコectメンバーがktypeがkobj.ktypeで設定する前に属しKSET自分のKSETの検索を使用します。KSETメンバーを指定しない場合は、ktypeとの関係を構築することになります。
たkobjectコールはKSETは、その動作を制御することができますので、それは、所属するUEVENT KSET操作関数ですので。kobコectがどのKSETに属していない場合は、UEVENTを送信することはできません。
要約、Ktypeたkobjectと全体のメカニズムを理解します。
たkobjectコア機能である:、カウントがゼロに低減される参照カウントを維持し、自動的に解除される(本明細書中にモジュールが話すことに責任たkobjectある)たkobject meomryスペースを占領しました。これは、たkobjectが動的(ダイナミックを解放する唯一の方法)を割り当てる必要があります決定します。
そしてたkobjectほとんどの使用シナリオでは、これらの大きなデータ構造は、大規模なデータ構造(例えば等KSET、device_driverへ、)に埋め込まれ、また動的に、動的放出を割り当てなければなりません。それでは時間は、それが解放されますか?埋め込まれたkobjectリリースです。しかし、kobコectリリースはたkobjectモジュールによって自動的に行われます(参照カウントが0であるに)、その後、どのように一緒にし、それらを含む大規模なデータ構造のリリースでは?
その後Ktypeに便利です。私たちは、リリースコールバック関数がたkobject(またはのたkobject含まれていても、データ構造)のメモリ領域を解放する責任があるKtype、知っている、その内部機能をKtype、誰によってそれを達成するには?トップからのデータ構造モジュールです!それだけが解放する必要の先頭へのポインタを見つけ、それを解放するために、データ構造に埋め込まれ、かつたkobjectポインタとデータ構造、データ構造の独自の種類別にされたkobject明らかになったため。
このことについて話して、それは非常に明確です。したがって、各たkobject埋め込みデータ構造は、例えばKSET、デバイス、device_driverへ等、ktypeを達成し、ここで、コールバック関数を定義しなければなりません。同様に、sysfs関連の操作は、あまりにも、データがたkobject上部構造に埋め込まれ、sysfsのはkobコectを見るので、ktypeトランジットなるが、実際の対象ファイル操作しなければなりません!
ところで、kobコectオブジェクト指向の考え方は、Linuxカーネルの究極の表現であるが、Linuxを使用する必要が実現する賢い(と非常に長いったらしい)手段を比較カーネルので、C言語の利点は、ここではありません。
MDEV原理
我々はSYSFSを分析した上で、ここではMDEVの分析を開始、我々はMDEVを分析することにより、sysfsのと彼の関係を理解します。MDEVが配置コードパッケージbusyboxの、で見つけることができるのbusybox / utilに-linuxの/ mdev.cファイル、彼はuevent_helper機能によって呼び出されます。MDEVでは主に二つのことを実行します。
まず最初に:
MDEV -sコマンドの実行、(MDEV)走査/ SYS /ブロック(デバイス/ SYS /ブロックのディレクトリに格納されたブロック、以降のカーネルバージョン2.6.25は、また、ブロックデバイスに格納されている/ SYS /クラス/ブロックスキャン.mdevディレクトリ/ SYS /下位互換性のためにブロック)DEVファイル属性および/ SYS /クラス二つのディレクトリ、デバイス番号にプロパティファイルから取得DEV(DEVファイル属性:デバイス番号の形式で格納されている「メジャーマイナー\ n」) 、およびデバイス名として属性のdevのデバイス名のファイルを含むディレクトリ名(デバイス名と呼ばれるファイル属性、およびサブシステムと呼ばれる/ SYS /クラスとデバイス名の間でディレクトリの一部を含む、すなわちdevのディレクトリ。で、各属性DEVファイルへのパスが/ SYS /クラス/サブシステム/デバイス名として表すことができる場所は/ dev)、 / devディレクトリの中に適切なデバイス・ファイルを作成します。例えば、猫/ SYS /クラス/ TTY / tty0のは/ dev 4になります:0、サブシステムがttyで、デバイス名はtty0のです。
二つ目:
場合は、その環境変数を取得するUEVENTイベントを渡すことuevnetイベントが(以前のhotplugイベントとして知られている)、MDEVと呼ばれている理由はMDEV:デバイスへのパスがUEVENTイベントの作用によって引き起こされると、デバイスはデバイスパスに位置しています。そして、イベントUEVENTはいた原因アクションを決定します。そして、操作に応じて、適切な処置を行うこと。アクションは、新しいデバイスがシステムに追加されているアドオン、ある場合には、関係なく、デバイスは仮想デバイスまたは実際の物理的なデバイスであるかどうかの、MDEVは最後のディレクトリへのデバイス番号は、デバイスのパスパスへのデバイスパスパスにdevの属性ファイルを介して取得しますデバイス名として(ファイルの属性が含まれているdevディレクトリ)は、対応するデバイスファイル/ devディレクトリを作成します。アクションがリモートの場合は、あること、デバイスは、デバイスのファイル名としてdevディレクトリの下の最後のディレクトリのパス名のシステムは、delete /デバイスパスから削除されます。アクションはどちらもアドオンも削除された場合は、何もしないMDEV。
私たちがしたいか、自動的にデバイスファイルを作成および削除、システムに追加の機器でシステムから削除した場合、その後、あなたには、上記から明らかであるMDEVにより、以下の3点を行う必要があります。
の特定のサブディレクトリ/ SYS /クラスで1
、名前としてデバイス名にデバイス名を作成します。2.
3も、このディレクトリ内のファイル属性のdevのデバイス名、ファイル属性DEV含まれている必要があります:出力デバイスID「メジャー、マイナー\ n」はフォームを。
我々上記の内容を知ることができることから、sysfsには、適切なディレクトリを作成UEVENTメカニズムのための準備作業を行うには、その後、MDEVを作成したsysfsディレクトリやファイルを呼び出すことによって、デバイスノードの作成を実現するためのsysfsに基づいています。
第二部:デバイスを作成するためのメカニズムと関連してコードの使用を記載しているノードUEVENT
我々はclass_createからこのメカニズムを分析し、このプロセスが実装されているかを分析するために、これらの2つの機能をclass_device_createする必要がありますしながら、今、私たちは、コード分析UEVENTメカニズムを組み合わせることがあります。私たちは今、最初class_createを分析します:
以下は、ある階層関係のclass_create機能:
class_create(THIS_MODULE,"buttonsdrv");
class_register(cls);
kobject_set_name(&cls->subsys.kobj, "%s", cls->name); //将类的名字led_class赋值给对应的kset
subsys_set_kset(cls, class_subsys);
subsystem_register(&cls->subsys);
kset_register(s); //创建class设备类目录
kset_add(k);
kobject_add(&k->kobj);
kobject_shadow_add(kobj, NULL);
parent = kobject_get(kobj->parent); // parent即class_kset.kobj,即/sysfs/class对应的目录
list_add_tail(&kobj->entry,&kobj->kset->list);
create_dir(kobj, shadow_parent); //创建一个class设备类目录
sysfs_create_dir(kobj, shadow_parent); //该接口是sysfs文件系统接口,代表创建一个目录,不再展开。
我々はkobコectを登録するとき、我々は、sysfsの中に対応するたkobjectは、ディレクトリ(DIR)であることがわかります以上のことから、呼び出しは(&K-> KOBJ)kobject_add;、その後、クラスのデバイスのディレクトリを作成します。私たちが見ることができますがclass_create機能が行われ、準作業ディレクトリはclass_device_create機能です。
記事の最初から絵がステータスの変化(例えば、追加、削除など)は、ユーザーがそれに応じて処理できるイベント通知を受けた後、そのスペース、ユーザ空間に通知されたときに我々は知ってたkobjectを説明しています。
:UEVENTの事件は、2つの方法でユーザ空間に報告
にkmodモジュールによって1、直接実行可能なプログラムやスクリプトのユーザ空間と呼ばれます。
2.ネットリンク通信メカニズム、ユーザ空間にカーネル空間からのイベント配信。
論文は、主に、直接実行可能なプログラムやスクリプトユーザ空間と呼ばれる、にkmodモジュールで説明します。そして、それはkobject.h、UEVENTモジュールによって(APIは、「LIB / kobject_uevent.c」ファイルに実装された)は、次のAPIを提供します。
int kobject_uevent(struct kobject *kobj, enum kobject_action action);
int kobject_uevent_env(struct kobject *kobj, enum kobject_action action,
char *envp[]);
int add_uevent_var(struct kobj_uevent_env *env, const char *format, ...);
int kobject_action_type(const char *buf, size_t count,enum kobject_action *type);
ここからclass_device_create機能は、彼がkobject_uevent機能を行ったかを確認するために、分析を開始します。私たちは、階層関係のclass_device_create機能を参照してください
class_device_create(buttonsdrv_class,NULL,MKDEV(auto_major,0),NULL,"buttonsdrv");
class_device_register(class_dev);
class_device_add(class_dev);
class_dev = class_device_get(class_dev);
parent_class = class_get(class_dev->class);
parent_class_dev = class_device_get(class_dev->parent);
kobject_set_name(&class_dev->kobj, "%s", class_dev->class_id);
kobject_add(&class_dev->kobj);
class_device_create_file(class_dev, attr);
class_device_add_groups(class_dev);
make_deprecated_class_device_links(class_dev);
kobject_uevent(&class_dev->kobj, KOBJ_ADD);
前のコードから、同様の作業の多くを行うclass_create class_device_createを参照してください-彼らはない同じ、聞かせてのは、分析の後にディレクトリを作成することであり、ときkobject_uevent機能にkobject_uevent機能を
/**
* 通过终端事件通知用户层
*
* @action: 发生的事件 (通常是 KOBJ_ADD 和 KOBJ_REMOVE)
* @kobj: 事件发生的kobject 结构体
*
*/
int kobject_uevent(struct kobject *kobj, enum kobject_action action)
{
return kobject_uevent_env(kobj, action, NULL);
}
彼は上記の説明しながら、私たちは、あなたがイベントを送信したい知っている、kobject_uevent_env関数を呼び出した後、そのイベントは何ですか?
私たちは見含める/ linuxの/ /のlinux-3.5 kobject.h
enum kobject_action {
KOBJ_ADD, //ADD/REMOVE,Kobject(或上层数据结构)的添加/移除事件。
KOBJ_REMOVE,
KOBJ_CHANGE, //CHANGE,Kobject(或上层数据结构)的状态或者内容发生改变。
//CHANGE,如果设备驱动需要上报的事件不再上面事件的范围内,
//或者是自定义的事件,可以使用该event,并携带相应的参数。
KOBJ_MOVE, //MOVE,Kobject(或上层数据结构)更改名称或者更改Parent(意味着在sysfs中更改了目录结构)。
KOBJ_ONLINE, //ONLINE/OFFLINE,Kobject(或上层数据结构)的上线/下线事件,其实是是否使能。
KOBJ_OFFLINE,
KOBJ_MAX
};
私たちはその後、分析してみましょうkobject_uevent_env機能:
/**
* 发送一个带有环境变量的事件
*
* @action: 发生的事件(通常为KOBJ_MOVE)
* @kobj: 事件发生的kobject结构体
* @envp_ext: 环境变量数据指针
*
*/
int kobject_uevent_env(struct kobject *kobj, enum kobject_action action,
char *envp_ext[])
{
action_string = action_to_string(action);
/* 查找当前kobject或其parent是否从属于某个kset;如果都不从属于某个kset,则返回错误。(说明一个kobject若没有加入kset,是不会上报uevent的) */
top_kobj = kobj;
while (!top_kobj->kset && top_kobj->parent) {
top_kobj = top_kobj->parent;
}
if (!top_kobj->kset) {
pr_debug("kobject attempted to send uevent without kset!\n");
return -EINVAL;
}
kset = top_kobj->kset;
uevent_ops = kset->uevent_ops;
/* 如果所属的kset有uevent_ops->filter,则调用该函数,若该函数返回0,则过滤此次上报。(kset 可以通过filter接口过滤不希望上报的event) */
if (uevent_ops && uevent_ops->filter)
if (!uevent_ops->filter(kset, kobj)) {
pr_debug("kobject filter function caused the event to drop!\n");
return 0;
}
/*判断所属的kset是否有合法的名称,若uevent_ops->name存在就用其返回的名称作为subsystem;若uevent_ops->name不存在就用kset本身的kobject的名称作为subsystem;若没有合法的名称,则不上报uevent */
if (uevent_ops && uevent_ops->name)
subsystem = uevent_ops->name(kset, kobj);
else
subsystem = kobject_name(&kset->kobj);
if (!subsystem) {
pr_debug("unset subsytem caused the event to drop!\n");
return 0;
}
/* 分配一个此次上报的环境变量 */
envp = kzalloc(NUM_ENVP * sizeof (char *), GFP_KERNEL);
if (!envp)
return -ENOMEM;
/*分配一个此次上报的用于保存环境变量的buffer, */
buffer = kmalloc(BUFFER_SIZE, GFP_KERNEL);
if (!buffer) {
retval = -ENOMEM;
goto exit;
}
/* 获得该kobject在sysfs中路径 */
devpath = kobject_get_path(kobj, GFP_KERNEL);
if (!devpath) {
retval = -ENOENT;
goto exit;
}
/* uevent_helper的环境变量*/
envp[i++] = "HOME=/";
envp[i++] = "PATH=/sbin:/bin:/usr/sbin:/usr/bin";
/* 添加环境变量 */
scratch = buffer;
envp [i++] = scratch;
scratch += sprintf(scratch, "ACTION=%s", action_string) + 1;
envp [i++] = scratch;
scratch += sprintf (scratch, "DEVPATH=%s", devpath) + 1;
envp [i++] = scratch;
scratch += sprintf(scratch, "SUBSYSTEM=%s", subsystem) + 1;
for (j = 0; envp_ext && envp_ext[j]; j++)
envp[i++] = envp_ext[j];
/* just reserve the space, overwrite it after kset call has returned */
envp[i++] = seq_buff = scratch;
scratch += strlen("SEQNUM=18446744073709551616") + 1;
/* 如果 uevent_ops->uevent 存在,调用该接口,添加kset统一的环境变量到env指针 */
if (uevent_ops && uevent_ops->uevent) {
retval = uevent_ops->uevent(kset, kobj,
&envp[i], NUM_ENVP - i, scratch,
BUFFER_SIZE - (scratch - buffer));
if (retval) {
pr_debug ("%s - uevent() returned %d\n",
__FUNCTION__, retval);
goto exit;
}
}
/* 调用add_uevent_var接口,添加格式为"SEQNUM=%llu”的序列号 */
spin_lock(&sequence_lock);
seq = ++uevent_seqnum;
spin_unlock(&sequence_lock);
sprintf(seq_buff, "SEQNUM=%llu", (unsigned long long)seq);
/* 以uevent_helper、 subsystem 以及添加了标准环境变量(HOME=/,PATH=/sbin:/bin:/usr/sbin:/usr/bin)的env指针为参数,调用kmod模块提供的call_usermodehelper函数,上报uevent。 */
if (uevent_helper[0]) {
char *argv [3];
argv [0] = uevent_helper;
argv [1] = (char *)subsystem;
argv [2] = NULL;
call_usermodehelper (argv[0], argv, envp, 0);
}
}
UEVENTモジュールにkmod UEVENTによって報告された、それは、call_usermodehelper機能を渡すユーザ空間内の実行可能ファイルを呼び出す(またはスクリプトを、短いUEVENTヘルパーのための)イベントを処理します。これは配列に格納されUEVENTヘルパーuevent_helperパス。あなたはCONFIG_UEVENT_HELPER_PATH、静的に割り当てUEVENTヘルパーによってカーネル設定項目をコンパイルすることができます。
しかし、この方法では、(など、メモリオーバーフローにつながる可能)デバイスの数がカーネルでサポートされているように、このようにシステムの起動が致命的になり、プロセスのフォーク各イベントのためになります。そのため、カーネルの唯一の以前のバージョンでは、このように使用され、今カーネルは、この方法を使用することは推奨されません。カーネルをコンパイルするときにそのため、あなたは項目を空白にして設定する必要があります。システム起動後、機器のほとんどは、検出システムのプロセスは、ホットプラグイベントを実行しているように、UEVENTヘルパーを再割り当てするために、必要に応じて、準備ができてきました。
これは、ヘルパー・パス「/ SYS /カーネル/ uevent_helper」ファイルに書き込むことによって達成することができます。実際には、カーネルSYSFSファイルシステムの形態は、ユーザがコードを対応するユーザ空間プログラム特定基準「./kernel/ksysfs.c」を変更するためのアクセスのためのスペースuevent_helperアレイを開きます。
>は、/ proc / sys / kernel / /etc/init.d/rcSでスクリプトに"/ sbinに/ MDEV"エコーを追加ホットプラグ、 あなたは猫/ SYS /カーネル/ uevent_helperつまり/ sbinに/ MDEVがあります。実行可能ファイルのパスの説明は、/ proc / sys / kernel /ホットプラグは、最終的に/ SYS /カーネル/ uevent_helperに書き込まれます。手動エコー「/カーネル/メイン」>に uevent_helper( / sbinに/ MDEV上書きされる前に)、rmmodは、/ SYS /カーネル/ uevent_helperに/カーネル/主が実行されるlsmodのは、イベントがユーザに報告されていることを示す場合スペース。
ここでは、Busyboxのを見て、デバイスノードを作成する方法です。
演奏MDEVを回し、前述の説明はは/ dev /ディレクトリに作成されるファイルのニーズにアクセスするためにsysfsファイルシステムとデバイスアプリケーション内のディレクトリやファイルを作成することです。MDEVによって行われる作業。
MDEV原理は、デバイスファイル/etc/mdev.conf定義ファイルの命名のルールを説明することで、環境変数の規則に基づく要件に合わせてデバイスファイルを作成します。mdev.confは、ユーザ層によって指定され、従ってより柔軟。この記事ではMDEV構成スクリプトの解析を拡張するものではありません。知識は私の翻訳を見ることができます:mdev.conf翻訳
/ UTIL-linuxの/ mdev.c Busyboxのに適切なプログラムをMDEV
int mdev_main(int argc UNUSED_PARAM, char **argv)
xchdir("/dev");
if (argv[1] && strcmp(argv[1], "-s")//系统启动时mdev –s才会执行这个分支
else
action = getenv("ACTION");
env_path = getenv("DEVPATH");
G.subsystem = getenv("SUBSYSTEM");
snprintf(temp, PATH_MAX, "/sys%s", env_path);//到/sysfs/devices/led目录
make_device(temp, /*delete:*/ 0);
strcpy(dev_maj_min, "/dev"); //读出dev属性文件,得到设备号
open_read_close(path, dev_maj_min + 1, 64);
….
mknod(node_name, rule->mode | type, makedev(major, minor)) //最终mknod创建节点
最終的には、は/ dev /ディレクトリ内のデバイスを作成するために、mknodを追跡します。
参考文献:
Linuxのデバイスモデルのsysfs、udevの統一、そしてその背後にある
Linuxデバイスモデル(2)_Kobject
とMDEV Linuxのデバイスファイルを作成し
、カーネルUEVENTにAPIを送信し、ユーザーが空間的に分解UEVENT
Linuxデバイスモデル(3)_Uevent
デバイスモデルのUEVENTメカニズム