kobject/sysfs(2)

Linuxでは膨大な種類のデバイスをサポートするドライバが、カーネルにビルドインされていることがセールス・ポイントの一つである。カーネル2.6系ではsysfsによる新しいドライバ・アーキテクチャの導入により、従来ソースのデバイスドライバもサポートされているものの、sysfsに対応した構造への書き換えが推奨される事になっている。

Linux-2.6.0-test2のテストリリースが始まっているが、ビルドインされているデバイスドライバの書き換えはそれほど進んでいない。今回は前回に続いて、sysfsとkobjectを理解するのために必要な、kset, ktype, subsystemの解説を紹介する。

2. kset

2.1 説明

ksetは、同じ型の中に組み込まれる1組のkobjectのセットである。

struct kset {
        struct subsystem        * subsys;
        struct kobj_type                * ktype;
        struct list_head                list;
        struct kobject          kobj;
};

void kset_init(struct kset * k);
int kset_add(struct kset * k);
int kset_register(struct kset * k);
void kset_unregister(struct kset * k);

struct kset * kset_get(struct kset * k);
void kset_put(struct kset * k);

struct kobject * kset_find_obj(struct kset *, char *);

kobjectsに組み込まれるオブジェクト型は、ktypeポインタに記述される。kobjectが属しているsubsystemは、subsysポインタで示される。

ksetがkobjectを含むという事は、それがkobjectの階層構造に登録され、sysfs経由でエクスポートされる事を意味する。さらに重要な点は、ksetがより大きいデータ型の中に組み込まれる可能性があり、そのオブジェクト型の別のksetの一部となる場合があるという事である。

例えばブロック型デバイスは、ブロック型デバイスのセットに含まれる(struct gendiskという)オブジェクトである。それは、そのデバイスで見つかった(struct hd_structという)一組のパーティション含むかもしれない。次のコードの断片は、この方法を示している。

         struct gendisk * disk;
         ...
         disk->kset.kobj.kset = &block_kset;
         disk->kset.ktype = &partition_ktype;
         kset_register(&disk->kset);
  • diskに組み込まれたオブジェクトが属しているksetはblock_ksetであって、そのことはdisk->kset.kobj.ksetによって示されている。
  • ディスクの「下位の」 リストのオブジェクトのタイプはパーティションであって、それはdisk->kset.ktypeでセットされている。
  • そしてksetが登録されている。登録では初期化と、組み込まれたkobjectを階層化構造に加えることを行う。

2.2 kset プログラミング・インタフェイス

全てのksetが提供するfinctionは、kset_find_obj()を除いて、kset固有の操作を実行した後に、組み込まれたkobjectsに呼び出しを転送する。ksetでは、階層構造に登録することなく、初期化された後で使われるというような、kobjectsに類似したプログラミングモデルも提供可能である。

kset_find_obj()は、特定の名前のkobjectを見つけるのに用いられて、見つかった場合にkobjectが返される。

2.3 sysfs

ksetに組み込まれたkobjectsが登録されるとき、ksetはsysfsとして現れる。1つの例外を除いて、それらはparentingの同じ原則に従う。つまりksetに親がなく、別のksetに組み込まれたkobjectの一部でもないならば、ksetの親はそれの属する「subsystem」となる。

ksetに親がない場合は、そのディレクトリはsysfs rootに作成される。この動作は、登録されるksetがsubsystemそのものとして組み込まれているときに行われる。

3. struct ktype

struct kobj_type {
	void (*release)(struct kobject *);
	struct sysfs_ops * sysfs_ops;
	struct attribute ** default_attrs;
};

オブジェクトの型は、一般的なオブジェクトとオブジェクトを構成する複合的な型の間で変換するために特定のfunctionを必要とする。struct kobj_typeでは次のように、オブジェクトに固有のメンバを提供している。

  • release: kobjectの参照カウントが0に達する時と呼び出される。これはオブジェクトを、構成する複合的な型に変換して、解放しなければならない。
  • sysfs_ops: sysfsにアクセスするために必要な変換機能を提供する。より詳しい情報は、sysfsのドキュメンテイションを参照の事。
  • default_attrs: オブジェクトが登録されたときに、sysfs経由でエクスポートされる標準属性。

struct kobj_typeのインスタンスは登録されずに、ksetによって参照されるだけである。一つのkobj_typeは、複数のksetによって参照される、そしてそれは同一オブジェクトの異なったセットである場合もある。

