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

Andrew Atrens atrens at nortelnetworks.com
Mon Feb 21 13:40:04 PST 2005


Improved version - aligns better with caller's M_*WAIT* semantics.

Final version hopefully - looking for feedback :) ...

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