All of lore.kernel.org
 help / color / mirror / Atom feed
* Fw: [Bug 4520] New: /proc/*/maps fragments too quickly compared to 2.4
@ 2005-04-24  4:18 Andrew Morton
  2005-04-24  7:42 ` Arjan van de Ven
  2005-04-27 18:27 ` Wolfgang Wander
  0 siblings, 2 replies; 3+ messages in thread
From: Andrew Morton @ 2005-04-24  4:18 UTC (permalink / raw)
  To: Ingo Molnar, Arjan van de Ven; +Cc: linux-mm, wwc

Guys, Wolfgang has found what appears to be a serious mmap fragmentation
problem with the mm_struct.free_area_cache.


Begin forwarded message:

Date: Tue, 19 Apr 2005 11:55:44 -0700
From: bugme-daemon@osdl.org
To: akpm@digeo.com
Subject: [Bug 4520] New: /proc/*/maps fragments too quickly compared to 2.4


http://bugme.osdl.org/show_bug.cgi?id=4520

           Summary: /proc/*/maps fragments too quickly compared to 2.4
    Kernel Version: 2.6.11.4
            Status: NEW
          Severity: normal
             Owner: akpm@digeo.com
         Submitter: wwc@rentec.com


Distribution: Suse 9.2
Hardware Environment: Dual AMD64 / 8GB memory
Software Environment: 64 bit kernel 2.6.11.2 or .4 running 32 bit application
Problem Description: 
The appended c program, compiled in 32 bit mode, runs on our 2.6.11.4 (64bit
kernel) out of memory after a short while. 

Once this happens the programs copies /proc/self/maps to stdout which is large
and very fragmented.  

The same program runs 'forever' and after that ;-) /proc/self/maps only 
contains a few entries of very large mmapped regions.

Steps to reproduce:
Compile the program below in 32 bit mode, run on 2.4 and 2.6 kernels.


#include <stdio.h>
#include <string.h>
#include <unistd.h>
#include <sys/mman.h>

#define numMaps   600
#define largeArea 9500000
#define forEver   1000000
#define oneMeg    0x100000

void
aLLocator()
{

  char* bvec[numMaps];
  unsigned int i;
  memset( bvec,0,sizeof(bvec));
	 
  for(  i = 0; i < forEver ; ++i ) {
    unsigned oidx;
    unsigned kidx;
    int len;
    /* munmap old entries */
    oidx = (i+numMaps/10) % numMaps;
    len = (oidx & 7) ? ((oidx&7)* oneMeg) : largeArea; /* map size */
    if( bvec[oidx] ) { munmap( bvec[oidx], len ); bvec[oidx] = 0; }

    /* mmap new ones */
    kidx = i % numMaps;
    len = (kidx & 7) ? ((kidx&7)* oneMeg) : largeArea; /* map size */
    bvec[kidx] = (char*)(mmap(0, len, PROT_READ|PROT_WRITE,
			      MAP_PRIVATE|MAP_ANONYMOUS, -1, 0));

    if( bvec[kidx] == (char*)(-1) ) {
      printf("Failed after %d rounds\n", i);
      break;
    }
  }
}

int main() {
  FILE *f;
  int c;

  aLLocator();

  f = fopen( "/proc/self/maps", "r" );
  while( (c = fgetc(f)) != EOF )
    putchar(c);
  fclose(f);
  
  return 0;
}

------- You are receiving this mail because: -------
You are the assignee for the bug, or are watching the assignee.
--
To unsubscribe, send a message with 'unsubscribe linux-mm' in
the body to majordomo@kvack.org.  For more info on Linux MM,
see: http://www.linux-mm.org/ .
Don't email: <a href=mailto:"aart@kvack.org"> aart@kvack.org </a>

^ permalink raw reply	[flat|nested] 3+ messages in thread

* Re: Fw: [Bug 4520] New: /proc/*/maps fragments too quickly compared to 2.4
  2005-04-24  4:18 Fw: [Bug 4520] New: /proc/*/maps fragments too quickly compared to 2.4 Andrew Morton
@ 2005-04-24  7:42 ` Arjan van de Ven
  2005-04-27 18:27 ` Wolfgang Wander
  1 sibling, 0 replies; 3+ messages in thread
