PageCacheを覗いてみる
一度読み込んだファイルデータはページキャッシュとして、ページ単位でプロセスのfile->address_space->radix_tree_root->radix_tree_nodeに、radix-treeという形式で保存されています。そのページキャッシュを覗いてみたいと思います。
なお、キャッシュがページ(4012K)を満たない場合、radix-treeスロットが設定されるところに、直接ページキャッシュのアドレスが設定されるようになっているようです。検証はそれを前提にして行っています。
なお、キャッシュがページ(4012K)を満たない場合、radix-treeスロットが設定されるところに、直接ページキャッシュのアドレスが設定されるようになっているようです。検証はそれを前提にして行っています。
#include <linux/kernel.h> #include <linux/sched.h> #include <linux/module.h> #include <linux/proc_fs.h> #include <asm/uaccess.h> #include <linux/fdtable.h> #include <linux/pagemap.h> #define PROC_NAME "hogehoge" static size_t proc_write( struct file *filp, const char __user *buff, unsigned long len, void *data ); static struct proc_dir_entry *dirp; static int proc_init_module(void) { dirp = (struct proc_dir_entry *) create_proc_entry(PROC_NAME, 0666, (struct proc_dir_entry *) 0); if (dirp == 0) return(-EINVAL); dirp->write_proc = (write_proc_t *) proc_write; return 0; } static void proc_cleanup_module(void) { remove_proc_entry(PROC_NAME, (struct proc_dir_entry *) 0); } static void do_page_cache(struct task_struct *process) { int i, ans = 0; struct files_struct *files; struct address_space *mapping; struct radix_tree_node *node; struct page *page; files = process->files; // ファイルaのファイルディスクリプターの取得 for (i = 0; i < files->fdt->max_fds; i++) { if (files->fdt->fd[i]) { if (!strcmp(files->fdt->fd[i]->f_path.dentry->d_name.name, "a")) { ans = 1; break; } } } if (ans) { mapping = files->fdt->fd[i]->f_mapping; // 本来これがradix-treeスロットバッファーのポインターになるのですが、 // ページは1つだけということでここにページキャッシュのページが設定されるようです。 node = mapping->page_tree.rnode; page = node; // kmapはpageをリニアアドレスに変換するマクロです。 printk("%s\n", kmap(page)); } return 0; } static size_t proc_write( struct file *filp, const char __user *buff, unsigned long len, void *data ) { char _buff[64]; if (copy_from_user(_buff, buff, len )) { return -EFAULT; } int mypid = simple_strtol(_buff, NULL, 0); struct task_struct *process; process = find_task_by_vpid(mypid); if (process) { do_do_page_cache(process); } else { mypid = -1; printk("pid error:%d\n", mypid); return -EFAULT; } return len; } module_init(proc_init_module); module_exit(proc_cleanup_module);ユーザプロセス
#include <stdio.h> #include <fcntl.h> main() { int fd; char buff[100]; fd = open("a", O_RDONLY); if (fd) { read(fd, buff, sizeof(buff)); printf("%s\n", buff); while(1) sleep(100); } }aファイルを作成してユーザプロセスを起動
[root@localhost test]# echo "abcdefghijklmn" > a [root@localhost test]# ./a.out & [1] 5184 [root@localhost test]# abcdefghijklmn起動したユーザプロセスIDを/proc/hogehogeに書き込む
[root@localhost test]# ps PID TTY TIME CMD 1479 pts/0 00:00:03 bash 5184 pts/0 00:00:00 a.out 5185 pts/0 00:00:00 ps [root@localhost test]# echo 5184 > /proc/hogehoge [root@localhost test]# dmesg abcdefghijklmn