diff options
Diffstat (limited to 'arch/x86/kernel/sys_x86_64.c')
-rw-r--r-- | arch/x86/kernel/sys_x86_64.c | 34 |
1 files changed, 17 insertions, 17 deletions
diff --git a/arch/x86/kernel/sys_x86_64.c b/arch/x86/kernel/sys_x86_64.c index 051489082d59..ef59642ff1bf 100644 --- a/arch/x86/kernel/sys_x86_64.c +++ b/arch/x86/kernel/sys_x86_64.c | |||
@@ -195,7 +195,7 @@ arch_get_unmapped_area_topdown(struct file *filp, const unsigned long addr0, | |||
195 | { | 195 | { |
196 | struct vm_area_struct *vma; | 196 | struct vm_area_struct *vma; |
197 | struct mm_struct *mm = current->mm; | 197 | struct mm_struct *mm = current->mm; |
198 | unsigned long addr = addr0; | 198 | unsigned long addr = addr0, start_addr; |
199 | 199 | ||
200 | /* requested length too big for entire address space */ | 200 | /* requested length too big for entire address space */ |
201 | if (len > TASK_SIZE) | 201 | if (len > TASK_SIZE) |
@@ -223,25 +223,14 @@ arch_get_unmapped_area_topdown(struct file *filp, const unsigned long addr0, | |||
223 | mm->free_area_cache = mm->mmap_base; | 223 | mm->free_area_cache = mm->mmap_base; |
224 | } | 224 | } |
225 | 225 | ||
226 | try_again: | ||
226 | /* either no address requested or can't fit in requested address hole */ | 227 | /* either no address requested or can't fit in requested address hole */ |
227 | addr = mm->free_area_cache; | 228 | start_addr = addr = mm->free_area_cache; |
228 | |||
229 | /* make sure it can fit in the remaining address space */ | ||
230 | if (addr > len) { | ||
231 | unsigned long tmp_addr = align_addr(addr - len, filp, | ||
232 | ALIGN_TOPDOWN); | ||
233 | |||
234 | vma = find_vma(mm, tmp_addr); | ||
235 | if (!vma || tmp_addr + len <= vma->vm_start) | ||
236 | /* remember the address as a hint for next time */ | ||
237 | return mm->free_area_cache = tmp_addr; | ||
238 | } | ||
239 | |||
240 | if (mm->mmap_base < len) | ||
241 | goto bottomup; | ||
242 | 229 | ||
243 | addr = mm->mmap_base-len; | 230 | if (addr < len) |
231 | goto fail; | ||
244 | 232 | ||
233 | addr -= len; | ||
245 | do { | 234 | do { |
246 | addr = align_addr(addr, filp, ALIGN_TOPDOWN); | 235 | addr = align_addr(addr, filp, ALIGN_TOPDOWN); |
247 | 236 | ||
@@ -263,6 +252,17 @@ arch_get_unmapped_area_topdown(struct file *filp, const unsigned long addr0, | |||
263 | addr = vma->vm_start-len; | 252 | addr = vma->vm_start-len; |
264 | } while (len < vma->vm_start); | 253 | } while (len < vma->vm_start); |
265 | 254 | ||
255 | fail: | ||
256 | /* | ||
257 | * if hint left us with no space for the requested | ||
258 | * mapping then try again: | ||
259 | */ | ||
260 | if (start_addr != mm->mmap_base) { | ||
261 | mm->free_area_cache = mm->mmap_base; | ||
262 | mm->cached_hole_size = 0; | ||
263 | goto try_again; | ||
264 | } | ||
265 | |||
266 | bottomup: | 266 | bottomup: |
267 | /* | 267 | /* |
268 | * A failed mmap() very likely causes application failure, | 268 | * A failed mmap() very likely causes application failure, |