From: Arjan van de Ven @ 2005-04-24  7:42 UTC (permalink / raw)
  To: Andrew Morton; +Cc: Ingo Molnar, linux-mm, wwc

On Sat, Apr 23, 2005 at 09:18:19PM -0700, Andrew Morton wrote:

Ingo, do you have time to look? I have "family duty" today and am travelling
the next few days; the earliest I can look is thursday realistically.

--
To unsubscribe, send a message with 'unsubscribe linux-mm' in
the body to majordomo@kvack.org.  For more info on Linux MM,
see: http://www.linux-mm.org/ .
Don't email: <a href=mailto:"aart@kvack.org"> aart@kvack.org </a>

^ permalink raw reply	[flat|nested] 3+ messages in thread

* Re: Fw: [Bug 4520] New: /proc/*/maps fragments too quickly compared to 2.4
  2005-04-24  4:18 Fw: [Bug 4520] New: /proc/*/maps fragments too quickly compared to 2.4 Andrew Morton
  2005-04-24  7:42 ` Arjan van de Ven
@ 2005-04-27 18:27 ` Wolfgang Wander
  1 sibling, 0 replies; 3+ messages in thread
From: Wolfgang Wander @ 2005-04-27 18:27 UTC (permalink / raw)
  To: Andrew Morton; +Cc: Ingo Molnar, Arjan van de Ven, linux-mm, wwc

Andrew Morton writes:
 > 
 > Guys, Wolfgang has found what appears to be a serious mmap fragmentation
 > problem with the mm_struct.free_area_cache.
 > 

Andrew asked me to send the appended patch also to the list for
comments:

  ------

   In addtion to the the free_area_cache I've added another member
called cached_hole_size which contains the largest hole we have found
up to the position of free_area_cache.  Thus if we come in with a new
request we know that we better start from scratch if the requested
length is less or equal to the cached_hole_size.

   I've tried to patch all available architectures but of course have
not even tried to compile it.  So far only i32 and x86_64 is tested.

   It avoids fragmentation (as 2.4 did) and should be still faster
than the uncached version I hacked earlier.  And yes - check how
I implemented the biggest unsigned long (~0UL), I'm not sure if that
is ok with your standards...

                Wolfgang


diff -ru linux-2.6.11.7/arch/arm/mm/mmap.c linux-2.6.11.7.wwc/arch/arm/mm/mmap.c
--- linux-2.6.11.7/arch/arm/mm/mmap.c	2005-03-02 02:38:10.000000000 -0500
+++ linux-2.6.11.7.wwc/arch/arm/mm/mmap.c	2005-04-27 09:19:19.000000000 -0400
@@ -73,8 +73,13 @@
 		    (!vma || addr + len <= vma->vm_start))
 			return addr;
 	}
-	start_addr = addr = mm->free_area_cache;
-
+	if( len > mm->cached_hole_size )
+	        start_addr = addr = mm->free_area_cache;
+	else {
+	        start_addr = TASK_UNMAPPED_BASE;
+	        mm->cached_hole_size = 0;
+	}
+	
 full_search:
 	if (do_align)
 		addr = COLOUR_ALIGN(addr, pgoff);
@@ -90,6 +95,7 @@
 			 */
 			if (start_addr != TASK_UNMAPPED_BASE) {
 				start_addr = addr = TASK_UNMAPPED_BASE;
+				mm->cached_hole_size = 0;
 				goto full_search;
 			}
 			return -ENOMEM;
@@ -101,6 +107,8 @@
 			mm->free_area_cache = addr + len;
 			return addr;
 		}
+		if( addr + mm->cached_hole_size < vma->vm_start )
+		        mm->cached_hole_size = vma->vm_start - addr;
 		addr = vma->vm_end;
 		if (do_align)
 			addr = COLOUR_ALIGN(addr, pgoff);
diff -ru linux-2.6.11.7/arch/i386/mm/hugetlbpage.c linux-2.6.11.7.wwc/arch/i386/mm/hugetlbpage.c
--- linux-2.6.11.7/arch/i386/mm/hugetlbpage.c	2005-03-02 02:38:26.000000000 -0500
+++ linux-2.6.11.7.wwc/arch/i386/mm/hugetlbpage.c	2005-04-27 12:41:42.000000000 -0400
@@ -298,7 +298,12 @@
 	struct vm_area_struct *vma;
 	unsigned long start_addr;
 
