Linuxなどのメモ書き

proc fs を使ったカーネル情報の表示 その2


Rev.7を表示中。最新版はこちら

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 ノードの作成

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()を登録しておけばよい。



作成中

関連ページ

Loadable Kernel Moduleの作り方
proc fs を使ったカーネル情報の表示


最終更新 2006/12/11 18:48:54 - kztomita
(2006/11/30 01:52:44 作成)


リンク

その他のWiki
Linuxメモ
Xnuメモ

会社
(有)ビットハイブ
受託開発やってます。

よくやる仕事

・Webシステム開発(LAMP環境)
・Linuxサーバー設定関連
サーバー移転作業代行

開発事例にデジタルカタログ/マンガビューワーを追加しました。

draggable.jsのスマホ対応版デモページを追加しました。説明はこちら

検索

Adsense
最近のコメント