/* * mm/interval_tree.c - interval tree for mapping->i_mmap * * Copyright (C) 2012, Michel Lespinasse * * This file is released under the GPL v2. */ #include #include #define ITSTRUCT struct vm_area_struct #define ITRB shared.linear.rb #define ITTYPE unsigned long #define ITSUBTREE shared.linear.rb_subtree_last #define ITSTART(n) ((n)->vm_pgoff) #define ITLAST(n) ((n)->vm_pgoff + \ (((n)->vm_end - (n)->vm_start) >> PAGE_SHIFT) - 1) #define ITSTATIC #define ITPREFIX vma_interval_tree #include /* Insert old immediately after vma in the interval tree */ void vma_interval_tree_add(struct vm_area_struct *vma, struct vm_area_struct *old, struct address_space *mapping) { struct rb_node **link; struct vm_area_struct *parent; unsigned long last; if (unlikely(vma->vm_flags & VM_NONLINEAR)) { list_add(&vma->shared.nonlinear, &old->shared.nonlinear); return; } last = ITLAST(vma); if (!old->shared.linear.rb.rb_right) { parent = old; link = &old->shared.linear.rb.rb_right; } else { parent = rb_entry(old->shared.linear.rb.rb_right, struct vm_area_struct, shared.linear.rb); if (parent->shared.linear.rb_subtree_last < last) parent->shared.linear.rb_subtree_last = last; while (parent->shared.linear.rb.rb_left) { parent = rb_entry(parent->shared.linear.rb.rb_left, struct vm_area_struct, shared.linear.rb); if (parent->shared.linear.rb_subtree_last < last) parent->shared.linear.rb_subtree_last = last; } link = &parent->shared.linear.rb.rb_left; } vma->shared.linear.rb_subtree_last = last; rb_link_node(&vma->shared.linear.rb, &parent->shared.linear.rb, link); rb_insert_augmented(&vma->shared.linear.rb, &mapping->i_mmap, &vma_interval_tree_augment_callbacks); }