-	start_addr = mm->free_area_cache;
+	if( len > mm->cached_hole_size ) 
+	        start_addr = mm->free_area_cache;
+	else {
+	        start_addr = TASK_UNMAPPED_BASE;
+	        mm->cached_hole_size = 0;
+	}
 
 full_search:
 	addr = ALIGN(start_addr, HPAGE_SIZE);
@@ -312,6 +317,7 @@
 			 */
 			if (start_addr != TASK_UNMAPPED_BASE) {
 				start_addr = TASK_UNMAPPED_BASE;
+				mm->cached_hole_size = 0;
 				goto full_search;
 			}
 			return -ENOMEM;
@@ -320,6 +326,8 @@
 			mm->free_area_cache = addr + len;
 			return addr;
 		}
+		if( addr + mm->cached_hole_size < vma->vm_start )
+		        mm->cached_hole_size = vma->vm_start - addr;
 		addr = ALIGN(vma->vm_end, HPAGE_SIZE);
 	}
 }
@@ -331,12 +339,17 @@
 	struct mm_struct *mm = current->mm;
 	struct vm_area_struct *vma, *prev_vma;
 	unsigned long base = mm->mmap_base, addr = addr0;
+	unsigned long largest_hole = mm->cached_hole_size;
 	int first_time = 1;
 
 	/* don't allow allocations above current base */
 	if (mm->free_area_cache > base)
 		mm->free_area_cache = base;
 
+	if( len <= largest_hole ) {
+	        largest_hole = 0;
+		mm->free_area_cache  = base;
+	}
 try_again:
 	/* make sure it can fit in the remaining address space */
 	if (mm->free_area_cache < len)
@@ -357,13 +370,20 @@
 		 * vma->vm_start, use it:
 		 */
 		if (addr + len <= vma->vm_start &&
-				(!prev_vma || (addr >= prev_vma->vm_end)))
+		        (!prev_vma || (addr >= prev_vma->vm_end))) {
 			/* remember the address as a hint for next time */
-			return (mm->free_area_cache = addr);
-		else
+		        mm->cached_hole_size = largest_hole;
+		        return (mm->free_area_cache = addr);
+		} else
 			/* pull free_area_cache down to the first hole */
-			if (mm->free_area_cache == vma->vm_end)
+		        if (mm->free_area_cache == vma->vm_end) {
 				mm->free_area_cache = vma->vm_start;
+				mm->cached_hole_size = largest_hole;
+			}
+				
+		/* remember the largest hole we saw so far */
+		if( addr + largest_hole < vma->vm_start )
+		        largest_hole = vma->vm_start - addr;
 
 		/* try just below the current vma->vm_start */
 		addr = (vma->vm_start - len) & HPAGE_MASK;
@@ -376,6 +396,7 @@
 	 */
 	if (first_time) {
 		mm->free_area_cache = base;
+		largest_hole = 0;
 		first_time = 0;
 		goto try_again;
 	}
@@ -386,6 +407,7 @@
 	 * allocations.
 	 */
 	mm->free_area_cache = TASK_UNMAPPED_BASE;
+	mm->cached_hole_size = ~0UL;
 	addr = hugetlb_get_unmapped_area_bottomup(file, addr0,
 			len, pgoff, flags);
 
@@ -393,7 +415,8 @@
 	 * Restore the topdown base:
 	 */
 	mm->free_area_cache = base;
-
+	mm->cached_hole_size = ~0UL;
+	
 	return addr;
 }
 
diff -ru linux-2.6.11.7/arch/ia64/kernel/sys_ia64.c linux-2.6.11.7.wwc/arch/ia64/kernel/sys_ia64.c
--- linux-2.6.11.7/arch/ia64/kernel/sys_ia64.c	2005-03-02 02:38:10.000000000 -0500
+++ linux-2.6.11.7.wwc/arch/ia64/kernel/sys_ia64.c	2005-04-27 09:19:19.000000000 -0400
@@ -38,9 +38,15 @@
 	if (REGION_NUMBER(addr) == REGION_HPAGE)
 		addr = 0;
 #endif
