kernel - Abort pageout operations when free memory recovers
authorMatthew Dillon <dillon@apollo.backplane.com>
Sat, 2 Mar 2013 06:07:51 +0000 (22:07 -0800)
committerMatthew Dillon <dillon@apollo.backplane.com>
Sat, 2 Mar 2013 06:07:51 +0000 (22:07 -0800)
* Nominal pageout operations free memory.  On systems with large amounts
  of ram the pageout count can be very large and take a long time to
  clear.  During this period, other unrelated processes might free memory.
  But even when sufficient memory is freed the pageout daemon still tries
  to finish clearing its previously calculated number of pages.

* Add a check in the deactivation scan to break out of the loop if
  a sufficient number of free pages is detected.

* Fixes unnecessary extra paging out of data (which can go on for several
  minutes) on large systems when memory is freed by other means.

sys/vm/vm_pageout.c

index 6bfe869..e282b6d 100644 (file)
@@ -1144,6 +1144,24 @@ vm_pageout_scan_inactive(int pass, int q, int avail_shortage,
                } else {
                        vm_page_wakeup(m);
                }
+
+               /*
+                * Systems with a ton of memory can wind up with huge
+                * deactivation counts.  Because the inactive scan is
+                * doing a lot of flushing, the combination can result
+                * in excessive paging even in situations where other
+                * unrelated threads free up sufficient VM.
+                *
+                * To deal with this we abort the nominal active->inactive
+                * scan before we hit the inactive target when free+cache
+                * levels have already reached their target.
+                *
+                * Note that nominally the inactive scan is not freeing or
+                * caching pages, it is deactivating active pages, so it
+                * will not by itself cause the abort condition.
+                */
+               if (vm_paging_target() < 0)
+                       break;
        }
        vm_page_queues_spin_lock(PQ_INACTIVE + q);
        TAILQ_REMOVE(&vm_page_queues[PQ_INACTIVE + q].pl, &marker, pageq);