configfs
configfsはprocfs/sysfsと同じように、ユーザ空間/カーネル空間をファイルを介してやり取りをするファイルシステムです。configfsの場合、このインターフェースとなるファイルをユーザ空間から制御できるということです。ただし、ユーザ空間で作成されるサブシステムグループと称するディレクトリので、配下のファイルはカーネルサイドマターです。
以下は、カーネルソースにインプリメントされているconfigfs_example_explicit.cを、configfsの本質が理解しやすいように、特化してモディファイしたサンプルです。
カーネル空間から作成されるサブシステムと称するbase_dirディレクトリに、ユーザ空間で作成されるサブシステムグループのディレクトリを作成すると、hoge_root_make_item()でをコールされ、配下にconfigfs_attributeで定義するファイルが作成されます。サンプルでは、obj_file1/obj_file2の2つのファイルが作成されますが、参照のコールバックは同じとなっています。
また、サブシステムグループファイルのデータもすべて共有となっていますが、サブシステムディレクトリを作成するhoge_root_make_item()で、kzalloc()としている故で、その動作については、configfsの機能マターでなく、利用する実装サイドに寄ります。
動作にあたって、configfsをmountしてますが、その必要はありません。先にconfigfsにサブシステムを作成した後に、configfsをmountしても先に作成したサブシステムグループ下のディレクトリが作成された形でマウントされます。
なお、カーネルのnfigfs_example_explicit.cは、サブシステムディレクトリもユーザ空間から作成出来るようにしています。この機能はconfigfs自身で実装されているものです。
以下は、カーネルソースにインプリメントされているconfigfs_example_explicit.cを、configfsの本質が理解しやすいように、特化してモディファイしたサンプルです。
カーネル空間から作成されるサブシステムと称するbase_dirディレクトリに、ユーザ空間で作成されるサブシステムグループのディレクトリを作成すると、hoge_root_make_item()でをコールされ、配下にconfigfs_attributeで定義するファイルが作成されます。サンプルでは、obj_file1/obj_file2の2つのファイルが作成されますが、参照のコールバックは同じとなっています。
また、サブシステムグループファイルのデータもすべて共有となっていますが、サブシステムディレクトリを作成するhoge_root_make_item()で、kzalloc()としている故で、その動作については、configfsの機能マターでなく、利用する実装サイドに寄ります。
#include <linux/init.h> #include <linux/module.h> #include <linux/slab.h> #include <linux/dcache.h> #include <linux/configfs.h> struct hoge_obj { struct config_item item; char param[64]; }; static inline struct hoge_obj *to_hoge_obj(struct config_item *item) { return item ? container_of(item, struct hoge_obj, item) : NULL; } static struct configfs_attribute obj_file1 = { .ca_owner = THIS_MODULE, .ca_name = "param1", .ca_mode = S_IRUGO | S_IWUSR, }; static struct configfs_attribute obj_file2 = { .ca_owner = THIS_MODULE, .ca_name = "param2", .ca_mode = S_IRUGO | S_IWUSR, }; static struct configfs_attribute *hoge_obj_attrs[] = { &obj_file1, &obj_file2, NULL, }; static ssize_t hoge_obj_attr_show(struct config_item *item, struct configfs_attribute *attr, char *page) { ssize_t count; struct hoge_obj *hoge_obj = to_hoge_obj(item); count = sprintf(page, "dir[%s]:file[%s]:data[%s]\n", item->ci_name, item->ci_dentry->d_name.name, hoge_obj->param); return count; } static ssize_t hoge_obj_attr_store(struct config_item *item, struct configfs_attribute *attr, const char *page, size_t count) { struct hoge_obj *hoge_obj = to_hoge_obj(item); char *p = (char *) page; printk("configfs:%s\n", p); strcpy(hoge_obj->param, p); return count; } static void hoge_obj_release(struct config_item *item) { kfree(to_hoge_obj(item)); } static struct configfs_item_operations hoge_obj_item_ops = { .release = hoge_obj_release, .show_attribute = hoge_obj_attr_show, .store_attribute = hoge_obj_attr_store, }; static struct config_item_type hoge_obj_type = { .ct_item_ops = &hoge_obj_item_ops, .ct_attrs = hoge_obj_attrs, .ct_owner = THIS_MODULE, }; struct hoge_root { struct config_group group; }; static inline struct hoge_root *to_hoge_root(struct config_item *item) { return item ? container_of(to_config_group(item), struct hoge_root, group) : NULL; } static struct config_item *hoge_root_make_item(struct config_group *group, const char *name) { struct hoge_obj *hoge_obj; hoge_obj = kzalloc(sizeof(struct hoge_obj), GFP_KERNEL); if (!hoge_obj) return ERR_PTR(-ENOMEM); config_item_init_type_name(&hoge_obj->item, name, &hoge_obj_type); strcpy(hoge_obj->param, "init"); return &hoge_obj->item; } static void hoge_root_release(struct config_item *item) { kfree(to_hoge_root(item)); } static struct configfs_item_operations hoge_root_item_ops = { .release = hoge_root_release, }; static struct configfs_group_operations hoge_root_group_ops = { .make_item = hoge_root_make_item, }; static struct config_item_type hoge_root_type = { .ct_item_ops = &hoge_root_item_ops, .ct_group_ops = &hoge_root_group_ops, .ct_owner = THIS_MODULE, }; static struct configfs_subsystem hoge_root_subsys = { .su_group = { .cg_item = { .ci_namebuf = "base_dir", .ci_type = &hoge_root_type, }, }, }; static int __init configfs_example_init(void) { int ret; struct configfs_subsystem *subsys; subsys = &hoge_root_subsys; config_group_init(&subsys->su_group); mutex_init(&subsys->su_mutex); ret = configfs_register_subsystem(subsys); if (ret) { printk(KERN_ERR "Error %d while registering subsystem %s\n", ret, subsys->su_group.cg_item.ci_namebuf); goto out_unregister; } return 0; out_unregister: configfs_unregister_subsystem(subsys); return ret; } static void __exit configfs_example_exit(void) { configfs_unregister_subsystem(&hoge_root_subsys); } module_init(configfs_example_init); module_exit(configfs_example_exit);
実行結果
[root@localhost lkm]# mount -t configfs none /config [root@localhost lkm]# insmod hoge_configfs.ko [root@localhost lkm]# ls /config/ base_dir [root@localhost lkm]# mkdir /config/base_dir/a [root@localhost lkm]# mkdir /config/base_dir/b [root@localhost lkm]# ls /config/base_dir/ a b [root@localhost lkm]# ls /config/base_dir/a param1 param2 [root@localhost lkm]# ls /config/base_dir/b param1 param2 [root@localhost lkm]# cat /config/base_dir/a/param1 dir[a]:file[a]:data[init] [root@localhost lkm]# cat /config/base_dir/a/param2 dir[a]:file[a]:data[init] [root@localhost lkm]# echo hoge > /config/base_dir/a/param1 [root@localhost lkm]# cat /config/base_dir/a/param1 dir[a]:file[a]:data[hoge] [root@localhost lkm]# cat /config/base_dir/a/param2 dir[a]:file[a]:data[hoge] [root@localhost lkm]# cat /config/base_dir/b/param1 dir[b]:file[b]:data[init] [root@localhost lkm]# cat /config/base_dir/b/param2 dir[b]:file[b]:data[init] [root@localhost lkm]# chmod -r /config/base_dir/b/param1 [root@localhost lkm]# cat /config/base_dir/b/param1 cat: /config/base_dir/b/param1: 許可がありません
補足
hoge_obj_attr_show()でitem->ci_dentry->d_name.nameは、直接参照してるファイル(param1/param2)かと思っていましたが、そうでなくサブシステムグループのディレクトリとなっています。思うにサブシステムグループ下のファイルは、vfs下で管理されないまさにconfigfs下でのバーチャルなファイルではないかと思います。動作にあたって、configfsをmountしてますが、その必要はありません。先にconfigfsにサブシステムを作成した後に、configfsをmountしても先に作成したサブシステムグループ下のディレクトリが作成された形でマウントされます。
なお、カーネルのnfigfs_example_explicit.cは、サブシステムディレクトリもユーザ空間から作成出来るようにしています。この機能はconfigfs自身で実装されているものです。