xref: /dragonfly/sys/vm/vm_swapcache.c (revision 27b6ee03)
1096e95c0SMatthew Dillon /*
28e7c4729SMatthew Dillon  * (MPSAFE)
38e7c4729SMatthew Dillon  *
4096e95c0SMatthew Dillon  * Copyright (c) 2010 The DragonFly Project.  All rights reserved.
5096e95c0SMatthew Dillon  *
6096e95c0SMatthew Dillon  * This code is derived from software contributed to The DragonFly Project
7096e95c0SMatthew Dillon  * by Matthew Dillon <dillon@backplane.com>
8096e95c0SMatthew Dillon  *
9096e95c0SMatthew Dillon  * Redistribution and use in source and binary forms, with or without
10096e95c0SMatthew Dillon  * modification, are permitted provided that the following conditions
11096e95c0SMatthew Dillon  * are met:
12096e95c0SMatthew Dillon  *
13096e95c0SMatthew Dillon  * 1. Redistributions of source code must retain the above copyright
14096e95c0SMatthew Dillon  *    notice, this list of conditions and the following disclaimer.
15096e95c0SMatthew Dillon  * 2. Redistributions in binary form must reproduce the above copyright
16096e95c0SMatthew Dillon  *    notice, this list of conditions and the following disclaimer in
17096e95c0SMatthew Dillon  *    the documentation and/or other materials provided with the
18096e95c0SMatthew Dillon  *    distribution.
19096e95c0SMatthew Dillon  * 3. Neither the name of The DragonFly Project nor the names of its
20096e95c0SMatthew Dillon  *    contributors may be used to endorse or promote products derived
21096e95c0SMatthew Dillon  *    from this software without specific, prior written permission.
22096e95c0SMatthew Dillon  *
23096e95c0SMatthew Dillon  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
24096e95c0SMatthew Dillon  * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
25096e95c0SMatthew Dillon  * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
26096e95c0SMatthew Dillon  * FOR A PARTICULAR PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE
27096e95c0SMatthew Dillon  * COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
28096e95c0SMatthew Dillon  * INCIDENTAL, SPECIAL, EXEMPLARY OR CONSEQUENTIAL DAMAGES (INCLUDING,
29096e95c0SMatthew Dillon  * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
30096e95c0SMatthew Dillon  * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
31096e95c0SMatthew Dillon  * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
32096e95c0SMatthew Dillon  * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
33096e95c0SMatthew Dillon  * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
34096e95c0SMatthew Dillon  * SUCH DAMAGE.
35096e95c0SMatthew Dillon  */
36096e95c0SMatthew Dillon 
37096e95c0SMatthew Dillon /*
38096e95c0SMatthew Dillon  * Implement the swapcache daemon.  When enabled swap is assumed to be
39096e95c0SMatthew Dillon  * configured on a fast storage device such as a SSD.  Swap is assigned
40096e95c0SMatthew Dillon  * to clean vnode-backed pages in the inactive queue, clustered by object
41096e95c0SMatthew Dillon  * if possible, and written out.  The swap assignment sticks around even
42096e95c0SMatthew Dillon  * after the underlying pages have been recycled.
43096e95c0SMatthew Dillon  *
44096e95c0SMatthew Dillon  * The daemon manages write bandwidth based on sysctl settings to control
45096e95c0SMatthew Dillon  * wear on the SSD.
46096e95c0SMatthew Dillon  *
47096e95c0SMatthew Dillon  * The vnode strategy code will check for the swap assignments and divert
483ffc7051SMatthew Dillon  * reads to the swap device when the data is present in the swapcache.
49096e95c0SMatthew Dillon  *
50096e95c0SMatthew Dillon  * This operates on both regular files and the block device vnodes used by
51096e95c0SMatthew Dillon  * filesystems to manage meta-data.
52096e95c0SMatthew Dillon  */
53096e95c0SMatthew Dillon 
54096e95c0SMatthew Dillon #include "opt_vm.h"
55096e95c0SMatthew Dillon #include <sys/param.h>
56096e95c0SMatthew Dillon #include <sys/systm.h>
57096e95c0SMatthew Dillon #include <sys/kernel.h>
58096e95c0SMatthew Dillon #include <sys/proc.h>
59096e95c0SMatthew Dillon #include <sys/kthread.h>
60096e95c0SMatthew Dillon #include <sys/resourcevar.h>
61096e95c0SMatthew Dillon #include <sys/signalvar.h>
62096e95c0SMatthew Dillon #include <sys/vnode.h>
63096e95c0SMatthew Dillon #include <sys/vmmeter.h>
64096e95c0SMatthew Dillon #include <sys/sysctl.h>
65497524bfSMatthew Dillon #include <sys/eventhandler.h>
66096e95c0SMatthew Dillon 
67096e95c0SMatthew Dillon #include <vm/vm.h>
68096e95c0SMatthew Dillon #include <vm/vm_param.h>
69096e95c0SMatthew Dillon #include <sys/lock.h>
70096e95c0SMatthew Dillon #include <vm/vm_object.h>
71096e95c0SMatthew Dillon #include <vm/vm_page.h>
72096e95c0SMatthew Dillon #include <vm/vm_map.h>
73096e95c0SMatthew Dillon #include <vm/vm_pageout.h>
74096e95c0SMatthew Dillon #include <vm/vm_pager.h>
75096e95c0SMatthew Dillon #include <vm/swap_pager.h>
76096e95c0SMatthew Dillon #include <vm/vm_extern.h>
77096e95c0SMatthew Dillon 
78096e95c0SMatthew Dillon #include <sys/thread2.h>
79b12defdcSMatthew Dillon #include <sys/spinlock2.h>
80096e95c0SMatthew Dillon #include <vm/vm_page2.h>
81096e95c0SMatthew Dillon 
82096e95c0SMatthew Dillon /* the kernel process "vm_pageout"*/
83aabd5ce8SMatthew Dillon static int vm_swapcached_flush (vm_page_t m, int isblkdev);
843ffc7051SMatthew Dillon static int vm_swapcache_test(vm_page_t m);
8500a3fdcaSMatthew Dillon static void vm_swapcache_writing(vm_page_t marker);
8600a3fdcaSMatthew Dillon static void vm_swapcache_cleaning(vm_object_t marker);
87096e95c0SMatthew Dillon struct thread *swapcached_thread;
88096e95c0SMatthew Dillon 
89096e95c0SMatthew Dillon SYSCTL_NODE(_vm, OID_AUTO, swapcache, CTLFLAG_RW, NULL, NULL);
90096e95c0SMatthew Dillon 
91c504e38eSMatthew Dillon int vm_swapcache_read_enable;
92e527fb6bSMatthew Dillon int vm_swapcache_inactive_heuristic;
93096e95c0SMatthew Dillon static int vm_swapcache_sleep;
941e5196f0SMatthew Dillon static int vm_swapcache_maxlaunder = 256;
95096e95c0SMatthew Dillon static int vm_swapcache_data_enable = 0;
96096e95c0SMatthew Dillon static int vm_swapcache_meta_enable = 0;
97e9b56058SMatthew Dillon static int vm_swapcache_maxswappct = 75;
98e527fb6bSMatthew Dillon static int vm_swapcache_hysteresis;
99bfa86281SMatthew Dillon int vm_swapcache_use_chflags = 1;	/* require chflags cache */
1003ffc7051SMatthew Dillon static int64_t vm_swapcache_minburst = 10000000LL;	/* 10MB */
1013ffc7051SMatthew Dillon static int64_t vm_swapcache_curburst = 4000000000LL;	/* 4G after boot */
1023ffc7051SMatthew Dillon static int64_t vm_swapcache_maxburst = 2000000000LL;	/* 2G nominal max */
1033ffc7051SMatthew Dillon static int64_t vm_swapcache_accrate = 100000LL;		/* 100K/s */
104096e95c0SMatthew Dillon static int64_t vm_swapcache_write_count;
1053ffc7051SMatthew Dillon static int64_t vm_swapcache_maxfilesize;
106096e95c0SMatthew Dillon 
107096e95c0SMatthew Dillon SYSCTL_INT(_vm_swapcache, OID_AUTO, maxlaunder,
108096e95c0SMatthew Dillon 	CTLFLAG_RW, &vm_swapcache_maxlaunder, 0, "");
109c504e38eSMatthew Dillon 
110096e95c0SMatthew Dillon SYSCTL_INT(_vm_swapcache, OID_AUTO, data_enable,
111096e95c0SMatthew Dillon 	CTLFLAG_RW, &vm_swapcache_data_enable, 0, "");
112096e95c0SMatthew Dillon SYSCTL_INT(_vm_swapcache, OID_AUTO, meta_enable,
113096e95c0SMatthew Dillon 	CTLFLAG_RW, &vm_swapcache_meta_enable, 0, "");
114c504e38eSMatthew Dillon SYSCTL_INT(_vm_swapcache, OID_AUTO, read_enable,
115c504e38eSMatthew Dillon 	CTLFLAG_RW, &vm_swapcache_read_enable, 0, "");
116e9b56058SMatthew Dillon SYSCTL_INT(_vm_swapcache, OID_AUTO, maxswappct,
117e9b56058SMatthew Dillon 	CTLFLAG_RW, &vm_swapcache_maxswappct, 0, "");
118e527fb6bSMatthew Dillon SYSCTL_INT(_vm_swapcache, OID_AUTO, hysteresis,
119e527fb6bSMatthew Dillon 	CTLFLAG_RW, &vm_swapcache_hysteresis, 0, "");
120e9b56058SMatthew Dillon SYSCTL_INT(_vm_swapcache, OID_AUTO, use_chflags,
121e9b56058SMatthew Dillon 	CTLFLAG_RW, &vm_swapcache_use_chflags, 0, "");
122c504e38eSMatthew Dillon 
1233ffc7051SMatthew Dillon SYSCTL_QUAD(_vm_swapcache, OID_AUTO, minburst,
1243ffc7051SMatthew Dillon 	CTLFLAG_RW, &vm_swapcache_minburst, 0, "");
125c504e38eSMatthew Dillon SYSCTL_QUAD(_vm_swapcache, OID_AUTO, curburst,
126c504e38eSMatthew Dillon 	CTLFLAG_RW, &vm_swapcache_curburst, 0, "");
127c504e38eSMatthew Dillon SYSCTL_QUAD(_vm_swapcache, OID_AUTO, maxburst,
128c504e38eSMatthew Dillon 	CTLFLAG_RW, &vm_swapcache_maxburst, 0, "");
1293ffc7051SMatthew Dillon SYSCTL_QUAD(_vm_swapcache, OID_AUTO, maxfilesize,
1303ffc7051SMatthew Dillon 	CTLFLAG_RW, &vm_swapcache_maxfilesize, 0, "");
131c504e38eSMatthew Dillon SYSCTL_QUAD(_vm_swapcache, OID_AUTO, accrate,
132c504e38eSMatthew Dillon 	CTLFLAG_RW, &vm_swapcache_accrate, 0, "");
133096e95c0SMatthew Dillon SYSCTL_QUAD(_vm_swapcache, OID_AUTO, write_count,
134096e95c0SMatthew Dillon 	CTLFLAG_RW, &vm_swapcache_write_count, 0, "");
135096e95c0SMatthew Dillon 
136e9b56058SMatthew Dillon #define SWAPMAX(adj)	\
137e9b56058SMatthew Dillon 	((int64_t)vm_swap_max * (vm_swapcache_maxswappct + (adj)) / 100)
138e9b56058SMatthew Dillon 
139096e95c0SMatthew Dillon /*
140497524bfSMatthew Dillon  * When shutting down the machine we want to stop swapcache operation
141497524bfSMatthew Dillon  * immediately so swap is not accessed after devices have been shuttered.
142497524bfSMatthew Dillon  */
143497524bfSMatthew Dillon static void
144497524bfSMatthew Dillon shutdown_swapcache(void *arg __unused)
145497524bfSMatthew Dillon {
146497524bfSMatthew Dillon 	vm_swapcache_read_enable = 0;
147497524bfSMatthew Dillon 	vm_swapcache_data_enable = 0;
148497524bfSMatthew Dillon 	vm_swapcache_meta_enable = 0;
149497524bfSMatthew Dillon 	wakeup(&vm_swapcache_sleep);	/* shortcut 5-second wait */
150497524bfSMatthew Dillon }
151497524bfSMatthew Dillon 
152497524bfSMatthew Dillon /*
153096e95c0SMatthew Dillon  * vm_swapcached is the high level pageout daemon.
1548e7c4729SMatthew Dillon  *
1558e7c4729SMatthew Dillon  * No requirements.
156096e95c0SMatthew Dillon  */
157096e95c0SMatthew Dillon static void
158cd8ab232SMatthew Dillon vm_swapcached_thread(void)
159096e95c0SMatthew Dillon {
16000a3fdcaSMatthew Dillon 	enum { SWAPC_WRITING, SWAPC_CLEANING } state = SWAPC_WRITING;
1613ffc7051SMatthew Dillon 	enum { SWAPB_BURSTING, SWAPB_RECOVERING } burst = SWAPB_BURSTING;
16251c99c61SMatthew Dillon 	static struct vm_page page_marker[PQ_L2_SIZE];
163027193ebSMatthew Dillon 	static struct vm_object object_marker;
164027193ebSMatthew Dillon 	int q;
165096e95c0SMatthew Dillon 
166096e95c0SMatthew Dillon 	/*
167096e95c0SMatthew Dillon 	 * Thread setup
168096e95c0SMatthew Dillon 	 */
169096e95c0SMatthew Dillon 	curthread->td_flags |= TDF_SYSTHREAD;
170497524bfSMatthew Dillon 	EVENTHANDLER_REGISTER(shutdown_pre_sync, shutdown_kproc,
171497524bfSMatthew Dillon 			      swapcached_thread, SHUTDOWN_PRI_FIRST);
172497524bfSMatthew Dillon 	EVENTHANDLER_REGISTER(shutdown_pre_sync, shutdown_swapcache,
173497524bfSMatthew Dillon 			      NULL, SHUTDOWN_PRI_SECOND);
174096e95c0SMatthew Dillon 
175096e95c0SMatthew Dillon 	/*
17600a3fdcaSMatthew Dillon 	 * Initialize our marker for the inactive scan (SWAPC_WRITING)
177096e95c0SMatthew Dillon 	 */
17800a3fdcaSMatthew Dillon 	bzero(&page_marker, sizeof(page_marker));
17951c99c61SMatthew Dillon 	for (q = 0; q < PQ_L2_SIZE; ++q) {
180027193ebSMatthew Dillon 		page_marker[q].flags = PG_BUSY | PG_FICTITIOUS | PG_MARKER;
181027193ebSMatthew Dillon 		page_marker[q].queue = PQ_INACTIVE + q;
182027193ebSMatthew Dillon 		page_marker[q].pc = q;
183027193ebSMatthew Dillon 		page_marker[q].wire_count = 1;
184027193ebSMatthew Dillon 		vm_page_queues_spin_lock(PQ_INACTIVE + q);
185027193ebSMatthew Dillon 		TAILQ_INSERT_HEAD(
186027193ebSMatthew Dillon 			&vm_page_queues[PQ_INACTIVE + q].pl,
187027193ebSMatthew Dillon 			&page_marker[q], pageq);
188027193ebSMatthew Dillon 		vm_page_queues_spin_unlock(PQ_INACTIVE + q);
189027193ebSMatthew Dillon 	}
190b12defdcSMatthew Dillon 
191e527fb6bSMatthew Dillon 	vm_swapcache_hysteresis = vmstats.v_inactive_target / 2;
192e527fb6bSMatthew Dillon 	vm_swapcache_inactive_heuristic = -vm_swapcache_hysteresis;
193096e95c0SMatthew Dillon 
19400a3fdcaSMatthew Dillon 	/*
19500a3fdcaSMatthew Dillon 	 * Initialize our marker for the vm_object scan (SWAPC_CLEANING)
19600a3fdcaSMatthew Dillon 	 */
19700a3fdcaSMatthew Dillon 	bzero(&object_marker, sizeof(object_marker));
19800a3fdcaSMatthew Dillon 	object_marker.type = OBJT_MARKER;
1992de4f77eSMatthew Dillon 	lwkt_gettoken(&vmobj_token);
20000a3fdcaSMatthew Dillon 	TAILQ_INSERT_HEAD(&vm_object_list, &object_marker, object_list);
2012de4f77eSMatthew Dillon 	lwkt_reltoken(&vmobj_token);
202096e95c0SMatthew Dillon 
203096e95c0SMatthew Dillon 	for (;;) {
204096e95c0SMatthew Dillon 		/*
205497524bfSMatthew Dillon 		 * Handle shutdown
206497524bfSMatthew Dillon 		 */
207497524bfSMatthew Dillon 		kproc_suspend_loop();
208497524bfSMatthew Dillon 
209497524bfSMatthew Dillon 		/*
2103da46bd7SMatthew Dillon 		 * Check every 5 seconds when not enabled or if no swap
2113da46bd7SMatthew Dillon 		 * is present.
212096e95c0SMatthew Dillon 		 */
2133da46bd7SMatthew Dillon 		if ((vm_swapcache_data_enable == 0 &&
2143da46bd7SMatthew Dillon 		     vm_swapcache_meta_enable == 0) ||
2153da46bd7SMatthew Dillon 		    vm_swap_max == 0) {
216096e95c0SMatthew Dillon 			tsleep(&vm_swapcache_sleep, 0, "csleep", hz * 5);
217096e95c0SMatthew Dillon 			continue;
218096e95c0SMatthew Dillon 		}
219c504e38eSMatthew Dillon 
220c504e38eSMatthew Dillon 		/*
2213da46bd7SMatthew Dillon 		 * Polling rate when enabled is approximately 10 hz.
222c504e38eSMatthew Dillon 		 */
223c504e38eSMatthew Dillon 		tsleep(&vm_swapcache_sleep, 0, "csleep", hz / 10);
22400a3fdcaSMatthew Dillon 
22500a3fdcaSMatthew Dillon 		/*
22600a3fdcaSMatthew Dillon 		 * State hysteresis.  Generate write activity up to 75% of
22700a3fdcaSMatthew Dillon 		 * swap, then clean out swap assignments down to 70%, then
22800a3fdcaSMatthew Dillon 		 * repeat.
22900a3fdcaSMatthew Dillon 		 */
23000a3fdcaSMatthew Dillon 		if (state == SWAPC_WRITING) {
231e9b56058SMatthew Dillon 			if (vm_swap_cache_use > SWAPMAX(0))
23200a3fdcaSMatthew Dillon 				state = SWAPC_CLEANING;
23300a3fdcaSMatthew Dillon 		} else {
23408fb7a9dSMatthew Dillon 			if (vm_swap_cache_use < SWAPMAX(-10))
23500a3fdcaSMatthew Dillon 				state = SWAPC_WRITING;
23600a3fdcaSMatthew Dillon 		}
23700a3fdcaSMatthew Dillon 
23800a3fdcaSMatthew Dillon 		/*
23900a3fdcaSMatthew Dillon 		 * We are allowed to continue accumulating burst value
2403ffc7051SMatthew Dillon 		 * in either state.  Allow the user to set curburst > maxburst
2413ffc7051SMatthew Dillon 		 * for the initial load-in.
24200a3fdcaSMatthew Dillon 		 */
2433ffc7051SMatthew Dillon 		if (vm_swapcache_curburst < vm_swapcache_maxburst) {
244c504e38eSMatthew Dillon 			vm_swapcache_curburst += vm_swapcache_accrate / 10;
245c504e38eSMatthew Dillon 			if (vm_swapcache_curburst > vm_swapcache_maxburst)
246c504e38eSMatthew Dillon 				vm_swapcache_curburst = vm_swapcache_maxburst;
2473ffc7051SMatthew Dillon 		}
248c504e38eSMatthew Dillon 
249c504e38eSMatthew Dillon 		/*
25000a3fdcaSMatthew Dillon 		 * We don't want to nickle-and-dime the scan as that will
25100a3fdcaSMatthew Dillon 		 * create unnecessary fragmentation.  The minimum burst
25200a3fdcaSMatthew Dillon 		 * is one-seconds worth of accumulation.
253c504e38eSMatthew Dillon 		 */
25400a3fdcaSMatthew Dillon 		if (state == SWAPC_WRITING) {
2553ffc7051SMatthew Dillon 			if (vm_swapcache_curburst >= vm_swapcache_accrate) {
2563ffc7051SMatthew Dillon 				if (burst == SWAPB_BURSTING) {
25751c99c61SMatthew Dillon 					for (q = 0; q < PQ_L2_SIZE; ++q) {
258027193ebSMatthew Dillon 						vm_swapcache_writing(
259027193ebSMatthew Dillon 							&page_marker[q]);
260027193ebSMatthew Dillon 					}
2613ffc7051SMatthew Dillon 					if (vm_swapcache_curburst <= 0)
2623ffc7051SMatthew Dillon 						burst = SWAPB_RECOVERING;
2633ffc7051SMatthew Dillon 				} else if (vm_swapcache_curburst >
2643ffc7051SMatthew Dillon 					   vm_swapcache_minburst) {
26551c99c61SMatthew Dillon 					for (q = 0; q < PQ_L2_SIZE; ++q) {
266027193ebSMatthew Dillon 						vm_swapcache_writing(
267027193ebSMatthew Dillon 							&page_marker[q]);
268027193ebSMatthew Dillon 					}
2693ffc7051SMatthew Dillon 					burst = SWAPB_BURSTING;
2703ffc7051SMatthew Dillon 				}
2713ffc7051SMatthew Dillon 			}
27200a3fdcaSMatthew Dillon 		} else {
27300a3fdcaSMatthew Dillon 			vm_swapcache_cleaning(&object_marker);
27400a3fdcaSMatthew Dillon 		}
27500a3fdcaSMatthew Dillon 	}
276eccc8ca1SMatthew Dillon 
277eccc8ca1SMatthew Dillon 	/*
278eccc8ca1SMatthew Dillon 	 * Cleanup (NOT REACHED)
279eccc8ca1SMatthew Dillon 	 */
28051c99c61SMatthew Dillon 	for (q = 0; q < PQ_L2_SIZE; ++q) {
281027193ebSMatthew Dillon 		vm_page_queues_spin_lock(PQ_INACTIVE + q);
282027193ebSMatthew Dillon 		TAILQ_REMOVE(
283027193ebSMatthew Dillon 			&vm_page_queues[PQ_INACTIVE + q].pl,
284027193ebSMatthew Dillon 			&page_marker[q], pageq);
285027193ebSMatthew Dillon 		vm_page_queues_spin_unlock(PQ_INACTIVE + q);
286027193ebSMatthew Dillon 	}
287eccc8ca1SMatthew Dillon 
2882de4f77eSMatthew Dillon 	lwkt_gettoken(&vmobj_token);
28900a3fdcaSMatthew Dillon 	TAILQ_REMOVE(&vm_object_list, &object_marker, object_list);
2902de4f77eSMatthew Dillon 	lwkt_reltoken(&vmobj_token);
29100a3fdcaSMatthew Dillon }
292096e95c0SMatthew Dillon 
293cd8ab232SMatthew Dillon static struct kproc_desc swpc_kp = {
294cd8ab232SMatthew Dillon 	"swapcached",
295cd8ab232SMatthew Dillon 	vm_swapcached_thread,
296cd8ab232SMatthew Dillon 	&swapcached_thread
297cd8ab232SMatthew Dillon };
298cd8ab232SMatthew Dillon SYSINIT(swapcached, SI_SUB_KTHREAD_PAGE, SI_ORDER_SECOND, kproc_start, &swpc_kp)
299cd8ab232SMatthew Dillon 
30000a3fdcaSMatthew Dillon static void
30100a3fdcaSMatthew Dillon vm_swapcache_writing(vm_page_t marker)
30200a3fdcaSMatthew Dillon {
30300a3fdcaSMatthew Dillon 	vm_object_t object;
30400a3fdcaSMatthew Dillon 	struct vnode *vp;
30500a3fdcaSMatthew Dillon 	vm_page_t m;
30600a3fdcaSMatthew Dillon 	int count;
307aabd5ce8SMatthew Dillon 	int isblkdev;
308096e95c0SMatthew Dillon 
309096e95c0SMatthew Dillon 	/*
310fdc53cc7SMatthew Dillon 	 * Deal with an overflow of the heuristic counter or if the user
311fdc53cc7SMatthew Dillon 	 * manually changes the hysteresis.
312fdc53cc7SMatthew Dillon 	 *
313e527fb6bSMatthew Dillon 	 * Try to avoid small incremental pageouts by waiting for enough
314e527fb6bSMatthew Dillon 	 * pages to buildup in the inactive queue to hopefully get a good
315e527fb6bSMatthew Dillon 	 * burst in.  This heuristic is bumped by the VM system and reset
316e527fb6bSMatthew Dillon 	 * when our scan hits the end of the queue.
317e527fb6bSMatthew Dillon 	 */
318fdc53cc7SMatthew Dillon 	if (vm_swapcache_inactive_heuristic < -vm_swapcache_hysteresis)
319fdc53cc7SMatthew Dillon 		vm_swapcache_inactive_heuristic = -vm_swapcache_hysteresis;
320e527fb6bSMatthew Dillon 	if (vm_swapcache_inactive_heuristic < 0)
321e527fb6bSMatthew Dillon 		return;
322e527fb6bSMatthew Dillon 
323e527fb6bSMatthew Dillon 	/*
324096e95c0SMatthew Dillon 	 * Scan the inactive queue from our marker to locate
325096e95c0SMatthew Dillon 	 * suitable pages to push to the swap cache.
326096e95c0SMatthew Dillon 	 *
327096e95c0SMatthew Dillon 	 * We are looking for clean vnode-backed pages.
3285ac04117SMatthew Dillon 	 *
3295ac04117SMatthew Dillon 	 * NOTE: PG_SWAPPED pages in particular are not part of
3305ac04117SMatthew Dillon 	 *	 our count because once the cache stabilizes we
3315ac04117SMatthew Dillon 	 *	 can end up with a very high datarate of VM pages
3325ac04117SMatthew Dillon 	 *	 cycling from it.
333096e95c0SMatthew Dillon 	 */
33400a3fdcaSMatthew Dillon 	count = vm_swapcache_maxlaunder;
33500a3fdcaSMatthew Dillon 
336027193ebSMatthew Dillon 	vm_page_queues_spin_lock(marker->queue);
337b12defdcSMatthew Dillon 	while ((m = TAILQ_NEXT(marker, pageq)) != NULL && count-- > 0) {
338027193ebSMatthew Dillon 		KKASSERT(m->queue == marker->queue);
339b12defdcSMatthew Dillon 
340b12defdcSMatthew Dillon 		if (vm_swapcache_curburst < 0)
341b12defdcSMatthew Dillon 			break;
342027193ebSMatthew Dillon 		TAILQ_REMOVE(
343027193ebSMatthew Dillon 			&vm_page_queues[marker->queue].pl, marker, pageq);
344027193ebSMatthew Dillon 		TAILQ_INSERT_AFTER(
345027193ebSMatthew Dillon 			&vm_page_queues[marker->queue].pl, m, marker, pageq);
3465ac04117SMatthew Dillon 		if (m->flags & (PG_MARKER | PG_SWAPPED)) {
347096e95c0SMatthew Dillon 			++count;
348096e95c0SMatthew Dillon 			continue;
349096e95c0SMatthew Dillon 		}
350b12defdcSMatthew Dillon 		if (vm_page_busy_try(m, TRUE))
351096e95c0SMatthew Dillon 			continue;
352027193ebSMatthew Dillon 		vm_page_queues_spin_unlock(marker->queue);
353b12defdcSMatthew Dillon 
354b12defdcSMatthew Dillon 		if ((object = m->object) == NULL) {
355b12defdcSMatthew Dillon 			vm_page_wakeup(m);
356027193ebSMatthew Dillon 			vm_page_queues_spin_lock(marker->queue);
357b12defdcSMatthew Dillon 			continue;
358b12defdcSMatthew Dillon 		}
359b12defdcSMatthew Dillon 		vm_object_hold(object);
360b12defdcSMatthew Dillon 		if (m->object != object) {
361b12defdcSMatthew Dillon 			vm_object_drop(object);
362b12defdcSMatthew Dillon 			vm_page_wakeup(m);
363027193ebSMatthew Dillon 			vm_page_queues_spin_lock(marker->queue);
364b12defdcSMatthew Dillon 			continue;
365b12defdcSMatthew Dillon 		}
366b12defdcSMatthew Dillon 		if (vm_swapcache_test(m)) {
367b12defdcSMatthew Dillon 			vm_object_drop(object);
368b12defdcSMatthew Dillon 			vm_page_wakeup(m);
369027193ebSMatthew Dillon 			vm_page_queues_spin_lock(marker->queue);
370b12defdcSMatthew Dillon 			continue;
371b12defdcSMatthew Dillon 		}
372b12defdcSMatthew Dillon 
373c504e38eSMatthew Dillon 		vp = object->handle;
374b12defdcSMatthew Dillon 		if (vp == NULL) {
375b12defdcSMatthew Dillon 			vm_object_drop(object);
376b12defdcSMatthew Dillon 			vm_page_wakeup(m);
377027193ebSMatthew Dillon 			vm_page_queues_spin_lock(marker->queue);
378c504e38eSMatthew Dillon 			continue;
379b12defdcSMatthew Dillon 		}
380d3070b8dSMatthew Dillon 
381c504e38eSMatthew Dillon 		switch(vp->v_type) {
382c504e38eSMatthew Dillon 		case VREG:
383e9b56058SMatthew Dillon 			/*
384bfa86281SMatthew Dillon 			 * PG_NOTMETA generically means 'don't swapcache this',
385bfa86281SMatthew Dillon 			 * and HAMMER will set this for regular data buffers
386bfa86281SMatthew Dillon 			 * (and leave it unset for meta-data buffers) as
387bfa86281SMatthew Dillon 			 * appropriate when double buffering is enabled.
388bfa86281SMatthew Dillon 			 */
389b12defdcSMatthew Dillon 			if (m->flags & PG_NOTMETA) {
390b12defdcSMatthew Dillon 				vm_object_drop(object);
391b12defdcSMatthew Dillon 				vm_page_wakeup(m);
392027193ebSMatthew Dillon 				vm_page_queues_spin_lock(marker->queue);
393bfa86281SMatthew Dillon 				continue;
394b12defdcSMatthew Dillon 			}
395bfa86281SMatthew Dillon 
396bfa86281SMatthew Dillon 			/*
397e9b56058SMatthew Dillon 			 * If data_enable is 0 do not try to swapcache data.
398e9b56058SMatthew Dillon 			 * If use_chflags is set then only swapcache data for
399e9b56058SMatthew Dillon 			 * VSWAPCACHE marked vnodes, otherwise any vnode.
400e9b56058SMatthew Dillon 			 */
401e9b56058SMatthew Dillon 			if (vm_swapcache_data_enable == 0 ||
402e9b56058SMatthew Dillon 			    ((vp->v_flag & VSWAPCACHE) == 0 &&
403e9b56058SMatthew Dillon 			     vm_swapcache_use_chflags)) {
404b12defdcSMatthew Dillon 				vm_object_drop(object);
405b12defdcSMatthew Dillon 				vm_page_wakeup(m);
406027193ebSMatthew Dillon 				vm_page_queues_spin_lock(marker->queue);
407c504e38eSMatthew Dillon 				continue;
408e9b56058SMatthew Dillon 			}
409d3070b8dSMatthew Dillon 			if (vm_swapcache_maxfilesize &&
410d3070b8dSMatthew Dillon 			    object->size >
411d3070b8dSMatthew Dillon 			    (vm_swapcache_maxfilesize >> PAGE_SHIFT)) {
412b12defdcSMatthew Dillon 				vm_object_drop(object);
413b12defdcSMatthew Dillon 				vm_page_wakeup(m);
414027193ebSMatthew Dillon 				vm_page_queues_spin_lock(marker->queue);
415d3070b8dSMatthew Dillon 				continue;
416d3070b8dSMatthew Dillon 			}
417aabd5ce8SMatthew Dillon 			isblkdev = 0;
418c504e38eSMatthew Dillon 			break;
419c504e38eSMatthew Dillon 		case VCHR:
420aabd5ce8SMatthew Dillon 			/*
421bfa86281SMatthew Dillon 			 * PG_NOTMETA generically means 'don't swapcache this',
422bfa86281SMatthew Dillon 			 * and HAMMER will set this for regular data buffers
423bfa86281SMatthew Dillon 			 * (and leave it unset for meta-data buffers) as
424bfa86281SMatthew Dillon 			 * appropriate when double buffering is enabled.
425aabd5ce8SMatthew Dillon 			 */
426b12defdcSMatthew Dillon 			if (m->flags & PG_NOTMETA) {
427b12defdcSMatthew Dillon 				vm_object_drop(object);
428b12defdcSMatthew Dillon 				vm_page_wakeup(m);
429027193ebSMatthew Dillon 				vm_page_queues_spin_lock(marker->queue);
430aabd5ce8SMatthew Dillon 				continue;
431b12defdcSMatthew Dillon 			}
432b12defdcSMatthew Dillon 			if (vm_swapcache_meta_enable == 0) {
433b12defdcSMatthew Dillon 				vm_object_drop(object);
434b12defdcSMatthew Dillon 				vm_page_wakeup(m);
435027193ebSMatthew Dillon 				vm_page_queues_spin_lock(marker->queue);
436c504e38eSMatthew Dillon 				continue;
437b12defdcSMatthew Dillon 			}
438aabd5ce8SMatthew Dillon 			isblkdev = 1;
439c504e38eSMatthew Dillon 			break;
440c504e38eSMatthew Dillon 		default:
441b12defdcSMatthew Dillon 			vm_object_drop(object);
442b12defdcSMatthew Dillon 			vm_page_wakeup(m);
443027193ebSMatthew Dillon 			vm_page_queues_spin_lock(marker->queue);
444c504e38eSMatthew Dillon 			continue;
445c504e38eSMatthew Dillon 		}
446096e95c0SMatthew Dillon 
447096e95c0SMatthew Dillon 
448096e95c0SMatthew Dillon 		/*
4493ffc7051SMatthew Dillon 		 * Assign swap and initiate I/O.
4503ffc7051SMatthew Dillon 		 *
4513ffc7051SMatthew Dillon 		 * (adjust for the --count which also occurs in the loop)
452096e95c0SMatthew Dillon 		 */
453aabd5ce8SMatthew Dillon 		count -= vm_swapcached_flush(m, isblkdev) - 1;
454096e95c0SMatthew Dillon 
455096e95c0SMatthew Dillon 		/*
456096e95c0SMatthew Dillon 		 * Setup for next loop using marker.
457096e95c0SMatthew Dillon 		 */
458b12defdcSMatthew Dillon 		vm_object_drop(object);
459027193ebSMatthew Dillon 		vm_page_queues_spin_lock(marker->queue);
460096e95c0SMatthew Dillon 	}
4611e5196f0SMatthew Dillon 
4621e5196f0SMatthew Dillon 	/*
463b12defdcSMatthew Dillon 	 * The marker could wind up at the end, which is ok.  If we hit the
464b12defdcSMatthew Dillon 	 * end of the list adjust the heuristic.
4651e5196f0SMatthew Dillon 	 *
4661e5196f0SMatthew Dillon 	 * Earlier inactive pages that were dirty and become clean
4671e5196f0SMatthew Dillon 	 * are typically moved to the end of PQ_INACTIVE by virtue
4681e5196f0SMatthew Dillon 	 * of vfs_vmio_release() when they become unwired from the
4691e5196f0SMatthew Dillon 	 * buffer cache.
4701e5196f0SMatthew Dillon 	 */
471b12defdcSMatthew Dillon 	if (m == NULL)
472e527fb6bSMatthew Dillon 		vm_swapcache_inactive_heuristic = -vm_swapcache_hysteresis;
473027193ebSMatthew Dillon 	vm_page_queues_spin_unlock(marker->queue);
474096e95c0SMatthew Dillon }
475096e95c0SMatthew Dillon 
476096e95c0SMatthew Dillon /*
477b12defdcSMatthew Dillon  * Flush the specified page using the swap_pager.  The page
478b12defdcSMatthew Dillon  * must be busied by the caller and its disposition will become
479b12defdcSMatthew Dillon  * the responsibility of this function.
4803ffc7051SMatthew Dillon  *
4813ffc7051SMatthew Dillon  * Try to collect surrounding pages, including pages which may
4823ffc7051SMatthew Dillon  * have already been assigned swap.  Try to cluster within a
4833ffc7051SMatthew Dillon  * contiguous aligned SMAP_META_PAGES (typ 16 x PAGE_SIZE) block
4843ffc7051SMatthew Dillon  * to match what swap_pager_putpages() can do.
4853ffc7051SMatthew Dillon  *
4863ffc7051SMatthew Dillon  * We also want to try to match against the buffer cache blocksize
4873ffc7051SMatthew Dillon  * but we don't really know what it is here.  Since the buffer cache
4883ffc7051SMatthew Dillon  * wires and unwires pages in groups the fact that we skip wired pages
4893ffc7051SMatthew Dillon  * should be sufficient.
4903ffc7051SMatthew Dillon  *
4913ffc7051SMatthew Dillon  * Returns a count of pages we might have flushed (minimum 1)
492096e95c0SMatthew Dillon  */
493096e95c0SMatthew Dillon static
4943ffc7051SMatthew Dillon int
495aabd5ce8SMatthew Dillon vm_swapcached_flush(vm_page_t m, int isblkdev)
496096e95c0SMatthew Dillon {
497096e95c0SMatthew Dillon 	vm_object_t object;
4983ffc7051SMatthew Dillon 	vm_page_t marray[SWAP_META_PAGES];
4993ffc7051SMatthew Dillon 	vm_pindex_t basei;
5003ffc7051SMatthew Dillon 	int rtvals[SWAP_META_PAGES];
5013ffc7051SMatthew Dillon 	int x;
5023ffc7051SMatthew Dillon 	int i;
5033ffc7051SMatthew Dillon 	int j;
5043ffc7051SMatthew Dillon 	int count;
505b12defdcSMatthew Dillon 	int error;
506096e95c0SMatthew Dillon 
507096e95c0SMatthew Dillon 	vm_page_io_start(m);
508096e95c0SMatthew Dillon 	vm_page_protect(m, VM_PROT_READ);
509096e95c0SMatthew Dillon 	object = m->object;
510b12defdcSMatthew Dillon 	vm_object_hold(object);
511096e95c0SMatthew Dillon 
5123ffc7051SMatthew Dillon 	/*
5133ffc7051SMatthew Dillon 	 * Try to cluster around (m), keeping in mind that the swap pager
5143ffc7051SMatthew Dillon 	 * can only do SMAP_META_PAGES worth of continguous write.
5153ffc7051SMatthew Dillon 	 */
5163ffc7051SMatthew Dillon 	x = (int)m->pindex & SWAP_META_MASK;
5173ffc7051SMatthew Dillon 	marray[x] = m;
5183ffc7051SMatthew Dillon 	basei = m->pindex;
519b12defdcSMatthew Dillon 	vm_page_wakeup(m);
5203ffc7051SMatthew Dillon 
5213ffc7051SMatthew Dillon 	for (i = x - 1; i >= 0; --i) {
522b12defdcSMatthew Dillon 		m = vm_page_lookup_busy_try(object, basei - x + i,
523b12defdcSMatthew Dillon 					    TRUE, &error);
524b12defdcSMatthew Dillon 		if (error || m == NULL)
5253ffc7051SMatthew Dillon 			break;
526b12defdcSMatthew Dillon 		if (vm_swapcache_test(m)) {
527b12defdcSMatthew Dillon 			vm_page_wakeup(m);
5283ffc7051SMatthew Dillon 			break;
529b12defdcSMatthew Dillon 		}
530b12defdcSMatthew Dillon 		if (isblkdev && (m->flags & PG_NOTMETA)) {
531b12defdcSMatthew Dillon 			vm_page_wakeup(m);
532aabd5ce8SMatthew Dillon 			break;
533b12defdcSMatthew Dillon 		}
5343ffc7051SMatthew Dillon 		vm_page_io_start(m);
5353ffc7051SMatthew Dillon 		vm_page_protect(m, VM_PROT_READ);
5363ffc7051SMatthew Dillon 		if (m->queue - m->pc == PQ_CACHE) {
5373ffc7051SMatthew Dillon 			vm_page_unqueue_nowakeup(m);
5383ffc7051SMatthew Dillon 			vm_page_deactivate(m);
5393ffc7051SMatthew Dillon 		}
5403ffc7051SMatthew Dillon 		marray[i] = m;
541b12defdcSMatthew Dillon 		vm_page_wakeup(m);
5423ffc7051SMatthew Dillon 	}
5433ffc7051SMatthew Dillon 	++i;
5443ffc7051SMatthew Dillon 
5453ffc7051SMatthew Dillon 	for (j = x + 1; j < SWAP_META_PAGES; ++j) {
546b12defdcSMatthew Dillon 		m = vm_page_lookup_busy_try(object, basei - x + j,
547b12defdcSMatthew Dillon 					    TRUE, &error);
548b12defdcSMatthew Dillon 		if (error || m == NULL)
5493ffc7051SMatthew Dillon 			break;
550b12defdcSMatthew Dillon 		if (vm_swapcache_test(m)) {
551b12defdcSMatthew Dillon 			vm_page_wakeup(m);
5523ffc7051SMatthew Dillon 			break;
553b12defdcSMatthew Dillon 		}
554b12defdcSMatthew Dillon 		if (isblkdev && (m->flags & PG_NOTMETA)) {
555b12defdcSMatthew Dillon 			vm_page_wakeup(m);
556aabd5ce8SMatthew Dillon 			break;
557b12defdcSMatthew Dillon 		}
5583ffc7051SMatthew Dillon 		vm_page_io_start(m);
5593ffc7051SMatthew Dillon 		vm_page_protect(m, VM_PROT_READ);
5603ffc7051SMatthew Dillon 		if (m->queue - m->pc == PQ_CACHE) {
5613ffc7051SMatthew Dillon 			vm_page_unqueue_nowakeup(m);
5623ffc7051SMatthew Dillon 			vm_page_deactivate(m);
5633ffc7051SMatthew Dillon 		}
5643ffc7051SMatthew Dillon 		marray[j] = m;
565b12defdcSMatthew Dillon 		vm_page_wakeup(m);
5663ffc7051SMatthew Dillon 	}
5673ffc7051SMatthew Dillon 
5683ffc7051SMatthew Dillon 	count = j - i;
5693ffc7051SMatthew Dillon 	vm_object_pip_add(object, count);
5703ffc7051SMatthew Dillon 	swap_pager_putpages(object, marray + i, count, FALSE, rtvals + i);
5713ffc7051SMatthew Dillon 	vm_swapcache_write_count += count * PAGE_SIZE;
5723ffc7051SMatthew Dillon 	vm_swapcache_curburst -= count * PAGE_SIZE;
5733ffc7051SMatthew Dillon 
5743ffc7051SMatthew Dillon 	while (i < j) {
5753ffc7051SMatthew Dillon 		if (rtvals[i] != VM_PAGER_PEND) {
576b12defdcSMatthew Dillon 			vm_page_busy_wait(marray[i], FALSE, "swppgfd");
5773ffc7051SMatthew Dillon 			vm_page_io_finish(marray[i]);
578b12defdcSMatthew Dillon 			vm_page_wakeup(marray[i]);
579096e95c0SMatthew Dillon 			vm_object_pip_wakeup(object);
580096e95c0SMatthew Dillon 		}
5813ffc7051SMatthew Dillon 		++i;
5823ffc7051SMatthew Dillon 	}
583b12defdcSMatthew Dillon 	vm_object_drop(object);
5843ffc7051SMatthew Dillon 	return(count);
585096e95c0SMatthew Dillon }
58600a3fdcaSMatthew Dillon 
5873ffc7051SMatthew Dillon /*
5883ffc7051SMatthew Dillon  * Test whether a VM page is suitable for writing to the swapcache.
5893ffc7051SMatthew Dillon  * Does not test m->queue, PG_MARKER, or PG_SWAPPED.
5903ffc7051SMatthew Dillon  *
5913ffc7051SMatthew Dillon  * Returns 0 on success, 1 on failure
5923ffc7051SMatthew Dillon  */
5933ffc7051SMatthew Dillon static int
5943ffc7051SMatthew Dillon vm_swapcache_test(vm_page_t m)
5953ffc7051SMatthew Dillon {
5963ffc7051SMatthew Dillon 	vm_object_t object;
5973ffc7051SMatthew Dillon 
598b12defdcSMatthew Dillon 	if (m->flags & PG_UNMANAGED)
5993ffc7051SMatthew Dillon 		return(1);
600b12defdcSMatthew Dillon 	if (m->hold_count || m->wire_count)
6013ffc7051SMatthew Dillon 		return(1);
6023ffc7051SMatthew Dillon 	if (m->valid != VM_PAGE_BITS_ALL)
6033ffc7051SMatthew Dillon 		return(1);
6043ffc7051SMatthew Dillon 	if (m->dirty & m->valid)
6053ffc7051SMatthew Dillon 		return(1);
6063ffc7051SMatthew Dillon 	if ((object = m->object) == NULL)
6073ffc7051SMatthew Dillon 		return(1);
6083ffc7051SMatthew Dillon 	if (object->type != OBJT_VNODE ||
6093ffc7051SMatthew Dillon 	    (object->flags & OBJ_DEAD)) {
6103ffc7051SMatthew Dillon 		return(1);
6113ffc7051SMatthew Dillon 	}
6123ffc7051SMatthew Dillon 	vm_page_test_dirty(m);
6133ffc7051SMatthew Dillon 	if (m->dirty & m->valid)
6143ffc7051SMatthew Dillon 		return(1);
6153ffc7051SMatthew Dillon 	return(0);
6163ffc7051SMatthew Dillon }
6173ffc7051SMatthew Dillon 
6183ffc7051SMatthew Dillon /*
6193ffc7051SMatthew Dillon  * Cleaning pass
6203ffc7051SMatthew Dillon  */
62100a3fdcaSMatthew Dillon static
62200a3fdcaSMatthew Dillon void
62300a3fdcaSMatthew Dillon vm_swapcache_cleaning(vm_object_t marker)
62400a3fdcaSMatthew Dillon {
62500a3fdcaSMatthew Dillon 	vm_object_t object;
62600a3fdcaSMatthew Dillon 	struct vnode *vp;
62700a3fdcaSMatthew Dillon 	int count;
62800a3fdcaSMatthew Dillon 	int n;
62900a3fdcaSMatthew Dillon 
63000a3fdcaSMatthew Dillon 	object = marker;
63100a3fdcaSMatthew Dillon 	count = vm_swapcache_maxlaunder;
63200a3fdcaSMatthew Dillon 
63300a3fdcaSMatthew Dillon 	/*
63400a3fdcaSMatthew Dillon 	 * Look for vnode objects
63500a3fdcaSMatthew Dillon 	 */
6362de4f77eSMatthew Dillon 	lwkt_gettoken(&vmobj_token);
6372de4f77eSMatthew Dillon 
638bfa86281SMatthew Dillon 	while ((object = TAILQ_NEXT(object, object_list)) != NULL) {
639d2d8515bSMatthew Dillon 		lwkt_yield();
640bfa86281SMatthew Dillon 		if (--count <= 0)
641bfa86281SMatthew Dillon 			break;
6422f2d9e58SVenkatesh Srinivas 		vm_object_hold(object);
6432f2d9e58SVenkatesh Srinivas 
6442f2d9e58SVenkatesh Srinivas 		/*
6452f2d9e58SVenkatesh Srinivas 		 * Only operate on live VNODE objects with regular/chardev types
6462f2d9e58SVenkatesh Srinivas 		 */
6472f2d9e58SVenkatesh Srinivas 		if ((object->type != OBJT_VNODE) ||
6482f2d9e58SVenkatesh Srinivas 		    ((object->flags & OBJ_DEAD) || object->swblock_count == 0) ||
6492f2d9e58SVenkatesh Srinivas 		    ((vp = object->handle) == NULL) ||
6502f2d9e58SVenkatesh Srinivas 		    (vp->v_type != VREG && vp->v_type != VCHR)) {
6512f2d9e58SVenkatesh Srinivas 			vm_object_drop(object);
65200a3fdcaSMatthew Dillon 			continue;
6532f2d9e58SVenkatesh Srinivas 		}
65400a3fdcaSMatthew Dillon 
65500a3fdcaSMatthew Dillon 		/*
65600a3fdcaSMatthew Dillon 		 * Adjust iterator.
65700a3fdcaSMatthew Dillon 		 */
65800a3fdcaSMatthew Dillon 		if (marker->backing_object != object)
65900a3fdcaSMatthew Dillon 			marker->size = 0;
66000a3fdcaSMatthew Dillon 
66100a3fdcaSMatthew Dillon 		/*
66200a3fdcaSMatthew Dillon 		 * Move the marker so we can work on the VM object
66300a3fdcaSMatthew Dillon 		 */
66400a3fdcaSMatthew Dillon 		TAILQ_REMOVE(&vm_object_list, marker, object_list);
66500a3fdcaSMatthew Dillon 		TAILQ_INSERT_AFTER(&vm_object_list, object,
66600a3fdcaSMatthew Dillon 				   marker, object_list);
66700a3fdcaSMatthew Dillon 
66800a3fdcaSMatthew Dillon 		/*
66900a3fdcaSMatthew Dillon 		 * Look for swblocks starting at our iterator.
67000a3fdcaSMatthew Dillon 		 *
67100a3fdcaSMatthew Dillon 		 * The swap_pager_condfree() function attempts to free
67200a3fdcaSMatthew Dillon 		 * swap space starting at the specified index.  The index
67300a3fdcaSMatthew Dillon 		 * will be updated on return.  The function will return
67400a3fdcaSMatthew Dillon 		 * a scan factor (NOT the number of blocks freed).
67500a3fdcaSMatthew Dillon 		 *
67600a3fdcaSMatthew Dillon 		 * If it must cut its scan of the object short due to an
67700a3fdcaSMatthew Dillon 		 * excessive number of swblocks, or is able to free the
67800a3fdcaSMatthew Dillon 		 * requested number of blocks, it will return n >= count
67900a3fdcaSMatthew Dillon 		 * and we break and pick it back up on a future attempt.
68000a3fdcaSMatthew Dillon 		 */
681*27b6ee03SMatthew Dillon 		vm_object_lock_swap();
68208fb7a9dSMatthew Dillon 		lwkt_reltoken(&vmobj_token);
683*27b6ee03SMatthew Dillon 
68400a3fdcaSMatthew Dillon 		n = swap_pager_condfree(object, &marker->size, count);
6852f2d9e58SVenkatesh Srinivas 
6862f2d9e58SVenkatesh Srinivas 		vm_object_drop(object);
687*27b6ee03SMatthew Dillon 		lwkt_gettoken(&vmobj_token);
6882f2d9e58SVenkatesh Srinivas 
68900a3fdcaSMatthew Dillon 		count -= n;
69000a3fdcaSMatthew Dillon 		if (count < 0)
69100a3fdcaSMatthew Dillon 			break;
69200a3fdcaSMatthew Dillon 
69300a3fdcaSMatthew Dillon 		/*
69400a3fdcaSMatthew Dillon 		 * Setup for loop.
69500a3fdcaSMatthew Dillon 		 */
69600a3fdcaSMatthew Dillon 		marker->size = 0;
69700a3fdcaSMatthew Dillon 		object = marker;
69800a3fdcaSMatthew Dillon 	}
69900a3fdcaSMatthew Dillon 
70000a3fdcaSMatthew Dillon 	/*
70100a3fdcaSMatthew Dillon 	 * Adjust marker so we continue the scan from where we left off.
70200a3fdcaSMatthew Dillon 	 * When we reach the end we start back at the beginning.
70300a3fdcaSMatthew Dillon 	 */
70400a3fdcaSMatthew Dillon 	TAILQ_REMOVE(&vm_object_list, marker, object_list);
70500a3fdcaSMatthew Dillon 	if (object)
70600a3fdcaSMatthew Dillon 		TAILQ_INSERT_BEFORE(object, marker, object_list);
70700a3fdcaSMatthew Dillon 	else
70800a3fdcaSMatthew Dillon 		TAILQ_INSERT_HEAD(&vm_object_list, marker, object_list);
70900a3fdcaSMatthew Dillon 	marker->backing_object = object;
7102de4f77eSMatthew Dillon 
7112de4f77eSMatthew Dillon 	lwkt_reltoken(&vmobj_token);
71200a3fdcaSMatthew Dillon }
713