seq_file
seq_fileはobject単位で管理されているリソースを、シーケンシャルとして参照させる事で、カーネルのリスト管理されているリソースをvfs下のシーケンシャルread/writeで参照するproc等での利用を目的とした機能です。以下は、その機能に特化したサンプルです。
seq_next()の引数m, void *v, loff_t *posは、読み込まれたobjectと、そのインデックス(読み込まれたobjectの数)で、*vはobjectがリスト管理されている場合等に参照されることになります。
do_mmap()は、seq_read()の第二引数のバッファは、ファイルオペレーションのreadコールバック関数を想定して故、ユーザ空間である必要があります。
seq_open()は、seq_operationsコールバックをhoge_file.private_datに設定する事で、fileオペレーションでseq_operationsコールバックを介しての参照が可能となります。なお、.showコールバックは表示というのでなく、目的とするobjectを seq_file->bufに複写します。
実際のファイルシステム下の実装は、ファイルオペレーションのopenコールバック関数にseq_open()を、readコールバック関数にseq_read()を設定します。
seq_next()の引数m, void *v, loff_t *posは、読み込まれたobjectと、そのインデックス(読み込まれたobjectの数)で、*vはobjectがリスト管理されている場合等に参照されることになります。
do_mmap()は、seq_read()の第二引数のバッファは、ファイルオペレーションのreadコールバック関数を想定して故、ユーザ空間である必要があります。
seq_open()は、seq_operationsコールバックをhoge_file.private_datに設定する事で、fileオペレーションでseq_operationsコールバックを介しての参照が可能となります。なお、.showコールバックは表示というのでなく、目的とするobjectを seq_file->bufに複写します。
#include <linux/kernel.h> #include <linux/fs.h> #include <linux/slab.h> #include <linux/seq_file.h> #include <linux/uaccess.h> #include <linux/string.h> #include <linux/mman.h> #include <linux/moduleparam.h> static struct file hoge_file; static char hoge_data[10][10]; static int size; module_param(size, int, 0); static int seq_show(struct seq_file *m, void *v) { return seq_printf(m, "%s:", (char *)v); } static void *seq_start(struct seq_file *m, loff_t *pos) { return hoge_data[*pos]; } static void *seq_next(struct seq_file *m, void *v, loff_t *pos) { if(*pos >= 9) { return NULL; } return hoge_data[++*pos]; } static void seq_stop(struct seq_file *m, void *p) { seq_puts(m, "[end]\n"); } static const struct seq_operations hoge_op = { .start = seq_start, .next = seq_next, .show = seq_show, .stop = seq_stop }; void hogedata_init(void) { int i; for (i = 0; i < 10; i++) { sprintf(hoge_data[i], "hoge%d", i+1); } } static int __init seq_hoge_init(void) { long addr; loff_t pos = 0; hogedata_init(); addr = do_mmap(NULL, 0, 4012, PROT_READ|PROT_WRITE, MAP_ANONYMOUS|MAP_PRIVATE, 0); seq_open(&hoge_file, &hoge_op); seq_read(&hoge_file, (char __user *)addr, size, &pos); printk((char *)addr); return 0; } static void seq_hoge_exit(void) { seq_release(NULL, &hoge_file); } module_init(seq_hoge_init); module_exit(seq_hoge_exit);実行結果
[root@localhost lkm]# insmod seq_hoge.ko size=100 [root@localhost lkm]# dmesg [ 643.296579] hoge1:hoge2:hoge3:hoge4:hoge5:hoge6:hoge7:hoge8:hoge9:hoge10:[end] [root@localhost lkm]# insmod seq_hoge.ko size=10 [root@localhost lkm]# dmesg [ 693.053244] hoge1:hoge読込みサイズで全objectを読み込めない時、[end]が表示されていませんが、.stopコールバックはコールされ、seq_file.buffには設定されていますが(バッファは4K単位)、ユーザ空間バッファへ転送する時に転送されません。
実際のファイルシステム下の実装は、ファイルオペレーションのopenコールバック関数にseq_open()を、readコールバック関数にseq_read()を設定します。