sysfs tips
GNU/Linux において、ユーザ/カーネル間でのメッセージのやりとりのインターフェイスの一つといて一般的に知られている sysfs だが。今日は、デバイスドライバ等で広く利用されている、sysfs エントリの追加/削除の手法について記載する。
sysfs のエントリ追加は block や bus といったエントリのサブエントリとして追加するようになり、各エントリの追加方法は、親エントリによってインターフェイスが変わってくる。以前にも、io スケジューラにおける sysfs エントリの扱いについて調べたが、今回はその方法とは違ったやり方で、エントリの更新を行う。
今回紹介するのは class へのサブエントリの追加/削除の方法になる。
多くのデバイスドライバにおいて、class エントリ配下に自前で宣言したディレクトリエントリの追加を行う際に、モジュールの
module_init マクロで指定したロード関数から class_create() [driver/base/class.c] を呼び出す。
第一引数には、登録を行う struct module * 型オブジェクトを指定する。これは THIS_MODULE
マクロによって、現在ロードするモジュールの struct module *
オブジェクトを指定できる。また、第二引数に追加するディレクトリエントリ表示名を指定する。
また、削除はアンロード関数から class_destroy() を指定する。
次に、class に追加したディレクトリに、属性 (attribute) を追加する処理を見て行く。ただ "属性" というのはあくまで内部的な扱で、見かけはオンメモリのファイルの追加である。
登録は class_create_file() 関数に struct class_attribute
*型オブジェクトを指定して行う。class_attribute *型オブジェクトの宣言については、io スケジューラの場合同様に __ATTR
マクロがそのまま使える。ただし、get/set 関数のプロトタイプ宣言は異なるので、struct class_attribute *
[include/linux/device.h] を確認しながら行う。
エントリに登録した属性の削除は、class_remove_file() によって行う。
以上より、これらの内容をコードにすると次のようになる。
struct class *foo_class;
static struct class_attribute foo_debug_file = __ATTR(hoge, S_IRUGO, NULL, NULL);
static int foo_init_module(void)
{
foo_class = class_create(THIS_MODULE, "foo");
if(IS_ERR(foo_class)){
return 1;
}
err = class_create_file(foo_class, &foo_debug_file);
if(err){
class_destroy(foo_class);
return 1;
}
return 0;
}
static void foo_cleanup_module(void)
{
class_remove_file(foo_class, &foo_debug_file);
class_destroy(foo_class);
}
module_init(foo_init_module);
module_exit(foo_cleanup_module);
これで、/sys/foo というエントリを追加し、/sys/foo/hoge というファイルが存在する事が確認できる。
注意:VM 等のサンドボックスで実行する事を強くお勧めする
- Category(s)
- GNU/Linux
- The URL to Trackback this entry is:
- http://dev.ariel-networks.com/Members/ohyama/sysfs-tips/tbping
sysfs tips 02
今回は、カーネルモジュールに対するパラメータの登録/設定方法について書く。
module_param() マクロによって、カーネルモジュールのロード時、及びロード後にモジュールがエクスポートしたパラメータを設定/参照する事が可能になる。ロード時にパラメータ設定を行い、以降いじれないようにする事もできる (むしろこれが一般的かもしれない) 。
コードは次のようになる。
1 #include <linux/module.h>
2 #include <linux/kernel.h>
3 #include <linux/namei.h>
4 #include <linux/dcache.h>
5 #include <linux/genhd.h>
6 #include <linux/kobject.h>
7 #include <linux/device.h>
8 #include <linux/sysfs.h>
9 #include <linux/miscdevice.h>
10
11 MODULE_DESCRIPTION("hoge");
12 MODULE_AUTHOR("H.OHYAMA");
13 MODULE_LICENSE("GPL");
14
15 static int val = 0;
16
17 static int hoge_init_module(void)
18 {
19 printk(KERN_ERR "kmodule [hoge] > val : %d\n", val);
20
21 return 0;
22 }
23
24 static void hoge_cleanup_module(void)
25 {
26 }
27
28 module_init(hoge_init_module);
29 module_exit(hoge_cleanup_module);
30
31 module_param(val, int , 0644);
パラメータ自体はプログラム内部の変数を対象とし、module_param() マクロで、パラメータの型とパーミッションを設定する。
型を指定するのは、パラメータ設定/参照の際に、数値や文字列などの型に応じた処理を行う必要があるためである。これらの型に応じた処理はそれぞれ kernel/params.c で定義されている。
またパラメータの設定/参照は、/sys/module/${modulename}/parameters/${parameter} から行うことができる。今回の場合では、/sys/module/hogemod/parameters/val となる。
ちなみに、module_param() マクロのパーミッション指定を 0000 とすると、このインターフェイスは存在しなくなる。
また次のように insmod 実行時にパラメータの値を設定することも出来る。パラメータを指定しているいくつかのカーネルモジュールでは、パーミッションを 0000 に設定することで、パラメータを insmod 時のみ設定可能なようにしている。
ちなみに、パラメータ設定はロード関数実行よりも前に行われるので、次のようにロード関数から設定されたパラメータ値を見ることができる。
最後に、module_param() マクロの中をもうちょっと詳しく見てみる。
module_param() マクロでは、型を指定する事で、各型毎の設定/参照関数が呼ばれるのだが。これを行うのが module_param_call() マクロになる。具体的には、module_param() で指定された型 (type) 毎に param_set_##type/param_get_##type がパラメータ設定/参照時に呼び出されるれ、module_param() で指定した変数に値が格納/参照される。
module_param_call() を自前で設定する事で、以下のようにパラメータ設定/参照時に実行されるコールバック関数を自前処理にする事もできる。
まずはコード。
1 #include <linux/module.h>
2 #include <linux/kernel.h>
3 #include <linux/namei.h>
4 #include <linux/dcache.h>
5 #include <linux/genhd.h>
6 #include <linux/kobject.h>
7 #include <linux/device.h>
8 #include <linux/sysfs.h>
10
11 MODULE_DESCRIPTION("hoge02");
12 MODULE_AUTHOR("H.OHYAMA");
13 MODULE_LICENSE("GPL");
14
15 static int val;
16 static int hoge_param_set(const char *, struct kernel_param *);
17 static int hoge_param_get(char *, struct kernel_param *);
18
19 static int hoge_param_set(const char *str, struct kernel_param *kp)
20 {
21 printk(KERN_ERR "hoge_param_set > str : %s\n", str);
22
23 return 0;
24 }
25
26 static int hoge_param_get(char *str, struct kernel_param *kp)
27 {
28 return sprintf(str, "hoge_param_get");
29 }
30
31 static int hoge_init_module(void)
32 {
33 return 0;
34 }
35
36 static void hoge_cleanup_module(void)
37 {
38 }
39
40 module_init(hoge_init_module);
41 module_exit(hoge_cleanup_module);
42 module_param_call(val, hoge_param_set, hoge_param_get, NULL, 0644);
続いて実行結果。
- Category(s)
- GNU/Linux
- The URL to Trackback this entry is:
- http://dev.ariel-networks.com/Members/ohyama/sysfs-tips-02/tbping