-	if (!addr)
-		addr = mm->free_area_cache;
-
+	if (!addr) {
+	        if( len > mm->cached_hole_size )
+		        addr = mm->free_area_cache;
+		else {
+		        addr = TASK_UNMAPPED_BASE;
+			mm->cached_hole_size = 0;
+		}
+	}
+			
 	if (map_shared && (TASK_SIZE > 0xfffffffful))
 		/*
 		 * For 64-bit tasks, align shared segments to 1MB to avoid potential
@@ -59,6 +65,7 @@
 			if (start_addr != TASK_UNMAPPED_BASE) {
 				/* Start a new search --- just in case we missed some holes.  */
 				addr = TASK_UNMAPPED_BASE;
+				mm->cached_hole_size = 0;
 				goto full_search;
 			}
 			return -ENOMEM;
@@ -68,6 +75,8 @@
 			mm->free_area_cache = addr + len;
 			return addr;
 		}
+		if( addr + mm->cached_hole_size < vma->vm_start )
+		        mm->cached_hole_size = vma->vm_start - addr;
 		addr = (vma->vm_end + align_mask) & ~align_mask;
 	}
 }
diff -ru linux-2.6.11.7/arch/ppc64/mm/hugetlbpage.c linux-2.6.11.7.wwc/arch/ppc64/mm/hugetlbpage.c
--- linux-2.6.11.7/arch/ppc64/mm/hugetlbpage.c	2005-03-02 02:38:09.000000000 -0500
+++ linux-2.6.11.7.wwc/arch/ppc64/mm/hugetlbpage.c	2005-04-27 12:43:52.000000000 -0400
@@ -515,7 +515,12 @@
 		    && !is_hugepage_only_range(addr,len))
 			return addr;
 	}
-	start_addr = addr = mm->free_area_cache;
+	if( len > mm->cached_hole_size ) 
+	        start_addr = addr = mm->free_area_cache;
+	else {
+	        start_addr = addr = TASK_UNMAPPED_BASE;
+	        mm->cached_hole_size = 0;
+	}
 
 full_search:
 	vma = find_vma(mm, addr);
@@ -539,6 +544,8 @@
 			mm->free_area_cache = addr + len;
 			return addr;
 		}
+		if( addr + mm->cached_hole_size < vma->vm_start )
+		        mm->cached_hole_size = vma->vm_start - addr;
 		addr = vma->vm_end;
 		vma = vma->vm_next;
 	}
@@ -546,6 +553,7 @@
 	/* Make sure we didn't miss any holes */
 	if (start_addr != TASK_UNMAPPED_BASE) {
 		start_addr = addr = TASK_UNMAPPED_BASE;
+		mm->cached_hole_size = 0;
 		goto full_search;
 	}
 	return -ENOMEM;
@@ -567,6 +575,7 @@
 	struct vm_area_struct *vma, *prev_vma;
 	struct mm_struct *mm = current->mm;
 	unsigned long base = mm->mmap_base, addr = addr0;
+	unsigned long largest_hole = mm->cached_hole_size;
 	int first_time = 1;
 
 	/* requested length too big for entire address space */
@@ -587,6 +596,10 @@
 			return addr;
 	}
 
+	if( len <= largest_hole ) {
+	        largest_hole = 0;
+		mm->free_area_cache  = base;
+	}
 try_again:
 	/* make sure it can fit in the remaining address space */
 	if (mm->free_area_cache < len)
@@ -615,13 +628,21 @@
 		 * vma->vm_start, use it:
 		 */
 		if (addr+len <= vma->vm_start &&
-				(!prev_vma || (addr >= prev_vma->vm_end)))
+		          (!prev_vma || (addr >= prev_vma->vm_end))) {
 			/* remember the address as a hint for next time */
-			return (mm->free_area_cache = addr);
+		        mm->cached_hole_size = largest_hole;
+		        return (mm->free_area_cache = addr);
+		}
 		else
 			/* pull free_area_cache down to the first hole */
