sysfsとkset
Rev.2を表示中。最新版はこちら。
カーネルは管理するデバイスドライバのようなオブジェクトを、カテゴリ毎の階層的に管理しています。カテゴリ毎に統合することで同じ処理を共有化でき、階層化することで、親子関係で必要とするオブジェクトを管理することができます。そしてこの構造をユーザ空間にエクスポートしているのが/sysとなります。/sys下のディレクトリがオブジェクトそのもので、配下のファイルがそのオブジェクトの属性となります。配下にディレクトリがある場合、それはそのオブジェクトの子オブジェクトということです。
この処理を管理するのが、kobjectです。オブジェクト毎の構造体内にkobjectを埋め込むことで、オブジェクト内に異なった処理をトランスペアレントに管理しています。
親子関係のオブジェクトを作成する場合、ksetが使われます。ksetそのものもkobjectをリストするkobjectで、ksetを登録すると言うことはkobjectを登録することと同じです。なお配下のオブジェクトはksetにリストされているので、子オブジェクト(ディレクトリ)の取得は、sysfsに依存することなく、ksetをヘッドとするリストを捜査することで行えます。
kobjectを登録すると、登録した/sys下のディレクトリにkobjectのディレクトリが作成され、その配下に、kobj_typeに設定するattrが、ファイルとして作成され、read/writeのコールバックとして、kobj_typeのコールバックがコールされます。
以下は、sysとkobj/ksetの関連性の理解するのに特化したサンプルです。
kset_create_and_add()でksetをkset_hogeディレクトリで、kernel_kobj下に作成します。kset_hogeオブジェクトのコールバック/属性が必要なら、第二引数(NULL)に、kobj_typeを設定します。
kobject_init_and_add()で、kobj(hoge)を登録するのですが、親オブジェクトの第二引数がNULLとしています。この時kobj->kset = hoge_ksetとするksetが親となります。なお、ksetの設定がないkobjectの登録は親となる第二引数を設定する必要があります。
#include <linux/kobject.h>
#include <linux/string.h>
#include <linux/sysfs.h>
#include <linux/slab.h>
#include <linux/module.h>
#include <linux/init.h>
MODULE_LICENSE("GPL");
static char sysbuff_aaa[64];
static char sysbuff_bbb[64];
static ssize_t hoge_show(struct kobject *kobj,
struct attribute *attr,
char *buf)
{
if (!strcmp(attr->name, "aaa")) {
sprintf(buf, "from aaa %s", sysbuff_aaa);
}
else {
sprintf(buf, "from bbb %s", sysbuff_bbb);
}
return strlen(buf);
}
static ssize_t hoge_store(struct kobject *kobj,
struct attribute *attr,
const char *buf, size_t len)
{
if (!strcmp(attr->name, "aaa")) {
strcpy(sysbuff_aaa, buf);
}
else {
strcpy(sysbuff_bbb, buf);
}
return len;
}
static const struct sysfs_ops hoge_sysfs_ops = {
.show = hoge_show,
.store = hoge_store,
};
static void hoge_release(struct kobject *kobj)
{
kfree(kobj);
}
static struct attribute hoge_attr1 = {
"aaa", 0666,
};
static struct attribute hoge_attr2 = {
"bbb", 0666,
};
static struct attribute *hoge_attrs[] = {
&hoge_attr1,
&hoge_attr2,
NULL,
};
static struct kobj_type hoge_ktype = {
.sysfs_ops = &hoge_sysfs_ops,
.release = hoge_release,
.default_attrs = hoge_attrs,
};
static struct kset *hoge_kset;
struct kobject *kobj;
static int __init hoge_init(void)
{
int ret;
hoge_kset = kset_create_and_add("kset_hoge", NULL, kernel_kobj);
if (!hoge_kset)
return -ENOMEM;
kobj = kzalloc(sizeof(*kobj), GFP_KERNEL);
if (!kobj)
return -EINVAL;
kobj->kset = hoge_kset;
ret = kobject_init_and_add(kobj, &hoge_ktype, NULL, "%s", "hoge");
return 0;
}
static void __exit hoge_exit(void)
{
kobject_put(kobj);
kset_unregister(hoge_kset);
}
module_init(hoge_init);
module_exit(hoge_exit);
[root@localhost lkm]# insmod sysfs.ko [root@localhost lkm]# ls -l /sys/kernel/kset_hoge/hoge/ 合計 0 -rw-rw-rw- 1 root root 4096 10月 13 06:17 aaa -rw-rw-rw- 1 root root 4096 10月 13 06:17 bbb [root@localhost lkm]# echo hogehoge1 > /sys/kernel/kset_hoge/hoge/aaa [root@localhost lkm]# echo hogehoge2 > /sys/kernel/kset_hoge/hoge/bbb [root@localhost lkm]# cat /sys/kernel/kset_hoge/hoge/aaa from aaa hogehoge1 [root@localhost lkm]# cat /sys/kernel/kset_hoge/hoge/bbb from bbb hogehoge2
補足
struct kobject/struct attributeをオブジェクト/アトリビュートのstructのメンバー(コンテナ)とすることで、任意の実装することができ、またstruct attributeコンテナにコールバックを設定することで、属性(ファイル)毎に指定したコールバック関数をコールすることができます。ただし、.sysfs_opsの.show/.storeコールバック関数内で、所定のattrコールバック関数がコールされるようにする必要があります。サンプルでは、ret = kobject_init_and_add(kobj, &hoge_ktype, NULL, "%s", "hoge");と1つしかkset配下に登録していませんが、別のkobjを作成し、そのksetにhoge_ksetを設定して登録することで、随時kset配下のオブジェクトに登録されていくわけです。






