φ(.. )メモシテオコウ debugfsのインターフェース

前も調べたことあった気がするけど忘れても良いようにメモを。

まずディレクトリを作成するのはdebugfs_create_dir()で1番目の引数はディレクトリ名、2番目はディレクトリを作りたい場所のdentryでNULLを渡せばdebugfsをマウントしている場所になる。例えばdebugfs_create_dir("foobar", NULL)を実行した時に/sys/kernel/debugがdebugfsのマウント先なら/sys/kernel/debug/foobarとなる。ディレクトリを作ったら読み書きしたい変数にアクセスするためのファイルを作成。この場合、方法は大雑把に2種類あって1つ目はdebugfs_create_file()を使う、もう1つはdebugfs_create_XXXのシリーズを使う(debugfs_create_u32とか)。前者はデータの読み書きをするためにfile_operations構造体にreadとかwriteをするための関数ポインタを登録してdebugfs_create_file()の引数として渡す必要がある。後者の場合は読み書きしたいデータのポインタを渡して、読み書きの処理自体をdebugfs_create_XXXに任せることができる。
マウントを終了したい場合はdebugfs_remove_recursive()にdebugfs_create_dir()の戻り値であるdentryを渡すと再帰的にクローズしてくれるらしい。

以下はu32型のデータを読み書きと、char型のデータを読み書きするサンプル。dtest_u32_dataの読み書きするためにdebugfs_create_u32()でファイルを作成し、データのrw処理はお任せ。char型のdtest_file_dataはdtest_read()とdtest_write()で実施。さらに読み書き時に特別な処理は不要だったのでsimple_read_from_buffer()、simple_write_to_buffer()というfs/libfs.cにある関数に処理を丸投げ。

#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/debugfs.h>

MODULE_DESCRIPTION("dtest module");
MODULE_AUTHOR("masami256");
MODULE_LICENSE("GPL");

static void dtest_remove_debugfs_dir(void);

static ssize_t dtest_read(struct file *filp, char __user *buf, size_t len, loff_t *ppos);
static ssize_t dtest_write(struct file *filp, const char __user *buf, size_t len, loff_t *ppos); 

static struct dentry *dtest_dir;
static struct dentry *dtest_u32_file;
static struct dentry *dtest_file;

static u32 dtest_u32_data;
static char dtest_file_data[32];

static struct file_operations dtest_fops = {
	.owner = THIS_MODULE,
	.read = dtest_read,
	.write = dtest_write,
};

static ssize_t
dtest_read(struct file *filp, char __user *buf, size_t len, loff_t *ppos)
{
	return simple_read_from_buffer(buf, len, ppos, dtest_file_data, sizeof(dtest_file_data));
}

static ssize_t
dtest_write(struct file *filp, const char __user *buf, size_t len, loff_t *ppos)
{
	return simple_write_to_buffer(dtest_file_data, sizeof(dtest_file_data), ppos, buf, len);
}

static void
dtest_remove_debugfs_dir(void)
{
	if (dtest_dir)
		debugfs_remove_recursive(dtest_dir);
}

static int
dtest_check_debugfs_create_func_result(const struct dentry *entry)
{
	if (!entry)
		return -1;

	if (ERR_PTR(-ENODEV) == entry)
		return -ENODEV;

	return 0;
}

static int 
dtest_create_debugfs_directory(void)
{
	dtest_dir = debugfs_create_dir("dtest", NULL);
	return dtest_check_debugfs_create_func_result(dtest_dir);
}
	
static int
dtest_create_debugfs_u32_file(void)
{
	dtest_u32_file = debugfs_create_u32("dtest_u32", 0644, dtest_dir, &dtest_u32_data);
	return dtest_check_debugfs_create_func_result(dtest_u32_file);
}

static int
dtest_create_file(void)
{
	dtest_file = debugfs_create_file("dtest_file", 0644, dtest_dir, &dtest_file_data, &dtest_fops);
	return dtest_check_debugfs_create_func_result(dtest_file);
}

static int
dtest_init(void)
{
	int ret = -1;

	printk(KERN_INFO"[-]dtest module is loaded\n");

	ret = dtest_create_debugfs_directory();
	if (ret)
		goto error_out;

	ret = dtest_create_debugfs_u32_file();
	if (ret)
		goto error_out;
	
	ret = dtest_create_file();
	if (ret)
		goto error_out;

	strcpy(dtest_file_data, "dtest");
	return 0;

error_out:
	dtest_remove_debugfs_dir();
	return ret;
}

static void
dtest_cleanup(void)
{
	dtest_remove_debugfs_dir();
	printk(KERN_INFO"[-]dtest module is unloaded\n");
}

module_init(dtest_init);
module_exit(dtest_cleanup);