-			if (mm->free_area_cache == vma->vm_end)
+		        if (mm->free_area_cache == vma->vm_end) {
 				mm->free_area_cache = vma->vm_start;
+				mm->cached_hole_size = largest_hole;
+			}
+				
+		/* remember the largest hole we saw so far */
+		if( addr + largest_hole < vma->vm_start )
+		        largest_hole = vma->vm_start - addr;
 
 		/* try just below the current vma->vm_start */
 		addr = vma->vm_start-len;
@@ -634,6 +655,7 @@
 	 */
 	if (first_time) {
 		mm->free_area_cache = base;
+		largest_hole = 0;
 		first_time = 0;
 		goto try_again;
 	}
@@ -644,12 +666,14 @@
 	 * allocations.
 	 */
 	mm->free_area_cache = TASK_UNMAPPED_BASE;
+	mm->cached_hole_size = ~0UL;
 	addr = arch_get_unmapped_area(filp, addr0, len, pgoff, flags);
 	/*
 	 * Restore the topdown base:
 	 */
 	mm->free_area_cache = base;
-
+	mm->cached_hole_size = ~0UL;
+	
 	return addr;
 }
 
diff -ru linux-2.6.11.7/arch/sh/kernel/sys_sh.c linux-2.6.11.7.wwc/arch/sh/kernel/sys_sh.c
--- linux-2.6.11.7/arch/sh/kernel/sys_sh.c	2005-03-02 02:38:34.000000000 -0500
+++ linux-2.6.11.7.wwc/arch/sh/kernel/sys_sh.c	2005-04-27 09:19:19.000000000 -0400
@@ -79,6 +79,10 @@
 		    (!vma || addr + len <= vma->vm_start))
 			return addr;
 	}
+	if( len <= mm->cached_hole_size ) {
+	        mm->cached_hole_size = 0;
+		mm->free_area_cache = TASK_UNMAPPED_BASE;
+	}
 	if (flags & MAP_PRIVATE)
 		addr = PAGE_ALIGN(mm->free_area_cache);
 	else
@@ -95,6 +99,7 @@
 			 */
 			if (start_addr != TASK_UNMAPPED_BASE) {
 				start_addr = addr = TASK_UNMAPPED_BASE;
+				mm->cached_hole_size = 0;
 				goto full_search;
 			}
 			return -ENOMEM;
@@ -106,6 +111,9 @@
 			mm->free_area_cache = addr + len;
 			return addr;
 		}
+		if( addr + mm->cached_hole_size < vma->vm_start )
+		        mm->cached_hole_size = vma->vm_start - addr;
+		
 		addr = vma->vm_end;
 		if (!(flags & MAP_PRIVATE))
 			addr = COLOUR_ALIGN(addr);
diff -ru linux-2.6.11.7/arch/sparc64/kernel/sys_sparc.c linux-2.6.11.7.wwc/arch/sparc64/kernel/sys_sparc.c
--- linux-2.6.11.7/arch/sparc64/kernel/sys_sparc.c	2005-03-02 02:38:10.000000000 -0500
+++ linux-2.6.11.7.wwc/arch/sparc64/kernel/sys_sparc.c	2005-04-27 09:19:19.000000000 -0400
@@ -84,6 +84,10 @@
 			return addr;
 	}
 
+	if( len <= mm->cached_hole_size ) {
+	        mm->cached_hole_size = 0;
+		mm->free_area_cache = TASK_UNMAPPED_BASE;
+	}
 	start_addr = addr = mm->free_area_cache;
 
 	task_size -= len;
@@ -103,6 +107,7 @@
 		if (task_size < addr) {
 			if (start_addr != TASK_UNMAPPED_BASE) {
 				start_addr = addr = TASK_UNMAPPED_BASE;
+				mm->cached_hole_size = 0;
 				goto full_search;
 			}
 			return -ENOMEM;
@@ -114,6 +119,9 @@
 			mm->free_area_cache = addr + len;
 			return addr;
 		}
+		if( addr + mm->cached_hole_size < vma->vm_start )
+		        mm->cached_hole_size = vma->vm_start - addr;
+		
 		addr = vma->vm_end;
 		if (do_color_align)
 			addr = COLOUR_ALIGN(addr, pgoff);
