proc経由でkernelとやり取りしてみる
procインタフェースを利用してユーザランドのアプリケーションとカーネルでデータをやりとりするサンプルです。
具体的には下記のようにechoでリダイレクトした文字列をカーネルで受信して、catで覗くとリダイレクトした文字列が表示されるような簡単なカーネルモジュールを作ります。開発環境はCentOS7です。
完成イメージ
$ echo "hello" > /proc/example
$ cat /proc/example
hello
$
[rtoc_mokuji title=”” title_display=”” heading=”h3″ list_h2_type=”” list_h3_type=”” display=”” frame_design=”” animation=””]
目次
ソースコード
procmod.c
#include <linux/module.h>
#include <linux/init.h>
#include <linux/proc_fs.h>
#include <linux/seq_file.h>
#include <linux/string.h>
static char example[64] = {0};
static ssize_t
example_write(
struct file *filp,
const char __user *buff,
size_t user_len,
loff_t *offset )
{
size_t len = 0;
if (0 != *offset)
return -EINVAL;
memset(example, 0, sizeof(example));
len = user_len > sizeof(example) ? sizeof(example) : user_len;
memcpy(example, buff, len);
example[len-1] = '\n';
printk(KERN_INFO "example: wrote - %s", example);
return user_len;
}
/* /proc/exampleの内容を表示 */
static int
example_show(
struct seq_file *p,
void *v)
{
seq_printf(p, "%s", example);
printk(KERN_INFO "example: show - %s", example);
return 0;
}
/* cat /proc/exampleで実行される */
static int
example_open(
struct inode *inode,
struct file *file)
{
return single_open(file, example_show, NULL);
}
static const struct file_operations proc_example_operations = {
.owner = THIS_MODULE,
.open = example_open,
.read = seq_read,
.llseek = seq_lseek,
.release = single_release,
.write = example_write,
};
/* insmod実行時に呼び出される */
static int proc_example_init(void)
{
proc_create("example", S_IRUGO | S_IWUGO, NULL, &proc_example_operations);
printk(KERN_INFO "example: Module loaded, and created /proc/example\n");
return 0;
}
/* rmmod実行時に呼び出される */
static void proc_example_exit(void)
{
remove_proc_entry("example", NULL);
printk(KERN_INFO "example: Module unloaded.\n");
}
module_init(proc_example_init);
module_exit(proc_example_exit);
MODULE_LICENSE("GPL");
MODULE_DESCRIPTION("Example Kernel Module");
Makefile
obj-m := procmod.o
all:
make -C /lib/modules/$(shell uname -r)/build M=$(PWD) modules
clean:
make -C /lib/modules/$(shell uname -r)/build M=$(PWD) clean
実行結果
ビルドしてカーネルモジュールをロードします。
$ make
make -C /lib/modules/3.10.0-514.26.2.el7.x86_64/build M=/home/user/driver/proc modules
make[1]: Entering directory `/usr/src/kernels/3.10.0-514.26.2.el7.x86_64'
CC [M] /home/user/driver/proc/procmod.o
Building modules, stage 2.
MODPOST 1 modules
CC /home/user/driver/proc/procmod.mod.o
LD [M] /home/user/driver/proc/procmod.ko
make[1]: Leaving directory `/usr/src/kernels/3.10.0-514.26.2.el7.x86_64'
$
$ sudo insmod procmod.ko
$ lsmod |grep procmod
procmod 12702 0

ちゃんとアプリ、カーネル間でデータをやりとりできました。
次回は/dev/にスペシャルファイルを作ってアプリとカーネル間でepoll,ioctlを使った通信を試したいと思います。
コメント