4. subsystem

4.1 説明

struct subsystem {
        struct kset             kset;
        struct rw_semaphore     rwsem;
};

int subsystem_register(struct subsystem *);
void subsystem_unregister(struct subsystem *);

struct subsystem * subsys_get(struct subsystem * s);
void subsys_put(struct subsystem * s);

subsystemは、ksetを組み込みメンバとして含んでいるので

  • それは、ksetに組み込まれたkobjectによってオブジェクト階層構造の中に現れる。
  • それは、ある型のオブジェクトのデフォルト・リストを維持することができる。

追加のksetは、サブシステムへの単なる参照により、登録前にサブシステムに所属させることができる。(この一方向の参照は、サブシステム側には所属させるksetを決める方法が無い事を意味する。)

subsystemに所属する全てのksetは、subsystemのR/Wセマフォ(rwsem)を共有する。

4.2 プログラミング・インタフェイス

subsystemのプログラミングインタフェイスは単純で、ksetとkobjectプログラミングインタフェイスのような柔軟性は提供しない。それらはリファレンス・カウントで示されるように、登録されているか、または未登録である。各々の呼び出しは、組み込まれているksetに呼び出しを転送する。(そしてそのksetは、それらの組み込まれたkobjectsに呼び出しを転送する)。

4.3 ヘルパー

subsystemへの関係付けと組み込まれたオブジェクトを簡単に操作するために、多くのマクロがヘルパーとして利用できる。

decl_subsys(name,type)

は、"type"型を組み込んだksetによる『"name"_subsys』というsubsystem名の宣言であり、例えば、

decl_subsys(devices,&ktype_devices);

は、次のような記述に等しい

struct subsystem device_subsys = {
	.kset = {
		.kobj = {
			.name = "devices",
		},
		.ktype = &ktype_devices,
	}
};

subsystemのデフォルト・リストを使うsubsystemに登録されるオブジェクトは、それらのksetポインタを正しくセットしておかなければならない。オブジェクトは、kobjects、ksetまたは他のsubsystemを組み込んでいる場合もある。次のヘルパーは、ksetをより簡単に設定する事ができる:

kobj_set_kset_s(obj,subsys)
  • はobj->kobjが存在して、それがstruct kobjectであるとみなす。
  • はそのkobjectのksetを、subsystemの組み込みksetとしてセットする。
kset_set_kset_s(obj,subsys)
  • はobj->ksetが存在して、struct ksetであるとみなす。
  • はそのkobjectが組み込まれているksetを、subsystemの組み込みksetとしてセットする。
subsys_set_kset(obj,subsys)
  • はobj->subsysが存在して、struct subsystemであるとみなす。
  • はobj->subsys.kset.kobj.ksetを、subsystemの組み込みksetとしてセットする。

4.4 sysfs

subsystemは、それに組み込まれたkobjectsを介してsysfsとして表わされる。それは以前述べたように、例外無しで同じ規則に従う。つまり組み込まれたkobjectが別のksetの一部であるか、または組み込まれたkobjectの親が明示的にセットされている場合以外は、sysfsではトップレベルのディレクトリを受け取る。

subsystemに組み込まれたksetがrwsemを使うためには、subsystemに「所属しなければならない」点に注意すべきである。これは、kset_add()の呼び出し後に実行される。(kset_add() では、それに親がなかった場合、それのsubsystemをデフォルトの親とする。)

<筆者によるここまでの解説>

筆者の調べた所では、kobjectに関するまとまった解説は前回・今回のこのドキュメンテーションだけである。これには開発に必要な情報は全て網羅されているはずである。しかしkobject, ksetの単純な構造をうまく組み合わせてsysfs、subsystemとそれの操作に必要なすべてのfunctionを実装しているPatric Mochelのトリックは、シンプルな単語を組み合わせて書かれている(原文の)解説だけでは理解して、吸収するには難しいと思われる。(このシンプルな解説を、今回うまく翻訳できていない筆者の技量不足な点はご容赦願いたい。)

sysfs/kobjectを使った実際の開発では、subsystemへのオブジェクト登録を行う具体的なソースコードの例を追いながら解説を進める方が有用であると思われる。次回以降では、サンプル・コードを紹介しながらkobject, sysfs, subsystemの実際のデバイスドライバの開発上における動作と役割、及び2.6のリリースにおいてLinuxカーネル・メーリングリスト(LKML)で議論されているトピックスについて紹介していく予定である。