diff -ru linux-2.6.11.7/arch/x86_64/ia32/ia32_aout.c linux-2.6.11.7.wwc/arch/x86_64/ia32/ia32_aout.c
--- linux-2.6.11.7/arch/x86_64/ia32/ia32_aout.c	2005-03-02 02:38:33.000000000 -0500
+++ linux-2.6.11.7.wwc/arch/x86_64/ia32/ia32_aout.c	2005-04-27 09:19:19.000000000 -0400
@@ -312,6 +312,7 @@
 	current->mm->brk = ex.a_bss +
 		(current->mm->start_brk = N_BSSADDR(ex));
 	current->mm->free_area_cache = TASK_UNMAPPED_BASE;
+	current->mm->cached_hole_size = 0;
 
 	current->mm->rss = 0;
 	current->mm->mmap = NULL;
diff -ru linux-2.6.11.7/arch/x86_64/kernel/sys_x86_64.c linux-2.6.11.7.wwc/arch/x86_64/kernel/sys_x86_64.c
--- linux-2.6.11.7/arch/x86_64/kernel/sys_x86_64.c	2005-03-02 02:38:13.000000000 -0500
+++ linux-2.6.11.7.wwc/arch/x86_64/kernel/sys_x86_64.c	2005-04-27 09:19:19.000000000 -0400
@@ -112,6 +112,10 @@
 		    (!vma || addr + len <= vma->vm_start))
 			return addr;
 	}
+	if( len <= mm->cached_hole_size ) {
+	        mm->cached_hole_size = 0;
+		mm->free_area_cache = begin;
+	}
 	addr = mm->free_area_cache;
 	if (addr < begin) 
 		addr = begin; 
@@ -127,6 +131,7 @@
 			 */
 			if (start_addr != begin) {
 				start_addr = addr = begin;
+				mm->cached_hole_size = 0;
 				goto full_search;
 			}
 			return -ENOMEM;
@@ -138,6 +143,9 @@
 			mm->free_area_cache = addr + len;
 			return addr;
 		}
+		if( addr + mm->cached_hole_size < vma->vm_start )
+		        mm->cached_hole_size = vma->vm_start - addr;
+		
 		addr = vma->vm_end;
 	}
 }
diff -ru linux-2.6.11.7/fs/binfmt_aout.c linux-2.6.11.7.wwc/fs/binfmt_aout.c
--- linux-2.6.11.7/fs/binfmt_aout.c	2005-03-02 02:38:37.000000000 -0500
+++ linux-2.6.11.7.wwc/fs/binfmt_aout.c	2005-04-27 09:19:19.000000000 -0400
@@ -316,6 +316,7 @@
 	current->mm->brk = ex.a_bss +
 		(current->mm->start_brk = N_BSSADDR(ex));
 	current->mm->free_area_cache = current->mm->mmap_base;
+	current->mm->cached_hole_size = current->mm->cached_hole_size;
 
 	current->mm->rss = 0;
 	current->mm->mmap = NULL;
diff -ru linux-2.6.11.7/fs/binfmt_elf.c linux-2.6.11.7.wwc/fs/binfmt_elf.c
--- linux-2.6.11.7/fs/binfmt_elf.c	2005-04-27 13:15:09.000000000 -0400
+++ linux-2.6.11.7.wwc/fs/binfmt_elf.c	2005-04-27 09:19:19.000000000 -0400
@@ -766,6 +766,8 @@
 	   change some of these later */
 	current->mm->rss = 0;
 	current->mm->free_area_cache = current->mm->mmap_base;
+	current->mm->cached_hole_size = current->mm->cached_hole_size;
+	
 	retval = setup_arg_pages(bprm, STACK_TOP, executable_stack);
 	if (retval < 0) {
 		send_sig(SIGKILL, current, 0);
diff -ru linux-2.6.11.7/fs/hugetlbfs/inode.c linux-2.6.11.7.wwc/fs/hugetlbfs/inode.c
--- linux-2.6.11.7/fs/hugetlbfs/inode.c	2005-03-02 02:38:25.000000000 -0500
+++ linux-2.6.11.7.wwc/fs/hugetlbfs/inode.c	2005-04-27 12:39:19.000000000 -0400
@@ -122,6 +122,11 @@
 
 	start_addr = mm->free_area_cache;
 
+	if(len <= mm->cached_hole_size ) 
+		start_addr = TASK_UNMAPPED_BASE;
+
+
+
 full_search:
 	addr = ALIGN(start_addr, HPAGE_SIZE);
 
diff -ru linux-2.6.11.7/include/linux/sched.h linux-2.6.11.7.wwc/include/linux/sched.h
--- linux-2.6.11.7/include/linux/sched.h	2005-03-02 02:37:48.000000000 -0500
+++ linux-2.6.11.7.wwc/include/linux/sched.h	2005-04-27 09:19:19.000000000 -0400
@@ -212,8 +212,9 @@
 				unsigned long addr, unsigned long len,
 				unsigned long pgoff, unsigned long flags);
 	void (*unmap_area) (struct vm_area_struct *area);
