xref: /freebsd/sys/vm/swap_pager.c (revision 2b0d37a4f81e2a22a623f7167619422a975fc5a6)
1df8bae1dSRodney W. Grimes /*
21c7c3c6aSMatthew Dillon  * Copyright (c) 1998 Matthew Dillon,
326f9a767SRodney W. Grimes  * Copyright (c) 1994 John S. Dyson
4df8bae1dSRodney W. Grimes  * Copyright (c) 1990 University of Utah.
5df8bae1dSRodney W. Grimes  * Copyright (c) 1991, 1993
6df8bae1dSRodney W. Grimes  *	The Regents of the University of California.  All rights reserved.
7df8bae1dSRodney W. Grimes  *
8df8bae1dSRodney W. Grimes  * This code is derived from software contributed to Berkeley by
9df8bae1dSRodney W. Grimes  * the Systems Programming Group of the University of Utah Computer
10df8bae1dSRodney W. Grimes  * Science Department.
11df8bae1dSRodney W. Grimes  *
12df8bae1dSRodney W. Grimes  * Redistribution and use in source and binary forms, with or without
13df8bae1dSRodney W. Grimes  * modification, are permitted provided that the following conditions
14df8bae1dSRodney W. Grimes  * are met:
15df8bae1dSRodney W. Grimes  * 1. Redistributions of source code must retain the above copyright
16df8bae1dSRodney W. Grimes  *    notice, this list of conditions and the following disclaimer.
17df8bae1dSRodney W. Grimes  * 2. Redistributions in binary form must reproduce the above copyright
18df8bae1dSRodney W. Grimes  *    notice, this list of conditions and the following disclaimer in the
19df8bae1dSRodney W. Grimes  *    documentation and/or other materials provided with the distribution.
20df8bae1dSRodney W. Grimes  * 3. All advertising materials mentioning features or use of this software
21df8bae1dSRodney W. Grimes  *    must display the following acknowledgement:
22df8bae1dSRodney W. Grimes  *	This product includes software developed by the University of
23df8bae1dSRodney W. Grimes  *	California, Berkeley and its contributors.
24df8bae1dSRodney W. Grimes  * 4. Neither the name of the University nor the names of its contributors
25df8bae1dSRodney W. Grimes  *    may be used to endorse or promote products derived from this software
26df8bae1dSRodney W. Grimes  *    without specific prior written permission.
27df8bae1dSRodney W. Grimes  *
28df8bae1dSRodney W. Grimes  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
29df8bae1dSRodney W. Grimes  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
30df8bae1dSRodney W. Grimes  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
31df8bae1dSRodney W. Grimes  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
32df8bae1dSRodney W. Grimes  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
33df8bae1dSRodney W. Grimes  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
34df8bae1dSRodney W. Grimes  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
35df8bae1dSRodney W. Grimes  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
36df8bae1dSRodney W. Grimes  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
37df8bae1dSRodney W. Grimes  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
38df8bae1dSRodney W. Grimes  * SUCH DAMAGE.
39df8bae1dSRodney W. Grimes  *
401c7c3c6aSMatthew Dillon  *				New Swap System
411c7c3c6aSMatthew Dillon  *				Matthew Dillon
421c7c3c6aSMatthew Dillon  *
431c7c3c6aSMatthew Dillon  * Radix Bitmap 'blists'.
441c7c3c6aSMatthew Dillon  *
451c7c3c6aSMatthew Dillon  *	- The new swapper uses the new radix bitmap code.  This should scale
461c7c3c6aSMatthew Dillon  *	  to arbitrarily small or arbitrarily large swap spaces and an almost
471c7c3c6aSMatthew Dillon  *	  arbitrary degree of fragmentation.
481c7c3c6aSMatthew Dillon  *
491c7c3c6aSMatthew Dillon  * Features:
501c7c3c6aSMatthew Dillon  *
511c7c3c6aSMatthew Dillon  *	- on the fly reallocation of swap during putpages.  The new system
521c7c3c6aSMatthew Dillon  *	  does not try to keep previously allocated swap blocks for dirty
531c7c3c6aSMatthew Dillon  *	  pages.
541c7c3c6aSMatthew Dillon  *
551c7c3c6aSMatthew Dillon  *	- on the fly deallocation of swap
561c7c3c6aSMatthew Dillon  *
571c7c3c6aSMatthew Dillon  *	- No more garbage collection required.  Unnecessarily allocated swap
581c7c3c6aSMatthew Dillon  *	  blocks only exist for dirty vm_page_t's now and these are already
591c7c3c6aSMatthew Dillon  *	  cycled (in a high-load system) by the pager.  We also do on-the-fly
601c7c3c6aSMatthew Dillon  *	  removal of invalidated swap blocks when a page is destroyed
611c7c3c6aSMatthew Dillon  *	  or renamed.
621c7c3c6aSMatthew Dillon  *
63df8bae1dSRodney W. Grimes  * from: Utah $Hdr: swap_pager.c 1.4 91/04/30$
64df8bae1dSRodney W. Grimes  *
65df8bae1dSRodney W. Grimes  *	@(#)swap_pager.c	8.9 (Berkeley) 3/21/94
661c7c3c6aSMatthew Dillon  *
672b0d37a4SMatthew Dillon  * $Id: swap_pager.c,v 1.112 1999/01/27 18:19:52 dillon Exp $
68df8bae1dSRodney W. Grimes  */
69df8bae1dSRodney W. Grimes 
70df8bae1dSRodney W. Grimes #include <sys/param.h>
71df8bae1dSRodney W. Grimes #include <sys/systm.h>
7264abb5a5SDavid Greenman #include <sys/kernel.h>
73df8bae1dSRodney W. Grimes #include <sys/proc.h>
74df8bae1dSRodney W. Grimes #include <sys/buf.h>
75df8bae1dSRodney W. Grimes #include <sys/vnode.h>
76df8bae1dSRodney W. Grimes #include <sys/malloc.h>
77efeaf95aSDavid Greenman #include <sys/vmmeter.h>
781c7c3c6aSMatthew Dillon #include <sys/blist.h>
791c7c3c6aSMatthew Dillon #include <sys/lock.h>
80df8bae1dSRodney W. Grimes 
81e47ed70bSJohn Dyson #ifndef MAX_PAGEOUT_CLUSTER
82ffc82b0aSJohn Dyson #define MAX_PAGEOUT_CLUSTER 16
83e47ed70bSJohn Dyson #endif
84e47ed70bSJohn Dyson 
85e47ed70bSJohn Dyson #define SWB_NPAGES	MAX_PAGEOUT_CLUSTER
86e47ed70bSJohn Dyson 
871c7c3c6aSMatthew Dillon #include "opt_swap.h"
88df8bae1dSRodney W. Grimes #include <vm/vm.h>
89efeaf95aSDavid Greenman #include <vm/vm_prot.h>
90efeaf95aSDavid Greenman #include <vm/vm_object.h>
91df8bae1dSRodney W. Grimes #include <vm/vm_page.h>
92efeaf95aSDavid Greenman #include <vm/vm_pager.h>
93df8bae1dSRodney W. Grimes #include <vm/vm_pageout.h>
94df8bae1dSRodney W. Grimes #include <vm/swap_pager.h>
95efeaf95aSDavid Greenman #include <vm/vm_extern.h>
961c7c3c6aSMatthew Dillon #include <vm/vm_zone.h>
97df8bae1dSRodney W. Grimes 
981c7c3c6aSMatthew Dillon #define SWM_FREE	0x02	/* free, period			*/
991c7c3c6aSMatthew Dillon #define SWM_POP		0x04	/* pop out			*/
10026f9a767SRodney W. Grimes 
10124a1cce3SDavid Greenman /*
1021c7c3c6aSMatthew Dillon  * vm_swap_size is in page-sized chunks now.  It was DEV_BSIZE'd chunks
1031c7c3c6aSMatthew Dillon  * in the old system.
10424a1cce3SDavid Greenman  */
1051c7c3c6aSMatthew Dillon 
1061c7c3c6aSMatthew Dillon extern int vm_swap_size;	/* number of free swap blocks, in pages */
1071c7c3c6aSMatthew Dillon 
1081c7c3c6aSMatthew Dillon int swap_pager_full;		/* swap space exhaustion (w/ hysteresis)*/
1091c7c3c6aSMatthew Dillon static int nsw_rcount;		/* free read buffers			*/
1101c7c3c6aSMatthew Dillon static int nsw_wcount;		/* free write buffers			*/
1111c7c3c6aSMatthew Dillon static int nsw_hysteresis;	/* hysteresis				*/
1121c7c3c6aSMatthew Dillon static int max_pageout_cluster;	/* maximum VOP I/O allowed		*/
1131c7c3c6aSMatthew Dillon static int sw_alloc_interlock;	/* swap pager allocation interlock	*/
1141c7c3c6aSMatthew Dillon 
1151c7c3c6aSMatthew Dillon struct blist *swapblist;
1161c7c3c6aSMatthew Dillon static struct swblock **swhash;
1171c7c3c6aSMatthew Dillon static int swhash_mask;
1181c7c3c6aSMatthew Dillon 
1191c7c3c6aSMatthew Dillon 
1201c7c3c6aSMatthew Dillon /*
1211c7c3c6aSMatthew Dillon  * "named" and "unnamed" anon region objects.  Try to reduce the overhead
1221c7c3c6aSMatthew Dillon  * of searching a named list by hashing it just a little.
1231c7c3c6aSMatthew Dillon  */
1241c7c3c6aSMatthew Dillon 
1251c7c3c6aSMatthew Dillon #define NOBJLISTS		8
1261c7c3c6aSMatthew Dillon 
1271c7c3c6aSMatthew Dillon #define NOBJLIST(handle)	\
1281c7c3c6aSMatthew Dillon 	(&swap_pager_object_list[((int)(long)handle >> 4) & (NOBJLISTS-1)])
1291c7c3c6aSMatthew Dillon 
1301c7c3c6aSMatthew Dillon static struct pagerlst	swap_pager_object_list[NOBJLISTS];
1311c7c3c6aSMatthew Dillon struct pagerlst		swap_pager_un_object_list;
1321c7c3c6aSMatthew Dillon vm_zone_t		swap_zone;
1331c7c3c6aSMatthew Dillon 
1341c7c3c6aSMatthew Dillon /*
1351c7c3c6aSMatthew Dillon  * pagerops for OBJT_SWAP - "swap pager".  Some ops are also global procedure
1361c7c3c6aSMatthew Dillon  * calls hooked from other parts of the VM system and do not appear here.
1371c7c3c6aSMatthew Dillon  * (see vm/swap_pager.h).
1381c7c3c6aSMatthew Dillon  */
1391c7c3c6aSMatthew Dillon 
140ff98689dSBruce Evans static vm_object_t
1416cde7a16SDavid Greenman 		swap_pager_alloc __P((void *handle, vm_ooffset_t size,
142a316d390SJohn Dyson 				      vm_prot_t prot, vm_ooffset_t offset));
143ff98689dSBruce Evans static void	swap_pager_dealloc __P((vm_object_t object));
144f708ef1bSPoul-Henning Kamp static int	swap_pager_getpages __P((vm_object_t, vm_page_t *, int, int));
145ff98689dSBruce Evans static void	swap_pager_init __P((void));
1461c7c3c6aSMatthew Dillon static void	swap_pager_unswapped __P((vm_page_t));
147f708ef1bSPoul-Henning Kamp 
148df8bae1dSRodney W. Grimes struct pagerops swappagerops = {
1491c7c3c6aSMatthew Dillon 	swap_pager_init,	/* early system initialization of pager	*/
1501c7c3c6aSMatthew Dillon 	swap_pager_alloc,	/* allocate an OBJT_SWAP object		*/
1511c7c3c6aSMatthew Dillon 	swap_pager_dealloc,	/* deallocate an OBJT_SWAP object	*/
1521c7c3c6aSMatthew Dillon 	swap_pager_getpages,	/* pagein				*/
1531c7c3c6aSMatthew Dillon 	swap_pager_putpages,	/* pageout				*/
1541c7c3c6aSMatthew Dillon 	swap_pager_haspage,	/* get backing store status for page	*/
1551c7c3c6aSMatthew Dillon 	swap_pager_unswapped	/* remove swap related to page		*/
156df8bae1dSRodney W. Grimes };
157df8bae1dSRodney W. Grimes 
1581c7c3c6aSMatthew Dillon /*
1591c7c3c6aSMatthew Dillon  * dmmax is in page-sized chunks with the new swap system.  It was
1601c7c3c6aSMatthew Dillon  * dev-bsized chunks in the old.
1611c7c3c6aSMatthew Dillon  *
1621c7c3c6aSMatthew Dillon  * swap_*() routines are externally accessible.  swp_*() routines are
1631c7c3c6aSMatthew Dillon  * internal.
1641c7c3c6aSMatthew Dillon  */
1651c7c3c6aSMatthew Dillon 
166f708ef1bSPoul-Henning Kamp int dmmax;
1671c7c3c6aSMatthew Dillon static int dmmax_mask;
1681c7c3c6aSMatthew Dillon int nswap_lowat = 128;		/* in pages, swap_pager_full warning	*/
1692b0d37a4SMatthew Dillon int nswap_hiwat = 512;		/* in pages, swap_pager_full warning	*/
17026f9a767SRodney W. Grimes 
1711c7c3c6aSMatthew Dillon static __inline void	swp_sizecheck __P((void));
1721c7c3c6aSMatthew Dillon static void	swp_pager_sync_iodone __P((struct buf *bp));
1731c7c3c6aSMatthew Dillon static void	swp_pager_async_iodone __P((struct buf *bp));
17424a1cce3SDavid Greenman 
1751c7c3c6aSMatthew Dillon /*
1761c7c3c6aSMatthew Dillon  * Swap bitmap functions
1771c7c3c6aSMatthew Dillon  */
1781c7c3c6aSMatthew Dillon 
1791c7c3c6aSMatthew Dillon static __inline void	swp_pager_freeswapspace __P((daddr_t blk, int npages));
1801c7c3c6aSMatthew Dillon static __inline daddr_t	swp_pager_getswapspace __P((int npages));
1811c7c3c6aSMatthew Dillon 
1821c7c3c6aSMatthew Dillon /*
1831c7c3c6aSMatthew Dillon  * Metadata functions
1841c7c3c6aSMatthew Dillon  */
1851c7c3c6aSMatthew Dillon 
1861c7c3c6aSMatthew Dillon static void swp_pager_meta_build __P((vm_object_t, daddr_t, daddr_t, int));
1871c7c3c6aSMatthew Dillon static void swp_pager_meta_free __P((vm_object_t, daddr_t, daddr_t));
1881c7c3c6aSMatthew Dillon static void swp_pager_meta_free_all __P((vm_object_t));
1891c7c3c6aSMatthew Dillon static daddr_t swp_pager_meta_ctl __P((vm_object_t, vm_pindex_t, int));
1901c7c3c6aSMatthew Dillon 
1911c7c3c6aSMatthew Dillon /*
1921c7c3c6aSMatthew Dillon  * SWP_SIZECHECK() -	update swap_pager_full indication
1931c7c3c6aSMatthew Dillon  *
1941c7c3c6aSMatthew Dillon  *	update the swap_pager_full indication and warn when we are
1951c7c3c6aSMatthew Dillon  *	about to run out of swap space.
1961c7c3c6aSMatthew Dillon  *
1971c7c3c6aSMatthew Dillon  *	No restrictions on call
1981c7c3c6aSMatthew Dillon  *	This routine may not block.
1991c7c3c6aSMatthew Dillon  *	This routine must be called at splvm()
2001c7c3c6aSMatthew Dillon  */
201de5f6a77SJohn Dyson 
202c1087c13SBruce Evans static __inline void
2031c7c3c6aSMatthew Dillon swp_sizecheck()
2040d94caffSDavid Greenman {
2051c7c3c6aSMatthew Dillon 	if (vm_swap_size < nswap_lowat) {
2062b0d37a4SMatthew Dillon 		if (swap_pager_full == 0) {
2071af87c92SDavid Greenman 			printf("swap_pager: out of swap space\n");
20826f9a767SRodney W. Grimes 			swap_pager_full = 1;
2092b0d37a4SMatthew Dillon 		}
2101c7c3c6aSMatthew Dillon 	} else if (vm_swap_size > nswap_hiwat) {
21126f9a767SRodney W. Grimes 		swap_pager_full = 0;
21226f9a767SRodney W. Grimes 	}
2131c7c3c6aSMatthew Dillon }
2141c7c3c6aSMatthew Dillon 
2151c7c3c6aSMatthew Dillon /*
2161c7c3c6aSMatthew Dillon  * SWAP_PAGER_INIT() -	initialize the swap pager!
2171c7c3c6aSMatthew Dillon  *
2181c7c3c6aSMatthew Dillon  *	Expected to be started from system init.  NOTE:  This code is run
2191c7c3c6aSMatthew Dillon  *	before much else so be careful what you depend on.  Most of the VM
2201c7c3c6aSMatthew Dillon  *	system has yet to be initialized at this point.
2211c7c3c6aSMatthew Dillon  */
22226f9a767SRodney W. Grimes 
223f5a12711SPoul-Henning Kamp static void
224df8bae1dSRodney W. Grimes swap_pager_init()
225df8bae1dSRodney W. Grimes {
2261c7c3c6aSMatthew Dillon 	/*
2271c7c3c6aSMatthew Dillon 	 * Initialize object lists
2281c7c3c6aSMatthew Dillon 	 */
2291c7c3c6aSMatthew Dillon 	int i;
2301c7c3c6aSMatthew Dillon 
2311c7c3c6aSMatthew Dillon 	for (i = 0; i < NOBJLISTS; ++i)
2321c7c3c6aSMatthew Dillon 		TAILQ_INIT(&swap_pager_object_list[i]);
23324a1cce3SDavid Greenman 	TAILQ_INIT(&swap_pager_un_object_list);
234df8bae1dSRodney W. Grimes 
235df8bae1dSRodney W. Grimes 	/*
2361c7c3c6aSMatthew Dillon 	 * Device Stripe, in PAGE_SIZE'd blocks
237df8bae1dSRodney W. Grimes 	 */
2381c7c3c6aSMatthew Dillon 
2391c7c3c6aSMatthew Dillon 	dmmax = SWB_NPAGES * 2;
2401c7c3c6aSMatthew Dillon 	dmmax_mask = ~(dmmax - 1);
2411c7c3c6aSMatthew Dillon }
24226f9a767SRodney W. Grimes 
243df8bae1dSRodney W. Grimes /*
2441c7c3c6aSMatthew Dillon  * SWAP_PAGER_SWAP_INIT() - swap pager initialization from pageout process
2451c7c3c6aSMatthew Dillon  *
2461c7c3c6aSMatthew Dillon  *	Expected to be started from pageout process once, prior to entering
2471c7c3c6aSMatthew Dillon  *	its main loop.
248df8bae1dSRodney W. Grimes  */
249df8bae1dSRodney W. Grimes 
25024a1cce3SDavid Greenman void
25124a1cce3SDavid Greenman swap_pager_swap_init()
252df8bae1dSRodney W. Grimes {
2531c7c3c6aSMatthew Dillon 	int n;
2540d94caffSDavid Greenman 
25526f9a767SRodney W. Grimes 	/*
2561c7c3c6aSMatthew Dillon 	 * Number of in-transit swap bp operations.  Don't
2571c7c3c6aSMatthew Dillon 	 * exhaust the pbufs completely.  Make sure we
2581c7c3c6aSMatthew Dillon 	 * initialize workable values (0 will work for hysteresis
2591c7c3c6aSMatthew Dillon 	 * but it isn't very efficient).
2601c7c3c6aSMatthew Dillon 	 *
2611c7c3c6aSMatthew Dillon 	 * The max_pageout_cluster is constrained by the bp->b_pages[]
2621c7c3c6aSMatthew Dillon 	 * array (MAXPHYS/PAGE_SIZE) and our locally defined
2631c7c3c6aSMatthew Dillon 	 * MAX_PAGEOUT_CLUSTER.   Also be aware that swap ops are
2641c7c3c6aSMatthew Dillon 	 * constrained by the swap device interleave stripe size.
26526f9a767SRodney W. Grimes 	 */
26624a1cce3SDavid Greenman 
2671c7c3c6aSMatthew Dillon 	nsw_rcount = (nswbuf + 1) / 2;
2681c7c3c6aSMatthew Dillon 	nsw_wcount = (nswbuf + 3) / 4;
2691c7c3c6aSMatthew Dillon 	nsw_hysteresis = nsw_wcount / 2;
2701c7c3c6aSMatthew Dillon 	max_pageout_cluster = min((MAXPHYS/PAGE_SIZE), MAX_PAGEOUT_CLUSTER);
27124a1cce3SDavid Greenman 
2721c7c3c6aSMatthew Dillon 	/*
2731c7c3c6aSMatthew Dillon 	 * Initialize our zone.  Right now I'm just guessing on the number
2741c7c3c6aSMatthew Dillon 	 * we need based on the number of pages in the system.  Each swblock
2751c7c3c6aSMatthew Dillon 	 * can hold 16 pages, so this is probably overkill.
2761c7c3c6aSMatthew Dillon 	 */
27724a1cce3SDavid Greenman 
2781c7c3c6aSMatthew Dillon 	n = cnt.v_page_count * 2;
27926f9a767SRodney W. Grimes 
2801c7c3c6aSMatthew Dillon 	swap_zone = zinit(
2811c7c3c6aSMatthew Dillon 	    "SWAPMETA",
2821c7c3c6aSMatthew Dillon 	    sizeof(struct swblock),
2831c7c3c6aSMatthew Dillon 	    n,
2841c7c3c6aSMatthew Dillon 	    ZONE_INTERRUPT,
2851c7c3c6aSMatthew Dillon 	    1
2861c7c3c6aSMatthew Dillon 	);
28724a1cce3SDavid Greenman 
2881c7c3c6aSMatthew Dillon 	/*
2891c7c3c6aSMatthew Dillon 	 * Initialize our meta-data hash table.  The swapper does not need to
2901c7c3c6aSMatthew Dillon 	 * be quite as efficient as the VM system, so we do not use an
2911c7c3c6aSMatthew Dillon 	 * oversized hash table.
2921c7c3c6aSMatthew Dillon 	 *
2931c7c3c6aSMatthew Dillon 	 * 	n: 		size of hash table, must be power of 2
2941c7c3c6aSMatthew Dillon 	 *	swhash_mask:	hash table index mask
2951c7c3c6aSMatthew Dillon 	 */
296df8bae1dSRodney W. Grimes 
2971c7c3c6aSMatthew Dillon 	for (n = 1; n < cnt.v_page_count / 4; n <<= 1)
2981c7c3c6aSMatthew Dillon 		;
2991c7c3c6aSMatthew Dillon 
3001c7c3c6aSMatthew Dillon 	swhash = malloc(sizeof(struct swblock *) * n, M_VMPGDATA, M_WAITOK);
3011c7c3c6aSMatthew Dillon 	bzero(swhash, sizeof(struct swblock *) * n);
3021c7c3c6aSMatthew Dillon 
3031c7c3c6aSMatthew Dillon 	swhash_mask = n - 1;
30424a1cce3SDavid Greenman }
30524a1cce3SDavid Greenman 
30624a1cce3SDavid Greenman /*
3071c7c3c6aSMatthew Dillon  * SWAP_PAGER_ALLOC() -	allocate a new OBJT_SWAP VM object and instantiate
3081c7c3c6aSMatthew Dillon  *			its metadata structures.
3091c7c3c6aSMatthew Dillon  *
3101c7c3c6aSMatthew Dillon  *	This routine is called from the mmap and fork code to create a new
3111c7c3c6aSMatthew Dillon  *	OBJT_SWAP object.  We do this by creating an OBJT_DEFAULT object
3121c7c3c6aSMatthew Dillon  *	and then converting it with swp_pager_meta_build().
3131c7c3c6aSMatthew Dillon  *
3141c7c3c6aSMatthew Dillon  *	This routine may block in vm_object_allocate() and create a named
3151c7c3c6aSMatthew Dillon  *	object lookup race, so we must interlock.   We must also run at
3161c7c3c6aSMatthew Dillon  *	splvm() for the object lookup to handle races with interrupts, but
3171c7c3c6aSMatthew Dillon  *	we do not have to maintain splvm() in between the lookup and the
3181c7c3c6aSMatthew Dillon  *	add because (I believe) it is not possible to attempt to create
3191c7c3c6aSMatthew Dillon  *	a new swap object w/handle when a default object with that handle
3201c7c3c6aSMatthew Dillon  *	already exists.
32124a1cce3SDavid Greenman  */
3221c7c3c6aSMatthew Dillon 
323f5a12711SPoul-Henning Kamp static vm_object_t
3246cde7a16SDavid Greenman swap_pager_alloc(void *handle, vm_ooffset_t size, vm_prot_t prot,
325b9dcd593SBruce Evans 		 vm_ooffset_t offset)
32624a1cce3SDavid Greenman {
32724a1cce3SDavid Greenman 	vm_object_t object;
32824a1cce3SDavid Greenman 
32924a1cce3SDavid Greenman 	if (handle) {
3301c7c3c6aSMatthew Dillon 		/*
3311c7c3c6aSMatthew Dillon 		 * Reference existing named region or allocate new one.  There
3321c7c3c6aSMatthew Dillon 		 * should not be a race here against swp_pager_meta_build()
3331c7c3c6aSMatthew Dillon 		 * as called from vm_page_remove() in regards to the lookup
3341c7c3c6aSMatthew Dillon 		 * of the handle.
3351c7c3c6aSMatthew Dillon 		 */
3361c7c3c6aSMatthew Dillon 
3371c7c3c6aSMatthew Dillon 		while (sw_alloc_interlock) {
3381c7c3c6aSMatthew Dillon 			sw_alloc_interlock = -1;
3391c7c3c6aSMatthew Dillon 			tsleep(&sw_alloc_interlock, PVM, "swpalc", 0);
3401c7c3c6aSMatthew Dillon 		}
3411c7c3c6aSMatthew Dillon 		sw_alloc_interlock = 1;
3421c7c3c6aSMatthew Dillon 
3431c7c3c6aSMatthew Dillon 		object = vm_pager_object_lookup(NOBJLIST(handle), handle);
3441c7c3c6aSMatthew Dillon 
34524a1cce3SDavid Greenman 		if (object != NULL) {
34624a1cce3SDavid Greenman 			vm_object_reference(object);
34724a1cce3SDavid Greenman 		} else {
3481c7c3c6aSMatthew Dillon 			object = vm_object_allocate(OBJT_DEFAULT,
3496cde7a16SDavid Greenman 				OFF_TO_IDX(offset + PAGE_MASK + size));
35024a1cce3SDavid Greenman 			object->handle = handle;
3511c7c3c6aSMatthew Dillon 
3521c7c3c6aSMatthew Dillon 			swp_pager_meta_build(
3531c7c3c6aSMatthew Dillon 			    object,
3541c7c3c6aSMatthew Dillon 			    0,
3551c7c3c6aSMatthew Dillon 			    SWAPBLK_NONE,
3561c7c3c6aSMatthew Dillon 			    0
3571c7c3c6aSMatthew Dillon 			);
35824a1cce3SDavid Greenman 		}
3591c7c3c6aSMatthew Dillon 
3601c7c3c6aSMatthew Dillon 		if (sw_alloc_interlock < 0)
3611c7c3c6aSMatthew Dillon 			wakeup(&sw_alloc_interlock);
3621c7c3c6aSMatthew Dillon 
3631c7c3c6aSMatthew Dillon 		sw_alloc_interlock = 0;
36424a1cce3SDavid Greenman 	} else {
3651c7c3c6aSMatthew Dillon 		object = vm_object_allocate(OBJT_DEFAULT,
3666cde7a16SDavid Greenman 			OFF_TO_IDX(offset + PAGE_MASK + size));
3671c7c3c6aSMatthew Dillon 
3681c7c3c6aSMatthew Dillon 		swp_pager_meta_build(
3691c7c3c6aSMatthew Dillon 		    object,
3701c7c3c6aSMatthew Dillon 		    0,
3711c7c3c6aSMatthew Dillon 		    SWAPBLK_NONE,
3721c7c3c6aSMatthew Dillon 		    0
3731c7c3c6aSMatthew Dillon 		);
37424a1cce3SDavid Greenman 	}
37524a1cce3SDavid Greenman 
37624a1cce3SDavid Greenman 	return (object);
377df8bae1dSRodney W. Grimes }
378df8bae1dSRodney W. Grimes 
37926f9a767SRodney W. Grimes /*
3801c7c3c6aSMatthew Dillon  * SWAP_PAGER_DEALLOC() -	remove swap metadata from object
3811c7c3c6aSMatthew Dillon  *
3821c7c3c6aSMatthew Dillon  *	The swap backing for the object is destroyed.  The code is
3831c7c3c6aSMatthew Dillon  *	designed such that we can reinstantiate it later, but this
3841c7c3c6aSMatthew Dillon  *	routine is typically called only when the entire object is
3851c7c3c6aSMatthew Dillon  *	about to be destroyed.
3861c7c3c6aSMatthew Dillon  *
3871c7c3c6aSMatthew Dillon  *	This routine may block, but no longer does.
3881c7c3c6aSMatthew Dillon  *
3891c7c3c6aSMatthew Dillon  *	The object must be locked or unreferenceable.
39026f9a767SRodney W. Grimes  */
39126f9a767SRodney W. Grimes 
392df8bae1dSRodney W. Grimes static void
3931c7c3c6aSMatthew Dillon swap_pager_dealloc(object)
3942a4895f4SDavid Greenman 	vm_object_t object;
39526f9a767SRodney W. Grimes {
39626f9a767SRodney W. Grimes 	/*
3971c7c3c6aSMatthew Dillon 	 * Remove from list right away so lookups will fail if we block for
3981c7c3c6aSMatthew Dillon 	 * pageout completion.
39926f9a767SRodney W. Grimes 	 */
400b44e4b7aSJohn Dyson 
4011c7c3c6aSMatthew Dillon 	if (object->handle == NULL) {
4021c7c3c6aSMatthew Dillon 		TAILQ_REMOVE(&swap_pager_un_object_list, object, pager_object_list);
40324ea4a96SDavid Greenman 	} else {
4041c7c3c6aSMatthew Dillon 		TAILQ_REMOVE(NOBJLIST(object->handle), object, pager_object_list);
40526f9a767SRodney W. Grimes 	}
4061c7c3c6aSMatthew Dillon 
4071c7c3c6aSMatthew Dillon 	vm_object_pip_wait(object, "swpdea");
4081c7c3c6aSMatthew Dillon 
4091c7c3c6aSMatthew Dillon 	/*
4101c7c3c6aSMatthew Dillon 	 * Free all remaining metadata.  We only bother to free it from
4111c7c3c6aSMatthew Dillon 	 * the swap meta data.  We do not attempt to free swapblk's still
4121c7c3c6aSMatthew Dillon 	 * associated with vm_page_t's for this object.  We do not care
4131c7c3c6aSMatthew Dillon 	 * if paging is still in progress on some objects.
4141c7c3c6aSMatthew Dillon 	 */
4151c7c3c6aSMatthew Dillon 
4161c7c3c6aSMatthew Dillon 	swp_pager_meta_free_all(object);
4171c7c3c6aSMatthew Dillon }
4181c7c3c6aSMatthew Dillon 
4191c7c3c6aSMatthew Dillon /************************************************************************
4201c7c3c6aSMatthew Dillon  *			SWAP PAGER BITMAP ROUTINES			*
4211c7c3c6aSMatthew Dillon  ************************************************************************/
4221c7c3c6aSMatthew Dillon 
4231c7c3c6aSMatthew Dillon /*
4241c7c3c6aSMatthew Dillon  * SWP_PAGER_GETSWAPSPACE() -	allocate raw swap space
4251c7c3c6aSMatthew Dillon  *
4261c7c3c6aSMatthew Dillon  *	Allocate swap for the requested number of pages.  The starting
4271c7c3c6aSMatthew Dillon  *	swap block number (a page index) is returned or SWAPBLK_NONE
4281c7c3c6aSMatthew Dillon  *	if the allocation failed.
4291c7c3c6aSMatthew Dillon  *
4301c7c3c6aSMatthew Dillon  *	Also has the side effect of advising that somebody made a mistake
4311c7c3c6aSMatthew Dillon  *	when they configured swap and didn't configure enough.
4321c7c3c6aSMatthew Dillon  *
4331c7c3c6aSMatthew Dillon  *	Must be called at splvm() to avoid races with bitmap frees from
4341c7c3c6aSMatthew Dillon  *	vm_page_remove() aka swap_pager_page_removed().
4351c7c3c6aSMatthew Dillon  *
4361c7c3c6aSMatthew Dillon  *	This routine may not block
4371c7c3c6aSMatthew Dillon  *	This routine must be called at splvm().
4381c7c3c6aSMatthew Dillon  */
4391c7c3c6aSMatthew Dillon 
4401c7c3c6aSMatthew Dillon static __inline daddr_t
4411c7c3c6aSMatthew Dillon swp_pager_getswapspace(npages)
4421c7c3c6aSMatthew Dillon 	int npages;
4431c7c3c6aSMatthew Dillon {
4441c7c3c6aSMatthew Dillon 	daddr_t blk;
4451c7c3c6aSMatthew Dillon 
4461c7c3c6aSMatthew Dillon 	if ((blk = blist_alloc(swapblist, npages)) == SWAPBLK_NONE) {
4472b0d37a4SMatthew Dillon 		if (swap_pager_full != 2) {
4481c7c3c6aSMatthew Dillon 			printf("swap_pager_getswapspace: failed\n");
4492b0d37a4SMatthew Dillon 			swap_pager_full = 2;
4502b0d37a4SMatthew Dillon 		}
4511c7c3c6aSMatthew Dillon 	} else {
4521c7c3c6aSMatthew Dillon 		vm_swap_size -= npages;
4531c7c3c6aSMatthew Dillon 		swp_sizecheck();
4541c7c3c6aSMatthew Dillon 	}
4551c7c3c6aSMatthew Dillon 	return(blk);
45626f9a767SRodney W. Grimes }
45726f9a767SRodney W. Grimes 
45826f9a767SRodney W. Grimes /*
4591c7c3c6aSMatthew Dillon  * SWP_PAGER_FREESWAPSPACE() -	free raw swap space
4601c7c3c6aSMatthew Dillon  *
4611c7c3c6aSMatthew Dillon  *	This routine returns the specified swap blocks back to the bitmap.
4621c7c3c6aSMatthew Dillon  *
4631c7c3c6aSMatthew Dillon  *	Note:  This routine may not block (it could in the old swap code),
4641c7c3c6aSMatthew Dillon  *	and through the use of the new blist routines it does not block.
4651c7c3c6aSMatthew Dillon  *
4661c7c3c6aSMatthew Dillon  *	We must be called at splvm() to avoid races with bitmap frees from
4671c7c3c6aSMatthew Dillon  *	vm_page_remove() aka swap_pager_page_removed().
4681c7c3c6aSMatthew Dillon  *
4691c7c3c6aSMatthew Dillon  *	This routine may not block
4701c7c3c6aSMatthew Dillon  *	This routine must be called at splvm().
47126f9a767SRodney W. Grimes  */
4721c7c3c6aSMatthew Dillon 
4731c7c3c6aSMatthew Dillon static __inline void
4741c7c3c6aSMatthew Dillon swp_pager_freeswapspace(blk, npages)
4751c7c3c6aSMatthew Dillon 	daddr_t blk;
4761c7c3c6aSMatthew Dillon 	int npages;
4770d94caffSDavid Greenman {
4781c7c3c6aSMatthew Dillon 	blist_free(swapblist, blk, npages);
4791c7c3c6aSMatthew Dillon 	vm_swap_size += npages;
4801c7c3c6aSMatthew Dillon 	swp_sizecheck();
48126f9a767SRodney W. Grimes }
4821c7c3c6aSMatthew Dillon 
48326f9a767SRodney W. Grimes /*
4841c7c3c6aSMatthew Dillon  * SWAP_PAGER_FREESPACE() -	frees swap blocks associated with a page
4851c7c3c6aSMatthew Dillon  *				range within an object.
4861c7c3c6aSMatthew Dillon  *
4871c7c3c6aSMatthew Dillon  *	This is a globally accessible routine.
4881c7c3c6aSMatthew Dillon  *
4891c7c3c6aSMatthew Dillon  *	This routine removes swapblk assignments from swap metadata.
4901c7c3c6aSMatthew Dillon  *
4911c7c3c6aSMatthew Dillon  *	The external callers of this routine typically have already destroyed
4921c7c3c6aSMatthew Dillon  *	or renamed vm_page_t's associated with this range in the object so
4931c7c3c6aSMatthew Dillon  *	we should be ok.
49426f9a767SRodney W. Grimes  */
4951c7c3c6aSMatthew Dillon 
49626f9a767SRodney W. Grimes void
49724a1cce3SDavid Greenman swap_pager_freespace(object, start, size)
49824a1cce3SDavid Greenman 	vm_object_t object;
499a316d390SJohn Dyson 	vm_pindex_t start;
500a316d390SJohn Dyson 	vm_size_t size;
50126f9a767SRodney W. Grimes {
5021c7c3c6aSMatthew Dillon 	swp_pager_meta_free(object, start, size);
50326f9a767SRodney W. Grimes }
50426f9a767SRodney W. Grimes 
5050a47b48bSJohn Dyson /*
5061c7c3c6aSMatthew Dillon  * SWAP_PAGER_COPY() -  copy blocks from source pager to destination pager
5071c7c3c6aSMatthew Dillon  *			and destroy the source.
5081c7c3c6aSMatthew Dillon  *
5091c7c3c6aSMatthew Dillon  *	Copy any valid swapblks from the source to the destination.  In
5101c7c3c6aSMatthew Dillon  *	cases where both the source and destination have a valid swapblk,
5111c7c3c6aSMatthew Dillon  *	we keep the destination's.
5121c7c3c6aSMatthew Dillon  *
5131c7c3c6aSMatthew Dillon  *	This routine is allowed to block.  It may block allocating metadata
5141c7c3c6aSMatthew Dillon  *	indirectly through swp_pager_meta_build() or if paging is still in
5151c7c3c6aSMatthew Dillon  *	progress on the source.
5161c7c3c6aSMatthew Dillon  *
5171c7c3c6aSMatthew Dillon  *	XXX vm_page_collapse() kinda expects us not to block because we
5181c7c3c6aSMatthew Dillon  *	supposedly do not need to allocate memory, but for the moment we
5191c7c3c6aSMatthew Dillon  *	*may* have to get a little memory from the zone allocator, but
5201c7c3c6aSMatthew Dillon  *	it is taken from the interrupt memory.  We should be ok.
5211c7c3c6aSMatthew Dillon  *
5221c7c3c6aSMatthew Dillon  *	The source object contains no vm_page_t's (which is just as well)
5231c7c3c6aSMatthew Dillon  *
5241c7c3c6aSMatthew Dillon  *	The source object is of type OBJT_SWAP.
5251c7c3c6aSMatthew Dillon  *
5261c7c3c6aSMatthew Dillon  *	The source and destination objects must be
5275e24f1a2SMatthew Dillon  *	locked or inaccessible (XXX are they ?)
52826f9a767SRodney W. Grimes  */
52926f9a767SRodney W. Grimes 
53026f9a767SRodney W. Grimes void
5311c7c3c6aSMatthew Dillon swap_pager_copy(srcobject, dstobject, offset, destroysource)
53224a1cce3SDavid Greenman 	vm_object_t srcobject;
53324a1cce3SDavid Greenman 	vm_object_t dstobject;
534a316d390SJohn Dyson 	vm_pindex_t offset;
535c0877f10SJohn Dyson 	int destroysource;
53626f9a767SRodney W. Grimes {
537a316d390SJohn Dyson 	vm_pindex_t i;
53826f9a767SRodney W. Grimes 
53926f9a767SRodney W. Grimes 	/*
5401c7c3c6aSMatthew Dillon 	 * If destroysource is set, we remove the source object from the
5411c7c3c6aSMatthew Dillon 	 * swap_pager internal queue now.
54226f9a767SRodney W. Grimes 	 */
5431c7c3c6aSMatthew Dillon 
544cbd8ec09SJohn Dyson 	if (destroysource) {
54524a1cce3SDavid Greenman 		if (srcobject->handle == NULL) {
5461c7c3c6aSMatthew Dillon 			TAILQ_REMOVE(
5471c7c3c6aSMatthew Dillon 			    &swap_pager_un_object_list,
5481c7c3c6aSMatthew Dillon 			    srcobject,
5491c7c3c6aSMatthew Dillon 			    pager_object_list
5501c7c3c6aSMatthew Dillon 			);
55126f9a767SRodney W. Grimes 		} else {
5521c7c3c6aSMatthew Dillon 			TAILQ_REMOVE(
5531c7c3c6aSMatthew Dillon 			    NOBJLIST(srcobject->handle),
5541c7c3c6aSMatthew Dillon 			    srcobject,
5551c7c3c6aSMatthew Dillon 			    pager_object_list
5561c7c3c6aSMatthew Dillon 			);
55726f9a767SRodney W. Grimes 		}
558cbd8ec09SJohn Dyson 	}
55926f9a767SRodney W. Grimes 
5601c7c3c6aSMatthew Dillon 	/*
5611c7c3c6aSMatthew Dillon 	 * transfer source to destination.
5621c7c3c6aSMatthew Dillon 	 */
5631c7c3c6aSMatthew Dillon 
5641c7c3c6aSMatthew Dillon 	for (i = 0; i < dstobject->size; ++i) {
5651c7c3c6aSMatthew Dillon 		daddr_t dstaddr;
5661c7c3c6aSMatthew Dillon 
5671c7c3c6aSMatthew Dillon 		/*
5681c7c3c6aSMatthew Dillon 		 * Locate (without changing) the swapblk on the destination,
5691c7c3c6aSMatthew Dillon 		 * unless it is invalid in which case free it silently, or
5701c7c3c6aSMatthew Dillon 		 * if the destination is a resident page, in which case the
5711c7c3c6aSMatthew Dillon 		 * source is thrown away.
5721c7c3c6aSMatthew Dillon 		 */
5731c7c3c6aSMatthew Dillon 
5741c7c3c6aSMatthew Dillon 		dstaddr = swp_pager_meta_ctl(dstobject, i, 0);
5751c7c3c6aSMatthew Dillon 
5761c7c3c6aSMatthew Dillon 		if (dstaddr == SWAPBLK_NONE) {
5771c7c3c6aSMatthew Dillon 			/*
5781c7c3c6aSMatthew Dillon 			 * Destination has no swapblk and is not resident,
5791c7c3c6aSMatthew Dillon 			 * copy source.
5801c7c3c6aSMatthew Dillon 			 */
5811c7c3c6aSMatthew Dillon 			daddr_t srcaddr;
5821c7c3c6aSMatthew Dillon 
5831c7c3c6aSMatthew Dillon 			srcaddr = swp_pager_meta_ctl(
5841c7c3c6aSMatthew Dillon 			    srcobject,
5851c7c3c6aSMatthew Dillon 			    i + offset,
5861c7c3c6aSMatthew Dillon 			    SWM_POP
5871c7c3c6aSMatthew Dillon 			);
5881c7c3c6aSMatthew Dillon 
5891c7c3c6aSMatthew Dillon 			if (srcaddr != SWAPBLK_NONE)
5901c7c3c6aSMatthew Dillon 				swp_pager_meta_build(dstobject, i, srcaddr, 1);
5911c7c3c6aSMatthew Dillon 		} else {
5921c7c3c6aSMatthew Dillon 			/*
5931c7c3c6aSMatthew Dillon 			 * Destination has valid swapblk or it is represented
5941c7c3c6aSMatthew Dillon 			 * by a resident page.  We destroy the sourceblock.
5951c7c3c6aSMatthew Dillon 			 */
5961c7c3c6aSMatthew Dillon 
5971c7c3c6aSMatthew Dillon 			swp_pager_meta_ctl(srcobject, i + offset, SWM_FREE);
5981c7c3c6aSMatthew Dillon 		}
59926f9a767SRodney W. Grimes 	}
60026f9a767SRodney W. Grimes 
60126f9a767SRodney W. Grimes 	/*
6021c7c3c6aSMatthew Dillon 	 * Free left over swap blocks in source.
6031c7c3c6aSMatthew Dillon 	 *
6041c7c3c6aSMatthew Dillon 	 * We have to revert the type to OBJT_DEFAULT so we do not accidently
6051c7c3c6aSMatthew Dillon 	 * double-remove the object from the swap queues.
60626f9a767SRodney W. Grimes 	 */
60726f9a767SRodney W. Grimes 
608c0877f10SJohn Dyson 	if (destroysource) {
6091c7c3c6aSMatthew Dillon 		swp_pager_meta_free_all(srcobject);
6101c7c3c6aSMatthew Dillon 		/*
6111c7c3c6aSMatthew Dillon 		 * Reverting the type is not necessary, the caller is going
6121c7c3c6aSMatthew Dillon 		 * to destroy srcobject directly, but I'm doing it here
6131c7c3c6aSMatthew Dillon 		 * for consistancy since we've removed the object from its
6141c7c3c6aSMatthew Dillon 		 * queues.
6151c7c3c6aSMatthew Dillon 		 */
6161c7c3c6aSMatthew Dillon 		srcobject->type = OBJT_DEFAULT;
617c0877f10SJohn Dyson 	}
61826f9a767SRodney W. Grimes 	return;
61926f9a767SRodney W. Grimes }
62026f9a767SRodney W. Grimes 
621df8bae1dSRodney W. Grimes /*
6221c7c3c6aSMatthew Dillon  * SWAP_PAGER_HASPAGE() -	determine if we have good backing store for
6231c7c3c6aSMatthew Dillon  *				the requested page.
6241c7c3c6aSMatthew Dillon  *
6251c7c3c6aSMatthew Dillon  *	We determine whether good backing store exists for the requested
6261c7c3c6aSMatthew Dillon  *	page and return TRUE if it does, FALSE if it doesn't.
6271c7c3c6aSMatthew Dillon  *
6281c7c3c6aSMatthew Dillon  *	If TRUE, we also try to determine how much valid, contiguous backing
6291c7c3c6aSMatthew Dillon  *	store exists before and after the requested page within a reasonable
6301c7c3c6aSMatthew Dillon  *	distance.  We do not try to restrict it to the swap device stripe
6311c7c3c6aSMatthew Dillon  *	(that is handled in getpages/putpages).  It probably isn't worth
6321c7c3c6aSMatthew Dillon  *	doing here.
633df8bae1dSRodney W. Grimes  */
63426f9a767SRodney W. Grimes 
6351c7c3c6aSMatthew Dillon boolean_t
636a316d390SJohn Dyson swap_pager_haspage(object, pindex, before, after)
63724a1cce3SDavid Greenman 	vm_object_t object;
638a316d390SJohn Dyson 	vm_pindex_t pindex;
63924a1cce3SDavid Greenman 	int *before;
64024a1cce3SDavid Greenman 	int *after;
64126f9a767SRodney W. Grimes {
6421c7c3c6aSMatthew Dillon 	daddr_t blk0;
64326f9a767SRodney W. Grimes 
6441c7c3c6aSMatthew Dillon 	/*
6451c7c3c6aSMatthew Dillon 	 * do we have good backing store at the requested index ?
6461c7c3c6aSMatthew Dillon 	 */
6471c7c3c6aSMatthew Dillon 
6481c7c3c6aSMatthew Dillon 	blk0 = swp_pager_meta_ctl(object, pindex, 0);
6491c7c3c6aSMatthew Dillon 
6501c7c3c6aSMatthew Dillon 	if (blk0 & SWAPBLK_NONE) {
6511c7c3c6aSMatthew Dillon 		if (before)
65224a1cce3SDavid Greenman 			*before = 0;
6531c7c3c6aSMatthew Dillon 		if (after)
65424a1cce3SDavid Greenman 			*after = 0;
65526f9a767SRodney W. Grimes 		return (FALSE);
65626f9a767SRodney W. Grimes 	}
65726f9a767SRodney W. Grimes 
65826f9a767SRodney W. Grimes 	/*
6591c7c3c6aSMatthew Dillon 	 * find backwards-looking contiguous good backing store
660e47ed70bSJohn Dyson 	 */
661e47ed70bSJohn Dyson 
6621c7c3c6aSMatthew Dillon 	if (before != NULL) {
66326f9a767SRodney W. Grimes 		int i;
6640d94caffSDavid Greenman 
6651c7c3c6aSMatthew Dillon 		for (i = 1; i < (SWB_NPAGES/2); ++i) {
6661c7c3c6aSMatthew Dillon 			daddr_t blk;
6671c7c3c6aSMatthew Dillon 
6681c7c3c6aSMatthew Dillon 			if (i > pindex)
6691c7c3c6aSMatthew Dillon 				break;
6701c7c3c6aSMatthew Dillon 			blk = swp_pager_meta_ctl(object, pindex - i, 0);
6711c7c3c6aSMatthew Dillon 			if (blk & SWAPBLK_NONE)
6721c7c3c6aSMatthew Dillon 				break;
6731c7c3c6aSMatthew Dillon 			if (blk != blk0 - i)
6741c7c3c6aSMatthew Dillon 				break;
675ffc82b0aSJohn Dyson 		}
6761c7c3c6aSMatthew Dillon 		*before = (i - 1);
67726f9a767SRodney W. Grimes 	}
67826f9a767SRodney W. Grimes 
67926f9a767SRodney W. Grimes 	/*
6801c7c3c6aSMatthew Dillon 	 * find forward-looking contiguous good backing store
68126f9a767SRodney W. Grimes 	 */
6821c7c3c6aSMatthew Dillon 
6831c7c3c6aSMatthew Dillon 	if (after != NULL) {
6841c7c3c6aSMatthew Dillon 		int i;
6851c7c3c6aSMatthew Dillon 
6861c7c3c6aSMatthew Dillon 		for (i = 1; i < (SWB_NPAGES/2); ++i) {
6871c7c3c6aSMatthew Dillon 			daddr_t blk;
6881c7c3c6aSMatthew Dillon 
6891c7c3c6aSMatthew Dillon 			blk = swp_pager_meta_ctl(object, pindex + i, 0);
6901c7c3c6aSMatthew Dillon 			if (blk & SWAPBLK_NONE)
6911c7c3c6aSMatthew Dillon 				break;
6921c7c3c6aSMatthew Dillon 			if (blk != blk0 + i)
6931c7c3c6aSMatthew Dillon 				break;
69426f9a767SRodney W. Grimes 		}
6951c7c3c6aSMatthew Dillon 		*after = (i - 1);
6961c7c3c6aSMatthew Dillon 	}
6971c7c3c6aSMatthew Dillon 
6981c7c3c6aSMatthew Dillon 	return (TRUE);
6991c7c3c6aSMatthew Dillon }
7001c7c3c6aSMatthew Dillon 
7011c7c3c6aSMatthew Dillon /*
7021c7c3c6aSMatthew Dillon  * SWAP_PAGER_PAGE_UNSWAPPED() - remove swap backing store related to page
7031c7c3c6aSMatthew Dillon  *
7041c7c3c6aSMatthew Dillon  *	This removes any associated swap backing store, whether valid or
7051c7c3c6aSMatthew Dillon  *	not, from the page.
7061c7c3c6aSMatthew Dillon  *
7071c7c3c6aSMatthew Dillon  *	This routine is typically called when a page is made dirty, at
7081c7c3c6aSMatthew Dillon  *	which point any associated swap can be freed.  MADV_FREE also
7091c7c3c6aSMatthew Dillon  *	calls us in a special-case situation
7101c7c3c6aSMatthew Dillon  *
7111c7c3c6aSMatthew Dillon  *	NOTE!!!  If the page is clean and the swap was valid, the caller
7121c7c3c6aSMatthew Dillon  *	should make the page dirty before calling this routine.  This routine
7131c7c3c6aSMatthew Dillon  *	does NOT change the m->dirty status of the page.  Also: MADV_FREE
7141c7c3c6aSMatthew Dillon  *	depends on it.
7151c7c3c6aSMatthew Dillon  *
7161c7c3c6aSMatthew Dillon  *	This routine may not block
7171c7c3c6aSMatthew Dillon  */
7181c7c3c6aSMatthew Dillon 
7191c7c3c6aSMatthew Dillon static void
7201c7c3c6aSMatthew Dillon swap_pager_unswapped(m)
7211c7c3c6aSMatthew Dillon 	vm_page_t m;
7221c7c3c6aSMatthew Dillon {
7231c7c3c6aSMatthew Dillon 	swp_pager_meta_ctl(m->object, m->pindex, SWM_FREE);
7241c7c3c6aSMatthew Dillon }
7251c7c3c6aSMatthew Dillon 
7261c7c3c6aSMatthew Dillon /*
7271c7c3c6aSMatthew Dillon  * SWAP_PAGER_GETPAGES() - bring pages in from swap
7281c7c3c6aSMatthew Dillon  *
7291c7c3c6aSMatthew Dillon  *	Attempt to retrieve (m, count) pages from backing store, but make
7301c7c3c6aSMatthew Dillon  *	sure we retrieve at least m[reqpage].  We try to load in as large
7311c7c3c6aSMatthew Dillon  *	a chunk surrounding m[reqpage] as is contiguous in swap and which
7321c7c3c6aSMatthew Dillon  *	belongs to the same object.
7331c7c3c6aSMatthew Dillon  *
7341c7c3c6aSMatthew Dillon  *	The code is designed for asynchronous operation and
7351c7c3c6aSMatthew Dillon  *	immediate-notification of 'reqpage' but tends not to be
7361c7c3c6aSMatthew Dillon  *	used that way.  Please do not optimize-out this algorithmic
7371c7c3c6aSMatthew Dillon  *	feature, I intend to improve on it in the future.
7381c7c3c6aSMatthew Dillon  *
7391c7c3c6aSMatthew Dillon  *	The parent has a single vm_object_pip_add() reference prior to
7401c7c3c6aSMatthew Dillon  *	calling us and we should return with the same.
7411c7c3c6aSMatthew Dillon  *
7421c7c3c6aSMatthew Dillon  *	The parent has BUSY'd the pages.  We should return with 'm'
7431c7c3c6aSMatthew Dillon  *	left busy, but the others adjusted.
7441c7c3c6aSMatthew Dillon  */
74526f9a767SRodney W. Grimes 
746f708ef1bSPoul-Henning Kamp static int
74724a1cce3SDavid Greenman swap_pager_getpages(object, m, count, reqpage)
74824a1cce3SDavid Greenman 	vm_object_t object;
74926f9a767SRodney W. Grimes 	vm_page_t *m;
75026f9a767SRodney W. Grimes 	int count, reqpage;
751df8bae1dSRodney W. Grimes {
7521c7c3c6aSMatthew Dillon 	struct buf *bp;
7531c7c3c6aSMatthew Dillon 	vm_page_t mreq;
7541c7c3c6aSMatthew Dillon 	int s;
75526f9a767SRodney W. Grimes 	int i;
75626f9a767SRodney W. Grimes 	int j;
7571c7c3c6aSMatthew Dillon 	daddr_t blk;
7581c7c3c6aSMatthew Dillon 	vm_offset_t kva;
7591c7c3c6aSMatthew Dillon 	vm_pindex_t lastpindex;
7600d94caffSDavid Greenman 
7611c7c3c6aSMatthew Dillon 	mreq = m[reqpage];
7621c7c3c6aSMatthew Dillon 
7631c7c3c6aSMatthew Dillon #if !defined(MAX_PERF)
7641c7c3c6aSMatthew Dillon 	if (mreq->object != object) {
7651c7c3c6aSMatthew Dillon 		panic("swap_pager_getpages: object mismatch %p/%p",
7661c7c3c6aSMatthew Dillon 		    object,
7671c7c3c6aSMatthew Dillon 		    mreq->object
7681c7c3c6aSMatthew Dillon 		);
76926f9a767SRodney W. Grimes 	}
7701c7c3c6aSMatthew Dillon #endif
7711c7c3c6aSMatthew Dillon 	/*
7721c7c3c6aSMatthew Dillon 	 * Calculate range to retrieve.  The pages have already been assigned
7731c7c3c6aSMatthew Dillon 	 * their swapblks.  We require a *contiguous* range that falls entirely
7741c7c3c6aSMatthew Dillon 	 * within a single device stripe.   If we do not supply it, bad things
7751c7c3c6aSMatthew Dillon 	 * happen.
7761c7c3c6aSMatthew Dillon 	 */
7771c7c3c6aSMatthew Dillon 
7781c7c3c6aSMatthew Dillon 
7791c7c3c6aSMatthew Dillon 	blk = swp_pager_meta_ctl(mreq->object, mreq->pindex, 0);
7801c7c3c6aSMatthew Dillon 
7811c7c3c6aSMatthew Dillon 	for (i = reqpage - 1; i >= 0; --i) {
7821c7c3c6aSMatthew Dillon 		daddr_t iblk;
7831c7c3c6aSMatthew Dillon 
7841c7c3c6aSMatthew Dillon 		iblk = swp_pager_meta_ctl(m[i]->object, m[i]->pindex, 0);
7851c7c3c6aSMatthew Dillon 		if (iblk & SWAPBLK_NONE)
7861c7c3c6aSMatthew Dillon 			break;
7871c7c3c6aSMatthew Dillon 
7881c7c3c6aSMatthew Dillon 		if ((blk ^ iblk) & dmmax_mask)
7891c7c3c6aSMatthew Dillon 			break;
7901c7c3c6aSMatthew Dillon 
7911c7c3c6aSMatthew Dillon 		if (blk != iblk + (reqpage - i))
79226f9a767SRodney W. Grimes 			break;
79326f9a767SRodney W. Grimes 	}
7941c7c3c6aSMatthew Dillon 	++i;
7951c7c3c6aSMatthew Dillon 
7961c7c3c6aSMatthew Dillon 	for (j = reqpage + 1; j < count; ++j) {
7971c7c3c6aSMatthew Dillon 		daddr_t jblk;
7981c7c3c6aSMatthew Dillon 
7991c7c3c6aSMatthew Dillon 		jblk = swp_pager_meta_ctl(m[j]->object, m[j]->pindex, 0);
8001c7c3c6aSMatthew Dillon 		if (jblk & SWAPBLK_NONE)
8011c7c3c6aSMatthew Dillon 			break;
8021c7c3c6aSMatthew Dillon 
8031c7c3c6aSMatthew Dillon 		if ((blk ^ jblk) & dmmax_mask)
8041c7c3c6aSMatthew Dillon 			break;
8051c7c3c6aSMatthew Dillon 
8061c7c3c6aSMatthew Dillon 		if (blk != jblk - (j - reqpage))
8071c7c3c6aSMatthew Dillon 			break;
80826f9a767SRodney W. Grimes 	}
80926f9a767SRodney W. Grimes 
8101c7c3c6aSMatthew Dillon 	/*
8111c7c3c6aSMatthew Dillon 	 * If blk itself is bad, well, we can't do any I/O.  This should
8121c7c3c6aSMatthew Dillon 	 * already be covered as a side effect, but I'm making sure.
8131c7c3c6aSMatthew Dillon 	 */
81426f9a767SRodney W. Grimes 
8151c7c3c6aSMatthew Dillon 	if (blk & SWAPBLK_NONE) {
8161c7c3c6aSMatthew Dillon 		i = reqpage;
8171c7c3c6aSMatthew Dillon 		j = reqpage + 1;
8181c7c3c6aSMatthew Dillon 	}
8191c7c3c6aSMatthew Dillon 
8201c7c3c6aSMatthew Dillon 	/*
8211c7c3c6aSMatthew Dillon 	 * free pages outside our collection range.   Note: we never free
8221c7c3c6aSMatthew Dillon 	 * mreq, it must remain busy throughout.
8231c7c3c6aSMatthew Dillon 	 */
8241c7c3c6aSMatthew Dillon 
8251c7c3c6aSMatthew Dillon 	{
8261c7c3c6aSMatthew Dillon 		int k;
8271c7c3c6aSMatthew Dillon 
8281c7c3c6aSMatthew Dillon 		for (k = 0; k < i; ++k) {
8291c7c3c6aSMatthew Dillon 			vm_page_free(m[k]);
8301c7c3c6aSMatthew Dillon 		}
8311c7c3c6aSMatthew Dillon 		for (k = j; k < count; ++k) {
8321c7c3c6aSMatthew Dillon 			vm_page_free(m[k]);
8331c7c3c6aSMatthew Dillon 		}
8341c7c3c6aSMatthew Dillon 	}
8351c7c3c6aSMatthew Dillon 
8361c7c3c6aSMatthew Dillon 	/*
8371c7c3c6aSMatthew Dillon 	 * Return VM_PAGER_FAIL if we have nothing
8381c7c3c6aSMatthew Dillon 	 * to do.  Return mreq still busy, but the
8391c7c3c6aSMatthew Dillon 	 * others unbusied.
8401c7c3c6aSMatthew Dillon 	 */
8411c7c3c6aSMatthew Dillon 
8421c7c3c6aSMatthew Dillon 	if (blk & SWAPBLK_NONE)
84326f9a767SRodney W. Grimes 		return(VM_PAGER_FAIL);
844df8bae1dSRodney W. Grimes 
84526f9a767SRodney W. Grimes 
84616f62314SDavid Greenman 	/*
84716f62314SDavid Greenman 	 * Get a swap buffer header to perform the IO
84816f62314SDavid Greenman 	 */
8491c7c3c6aSMatthew Dillon 
8501c7c3c6aSMatthew Dillon 	bp = getpbuf(&nsw_rcount);
85116f62314SDavid Greenman 	kva = (vm_offset_t) bp->b_data;
85226f9a767SRodney W. Grimes 
85316f62314SDavid Greenman 	/*
85416f62314SDavid Greenman 	 * map our page(s) into kva for input
8551c7c3c6aSMatthew Dillon 	 *
8561c7c3c6aSMatthew Dillon 	 * NOTE: B_PAGING is set by pbgetvp()
85716f62314SDavid Greenman 	 */
85816f62314SDavid Greenman 
8591c7c3c6aSMatthew Dillon 	pmap_qenter(kva, m + i, j - i);
8601c7c3c6aSMatthew Dillon 
8611c7c3c6aSMatthew Dillon 	bp->b_flags = B_BUSY | B_READ | B_CALL;
8621c7c3c6aSMatthew Dillon 	bp->b_iodone = swp_pager_async_iodone;
863df8bae1dSRodney W. Grimes 	bp->b_proc = &proc0;	/* XXX (but without B_PHYS set this is ok) */
86426f9a767SRodney W. Grimes 	bp->b_rcred = bp->b_wcred = bp->b_proc->p_ucred;
86526f9a767SRodney W. Grimes 	crhold(bp->b_rcred);
86626f9a767SRodney W. Grimes 	crhold(bp->b_wcred);
867ab3f7469SPoul-Henning Kamp 	bp->b_data = (caddr_t) kva;
8681c7c3c6aSMatthew Dillon 	/*
8691c7c3c6aSMatthew Dillon 	 * b_blkno is in page-sized chunks.  swapblk is valid, too, so
8701c7c3c6aSMatthew Dillon 	 * we don't have to mask it against SWAPBLK_MASK.
8711c7c3c6aSMatthew Dillon 	 */
8721c7c3c6aSMatthew Dillon 	bp->b_blkno = blk - (reqpage - i);
8731c7c3c6aSMatthew Dillon 	bp->b_bcount = PAGE_SIZE * (j - i);
8741c7c3c6aSMatthew Dillon 	bp->b_bufsize = PAGE_SIZE * (j - i);
8751c7c3c6aSMatthew Dillon 	bp->b_pager.pg_reqpage = reqpage - i;
8761c7c3c6aSMatthew Dillon 
8771c7c3c6aSMatthew Dillon 	{
8781c7c3c6aSMatthew Dillon 		int k;
8791c7c3c6aSMatthew Dillon 
8801c7c3c6aSMatthew Dillon 		for (k = i; k < j; ++k) {
8811c7c3c6aSMatthew Dillon 			bp->b_pages[k - i] = m[k];
8821c7c3c6aSMatthew Dillon 			vm_page_flag_set(m[k], PG_SWAPINPROG);
8831c7c3c6aSMatthew Dillon 		}
8841c7c3c6aSMatthew Dillon 	}
8851c7c3c6aSMatthew Dillon 	bp->b_npages = j - i;
88626f9a767SRodney W. Grimes 
8870d94caffSDavid Greenman 	pbgetvp(swapdev_vp, bp);
888df8bae1dSRodney W. Grimes 
889976e77fcSDavid Greenman 	cnt.v_swapin++;
8901c7c3c6aSMatthew Dillon 	cnt.v_swappgsin += bp->b_npages;
8911c7c3c6aSMatthew Dillon 
892df8bae1dSRodney W. Grimes 	/*
8931c7c3c6aSMatthew Dillon 	 * We still hold the lock on mreq, and our automatic completion routine
8941c7c3c6aSMatthew Dillon 	 * does not remove it.
895df8bae1dSRodney W. Grimes 	 */
8961c7c3c6aSMatthew Dillon 
8971c7c3c6aSMatthew Dillon 	vm_object_pip_add(mreq->object, bp->b_npages);
8981c7c3c6aSMatthew Dillon 	lastpindex = m[j-1]->pindex;
8991c7c3c6aSMatthew Dillon 
9001c7c3c6aSMatthew Dillon 	/*
9011c7c3c6aSMatthew Dillon 	 * perform the I/O.  NOTE!!!  bp cannot be considered valid after
9021c7c3c6aSMatthew Dillon 	 * this point because we automatically release it on completion.
9031c7c3c6aSMatthew Dillon 	 * Instead, we look at the one page we are interested in which we
9041c7c3c6aSMatthew Dillon 	 * still hold a lock on even through the I/O completion.
9051c7c3c6aSMatthew Dillon 	 *
9061c7c3c6aSMatthew Dillon 	 * The other pages in our m[] array are also released on completion,
9071c7c3c6aSMatthew Dillon 	 * so we cannot assume they are valid anymore either.
9081c7c3c6aSMatthew Dillon 	 *
9091c7c3c6aSMatthew Dillon 	 * NOTE: b_blkno is destroyed by the call to VOP_STRATEGY
9101c7c3c6aSMatthew Dillon 	 */
9111c7c3c6aSMatthew Dillon 
912fd5d1124SJulian Elischer 	VOP_STRATEGY(bp->b_vp, bp);
91326f9a767SRodney W. Grimes 
91426f9a767SRodney W. Grimes 	/*
9151c7c3c6aSMatthew Dillon 	 * wait for the page we want to complete.  PG_SWAPINPROG is always
9161c7c3c6aSMatthew Dillon 	 * cleared on completion.  If an I/O error occurs, SWAPBLK_NONE
9171c7c3c6aSMatthew Dillon 	 * is set in the meta-data.
91826f9a767SRodney W. Grimes 	 */
9191b119d9dSDavid Greenman 
9201c7c3c6aSMatthew Dillon 	s = splvm();
9211c7c3c6aSMatthew Dillon 
9221c7c3c6aSMatthew Dillon 	while ((mreq->flags & PG_SWAPINPROG) != 0) {
9231c7c3c6aSMatthew Dillon 		vm_page_flag_set(mreq, PG_WANTED | PG_REFERENCED);
9241c7c3c6aSMatthew Dillon 		cnt.v_intrans++;
9251c7c3c6aSMatthew Dillon 		if (tsleep(mreq, PSWP, "swread", hz*20)) {
926ac1e407bSBruce Evans 			printf(
9271c7c3c6aSMatthew Dillon 			    "swap_pager: indefinite wait buffer: device:"
9281c7c3c6aSMatthew Dillon 				" %#lx, blkno: %ld, size: %ld\n",
9291c7c3c6aSMatthew Dillon 			    (u_long)bp->b_dev, (long)bp->b_blkno,
9301c7c3c6aSMatthew Dillon 			    (long)bp->b_bcount
9311c7c3c6aSMatthew Dillon 			);
9321c7c3c6aSMatthew Dillon 		}
9331b119d9dSDavid Greenman 	}
93426f9a767SRodney W. Grimes 
935df8bae1dSRodney W. Grimes 	splx(s);
93626f9a767SRodney W. Grimes 
93726f9a767SRodney W. Grimes 	/*
9381c7c3c6aSMatthew Dillon 	 * mreq is left bussied after completion, but all the other pages
9391c7c3c6aSMatthew Dillon 	 * are freed.  If we had an unrecoverable read error the page will
9401c7c3c6aSMatthew Dillon 	 * not be valid.
94126f9a767SRodney W. Grimes 	 */
94226f9a767SRodney W. Grimes 
9431c7c3c6aSMatthew Dillon 	if (mreq->valid != VM_PAGE_BITS_ALL) {
9441c7c3c6aSMatthew Dillon 		return(VM_PAGER_ERROR);
94526f9a767SRodney W. Grimes 	} else {
9461c7c3c6aSMatthew Dillon 		mreq->object->last_read = lastpindex;
9471c7c3c6aSMatthew Dillon 		return(VM_PAGER_OK);
94826f9a767SRodney W. Grimes 	}
9491c7c3c6aSMatthew Dillon 
9501c7c3c6aSMatthew Dillon 	/*
9511c7c3c6aSMatthew Dillon 	 * A final note: in a low swap situation, we cannot deallocate swap
9521c7c3c6aSMatthew Dillon 	 * and mark a page dirty here because the caller is likely to mark
9531c7c3c6aSMatthew Dillon 	 * the page clean when we return, causing the page to possibly revert
9541c7c3c6aSMatthew Dillon 	 * to all-zero's later.
9551c7c3c6aSMatthew Dillon 	 */
956df8bae1dSRodney W. Grimes }
957df8bae1dSRodney W. Grimes 
9581c7c3c6aSMatthew Dillon /*
9591c7c3c6aSMatthew Dillon  *	swap_pager_putpages:
9601c7c3c6aSMatthew Dillon  *
9611c7c3c6aSMatthew Dillon  *	Assign swap (if necessary) and initiate I/O on the specified pages.
9621c7c3c6aSMatthew Dillon  *
9631c7c3c6aSMatthew Dillon  *	We support both OBJT_DEFAULT and OBJT_SWAP objects.  DEFAULT objects
9641c7c3c6aSMatthew Dillon  *	are automatically converted to SWAP objects.
9651c7c3c6aSMatthew Dillon  *
9661c7c3c6aSMatthew Dillon  *	In a low memory situation we may block in VOP_STRATEGY(), but the new
9671c7c3c6aSMatthew Dillon  *	vm_page reservation system coupled with properly written VFS devices
9681c7c3c6aSMatthew Dillon  *	should ensure that no low-memory deadlock occurs.  This is an area
9691c7c3c6aSMatthew Dillon  *	which needs work.
9701c7c3c6aSMatthew Dillon  *
9711c7c3c6aSMatthew Dillon  *	The parent has N vm_object_pip_add() references prior to
9721c7c3c6aSMatthew Dillon  *	calling us and will remove references for rtvals[] that are
9731c7c3c6aSMatthew Dillon  *	not set to VM_PAGER_PEND.  We need to remove the rest on I/O
9741c7c3c6aSMatthew Dillon  *	completion.
9751c7c3c6aSMatthew Dillon  *
9761c7c3c6aSMatthew Dillon  *	The parent has soft-busy'd the pages it passes us and will unbusy
9771c7c3c6aSMatthew Dillon  *	those whos rtvals[] entry is not set to VM_PAGER_PEND on return.
9781c7c3c6aSMatthew Dillon  *	We need to unbusy the rest on I/O completion.
9791c7c3c6aSMatthew Dillon  */
9801c7c3c6aSMatthew Dillon 
981e4542174SMatthew Dillon void
98224a1cce3SDavid Greenman swap_pager_putpages(object, m, count, sync, rtvals)
98324a1cce3SDavid Greenman 	vm_object_t object;
98426f9a767SRodney W. Grimes 	vm_page_t *m;
98526f9a767SRodney W. Grimes 	int count;
98624a1cce3SDavid Greenman 	boolean_t sync;
98726f9a767SRodney W. Grimes 	int *rtvals;
988df8bae1dSRodney W. Grimes {
9891c7c3c6aSMatthew Dillon 	int i;
9901c7c3c6aSMatthew Dillon 	int n = 0;
991df8bae1dSRodney W. Grimes 
9921c7c3c6aSMatthew Dillon #if !defined(MAX_PERF)
9931c7c3c6aSMatthew Dillon 	if (count && m[0]->object != object) {
9941c7c3c6aSMatthew Dillon 		panic("swap_pager_getpages: object mismatch %p/%p",
9951c7c3c6aSMatthew Dillon 		    object,
9961c7c3c6aSMatthew Dillon 		    m[0]->object
9971c7c3c6aSMatthew Dillon 		);
9981c7c3c6aSMatthew Dillon 	}
9991c7c3c6aSMatthew Dillon #endif
10001c7c3c6aSMatthew Dillon 	/*
10011c7c3c6aSMatthew Dillon 	 * Step 1
10021c7c3c6aSMatthew Dillon 	 *
10031c7c3c6aSMatthew Dillon 	 * Turn object into OBJT_SWAP
10041c7c3c6aSMatthew Dillon 	 * check for bogus sysops
10051c7c3c6aSMatthew Dillon 	 * force sync if not pageout process
10061c7c3c6aSMatthew Dillon 	 */
1007e736cd05SJohn Dyson 
10081c7c3c6aSMatthew Dillon 	if (object->type != OBJT_SWAP) {
10091c7c3c6aSMatthew Dillon 		swp_pager_meta_build(object, 0, SWAPBLK_NONE, 0);
10105663e6deSDavid Greenman 	}
1011e47ed70bSJohn Dyson 
1012e47ed70bSJohn Dyson 	if (curproc != pageproc)
1013e47ed70bSJohn Dyson 		sync = TRUE;
101426f9a767SRodney W. Grimes 
10151c7c3c6aSMatthew Dillon 	/*
10161c7c3c6aSMatthew Dillon 	 * Step 2
10171c7c3c6aSMatthew Dillon 	 *
10181c7c3c6aSMatthew Dillon 	 * Assign swap blocks and issue I/O.  We reallocate swap on the fly.
10191c7c3c6aSMatthew Dillon 	 * The page is left dirty until the pageout operation completes
10201c7c3c6aSMatthew Dillon 	 * successfully.
10211c7c3c6aSMatthew Dillon 	 */
102226f9a767SRodney W. Grimes 
10231c7c3c6aSMatthew Dillon 	for (i = 0; i < count; i += n) {
10241c7c3c6aSMatthew Dillon 		int s;
10251c7c3c6aSMatthew Dillon 		int j;
10261c7c3c6aSMatthew Dillon 		struct buf *bp;
1027a316d390SJohn Dyson 		daddr_t blk;
102826f9a767SRodney W. Grimes 
1029df8bae1dSRodney W. Grimes 		/*
10301c7c3c6aSMatthew Dillon 		 * Maximum I/O size is limited by a number of factors.
1031df8bae1dSRodney W. Grimes 		 */
103226f9a767SRodney W. Grimes 
10331c7c3c6aSMatthew Dillon 		n = min(BLIST_MAX_ALLOC, count - i);
10341c7c3c6aSMatthew Dillon 		n = min(n, max_pageout_cluster);
10351c7c3c6aSMatthew Dillon 
103626f9a767SRodney W. Grimes 		/*
10371c7c3c6aSMatthew Dillon 		 * Get biggest block of swap we can.  If we fail, fall
10381c7c3c6aSMatthew Dillon 		 * back and try to allocate a smaller block.  Don't go
10391c7c3c6aSMatthew Dillon 		 * overboard trying to allocate space if it would overly
10401c7c3c6aSMatthew Dillon 		 * fragment swap.
104126f9a767SRodney W. Grimes 		 */
10421c7c3c6aSMatthew Dillon 		while (
10431c7c3c6aSMatthew Dillon 		    (blk = swp_pager_getswapspace(n)) == SWAPBLK_NONE &&
10441c7c3c6aSMatthew Dillon 		    n > 4
10451c7c3c6aSMatthew Dillon 		) {
10461c7c3c6aSMatthew Dillon 			n >>= 1;
104726f9a767SRodney W. Grimes 		}
10481c7c3c6aSMatthew Dillon 		if (blk == SWAPBLK_NONE) {
10491c7c3c6aSMatthew Dillon 			for (j = 0; j < n; ++j) {
10501c7c3c6aSMatthew Dillon 				rtvals[i+j] = VM_PAGER_FAIL;
105126f9a767SRodney W. Grimes 			}
10521c7c3c6aSMatthew Dillon 			continue;
105326f9a767SRodney W. Grimes 		}
105426f9a767SRodney W. Grimes 
105526f9a767SRodney W. Grimes 		/*
10561c7c3c6aSMatthew Dillon 		 * Oops, too big if it crosses a stripe
10571c7c3c6aSMatthew Dillon 		 *
10581c7c3c6aSMatthew Dillon 		 * 1111000000
10591c7c3c6aSMatthew Dillon 		 *     111111
10601c7c3c6aSMatthew Dillon 		 *    1000001
106126f9a767SRodney W. Grimes 		 */
10621c7c3c6aSMatthew Dillon 		if ((blk ^ (blk + n)) & dmmax_mask) {
10631c7c3c6aSMatthew Dillon 			j = ((blk + dmmax) & dmmax_mask) - blk;
10641c7c3c6aSMatthew Dillon 			swp_pager_freeswapspace(blk + j, n - j);
10651c7c3c6aSMatthew Dillon 			n = j;
1066e47ed70bSJohn Dyson 		}
106726f9a767SRodney W. Grimes 
106826f9a767SRodney W. Grimes 		/*
10691c7c3c6aSMatthew Dillon 		 * All I/O parameters have been satisfied, build the I/O
10701c7c3c6aSMatthew Dillon 		 * request and assign the swap space.
10711c7c3c6aSMatthew Dillon 		 *
10721c7c3c6aSMatthew Dillon 		 * NOTE: B_PAGING is set by pbgetvp()
107326f9a767SRodney W. Grimes 		 */
107426f9a767SRodney W. Grimes 
10751c7c3c6aSMatthew Dillon 		bp = getpbuf(&nsw_wcount);
10761c7c3c6aSMatthew Dillon 		bp->b_spc = NULL;	/* not used, but NULL-out anyway */
107726f9a767SRodney W. Grimes 
10781c7c3c6aSMatthew Dillon 		pmap_qenter((vm_offset_t)bp->b_data, &m[i], n);
10791c7c3c6aSMatthew Dillon 
10801c7c3c6aSMatthew Dillon 		bp->b_flags = B_BUSY | B_ASYNC;
10811c7c3c6aSMatthew Dillon 		bp->b_proc = &proc0; /* XXX (but without B_PHYS this is ok) */
108226f9a767SRodney W. Grimes 		bp->b_rcred = bp->b_wcred = bp->b_proc->p_ucred;
10831c7c3c6aSMatthew Dillon 
1084a481f200SDavid Greenman 		if (bp->b_rcred != NOCRED)
108526f9a767SRodney W. Grimes 			crhold(bp->b_rcred);
1086a481f200SDavid Greenman 		if (bp->b_wcred != NOCRED)
108726f9a767SRodney W. Grimes 			crhold(bp->b_wcred);
10880d94caffSDavid Greenman 		pbgetvp(swapdev_vp, bp);
108916f62314SDavid Greenman 
10901c7c3c6aSMatthew Dillon 		bp->b_bcount = PAGE_SIZE * n;
10911c7c3c6aSMatthew Dillon 		bp->b_bufsize = PAGE_SIZE * n;
10921c7c3c6aSMatthew Dillon 		bp->b_blkno = blk;
1093e47ed70bSJohn Dyson 
1094e47ed70bSJohn Dyson 		s = splvm();
10951c7c3c6aSMatthew Dillon 
10961c7c3c6aSMatthew Dillon 		for (j = 0; j < n; ++j) {
10971c7c3c6aSMatthew Dillon 			vm_page_t mreq = m[i+j];
10981c7c3c6aSMatthew Dillon 
10991c7c3c6aSMatthew Dillon 			swp_pager_meta_build(
11001c7c3c6aSMatthew Dillon 			    mreq->object,
11011c7c3c6aSMatthew Dillon 			    mreq->pindex,
11021c7c3c6aSMatthew Dillon 			    blk + j,
11031c7c3c6aSMatthew Dillon 			    0
11041c7c3c6aSMatthew Dillon 			);
11057dbf82dcSMatthew Dillon 			vm_page_dirty(mreq);
11061c7c3c6aSMatthew Dillon 			rtvals[i+j] = VM_PAGER_OK;
11071c7c3c6aSMatthew Dillon 
11081c7c3c6aSMatthew Dillon 			vm_page_flag_set(mreq, PG_SWAPINPROG);
11091c7c3c6aSMatthew Dillon 			bp->b_pages[j] = mreq;
11101c7c3c6aSMatthew Dillon 		}
11111c7c3c6aSMatthew Dillon 		bp->b_flags |= B_CALL;
11121c7c3c6aSMatthew Dillon 		bp->b_npages = n;
11131c7c3c6aSMatthew Dillon 
11141c7c3c6aSMatthew Dillon 		cnt.v_swapout++;
11151c7c3c6aSMatthew Dillon 		cnt.v_swappgsout += bp->b_npages;
111626f9a767SRodney W. Grimes 		swapdev_vp->v_numoutput++;
111726f9a767SRodney W. Grimes 
111826f9a767SRodney W. Grimes 		/*
11191c7c3c6aSMatthew Dillon 		 * asynchronous
11201c7c3c6aSMatthew Dillon 		 *
11211c7c3c6aSMatthew Dillon 		 * NOTE: b_blkno is destroyed by the call to VOP_STRATEGY
112226f9a767SRodney W. Grimes 		 */
1123e47ed70bSJohn Dyson 
11241c7c3c6aSMatthew Dillon 		if (sync == FALSE) {
11251c7c3c6aSMatthew Dillon 			bp->b_iodone = swp_pager_async_iodone;
112626f9a767SRodney W. Grimes 			bp->b_dirtyoff = 0;
112726f9a767SRodney W. Grimes 			bp->b_dirtyend = bp->b_bcount;
1128fd5d1124SJulian Elischer 			VOP_STRATEGY(bp->b_vp, bp);
11291c7c3c6aSMatthew Dillon 
11301c7c3c6aSMatthew Dillon 			for (j = 0; j < n; ++j)
11311c7c3c6aSMatthew Dillon 				rtvals[i+j] = VM_PAGER_PEND;
11321c7c3c6aSMatthew Dillon 
1133ccbbd927SBruce Evans 			splx(s);
11341c7c3c6aSMatthew Dillon 			continue;
113526f9a767SRodney W. Grimes 		}
1136e47ed70bSJohn Dyson 
113726f9a767SRodney W. Grimes 		/*
11381c7c3c6aSMatthew Dillon 		 * synchronous
11391c7c3c6aSMatthew Dillon 		 *
11401c7c3c6aSMatthew Dillon 		 * NOTE: b_blkno is destroyed by the call to VOP_STRATEGY
11411c7c3c6aSMatthew Dillon 		 */
11421c7c3c6aSMatthew Dillon 
11431c7c3c6aSMatthew Dillon 		bp->b_iodone = swp_pager_sync_iodone;
11441c7c3c6aSMatthew Dillon 		VOP_STRATEGY(bp->b_vp, bp);
11451c7c3c6aSMatthew Dillon 
11461c7c3c6aSMatthew Dillon 		/*
11471c7c3c6aSMatthew Dillon 		 * Wait for the sync I/O to complete, then update rtvals.
11481c7c3c6aSMatthew Dillon 		 * We just set the rtvals[] to VM_PAGER_PEND so we can call
11491c7c3c6aSMatthew Dillon 		 * our async completion routine at the end, thus avoiding a
11501c7c3c6aSMatthew Dillon 		 * double-free.
115126f9a767SRodney W. Grimes 		 */
115226f9a767SRodney W. Grimes 		while ((bp->b_flags & B_DONE) == 0) {
115324a1cce3SDavid Greenman 			tsleep(bp, PVM, "swwrt", 0);
115426f9a767SRodney W. Grimes 		}
1155e47ed70bSJohn Dyson 
1156e4542174SMatthew Dillon #if 0
11571b119d9dSDavid Greenman 		if (bp->b_flags & B_ERROR) {
11581c7c3c6aSMatthew Dillon 			grv = VM_PAGER_ERROR;
11591b119d9dSDavid Greenman 		}
1160e4542174SMatthew Dillon #endif
116126f9a767SRodney W. Grimes 
11621c7c3c6aSMatthew Dillon 		for (j = 0; j < n; ++j)
11631c7c3c6aSMatthew Dillon 			rtvals[i+j] = VM_PAGER_PEND;
116426f9a767SRodney W. Grimes 
1165e4542174SMatthew Dillon #if 0
11661c7c3c6aSMatthew Dillon 		if (bp->b_flags & B_ERROR) {
11671c7c3c6aSMatthew Dillon 			grv = VM_PAGER_ERROR;
11681c7c3c6aSMatthew Dillon 		}
1169e4542174SMatthew Dillon #endif
11701c7c3c6aSMatthew Dillon 
11711c7c3c6aSMatthew Dillon 		/*
11721c7c3c6aSMatthew Dillon 		 * Now that we are through with the bp, we can call the
11731c7c3c6aSMatthew Dillon 		 * normal async completion, which frees everything up.
11741c7c3c6aSMatthew Dillon 		 */
11751c7c3c6aSMatthew Dillon 
11761c7c3c6aSMatthew Dillon 		swp_pager_async_iodone(bp);
117726f9a767SRodney W. Grimes 
117826f9a767SRodney W. Grimes 		splx(s);
11791c7c3c6aSMatthew Dillon 	}
11801c7c3c6aSMatthew Dillon }
11811c7c3c6aSMatthew Dillon 
11821c7c3c6aSMatthew Dillon /*
11831c7c3c6aSMatthew Dillon  *	swap_pager_sync_iodone:
11841c7c3c6aSMatthew Dillon  *
11851c7c3c6aSMatthew Dillon  *	Completion routine for synchronous reads and writes from/to swap.
11861c7c3c6aSMatthew Dillon  *	We just mark the bp is complete and wake up anyone waiting on it.
11871c7c3c6aSMatthew Dillon  *
11881c7c3c6aSMatthew Dillon  *	This routine may not block.
11891c7c3c6aSMatthew Dillon  */
11901c7c3c6aSMatthew Dillon 
11911c7c3c6aSMatthew Dillon static void
11921c7c3c6aSMatthew Dillon swp_pager_sync_iodone(bp)
11931c7c3c6aSMatthew Dillon 	struct buf *bp;
11941c7c3c6aSMatthew Dillon {
11951c7c3c6aSMatthew Dillon 	bp->b_flags |= B_DONE;
11961c7c3c6aSMatthew Dillon 	bp->b_flags &= ~B_ASYNC;
11971c7c3c6aSMatthew Dillon 	wakeup(bp);
11981c7c3c6aSMatthew Dillon }
11991c7c3c6aSMatthew Dillon 
12001c7c3c6aSMatthew Dillon /*
12011c7c3c6aSMatthew Dillon  *	swp_pager_async_iodone:
12021c7c3c6aSMatthew Dillon  *
12031c7c3c6aSMatthew Dillon  *	Completion routine for asynchronous reads and writes from/to swap.
12041c7c3c6aSMatthew Dillon  *	Also called manually by synchronous code to finish up a bp.
12051c7c3c6aSMatthew Dillon  *
12061c7c3c6aSMatthew Dillon  *	WARNING!  This routine may be called from an interrupt.  We cannot
12071c7c3c6aSMatthew Dillon  *	mess with swap metadata unless we want to run all our other routines
12081c7c3c6aSMatthew Dillon  *	at splbio() too, which I'd rather not do.  We up ourselves
12091c7c3c6aSMatthew Dillon  * 	to splvm() because we may call vm_page_free(), which can unlink a
12101c7c3c6aSMatthew Dillon  *	page from an object.
12111c7c3c6aSMatthew Dillon  *
12121c7c3c6aSMatthew Dillon  *	XXX currently I do not believe any object routines protect
12131c7c3c6aSMatthew Dillon  *	object->memq at splvm().  The code must be gone over to determine
12141c7c3c6aSMatthew Dillon  *	the actual state of the problem.
12151c7c3c6aSMatthew Dillon  *
12161c7c3c6aSMatthew Dillon  *	For READ operations, the pages are PG_BUSY'd.  For WRITE operations,
12171c7c3c6aSMatthew Dillon  *	the pages are vm_page_t->busy'd.  For READ operations, we PG_BUSY
12181c7c3c6aSMatthew Dillon  *	unbusy all pages except the 'main' request page.  For WRITE
12191c7c3c6aSMatthew Dillon  *	operations, we vm_page_t->busy'd unbusy all pages ( we can do this
12201c7c3c6aSMatthew Dillon  *	because we marked them all VM_PAGER_PEND on return from putpages ).
12211c7c3c6aSMatthew Dillon  *
12221c7c3c6aSMatthew Dillon  *	This routine may not block.
12231c7c3c6aSMatthew Dillon  *	This routine is called at splbio()
12241c7c3c6aSMatthew Dillon  */
12251c7c3c6aSMatthew Dillon 
12261c7c3c6aSMatthew Dillon static void
12271c7c3c6aSMatthew Dillon swp_pager_async_iodone(bp)
12281c7c3c6aSMatthew Dillon 	register struct buf *bp;
12291c7c3c6aSMatthew Dillon {
12301c7c3c6aSMatthew Dillon 	int s;
12311c7c3c6aSMatthew Dillon 	int i;
12321c7c3c6aSMatthew Dillon 	vm_object_t object = NULL;
12331c7c3c6aSMatthew Dillon 
12341c7c3c6aSMatthew Dillon 	s = splvm();
12351c7c3c6aSMatthew Dillon 
12361c7c3c6aSMatthew Dillon 	bp->b_flags |= B_DONE;
12371c7c3c6aSMatthew Dillon 
12381c7c3c6aSMatthew Dillon 	/*
12391c7c3c6aSMatthew Dillon 	 * report error
12401c7c3c6aSMatthew Dillon 	 */
12411c7c3c6aSMatthew Dillon 
12421c7c3c6aSMatthew Dillon 	if (bp->b_flags & B_ERROR) {
12431c7c3c6aSMatthew Dillon 		printf(
12441c7c3c6aSMatthew Dillon 		    "swap_pager: I/O error - %s failed; blkno %ld,"
12451c7c3c6aSMatthew Dillon 			"size %ld, error %d\n",
12461c7c3c6aSMatthew Dillon 		    ((bp->b_flags & B_READ) ? "pagein" : "pageout"),
12471c7c3c6aSMatthew Dillon 		    (long)bp->b_blkno,
12481c7c3c6aSMatthew Dillon 		    (long)bp->b_bcount,
12491c7c3c6aSMatthew Dillon 		    bp->b_error
12501c7c3c6aSMatthew Dillon 		);
12511c7c3c6aSMatthew Dillon 	}
12521c7c3c6aSMatthew Dillon 
12531c7c3c6aSMatthew Dillon 	/*
12541c7c3c6aSMatthew Dillon 	 * set object.
12551c7c3c6aSMatthew Dillon 	 */
12561c7c3c6aSMatthew Dillon 
12571c7c3c6aSMatthew Dillon 	if (bp->b_npages)
12581c7c3c6aSMatthew Dillon 		object = bp->b_pages[0]->object;
125926f9a767SRodney W. Grimes 
126026f9a767SRodney W. Grimes 	/*
126126f9a767SRodney W. Grimes 	 * remove the mapping for kernel virtual
126226f9a767SRodney W. Grimes 	 */
12631c7c3c6aSMatthew Dillon 
12641c7c3c6aSMatthew Dillon 	pmap_qremove((vm_offset_t)bp->b_data, bp->b_npages);
126526f9a767SRodney W. Grimes 
126626f9a767SRodney W. Grimes 	/*
12671c7c3c6aSMatthew Dillon 	 * cleanup pages.  If an error occurs writing to swap, we are in
12681c7c3c6aSMatthew Dillon 	 * very serious trouble.  If it happens to be a disk error, though,
12691c7c3c6aSMatthew Dillon 	 * we may be able to recover by reassigning the swap later on.  So
12701c7c3c6aSMatthew Dillon 	 * in this case we remove the m->swapblk assignment for the page
12711c7c3c6aSMatthew Dillon 	 * but do not free it in the rlist.  The errornous block(s) are thus
12721c7c3c6aSMatthew Dillon 	 * never reallocated as swap.  Redirty the page and continue.
127326f9a767SRodney W. Grimes 	 */
127426f9a767SRodney W. Grimes 
12751c7c3c6aSMatthew Dillon 	for (i = 0; i < bp->b_npages; ++i) {
12761c7c3c6aSMatthew Dillon 		vm_page_t m = bp->b_pages[i];
1277e47ed70bSJohn Dyson 
12781c7c3c6aSMatthew Dillon 		vm_page_flag_clear(m, PG_SWAPINPROG);
1279e47ed70bSJohn Dyson 
128026f9a767SRodney W. Grimes 		if (bp->b_flags & B_ERROR) {
1281ffc82b0aSJohn Dyson 			/*
12821c7c3c6aSMatthew Dillon 			 * If an error occurs I'd love to throw the swapblk
12831c7c3c6aSMatthew Dillon 			 * away without freeing it back to swapspace, so it
12841c7c3c6aSMatthew Dillon 			 * can never be used again.  But I can't from an
12851c7c3c6aSMatthew Dillon 			 * interrupt.
1286ffc82b0aSJohn Dyson 			 */
12871c7c3c6aSMatthew Dillon 
12881c7c3c6aSMatthew Dillon 			if (bp->b_flags & B_READ) {
12891c7c3c6aSMatthew Dillon 				/*
12901c7c3c6aSMatthew Dillon 				 * When reading, reqpage needs to stay
12911c7c3c6aSMatthew Dillon 				 * locked for the parent, but all other
12921c7c3c6aSMatthew Dillon 				 * pages can be freed.  We still want to
12931c7c3c6aSMatthew Dillon 				 * wakeup the parent waiting on the page,
12941c7c3c6aSMatthew Dillon 				 * though.  ( also: pg_reqpage can be -1 and
12951c7c3c6aSMatthew Dillon 				 * not match anything ).
12961c7c3c6aSMatthew Dillon 				 *
12971c7c3c6aSMatthew Dillon 				 * We have to wake specifically requested pages
12981c7c3c6aSMatthew Dillon 				 * up too because we cleared PG_SWAPINPROG and
12991c7c3c6aSMatthew Dillon 				 * someone may be waiting for that.
13001c7c3c6aSMatthew Dillon 				 *
13011c7c3c6aSMatthew Dillon 				 * NOTE: for reads, m->dirty will probably
13021c7c3c6aSMatthew Dillon 				 * be overriden by the original caller of
13031c7c3c6aSMatthew Dillon 				 * getpages so don't play cute tricks here.
13041c7c3c6aSMatthew Dillon 				 *
13051c7c3c6aSMatthew Dillon 				 * XXX it may not be legal to free the page
13061c7c3c6aSMatthew Dillon 				 * here as this messes with the object->memq's.
13071c7c3c6aSMatthew Dillon 				 */
13081c7c3c6aSMatthew Dillon 
13091c7c3c6aSMatthew Dillon 				m->valid = 0;
13101c7c3c6aSMatthew Dillon 				vm_page_flag_clear(m, PG_ZERO);
13111c7c3c6aSMatthew Dillon 
13121c7c3c6aSMatthew Dillon 				if (i != bp->b_pager.pg_reqpage)
13131c7c3c6aSMatthew Dillon 					vm_page_free(m);
13141c7c3c6aSMatthew Dillon 				else
13151c7c3c6aSMatthew Dillon 					vm_page_flash(m);
13161c7c3c6aSMatthew Dillon 				/*
13171c7c3c6aSMatthew Dillon 				 * If i == bp->b_pager.pg_reqpage, do not wake
13181c7c3c6aSMatthew Dillon 				 * the page up.  The caller needs to.
13191c7c3c6aSMatthew Dillon 				 */
13201c7c3c6aSMatthew Dillon 			} else {
13211c7c3c6aSMatthew Dillon 				/*
13221c7c3c6aSMatthew Dillon 				 * If a write error occurs, reactivate page
13231c7c3c6aSMatthew Dillon 				 * so it doesn't clog the inactive list,
13241c7c3c6aSMatthew Dillon 				 * then finish the I/O.
13251c7c3c6aSMatthew Dillon 				 */
13267dbf82dcSMatthew Dillon 				vm_page_dirty(m);
13271c7c3c6aSMatthew Dillon 				vm_page_activate(m);
13281c7c3c6aSMatthew Dillon 				vm_page_io_finish(m);
13291c7c3c6aSMatthew Dillon 			}
13301c7c3c6aSMatthew Dillon 		} else if (bp->b_flags & B_READ) {
13311c7c3c6aSMatthew Dillon 			/*
13321c7c3c6aSMatthew Dillon 			 * For read success, clear dirty bits.  Nobody should
13331c7c3c6aSMatthew Dillon 			 * have this page mapped but don't take any chances,
13341c7c3c6aSMatthew Dillon 			 * make sure the pmap modify bits are also cleared.
13351c7c3c6aSMatthew Dillon 			 *
13361c7c3c6aSMatthew Dillon 			 * NOTE: for reads, m->dirty will probably be
13371c7c3c6aSMatthew Dillon 			 * overriden by the original caller of getpages so
13381c7c3c6aSMatthew Dillon 			 * we cannot set them in order to free the underlying
13391c7c3c6aSMatthew Dillon 			 * swap in a low-swap situation.  I don't think we'd
13401c7c3c6aSMatthew Dillon 			 * want to do that anyway, but it was an optimization
13411c7c3c6aSMatthew Dillon 			 * that existed in the old swapper for a time before
13421c7c3c6aSMatthew Dillon 			 * it got ripped out due to precisely this problem.
13431c7c3c6aSMatthew Dillon 			 *
13441c7c3c6aSMatthew Dillon 			 * clear PG_ZERO in page.
13451c7c3c6aSMatthew Dillon 			 *
13461c7c3c6aSMatthew Dillon 			 * If not the requested page then deactivate it.
13471c7c3c6aSMatthew Dillon 			 *
13481c7c3c6aSMatthew Dillon 			 * Note that the requested page, reqpage, is left
13491c7c3c6aSMatthew Dillon 			 * busied, but we still have to wake it up.  The
13501c7c3c6aSMatthew Dillon 			 * other pages are released (unbusied) by
13511c7c3c6aSMatthew Dillon 			 * vm_page_wakeup().  We do not set reqpage's
13521c7c3c6aSMatthew Dillon 			 * valid bits here, it is up to the caller.
13531c7c3c6aSMatthew Dillon 			 */
13541c7c3c6aSMatthew Dillon 
13551c7c3c6aSMatthew Dillon 			pmap_clear_modify(VM_PAGE_TO_PHYS(m));
13561c7c3c6aSMatthew Dillon 			m->valid = VM_PAGE_BITS_ALL;
13571c7c3c6aSMatthew Dillon 			m->dirty = 0;
13581c7c3c6aSMatthew Dillon 			vm_page_flag_clear(m, PG_ZERO);
13591c7c3c6aSMatthew Dillon 
13601c7c3c6aSMatthew Dillon 			/*
13611c7c3c6aSMatthew Dillon 			 * We have to wake specifically requested pages
13621c7c3c6aSMatthew Dillon 			 * up too because we cleared PG_SWAPINPROG and
13631c7c3c6aSMatthew Dillon 			 * could be waiting for it in getpages.  However,
13641c7c3c6aSMatthew Dillon 			 * be sure to not unbusy getpages specifically
13651c7c3c6aSMatthew Dillon 			 * requested page - getpages expects it to be
13661c7c3c6aSMatthew Dillon 			 * left busy.
13671c7c3c6aSMatthew Dillon 			 */
13681c7c3c6aSMatthew Dillon 			if (i != bp->b_pager.pg_reqpage) {
13691c7c3c6aSMatthew Dillon 				vm_page_deactivate(m);
13701c7c3c6aSMatthew Dillon 				vm_page_wakeup(m);
13711c7c3c6aSMatthew Dillon 			} else {
13721c7c3c6aSMatthew Dillon 				vm_page_flash(m);
13731c7c3c6aSMatthew Dillon 			}
13741c7c3c6aSMatthew Dillon 		} else {
13751c7c3c6aSMatthew Dillon 			/*
13761c7c3c6aSMatthew Dillon 			 * For write success, clear the modify and dirty
13771c7c3c6aSMatthew Dillon 			 * status, then finish the I/O ( which decrements the
13781c7c3c6aSMatthew Dillon 			 * busy count and possibly wakes waiter's up ).
13791c7c3c6aSMatthew Dillon 			 */
13801c7c3c6aSMatthew Dillon 			vm_page_protect(m, VM_PROT_READ);
13811c7c3c6aSMatthew Dillon 			pmap_clear_modify(VM_PAGE_TO_PHYS(m));
13821c7c3c6aSMatthew Dillon 			m->dirty = 0;
13831c7c3c6aSMatthew Dillon 			vm_page_io_finish(m);
1384ffc82b0aSJohn Dyson 		}
1385df8bae1dSRodney W. Grimes 	}
138626f9a767SRodney W. Grimes 
13871c7c3c6aSMatthew Dillon 	/*
13881c7c3c6aSMatthew Dillon 	 * adjust pip.  NOTE: the original parent may still have its own
13891c7c3c6aSMatthew Dillon 	 * pip refs on the object.
13901c7c3c6aSMatthew Dillon 	 */
13910d94caffSDavid Greenman 
13921c7c3c6aSMatthew Dillon 	if (object)
13931c7c3c6aSMatthew Dillon 		vm_object_pip_wakeupn(object, bp->b_npages);
139426f9a767SRodney W. Grimes 
13951c7c3c6aSMatthew Dillon 	/*
13961c7c3c6aSMatthew Dillon 	 * release the physical I/O buffer
13971c7c3c6aSMatthew Dillon 	 */
1398e47ed70bSJohn Dyson 
13991c7c3c6aSMatthew Dillon 	relpbuf(bp, ((bp->b_flags & B_READ) ? &nsw_rcount : &nsw_wcount));
1400e47ed70bSJohn Dyson 
140126f9a767SRodney W. Grimes 	splx(s);
140226f9a767SRodney W. Grimes }
14031c7c3c6aSMatthew Dillon 
14041c7c3c6aSMatthew Dillon /************************************************************************
14051c7c3c6aSMatthew Dillon  *				SWAP META DATA 				*
14061c7c3c6aSMatthew Dillon  ************************************************************************
14071c7c3c6aSMatthew Dillon  *
14081c7c3c6aSMatthew Dillon  *	These routines manipulate the swap metadata stored in the
14091c7c3c6aSMatthew Dillon  *	OBJT_SWAP object.
14101c7c3c6aSMatthew Dillon  *
14111c7c3c6aSMatthew Dillon  *	In fact, we just have a few counters in the vm_object_t.  The
14121c7c3c6aSMatthew Dillon  *	metadata is actually stored in a hash table.
14131c7c3c6aSMatthew Dillon  */
14141c7c3c6aSMatthew Dillon 
14151c7c3c6aSMatthew Dillon /*
14161c7c3c6aSMatthew Dillon  * SWP_PAGER_HASH() -	hash swap meta data
14171c7c3c6aSMatthew Dillon  *
14181c7c3c6aSMatthew Dillon  *	This is an inline helper function which hash the swapblk given
14191c7c3c6aSMatthew Dillon  *	the object and page index.  It returns a pointer to a pointer
14201c7c3c6aSMatthew Dillon  *	to the object, or a pointer to a NULL pointer if it could not
14211c7c3c6aSMatthew Dillon  *	find a swapblk.
14221c7c3c6aSMatthew Dillon  */
14231c7c3c6aSMatthew Dillon 
14241c7c3c6aSMatthew Dillon static __inline struct swblock **
14251c7c3c6aSMatthew Dillon swp_pager_hash(vm_object_t object, daddr_t index)
14261c7c3c6aSMatthew Dillon {
14271c7c3c6aSMatthew Dillon 	struct swblock **pswap;
14281c7c3c6aSMatthew Dillon 	struct swblock *swap;
14291c7c3c6aSMatthew Dillon 
14301c7c3c6aSMatthew Dillon 	index &= ~SWAP_META_MASK;
14311c7c3c6aSMatthew Dillon 	pswap = &swhash[(index ^ (int)(long)object) & swhash_mask];
14321c7c3c6aSMatthew Dillon 
14331c7c3c6aSMatthew Dillon 	while ((swap = *pswap) != NULL) {
14341c7c3c6aSMatthew Dillon 		if (swap->swb_object == object &&
14351c7c3c6aSMatthew Dillon 		    swap->swb_index == index
14361c7c3c6aSMatthew Dillon 		) {
14371c7c3c6aSMatthew Dillon 			break;
14381c7c3c6aSMatthew Dillon 		}
14391c7c3c6aSMatthew Dillon 		pswap = &swap->swb_hnext;
14401c7c3c6aSMatthew Dillon 	}
14411c7c3c6aSMatthew Dillon 	return(pswap);
14421c7c3c6aSMatthew Dillon }
14431c7c3c6aSMatthew Dillon 
14441c7c3c6aSMatthew Dillon /*
14451c7c3c6aSMatthew Dillon  * SWP_PAGER_META_BUILD() -	add swap block to swap meta data for object
14461c7c3c6aSMatthew Dillon  *
14471c7c3c6aSMatthew Dillon  *	We first convert the object to a swap object if it is a default
14481c7c3c6aSMatthew Dillon  *	object.
14491c7c3c6aSMatthew Dillon  *
14501c7c3c6aSMatthew Dillon  *	The specified swapblk is added to the object's swap metadata.  If
14511c7c3c6aSMatthew Dillon  *	the swapblk is not valid, it is freed instead.  Any previously
14521c7c3c6aSMatthew Dillon  *	assigned swapblk is freed.
14531c7c3c6aSMatthew Dillon  */
14541c7c3c6aSMatthew Dillon 
14551c7c3c6aSMatthew Dillon static void
14561c7c3c6aSMatthew Dillon swp_pager_meta_build(
14571c7c3c6aSMatthew Dillon 	vm_object_t object,
14581c7c3c6aSMatthew Dillon 	daddr_t index,
14591c7c3c6aSMatthew Dillon 	daddr_t swapblk,
14601c7c3c6aSMatthew Dillon 	int waitok
14611c7c3c6aSMatthew Dillon ) {
14621c7c3c6aSMatthew Dillon 	struct swblock *swap;
14631c7c3c6aSMatthew Dillon 	struct swblock **pswap;
14641c7c3c6aSMatthew Dillon 
14651c7c3c6aSMatthew Dillon 	/*
14661c7c3c6aSMatthew Dillon 	 * Convert default object to swap object if necessary
14671c7c3c6aSMatthew Dillon 	 */
14681c7c3c6aSMatthew Dillon 
14691c7c3c6aSMatthew Dillon 	if (object->type != OBJT_SWAP) {
14701c7c3c6aSMatthew Dillon 		object->type = OBJT_SWAP;
14711c7c3c6aSMatthew Dillon 		object->un_pager.swp.swp_bcount = 0;
14721c7c3c6aSMatthew Dillon 
14731c7c3c6aSMatthew Dillon 		if (object->handle != NULL) {
14741c7c3c6aSMatthew Dillon 			TAILQ_INSERT_TAIL(
14751c7c3c6aSMatthew Dillon 			    NOBJLIST(object->handle),
14761c7c3c6aSMatthew Dillon 			    object,
14771c7c3c6aSMatthew Dillon 			    pager_object_list
14781c7c3c6aSMatthew Dillon 			);
14791c7c3c6aSMatthew Dillon 		} else {
14801c7c3c6aSMatthew Dillon 			TAILQ_INSERT_TAIL(
14811c7c3c6aSMatthew Dillon 			    &swap_pager_un_object_list,
14821c7c3c6aSMatthew Dillon 			    object,
14831c7c3c6aSMatthew Dillon 			    pager_object_list
14841c7c3c6aSMatthew Dillon 			);
14851c7c3c6aSMatthew Dillon 		}
14861c7c3c6aSMatthew Dillon 	}
14871c7c3c6aSMatthew Dillon 
14881c7c3c6aSMatthew Dillon 	/*
14891c7c3c6aSMatthew Dillon 	 * Wait for free memory when waitok is TRUE prior to calling the
14901c7c3c6aSMatthew Dillon 	 * zone allocator.
14911c7c3c6aSMatthew Dillon 	 */
14921c7c3c6aSMatthew Dillon 
14931c7c3c6aSMatthew Dillon 	while (waitok && cnt.v_free_count == 0) {
14941c7c3c6aSMatthew Dillon 		VM_WAIT;
14951c7c3c6aSMatthew Dillon 	}
14961c7c3c6aSMatthew Dillon 
14971c7c3c6aSMatthew Dillon 	/*
14981c7c3c6aSMatthew Dillon 	 * If swapblk being added is invalid, just free it.
14991c7c3c6aSMatthew Dillon 	 */
15001c7c3c6aSMatthew Dillon 
15011c7c3c6aSMatthew Dillon 	if (swapblk & SWAPBLK_NONE) {
15021c7c3c6aSMatthew Dillon 		if (swapblk != SWAPBLK_NONE) {
15031c7c3c6aSMatthew Dillon 			swp_pager_freeswapspace(
15041c7c3c6aSMatthew Dillon 			    index,
15051c7c3c6aSMatthew Dillon 			    1
15061c7c3c6aSMatthew Dillon 			);
15071c7c3c6aSMatthew Dillon 			swapblk = SWAPBLK_NONE;
15081c7c3c6aSMatthew Dillon 		}
15091c7c3c6aSMatthew Dillon 	}
15101c7c3c6aSMatthew Dillon 
15111c7c3c6aSMatthew Dillon 	/*
15121c7c3c6aSMatthew Dillon 	 * Locate hash entry.  If not found create, but if we aren't adding
15131c7c3c6aSMatthew Dillon 	 * anything just return.
15141c7c3c6aSMatthew Dillon 	 */
15151c7c3c6aSMatthew Dillon 
15161c7c3c6aSMatthew Dillon 	pswap = swp_pager_hash(object, index);
15171c7c3c6aSMatthew Dillon 
15181c7c3c6aSMatthew Dillon 	if ((swap = *pswap) == NULL) {
15191c7c3c6aSMatthew Dillon 		int i;
15201c7c3c6aSMatthew Dillon 
15211c7c3c6aSMatthew Dillon 		if (swapblk == SWAPBLK_NONE)
15221c7c3c6aSMatthew Dillon 			return;
15231c7c3c6aSMatthew Dillon 
15241c7c3c6aSMatthew Dillon 		swap = *pswap = zalloc(swap_zone);
15251c7c3c6aSMatthew Dillon 
15261c7c3c6aSMatthew Dillon 		swap->swb_hnext = NULL;
15271c7c3c6aSMatthew Dillon 		swap->swb_object = object;
15281c7c3c6aSMatthew Dillon 		swap->swb_index = index & ~SWAP_META_MASK;
15291c7c3c6aSMatthew Dillon 		swap->swb_count = 0;
15301c7c3c6aSMatthew Dillon 
15311c7c3c6aSMatthew Dillon 		++object->un_pager.swp.swp_bcount;
15321c7c3c6aSMatthew Dillon 
15331c7c3c6aSMatthew Dillon 		for (i = 0; i < SWAP_META_PAGES; ++i)
15341c7c3c6aSMatthew Dillon 			swap->swb_pages[i] = SWAPBLK_NONE;
15351c7c3c6aSMatthew Dillon 	}
15361c7c3c6aSMatthew Dillon 
15371c7c3c6aSMatthew Dillon 	/*
15381c7c3c6aSMatthew Dillon 	 * Delete prior contents of metadata
15391c7c3c6aSMatthew Dillon 	 */
15401c7c3c6aSMatthew Dillon 
15411c7c3c6aSMatthew Dillon 	index &= SWAP_META_MASK;
15421c7c3c6aSMatthew Dillon 
15431c7c3c6aSMatthew Dillon 	if (swap->swb_pages[index] != SWAPBLK_NONE) {
15441c7c3c6aSMatthew Dillon 		swp_pager_freeswapspace(
15451c7c3c6aSMatthew Dillon 		    swap->swb_pages[index] & SWAPBLK_MASK,
15461c7c3c6aSMatthew Dillon 		    1
15471c7c3c6aSMatthew Dillon 		);
15481c7c3c6aSMatthew Dillon 		--swap->swb_count;
15491c7c3c6aSMatthew Dillon 	}
15501c7c3c6aSMatthew Dillon 
15511c7c3c6aSMatthew Dillon 	/*
15521c7c3c6aSMatthew Dillon 	 * Enter block into metadata
15531c7c3c6aSMatthew Dillon 	 */
15541c7c3c6aSMatthew Dillon 
15551c7c3c6aSMatthew Dillon 	swap->swb_pages[index] = swapblk;
15561c7c3c6aSMatthew Dillon 	++swap->swb_count;
15571c7c3c6aSMatthew Dillon }
15581c7c3c6aSMatthew Dillon 
15591c7c3c6aSMatthew Dillon /*
15601c7c3c6aSMatthew Dillon  * SWP_PAGER_META_FREE() - free a range of blocks in the object's swap metadata
15611c7c3c6aSMatthew Dillon  *
15621c7c3c6aSMatthew Dillon  *	The requested range of blocks is freed, with any associated swap
15631c7c3c6aSMatthew Dillon  *	returned to the swap bitmap.
15641c7c3c6aSMatthew Dillon  *
15651c7c3c6aSMatthew Dillon  *	This routine will free swap metadata structures as they are cleaned
15661c7c3c6aSMatthew Dillon  *	out.  This routine does *NOT* operate on swap metadata associated
15671c7c3c6aSMatthew Dillon  *	with resident pages.
15681c7c3c6aSMatthew Dillon  *
15691c7c3c6aSMatthew Dillon  *	This routine must be called at splvm()
15701c7c3c6aSMatthew Dillon  */
15711c7c3c6aSMatthew Dillon 
15721c7c3c6aSMatthew Dillon static void
15731c7c3c6aSMatthew Dillon swp_pager_meta_free(vm_object_t object, daddr_t index, daddr_t count)
15741c7c3c6aSMatthew Dillon {
15751c7c3c6aSMatthew Dillon 	if (object->type != OBJT_SWAP)
15761c7c3c6aSMatthew Dillon 		return;
15771c7c3c6aSMatthew Dillon 
15781c7c3c6aSMatthew Dillon 	while (count > 0) {
15791c7c3c6aSMatthew Dillon 		struct swblock **pswap;
15801c7c3c6aSMatthew Dillon 		struct swblock *swap;
15811c7c3c6aSMatthew Dillon 
15821c7c3c6aSMatthew Dillon 		pswap = swp_pager_hash(object, index);
15831c7c3c6aSMatthew Dillon 
15841c7c3c6aSMatthew Dillon 		if ((swap = *pswap) != NULL) {
15851c7c3c6aSMatthew Dillon 			daddr_t v = swap->swb_pages[index & SWAP_META_MASK];
15861c7c3c6aSMatthew Dillon 
15871c7c3c6aSMatthew Dillon 			if (v != SWAPBLK_NONE) {
15881c7c3c6aSMatthew Dillon 				swp_pager_freeswapspace(v, 1);
15891c7c3c6aSMatthew Dillon 				swap->swb_pages[index & SWAP_META_MASK] =
15901c7c3c6aSMatthew Dillon 					SWAPBLK_NONE;
15911c7c3c6aSMatthew Dillon 				if (--swap->swb_count == 0) {
15921c7c3c6aSMatthew Dillon 					*pswap = swap->swb_hnext;
15931c7c3c6aSMatthew Dillon 					zfree(swap_zone, swap);
15941c7c3c6aSMatthew Dillon 					--object->un_pager.swp.swp_bcount;
15951c7c3c6aSMatthew Dillon 				}
15961c7c3c6aSMatthew Dillon 			}
15971c7c3c6aSMatthew Dillon 			--count;
15981c7c3c6aSMatthew Dillon 			++index;
15991c7c3c6aSMatthew Dillon 		} else {
16001c7c3c6aSMatthew Dillon 			daddr_t n = SWAP_META_PAGES - (index & SWAP_META_MASK);
16011c7c3c6aSMatthew Dillon 			count -= n;
16021c7c3c6aSMatthew Dillon 			index += n;
16031c7c3c6aSMatthew Dillon 		}
16041c7c3c6aSMatthew Dillon 	}
16051c7c3c6aSMatthew Dillon }
16061c7c3c6aSMatthew Dillon 
16071c7c3c6aSMatthew Dillon /*
16081c7c3c6aSMatthew Dillon  * SWP_PAGER_META_FREE_ALL() - destroy all swap metadata associated with object
16091c7c3c6aSMatthew Dillon  *
16101c7c3c6aSMatthew Dillon  *	This routine locates and destroys all swap metadata associated with
16111c7c3c6aSMatthew Dillon  *	an object.
16121c7c3c6aSMatthew Dillon  */
16131c7c3c6aSMatthew Dillon 
16141c7c3c6aSMatthew Dillon static void
16151c7c3c6aSMatthew Dillon swp_pager_meta_free_all(vm_object_t object)
16161c7c3c6aSMatthew Dillon {
16171c7c3c6aSMatthew Dillon 	daddr_t index = 0;
16181c7c3c6aSMatthew Dillon 
16191c7c3c6aSMatthew Dillon 	if (object->type != OBJT_SWAP)
16201c7c3c6aSMatthew Dillon 		return;
16211c7c3c6aSMatthew Dillon 
16221c7c3c6aSMatthew Dillon 	while (object->un_pager.swp.swp_bcount) {
16231c7c3c6aSMatthew Dillon 		struct swblock **pswap;
16241c7c3c6aSMatthew Dillon 		struct swblock *swap;
16251c7c3c6aSMatthew Dillon 
16261c7c3c6aSMatthew Dillon 		pswap = swp_pager_hash(object, index);
16271c7c3c6aSMatthew Dillon 		if ((swap = *pswap) != NULL) {
16281c7c3c6aSMatthew Dillon 			int i;
16291c7c3c6aSMatthew Dillon 
16301c7c3c6aSMatthew Dillon 			for (i = 0; i < SWAP_META_PAGES; ++i) {
16311c7c3c6aSMatthew Dillon 				daddr_t v = swap->swb_pages[i];
16321c7c3c6aSMatthew Dillon 				if (v != SWAPBLK_NONE) {
16331c7c3c6aSMatthew Dillon #if !defined(MAX_PERF)
16341c7c3c6aSMatthew Dillon 					--swap->swb_count;
16351c7c3c6aSMatthew Dillon #endif
16361c7c3c6aSMatthew Dillon 					swp_pager_freeswapspace(
16371c7c3c6aSMatthew Dillon 					    v,
16381c7c3c6aSMatthew Dillon 					    1
16391c7c3c6aSMatthew Dillon 					);
16401c7c3c6aSMatthew Dillon 				}
16411c7c3c6aSMatthew Dillon 			}
16421c7c3c6aSMatthew Dillon #if !defined(MAX_PERF)
16431c7c3c6aSMatthew Dillon 			if (swap->swb_count != 0)
16441c7c3c6aSMatthew Dillon 				panic("swap_pager_meta_free_all: swb_count != 0");
16451c7c3c6aSMatthew Dillon #endif
16461c7c3c6aSMatthew Dillon 			*pswap = swap->swb_hnext;
16471c7c3c6aSMatthew Dillon 			zfree(swap_zone, swap);
16481c7c3c6aSMatthew Dillon 			--object->un_pager.swp.swp_bcount;
16491c7c3c6aSMatthew Dillon 		}
16501c7c3c6aSMatthew Dillon 		index += SWAP_META_PAGES;
16511c7c3c6aSMatthew Dillon #if !defined(MAX_PERF)
16521c7c3c6aSMatthew Dillon 		if (index > 0x20000000)
16531c7c3c6aSMatthew Dillon 			panic("swp_pager_meta_free_all: failed to locate all swap meta blocks");
16541c7c3c6aSMatthew Dillon #endif
16551c7c3c6aSMatthew Dillon 	}
16561c7c3c6aSMatthew Dillon }
16571c7c3c6aSMatthew Dillon 
16581c7c3c6aSMatthew Dillon /*
16591c7c3c6aSMatthew Dillon  * SWP_PAGER_METACTL() -  misc control of swap and vm_page_t meta data.
16601c7c3c6aSMatthew Dillon  *
16611c7c3c6aSMatthew Dillon  *	This routine is capable of looking up, popping, or freeing
16621c7c3c6aSMatthew Dillon  *	swapblk assignments in the swap meta data or in the vm_page_t.
16631c7c3c6aSMatthew Dillon  *	The routine typically returns the swapblk being looked-up, or popped,
16641c7c3c6aSMatthew Dillon  *	or SWAPBLK_NONE if the block was freed, or SWAPBLK_NONE if the block
16651c7c3c6aSMatthew Dillon  *	was invalid.  This routine will automatically free any invalid
16661c7c3c6aSMatthew Dillon  *	meta-data swapblks.
16671c7c3c6aSMatthew Dillon  *
16681c7c3c6aSMatthew Dillon  *	It is not possible to store invalid swapblks in the swap meta data
16691c7c3c6aSMatthew Dillon  *	(other then a literal 'SWAPBLK_NONE'), so we don't bother checking.
16701c7c3c6aSMatthew Dillon  *
16711c7c3c6aSMatthew Dillon  *	When acting on a busy resident page and paging is in progress, we
16721c7c3c6aSMatthew Dillon  *	have to wait until paging is complete but otherwise can act on the
16731c7c3c6aSMatthew Dillon  *	busy page.
16741c7c3c6aSMatthew Dillon  *
16751c7c3c6aSMatthew Dillon  *	SWM_FREE	remove and free swap block from metadata
16761c7c3c6aSMatthew Dillon  *
16771c7c3c6aSMatthew Dillon  *	SWM_POP		remove from meta data but do not free.. pop it out
16781c7c3c6aSMatthew Dillon  */
16791c7c3c6aSMatthew Dillon 
16801c7c3c6aSMatthew Dillon static daddr_t
16811c7c3c6aSMatthew Dillon swp_pager_meta_ctl(
16821c7c3c6aSMatthew Dillon 	vm_object_t object,
16831c7c3c6aSMatthew Dillon 	vm_pindex_t index,
16841c7c3c6aSMatthew Dillon 	int flags
16851c7c3c6aSMatthew Dillon ) {
16861c7c3c6aSMatthew Dillon 	/*
16871c7c3c6aSMatthew Dillon 	 * The meta data only exists of the object is OBJT_SWAP
16881c7c3c6aSMatthew Dillon 	 * and even then might not be allocated yet.
16891c7c3c6aSMatthew Dillon 	 */
16901c7c3c6aSMatthew Dillon 
16911c7c3c6aSMatthew Dillon 	if (
16921c7c3c6aSMatthew Dillon 	    object->type != OBJT_SWAP ||
16931c7c3c6aSMatthew Dillon 	    object->un_pager.swp.swp_bcount == 0
16941c7c3c6aSMatthew Dillon 	) {
16951c7c3c6aSMatthew Dillon 		return(SWAPBLK_NONE);
16961c7c3c6aSMatthew Dillon 	}
16971c7c3c6aSMatthew Dillon 
16981c7c3c6aSMatthew Dillon 	{
16991c7c3c6aSMatthew Dillon 		struct swblock **pswap;
17001c7c3c6aSMatthew Dillon 		struct swblock *swap;
17011c7c3c6aSMatthew Dillon 		daddr_t r1 = SWAPBLK_NONE;
17021c7c3c6aSMatthew Dillon 
17031c7c3c6aSMatthew Dillon 		pswap = swp_pager_hash(object, index);
17041c7c3c6aSMatthew Dillon 
17051c7c3c6aSMatthew Dillon 		index &= SWAP_META_MASK;
17061c7c3c6aSMatthew Dillon 
17071c7c3c6aSMatthew Dillon 		if ((swap = *pswap) != NULL) {
17081c7c3c6aSMatthew Dillon 			r1 = swap->swb_pages[index];
17091c7c3c6aSMatthew Dillon 
17101c7c3c6aSMatthew Dillon 			if (r1 != SWAPBLK_NONE) {
17111c7c3c6aSMatthew Dillon 				if (flags & SWM_FREE) {
17121c7c3c6aSMatthew Dillon 					swp_pager_freeswapspace(
17131c7c3c6aSMatthew Dillon 					    r1,
17141c7c3c6aSMatthew Dillon 					    1
17151c7c3c6aSMatthew Dillon 					);
17161c7c3c6aSMatthew Dillon 					r1 = SWAPBLK_NONE;
17171c7c3c6aSMatthew Dillon 				}
17181c7c3c6aSMatthew Dillon 				if (flags & (SWM_FREE|SWM_POP)) {
17191c7c3c6aSMatthew Dillon 					swap->swb_pages[index] = SWAPBLK_NONE;
17201c7c3c6aSMatthew Dillon 					if (--swap->swb_count == 0) {
17211c7c3c6aSMatthew Dillon 						*pswap = swap->swb_hnext;
17221c7c3c6aSMatthew Dillon 						zfree(swap_zone, swap);
17231c7c3c6aSMatthew Dillon 						--object->un_pager.swp.swp_bcount;
17241c7c3c6aSMatthew Dillon 					}
17251c7c3c6aSMatthew Dillon 				}
17261c7c3c6aSMatthew Dillon 	 		}
17271c7c3c6aSMatthew Dillon 		}
17281c7c3c6aSMatthew Dillon 
17291c7c3c6aSMatthew Dillon 		return(r1);
17301c7c3c6aSMatthew Dillon 	}
17311c7c3c6aSMatthew Dillon 	/* not reached */
17321c7c3c6aSMatthew Dillon }
17331c7c3c6aSMatthew Dillon 
1734