proc fs を使ったカーネル情報の表示
Rev.16を表示中。最新版はこちら。
1.概要
Linuxでは/proc/配下に擬似ファイルシステム(proc fs)がマウントされており、ここの擬似的なファイルからカーネル内の様々な情報を簡単に取得できる。ここでは、proc fsにノードを作成して、カーネル内の情報を出力するモジュールの作り方をまとめる。Loadable Moduleとして作成する。
2. サンプルモジュール
proc fsにノードを作成して、そのノードからカーネル内の情報を出力するモジュールの例を以下に示す。2.1 SouceとMakefile
以下のMakefileとSource(proctest.c)を同じディレクトリに置いてmakeするとLoadable Module proctestmod.koができる(Loadable Moduleの基本的な作りはLoadable Kernel Moduleの作り方を参照)。
このモジュールはカーネルにロードされると/proc/に'test'という名前の擬似ファイルを作成する。そして、/proc/testの中を見るとこのモジュール内の関数のアドレスを表示する。
Makefile
KERNELSRCDIR = /usr/src/linux BUILD_DIR := $(shell pwd) VERBOSE = 0 # モジュール名 obj-m := proctestmod.o # <モジュール名>-objs にモジュールを構成するオブジェクトの一覧を列挙する proctestmod-objs := proctest.o all: make -C $(KERNELSRCDIR) SUBDIRS=$(BUILD_DIR) KBUILD_VERBOSE=$(VERBOSE) modules clean: rm -f *.o rm -f *.ko rm -f *.mod.c rm -f *~
proctest.c
#include <linux/config.h> #include <linux/types.h> #include <linux/module.h> #include <linux/kernel.h> #include <linux/fs.h> #include <linux/proc_fs.h> MODULE_DESCRIPTION("Proc FS Test Module"); MODULE_AUTHOR("kztomita"); MODULE_LICENSE("GPL"); #define PROC_NAME "test" static int proctest_read(char *, char **, off_t, int, int *, void *); static struct proc_dir_entry *dirp; static int proctest_init_module(void) { /* * Create a proc file. */ dirp = (struct proc_dir_entry *) create_proc_entry(PROC_NAME, 0444, (struct proc_dir_entry *) 0); if (dirp == 0) return(-EINVAL); dirp->read_proc = (read_proc_t *) proctest_read; return 0; } static void proctest_cleanup_module(void) { remove_proc_entry(PROC_NAME, (struct proc_dir_entry *) 0); } static int proctest_read(char *buffer, char **start, off_t offset, int count, int *peof, void *dat) { int len = 0; len += sprintf(buffer + len, "proctest_init_module():: 0x%08x\n", (unsigned int) proctest_init_module); len += sprintf(buffer + len, "proctest_cleanup_module():: 0x%08x\n", (unsigned int) proctest_cleanup_module); return len; } module_init(proctest_init_module); module_exit(proctest_cleanup_module);
2.2 実行結果
作成したモジュールをロードして/proc/testを読みだした結果は以下のとおり。# /sbin/insmod proctestmod.ko モジュールをロード # ls /proc/ | grep test test testファイルができている # more /proc/test カーネル内の情報(関数アドレス)が確認できる proctest_init_module():: 0xf88ee000 proctest_cleanup_module():: 0xf88ee03c #
3. 解説
3.1 ノードの作成
モジュールが読みこまれた時にproc fs上に擬似ファイル/proc/testを作成している。ファイルの作成にはcreate_proc_entry()を使用する。
struct proc_dir_entry *create_proc_entry(const char *name, mode_t mode, struct proc_dir_entry *parent)
引数nameはファイル名、modeはパーミッション、parentはファイルを作る親ディレクトリのディレクトリエントリを指定する(*1)。NULLを指定すると、/proc直下に作成される。返り値は作成したノードのディレクトリエントリであるstruct proc_dir_entryへのポインタを返す。
ファイルを作成した後は、ファイルをRead/Writeした時にファイルシステムから呼び出されるハンドラを登録する。ハンドラはRead/Writeでそれぞれ、proc_dir_entry.read_proc,write_procに登録する。上記のサンプルではReadのみ処理するためread_procのみ指定している。
(*1) ディレクトリを作成したい場合は、proc_mkdir()を使用する。ディレクトリを指定するにはproc_mkdir()で返されたstruct proc_dir_entry をcreate_proc_entry()のparentに渡せばよい。3.2 Readハンドラ
File SystemからよびだされるReadルーチン。関数のプロトタイプは以下のとおり。
int f(char *buffer, char **start, off_t offset, int count, int *peof, void *dat)
各引数の意味は表1の通り。
引数 |
説明 |
---|---|
buffer |
データ格納用Bufferの先頭アドレス。ハンドラはこの領域にデータを格納して返す。 |
start |
呼び出し時の初期値は *start == NULL。*startに後に示す値を入れてリターンすることで、呼び出したFile SystemとReadハンドラ間のインタフェースが決まる。 |
offset |
Readすべきデータのoffset。 |
count |
bufferが指しているバッファのサイズ |
peof |
データがもうない(EOF)ことを呼び出し側に知らせるのに使用する。 *peof = 1としてリターンする。 |
dat |
|
作成中
3.3 File SystemとReadハンドラのインタフェース