/proc/pid/maps のフラグ rwxp における p とは
マッピング領域がプライベートマッピングされていることを表す.
プライベートファイルマッピングでは,マッピング領域への変更はマッピング対象ファイルに影響を与えない.例えば,gnome-terminal の maps を見ると,
$ cat /proc/`pgrep gnome-terminal | head -n 1`/maps 08045000-0808d000 r-xp 00000000 fd:00 131656 /usr/bin/gnome-terminal 0808d000-0808f000 rw-p 00048000 fd:00 131656 /usr/bin/gnome-terminal ...
となっており,元のファイルの text/data セクションはプライベートマッピングされていることが分かる.
これはコピーオンライトを用いて実装されており,マッピング領域の変更時にページフォルトが発生し,その際( mm/memory.c do_wp_page()) にて
匿名マッピング用のページが確保され new_page = alloc_page_vma(GFP_HIGHUSER, vma, address);
変更対象がコピーされ cow_user_page(new_page, old_page, address, vma);
vma 中の変更前のページが取り除かれ page_remove_rmap(old_page, vma);
新しいページが追加される page_add_new_anon_rmap(new_page, vma, address);
the Ninth Real-Time Linux Workshop の論文
http://www.linuxdevices.com/news/NS2574496181.html
LinuxDevices has published the full text of 28 papers from the Ninth Real-Time Linux Workshop, Nov. 2-3 in Linz, Austria.
...
The papers are available free, and without registration, via the links below
sizeof と kobjsize
上記に関連して.
uClinuxで使う mm/nommu.c 中の重要関数 do_mmap_pgoff() では,
... struct vm_area_struct *vma = NULL; ... vma = kzalloc(sizeof(struct vm_area_struct), GFP_KERNEL); ... realalloc += kobjsize(vma); askedalloc += sizeof(*vma);
としている箇所がある.
ここで,realalloc は実際に確保された値.askedalloc は本来欲しかった値.
sizeof演算子では,struct vm_area_struct のサイズが取得できる.
一方,kobjsize(vma) では,vma が kzalloc()(kmalloc()) によってスラブオブジェクトとして確保されるため,サイズは2の冪乗となり,その値が返る.
よって,realalloc には実際に確保された2の冪乗サイズ.askedalloc には要求された構造体のサイズが入る.
ちなみん,これら二つの変数は,2.6.23-mm1 現在全く使われていない.
スラブオブジェクトからサイズを取得するには(メモ)
kobjsize()
スラブオブジェクトのアドレス objp から,オブジェクトサイズを取得する.
kobjsize(スラブオブジェクトのアドレスobjp)
↓
ksize(objp)
↓
return obj_size(virt_to_cache(objp))
virt_to_cache()
スラブオブジェクトのアドレス objp から キャッシュディスクリプタ kmem_cache を取得する.
kmem_cache は slab.h で定義され,slab_size,buffer_size メンバを持つ.obj_size() は buffer_size を返す.
この二つの違いは後で押さえる.
virt_to_cache(objp) ↓ struct page *page = virt_to_head_page(objp) ↓ return page_get_cache(page)
virt_to_head_page()
virt_to_head_page(objp) ↓ struct page *page = virt_to_page(objp) ↓ return compound_head(page);
virt_to_page() 重要
アドレスから,オブジェクトが属するページのページディスクリプタを取得する.
ページディスクリプタの取得には,ページの物理アドレスが必要.ここでオブジェクトのアドレスは仮想アドレスである.
x86でRAMのZONE_NORMAL(16MBから896MB)に対応する物理アドレスにマッピングされた仮想アドレスの場合,リニアマッピングされているので,仮想アドレス-0xc0000000 で物理アドレスが取得できる.
virt_to_page(objp) ↓ pfn_to_page(__pa(objp) >> PAGE_SHIFT) →ARMの場合 #define __pa(x) __virt_to_phys((unsigned long)(x)) →x86の場合 #define __pa(x) ((unsigned long)(x)-PAGE_OFFSET)
__virt_to_phys() 重要
仮想アドレスから物理アドレスを得る.
ARMの場合,RAMが物理アドレスの0番地から始まるのではないため,RAMが開始するPHYS_OFFSETを物理アドレスに加算している.また,仮想アドレスはPAGE_OFFSET(大体の場合,3GB)以降にリニアマッピングされるため,それを減算している.こうやって仮想アドレスから物理アドレスを得る.
#define __virt_to_phys(x) ((x) - PAGE_OFFSET + PHYS_OFFSET)
メモリマッピングのデマンドページング - 2.6.23-mm1
(少なくとも2.6.22では) デマンドページング時は handle_pte_fault() から mm/memory.c do_no_page() が呼ばれていたが,2.6.23-mm1 では,do_no_page() は do_linear_fault() と関数名が変更されている.また,do_file_page() はdo_nolinear_fault() となり,do_file_page() と do_no_page() の中身が __do_fault() にまとめられ,do_linear_fault() と do_nolinear_fault() から呼ばれるようになっている.
.nopageメソッドも.faultメソッドに名前が変更してる.