スラブオブジェクトからサイズを取得するには(メモ)
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)