-	unsigned long mmap_base;		/* base of mmap area */
-	unsigned long free_area_cache;		/* first hole */
+        unsigned long mmap_base;		/* base of mmap area */
+        unsigned long cached_hole_size;         /* if non-zero, the largest hole below free_area_cache */
+	unsigned long free_area_cache;		/* first hole of size cached_hole_size or larger */
 	pgd_t * pgd;
 	atomic_t mm_users;			/* How many users with user space? */
 	atomic_t mm_count;			/* How many references to "struct mm_struct" (users count as 1) */
diff -ru linux-2.6.11.7/kernel/fork.c linux-2.6.11.7.wwc/kernel/fork.c
--- linux-2.6.11.7/kernel/fork.c	2005-03-02 02:37:48.000000000 -0500
+++ linux-2.6.11.7.wwc/kernel/fork.c	2005-04-27 12:44:24.000000000 -0400
@@ -173,6 +173,7 @@
 	mm->mmap = NULL;
 	mm->mmap_cache = NULL;
 	mm->free_area_cache = oldmm->mmap_base;
+	mm->cached_hole_size = ~0UL;
 	mm->map_count = 0;
 	mm->rss = 0;
 	mm->anon_rss = 0;
@@ -301,7 +302,8 @@
 	mm->ioctx_list = NULL;
 	mm->default_kioctx = (struct kioctx)INIT_KIOCTX(mm->default_kioctx, *mm);
 	mm->free_area_cache = TASK_UNMAPPED_BASE;
-
+	mm->cached_hole_size = ~0UL;
+	
 	if (likely(!mm_alloc_pgd(mm))) {
 		mm->def_flags = 0;
 		return mm;
diff -ru linux-2.6.11.7/mm/mmap.c linux-2.6.11.7.wwc/mm/mmap.c
--- linux-2.6.11.7/mm/mmap.c	2005-03-02 02:38:12.000000000 -0500
+++ linux-2.6.11.7.wwc/mm/mmap.c	2005-04-27 12:57:00.000000000 -0400
@@ -1173,7 +1173,12 @@
 		    (!vma || addr + len <= vma->vm_start))
 			return addr;
 	}
-	start_addr = addr = mm->free_area_cache;
+	if( len > mm->cached_hole_size ) 
+	        start_addr = addr = mm->free_area_cache;
+	else {
+	        start_addr = addr = TASK_UNMAPPED_BASE;
+	        mm->cached_hole_size = 0;
+	}
 
 full_search:
 	for (vma = find_vma(mm, addr); ; vma = vma->vm_next) {
@@ -1184,7 +1189,8 @@
 			 * some holes.
 			 */
 			if (start_addr != TASK_UNMAPPED_BASE) {
-				start_addr = addr = TASK_UNMAPPED_BASE;
+			        start_addr = addr = TASK_UNMAPPED_BASE;
+				mm->cached_hole_size = 0;
 				goto full_search;
 			}
 			return -ENOMEM;
@@ -1196,6 +1202,8 @@
 			mm->free_area_cache = addr + len;
 			return addr;
 		}
+		if( addr + mm->cached_hole_size < vma->vm_start )
+		        mm->cached_hole_size = vma->vm_start - addr;
 		addr = vma->vm_end;
 	}
 }
