improved version - Re: contig memory allocator fix (vm_contig.c)

Andrew Atrens atrens at nortelnetworks.com
Tue Feb 22 07:23:10 PST 2005


Matthew Dillon wrote:

> 
> :Improved version - aligns better with caller's M_*WAIT* semantics.
> :
> :Final version hopefully - looking for feedback :) ...
> :
> :Andrew.
> 
>     The patch doesn't seem to apply cleanly, I think you have line wrap
>     turned on or something.  Could you repost it as a mime attachment or
>     with line wrap turned off ?


I bet that's it. :) The line containing 'flags' is the longest line of
the patch, and 'flags);' is right at the end of it.

Okay, it's a regular attachment this time.


Andrew.
--- vm_contig.c.old	2004-11-10 15:19:51.000000000 -0500
+++ vm_contig.c	2005-02-21 15:55:48.000000000 -0500
@@ -179,7 +179,22 @@
 }
 
 /*
- * vm_contig_pg_alloc:
+ * vm_contig_pg_flush:
+ * 
+ * Attempt to flush (count) pages from the given page queue. 
+ *
+ * Return TRUE on success
+ */
+static int
+vm_contig_pg_flush( int queue, int count ) {
+	for ( ; count > 0 ; count-- ) {
+		if (! vm_contig_pg_clean( queue ) )
+			break;
+	}
+	return (count > 0);
+}
+/*
+ * vm_contig_int_pg_alloc:
  *
  * Allocate contiguous pages from the VM.  This function does not
  * map the allocated pages into the kernel map, otherwise it is
@@ -189,13 +204,14 @@
  * statistics and for allocations of less than a page.
  *
  */
-int
-vm_contig_pg_alloc(
+static int
+vm_contig_int_pg_alloc(
 	unsigned long size,
 	vm_paddr_t low,
 	vm_paddr_t high,
 	unsigned long alignment,
-	unsigned long boundary)
+	unsigned long boundary,
+	unsigned int mflags )
 {
 	int i, start, pass;
 	vm_offset_t phys;
@@ -212,8 +228,10 @@
 		panic("vm_contig_pg_alloc: boundary must be a power of 2");
 
 	start = 0;
-	for (pass = 0; pass <= 1; pass++) {
-		crit_enter();
+
+	crit_enter();
+
+	for (pass = 0; pass <= 2; pass++) {
 again:
 		/*
 		 * Find first page in array that is free, within range, aligned, and
@@ -244,13 +262,40 @@
 		if ((i == vmstats.v_page_count) ||
 			((VM_PAGE_TO_PHYS(&pga[i]) + size) > high)) {
 
-again1:
-			if (vm_contig_pg_clean(PQ_INACTIVE))
-				goto again1;
-			if (vm_contig_pg_clean(PQ_ACTIVE))
-				goto again1;
+			/*
+			 * Best effort flush of all inactive pages.
+			 * This is quite quick, for now stall all
+			 * callers, even if they've specified M_NOWAIT.
+			 */
+			if ( !vm_contig_pg_flush( PQ_INACTIVE,
+				 vmstats.v_inactive_count ) ) {
+				crit_exit(); /* give interrupts a chance */
+				crit_enter();
+			}
+
+			/*
+			 * Best effort flush of active pages.
+			 *
+			 * This is very, very slow.
+			 * Only do this if the caller has agreed to M_WAITOK.
+			 *
+			 * If enough pages are flushed, we may succeed on
+			 * next (final) pass, if not the caller, contigmalloc(),
+			 * will fail in the index < 0 case.
+			 */
+			if ( pass > 0 && (mflags & M_WAITOK) ) {
+				vm_contig_pg_flush( PQ_ACTIVE,
+						vmstats.v_active_count);
+			}
+
+			crit_exit(); /* give interrupts a chance */
 
-			crit_exit();
+			/*
+			 * We're already too high in the address space
+			 * to succeed, reset to 0 for the next iteration.
+			 */
+			start = 0;
+			crit_enter();
 			continue;	/* next pass */
 		}
 		start = i;
@@ -311,6 +356,30 @@
 	return (-1);
 }
 
+
+/*
+ * vm_contig_pg_alloc:
+ *
+ * Allocate contiguous pages from the VM.  This function does not
+ * map the allocated pages into the kernel map, otherwise it is
+ * impossible to make large allocations (i.e. >2G).
+ *
+ * Malloc()'s data structures have been used for collection of
+ * statistics and for allocations of less than a page.
+ *
+ */
+int
+vm_contig_pg_alloc(
+	unsigned long size,
+	vm_paddr_t low,
+	vm_paddr_t high,
+	unsigned long alignment,
+	unsigned long boundary)
+{
+	return vm_contig_int_pg_alloc(size, low, high, 
+			alignment, boundary, M_WAITOK);
+}
+
 /*
  * vm_contig_pg_free:
  *
@@ -423,7 +492,7 @@
 	int index;
 	void *rv;
 
-	index = vm_contig_pg_alloc(size, low, high, alignment, boundary);
+	index = vm_contig_int_pg_alloc(size, low, high, alignment, boundary, flags);
 	if (index < 0) {
 		printf("contigmalloc_map: failed in index < 0 case!");
 		return NULL;




More information about the Submit mailing list