kernel - Increase VM page free minimums for allocations
authorMatthew Dillon <dillon@apollo.backplane.com>
Tue, 25 Oct 2011 04:53:43 +0000 (21:53 -0700)
committerMatthew Dillon <dillon@apollo.backplane.com>
Tue, 25 Oct 2011 04:53:43 +0000 (21:53 -0700)
* Recent work removed the global vm_token and moved to per-vm_page_queue
  spin locks, which allows cpus to allocate VM pages concurrently.  This
  could result in a situation where remaining free pages got blown out
  without giving the system a chance to replentish them.

* Symptoms included the BUF/BIO system complaining of memory exhaustion
  and the pageout daemon deadlocking on low memory (which would deadlock
  the whole machine in a memory-exhausted state).

* Increase minimums to prevent this.  In particular, the interrupt_free_min
  was previously hardwired to a value of 2.. as in 2 pages (8192 bytes),
  which is an excessively low value.  The new calculations place this value
  (typically) around a few-hundred pages.

sys/vm/vm_pageout.c
sys/vm/vnode_pager.c

index 855084a..cd8b0cd 100644 (file)
@@ -1678,18 +1678,21 @@ vm_pageout_free_page_calc(vm_size_t count)
        /*
         * free_reserved needs to include enough for the largest swap pager
         * structures plus enough for any pv_entry structs when paging.
+        *
+        * v_free_min           normal allocations
+        * v_free_reserved      system allocations
+        * v_pageout_free_min   allocations by pageout daemon
+        * v_interrupt_free_min low level allocations (e.g swap structures)
         */
        if (vmstats.v_page_count > 1024)
-               vmstats.v_free_min = 4 + (vmstats.v_page_count - 1024) / 200;
+               vmstats.v_free_min = 64 + (vmstats.v_page_count - 1024) / 200;
        else
-               vmstats.v_free_min = 4;
-       vmstats.v_pageout_free_min = (2*MAXBSIZE)/PAGE_SIZE +
-               vmstats.v_interrupt_free_min;
-       vmstats.v_free_reserved = vm_pageout_page_count +
-               vmstats.v_pageout_free_min + (count / 768) + PQ_L2_SIZE;
-       vmstats.v_free_severe = vmstats.v_free_min / 2;
-       vmstats.v_free_min += vmstats.v_free_reserved;
-       vmstats.v_free_severe += vmstats.v_free_reserved;
+               vmstats.v_free_min = 64;
+       vmstats.v_free_reserved = vmstats.v_free_min * 4 / 8 + 7;
+       vmstats.v_free_severe = vmstats.v_free_min * 4 / 8 + 0;
+       vmstats.v_pageout_free_min = vmstats.v_free_min * 2 / 8 + 7;
+       vmstats.v_interrupt_free_min = vmstats.v_free_min * 1 / 8 + 7;
+
        return 1;
 }
 
@@ -1710,7 +1713,6 @@ vm_pageout_thread(void)
         */
        curthread->td_flags |= TDF_SYSTHREAD;
 
-       vmstats.v_interrupt_free_min = 2;
        if (vmstats.v_page_count < 2000)
                vm_pageout_page_count = 8;
 
index 081862e..9a589d4 100644 (file)
@@ -709,8 +709,10 @@ vnode_pager_putpages(vm_object_t object, vm_page_t *m, int count,
         * daemon up.  This should be probably be addressed XXX.
         */
 
-       if ((vmstats.v_free_count + vmstats.v_cache_count) < vmstats.v_pageout_free_min)
+       if ((vmstats.v_free_count + vmstats.v_cache_count) <
+           vmstats.v_pageout_free_min) {
                sync |= OBJPC_SYNC;
+       }
 
        /*
         * Call device-specific putpages function