Commit e180b535 authored by Matthew Wilcox's avatar Matthew Wilcox Committed by Linus Torvalds

[PATCH] rewrite find_vma_prev

For PA-RISC, we need find_vma_prev to return `prev', even if vma is NULL.
Our stack is at the top of memory, growing upwards, so when we page fault
we need to see prev.  For added bonus points, the code becomes simpler,
less indented, shorter and (for me, anyway) easier to understand.  The
code is well-tested, even on x86.  For PA and ia64 this code is called in
the page fault handler path so it is exercised frequently.
parent 5daf6d5d
...@@ -669,49 +669,53 @@ struct vm_area_struct * find_vma(struct mm_struct * mm, unsigned long addr) ...@@ -669,49 +669,53 @@ struct vm_area_struct * find_vma(struct mm_struct * mm, unsigned long addr)
struct vm_area_struct * find_vma_prev(struct mm_struct * mm, unsigned long addr, struct vm_area_struct * find_vma_prev(struct mm_struct * mm, unsigned long addr,
struct vm_area_struct **pprev) struct vm_area_struct **pprev)
{ {
if (mm) { struct vm_area_struct *vma = NULL, *prev = NULL;
/* Go through the RB tree quickly. */ rb_node_t * rb_node;
struct vm_area_struct * vma; if (!mm)
rb_node_t * rb_node, * rb_last_right, * rb_prev; goto out;
/* Guard against addr being lower than the first VMA */
vma = mm->mmap;
/* Go through the RB tree quickly. */
rb_node = mm->mm_rb.rb_node; rb_node = mm->mm_rb.rb_node;
rb_last_right = rb_prev = NULL;
vma = NULL;
while (rb_node) { while (rb_node) {
struct vm_area_struct * vma_tmp; struct vm_area_struct *vma_tmp;
vma_tmp = rb_entry(rb_node, struct vm_area_struct, vm_rb); vma_tmp = rb_entry(rb_node, struct vm_area_struct, vm_rb);
if (vma_tmp->vm_end > addr) { if (addr < vma_tmp->vm_end) {
vma = vma_tmp;
rb_prev = rb_last_right;
if (vma_tmp->vm_start <= addr)
break;
rb_node = rb_node->rb_left; rb_node = rb_node->rb_left;
} else { } else {
rb_last_right = rb_node; prev = vma_tmp;
if (!prev->vm_next || (addr < prev->vm_next->vm_end))
break;
rb_node = rb_node->rb_right; rb_node = rb_node->rb_right;
} }
} }
if (vma) {
if (vma->vm_rb.rb_left) { out:
rb_prev = vma->vm_rb.rb_left; *pprev = prev;
while (rb_prev->rb_right) return prev ? prev->vm_next : vma;
rb_prev = rb_prev->rb_right; }
}
*pprev = NULL; #ifdef ARCH_STACK_GROWSUP
if (rb_prev) struct vm_area_struct * find_extend_vma(struct mm_struct * mm, unsigned long addr)
*pprev = rb_entry(rb_prev, struct vm_area_struct, vm_rb); {
if ((rb_prev ? (*pprev)->vm_next : mm->mmap) != vma) struct vm_area_struct *vma, *prev;
BUG();
addr &= PAGE_MASK;
vma = find_vma_prev(mm, addr, &prev);
if (vma && (vma->vm_start <= addr))
return vma; return vma;
} if (!prev || expand_stack(prev, addr))
}
*pprev = NULL;
return NULL; return NULL;
if (prev->vm_flags & VM_LOCKED) {
make_pages_present(addr, prev->vm_end);
}
return prev;
} }
#else
struct vm_area_struct * find_extend_vma(struct mm_struct * mm, unsigned long addr) struct vm_area_struct * find_extend_vma(struct mm_struct * mm, unsigned long addr)
{ {
struct vm_area_struct * vma; struct vm_area_struct * vma;
...@@ -733,6 +737,7 @@ struct vm_area_struct * find_extend_vma(struct mm_struct * mm, unsigned long add ...@@ -733,6 +737,7 @@ struct vm_area_struct * find_extend_vma(struct mm_struct * mm, unsigned long add
} }
return vma; return vma;
} }
#endif
/* /*
* Try to free as many page directory entries as we can, * Try to free as many page directory entries as we can,
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment