赤黒木2(find_vma)
仮想メモリ領域は、プロセス毎のmm_struct(current->mm)に、mm_struct.mm_rbをルートとする赤黒木でリスト管理されます。
mm->mmap_cacheでないなら、赤黒木のルートのmm->mm_rbから検索します。赤黒木から取得したvm_area_structのアドレスとの大/小をチェックすることで、次のノードが右か左かとして、走査します。
再度同じvm_area_structが検索される可能性が高いため、取得したvm_area_structをmm->mmap_cacheに設定しておきます。
rb_entryマクロはlist_headマクロと同じで、メンバーとしてのptrの構造体のアドレスを返すだけで、 rb_nodeのアドレスからstruct vm_area_structのメンバーvm_rbの位置のオフセットを引けば、その先頭。すなわち、rb_nodeの属するstruct vm_area_structが取得できます。
struct mm_struct {
struct vm_area_struct * mmap; /* list of VMAs */
struct rb_root mm_rb;
struct vm_area_struct * mmap_cache; /* last find_vma result */
int map_count
:
};
struct vm_area_struct {
struct mm_struct * vm_mm; /* The address space we belong to. */
unsigned long vm_start; /* Our start address within vm_mm. */
unsigned long vm_end; /* The first byte after our end address
within vm_mm. */
struct vm_area_struct *vm_next, *vm_prev;
pgprot_t vm_page_prot; /* Access permissions of this VMA. */
unsigned long vm_flags; /* Flags, see mm.h. */
struct rb_node vm_rb;
:
};
find_vma()は、struct mm_struct current->mmの指定するアドレスのvm_area_structを取得します。mm->mmap_cacheでないなら、赤黒木のルートのmm->mm_rbから検索します。赤黒木から取得したvm_area_structのアドレスとの大/小をチェックすることで、次のノードが右か左かとして、走査します。
再度同じvm_area_structが検索される可能性が高いため、取得したvm_area_structをmm->mmap_cacheに設定しておきます。
rb_entryマクロはlist_headマクロと同じで、メンバーとしてのptrの構造体のアドレスを返すだけで、 rb_nodeのアドレスからstruct vm_area_structのメンバーvm_rbの位置のオフセットを引けば、その先頭。すなわち、rb_nodeの属するstruct vm_area_structが取得できます。
#define rb_entry(ptr, type, member) container_of(ptr, type, member)
struct rb_node
{
unsigned long rb_parent_color;
struct rb_node *rb_right;
struct rb_node *rb_left;
} __attribute__((aligned(sizeof(long))));
struct rb_root
{
struct rb_node *rb_node;
};
struct vm_area_struct *find_vma(struct mm_struct *mm, unsigned long addr)
{
struct vm_area_struct *vma = NULL;
if (mm) {
/* Check the cache first. */
/* (Cache hit rate is typically around 35%.) */
vma = mm->mmap_cache;
if (!(vma && vma->vm_end > addr && vma->vm_start <= addr)) {
struct rb_node * rb_node;
rb_node = mm->mm_rb.rb_node;
vma = NULL;
while (rb_node) {
struct vm_area_struct * vma_tmp;
vma_tmp = rb_entry(rb_node,
struct vm_area_struct, vm_rb);
if (vma_tmp->vm_end > addr) {
vma = vma_tmp;
if (vma_tmp->vm_start <= addr)
break;
rb_node = rb_node->rb_left;
} else
rb_node = rb_node->rb_right;
}
if (vma)
mm->mmap_cache = vma;
}
}
return vma;
}







