summaryrefslogtreecommitdiffstats
path: root/sys/vm/vm_pageout.c
diff options
context:
space:
mode:
Diffstat (limited to 'sys/vm/vm_pageout.c')
-rw-r--r--sys/vm/vm_pageout.c187
1 files changed, 95 insertions, 92 deletions
diff --git a/sys/vm/vm_pageout.c b/sys/vm/vm_pageout.c
index bc8784c..d24e51c 100644
--- a/sys/vm/vm_pageout.c
+++ b/sys/vm/vm_pageout.c
@@ -219,7 +219,7 @@ vm_pageout_clean(m)
register vm_object_t object;
vm_page_t mc[2*vm_pageout_page_count];
int pageout_count;
- int i, forward_okay, backward_okay, page_base;
+ int ib, is, page_base;
vm_pindex_t pindex = m->pindex;
object = m->object;
@@ -243,11 +243,9 @@ vm_pageout_clean(m)
mc[vm_pageout_page_count] = m;
pageout_count = 1;
page_base = vm_pageout_page_count;
- forward_okay = TRUE;
- if (pindex != 0)
- backward_okay = TRUE;
- else
- backward_okay = FALSE;
+ ib = 1;
+ is = 1;
+
/*
* Scan object for clusterable pages.
*
@@ -258,82 +256,84 @@ vm_pageout_clean(m)
* active page.
* -or-
* 2) we force the issue.
+ *
+ * During heavy mmap/modification loads the pageout
+ * daemon can really fragment the underlying file
+ * due to flushing pages out of order and not trying
+ * align the clusters (which leave sporatic out-of-order
+ * holes). To solve this problem we do the reverse scan
+ * first and attempt to align our cluster, then do a
+ * forward scan if room remains.
*/
- for (i = 1; (i < vm_pageout_page_count) && (forward_okay || backward_okay); i++) {
+
+more:
+ while (ib && pageout_count < vm_pageout_page_count) {
vm_page_t p;
- /*
- * See if forward page is clusterable.
- */
- if (forward_okay) {
- /*
- * Stop forward scan at end of object.
- */
- if ((pindex + i) > object->size) {
- forward_okay = FALSE;
- goto do_backward;
- }
- p = vm_page_lookup(object, pindex + i);
- if (p) {
- if (((p->queue - p->pc) == PQ_CACHE) ||
- (p->flags & PG_BUSY) || p->busy) {
- forward_okay = FALSE;
- goto do_backward;
- }
- vm_page_test_dirty(p);
- if ((p->dirty & p->valid) != 0 &&
- (p->queue == PQ_INACTIVE) &&
- (p->wire_count == 0) &&
- (p->hold_count == 0)) {
- mc[vm_pageout_page_count + i] = p;
- pageout_count++;
- if (pageout_count == vm_pageout_page_count)
- break;
- } else {
- forward_okay = FALSE;
- }
- } else {
- forward_okay = FALSE;
- }
+ if (ib > pindex) {
+ ib = 0;
+ break;
+ }
+
+ if ((p = vm_page_lookup(object, pindex - ib)) == NULL) {
+ ib = 0;
+ break;
+ }
+ if (((p->queue - p->pc) == PQ_CACHE) ||
+ (p->flags & PG_BUSY) || p->busy) {
+ ib = 0;
+ break;
+ }
+ vm_page_test_dirty(p);
+ if ((p->dirty & p->valid) == 0 ||
+ p->queue != PQ_INACTIVE ||
+ p->wire_count != 0 ||
+ p->hold_count != 0) {
+ ib = 0;
+ break;
}
-do_backward:
+ mc[--page_base] = p;
+ ++pageout_count;
+ ++ib;
/*
- * See if backward page is clusterable.
+ * alignment boundry, stop here and switch directions. Do
+ * not clear ib.
*/
- if (backward_okay) {
- /*
- * Stop backward scan at beginning of object.
- */
- if ((pindex - i) == 0) {
- backward_okay = FALSE;
- }
- p = vm_page_lookup(object, pindex - i);
- if (p) {
- if (((p->queue - p->pc) == PQ_CACHE) ||
- (p->flags & PG_BUSY) || p->busy) {
- backward_okay = FALSE;
- continue;
- }
- vm_page_test_dirty(p);
- if ((p->dirty & p->valid) != 0 &&
- (p->queue == PQ_INACTIVE) &&
- (p->wire_count == 0) &&
- (p->hold_count == 0)) {
- mc[vm_pageout_page_count - i] = p;
- pageout_count++;
- page_base--;
- if (pageout_count == vm_pageout_page_count)
- break;
- } else {
- backward_okay = FALSE;
- }
- } else {
- backward_okay = FALSE;
- }
+ if ((pindex - (ib - 1)) % vm_pageout_page_count == 0)
+ break;
+ }
+
+ while (pageout_count < vm_pageout_page_count &&
+ pindex + is < object->size) {
+ vm_page_t p;
+
+ if ((p = vm_page_lookup(object, pindex + is)) == NULL)
+ break;
+ if (((p->queue - p->pc) == PQ_CACHE) ||
+ (p->flags & PG_BUSY) || p->busy) {
+ break;
}
+ vm_page_test_dirty(p);
+ if ((p->dirty & p->valid) == 0 ||
+ p->queue != PQ_INACTIVE ||
+ p->wire_count != 0 ||
+ p->hold_count != 0) {
+ break;
+ }
+ mc[page_base + pageout_count] = p;
+ ++pageout_count;
+ ++is;
}
/*
+ * If we exhausted our forward scan, continue with the reverse scan
+ * when possible, even past a page boundry. This catches boundry
+ * conditions.
+ */
+ if (ib && pageout_count < vm_pageout_page_count)
+ goto more;
+
+ /*
* we allow reads during pageouts...
*/
return vm_pageout_flush(&mc[page_base], pageout_count, 0);
@@ -397,7 +397,7 @@ vm_pageout_flush(mc, count, flags)
* worked.
*/
pmap_clear_modify(VM_PAGE_TO_PHYS(mt));
- mt->dirty = 0;
+ vm_page_undirty(mt);
break;
case VM_PAGER_ERROR:
case VM_PAGER_FAIL:
@@ -646,9 +646,7 @@ vm_pageout_scan()
* to the cache.
*/
- page_shortage = (cnt.v_free_target + cnt.v_cache_min) -
- (cnt.v_free_count + cnt.v_cache_count);
- page_shortage += addl_page_shortage_init;
+ page_shortage = vm_paging_target() + addl_page_shortage_init;
/*
* Figure out what to do with dirty pages when they are encountered.
@@ -787,7 +785,7 @@ rescan0:
} else {
swap_pageouts_ok = !(defer_swap_pageouts || disable_swap_pageouts);
swap_pageouts_ok |= (!disable_swap_pageouts && defer_swap_pageouts &&
- (cnt.v_free_count + cnt.v_cache_count) < cnt.v_free_min);
+ vm_page_count_min());
}
@@ -1082,15 +1080,11 @@ rescan0:
* in a writeable object, wakeup the sync daemon. And kick swapout
* if we did not get enough free pages.
*/
- if ((cnt.v_cache_count + cnt.v_free_count) <
- (cnt.v_free_target + cnt.v_cache_min) ) {
- if (vnodes_skipped &&
- (cnt.v_cache_count + cnt.v_free_count) < cnt.v_free_min) {
+ if (vm_paging_target() > 0) {
+ if (vnodes_skipped && vm_page_count_min())
(void) speedup_syncer();
- }
#if !defined(NO_SWAPPING)
- if (vm_swap_enabled &&
- (cnt.v_free_count + cnt.v_cache_count < cnt.v_free_target)) {
+ if (vm_swap_enabled && vm_page_count_target()) {
vm_req_vmdaemon();
vm_pageout_req_swapout |= VM_SWAP_NORMAL;
}
@@ -1101,8 +1095,7 @@ rescan0:
* make sure that we have swap space -- if we are low on memory and
* swap -- then kill the biggest process.
*/
- if ((vm_swap_size == 0 || swap_pager_full) &&
- ((cnt.v_free_count + cnt.v_cache_count) < cnt.v_free_min)) {
+ if ((vm_swap_size == 0 || swap_pager_full) && vm_page_count_min()) {
bigproc = NULL;
bigsize = 0;
for (p = allproc.lh_first; p != 0; p = p->p_list.le_next) {
@@ -1160,8 +1153,10 @@ vm_pageout_page_stats()
static int fullintervalcount = 0;
int page_shortage;
- page_shortage = (cnt.v_inactive_target + cnt.v_cache_max + cnt.v_free_min) -
+ page_shortage =
+ (cnt.v_inactive_target + cnt.v_cache_max + cnt.v_free_min) -
(cnt.v_free_count + cnt.v_inactive_count + cnt.v_cache_count);
+
if (page_shortage <= 0)
return;
@@ -1253,7 +1248,9 @@ vm_size_t count;
cnt.v_interrupt_free_min;
cnt.v_free_reserved = vm_pageout_page_count +
cnt.v_pageout_free_min + (count / 768) + PQ_L2_SIZE;
+ cnt.v_free_severe = cnt.v_free_min / 2;
cnt.v_free_min += cnt.v_free_reserved;
+ cnt.v_free_severe += cnt.v_free_reserved;
return 1;
}
@@ -1326,8 +1323,17 @@ vm_pageout()
while (TRUE) {
int error;
int s = splvm();
- if (!vm_pages_needed ||
- ((cnt.v_free_count + cnt.v_cache_count) > cnt.v_free_min)) {
+
+ if (vm_pages_needed && vm_page_count_min()) {
+ /*
+ * Still not done, sleep a bit and go again
+ */
+ vm_pages_needed = 0;
+ tsleep(&vm_pages_needed, PVM, "psleep", hz/2);
+ } else {
+ /*
+ * Good enough, sleep & handle stats
+ */
vm_pages_needed = 0;
error = tsleep(&vm_pages_needed,
PVM, "psleep", vm_pageout_stats_interval * hz);
@@ -1336,9 +1342,6 @@ vm_pageout()
vm_pageout_page_stats();
continue;
}
- } else if (vm_pages_needed) {
- vm_pages_needed = 0;
- tsleep(&vm_pages_needed, PVM, "psleep", hz/2);
}
if (vm_pages_needed)
OpenPOWER on IntegriCloud