Commit e8c59c0c authored by Andrew Burgess's avatar Andrew Burgess Committed by Tony Luck

[IA64] Failure to grow RBS

There is a bug in the ia64_do_page_fault code that can cause a failure
to grow the register backing store, or any mapping that is marked as
VM_GROWSUP if the mapping is the highest mapped area of memory.

When the address accessed is below the first mapping the previous mapping
is returned as NULL, and this case is handled.  However, when the address
accessed is above the highest mapping the vma returned is NULL, this
case is not handled correctly, and it fails to spot that this access
might require an existing mapping to grow upwards.
Signed-off-by: default avatarAndrew Burgess <andrew@transitive.com>
Signed-off-by: default avatarTony Luck <tony.luck@intel.com>
parent 182fdd22
...@@ -112,11 +112,17 @@ ia64_do_page_fault (unsigned long address, unsigned long isr, struct pt_regs *re ...@@ -112,11 +112,17 @@ ia64_do_page_fault (unsigned long address, unsigned long isr, struct pt_regs *re
down_read(&mm->mmap_sem); down_read(&mm->mmap_sem);
vma = find_vma_prev(mm, address, &prev_vma); vma = find_vma_prev(mm, address, &prev_vma);
if (!vma) if (!vma && !prev_vma )
goto bad_area; goto bad_area;
/* find_vma_prev() returns vma such that address < vma->vm_end or NULL */ /*
if (address < vma->vm_start) * find_vma_prev() returns vma such that address < vma->vm_end or NULL
*
* May find no vma, but could be that the last vm area is the
* register backing store that needs to expand upwards, in
* this case vma will be null, but prev_vma will ne non-null
*/
if (( !vma && prev_vma ) || (address < vma->vm_start) )
goto check_expansion; goto check_expansion;
good_area: good_area:
...@@ -172,6 +178,8 @@ ia64_do_page_fault (unsigned long address, unsigned long isr, struct pt_regs *re ...@@ -172,6 +178,8 @@ ia64_do_page_fault (unsigned long address, unsigned long isr, struct pt_regs *re
check_expansion: check_expansion:
if (!(prev_vma && (prev_vma->vm_flags & VM_GROWSUP) && (address == prev_vma->vm_end))) { if (!(prev_vma && (prev_vma->vm_flags & VM_GROWSUP) && (address == prev_vma->vm_end))) {
if (!vma)
goto bad_area;
if (!(vma->vm_flags & VM_GROWSDOWN)) if (!(vma->vm_flags & VM_GROWSDOWN))
goto bad_area; goto bad_area;
if (REGION_NUMBER(address) != REGION_NUMBER(vma->vm_start) if (REGION_NUMBER(address) != REGION_NUMBER(vma->vm_start)
......
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