Date: Sun, 11 Oct 2015 16:31:27 +0000 (UTC) From: Alan Cox <alc@FreeBSD.org> To: src-committers@freebsd.org, svn-src-user@freebsd.org Subject: svn commit: r289141 - in user/alc/PQ_LAUNDRY/sys: sys vm Message-ID: <201510111631.t9BGVR4J009266@repo.freebsd.org>
next in thread | raw e-mail | index | archive | help
Author: alc Date: Sun Oct 11 16:31:27 2015 New Revision: 289141 URL: https://svnweb.freebsd.org/changeset/base/289141 Log: Create the basic mechanisms, i.e., a separate queue for laundering dirty pages and a thread for servicing that queue. However, the laundering policy is still very much a work in progress. Discussed with: jeff, kib Sponsored by: EMC / Isilon Storage Division Modified: user/alc/PQ_LAUNDRY/sys/sys/vmmeter.h user/alc/PQ_LAUNDRY/sys/vm/swap_pager.c user/alc/PQ_LAUNDRY/sys/vm/vm_meter.c user/alc/PQ_LAUNDRY/sys/vm/vm_page.c user/alc/PQ_LAUNDRY/sys/vm/vm_page.h user/alc/PQ_LAUNDRY/sys/vm/vm_pageout.c Modified: user/alc/PQ_LAUNDRY/sys/sys/vmmeter.h ============================================================================== --- user/alc/PQ_LAUNDRY/sys/sys/vmmeter.h Sun Oct 11 15:39:37 2015 (r289140) +++ user/alc/PQ_LAUNDRY/sys/sys/vmmeter.h Sun Oct 11 16:31:27 2015 (r289141) @@ -96,6 +96,7 @@ struct vmmeter { u_int v_active_count; /* (q) pages active */ u_int v_inactive_target; /* (c) pages desired inactive */ u_int v_inactive_count; /* (q) pages inactive */ + u_int v_laundry_count; /* (q) pages dirty */ u_int v_cache_count; /* (f) pages on cache queue */ u_int v_pageout_free_min; /* (c) min pages reserved for kernel */ u_int v_interrupt_free_min; /* (c) reserved pages for int code */ @@ -111,7 +112,7 @@ struct vmmeter { u_int v_vforkpages; /* (p) VM pages affected by vfork() */ u_int v_rforkpages; /* (p) VM pages affected by rfork() */ u_int v_kthreadpages; /* (p) VM pages affected by fork() by kernel */ - u_int v_spare[2]; + u_int v_spare[1]; }; #ifdef _KERNEL Modified: user/alc/PQ_LAUNDRY/sys/vm/swap_pager.c ============================================================================== --- user/alc/PQ_LAUNDRY/sys/vm/swap_pager.c Sun Oct 11 15:39:37 2015 (r289140) +++ user/alc/PQ_LAUNDRY/sys/vm/swap_pager.c Sun Oct 11 16:31:27 2015 (r289141) @@ -1617,12 +1617,10 @@ swp_pager_async_iodone(struct buf *bp) ("swp_pager_async_iodone: page %p is not write" " protected", m)); vm_page_undirty(m); + vm_page_lock(m); + vm_page_deactivate(m); + vm_page_unlock(m); vm_page_sunbusy(m); - if (vm_page_count_severe()) { - vm_page_lock(m); - vm_page_try_to_cache(m); - vm_page_unlock(m); - } } } Modified: user/alc/PQ_LAUNDRY/sys/vm/vm_meter.c ============================================================================== --- user/alc/PQ_LAUNDRY/sys/vm/vm_meter.c Sun Oct 11 15:39:37 2015 (r289140) +++ user/alc/PQ_LAUNDRY/sys/vm/vm_meter.c Sun Oct 11 16:31:27 2015 (r289141) @@ -303,6 +303,7 @@ VM_STATS_VM(v_wire_count, "Wired pages") VM_STATS_VM(v_active_count, "Active pages"); VM_STATS_VM(v_inactive_target, "Desired inactive pages"); VM_STATS_VM(v_inactive_count, "Inactive pages"); +VM_STATS_VM(v_laundry_count, "Dirty pages"); VM_STATS_VM(v_cache_count, "Pages on cache queue"); VM_STATS_VM(v_pageout_free_min, "Min pages reserved for kernel"); VM_STATS_VM(v_interrupt_free_min, "Reserved pages for interrupt code"); Modified: user/alc/PQ_LAUNDRY/sys/vm/vm_page.c ============================================================================== --- user/alc/PQ_LAUNDRY/sys/vm/vm_page.c Sun Oct 11 15:39:37 2015 (r289140) +++ user/alc/PQ_LAUNDRY/sys/vm/vm_page.c Sun Oct 11 16:31:27 2015 (r289141) @@ -387,6 +387,10 @@ vm_page_domain_init(struct vm_domain *vm "vm active pagequeue"; *__DECONST(int **, &vmd->vmd_pagequeues[PQ_ACTIVE].pq_vcnt) = &vm_cnt.v_active_count; + *__DECONST(char **, &vmd->vmd_pagequeues[PQ_LAUNDRY].pq_name) = + "vm laundry pagequeue"; + *__DECONST(int **, &vmd->vmd_pagequeues[PQ_LAUNDRY].pq_vcnt) = + &vm_cnt.v_laundry_count; vmd->vmd_page_count = 0; vmd->vmd_free_count = 0; vmd->vmd_segs = 0; @@ -2510,11 +2514,8 @@ vm_page_unwire(vm_page_t m, uint8_t queu if (m->wire_count == 0) { atomic_subtract_int(&vm_cnt.v_wire_count, 1); if ((m->oflags & VPO_UNMANAGED) == 0 && - m->object != NULL && queue != PQ_NONE) { - if (queue == PQ_INACTIVE) - m->flags &= ~PG_WINATCFLS; + m->object != NULL && queue != PQ_NONE) vm_page_enqueue(queue, m); - } return (TRUE); } else return (FALSE); @@ -2565,7 +2566,6 @@ _vm_page_deactivate(vm_page_t m, int ath } else { if (queue != PQ_NONE) vm_page_dequeue(m); - m->flags &= ~PG_WINATCFLS; vm_pagequeue_lock(pq); } m->queue = PQ_INACTIVE; @@ -2604,6 +2604,26 @@ vm_page_deactivate_noreuse(vm_page_t m) } /* + * XXX + */ +void +vm_page_launder(vm_page_t m) +{ + int queue; + + vm_page_assert_locked(m); + if ((queue = m->queue) != PQ_LAUNDRY) { + if (m->wire_count == 0 && (m->oflags & VPO_UNMANAGED) == 0) { + if (queue != PQ_NONE) + vm_page_dequeue(m); + vm_page_enqueue(PQ_LAUNDRY, m); + } else + KASSERT(queue == PQ_NONE, + ("wired page %p is queued", m)); + } +} + +/* * vm_page_try_to_cache: * * Returns 0 on failure, 1 on success @@ -2797,7 +2817,10 @@ vm_page_advise(vm_page_t m, int advice) * tail, thus defeating the queue's LRU operation and ensuring that the * page will be reused quickly. */ - _vm_page_deactivate(m, m->dirty == 0); + if (m->dirty == 0) + _vm_page_deactivate(m, TRUE); + else + vm_page_launder(m); } /* Modified: user/alc/PQ_LAUNDRY/sys/vm/vm_page.h ============================================================================== --- user/alc/PQ_LAUNDRY/sys/vm/vm_page.h Sun Oct 11 15:39:37 2015 (r289140) +++ user/alc/PQ_LAUNDRY/sys/vm/vm_page.h Sun Oct 11 16:31:27 2015 (r289141) @@ -206,7 +206,8 @@ struct vm_page { #define PQ_NONE 255 #define PQ_INACTIVE 0 #define PQ_ACTIVE 1 -#define PQ_COUNT 2 +#define PQ_LAUNDRY 2 +#define PQ_COUNT 3 TAILQ_HEAD(pglist, vm_page); SLIST_HEAD(spglist, vm_page); @@ -326,7 +327,6 @@ extern struct mtx_padalign pa_lock[]; #define PG_FICTITIOUS 0x0004 /* physical page doesn't exist */ #define PG_ZERO 0x0008 /* page is zeroed */ #define PG_MARKER 0x0010 /* special queue marker page */ -#define PG_WINATCFLS 0x0040 /* flush dirty page on inactive q */ #define PG_NODUMP 0x0080 /* don't include this page in a dump */ #define PG_UNHOLDFREE 0x0100 /* delayed free of a held page */ @@ -459,6 +459,7 @@ vm_page_t vm_page_getfake(vm_paddr_t pad void vm_page_initfake(vm_page_t m, vm_paddr_t paddr, vm_memattr_t memattr); int vm_page_insert (vm_page_t, vm_object_t, vm_pindex_t); boolean_t vm_page_is_cached(vm_object_t object, vm_pindex_t pindex); +void vm_page_launder(vm_page_t m); vm_page_t vm_page_lookup (vm_object_t, vm_pindex_t); vm_page_t vm_page_next(vm_page_t m); int vm_page_pa_tryrelock(pmap_t, vm_paddr_t, vm_paddr_t *); Modified: user/alc/PQ_LAUNDRY/sys/vm/vm_pageout.c ============================================================================== --- user/alc/PQ_LAUNDRY/sys/vm/vm_pageout.c Sun Oct 11 15:39:37 2015 (r289140) +++ user/alc/PQ_LAUNDRY/sys/vm/vm_pageout.c Sun Oct 11 16:31:27 2015 (r289141) @@ -168,7 +168,6 @@ MTX_SYSINIT(vm_daemon, &vm_daemon_mtx, " #endif static int vm_max_launder = 32; static int vm_pageout_update_period; -static int defer_swap_pageouts; static int disable_swap_pageouts; static int lowmem_period = 10; static time_t lowmem_uptime; @@ -213,9 +212,6 @@ SYSCTL_INT(_vm, OID_AUTO, swap_idle_enab CTLFLAG_RW, &vm_swap_idle_enabled, 0, "Allow swapout on idle criteria"); #endif -SYSCTL_INT(_vm, OID_AUTO, defer_swapspace_pageouts, - CTLFLAG_RW, &defer_swap_pageouts, 0, "Give preference to dirty pages in mem"); - SYSCTL_INT(_vm, OID_AUTO, disable_swapspace_pageouts, CTLFLAG_RW, &disable_swap_pageouts, 0, "Disallow swapout of dirty pages"); @@ -233,6 +229,8 @@ SYSCTL_INT(_vm, OID_AUTO, max_wired, static boolean_t vm_pageout_fallback_object_lock(vm_page_t, vm_page_t *); static boolean_t vm_pageout_launder(struct vm_pagequeue *pq, int, vm_paddr_t, vm_paddr_t); +static void vm_pageout_launder1(struct vm_domain *vmd, int pass); +static void vm_pageout_laundry_worker(void *arg); #if !defined(NO_SWAPPING) static void vm_pageout_map_deactivate_pages(vm_map_t, long); static void vm_pageout_object_deactivate_pages(pmap_t, vm_object_t, long); @@ -388,8 +386,7 @@ vm_pageout_cluster(vm_page_t m) * We can cluster ONLY if: ->> the page is NOT * clean, wired, busy, held, or mapped into a * buffer, and one of the following: - * 1) The page is inactive, or a seldom used - * active page. + * 1) The page is in the laundry. * -or- * 2) we force the issue. * @@ -420,7 +417,7 @@ more: break; } vm_page_lock(p); - if (p->queue != PQ_INACTIVE || + if (p->queue != PQ_LAUNDRY || p->hold_count != 0) { /* may be undergoing I/O */ vm_page_unlock(p); ib = 0; @@ -448,7 +445,7 @@ more: if (p->dirty == 0) break; vm_page_lock(p); - if (p->queue != PQ_INACTIVE || + if (p->queue != PQ_LAUNDRY || p->hold_count != 0) { /* may be undergoing I/O */ vm_page_unlock(p); break; @@ -546,11 +543,11 @@ vm_pageout_flush(vm_page_t *mc, int coun case VM_PAGER_FAIL: /* * If page couldn't be paged out, then reactivate the - * page so it doesn't clog the inactive list. (We + * page so it doesn't clog the XXX list. (We * will try paging out it again later). */ vm_page_lock(mt); - vm_page_activate(mt); + vm_page_activate(mt); // XXX vm_page_unlock(mt); if (eio != NULL && i >= mreq && i - mreq < runlen) *eio = TRUE; @@ -972,7 +969,7 @@ vm_pageout_clean(vm_page_t m) * (3) reallocated to a different offset, or * (4) cleaned. */ - if (m->queue != PQ_INACTIVE || m->object != object || + if (m->queue != PQ_LAUNDRY || m->object != object || m->pindex != pindex || m->dirty == 0) { vm_page_unlock(m); error = ENXIO; @@ -1015,11 +1012,218 @@ unlock_mp: } /* + * XXX + */ +static void +vm_pageout_launder1(struct vm_domain *vmd, int pass) +{ + vm_page_t m, next; + struct vm_page laundry_marker; + struct vm_pagequeue *pq; + vm_object_t object; + int act_delta, error, maxlaunder, maxscan, vnodes_skipped; + boolean_t pageout_ok, queues_locked; + + vm_pageout_init_marker(&laundry_marker, PQ_LAUNDRY); + + /* + * maxlaunder limits the number of dirty pages we flush per scan. + * For most systems a smaller value (16 or 32) is more robust under + * extreme memory and disk pressure because any unnecessary writes + * to disk can result in extreme performance degredation. However, + * systems with excessive dirty pages (especially when MAP_NOSYNC is + * used) will die horribly with limited laundering. If the pageout + * daemon cannot clean enough pages in the first pass, we let it go + * all out in succeeding passes. + */ + if ((maxlaunder = vm_max_launder) <= 1) + maxlaunder = 1; + if (pass > 1) + maxlaunder = 10000; + + vnodes_skipped = 0; + + /* + * XXX + */ + pq = &vmd->vmd_pagequeues[PQ_LAUNDRY]; + maxscan = pq->pq_cnt; + vm_pagequeue_lock(pq); + queues_locked = TRUE; + for (m = TAILQ_FIRST(&pq->pq_pl); + m != NULL && maxscan-- > 0 && maxlaunder > 0; + m = next) { + vm_pagequeue_assert_locked(pq); + KASSERT(queues_locked, ("unlocked laundry queue")); + KASSERT(m->queue == PQ_LAUNDRY, + ("page %p has an inconsistent queue", m)); + next = TAILQ_NEXT(m, plinks.q); + if ((m->flags & PG_MARKER) != 0) + continue; + KASSERT((m->flags & PG_FICTITIOUS) == 0, + ("PG_FICTITIOUS page %p cannot be in laundry queue", m)); + KASSERT((m->oflags & VPO_UNMANAGED) == 0, + ("VPO_UNMANAGED page %p cannot be in laundry queue", m)); + if (!vm_pageout_page_lock(m, &next) || m->hold_count != 0) { + vm_page_unlock(m); + continue; + } + object = m->object; + if ((!VM_OBJECT_TRYWLOCK(object) && + (!vm_pageout_fallback_object_lock(m, &next) || + m->hold_count != 0)) || vm_page_busied(m)) { + VM_OBJECT_WUNLOCK(object); + vm_page_unlock(m); + continue; + } + + /* + * We unlock the laundry queue, invalidating the + * 'next' pointer. Use our marker to remember our + * place. + */ + TAILQ_INSERT_AFTER(&pq->pq_pl, m, &laundry_marker, plinks.q); + vm_pagequeue_unlock(pq); + queues_locked = FALSE; + + /* + * Invalid pages can be easily freed. They cannot be + * mapped; vm_page_free() asserts this. + */ + if (m->valid == 0) + goto free_page; + + /* + * If the page has been referenced and the object is not dead, + * reactivate or requeue the page depending on whether the + * object is mapped. + */ + if ((m->aflags & PGA_REFERENCED) != 0) { + vm_page_aflag_clear(m, PGA_REFERENCED); + act_delta = 1; + } else + act_delta = 0; + if (object->ref_count != 0) + act_delta += pmap_ts_referenced(m); + else { + KASSERT(!pmap_page_is_mapped(m), + ("page %p is mapped", m)); + } + if (act_delta != 0) { + if (object->ref_count != 0) { + vm_page_activate(m); + + /* + * Increase the activation count if the page + * was referenced while in the laundry queue. + * This makes it less likely that the page will + * be returned prematurely to the inactive + * queue. + */ + m->act_count += act_delta + ACT_ADVANCE; + goto drop_page; + } else if ((object->flags & OBJ_DEAD) == 0) { + vm_page_deactivate(m); // XXX + goto drop_page; + } + } + + /* + * If the page appears to be clean at the machine-independent + * layer, then remove all of its mappings from the pmap in + * anticipation of placing it onto the cache queue. If, + * however, any of the page's mappings allow write access, + * then the page may still be modified until the last of those + * mappings are removed. + */ + if (object->ref_count != 0) { + vm_page_test_dirty(m); + if (m->dirty == 0) + pmap_remove_all(m); + } + + /* + * Clean pages can be freed, but dirty pages must be sent back + * to the laundry, unless they belong to a dead object. + * However, requeueing dirty pages from dead objects is + * pointless, as they are being paged out and freed by the + * thread that destroyed the object. + */ + if (m->dirty == 0) { +free_page: + vm_page_free(m); + PCPU_INC(cnt.v_dfree); + } else if ((object->flags & OBJ_DEAD) == 0) { + if (object->type != OBJT_SWAP && + object->type != OBJT_DEFAULT) + pageout_ok = TRUE; + else if (disable_swap_pageouts) + pageout_ok = FALSE; + else + pageout_ok = TRUE; + if (!pageout_ok) { + vm_pagequeue_lock(pq); + queues_locked = TRUE; + vm_page_requeue_locked(m); + goto drop_page; + } + error = vm_pageout_clean(m); + if (error == 0) + maxlaunder--; + else if (error == EDEADLK) { + pageout_lock_miss++; + vnodes_skipped++; + } + goto relock_queues; + } +drop_page: + vm_page_unlock(m); + VM_OBJECT_WUNLOCK(object); +relock_queues: + if (!queues_locked) { + vm_pagequeue_lock(pq); + queues_locked = TRUE; + } + next = TAILQ_NEXT(&laundry_marker, plinks.q); + TAILQ_REMOVE(&pq->pq_pl, &laundry_marker, plinks.q); + } + vm_pagequeue_unlock(pq); + + /* + * Wakeup the sync daemon if we skipped a vnode in a writeable object + * and we didn't launder enough pages. + */ + if (vnodes_skipped > 0 && maxlaunder > 0) + (void)speedup_syncer(); +} + +/* + * XXX + */ +static void +vm_pageout_laundry_worker(void *arg) +{ + struct vm_domain *domain; + int domidx; + + domidx = (uintptr_t)arg; + domain = &vm_dom[domidx]; + KASSERT(domain->vmd_segs != 0, ("domain without segments")); + + /* + * The pageout laundry worker is never done, so loop forever. + */ + for (;;) { + tsleep(&vm_cnt.v_laundry_count, PVM, "laundr", hz / 10); + vm_pageout_launder1(domain, 1); + } +} + +/* * vm_pageout_scan does the dirty work for the pageout daemon. * * pass 0 - Update active LRU/deactivate pages * pass 1 - Move inactive to cache or free - * pass 2 - Launder dirty pages */ static void vm_pageout_scan(struct vm_domain *vmd, int pass) @@ -1028,9 +1232,9 @@ vm_pageout_scan(struct vm_domain *vmd, i struct vm_pagequeue *pq; vm_object_t object; long min_scan; - int act_delta, addl_page_shortage, deficit, error, maxlaunder, maxscan; - int page_shortage, scan_tick, scanned, vnodes_skipped; - boolean_t pageout_ok, queues_locked; + int act_delta, addl_page_shortage, deficit, maxscan; + int page_shortage, scan_tick, scanned; + boolean_t queues_locked; /* * If we need to reclaim memory ask kernel caches to return @@ -1070,23 +1274,6 @@ vm_pageout_scan(struct vm_domain *vmd, i page_shortage = deficit = 0; /* - * maxlaunder limits the number of dirty pages we flush per scan. - * For most systems a smaller value (16 or 32) is more robust under - * extreme memory and disk pressure because any unnecessary writes - * to disk can result in extreme performance degredation. However, - * systems with excessive dirty pages (especially when MAP_NOSYNC is - * used) will die horribly with limited laundering. If the pageout - * daemon cannot clean enough pages in the first pass, we let it go - * all out in succeeding passes. - */ - if ((maxlaunder = vm_max_launder) <= 1) - maxlaunder = 1; - if (pass > 1) - maxlaunder = 10000; - - vnodes_skipped = 0; - - /* * Start scanning the inactive queue for pages we can move to the * cache or free. The scan will stop when the target is reached or * we have scanned the entire inactive queue. Note that m->act_count @@ -1170,6 +1357,7 @@ unlock_page: * place. */ TAILQ_INSERT_AFTER(&pq->pq_pl, m, &vmd->vmd_marker, plinks.q); + vm_page_dequeue_locked(m); vm_pagequeue_unlock(pq); queues_locked = FALSE; @@ -1209,8 +1397,14 @@ unlock_page: */ m->act_count += act_delta + ACT_ADVANCE; goto drop_page; - } else if ((object->flags & OBJ_DEAD) == 0) - goto requeue_page; + } else if ((object->flags & OBJ_DEAD) == 0) { + vm_pagequeue_lock(pq); + queues_locked = TRUE; + m->queue = PQ_INACTIVE; + TAILQ_INSERT_TAIL(&pq->pq_pl, m, plinks.q); + vm_pagequeue_cnt_inc(pq); + goto drop_page; + } } /* @@ -1227,83 +1421,23 @@ unlock_page: pmap_remove_all(m); } + /* + * Clean pages can be freed, but dirty pages must be sent back + * to the laundry, unless they belong to a dead object. + * However, requeueing dirty pages from dead objects is + * pointless, as they are being paged out and freed by the + * thread that destroyed the object. + */ if (m->dirty == 0) { - /* - * Clean pages can be freed. - */ free_page: vm_page_free(m); PCPU_INC(cnt.v_dfree); --page_shortage; - } else if ((object->flags & OBJ_DEAD) != 0) { - /* - * Leave dirty pages from dead objects at the front of - * the queue. They are being paged out and freed by - * the thread that destroyed the object. They will - * leave the queue shortly after the scan finishes, so - * they should be discounted from the inactive count. - */ - addl_page_shortage++; - } else if ((m->flags & PG_WINATCFLS) == 0 && pass < 2) { - /* - * Dirty pages need to be paged out, but flushing - * a page is extremely expensive versus freeing - * a clean page. Rather then artificially limiting - * the number of pages we can flush, we instead give - * dirty pages extra priority on the inactive queue - * by forcing them to be cycled through the queue - * twice before being flushed, after which the - * (now clean) page will cycle through once more - * before being freed. This significantly extends - * the thrash point for a heavily loaded machine. - */ - m->flags |= PG_WINATCFLS; -requeue_page: - vm_pagequeue_lock(pq); - queues_locked = TRUE; - vm_page_requeue_locked(m); - } else if (maxlaunder > 0) { - /* - * We always want to try to flush some dirty pages if - * we encounter them, to keep the system stable. - * Normally this number is small, but under extreme - * pressure where there are insufficient clean pages - * on the inactive queue, we may have to go all out. - */ - - if (object->type != OBJT_SWAP && - object->type != OBJT_DEFAULT) - pageout_ok = TRUE; - else if (disable_swap_pageouts) - pageout_ok = FALSE; - else if (defer_swap_pageouts) - pageout_ok = vm_page_count_min(); - else - pageout_ok = TRUE; - if (!pageout_ok) - goto requeue_page; - error = vm_pageout_clean(m); - /* - * Decrement page_shortage on success to account for - * the (future) cleaned page. Otherwise we could wind - * up laundering or cleaning too many pages. - */ - if (error == 0) { - page_shortage--; - maxlaunder--; - } else if (error == EDEADLK) { - pageout_lock_miss++; - vnodes_skipped++; - } else if (error == EBUSY) { - addl_page_shortage++; - } - vm_page_lock_assert(m, MA_NOTOWNED); - goto relock_queues; - } + } else if ((object->flags & OBJ_DEAD) == 0) + vm_page_launder(m); drop_page: vm_page_unlock(m); VM_OBJECT_WUNLOCK(object); -relock_queues: if (!queues_locked) { vm_pagequeue_lock(pq); queues_locked = TRUE; @@ -1313,6 +1447,13 @@ relock_queues: } vm_pagequeue_unlock(pq); + /* + * Wakeup the laundry thread(s) if we didn't free the targeted number + * of pages. + */ + if (page_shortage > 0) + wakeup(&vm_cnt.v_laundry_count); + #if !defined(NO_SWAPPING) /* * Wakeup the swapout daemon if we didn't cache or free the targeted @@ -1323,14 +1464,6 @@ relock_queues: #endif /* - * Wakeup the sync daemon if we skipped a vnode in a writeable object - * and we didn't cache or free enough pages. - */ - if (vnodes_skipped > 0 && page_shortage > vm_cnt.v_free_target - - vm_cnt.v_free_min) - (void)speedup_syncer(); - - /* * Compute the number of pages we want to try to move from the * active queue to the inactive queue. */ @@ -1422,7 +1555,14 @@ relock_queues: if (m->act_count == 0) { /* Dequeue to avoid later lock recursion. */ vm_page_dequeue_locked(m); - vm_page_deactivate(m); +#if 0 + if (m->object->ref_count != 0) + vm_page_test_dirty(m); +#endif + if (m->dirty == 0) + vm_page_deactivate(m); + else + vm_page_launder(m); page_shortage--; } else vm_page_requeue_locked(m); @@ -1734,6 +1874,10 @@ vm_pageout(void) #endif swap_pager_swap_init(); + error = kthread_add(vm_pageout_laundry_worker, NULL, curproc, NULL, + 0, 0, "laundry: dom0"); + if (error != 0) + panic("starting laundry for domain 0, error %d", error); #if MAXMEMDOM > 1 for (i = 1; i < vm_ndomains; i++) { error = kthread_add(vm_pageout_worker, (void *)(uintptr_t)i,
Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?201510111631.t9BGVR4J009266>