Re: [BUG] get_unmapped_area() change -> non booting machine

From: Andi Kleen
Date: Tue Feb 10 2004 - 02:19:25 EST


On Tue, 10 Feb 2004 14:47:09 +1100
Benjamin Herrenschmidt <benh@xxxxxxxxxxxxxxxxxxx> wrote:
> Just reverting the patch fixes it. Though, the patch do make sense in
> some cases, paulus suggested to modify the code so that for a non
> MAP_FIXED map, it still search from the passed-in address, but avoids
> the spare between the current mm->brk and TASK_UNMAPPED_BASE, thus the
> algorithm would still work for things outside of these areas.
>
> Commment ?

Can you test this patch please? It essentially implements Paulus' suggestion.

It also fixes another issue (don't use free_area_cache when the user gave an
address hint).

--- linux-2.6.3rc1-amd64/mm/mmap.c-o 2004-01-28 17:12:37.000000000 +0100
+++ linux-2.6.3rc1-amd64/mm/mmap.c 2004-02-12 00:16:35.000000000 +0100
@@ -727,18 +727,20 @@
*/
#ifndef HAVE_ARCH_UNMAPPED_AREA
static inline unsigned long
-arch_get_unmapped_area(struct file *filp, unsigned long addr,
+arch_get_unmapped_area(struct file *filp, unsigned long uaddr,
unsigned long len, unsigned long pgoff, unsigned long flags)
{
struct mm_struct *mm = current->mm;
struct vm_area_struct *vma;
unsigned long start_addr;
+ unsigned long unmapped_base;
+ unsigned long addr;

if (len > TASK_SIZE)
return -ENOMEM;

- if (addr) {
- addr = PAGE_ALIGN(addr);
+ if (uaddr) {
+ addr = PAGE_ALIGN(uaddr);
vma = find_vma(mm, addr);
if (TASK_SIZE - len >= addr &&
(!vma || addr + len <= vma->vm_start))
@@ -747,28 +749,40 @@
addr = mm->free_area_cache;
start_addr = addr;

+ unmapped_base = TASK_UNMAPPED_BASE;
full_search:
- for (vma = find_vma(mm, addr); ; vma = vma->vm_next) {
+ for (vma = find_vma(mm, addr); ; ) {
/* At this point: (!vma || addr < vma->vm_end). */
if (TASK_SIZE - len < addr) {
/*
* Start a new search - just in case we missed
* some holes.
*/
- if (start_addr != TASK_UNMAPPED_BASE) {
- start_addr = addr = TASK_UNMAPPED_BASE;
+ if (start_addr > unmapped_base) {
+ start_addr = addr = unmapped_base;
goto full_search;
}
return -ENOMEM;
}
+ /* On the first pass always skip the brk gap to not
+ confuse glibc malloc. This can happen with user
+ address hints < TASK_UNMAPPED_BASE. */
+ if (addr >= mm->brk && addr < unmapped_base) {
+ vma = find_vma(mm, unmapped_base);
+ addr = unmapped_base;
+ continue;
+ }
if (!vma || addr + len <= vma->vm_start) {
/*
- * Remember the place where we stopped the search:
+ * Remember the place where we stopped the search,
+ * but only if the user didn't give hints.
*/
- mm->free_area_cache = addr + len;
+ if (uaddr == 0)
+ mm->free_area_cache = addr + len;
return addr;
}
addr = vma->vm_end;
+ vma = vma->vm_next;
}
}
#else
-
To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
the body of a message to majordomo@xxxxxxxxxxxxxxx
More majordomo info at http://vger.kernel.org/majordomo-info.html
Please read the FAQ at http://www.tux.org/lkml/