赤黒木3(insert_vm_struct)
find_vma_prepare()で以下の接続ポインタの赤黒木/双方向リストに登録するための必要な位置情報を取得し、__vma_link()でリストします。
・prevは昇順リストの直前のノードのポインタ
・rb_linkは赤黒木の親ノードの左右に接続する子ノードのポインタ
・rb_parentは赤黒木の親ノードのポインタ
__vma_link_rb()は、rb_parentを親として、rb_parentの接続子ノードのrb_linkに接続する赤黒木
__vma_link_file()は、vmaがファイルマップならinode->i_mappingのアドレススペースをvma->sharedをヘッドとする双方向リストに接続します。
赤黒木のノードの左パス配下のノードは全て、親ノードより小さく、右パスのそれは親ノードより大きいと言うことで、従ってノードが親の右子ノードに接続されれば、その親ノードが昇順リストの直前のノードとなり、以降その左パスに接続されるなら、直前のノードは、最初に右に接続された親ノードであり続けるわけです。
・親ノード<右子ノードの左子ノードの左子ノード<右子ノードの左子ノード<右子ノード
mm_structのルートからaddrの大小に応じて右左パスを、そして、addrのvmaがなければ、赤黒木の終端(*__rb_link==NULL)まで走査していき、addrのvmaが接続される親をrb_parent、また接続される親の右か左かをrb_linkに設定し、右子ノードを親とするタイミングでrb_prevをその親とします。。
・prevは昇順リストの直前のノードのポインタ
・rb_linkは赤黒木の親ノードの左右に接続する子ノードのポインタ
・rb_parentは赤黒木の親ノードのポインタ
static void __insert_vm_struct(struct mm_struct * mm, struct vm_area_struct * vma) { struct vm_area_struct * __vma, * prev; struct rb_node ** rb_link, * rb_parent; __vma = find_vma_prepare(mm, vma->vm_start,&prev, &rb_link, &rb_parent); if (__vma && __vma->vm_start < vma->vm_end) BUG(); __vma_link(mm, vma, prev, rb_link, rb_parent); mark_mm_hugetlb(mm, vma); mm->map_count++; validate_mm(mm); }__vma_link_list()は、 prev->vm_nextに接続とするvmaの昇順リスト、
__vma_link_rb()は、rb_parentを親として、rb_parentの接続子ノードのrb_linkに接続する赤黒木
__vma_link_file()は、vmaがファイルマップならinode->i_mappingのアドレススペースをvma->sharedをヘッドとする双方向リストに接続します。
__vma_link(struct mm_struct *mm, struct vm_area_struct *vma, struct vm_area_struct *prev, struct rb_node **rb_link, struct rb_node *rb_parent) { __vma_link_list(mm, vma, prev, rb_parent); __vma_link_rb(mm, vma, rb_link, rb_parent); __vma_link_file(vma); }find_vma_prepare()はfind_vma()と同じように、addrのvm_area_structを取得(あれば)しますが、同時に昇順リストの直前vm_area_structと、赤黒木の親の右/左子のどちらに接続されているかの情報(接続ポインタを取得すれば右左は関係ありません。)も取得します。
赤黒木のノードの左パス配下のノードは全て、親ノードより小さく、右パスのそれは親ノードより大きいと言うことで、従ってノードが親の右子ノードに接続されれば、その親ノードが昇順リストの直前のノードとなり、以降その左パスに接続されるなら、直前のノードは、最初に右に接続された親ノードであり続けるわけです。
・親ノード<右子ノードの左子ノードの左子ノード<右子ノードの左子ノード<右子ノード
mm_structのルートからaddrの大小に応じて右左パスを、そして、addrのvmaがなければ、赤黒木の終端(*__rb_link==NULL)まで走査していき、addrのvmaが接続される親をrb_parent、また接続される親の右か左かをrb_linkに設定し、右子ノードを親とするタイミングでrb_prevをその親とします。。
static struct vm_area_struct * find_vma_prepare(struct mm_struct *mm, unsigned long addr, struct vm_area_struct **pprev, struct rb_node ***rb_link, struct rb_node ** rb_parent) { struct vm_area_struct * vma; struct rb_node ** __rb_link, * __rb_parent, * rb_prev; __rb_link = &mm->mm_rb.rb_node; rb_prev = __rb_parent = NULL; vma = NULL; while (*__rb_link) { struct vm_area_struct *vma_tmp; __rb_parent = *__rb_link; vma_tmp = rb_entry(__rb_parent, struct vm_area_struct, vm_rb); if (vma_tmp->vm_end > addr) { vma = vma_tmp; if (vma_tmp->vm_start <= addr) return vma; __rb_link = &__rb_parent->rb_left; } else { rb_prev = __rb_parent; __rb_link = &__rb_parent->rb_right; } } *pprev = NULL; if (rb_prev) *pprev = rb_entry(rb_prev, struct vm_area_struct, vm_rb); *rb_link = __rb_link; *rb_parent = __rb_parent; return vma; }昇順リスト
static inline void __vma_link_list(struct mm_struct *mm, struct vm_area_struct *vma, struct vm_area_struct *prev, struct rb_node *rb_parent) { if (prev) { vma->vm_next = prev->vm_next; prev->vm_next = vma; } else { mm->mmap = vma; if (rb_parent) vma->vm_next = rb_entry(rb_parent, struct vm_area_struct, vm_rb); else vma->vm_next = NULL; } }赤黒木
static void __vma_link_rb(struct mm_struct *mm, struct vm_area_struct *vma, struct rb_node **rb_link, struct rb_node *rb_parent) { rb_link_node(&vma->vm_rb, rb_parent, rb_link); rb_insert_color(&vma->vm_rb, &mm->mm_rb); }ファイルマップドリスト
static inline void __vma_link_file(struct vm_area_struct *vma) { struct file * file; file = vma->vm_file; if (file) { struct inode * inode = file->f_dentry->d_inode; struct address_space *mapping = inode->i_mapping; if (vma->vm_flags & VM_DENYWRITE) atomic_dec(&inode->i_writecount); if (vma->vm_flags & VM_SHARED) list_add_tail(&vma->shared, &mapping->i_mmap_shared); else list_add_tail(&vma->shared, &mapping->i_mmap); } }