無料Wikiサービス | デモページ
Linuxなどのメモ書き
検索

Adsense

proc fs を使ったカーネル情報の表示 その2 の差分
Rev.7→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ができる。

Makefile
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


proc.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>
#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 を使ったカーネル情報の表示