proc fs を使ったカーネル情報の表示 その2
Rev.8を表示中。最新版はこちら。
1. 概要
proc fs を使ったカーネル情報の表示ではproc fsを使用してカーネル内の情報を表示する方法を示した。この方法では、バッファに収まる小さいデータを出力するのに適していたが、ここでは、seq_fileを使用してプロセス情報のようなレコード情報を大量に出力する方法を示す。
2. サンプルモジュール
2.1 Source
以下サンプルは/proc/processを読むと、全プロセスの情報(task_structのアドレス、mm_structのアドレス、ページディレクトリの内容)を出力する。
MakefileとSource(proc.c)を同じディレクトリに置いてmakeするとprocmod.koができる。
KERNELSRCDIR = /usr/src/linux BUILD_DIR := $(shell pwd) VERBOSE = 0 # obj-m にモジュール名を定義 obj-m := procmod.o procmod-objs := proc.o include $(KERNELSRCDIR)/.config all: make -C $(KERNELSRCDIR) SUBDIRS=$(BUILD_DIR) \ KBUILD_VERBOSE=$(VERBOSE) modules
#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> #include <linux/seq_file.h> static int process_init_module(void); static void process_cleanup_module(void); static int procinfo_open(struct inode *, struct file *); static void *s_start(struct seq_file *, loff_t *); static void *s_next(struct seq_file *, void *, loff_t *); static void s_stop(struct seq_file *, void *); static int s_show(struct seq_file *, void *); MODULE_DESCRIPTION("Process Information"); MODULE_AUTHOR("Kazuyoshi Tomita"); MODULE_LICENSE("GPL"); #define ENTRY_NAME "process" static struct proc_dir_entry *infop; /* seq_file用 file_operations */ static struct file_operations proc_procinfo_operations = { .open = procinfo_open, .read = seq_read, .llseek = seq_lseek, .release = seq_release, }; /* seq_file用のハンドラ */ struct seq_operations procinfo_op = { .start = s_start, .next = s_next, .stop = s_stop, .show = s_show, }; static int process_init_module(void) { /* * Create a proc file. */ infop = (struct proc_dir_entry *) create_proc_entry(ENTRY_NAME, 0444, (struct proc_dir_entry *) 0); if(infop == 0) { return(-EINVAL); } infop->proc_fops = &proc_procinfo_operations; return(0); } /* Cleanup - undo whatever init_module did */ static void process_cleanup_module(void) { remove_proc_entry( ENTRY_NAME, (struct proc_dir_entry *) 0); } static int procinfo_open(struct inode *inode, struct file *file) { return seq_open(file, &procinfo_op); } static void *s_start(struct seq_file *m, loff_t *pos) { struct task_struct *taskp; int i; if (*pos == 0) { seq_puts(m, "## Process Information ##\n"); } read_lock(&tasklist_lock); taskp = &init_task; for (i = 0 ; i < *pos ; i++) { taskp = next_task(taskp); if (taskp == &init_task) { read_unlock(&tasklist_lock); return NULL; } } read_unlock(&tasklist_lock); return taskp; } static void *s_next(struct seq_file *m, void *p, loff_t *pos) { struct task_struct *taskp = (struct task_struct *) p; read_lock(&tasklist_lock); ++*pos; taskp = next_task(taskp); if (taskp == &init_task) taskp = NULL; read_unlock(&tasklist_lock); return taskp; } static void s_stop(struct seq_file *m, void *p) { } static int s_show(struct seq_file *m, void *p) { struct task_struct *taskp = (struct task_struct *) p; int i; seq_printf(m, "\ttask\t0x%08x\n", (unsigned int) taskp); seq_printf(m, "\tmm\t%08x\n", (unsigned int) taskp->mm); seq_printf(m, "\tactive\t%08x\n", (unsigned int) taskp->active_mm); if (taskp->active_mm) { pgd_t *pgd = taskp->active_mm->pgd; seq_printf(m, "\tpgd\t%08x\n", (unsigned int) pgd); if (pgd) { for (i = 768 ; i < 773 ; i+=4) { seq_printf(m, "\t%08x %08x %08x %08x\n", (unsigned int) pgd[i].pgd, (unsigned int) pgd[i+1].pgd, (unsigned int) pgd[i+2].pgd, (unsigned int) pgd[i+3].pgd); } } } seq_puts(m, "\n"); return 0; } module_init(process_init_module); module_exit(process_cleanup_module);
2.2 実行結果
作成したモジュールをロードして/proc/processを読みだした結果は以下のとおり。# /sbin/insmod procmod.ko # more /proc/process ## Process Information ## task 0xc046cbe0 mm 00000000 active f5eec080 pgd f4130000 000001e3 004001e3 008001e3 00c001e3 010001e3 014001e3 018001e3 01c001e3 task 0xc1d4fa30 mm f7e94a80 active f7e94a80 pgd f7e98000 000001e3 004001e3 008001e3 00c001e3 010001e3 014001e3 018001e3 01c001e3 <略>
3. 解説
3.1 ノードの作成
モジュール初期化時(process_init_module())にcreate_proc_entry()でproc fs上にファイルを作成するのは、「proc fs を使ったカーネル情報の表示」と同じ。
ファイル(/proc/process)を作成した後は、ファイルへアクセスした時のハンドラ群を登録する。これには、create_proc_entry()が返したstruct proc_dir_entryのproc_fopsに/proc/process用のstruct file_operationsを定義して登録すればよい。ここでは/proc/process用のstruct file_operationsとしてproc_procinfo_operationsを定義している。proc_procinfo_operationsは.openのみseq_fileをopenするための自前のルーチンprocinfo_open()を指定して後はseq_file.cが提供しているルーチンseq_read(), seq_lseek(), seq_release()を登録しておけばよい。
3.2 ファイルのオープン
/proc/processがopenされるとproc_fops.openに登録したprocinfo_open()が呼び出される。procinfo_open()はseq_open()でseq_fileをopenする。seq_open()では、seq_fileにアクセスした時のハンドラ群seq_operationsを登録する。
表1 struct seq_operations のフィールド
フィールド |
説明 |
---|---|
start |
|
next |
|
stop |
|
show |
|
3.3 seq_fileのハンドラ
作成中
関連ページ
Loadable Kernel Moduleの作り方proc fs を使ったカーネル情報の表示