@@ -1207,8 +1215,13 @@
 	 * Is this a new hole at the lowest possible address?
 	 */
 	if (area->vm_start >= TASK_UNMAPPED_BASE &&
-			area->vm_start < area->vm_mm->free_area_cache)
-		area->vm_mm->free_area_cache = area->vm_start;
+	    area->vm_start < area->vm_mm->free_area_cache) {
+	        unsigned area_size = area->vm_end-area->vm_start;
+		if( area->vm_mm->cached_hole_size < area_size ) 
+		        area->vm_mm->cached_hole_size = area_size;
+		else
+		        area->vm_mm->cached_hole_size = ~0UL;
+	}
 }
 
 /*
@@ -1224,6 +1237,7 @@
 	struct vm_area_struct *vma, *prev_vma;
 	struct mm_struct *mm = current->mm;
 	unsigned long base = mm->mmap_base, addr = addr0;
+	unsigned long largest_hole = mm->cached_hole_size;
 	int first_time = 1;
 
 	/* requested length too big for entire address space */
@@ -1243,6 +1257,10 @@
 			return addr;
 	}
 
+	if( len <= mm->cached_hole_size ) {
+	        largest_hole = 0;
+		mm->free_area_cache  = base;
+	}
 try_again:
 	/* make sure it can fit in the remaining address space */
 	if (mm->free_area_cache < len)
@@ -1263,13 +1281,20 @@
 		 * vma->vm_start, use it:
 		 */
 		if (addr+len <= vma->vm_start &&
-				(!prev_vma || (addr >= prev_vma->vm_end)))
+		        (!prev_vma || (addr >= prev_vma->vm_end))) {
 			/* remember the address as a hint for next time */
-			return (mm->free_area_cache = addr);
-		else
+		        mm->cached_hole_size = largest_hole;
+		        return (mm->free_area_cache = addr);
+		} else
 			/* pull free_area_cache down to the first hole */
-			if (mm->free_area_cache == vma->vm_end)
+		        if (mm->free_area_cache == vma->vm_end) {
 				mm->free_area_cache = vma->vm_start;
+				mm->cached_hole_size = largest_hole;
+			}
+				
+		/* remember the largest hole we saw so far */
+		if( addr + largest_hole < vma->vm_start )
+		        largest_hole = vma->vm_start - addr;
 
 		/* try just below the current vma->vm_start */
 		addr = vma->vm_start-len;
@@ -1282,6 +1307,7 @@
 	 */
 	if (first_time) {
 		mm->free_area_cache = base;
+		largest_hole = 0;
 		first_time = 0;
 		goto try_again;
 	}
@@ -1292,12 +1318,14 @@
 	 * allocations.
 	 */
 	mm->free_area_cache = TASK_UNMAPPED_BASE;
+	mm->cached_hole_size = ~0UL;
 	addr = arch_get_unmapped_area(filp, addr0, len, pgoff, flags);
 	/*
 	 * Restore the topdown base:
 	 */
 	mm->free_area_cache = base;
-
+	mm->cached_hole_size = ~0UL;
+	
 	return addr;
 }
 #endif
@@ -1307,8 +1335,13 @@
 	/*
 	 * Is this a new hole at the highest possible address?
 	 */
-	if (area->vm_end > area->vm_mm->free_area_cache)
-		area->vm_mm->free_area_cache = area->vm_end;
+        if (area->vm_end > area->vm_mm->free_area_cache) {
+	        unsigned area_size = area->vm_end-area->vm_start;
+		if( area->vm_mm->cached_hole_size < area_size ) 
+		        area->vm_mm->cached_hole_size = area_size;
+		else
+		        area->vm_mm->cached_hole_size = ~0UL;
+	}
 }
 
 unsigned long
--
To unsubscribe, send a message with 'unsubscribe linux-mm' in
the body to majordomo@kvack.org.  For more info on Linux MM,
see: http://www.linux-mm.org/ .
Don't email: <a href=mailto:"aart@kvack.org"> aart@kvack.org </a>

^ permalink raw reply	[flat|nested] 3+ messages in thread

end of thread, other threads:[~2005-04-27 18:27 UTC | newest]

Thread overview: 3+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2005-04-24  4:18 Fw: [Bug 4520] New: /proc/*/maps fragments too quickly compared to 2.4 Andrew Morton
2005-04-24  7:42 ` Arjan van de Ven
2005-04-27 18:27 ` Wolfgang Wander

This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.