aboutsummaryrefslogtreecommitdiffstats
path: root/arch/ia64/mm/fault.c
diff options
context:
space:
mode:
authorAndrew Burgess <andrew@transitive.com>2007-08-16 13:30:46 -0400
committerTony Luck <tony.luck@intel.com>2007-08-16 13:30:46 -0400
commite8c59c0cf9c91dccfb6367c306d753500d5a0150 (patch)
treedb4a13d5f5f88e2cc2da56fb4e8a3d6d6ea3ba4e /arch/ia64/mm/fault.c
parent182fdd225de8fc3b1b721ae944fc41146a0bd812 (diff)
[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: Andrew Burgess <andrew@transitive.com> Signed-off-by: Tony Luck <tony.luck@intel.com>
Diffstat (limited to 'arch/ia64/mm/fault.c')
-rw-r--r--arch/ia64/mm/fault.c14
1 files changed, 11 insertions, 3 deletions
diff --git a/arch/ia64/mm/fault.c b/arch/ia64/mm/fault.c
index 73ccb6010c05..9150ffaff9e8 100644
--- a/arch/ia64/mm/fault.c
+++ b/arch/ia64/mm/fault.c
@@ -112,11 +112,17 @@ ia64_do_page_fault (unsigned long address, unsigned long isr, struct pt_regs *re
112 down_read(&mm->mmap_sem); 112 down_read(&mm->mmap_sem);
113 113
114 vma = find_vma_prev(mm, address, &prev_vma); 114 vma = find_vma_prev(mm, address, &prev_vma);
115 if (!vma) 115 if (!vma && !prev_vma )
116 goto bad_area; 116 goto bad_area;
117 117
118 /* find_vma_prev() returns vma such that address < vma->vm_end or NULL */ 118 /*
119 if (address < vma->vm_start) 119 * find_vma_prev() returns vma such that address < vma->vm_end or NULL
120 *
121 * May find no vma, but could be that the last vm area is the
122 * register backing store that needs to expand upwards, in
123 * this case vma will be null, but prev_vma will ne non-null
124 */
125 if (( !vma && prev_vma ) || (address < vma->vm_start) )
120 goto check_expansion; 126 goto check_expansion;
121 127
122 good_area: 128 good_area:
@@ -172,6 +178,8 @@ ia64_do_page_fault (unsigned long address, unsigned long isr, struct pt_regs *re
172 178
173 check_expansion: 179 check_expansion:
174 if (!(prev_vma && (prev_vma->vm_flags & VM_GROWSUP) && (address == prev_vma->vm_end))) { 180 if (!(prev_vma && (prev_vma->vm_flags & VM_GROWSUP) && (address == prev_vma->vm_end))) {
181 if (!vma)
182 goto bad_area;
175 if (!(vma->vm_flags & VM_GROWSDOWN)) 183 if (!(vma->vm_flags & VM_GROWSDOWN))
176 goto bad_area; 184 goto bad_area;
177 if (REGION_NUMBER(address) != REGION_NUMBER(vma->vm_start) 185 if (REGION_NUMBER(address) != REGION_NUMBER(vma->vm_start)