vm_area_structの仮想空間
プロセス作成は親プロセスのtask_structをcloneで複写し、execで動作プロセスのメモリを確保しロードします。この子プロセスが使用するメモリはtask_struct->mm_struct->vm_area_structに設定されます。これは仮想アドレスで/proc/プロセスID/mapsで表示されるものです。なお必要とされるまで実メモリーは確保されていません。このプロセスが使う仮想メモリを見てみようと思います。
#include <linux/kernel.h> #include <linux/sched.h> #include <linux/module.h> #include <linux/proc_fs.h> #include <asm/uaccess.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_vm_area(struct task_struct *process) { struct mm_struct *mm; struct vm_area_struct *vm_area; int i; mm = process->mm; vm_area = mm->mmap; printk("vm_area %d:\n", mm->map_count); for (i = 0; i < mm->map_count; i++) { printk("%08x-%08x\n", vm_area->vm_start, vm_area->vm_end); vm_area = vm_area->vm_next; } } 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_vm_area(process); } else { mypid = -1; printk("pid error:%d\n", mypid); return -EFAULT; } return len; } module_init(proc_init_module); module_exit(proc_cleanup_module);動作確認
root@localhost test]# insmod test.ko [root@localhost test]# ps PID TTY TIME CMD 1477 pts/0 00:00:01 bash 2579 pts/0 00:00:00 ps [root@localhost test]# echo 1477 > /proc/hogehoge [root@localhost test]# dmesg vm_area 33: 00294000-00295000 002e7000-002f2000 002f2000-002f3000 002f3000-002f4000 00428000-00440000 00440000-00441000 00441000-00442000 0079d000-007b3000 007b3000-007b6000 00ad0000-00af0000 00af1000-00af2000 00af2000-00af3000 00af5000-00c63000 00c63000-00c65000 00c65000-00c66000 00c66000-00c69000 00c96000-00c99000 00c99000-00c9a000 00c9a000-00c9b000 00f49000-00f4c000 00f4c000-00f4d000 00f4d000-00f4e000 08047000-080fb000 080fb000-08100000 08100000-08105000 09615000-09656000 b7dce000-b7dea000 b7dea000-b7dec000 b7dec000-b7df3000 b7df3000-b7ed7000 b7ed7000-b80d7000 b80d7000-b80d9000 bfc3e000-bfc53000これがbashが使う仮想メモリー空間ということです。/proc/1477/mapsの内容とぴったり一致いたします。注目するところは最後がbfc53000までということです。c0000000はカーネル空間が使うアドレスで一般プロセスは使用できないからです。
[root@localhost test]# cat /proc/1477/maps 00294000-00295000 r-xp 00294000 00:00 0 [vdso] 002e7000-002f2000 r-xp 00000000 fd:00 409723 /lib/libnss_files-2.9.so 002f2000-002f3000 r--p 0000a000 fd:00 409723 /lib/libnss_files-2.9.so 002f3000-002f4000 rw-p 0000b000 fd:00 409723 /lib/libnss_files-2.9.so 00428000-00440000 r-xp 00000000 fd:00 386058 /usr/lib/gconv/libJIS.so 00440000-00441000 r--p 00017000 fd:00 386058 /usr/lib/gconv/libJIS.so 00441000-00442000 rw-p 00018000 fd:00 386058 /usr/lib/gconv/libJIS.so 0079d000-007b3000 r-xp 00000000 fd:00 465706 /lib/libtinfo.so.5.6 007b3000-007b6000 rw-p 00015000 fd:00 465706 /lib/libtinfo.so.5.6 00ad0000-00af0000 r-xp 00000000 fd:00 464272 /lib/ld-2.9.so 00af1000-00af2000 r--p 00020000 fd:00 464272 /lib/ld-2.9.so 00af2000-00af3000 rw-p 00021000 fd:00 464272 /lib/ld-2.9.so 00af5000-00c63000 r-xp 00000000 fd:00 464273 /lib/libc-2.9.so 00c63000-00c65000 r--p 0016e000 fd:00 464273 /lib/libc-2.9.so 00c65000-00c66000 rw-p 00170000 fd:00 464273 /lib/libc-2.9.so 00c66000-00c69000 rw-p 00c66000 00:00 0 00c96000-00c99000 r-xp 00000000 fd:00 464279 /lib/libdl-2.9.so 00c99000-00c9a000 r--p 00002000 fd:00 464279 /lib/libdl-2.9.so 00c9a000-00c9b000 rw-p 00003000 fd:00 464279 /lib/libdl-2.9.so 00f49000-00f4c000 r-xp 00000000 fd:00 385855 /usr/lib/gconv/EUC-JP.so 00f4c000-00f4d000 r--p 00002000 fd:00 385855 /usr/lib/gconv/EUC-JP.so 00f4d000-00f4e000 rw-p 00003000 fd:00 385855 /usr/lib/gconv/EUC-JP.so 08047000-080fb000 r-xp 00000000 fd:00 395533 /bin/bash 080fb000-08100000 rw-p 000b3000 fd:00 395533 /bin/bash 08100000-08105000 rw-p 08100000 00:00 0 09615000-09656000 rw-p 09615000 00:00 0 [heap] b7dce000-b7dea000 r--p 00000000 fd:00 369496 /usr/share/locale/ja/LC_MESSAGES/libc.mo b7dea000-b7dec000 rw-p b7dea000 00:00 0 b7dec000-b7df3000 r--s 00000000 fd:00 386077 /usr/lib/gconv/gconv-modules.cache b7df3000-b7ed7000 r--p 034df000 fd:00 294949 /usr/lib/locale/locale-archive b7ed7000-b80d7000 r--p 00000000 fd:00 294949 /usr/lib/locale/locale-archive b80d7000-b80d9000 rw-p b80d7000 00:00 0 bfc3e000-bfc53000 rw-p bffeb000 00:00 0 [stack]ちなみに小さいプロセスの仮想メモリー空間をみてみると、
#include "stdio.h" main() { while(1) sleep(100); }
root@localhost test]# ./a.out & [1] 2608 [root@localhost test]# echo 2608 > /proc/hogehoge [root@localhost test]# dmesg vm_area 12: 00a03000-00a04000 00ad0000-00af0000 00af1000-00af2000 00af2000-00af3000 00af5000-00c63000 00c63000-00c65000 00c65000-00c66000 00c66000-00c69000 08048000-08049000 08049000-0804a000 b809b000-b809d000 bfda4000-bfdb9000使われるメモリー空間がもちろんbashより小さいです。最後はやはりc0000000を超えてはいませんね。各プロセスのメモリ空間はtask_struc->mm_struct->vm_area_structで管理されているということでした。