xref: /freebsd/sys/vm/swap_pager.c (revision 1c7c3c6a869e5eb64a19fda327dbe9f37af584b2)
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  *
671c7c3c6aSMatthew Dillon  * $Id: swap_pager.c,v 1.107 1999/01/10 01:58:28 eivind 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	*/
1691c7c3c6aSMatthew Dillon int nswap_hiwat = 256;		/* 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) {
206a1f6d91cSDavid Greenman 		if (swap_pager_full == 0)
2071af87c92SDavid Greenman 			printf("swap_pager: out of swap space\n");
20826f9a767SRodney W. Grimes 		swap_pager_full = 1;
2091c7c3c6aSMatthew Dillon 	} else if (vm_swap_size > nswap_hiwat) {
21026f9a767SRodney W. Grimes 		swap_pager_full = 0;
21126f9a767SRodney W. Grimes 	}
2121c7c3c6aSMatthew Dillon }
2131c7c3c6aSMatthew Dillon 
2141c7c3c6aSMatthew Dillon /*
2151c7c3c6aSMatthew Dillon  * SWAP_PAGER_INIT() -	initialize the swap pager!
2161c7c3c6aSMatthew Dillon  *
2171c7c3c6aSMatthew Dillon  *	Expected to be started from system init.  NOTE:  This code is run
2181c7c3c6aSMatthew Dillon  *	before much else so be careful what you depend on.  Most of the VM
2191c7c3c6aSMatthew Dillon  *	system has yet to be initialized at this point.
2201c7c3c6aSMatthew Dillon  */
22126f9a767SRodney W. Grimes 
222f5a12711SPoul-Henning Kamp static void
223df8bae1dSRodney W. Grimes swap_pager_init()
224df8bae1dSRodney W. Grimes {
2251c7c3c6aSMatthew Dillon 	/*
2261c7c3c6aSMatthew Dillon 	 * Initialize object lists
2271c7c3c6aSMatthew Dillon 	 */
2281c7c3c6aSMatthew Dillon 	int i;
2291c7c3c6aSMatthew Dillon 
2301c7c3c6aSMatthew Dillon 	for (i = 0; i < NOBJLISTS; ++i)
2311c7c3c6aSMatthew Dillon 		TAILQ_INIT(&swap_pager_object_list[i]);
23224a1cce3SDavid Greenman 	TAILQ_INIT(&swap_pager_un_object_list);
233df8bae1dSRodney W. Grimes 
234df8bae1dSRodney W. Grimes 	/*
2351c7c3c6aSMatthew Dillon 	 * Device Stripe, in PAGE_SIZE'd blocks
236df8bae1dSRodney W. Grimes 	 */
2371c7c3c6aSMatthew Dillon 
2381c7c3c6aSMatthew Dillon 	dmmax = SWB_NPAGES * 2;
2391c7c3c6aSMatthew Dillon 	dmmax_mask = ~(dmmax - 1);
2401c7c3c6aSMatthew Dillon }
24126f9a767SRodney W. Grimes 
242df8bae1dSRodney W. Grimes /*
2431c7c3c6aSMatthew Dillon  * SWAP_PAGER_SWAP_INIT() - swap pager initialization from pageout process
2441c7c3c6aSMatthew Dillon  *
2451c7c3c6aSMatthew Dillon  *	Expected to be started from pageout process once, prior to entering
2461c7c3c6aSMatthew Dillon  *	its main loop.
247df8bae1dSRodney W. Grimes  */
248df8bae1dSRodney W. Grimes 
24924a1cce3SDavid Greenman void
25024a1cce3SDavid Greenman swap_pager_swap_init()
251df8bae1dSRodney W. Grimes {
2521c7c3c6aSMatthew Dillon 	int n;
2530d94caffSDavid Greenman 
25426f9a767SRodney W. Grimes 	/*
2551c7c3c6aSMatthew Dillon 	 * Number of in-transit swap bp operations.  Don't
2561c7c3c6aSMatthew Dillon 	 * exhaust the pbufs completely.  Make sure we
2571c7c3c6aSMatthew Dillon 	 * initialize workable values (0 will work for hysteresis
2581c7c3c6aSMatthew Dillon 	 * but it isn't very efficient).
2591c7c3c6aSMatthew Dillon 	 *
2601c7c3c6aSMatthew Dillon 	 * The max_pageout_cluster is constrained by the bp->b_pages[]
2611c7c3c6aSMatthew Dillon 	 * array (MAXPHYS/PAGE_SIZE) and our locally defined
2621c7c3c6aSMatthew Dillon 	 * MAX_PAGEOUT_CLUSTER.   Also be aware that swap ops are
2631c7c3c6aSMatthew Dillon 	 * constrained by the swap device interleave stripe size.
26426f9a767SRodney W. Grimes 	 */
26524a1cce3SDavid Greenman 
2661c7c3c6aSMatthew Dillon 	nsw_rcount = (nswbuf + 1) / 2;
2671c7c3c6aSMatthew Dillon 	nsw_wcount = (nswbuf + 3) / 4;
2681c7c3c6aSMatthew Dillon 	nsw_hysteresis = nsw_wcount / 2;
2691c7c3c6aSMatthew Dillon 	max_pageout_cluster = min((MAXPHYS/PAGE_SIZE), MAX_PAGEOUT_CLUSTER);
27024a1cce3SDavid Greenman 
2711c7c3c6aSMatthew Dillon 	/*
2721c7c3c6aSMatthew Dillon 	 * Initialize our zone.  Right now I'm just guessing on the number
2731c7c3c6aSMatthew Dillon 	 * we need based on the number of pages in the system.  Each swblock
2741c7c3c6aSMatthew Dillon 	 * can hold 16 pages, so this is probably overkill.
2751c7c3c6aSMatthew Dillon 	 */
27624a1cce3SDavid Greenman 
2771c7c3c6aSMatthew Dillon 	n = cnt.v_page_count * 2;
27826f9a767SRodney W. Grimes 
2791c7c3c6aSMatthew Dillon 	swap_zone = zinit(
2801c7c3c6aSMatthew Dillon 	    "SWAPMETA",
2811c7c3c6aSMatthew Dillon 	    sizeof(struct swblock),
2821c7c3c6aSMatthew Dillon 	    n,
2831c7c3c6aSMatthew Dillon 	    ZONE_INTERRUPT,
2841c7c3c6aSMatthew Dillon 	    1
2851c7c3c6aSMatthew Dillon 	);
28624a1cce3SDavid Greenman 
2871c7c3c6aSMatthew Dillon 	/*
2881c7c3c6aSMatthew Dillon 	 * Initialize our meta-data hash table.  The swapper does not need to
2891c7c3c6aSMatthew Dillon 	 * be quite as efficient as the VM system, so we do not use an
2901c7c3c6aSMatthew Dillon 	 * oversized hash table.
2911c7c3c6aSMatthew Dillon 	 *
2921c7c3c6aSMatthew Dillon 	 * 	n: 		size of hash table, must be power of 2
2931c7c3c6aSMatthew Dillon 	 *	swhash_mask:	hash table index mask
2941c7c3c6aSMatthew Dillon 	 */
295df8bae1dSRodney W. Grimes 
2961c7c3c6aSMatthew Dillon 	for (n = 1; n < cnt.v_page_count / 4; n <<= 1)
2971c7c3c6aSMatthew Dillon 		;
2981c7c3c6aSMatthew Dillon 
2991c7c3c6aSMatthew Dillon 	swhash = malloc(sizeof(struct swblock *) * n, M_VMPGDATA, M_WAITOK);
3001c7c3c6aSMatthew Dillon 	bzero(swhash, sizeof(struct swblock *) * n);
3011c7c3c6aSMatthew Dillon 
3021c7c3c6aSMatthew Dillon 	swhash_mask = n - 1;
30324a1cce3SDavid Greenman }
30424a1cce3SDavid Greenman 
30524a1cce3SDavid Greenman /*
3061c7c3c6aSMatthew Dillon  * SWAP_PAGER_ALLOC() -	allocate a new OBJT_SWAP VM object and instantiate
3071c7c3c6aSMatthew Dillon  *			its metadata structures.
3081c7c3c6aSMatthew Dillon  *
3091c7c3c6aSMatthew Dillon  *	This routine is called from the mmap and fork code to create a new
3101c7c3c6aSMatthew Dillon  *	OBJT_SWAP object.  We do this by creating an OBJT_DEFAULT object
3111c7c3c6aSMatthew Dillon  *	and then converting it with swp_pager_meta_build().
3121c7c3c6aSMatthew Dillon  *
3131c7c3c6aSMatthew Dillon  *	This routine may block in vm_object_allocate() and create a named
3141c7c3c6aSMatthew Dillon  *	object lookup race, so we must interlock.   We must also run at
3151c7c3c6aSMatthew Dillon  *	splvm() for the object lookup to handle races with interrupts, but
3161c7c3c6aSMatthew Dillon  *	we do not have to maintain splvm() in between the lookup and the
3171c7c3c6aSMatthew Dillon  *	add because (I believe) it is not possible to attempt to create
3181c7c3c6aSMatthew Dillon  *	a new swap object w/handle when a default object with that handle
3191c7c3c6aSMatthew Dillon  *	already exists.
32024a1cce3SDavid Greenman  */
3211c7c3c6aSMatthew Dillon 
322f5a12711SPoul-Henning Kamp static vm_object_t
3236cde7a16SDavid Greenman swap_pager_alloc(void *handle, vm_ooffset_t size, vm_prot_t prot,
324b9dcd593SBruce Evans 		 vm_ooffset_t offset)
32524a1cce3SDavid Greenman {
32624a1cce3SDavid Greenman 	vm_object_t object;
32724a1cce3SDavid Greenman 
32824a1cce3SDavid Greenman 	if (handle) {
3291c7c3c6aSMatthew Dillon 		/*
3301c7c3c6aSMatthew Dillon 		 * Reference existing named region or allocate new one.  There
3311c7c3c6aSMatthew Dillon 		 * should not be a race here against swp_pager_meta_build()
3321c7c3c6aSMatthew Dillon 		 * as called from vm_page_remove() in regards to the lookup
3331c7c3c6aSMatthew Dillon 		 * of the handle.
3341c7c3c6aSMatthew Dillon 		 */
3351c7c3c6aSMatthew Dillon 
3361c7c3c6aSMatthew Dillon 		while (sw_alloc_interlock) {
3371c7c3c6aSMatthew Dillon 			sw_alloc_interlock = -1;
3381c7c3c6aSMatthew Dillon 			tsleep(&sw_alloc_interlock, PVM, "swpalc", 0);
3391c7c3c6aSMatthew Dillon 		}
3401c7c3c6aSMatthew Dillon 		sw_alloc_interlock = 1;
3411c7c3c6aSMatthew Dillon 
3421c7c3c6aSMatthew Dillon 		object = vm_pager_object_lookup(NOBJLIST(handle), handle);
3431c7c3c6aSMatthew Dillon 
34424a1cce3SDavid Greenman 		if (object != NULL) {
34524a1cce3SDavid Greenman 			vm_object_reference(object);
34624a1cce3SDavid Greenman 		} else {
3471c7c3c6aSMatthew Dillon 			object = vm_object_allocate(OBJT_DEFAULT,
3486cde7a16SDavid Greenman 				OFF_TO_IDX(offset + PAGE_MASK + size));
34924a1cce3SDavid Greenman 			object->handle = handle;
3501c7c3c6aSMatthew Dillon 
3511c7c3c6aSMatthew Dillon 			swp_pager_meta_build(
3521c7c3c6aSMatthew Dillon 			    object,
3531c7c3c6aSMatthew Dillon 			    0,
3541c7c3c6aSMatthew Dillon 			    SWAPBLK_NONE,
3551c7c3c6aSMatthew Dillon 			    0
3561c7c3c6aSMatthew Dillon 			);
35724a1cce3SDavid Greenman 		}
3581c7c3c6aSMatthew Dillon 
3591c7c3c6aSMatthew Dillon 		if (sw_alloc_interlock < 0)
3601c7c3c6aSMatthew Dillon 			wakeup(&sw_alloc_interlock);
3611c7c3c6aSMatthew Dillon 
3621c7c3c6aSMatthew Dillon 		sw_alloc_interlock = 0;
36324a1cce3SDavid Greenman 	} else {
3641c7c3c6aSMatthew Dillon 		object = vm_object_allocate(OBJT_DEFAULT,
3656cde7a16SDavid Greenman 			OFF_TO_IDX(offset + PAGE_MASK + size));
3661c7c3c6aSMatthew Dillon 
3671c7c3c6aSMatthew Dillon 		swp_pager_meta_build(
3681c7c3c6aSMatthew Dillon 		    object,
3691c7c3c6aSMatthew Dillon 		    0,
3701c7c3c6aSMatthew Dillon 		    SWAPBLK_NONE,
3711c7c3c6aSMatthew Dillon 		    0
3721c7c3c6aSMatthew Dillon 		);
37324a1cce3SDavid Greenman 	}
37424a1cce3SDavid Greenman 
37524a1cce3SDavid Greenman 	return (object);
376df8bae1dSRodney W. Grimes }
377df8bae1dSRodney W. Grimes 
37826f9a767SRodney W. Grimes /*
3791c7c3c6aSMatthew Dillon  * SWAP_PAGER_DEALLOC() -	remove swap metadata from object
3801c7c3c6aSMatthew Dillon  *
3811c7c3c6aSMatthew Dillon  *	The swap backing for the object is destroyed.  The code is
3821c7c3c6aSMatthew Dillon  *	designed such that we can reinstantiate it later, but this
3831c7c3c6aSMatthew Dillon  *	routine is typically called only when the entire object is
3841c7c3c6aSMatthew Dillon  *	about to be destroyed.
3851c7c3c6aSMatthew Dillon  *
3861c7c3c6aSMatthew Dillon  *	This routine may block, but no longer does.
3871c7c3c6aSMatthew Dillon  *
3881c7c3c6aSMatthew Dillon  *	The object must be locked or unreferenceable.
38926f9a767SRodney W. Grimes  */
39026f9a767SRodney W. Grimes 
391df8bae1dSRodney W. Grimes static void
3921c7c3c6aSMatthew Dillon swap_pager_dealloc(object)
3932a4895f4SDavid Greenman 	vm_object_t object;
39426f9a767SRodney W. Grimes {
39526f9a767SRodney W. Grimes 	/*
3961c7c3c6aSMatthew Dillon 	 * Remove from list right away so lookups will fail if we block for
3971c7c3c6aSMatthew Dillon 	 * pageout completion.
39826f9a767SRodney W. Grimes 	 */
399b44e4b7aSJohn Dyson 
4001c7c3c6aSMatthew Dillon 	if (object->handle == NULL) {
4011c7c3c6aSMatthew Dillon 		TAILQ_REMOVE(&swap_pager_un_object_list, object, pager_object_list);
40224ea4a96SDavid Greenman 	} else {
4031c7c3c6aSMatthew Dillon 		TAILQ_REMOVE(NOBJLIST(object->handle), object, pager_object_list);
40426f9a767SRodney W. Grimes 	}
4051c7c3c6aSMatthew Dillon 
4061c7c3c6aSMatthew Dillon 	vm_object_pip_wait(object, "swpdea");
4071c7c3c6aSMatthew Dillon 
4081c7c3c6aSMatthew Dillon 	/*
4091c7c3c6aSMatthew Dillon 	 * Free all remaining metadata.  We only bother to free it from
4101c7c3c6aSMatthew Dillon 	 * the swap meta data.  We do not attempt to free swapblk's still
4111c7c3c6aSMatthew Dillon 	 * associated with vm_page_t's for this object.  We do not care
4121c7c3c6aSMatthew Dillon 	 * if paging is still in progress on some objects.
4131c7c3c6aSMatthew Dillon 	 */
4141c7c3c6aSMatthew Dillon 
4151c7c3c6aSMatthew Dillon 	swp_pager_meta_free_all(object);
4161c7c3c6aSMatthew Dillon }
4171c7c3c6aSMatthew Dillon 
4181c7c3c6aSMatthew Dillon /************************************************************************
4191c7c3c6aSMatthew Dillon  *			SWAP PAGER BITMAP ROUTINES			*
4201c7c3c6aSMatthew Dillon  ************************************************************************/
4211c7c3c6aSMatthew Dillon 
4221c7c3c6aSMatthew Dillon /*
4231c7c3c6aSMatthew Dillon  * SWP_PAGER_GETSWAPSPACE() -	allocate raw swap space
4241c7c3c6aSMatthew Dillon  *
4251c7c3c6aSMatthew Dillon  *	Allocate swap for the requested number of pages.  The starting
4261c7c3c6aSMatthew Dillon  *	swap block number (a page index) is returned or SWAPBLK_NONE
4271c7c3c6aSMatthew Dillon  *	if the allocation failed.
4281c7c3c6aSMatthew Dillon  *
4291c7c3c6aSMatthew Dillon  *	Also has the side effect of advising that somebody made a mistake
4301c7c3c6aSMatthew Dillon  *	when they configured swap and didn't configure enough.
4311c7c3c6aSMatthew Dillon  *
4321c7c3c6aSMatthew Dillon  *	Must be called at splvm() to avoid races with bitmap frees from
4331c7c3c6aSMatthew Dillon  *	vm_page_remove() aka swap_pager_page_removed().
4341c7c3c6aSMatthew Dillon  *
4351c7c3c6aSMatthew Dillon  *	This routine may not block
4361c7c3c6aSMatthew Dillon  *	This routine must be called at splvm().
4371c7c3c6aSMatthew Dillon  */
4381c7c3c6aSMatthew Dillon 
4391c7c3c6aSMatthew Dillon static __inline daddr_t
4401c7c3c6aSMatthew Dillon swp_pager_getswapspace(npages)
4411c7c3c6aSMatthew Dillon 	int npages;
4421c7c3c6aSMatthew Dillon {
4431c7c3c6aSMatthew Dillon 	daddr_t blk;
4441c7c3c6aSMatthew Dillon 
4451c7c3c6aSMatthew Dillon 	if ((blk = blist_alloc(swapblist, npages)) == SWAPBLK_NONE) {
4461c7c3c6aSMatthew Dillon 		printf("swap_pager_getswapspace: failed\n");
4471c7c3c6aSMatthew Dillon 	} else {
4481c7c3c6aSMatthew Dillon 		vm_swap_size -= npages;
4491c7c3c6aSMatthew Dillon 		swp_sizecheck();
4501c7c3c6aSMatthew Dillon 	}
4511c7c3c6aSMatthew Dillon 	return(blk);
45226f9a767SRodney W. Grimes }
45326f9a767SRodney W. Grimes 
45426f9a767SRodney W. Grimes /*
4551c7c3c6aSMatthew Dillon  * SWP_PAGER_FREESWAPSPACE() -	free raw swap space
4561c7c3c6aSMatthew Dillon  *
4571c7c3c6aSMatthew Dillon  *	This routine returns the specified swap blocks back to the bitmap.
4581c7c3c6aSMatthew Dillon  *
4591c7c3c6aSMatthew Dillon  *	Note:  This routine may not block (it could in the old swap code),
4601c7c3c6aSMatthew Dillon  *	and through the use of the new blist routines it does not block.
4611c7c3c6aSMatthew Dillon  *
4621c7c3c6aSMatthew Dillon  *	We must be called at splvm() to avoid races with bitmap frees from
4631c7c3c6aSMatthew Dillon  *	vm_page_remove() aka swap_pager_page_removed().
4641c7c3c6aSMatthew Dillon  *
4651c7c3c6aSMatthew Dillon  *	This routine may not block
4661c7c3c6aSMatthew Dillon  *	This routine must be called at splvm().
46726f9a767SRodney W. Grimes  */
4681c7c3c6aSMatthew Dillon 
4691c7c3c6aSMatthew Dillon static __inline void
4701c7c3c6aSMatthew Dillon swp_pager_freeswapspace(blk, npages)
4711c7c3c6aSMatthew Dillon 	daddr_t blk;
4721c7c3c6aSMatthew Dillon 	int npages;
4730d94caffSDavid Greenman {
4741c7c3c6aSMatthew Dillon 	blist_free(swapblist, blk, npages);
4751c7c3c6aSMatthew Dillon 	vm_swap_size += npages;
4761c7c3c6aSMatthew Dillon 	swp_sizecheck();
47726f9a767SRodney W. Grimes }
4781c7c3c6aSMatthew Dillon 
47926f9a767SRodney W. Grimes /*
4801c7c3c6aSMatthew Dillon  * SWAP_PAGER_FREESPACE() -	frees swap blocks associated with a page
4811c7c3c6aSMatthew Dillon  *				range within an object.
4821c7c3c6aSMatthew Dillon  *
4831c7c3c6aSMatthew Dillon  *	This is a globally accessible routine.
4841c7c3c6aSMatthew Dillon  *
4851c7c3c6aSMatthew Dillon  *	This routine removes swapblk assignments from swap metadata.
4861c7c3c6aSMatthew Dillon  *
4871c7c3c6aSMatthew Dillon  *	The external callers of this routine typically have already destroyed
4881c7c3c6aSMatthew Dillon  *	or renamed vm_page_t's associated with this range in the object so
4891c7c3c6aSMatthew Dillon  *	we should be ok.
49026f9a767SRodney W. Grimes  */
4911c7c3c6aSMatthew Dillon 
49226f9a767SRodney W. Grimes void
49324a1cce3SDavid Greenman swap_pager_freespace(object, start, size)
49424a1cce3SDavid Greenman 	vm_object_t object;
495a316d390SJohn Dyson 	vm_pindex_t start;
496a316d390SJohn Dyson 	vm_size_t size;
49726f9a767SRodney W. Grimes {
4981c7c3c6aSMatthew Dillon 	swp_pager_meta_free(object, start, size);
49926f9a767SRodney W. Grimes }
50026f9a767SRodney W. Grimes 
5010a47b48bSJohn Dyson /*
5021c7c3c6aSMatthew Dillon  * SWAP_PAGER_COPY() -  copy blocks from source pager to destination pager
5031c7c3c6aSMatthew Dillon  *			and destroy the source.
5041c7c3c6aSMatthew Dillon  *
5051c7c3c6aSMatthew Dillon  *	Copy any valid swapblks from the source to the destination.  In
5061c7c3c6aSMatthew Dillon  *	cases where both the source and destination have a valid swapblk,
5071c7c3c6aSMatthew Dillon  *	we keep the destination's.
5081c7c3c6aSMatthew Dillon  *
5091c7c3c6aSMatthew Dillon  *	This routine is allowed to block.  It may block allocating metadata
5101c7c3c6aSMatthew Dillon  *	indirectly through swp_pager_meta_build() or if paging is still in
5111c7c3c6aSMatthew Dillon  *	progress on the source.
5121c7c3c6aSMatthew Dillon  *
5131c7c3c6aSMatthew Dillon  *	XXX vm_page_collapse() kinda expects us not to block because we
5141c7c3c6aSMatthew Dillon  *	supposedly do not need to allocate memory, but for the moment we
5151c7c3c6aSMatthew Dillon  *	*may* have to get a little memory from the zone allocator, but
5161c7c3c6aSMatthew Dillon  *	it is taken from the interrupt memory.  We should be ok.
5171c7c3c6aSMatthew Dillon  *
5181c7c3c6aSMatthew Dillon  *	The source object contains no vm_page_t's (which is just as well)
5191c7c3c6aSMatthew Dillon  *
5201c7c3c6aSMatthew Dillon  *	The source object is of type OBJT_SWAP.
5211c7c3c6aSMatthew Dillon  *
5221c7c3c6aSMatthew Dillon  *	The source and destination objects must be
5231c7c3c6aSMatthew Dillon  *	locked or inaccessible (XXX are they ???)
52426f9a767SRodney W. Grimes  */
52526f9a767SRodney W. Grimes 
52626f9a767SRodney W. Grimes void
5271c7c3c6aSMatthew Dillon swap_pager_copy(srcobject, dstobject, offset, destroysource)
52824a1cce3SDavid Greenman 	vm_object_t srcobject;
52924a1cce3SDavid Greenman 	vm_object_t dstobject;
530a316d390SJohn Dyson 	vm_pindex_t offset;
531c0877f10SJohn Dyson 	int destroysource;
53226f9a767SRodney W. Grimes {
533a316d390SJohn Dyson 	vm_pindex_t i;
53426f9a767SRodney W. Grimes 
53526f9a767SRodney W. Grimes 	/*
5361c7c3c6aSMatthew Dillon 	 * If destroysource is set, we remove the source object from the
5371c7c3c6aSMatthew Dillon 	 * swap_pager internal queue now.
53826f9a767SRodney W. Grimes 	 */
5391c7c3c6aSMatthew Dillon 
540cbd8ec09SJohn Dyson 	if (destroysource) {
54124a1cce3SDavid Greenman 		if (srcobject->handle == NULL) {
5421c7c3c6aSMatthew Dillon 			TAILQ_REMOVE(
5431c7c3c6aSMatthew Dillon 			    &swap_pager_un_object_list,
5441c7c3c6aSMatthew Dillon 			    srcobject,
5451c7c3c6aSMatthew Dillon 			    pager_object_list
5461c7c3c6aSMatthew Dillon 			);
54726f9a767SRodney W. Grimes 		} else {
5481c7c3c6aSMatthew Dillon 			TAILQ_REMOVE(
5491c7c3c6aSMatthew Dillon 			    NOBJLIST(srcobject->handle),
5501c7c3c6aSMatthew Dillon 			    srcobject,
5511c7c3c6aSMatthew Dillon 			    pager_object_list
5521c7c3c6aSMatthew Dillon 			);
55326f9a767SRodney W. Grimes 		}
554cbd8ec09SJohn Dyson 	}
55526f9a767SRodney W. Grimes 
5561c7c3c6aSMatthew Dillon 	/*
5571c7c3c6aSMatthew Dillon 	 * transfer source to destination.
5581c7c3c6aSMatthew Dillon 	 */
5591c7c3c6aSMatthew Dillon 
5601c7c3c6aSMatthew Dillon 	for (i = 0; i < dstobject->size; ++i) {
5611c7c3c6aSMatthew Dillon 		daddr_t dstaddr;
5621c7c3c6aSMatthew Dillon 
5631c7c3c6aSMatthew Dillon 		/*
5641c7c3c6aSMatthew Dillon 		 * Locate (without changing) the swapblk on the destination,
5651c7c3c6aSMatthew Dillon 		 * unless it is invalid in which case free it silently, or
5661c7c3c6aSMatthew Dillon 		 * if the destination is a resident page, in which case the
5671c7c3c6aSMatthew Dillon 		 * source is thrown away.
5681c7c3c6aSMatthew Dillon 		 */
5691c7c3c6aSMatthew Dillon 
5701c7c3c6aSMatthew Dillon 		dstaddr = swp_pager_meta_ctl(dstobject, i, 0);
5711c7c3c6aSMatthew Dillon 
5721c7c3c6aSMatthew Dillon 		if (dstaddr == SWAPBLK_NONE) {
5731c7c3c6aSMatthew Dillon 			/*
5741c7c3c6aSMatthew Dillon 			 * Destination has no swapblk and is not resident,
5751c7c3c6aSMatthew Dillon 			 * copy source.
5761c7c3c6aSMatthew Dillon 			 */
5771c7c3c6aSMatthew Dillon 			daddr_t srcaddr;
5781c7c3c6aSMatthew Dillon 
5791c7c3c6aSMatthew Dillon 			srcaddr = swp_pager_meta_ctl(
5801c7c3c6aSMatthew Dillon 			    srcobject,
5811c7c3c6aSMatthew Dillon 			    i + offset,
5821c7c3c6aSMatthew Dillon 			    SWM_POP
5831c7c3c6aSMatthew Dillon 			);
5841c7c3c6aSMatthew Dillon 
5851c7c3c6aSMatthew Dillon 			if (srcaddr != SWAPBLK_NONE)
5861c7c3c6aSMatthew Dillon 				swp_pager_meta_build(dstobject, i, srcaddr, 1);
5871c7c3c6aSMatthew Dillon 		} else {
5881c7c3c6aSMatthew Dillon 			/*
5891c7c3c6aSMatthew Dillon 			 * Destination has valid swapblk or it is represented
5901c7c3c6aSMatthew Dillon 			 * by a resident page.  We destroy the sourceblock.
5911c7c3c6aSMatthew Dillon 			 */
5921c7c3c6aSMatthew Dillon 
5931c7c3c6aSMatthew Dillon 			swp_pager_meta_ctl(srcobject, i + offset, SWM_FREE);
5941c7c3c6aSMatthew Dillon 		}
59526f9a767SRodney W. Grimes 	}
59626f9a767SRodney W. Grimes 
59726f9a767SRodney W. Grimes 	/*
5981c7c3c6aSMatthew Dillon 	 * Free left over swap blocks in source.
5991c7c3c6aSMatthew Dillon 	 *
6001c7c3c6aSMatthew Dillon 	 * We have to revert the type to OBJT_DEFAULT so we do not accidently
6011c7c3c6aSMatthew Dillon 	 * double-remove the object from the swap queues.
60226f9a767SRodney W. Grimes 	 */
60326f9a767SRodney W. Grimes 
604c0877f10SJohn Dyson 	if (destroysource) {
6051c7c3c6aSMatthew Dillon 		swp_pager_meta_free_all(srcobject);
6061c7c3c6aSMatthew Dillon 		/*
6071c7c3c6aSMatthew Dillon 		 * Reverting the type is not necessary, the caller is going
6081c7c3c6aSMatthew Dillon 		 * to destroy srcobject directly, but I'm doing it here
6091c7c3c6aSMatthew Dillon 		 * for consistancy since we've removed the object from its
6101c7c3c6aSMatthew Dillon 		 * queues.
6111c7c3c6aSMatthew Dillon 		 */
6121c7c3c6aSMatthew Dillon 		srcobject->type = OBJT_DEFAULT;
613c0877f10SJohn Dyson 	}
61426f9a767SRodney W. Grimes 	return;
61526f9a767SRodney W. Grimes }
61626f9a767SRodney W. Grimes 
617df8bae1dSRodney W. Grimes /*
6181c7c3c6aSMatthew Dillon  * SWAP_PAGER_HASPAGE() -	determine if we have good backing store for
6191c7c3c6aSMatthew Dillon  *				the requested page.
6201c7c3c6aSMatthew Dillon  *
6211c7c3c6aSMatthew Dillon  *	We determine whether good backing store exists for the requested
6221c7c3c6aSMatthew Dillon  *	page and return TRUE if it does, FALSE if it doesn't.
6231c7c3c6aSMatthew Dillon  *
6241c7c3c6aSMatthew Dillon  *	If TRUE, we also try to determine how much valid, contiguous backing
6251c7c3c6aSMatthew Dillon  *	store exists before and after the requested page within a reasonable
6261c7c3c6aSMatthew Dillon  *	distance.  We do not try to restrict it to the swap device stripe
6271c7c3c6aSMatthew Dillon  *	(that is handled in getpages/putpages).  It probably isn't worth
6281c7c3c6aSMatthew Dillon  *	doing here.
629df8bae1dSRodney W. Grimes  */
63026f9a767SRodney W. Grimes 
6311c7c3c6aSMatthew Dillon boolean_t
632a316d390SJohn Dyson swap_pager_haspage(object, pindex, before, after)
63324a1cce3SDavid Greenman 	vm_object_t object;
634a316d390SJohn Dyson 	vm_pindex_t pindex;
63524a1cce3SDavid Greenman 	int *before;
63624a1cce3SDavid Greenman 	int *after;
63726f9a767SRodney W. Grimes {
6381c7c3c6aSMatthew Dillon 	daddr_t blk0;
63926f9a767SRodney W. Grimes 
6401c7c3c6aSMatthew Dillon 	/*
6411c7c3c6aSMatthew Dillon 	 * do we have good backing store at the requested index ?
6421c7c3c6aSMatthew Dillon 	 */
6431c7c3c6aSMatthew Dillon 
6441c7c3c6aSMatthew Dillon 	blk0 = swp_pager_meta_ctl(object, pindex, 0);
6451c7c3c6aSMatthew Dillon 
6461c7c3c6aSMatthew Dillon 	if (blk0 & SWAPBLK_NONE) {
6471c7c3c6aSMatthew Dillon 		if (before)
64824a1cce3SDavid Greenman 			*before = 0;
6491c7c3c6aSMatthew Dillon 		if (after)
65024a1cce3SDavid Greenman 			*after = 0;
65126f9a767SRodney W. Grimes 		return (FALSE);
65226f9a767SRodney W. Grimes 	}
65326f9a767SRodney W. Grimes 
65426f9a767SRodney W. Grimes 	/*
6551c7c3c6aSMatthew Dillon 	 * find backwards-looking contiguous good backing store
656e47ed70bSJohn Dyson 	 */
657e47ed70bSJohn Dyson 
6581c7c3c6aSMatthew Dillon 	if (before != NULL) {
65926f9a767SRodney W. Grimes 		int i;
6600d94caffSDavid Greenman 
6611c7c3c6aSMatthew Dillon 		for (i = 1; i < (SWB_NPAGES/2); ++i) {
6621c7c3c6aSMatthew Dillon 			daddr_t blk;
6631c7c3c6aSMatthew Dillon 
6641c7c3c6aSMatthew Dillon 			if (i > pindex)
6651c7c3c6aSMatthew Dillon 				break;
6661c7c3c6aSMatthew Dillon 			blk = swp_pager_meta_ctl(object, pindex - i, 0);
6671c7c3c6aSMatthew Dillon 			if (blk & SWAPBLK_NONE)
6681c7c3c6aSMatthew Dillon 				break;
6691c7c3c6aSMatthew Dillon 			if (blk != blk0 - i)
6701c7c3c6aSMatthew Dillon 				break;
671ffc82b0aSJohn Dyson 		}
6721c7c3c6aSMatthew Dillon 		*before = (i - 1);
67326f9a767SRodney W. Grimes 	}
67426f9a767SRodney W. Grimes 
67526f9a767SRodney W. Grimes 	/*
6761c7c3c6aSMatthew Dillon 	 * find forward-looking contiguous good backing store
67726f9a767SRodney W. Grimes 	 */
6781c7c3c6aSMatthew Dillon 
6791c7c3c6aSMatthew Dillon 	if (after != NULL) {
6801c7c3c6aSMatthew Dillon 		int i;
6811c7c3c6aSMatthew Dillon 
6821c7c3c6aSMatthew Dillon 		for (i = 1; i < (SWB_NPAGES/2); ++i) {
6831c7c3c6aSMatthew Dillon 			daddr_t blk;
6841c7c3c6aSMatthew Dillon 
6851c7c3c6aSMatthew Dillon 			blk = swp_pager_meta_ctl(object, pindex + i, 0);
6861c7c3c6aSMatthew Dillon 			if (blk & SWAPBLK_NONE)
6871c7c3c6aSMatthew Dillon 				break;
6881c7c3c6aSMatthew Dillon 			if (blk != blk0 + i)
6891c7c3c6aSMatthew Dillon 				break;
69026f9a767SRodney W. Grimes 		}
6911c7c3c6aSMatthew Dillon 		*after = (i - 1);
6921c7c3c6aSMatthew Dillon 	}
6931c7c3c6aSMatthew Dillon 
6941c7c3c6aSMatthew Dillon 	return (TRUE);
6951c7c3c6aSMatthew Dillon }
6961c7c3c6aSMatthew Dillon 
6971c7c3c6aSMatthew Dillon /*
6981c7c3c6aSMatthew Dillon  * SWAP_PAGER_PAGE_UNSWAPPED() - remove swap backing store related to page
6991c7c3c6aSMatthew Dillon  *
7001c7c3c6aSMatthew Dillon  *	This removes any associated swap backing store, whether valid or
7011c7c3c6aSMatthew Dillon  *	not, from the page.
7021c7c3c6aSMatthew Dillon  *
7031c7c3c6aSMatthew Dillon  *	This routine is typically called when a page is made dirty, at
7041c7c3c6aSMatthew Dillon  *	which point any associated swap can be freed.  MADV_FREE also
7051c7c3c6aSMatthew Dillon  *	calls us in a special-case situation
7061c7c3c6aSMatthew Dillon  *
7071c7c3c6aSMatthew Dillon  *	NOTE!!!  If the page is clean and the swap was valid, the caller
7081c7c3c6aSMatthew Dillon  *	should make the page dirty before calling this routine.  This routine
7091c7c3c6aSMatthew Dillon  *	does NOT change the m->dirty status of the page.  Also: MADV_FREE
7101c7c3c6aSMatthew Dillon  *	depends on it.
7111c7c3c6aSMatthew Dillon  *
7121c7c3c6aSMatthew Dillon  *	This routine may not block
7131c7c3c6aSMatthew Dillon  */
7141c7c3c6aSMatthew Dillon 
7151c7c3c6aSMatthew Dillon static void
7161c7c3c6aSMatthew Dillon swap_pager_unswapped(m)
7171c7c3c6aSMatthew Dillon 	vm_page_t m;
7181c7c3c6aSMatthew Dillon {
7191c7c3c6aSMatthew Dillon 	swp_pager_meta_ctl(m->object, m->pindex, SWM_FREE);
7201c7c3c6aSMatthew Dillon }
7211c7c3c6aSMatthew Dillon 
7221c7c3c6aSMatthew Dillon /*
7231c7c3c6aSMatthew Dillon  * SWAP_PAGER_GETPAGES() - bring pages in from swap
7241c7c3c6aSMatthew Dillon  *
7251c7c3c6aSMatthew Dillon  *	Attempt to retrieve (m, count) pages from backing store, but make
7261c7c3c6aSMatthew Dillon  *	sure we retrieve at least m[reqpage].  We try to load in as large
7271c7c3c6aSMatthew Dillon  *	a chunk surrounding m[reqpage] as is contiguous in swap and which
7281c7c3c6aSMatthew Dillon  *	belongs to the same object.
7291c7c3c6aSMatthew Dillon  *
7301c7c3c6aSMatthew Dillon  *	The code is designed for asynchronous operation and
7311c7c3c6aSMatthew Dillon  *	immediate-notification of 'reqpage' but tends not to be
7321c7c3c6aSMatthew Dillon  *	used that way.  Please do not optimize-out this algorithmic
7331c7c3c6aSMatthew Dillon  *	feature, I intend to improve on it in the future.
7341c7c3c6aSMatthew Dillon  *
7351c7c3c6aSMatthew Dillon  *	The parent has a single vm_object_pip_add() reference prior to
7361c7c3c6aSMatthew Dillon  *	calling us and we should return with the same.
7371c7c3c6aSMatthew Dillon  *
7381c7c3c6aSMatthew Dillon  *	The parent has BUSY'd the pages.  We should return with 'm'
7391c7c3c6aSMatthew Dillon  *	left busy, but the others adjusted.
7401c7c3c6aSMatthew Dillon  */
74126f9a767SRodney W. Grimes 
742f708ef1bSPoul-Henning Kamp static int
74324a1cce3SDavid Greenman swap_pager_getpages(object, m, count, reqpage)
74424a1cce3SDavid Greenman 	vm_object_t object;
74526f9a767SRodney W. Grimes 	vm_page_t *m;
74626f9a767SRodney W. Grimes 	int count, reqpage;
747df8bae1dSRodney W. Grimes {
7481c7c3c6aSMatthew Dillon 	struct buf *bp;
7491c7c3c6aSMatthew Dillon 	vm_page_t mreq;
7501c7c3c6aSMatthew Dillon 	int s;
75126f9a767SRodney W. Grimes 	int i;
75226f9a767SRodney W. Grimes 	int j;
7531c7c3c6aSMatthew Dillon 	daddr_t blk;
7541c7c3c6aSMatthew Dillon 	vm_offset_t kva;
7551c7c3c6aSMatthew Dillon 	vm_pindex_t lastpindex;
7560d94caffSDavid Greenman 
7571c7c3c6aSMatthew Dillon 	mreq = m[reqpage];
7581c7c3c6aSMatthew Dillon 
7591c7c3c6aSMatthew Dillon #if !defined(MAX_PERF)
7601c7c3c6aSMatthew Dillon 	if (mreq->object != object) {
7611c7c3c6aSMatthew Dillon 		panic("swap_pager_getpages: object mismatch %p/%p",
7621c7c3c6aSMatthew Dillon 		    object,
7631c7c3c6aSMatthew Dillon 		    mreq->object
7641c7c3c6aSMatthew Dillon 		);
76526f9a767SRodney W. Grimes 	}
7661c7c3c6aSMatthew Dillon #endif
7671c7c3c6aSMatthew Dillon 	/*
7681c7c3c6aSMatthew Dillon 	 * Calculate range to retrieve.  The pages have already been assigned
7691c7c3c6aSMatthew Dillon 	 * their swapblks.  We require a *contiguous* range that falls entirely
7701c7c3c6aSMatthew Dillon 	 * within a single device stripe.   If we do not supply it, bad things
7711c7c3c6aSMatthew Dillon 	 * happen.
7721c7c3c6aSMatthew Dillon 	 */
7731c7c3c6aSMatthew Dillon 
7741c7c3c6aSMatthew Dillon 
7751c7c3c6aSMatthew Dillon 	blk = swp_pager_meta_ctl(mreq->object, mreq->pindex, 0);
7761c7c3c6aSMatthew Dillon 
7771c7c3c6aSMatthew Dillon 	for (i = reqpage - 1; i >= 0; --i) {
7781c7c3c6aSMatthew Dillon 		daddr_t iblk;
7791c7c3c6aSMatthew Dillon 
7801c7c3c6aSMatthew Dillon 		iblk = swp_pager_meta_ctl(m[i]->object, m[i]->pindex, 0);
7811c7c3c6aSMatthew Dillon 		if (iblk & SWAPBLK_NONE)
7821c7c3c6aSMatthew Dillon 			break;
7831c7c3c6aSMatthew Dillon 
7841c7c3c6aSMatthew Dillon 		if ((blk ^ iblk) & dmmax_mask)
7851c7c3c6aSMatthew Dillon 			break;
7861c7c3c6aSMatthew Dillon 
7871c7c3c6aSMatthew Dillon 		if (blk != iblk + (reqpage - i))
78826f9a767SRodney W. Grimes 			break;
78926f9a767SRodney W. Grimes 	}
7901c7c3c6aSMatthew Dillon 	++i;
7911c7c3c6aSMatthew Dillon 
7921c7c3c6aSMatthew Dillon 	for (j = reqpage + 1; j < count; ++j) {
7931c7c3c6aSMatthew Dillon 		daddr_t jblk;
7941c7c3c6aSMatthew Dillon 
7951c7c3c6aSMatthew Dillon 		jblk = swp_pager_meta_ctl(m[j]->object, m[j]->pindex, 0);
7961c7c3c6aSMatthew Dillon 		if (jblk & SWAPBLK_NONE)
7971c7c3c6aSMatthew Dillon 			break;
7981c7c3c6aSMatthew Dillon 
7991c7c3c6aSMatthew Dillon 		if ((blk ^ jblk) & dmmax_mask)
8001c7c3c6aSMatthew Dillon 			break;
8011c7c3c6aSMatthew Dillon 
8021c7c3c6aSMatthew Dillon 		if (blk != jblk - (j - reqpage))
8031c7c3c6aSMatthew Dillon 			break;
80426f9a767SRodney W. Grimes 	}
80526f9a767SRodney W. Grimes 
8061c7c3c6aSMatthew Dillon 	/*
8071c7c3c6aSMatthew Dillon 	 * If blk itself is bad, well, we can't do any I/O.  This should
8081c7c3c6aSMatthew Dillon 	 * already be covered as a side effect, but I'm making sure.
8091c7c3c6aSMatthew Dillon 	 */
81026f9a767SRodney W. Grimes 
8111c7c3c6aSMatthew Dillon 	if (blk & SWAPBLK_NONE) {
8121c7c3c6aSMatthew Dillon 		i = reqpage;
8131c7c3c6aSMatthew Dillon 		j = reqpage + 1;
8141c7c3c6aSMatthew Dillon 	}
8151c7c3c6aSMatthew Dillon 
8161c7c3c6aSMatthew Dillon 	/*
8171c7c3c6aSMatthew Dillon 	 * free pages outside our collection range.   Note: we never free
8181c7c3c6aSMatthew Dillon 	 * mreq, it must remain busy throughout.
8191c7c3c6aSMatthew Dillon 	 */
8201c7c3c6aSMatthew Dillon 
8211c7c3c6aSMatthew Dillon 	{
8221c7c3c6aSMatthew Dillon 		int k;
8231c7c3c6aSMatthew Dillon 
8241c7c3c6aSMatthew Dillon 		for (k = 0; k < i; ++k) {
8251c7c3c6aSMatthew Dillon 			vm_page_free(m[k]);
8261c7c3c6aSMatthew Dillon 		}
8271c7c3c6aSMatthew Dillon 		for (k = j; k < count; ++k) {
8281c7c3c6aSMatthew Dillon 			vm_page_free(m[k]);
8291c7c3c6aSMatthew Dillon 		}
8301c7c3c6aSMatthew Dillon 	}
8311c7c3c6aSMatthew Dillon 
8321c7c3c6aSMatthew Dillon 	/*
8331c7c3c6aSMatthew Dillon 	 * Return VM_PAGER_FAIL if we have nothing
8341c7c3c6aSMatthew Dillon 	 * to do.  Return mreq still busy, but the
8351c7c3c6aSMatthew Dillon 	 * others unbusied.
8361c7c3c6aSMatthew Dillon 	 */
8371c7c3c6aSMatthew Dillon 
8381c7c3c6aSMatthew Dillon 	if (blk & SWAPBLK_NONE)
83926f9a767SRodney W. Grimes 		return(VM_PAGER_FAIL);
840df8bae1dSRodney W. Grimes 
84126f9a767SRodney W. Grimes 
84216f62314SDavid Greenman 	/*
84316f62314SDavid Greenman 	 * Get a swap buffer header to perform the IO
84416f62314SDavid Greenman 	 */
8451c7c3c6aSMatthew Dillon 
8461c7c3c6aSMatthew Dillon 	bp = getpbuf(&nsw_rcount);
84716f62314SDavid Greenman 	kva = (vm_offset_t) bp->b_data;
84826f9a767SRodney W. Grimes 
84916f62314SDavid Greenman 	/*
85016f62314SDavid Greenman 	 * map our page(s) into kva for input
8511c7c3c6aSMatthew Dillon 	 *
8521c7c3c6aSMatthew Dillon 	 * NOTE: B_PAGING is set by pbgetvp()
85316f62314SDavid Greenman 	 */
85416f62314SDavid Greenman 
8551c7c3c6aSMatthew Dillon 	pmap_qenter(kva, m + i, j - i);
8561c7c3c6aSMatthew Dillon 
8571c7c3c6aSMatthew Dillon 	bp->b_flags = B_BUSY | B_READ | B_CALL;
8581c7c3c6aSMatthew Dillon 	bp->b_iodone = swp_pager_async_iodone;
859df8bae1dSRodney W. Grimes 	bp->b_proc = &proc0;	/* XXX (but without B_PHYS set this is ok) */
86026f9a767SRodney W. Grimes 	bp->b_rcred = bp->b_wcred = bp->b_proc->p_ucred;
86126f9a767SRodney W. Grimes 	crhold(bp->b_rcred);
86226f9a767SRodney W. Grimes 	crhold(bp->b_wcred);
863ab3f7469SPoul-Henning Kamp 	bp->b_data = (caddr_t) kva;
8641c7c3c6aSMatthew Dillon 	/*
8651c7c3c6aSMatthew Dillon 	 * b_blkno is in page-sized chunks.  swapblk is valid, too, so
8661c7c3c6aSMatthew Dillon 	 * we don't have to mask it against SWAPBLK_MASK.
8671c7c3c6aSMatthew Dillon 	 */
8681c7c3c6aSMatthew Dillon 	bp->b_blkno = blk - (reqpage - i);
8691c7c3c6aSMatthew Dillon 	bp->b_bcount = PAGE_SIZE * (j - i);
8701c7c3c6aSMatthew Dillon 	bp->b_bufsize = PAGE_SIZE * (j - i);
8711c7c3c6aSMatthew Dillon 	bp->b_pager.pg_reqpage = reqpage - i;
8721c7c3c6aSMatthew Dillon 
8731c7c3c6aSMatthew Dillon 	{
8741c7c3c6aSMatthew Dillon 		int k;
8751c7c3c6aSMatthew Dillon 
8761c7c3c6aSMatthew Dillon 		for (k = i; k < j; ++k) {
8771c7c3c6aSMatthew Dillon 			bp->b_pages[k - i] = m[k];
8781c7c3c6aSMatthew Dillon 			vm_page_flag_set(m[k], PG_SWAPINPROG);
8791c7c3c6aSMatthew Dillon 		}
8801c7c3c6aSMatthew Dillon 	}
8811c7c3c6aSMatthew Dillon 	bp->b_npages = j - i;
88226f9a767SRodney W. Grimes 
8830d94caffSDavid Greenman 	pbgetvp(swapdev_vp, bp);
884df8bae1dSRodney W. Grimes 
885976e77fcSDavid Greenman 	cnt.v_swapin++;
8861c7c3c6aSMatthew Dillon 	cnt.v_swappgsin += bp->b_npages;
8871c7c3c6aSMatthew Dillon 
888df8bae1dSRodney W. Grimes 	/*
8891c7c3c6aSMatthew Dillon 	 * We still hold the lock on mreq, and our automatic completion routine
8901c7c3c6aSMatthew Dillon 	 * does not remove it.
891df8bae1dSRodney W. Grimes 	 */
8921c7c3c6aSMatthew Dillon 
8931c7c3c6aSMatthew Dillon 	vm_object_pip_add(mreq->object, bp->b_npages);
8941c7c3c6aSMatthew Dillon 	lastpindex = m[j-1]->pindex;
8951c7c3c6aSMatthew Dillon 
8961c7c3c6aSMatthew Dillon 	/*
8971c7c3c6aSMatthew Dillon 	 * perform the I/O.  NOTE!!!  bp cannot be considered valid after
8981c7c3c6aSMatthew Dillon 	 * this point because we automatically release it on completion.
8991c7c3c6aSMatthew Dillon 	 * Instead, we look at the one page we are interested in which we
9001c7c3c6aSMatthew Dillon 	 * still hold a lock on even through the I/O completion.
9011c7c3c6aSMatthew Dillon 	 *
9021c7c3c6aSMatthew Dillon 	 * The other pages in our m[] array are also released on completion,
9031c7c3c6aSMatthew Dillon 	 * so we cannot assume they are valid anymore either.
9041c7c3c6aSMatthew Dillon 	 *
9051c7c3c6aSMatthew Dillon 	 * NOTE: b_blkno is destroyed by the call to VOP_STRATEGY
9061c7c3c6aSMatthew Dillon 	 */
9071c7c3c6aSMatthew Dillon 
908fd5d1124SJulian Elischer 	VOP_STRATEGY(bp->b_vp, bp);
90926f9a767SRodney W. Grimes 
91026f9a767SRodney W. Grimes 	/*
9111c7c3c6aSMatthew Dillon 	 * wait for the page we want to complete.  PG_SWAPINPROG is always
9121c7c3c6aSMatthew Dillon 	 * cleared on completion.  If an I/O error occurs, SWAPBLK_NONE
9131c7c3c6aSMatthew Dillon 	 * is set in the meta-data.
91426f9a767SRodney W. Grimes 	 */
9151b119d9dSDavid Greenman 
9161c7c3c6aSMatthew Dillon 	s = splvm();
9171c7c3c6aSMatthew Dillon 
9181c7c3c6aSMatthew Dillon 	while ((mreq->flags & PG_SWAPINPROG) != 0) {
9191c7c3c6aSMatthew Dillon 		vm_page_flag_set(mreq, PG_WANTED | PG_REFERENCED);
9201c7c3c6aSMatthew Dillon 		cnt.v_intrans++;
9211c7c3c6aSMatthew Dillon 		if (tsleep(mreq, PSWP, "swread", hz*20)) {
922ac1e407bSBruce Evans 			printf(
9231c7c3c6aSMatthew Dillon 			    "swap_pager: indefinite wait buffer: device:"
9241c7c3c6aSMatthew Dillon 				" %#lx, blkno: %ld, size: %ld\n",
9251c7c3c6aSMatthew Dillon 			    (u_long)bp->b_dev, (long)bp->b_blkno,
9261c7c3c6aSMatthew Dillon 			    (long)bp->b_bcount
9271c7c3c6aSMatthew Dillon 			);
9281c7c3c6aSMatthew Dillon 		}
9291b119d9dSDavid Greenman 	}
93026f9a767SRodney W. Grimes 
931df8bae1dSRodney W. Grimes 	splx(s);
93226f9a767SRodney W. Grimes 
93326f9a767SRodney W. Grimes 	/*
9341c7c3c6aSMatthew Dillon 	 * mreq is left bussied after completion, but all the other pages
9351c7c3c6aSMatthew Dillon 	 * are freed.  If we had an unrecoverable read error the page will
9361c7c3c6aSMatthew Dillon 	 * not be valid.
93726f9a767SRodney W. Grimes 	 */
93826f9a767SRodney W. Grimes 
9391c7c3c6aSMatthew Dillon 	if (mreq->valid != VM_PAGE_BITS_ALL) {
9401c7c3c6aSMatthew Dillon 		return(VM_PAGER_ERROR);
94126f9a767SRodney W. Grimes 	} else {
9421c7c3c6aSMatthew Dillon 		mreq->object->last_read = lastpindex;
9431c7c3c6aSMatthew Dillon 		return(VM_PAGER_OK);
94426f9a767SRodney W. Grimes 	}
9451c7c3c6aSMatthew Dillon 
9461c7c3c6aSMatthew Dillon 	/*
9471c7c3c6aSMatthew Dillon 	 * A final note: in a low swap situation, we cannot deallocate swap
9481c7c3c6aSMatthew Dillon 	 * and mark a page dirty here because the caller is likely to mark
9491c7c3c6aSMatthew Dillon 	 * the page clean when we return, causing the page to possibly revert
9501c7c3c6aSMatthew Dillon 	 * to all-zero's later.
9511c7c3c6aSMatthew Dillon 	 */
952df8bae1dSRodney W. Grimes }
953df8bae1dSRodney W. Grimes 
9541c7c3c6aSMatthew Dillon /*
9551c7c3c6aSMatthew Dillon  *	swap_pager_putpages:
9561c7c3c6aSMatthew Dillon  *
9571c7c3c6aSMatthew Dillon  *	Assign swap (if necessary) and initiate I/O on the specified pages.
9581c7c3c6aSMatthew Dillon  *
9591c7c3c6aSMatthew Dillon  *	We support both OBJT_DEFAULT and OBJT_SWAP objects.  DEFAULT objects
9601c7c3c6aSMatthew Dillon  *	are automatically converted to SWAP objects.
9611c7c3c6aSMatthew Dillon  *
9621c7c3c6aSMatthew Dillon  *	In a low memory situation we may block in VOP_STRATEGY(), but the new
9631c7c3c6aSMatthew Dillon  *	vm_page reservation system coupled with properly written VFS devices
9641c7c3c6aSMatthew Dillon  *	should ensure that no low-memory deadlock occurs.  This is an area
9651c7c3c6aSMatthew Dillon  *	which needs work.
9661c7c3c6aSMatthew Dillon  *
9671c7c3c6aSMatthew Dillon  *	The parent has N vm_object_pip_add() references prior to
9681c7c3c6aSMatthew Dillon  *	calling us and will remove references for rtvals[] that are
9691c7c3c6aSMatthew Dillon  *	not set to VM_PAGER_PEND.  We need to remove the rest on I/O
9701c7c3c6aSMatthew Dillon  *	completion.
9711c7c3c6aSMatthew Dillon  *
9721c7c3c6aSMatthew Dillon  *	The parent has soft-busy'd the pages it passes us and will unbusy
9731c7c3c6aSMatthew Dillon  *	those whos rtvals[] entry is not set to VM_PAGER_PEND on return.
9741c7c3c6aSMatthew Dillon  *	We need to unbusy the rest on I/O completion.
9751c7c3c6aSMatthew Dillon  */
9761c7c3c6aSMatthew Dillon 
97726f9a767SRodney W. Grimes int
97824a1cce3SDavid Greenman swap_pager_putpages(object, m, count, sync, rtvals)
97924a1cce3SDavid Greenman 	vm_object_t object;
98026f9a767SRodney W. Grimes 	vm_page_t *m;
98126f9a767SRodney W. Grimes 	int count;
98224a1cce3SDavid Greenman 	boolean_t sync;
98326f9a767SRodney W. Grimes 	int *rtvals;
984df8bae1dSRodney W. Grimes {
9851c7c3c6aSMatthew Dillon 	int i;
9861c7c3c6aSMatthew Dillon 	int n = 0;
9871c7c3c6aSMatthew Dillon 	int grv = VM_PAGER_OK;
988df8bae1dSRodney W. Grimes 
9891c7c3c6aSMatthew Dillon #if !defined(MAX_PERF)
9901c7c3c6aSMatthew Dillon 	if (count && m[0]->object != object) {
9911c7c3c6aSMatthew Dillon 		panic("swap_pager_getpages: object mismatch %p/%p",
9921c7c3c6aSMatthew Dillon 		    object,
9931c7c3c6aSMatthew Dillon 		    m[0]->object
9941c7c3c6aSMatthew Dillon 		);
9951c7c3c6aSMatthew Dillon 	}
9961c7c3c6aSMatthew Dillon #endif
9971c7c3c6aSMatthew Dillon 	/*
9981c7c3c6aSMatthew Dillon 	 * Step 1
9991c7c3c6aSMatthew Dillon 	 *
10001c7c3c6aSMatthew Dillon 	 * Turn object into OBJT_SWAP
10011c7c3c6aSMatthew Dillon 	 * check for bogus sysops
10021c7c3c6aSMatthew Dillon 	 * force sync if not pageout process
10031c7c3c6aSMatthew Dillon 	 */
1004e736cd05SJohn Dyson 
10051c7c3c6aSMatthew Dillon 	if (object->type != OBJT_SWAP) {
10061c7c3c6aSMatthew Dillon 		swp_pager_meta_build(object, 0, SWAPBLK_NONE, 0);
10075663e6deSDavid Greenman 	}
1008e47ed70bSJohn Dyson 
1009e47ed70bSJohn Dyson 	if (curproc != pageproc)
1010e47ed70bSJohn Dyson 		sync = TRUE;
101126f9a767SRodney W. Grimes 
10121c7c3c6aSMatthew Dillon 	/*
10131c7c3c6aSMatthew Dillon 	 * Step 2
10141c7c3c6aSMatthew Dillon 	 *
10151c7c3c6aSMatthew Dillon 	 * Assign swap blocks and issue I/O.  We reallocate swap on the fly.
10161c7c3c6aSMatthew Dillon 	 * The page is left dirty until the pageout operation completes
10171c7c3c6aSMatthew Dillon 	 * successfully.
10181c7c3c6aSMatthew Dillon 	 */
101926f9a767SRodney W. Grimes 
10201c7c3c6aSMatthew Dillon 	for (i = 0; i < count; i += n) {
10211c7c3c6aSMatthew Dillon 		int s;
10221c7c3c6aSMatthew Dillon 		int j;
10231c7c3c6aSMatthew Dillon 		struct buf *bp;
1024a316d390SJohn Dyson 		daddr_t blk;
102526f9a767SRodney W. Grimes 
1026df8bae1dSRodney W. Grimes 		/*
10271c7c3c6aSMatthew Dillon 		 * Maximum I/O size is limited by a number of factors.
1028df8bae1dSRodney W. Grimes 		 */
102926f9a767SRodney W. Grimes 
10301c7c3c6aSMatthew Dillon 		n = min(BLIST_MAX_ALLOC, count - i);
10311c7c3c6aSMatthew Dillon 		n = min(n, max_pageout_cluster);
10321c7c3c6aSMatthew Dillon 
103326f9a767SRodney W. Grimes 		/*
10341c7c3c6aSMatthew Dillon 		 * Get biggest block of swap we can.  If we fail, fall
10351c7c3c6aSMatthew Dillon 		 * back and try to allocate a smaller block.  Don't go
10361c7c3c6aSMatthew Dillon 		 * overboard trying to allocate space if it would overly
10371c7c3c6aSMatthew Dillon 		 * fragment swap.
103826f9a767SRodney W. Grimes 		 */
10391c7c3c6aSMatthew Dillon 		while (
10401c7c3c6aSMatthew Dillon 		    (blk = swp_pager_getswapspace(n)) == SWAPBLK_NONE &&
10411c7c3c6aSMatthew Dillon 		    n > 4
10421c7c3c6aSMatthew Dillon 		) {
10431c7c3c6aSMatthew Dillon 			n >>= 1;
104426f9a767SRodney W. Grimes 		}
10451c7c3c6aSMatthew Dillon 		if (blk == SWAPBLK_NONE) {
10461c7c3c6aSMatthew Dillon 			for (j = 0; j < n; ++j) {
10471c7c3c6aSMatthew Dillon 				rtvals[i+j] = VM_PAGER_FAIL;
104826f9a767SRodney W. Grimes 			}
10491c7c3c6aSMatthew Dillon 			grv = VM_PAGER_FAIL;
10501c7c3c6aSMatthew Dillon 			continue;
105126f9a767SRodney W. Grimes 		}
105226f9a767SRodney W. Grimes 
105326f9a767SRodney W. Grimes 		/*
10541c7c3c6aSMatthew Dillon 		 * Oops, too big if it crosses a stripe
10551c7c3c6aSMatthew Dillon 		 *
10561c7c3c6aSMatthew Dillon 		 * 1111000000
10571c7c3c6aSMatthew Dillon 		 *     111111
10581c7c3c6aSMatthew Dillon 		 *    1000001
105926f9a767SRodney W. Grimes 		 */
10601c7c3c6aSMatthew Dillon 		if ((blk ^ (blk + n)) & dmmax_mask) {
10611c7c3c6aSMatthew Dillon 			j = ((blk + dmmax) & dmmax_mask) - blk;
10621c7c3c6aSMatthew Dillon 			swp_pager_freeswapspace(blk + j, n - j);
10631c7c3c6aSMatthew Dillon 			n = j;
1064e47ed70bSJohn Dyson 		}
106526f9a767SRodney W. Grimes 
106626f9a767SRodney W. Grimes 		/*
10671c7c3c6aSMatthew Dillon 		 * All I/O parameters have been satisfied, build the I/O
10681c7c3c6aSMatthew Dillon 		 * request and assign the swap space.
10691c7c3c6aSMatthew Dillon 		 *
10701c7c3c6aSMatthew Dillon 		 * NOTE: B_PAGING is set by pbgetvp()
107126f9a767SRodney W. Grimes 		 */
107226f9a767SRodney W. Grimes 
10731c7c3c6aSMatthew Dillon 		bp = getpbuf(&nsw_wcount);
10741c7c3c6aSMatthew Dillon 		bp->b_spc = NULL;	/* not used, but NULL-out anyway */
107526f9a767SRodney W. Grimes 
10761c7c3c6aSMatthew Dillon 		pmap_qenter((vm_offset_t)bp->b_data, &m[i], n);
10771c7c3c6aSMatthew Dillon 
10781c7c3c6aSMatthew Dillon 		bp->b_flags = B_BUSY | B_ASYNC;
10791c7c3c6aSMatthew Dillon 		bp->b_proc = &proc0; /* XXX (but without B_PHYS this is ok) */
108026f9a767SRodney W. Grimes 		bp->b_rcred = bp->b_wcred = bp->b_proc->p_ucred;
10811c7c3c6aSMatthew Dillon 
1082a481f200SDavid Greenman 		if (bp->b_rcred != NOCRED)
108326f9a767SRodney W. Grimes 			crhold(bp->b_rcred);
1084a481f200SDavid Greenman 		if (bp->b_wcred != NOCRED)
108526f9a767SRodney W. Grimes 			crhold(bp->b_wcred);
10860d94caffSDavid Greenman 		pbgetvp(swapdev_vp, bp);
108716f62314SDavid Greenman 
10881c7c3c6aSMatthew Dillon 		bp->b_bcount = PAGE_SIZE * n;
10891c7c3c6aSMatthew Dillon 		bp->b_bufsize = PAGE_SIZE * n;
10901c7c3c6aSMatthew Dillon 		bp->b_blkno = blk;
1091e47ed70bSJohn Dyson 
1092e47ed70bSJohn Dyson 		s = splvm();
10931c7c3c6aSMatthew Dillon 
10941c7c3c6aSMatthew Dillon 		for (j = 0; j < n; ++j) {
10951c7c3c6aSMatthew Dillon 			vm_page_t mreq = m[i+j];
10961c7c3c6aSMatthew Dillon 
10971c7c3c6aSMatthew Dillon 			swp_pager_meta_build(
10981c7c3c6aSMatthew Dillon 			    mreq->object,
10991c7c3c6aSMatthew Dillon 			    mreq->pindex,
11001c7c3c6aSMatthew Dillon 			    blk + j,
11011c7c3c6aSMatthew Dillon 			    0
11021c7c3c6aSMatthew Dillon 			);
11031c7c3c6aSMatthew Dillon 			mreq->dirty = VM_PAGE_BITS_ALL;
11041c7c3c6aSMatthew Dillon 			rtvals[i+j] = VM_PAGER_OK;
11051c7c3c6aSMatthew Dillon 
11061c7c3c6aSMatthew Dillon 			vm_page_flag_set(mreq, PG_SWAPINPROG);
11071c7c3c6aSMatthew Dillon 			bp->b_pages[j] = mreq;
11081c7c3c6aSMatthew Dillon 		}
11091c7c3c6aSMatthew Dillon 		bp->b_flags |= B_CALL;
11101c7c3c6aSMatthew Dillon 		bp->b_npages = n;
11111c7c3c6aSMatthew Dillon 
11121c7c3c6aSMatthew Dillon 		cnt.v_swapout++;
11131c7c3c6aSMatthew Dillon 		cnt.v_swappgsout += bp->b_npages;
111426f9a767SRodney W. Grimes 		swapdev_vp->v_numoutput++;
111526f9a767SRodney W. Grimes 
111626f9a767SRodney W. Grimes 		/*
11171c7c3c6aSMatthew Dillon 		 * asynchronous
11181c7c3c6aSMatthew Dillon 		 *
11191c7c3c6aSMatthew Dillon 		 * NOTE: b_blkno is destroyed by the call to VOP_STRATEGY
112026f9a767SRodney W. Grimes 		 */
1121e47ed70bSJohn Dyson 
11221c7c3c6aSMatthew Dillon 		if (sync == FALSE) {
11231c7c3c6aSMatthew Dillon 			bp->b_iodone = swp_pager_async_iodone;
112426f9a767SRodney W. Grimes 			bp->b_dirtyoff = 0;
112526f9a767SRodney W. Grimes 			bp->b_dirtyend = bp->b_bcount;
1126fd5d1124SJulian Elischer 			VOP_STRATEGY(bp->b_vp, bp);
11271c7c3c6aSMatthew Dillon 
11281c7c3c6aSMatthew Dillon 			for (j = 0; j < n; ++j)
11291c7c3c6aSMatthew Dillon 				rtvals[i+j] = VM_PAGER_PEND;
11301c7c3c6aSMatthew Dillon 
1131ccbbd927SBruce Evans 			splx(s);
11321c7c3c6aSMatthew Dillon 			grv = VM_PAGER_PEND;
11331c7c3c6aSMatthew Dillon 			continue;
113426f9a767SRodney W. Grimes 		}
1135e47ed70bSJohn Dyson 
113626f9a767SRodney W. Grimes 		/*
11371c7c3c6aSMatthew Dillon 		 * synchronous
11381c7c3c6aSMatthew Dillon 		 *
11391c7c3c6aSMatthew Dillon 		 * NOTE: b_blkno is destroyed by the call to VOP_STRATEGY
11401c7c3c6aSMatthew Dillon 		 */
11411c7c3c6aSMatthew Dillon 
11421c7c3c6aSMatthew Dillon 		bp->b_iodone = swp_pager_sync_iodone;
11431c7c3c6aSMatthew Dillon 		VOP_STRATEGY(bp->b_vp, bp);
11441c7c3c6aSMatthew Dillon 
11451c7c3c6aSMatthew Dillon 		/*
11461c7c3c6aSMatthew Dillon 		 * Wait for the sync I/O to complete, then update rtvals.
11471c7c3c6aSMatthew Dillon 		 * We just set the rtvals[] to VM_PAGER_PEND so we can call
11481c7c3c6aSMatthew Dillon 		 * our async completion routine at the end, thus avoiding a
11491c7c3c6aSMatthew Dillon 		 * double-free.
115026f9a767SRodney W. Grimes 		 */
115126f9a767SRodney W. Grimes 		while ((bp->b_flags & B_DONE) == 0) {
115224a1cce3SDavid Greenman 			tsleep(bp, PVM, "swwrt", 0);
115326f9a767SRodney W. Grimes 		}
1154e47ed70bSJohn Dyson 
11551b119d9dSDavid Greenman 		if (bp->b_flags & B_ERROR) {
11561c7c3c6aSMatthew Dillon 			grv = VM_PAGER_ERROR;
11571b119d9dSDavid Greenman 		}
115826f9a767SRodney W. Grimes 
11591c7c3c6aSMatthew Dillon 		for (j = 0; j < n; ++j)
11601c7c3c6aSMatthew Dillon 			rtvals[i+j] = VM_PAGER_PEND;
116126f9a767SRodney W. Grimes 
11621c7c3c6aSMatthew Dillon 		if (bp->b_flags & B_ERROR) {
11631c7c3c6aSMatthew Dillon 			grv = VM_PAGER_ERROR;
11641c7c3c6aSMatthew Dillon 		}
11651c7c3c6aSMatthew Dillon 
11661c7c3c6aSMatthew Dillon 		/*
11671c7c3c6aSMatthew Dillon 		 * Now that we are through with the bp, we can call the
11681c7c3c6aSMatthew Dillon 		 * normal async completion, which frees everything up.
11691c7c3c6aSMatthew Dillon 		 */
11701c7c3c6aSMatthew Dillon 
11711c7c3c6aSMatthew Dillon 		swp_pager_async_iodone(bp);
117226f9a767SRodney W. Grimes 
117326f9a767SRodney W. Grimes 		splx(s);
11741c7c3c6aSMatthew Dillon 	}
11751c7c3c6aSMatthew Dillon 
11761c7c3c6aSMatthew Dillon 	return(grv);
11771c7c3c6aSMatthew Dillon }
11781c7c3c6aSMatthew Dillon 
11791c7c3c6aSMatthew Dillon /*
11801c7c3c6aSMatthew Dillon  *	swap_pager_sync_iodone:
11811c7c3c6aSMatthew Dillon  *
11821c7c3c6aSMatthew Dillon  *	Completion routine for synchronous reads and writes from/to swap.
11831c7c3c6aSMatthew Dillon  *	We just mark the bp is complete and wake up anyone waiting on it.
11841c7c3c6aSMatthew Dillon  *
11851c7c3c6aSMatthew Dillon  *	This routine may not block.
11861c7c3c6aSMatthew Dillon  */
11871c7c3c6aSMatthew Dillon 
11881c7c3c6aSMatthew Dillon static void
11891c7c3c6aSMatthew Dillon swp_pager_sync_iodone(bp)
11901c7c3c6aSMatthew Dillon 	struct buf *bp;
11911c7c3c6aSMatthew Dillon {
11921c7c3c6aSMatthew Dillon 	bp->b_flags |= B_DONE;
11931c7c3c6aSMatthew Dillon 	bp->b_flags &= ~B_ASYNC;
11941c7c3c6aSMatthew Dillon 	wakeup(bp);
11951c7c3c6aSMatthew Dillon }
11961c7c3c6aSMatthew Dillon 
11971c7c3c6aSMatthew Dillon /*
11981c7c3c6aSMatthew Dillon  *	swp_pager_async_iodone:
11991c7c3c6aSMatthew Dillon  *
12001c7c3c6aSMatthew Dillon  *	Completion routine for asynchronous reads and writes from/to swap.
12011c7c3c6aSMatthew Dillon  *	Also called manually by synchronous code to finish up a bp.
12021c7c3c6aSMatthew Dillon  *
12031c7c3c6aSMatthew Dillon  *	WARNING!  This routine may be called from an interrupt.  We cannot
12041c7c3c6aSMatthew Dillon  *	mess with swap metadata unless we want to run all our other routines
12051c7c3c6aSMatthew Dillon  *	at splbio() too, which I'd rather not do.  We up ourselves
12061c7c3c6aSMatthew Dillon  * 	to splvm() because we may call vm_page_free(), which can unlink a
12071c7c3c6aSMatthew Dillon  *	page from an object.
12081c7c3c6aSMatthew Dillon  *
12091c7c3c6aSMatthew Dillon  *	XXX currently I do not believe any object routines protect
12101c7c3c6aSMatthew Dillon  *	object->memq at splvm().  The code must be gone over to determine
12111c7c3c6aSMatthew Dillon  *	the actual state of the problem.
12121c7c3c6aSMatthew Dillon  *
12131c7c3c6aSMatthew Dillon  *	For READ operations, the pages are PG_BUSY'd.  For WRITE operations,
12141c7c3c6aSMatthew Dillon  *	the pages are vm_page_t->busy'd.  For READ operations, we PG_BUSY
12151c7c3c6aSMatthew Dillon  *	unbusy all pages except the 'main' request page.  For WRITE
12161c7c3c6aSMatthew Dillon  *	operations, we vm_page_t->busy'd unbusy all pages ( we can do this
12171c7c3c6aSMatthew Dillon  *	because we marked them all VM_PAGER_PEND on return from putpages ).
12181c7c3c6aSMatthew Dillon  *
12191c7c3c6aSMatthew Dillon  *	This routine may not block.
12201c7c3c6aSMatthew Dillon  *	This routine is called at splbio()
12211c7c3c6aSMatthew Dillon  */
12221c7c3c6aSMatthew Dillon 
12231c7c3c6aSMatthew Dillon static void
12241c7c3c6aSMatthew Dillon swp_pager_async_iodone(bp)
12251c7c3c6aSMatthew Dillon 	register struct buf *bp;
12261c7c3c6aSMatthew Dillon {
12271c7c3c6aSMatthew Dillon 	int s;
12281c7c3c6aSMatthew Dillon 	int i;
12291c7c3c6aSMatthew Dillon 	vm_object_t object = NULL;
12301c7c3c6aSMatthew Dillon 
12311c7c3c6aSMatthew Dillon 	s = splvm();
12321c7c3c6aSMatthew Dillon 
12331c7c3c6aSMatthew Dillon 	bp->b_flags |= B_DONE;
12341c7c3c6aSMatthew Dillon 
12351c7c3c6aSMatthew Dillon 	/*
12361c7c3c6aSMatthew Dillon 	 * report error
12371c7c3c6aSMatthew Dillon 	 */
12381c7c3c6aSMatthew Dillon 
12391c7c3c6aSMatthew Dillon 	if (bp->b_flags & B_ERROR) {
12401c7c3c6aSMatthew Dillon 		printf(
12411c7c3c6aSMatthew Dillon 		    "swap_pager: I/O error - %s failed; blkno %ld,"
12421c7c3c6aSMatthew Dillon 			"size %ld, error %d\n",
12431c7c3c6aSMatthew Dillon 		    ((bp->b_flags & B_READ) ? "pagein" : "pageout"),
12441c7c3c6aSMatthew Dillon 		    (long)bp->b_blkno,
12451c7c3c6aSMatthew Dillon 		    (long)bp->b_bcount,
12461c7c3c6aSMatthew Dillon 		    bp->b_error
12471c7c3c6aSMatthew Dillon 		);
12481c7c3c6aSMatthew Dillon 	}
12491c7c3c6aSMatthew Dillon 
12501c7c3c6aSMatthew Dillon 	/*
12511c7c3c6aSMatthew Dillon 	 * set object.
12521c7c3c6aSMatthew Dillon 	 */
12531c7c3c6aSMatthew Dillon 
12541c7c3c6aSMatthew Dillon 	if (bp->b_npages)
12551c7c3c6aSMatthew Dillon 		object = bp->b_pages[0]->object;
125626f9a767SRodney W. Grimes 
125726f9a767SRodney W. Grimes 	/*
125826f9a767SRodney W. Grimes 	 * remove the mapping for kernel virtual
125926f9a767SRodney W. Grimes 	 */
12601c7c3c6aSMatthew Dillon 
12611c7c3c6aSMatthew Dillon 	pmap_qremove((vm_offset_t)bp->b_data, bp->b_npages);
126226f9a767SRodney W. Grimes 
126326f9a767SRodney W. Grimes 	/*
12641c7c3c6aSMatthew Dillon 	 * cleanup pages.  If an error occurs writing to swap, we are in
12651c7c3c6aSMatthew Dillon 	 * very serious trouble.  If it happens to be a disk error, though,
12661c7c3c6aSMatthew Dillon 	 * we may be able to recover by reassigning the swap later on.  So
12671c7c3c6aSMatthew Dillon 	 * in this case we remove the m->swapblk assignment for the page
12681c7c3c6aSMatthew Dillon 	 * but do not free it in the rlist.  The errornous block(s) are thus
12691c7c3c6aSMatthew Dillon 	 * never reallocated as swap.  Redirty the page and continue.
127026f9a767SRodney W. Grimes 	 */
127126f9a767SRodney W. Grimes 
12721c7c3c6aSMatthew Dillon 	for (i = 0; i < bp->b_npages; ++i) {
12731c7c3c6aSMatthew Dillon 		vm_page_t m = bp->b_pages[i];
1274e47ed70bSJohn Dyson 
12751c7c3c6aSMatthew Dillon 		vm_page_flag_clear(m, PG_SWAPINPROG);
1276e47ed70bSJohn Dyson 
127726f9a767SRodney W. Grimes 		if (bp->b_flags & B_ERROR) {
1278ffc82b0aSJohn Dyson 			/*
12791c7c3c6aSMatthew Dillon 			 * If an error occurs I'd love to throw the swapblk
12801c7c3c6aSMatthew Dillon 			 * away without freeing it back to swapspace, so it
12811c7c3c6aSMatthew Dillon 			 * can never be used again.  But I can't from an
12821c7c3c6aSMatthew Dillon 			 * interrupt.
1283ffc82b0aSJohn Dyson 			 */
12841c7c3c6aSMatthew Dillon 
12851c7c3c6aSMatthew Dillon 			if (bp->b_flags & B_READ) {
12861c7c3c6aSMatthew Dillon 				/*
12871c7c3c6aSMatthew Dillon 				 * When reading, reqpage needs to stay
12881c7c3c6aSMatthew Dillon 				 * locked for the parent, but all other
12891c7c3c6aSMatthew Dillon 				 * pages can be freed.  We still want to
12901c7c3c6aSMatthew Dillon 				 * wakeup the parent waiting on the page,
12911c7c3c6aSMatthew Dillon 				 * though.  ( also: pg_reqpage can be -1 and
12921c7c3c6aSMatthew Dillon 				 * not match anything ).
12931c7c3c6aSMatthew Dillon 				 *
12941c7c3c6aSMatthew Dillon 				 * We have to wake specifically requested pages
12951c7c3c6aSMatthew Dillon 				 * up too because we cleared PG_SWAPINPROG and
12961c7c3c6aSMatthew Dillon 				 * someone may be waiting for that.
12971c7c3c6aSMatthew Dillon 				 *
12981c7c3c6aSMatthew Dillon 				 * NOTE: for reads, m->dirty will probably
12991c7c3c6aSMatthew Dillon 				 * be overriden by the original caller of
13001c7c3c6aSMatthew Dillon 				 * getpages so don't play cute tricks here.
13011c7c3c6aSMatthew Dillon 				 *
13021c7c3c6aSMatthew Dillon 				 * XXX it may not be legal to free the page
13031c7c3c6aSMatthew Dillon 				 * here as this messes with the object->memq's.
13041c7c3c6aSMatthew Dillon 				 */
13051c7c3c6aSMatthew Dillon 
13061c7c3c6aSMatthew Dillon 				m->valid = 0;
13071c7c3c6aSMatthew Dillon 				vm_page_flag_clear(m, PG_ZERO);
13081c7c3c6aSMatthew Dillon 
13091c7c3c6aSMatthew Dillon 				if (i != bp->b_pager.pg_reqpage)
13101c7c3c6aSMatthew Dillon 					vm_page_free(m);
13111c7c3c6aSMatthew Dillon 				else
13121c7c3c6aSMatthew Dillon 					vm_page_flash(m);
13131c7c3c6aSMatthew Dillon 				/*
13141c7c3c6aSMatthew Dillon 				 * If i == bp->b_pager.pg_reqpage, do not wake
13151c7c3c6aSMatthew Dillon 				 * the page up.  The caller needs to.
13161c7c3c6aSMatthew Dillon 				 */
13171c7c3c6aSMatthew Dillon 			} else {
13181c7c3c6aSMatthew Dillon 				/*
13191c7c3c6aSMatthew Dillon 				 * If a write error occurs, reactivate page
13201c7c3c6aSMatthew Dillon 				 * so it doesn't clog the inactive list,
13211c7c3c6aSMatthew Dillon 				 * then finish the I/O.
13221c7c3c6aSMatthew Dillon 				 */
13231c7c3c6aSMatthew Dillon 				m->dirty = VM_PAGE_BITS_ALL;
13241c7c3c6aSMatthew Dillon 				vm_page_activate(m);
13251c7c3c6aSMatthew Dillon 				vm_page_io_finish(m);
13261c7c3c6aSMatthew Dillon 			}
13271c7c3c6aSMatthew Dillon 		} else if (bp->b_flags & B_READ) {
13281c7c3c6aSMatthew Dillon 			/*
13291c7c3c6aSMatthew Dillon 			 * For read success, clear dirty bits.  Nobody should
13301c7c3c6aSMatthew Dillon 			 * have this page mapped but don't take any chances,
13311c7c3c6aSMatthew Dillon 			 * make sure the pmap modify bits are also cleared.
13321c7c3c6aSMatthew Dillon 			 *
13331c7c3c6aSMatthew Dillon 			 * NOTE: for reads, m->dirty will probably be
13341c7c3c6aSMatthew Dillon 			 * overriden by the original caller of getpages so
13351c7c3c6aSMatthew Dillon 			 * we cannot set them in order to free the underlying
13361c7c3c6aSMatthew Dillon 			 * swap in a low-swap situation.  I don't think we'd
13371c7c3c6aSMatthew Dillon 			 * want to do that anyway, but it was an optimization
13381c7c3c6aSMatthew Dillon 			 * that existed in the old swapper for a time before
13391c7c3c6aSMatthew Dillon 			 * it got ripped out due to precisely this problem.
13401c7c3c6aSMatthew Dillon 			 *
13411c7c3c6aSMatthew Dillon 			 * clear PG_ZERO in page.
13421c7c3c6aSMatthew Dillon 			 *
13431c7c3c6aSMatthew Dillon 			 * If not the requested page then deactivate it.
13441c7c3c6aSMatthew Dillon 			 *
13451c7c3c6aSMatthew Dillon 			 * Note that the requested page, reqpage, is left
13461c7c3c6aSMatthew Dillon 			 * busied, but we still have to wake it up.  The
13471c7c3c6aSMatthew Dillon 			 * other pages are released (unbusied) by
13481c7c3c6aSMatthew Dillon 			 * vm_page_wakeup().  We do not set reqpage's
13491c7c3c6aSMatthew Dillon 			 * valid bits here, it is up to the caller.
13501c7c3c6aSMatthew Dillon 			 */
13511c7c3c6aSMatthew Dillon 
13521c7c3c6aSMatthew Dillon 			pmap_clear_modify(VM_PAGE_TO_PHYS(m));
13531c7c3c6aSMatthew Dillon 			m->valid = VM_PAGE_BITS_ALL;
13541c7c3c6aSMatthew Dillon 			m->dirty = 0;
13551c7c3c6aSMatthew Dillon 			vm_page_flag_clear(m, PG_ZERO);
13561c7c3c6aSMatthew Dillon 
13571c7c3c6aSMatthew Dillon 			/*
13581c7c3c6aSMatthew Dillon 			 * We have to wake specifically requested pages
13591c7c3c6aSMatthew Dillon 			 * up too because we cleared PG_SWAPINPROG and
13601c7c3c6aSMatthew Dillon 			 * could be waiting for it in getpages.  However,
13611c7c3c6aSMatthew Dillon 			 * be sure to not unbusy getpages specifically
13621c7c3c6aSMatthew Dillon 			 * requested page - getpages expects it to be
13631c7c3c6aSMatthew Dillon 			 * left busy.
13641c7c3c6aSMatthew Dillon 			 */
13651c7c3c6aSMatthew Dillon 			if (i != bp->b_pager.pg_reqpage) {
13661c7c3c6aSMatthew Dillon 				vm_page_deactivate(m);
13671c7c3c6aSMatthew Dillon 				vm_page_wakeup(m);
13681c7c3c6aSMatthew Dillon 			} else {
13691c7c3c6aSMatthew Dillon 				vm_page_flash(m);
13701c7c3c6aSMatthew Dillon 			}
13711c7c3c6aSMatthew Dillon 		} else {
13721c7c3c6aSMatthew Dillon 			/*
13731c7c3c6aSMatthew Dillon 			 * For write success, clear the modify and dirty
13741c7c3c6aSMatthew Dillon 			 * status, then finish the I/O ( which decrements the
13751c7c3c6aSMatthew Dillon 			 * busy count and possibly wakes waiter's up ).
13761c7c3c6aSMatthew Dillon 			 */
13771c7c3c6aSMatthew Dillon 			vm_page_protect(m, VM_PROT_READ);
13781c7c3c6aSMatthew Dillon 			pmap_clear_modify(VM_PAGE_TO_PHYS(m));
13791c7c3c6aSMatthew Dillon 			m->dirty = 0;
13801c7c3c6aSMatthew Dillon 			vm_page_io_finish(m);
1381ffc82b0aSJohn Dyson 		}
1382df8bae1dSRodney W. Grimes 	}
138326f9a767SRodney W. Grimes 
13841c7c3c6aSMatthew Dillon 	/*
13851c7c3c6aSMatthew Dillon 	 * adjust pip.  NOTE: the original parent may still have its own
13861c7c3c6aSMatthew Dillon 	 * pip refs on the object.
13871c7c3c6aSMatthew Dillon 	 */
13880d94caffSDavid Greenman 
13891c7c3c6aSMatthew Dillon 	if (object)
13901c7c3c6aSMatthew Dillon 		vm_object_pip_wakeupn(object, bp->b_npages);
139126f9a767SRodney W. Grimes 
13921c7c3c6aSMatthew Dillon 	/*
13931c7c3c6aSMatthew Dillon 	 * release the physical I/O buffer
13941c7c3c6aSMatthew Dillon 	 */
1395e47ed70bSJohn Dyson 
13961c7c3c6aSMatthew Dillon 	relpbuf(bp, ((bp->b_flags & B_READ) ? &nsw_rcount : &nsw_wcount));
1397e47ed70bSJohn Dyson 
139826f9a767SRodney W. Grimes 	splx(s);
139926f9a767SRodney W. Grimes }
14001c7c3c6aSMatthew Dillon 
14011c7c3c6aSMatthew Dillon /************************************************************************
14021c7c3c6aSMatthew Dillon  *				SWAP META DATA 				*
14031c7c3c6aSMatthew Dillon  ************************************************************************
14041c7c3c6aSMatthew Dillon  *
14051c7c3c6aSMatthew Dillon  *	These routines manipulate the swap metadata stored in the
14061c7c3c6aSMatthew Dillon  *	OBJT_SWAP object.
14071c7c3c6aSMatthew Dillon  *
14081c7c3c6aSMatthew Dillon  *	In fact, we just have a few counters in the vm_object_t.  The
14091c7c3c6aSMatthew Dillon  *	metadata is actually stored in a hash table.
14101c7c3c6aSMatthew Dillon  */
14111c7c3c6aSMatthew Dillon 
14121c7c3c6aSMatthew Dillon /*
14131c7c3c6aSMatthew Dillon  * SWP_PAGER_HASH() -	hash swap meta data
14141c7c3c6aSMatthew Dillon  *
14151c7c3c6aSMatthew Dillon  *	This is an inline helper function which hash the swapblk given
14161c7c3c6aSMatthew Dillon  *	the object and page index.  It returns a pointer to a pointer
14171c7c3c6aSMatthew Dillon  *	to the object, or a pointer to a NULL pointer if it could not
14181c7c3c6aSMatthew Dillon  *	find a swapblk.
14191c7c3c6aSMatthew Dillon  */
14201c7c3c6aSMatthew Dillon 
14211c7c3c6aSMatthew Dillon static __inline struct swblock **
14221c7c3c6aSMatthew Dillon swp_pager_hash(vm_object_t object, daddr_t index)
14231c7c3c6aSMatthew Dillon {
14241c7c3c6aSMatthew Dillon 	struct swblock **pswap;
14251c7c3c6aSMatthew Dillon 	struct swblock *swap;
14261c7c3c6aSMatthew Dillon 
14271c7c3c6aSMatthew Dillon 	index &= ~SWAP_META_MASK;
14281c7c3c6aSMatthew Dillon 	pswap = &swhash[(index ^ (int)(long)object) & swhash_mask];
14291c7c3c6aSMatthew Dillon 
14301c7c3c6aSMatthew Dillon 	while ((swap = *pswap) != NULL) {
14311c7c3c6aSMatthew Dillon 		if (swap->swb_object == object &&
14321c7c3c6aSMatthew Dillon 		    swap->swb_index == index
14331c7c3c6aSMatthew Dillon 		) {
14341c7c3c6aSMatthew Dillon 			break;
14351c7c3c6aSMatthew Dillon 		}
14361c7c3c6aSMatthew Dillon 		pswap = &swap->swb_hnext;
14371c7c3c6aSMatthew Dillon 	}
14381c7c3c6aSMatthew Dillon 	return(pswap);
14391c7c3c6aSMatthew Dillon }
14401c7c3c6aSMatthew Dillon 
14411c7c3c6aSMatthew Dillon /*
14421c7c3c6aSMatthew Dillon  * SWP_PAGER_META_BUILD() -	add swap block to swap meta data for object
14431c7c3c6aSMatthew Dillon  *
14441c7c3c6aSMatthew Dillon  *	We first convert the object to a swap object if it is a default
14451c7c3c6aSMatthew Dillon  *	object.
14461c7c3c6aSMatthew Dillon  *
14471c7c3c6aSMatthew Dillon  *	The specified swapblk is added to the object's swap metadata.  If
14481c7c3c6aSMatthew Dillon  *	the swapblk is not valid, it is freed instead.  Any previously
14491c7c3c6aSMatthew Dillon  *	assigned swapblk is freed.
14501c7c3c6aSMatthew Dillon  */
14511c7c3c6aSMatthew Dillon 
14521c7c3c6aSMatthew Dillon static void
14531c7c3c6aSMatthew Dillon swp_pager_meta_build(
14541c7c3c6aSMatthew Dillon 	vm_object_t object,
14551c7c3c6aSMatthew Dillon 	daddr_t index,
14561c7c3c6aSMatthew Dillon 	daddr_t swapblk,
14571c7c3c6aSMatthew Dillon 	int waitok
14581c7c3c6aSMatthew Dillon ) {
14591c7c3c6aSMatthew Dillon 	struct swblock *swap;
14601c7c3c6aSMatthew Dillon 	struct swblock **pswap;
14611c7c3c6aSMatthew Dillon 
14621c7c3c6aSMatthew Dillon 	/*
14631c7c3c6aSMatthew Dillon 	 * Convert default object to swap object if necessary
14641c7c3c6aSMatthew Dillon 	 */
14651c7c3c6aSMatthew Dillon 
14661c7c3c6aSMatthew Dillon 	if (object->type != OBJT_SWAP) {
14671c7c3c6aSMatthew Dillon 		object->type = OBJT_SWAP;
14681c7c3c6aSMatthew Dillon 		object->un_pager.swp.swp_bcount = 0;
14691c7c3c6aSMatthew Dillon 
14701c7c3c6aSMatthew Dillon 		if (object->handle != NULL) {
14711c7c3c6aSMatthew Dillon 			TAILQ_INSERT_TAIL(
14721c7c3c6aSMatthew Dillon 			    NOBJLIST(object->handle),
14731c7c3c6aSMatthew Dillon 			    object,
14741c7c3c6aSMatthew Dillon 			    pager_object_list
14751c7c3c6aSMatthew Dillon 			);
14761c7c3c6aSMatthew Dillon 		} else {
14771c7c3c6aSMatthew Dillon 			TAILQ_INSERT_TAIL(
14781c7c3c6aSMatthew Dillon 			    &swap_pager_un_object_list,
14791c7c3c6aSMatthew Dillon 			    object,
14801c7c3c6aSMatthew Dillon 			    pager_object_list
14811c7c3c6aSMatthew Dillon 			);
14821c7c3c6aSMatthew Dillon 		}
14831c7c3c6aSMatthew Dillon 	}
14841c7c3c6aSMatthew Dillon 
14851c7c3c6aSMatthew Dillon 	/*
14861c7c3c6aSMatthew Dillon 	 * Wait for free memory when waitok is TRUE prior to calling the
14871c7c3c6aSMatthew Dillon 	 * zone allocator.
14881c7c3c6aSMatthew Dillon 	 */
14891c7c3c6aSMatthew Dillon 
14901c7c3c6aSMatthew Dillon 	while (waitok && cnt.v_free_count == 0) {
14911c7c3c6aSMatthew Dillon 		VM_WAIT;
14921c7c3c6aSMatthew Dillon 	}
14931c7c3c6aSMatthew Dillon 
14941c7c3c6aSMatthew Dillon 	/*
14951c7c3c6aSMatthew Dillon 	 * If swapblk being added is invalid, just free it.
14961c7c3c6aSMatthew Dillon 	 */
14971c7c3c6aSMatthew Dillon 
14981c7c3c6aSMatthew Dillon 	if (swapblk & SWAPBLK_NONE) {
14991c7c3c6aSMatthew Dillon 		if (swapblk != SWAPBLK_NONE) {
15001c7c3c6aSMatthew Dillon 			swp_pager_freeswapspace(
15011c7c3c6aSMatthew Dillon 			    index,
15021c7c3c6aSMatthew Dillon 			    1
15031c7c3c6aSMatthew Dillon 			);
15041c7c3c6aSMatthew Dillon 			swapblk = SWAPBLK_NONE;
15051c7c3c6aSMatthew Dillon 		}
15061c7c3c6aSMatthew Dillon 	}
15071c7c3c6aSMatthew Dillon 
15081c7c3c6aSMatthew Dillon 	/*
15091c7c3c6aSMatthew Dillon 	 * Locate hash entry.  If not found create, but if we aren't adding
15101c7c3c6aSMatthew Dillon 	 * anything just return.
15111c7c3c6aSMatthew Dillon 	 */
15121c7c3c6aSMatthew Dillon 
15131c7c3c6aSMatthew Dillon 	pswap = swp_pager_hash(object, index);
15141c7c3c6aSMatthew Dillon 
15151c7c3c6aSMatthew Dillon 	if ((swap = *pswap) == NULL) {
15161c7c3c6aSMatthew Dillon 		int i;
15171c7c3c6aSMatthew Dillon 
15181c7c3c6aSMatthew Dillon 		if (swapblk == SWAPBLK_NONE)
15191c7c3c6aSMatthew Dillon 			return;
15201c7c3c6aSMatthew Dillon 
15211c7c3c6aSMatthew Dillon 		swap = *pswap = zalloc(swap_zone);
15221c7c3c6aSMatthew Dillon 
15231c7c3c6aSMatthew Dillon 		swap->swb_hnext = NULL;
15241c7c3c6aSMatthew Dillon 		swap->swb_object = object;
15251c7c3c6aSMatthew Dillon 		swap->swb_index = index & ~SWAP_META_MASK;
15261c7c3c6aSMatthew Dillon 		swap->swb_count = 0;
15271c7c3c6aSMatthew Dillon 
15281c7c3c6aSMatthew Dillon 		++object->un_pager.swp.swp_bcount;
15291c7c3c6aSMatthew Dillon 
15301c7c3c6aSMatthew Dillon 		for (i = 0; i < SWAP_META_PAGES; ++i)
15311c7c3c6aSMatthew Dillon 			swap->swb_pages[i] = SWAPBLK_NONE;
15321c7c3c6aSMatthew Dillon 	}
15331c7c3c6aSMatthew Dillon 
15341c7c3c6aSMatthew Dillon 	/*
15351c7c3c6aSMatthew Dillon 	 * Delete prior contents of metadata
15361c7c3c6aSMatthew Dillon 	 */
15371c7c3c6aSMatthew Dillon 
15381c7c3c6aSMatthew Dillon 	index &= SWAP_META_MASK;
15391c7c3c6aSMatthew Dillon 
15401c7c3c6aSMatthew Dillon 	if (swap->swb_pages[index] != SWAPBLK_NONE) {
15411c7c3c6aSMatthew Dillon 		swp_pager_freeswapspace(
15421c7c3c6aSMatthew Dillon 		    swap->swb_pages[index] & SWAPBLK_MASK,
15431c7c3c6aSMatthew Dillon 		    1
15441c7c3c6aSMatthew Dillon 		);
15451c7c3c6aSMatthew Dillon 		--swap->swb_count;
15461c7c3c6aSMatthew Dillon 	}
15471c7c3c6aSMatthew Dillon 
15481c7c3c6aSMatthew Dillon 	/*
15491c7c3c6aSMatthew Dillon 	 * Enter block into metadata
15501c7c3c6aSMatthew Dillon 	 */
15511c7c3c6aSMatthew Dillon 
15521c7c3c6aSMatthew Dillon 	swap->swb_pages[index] = swapblk;
15531c7c3c6aSMatthew Dillon 	++swap->swb_count;
15541c7c3c6aSMatthew Dillon }
15551c7c3c6aSMatthew Dillon 
15561c7c3c6aSMatthew Dillon /*
15571c7c3c6aSMatthew Dillon  * SWP_PAGER_META_FREE() - free a range of blocks in the object's swap metadata
15581c7c3c6aSMatthew Dillon  *
15591c7c3c6aSMatthew Dillon  *	The requested range of blocks is freed, with any associated swap
15601c7c3c6aSMatthew Dillon  *	returned to the swap bitmap.
15611c7c3c6aSMatthew Dillon  *
15621c7c3c6aSMatthew Dillon  *	This routine will free swap metadata structures as they are cleaned
15631c7c3c6aSMatthew Dillon  *	out.  This routine does *NOT* operate on swap metadata associated
15641c7c3c6aSMatthew Dillon  *	with resident pages.
15651c7c3c6aSMatthew Dillon  *
15661c7c3c6aSMatthew Dillon  *	This routine must be called at splvm()
15671c7c3c6aSMatthew Dillon  */
15681c7c3c6aSMatthew Dillon 
15691c7c3c6aSMatthew Dillon static void
15701c7c3c6aSMatthew Dillon swp_pager_meta_free(vm_object_t object, daddr_t index, daddr_t count)
15711c7c3c6aSMatthew Dillon {
15721c7c3c6aSMatthew Dillon 	if (object->type != OBJT_SWAP)
15731c7c3c6aSMatthew Dillon 		return;
15741c7c3c6aSMatthew Dillon 
15751c7c3c6aSMatthew Dillon 	while (count > 0) {
15761c7c3c6aSMatthew Dillon 		struct swblock **pswap;
15771c7c3c6aSMatthew Dillon 		struct swblock *swap;
15781c7c3c6aSMatthew Dillon 
15791c7c3c6aSMatthew Dillon 		pswap = swp_pager_hash(object, index);
15801c7c3c6aSMatthew Dillon 
15811c7c3c6aSMatthew Dillon 		if ((swap = *pswap) != NULL) {
15821c7c3c6aSMatthew Dillon 			daddr_t v = swap->swb_pages[index & SWAP_META_MASK];
15831c7c3c6aSMatthew Dillon 
15841c7c3c6aSMatthew Dillon 			if (v != SWAPBLK_NONE) {
15851c7c3c6aSMatthew Dillon 				swp_pager_freeswapspace(v, 1);
15861c7c3c6aSMatthew Dillon 				swap->swb_pages[index & SWAP_META_MASK] =
15871c7c3c6aSMatthew Dillon 					SWAPBLK_NONE;
15881c7c3c6aSMatthew Dillon 				if (--swap->swb_count == 0) {
15891c7c3c6aSMatthew Dillon 					*pswap = swap->swb_hnext;
15901c7c3c6aSMatthew Dillon 					zfree(swap_zone, swap);
15911c7c3c6aSMatthew Dillon 					--object->un_pager.swp.swp_bcount;
15921c7c3c6aSMatthew Dillon 				}
15931c7c3c6aSMatthew Dillon 			}
15941c7c3c6aSMatthew Dillon 			--count;
15951c7c3c6aSMatthew Dillon 			++index;
15961c7c3c6aSMatthew Dillon 		} else {
15971c7c3c6aSMatthew Dillon 			daddr_t n = SWAP_META_PAGES - (index & SWAP_META_MASK);
15981c7c3c6aSMatthew Dillon 			count -= n;
15991c7c3c6aSMatthew Dillon 			index += n;
16001c7c3c6aSMatthew Dillon 		}
16011c7c3c6aSMatthew Dillon 	}
16021c7c3c6aSMatthew Dillon }
16031c7c3c6aSMatthew Dillon 
16041c7c3c6aSMatthew Dillon /*
16051c7c3c6aSMatthew Dillon  * SWP_PAGER_META_FREE_ALL() - destroy all swap metadata associated with object
16061c7c3c6aSMatthew Dillon  *
16071c7c3c6aSMatthew Dillon  *	This routine locates and destroys all swap metadata associated with
16081c7c3c6aSMatthew Dillon  *	an object.
16091c7c3c6aSMatthew Dillon  */
16101c7c3c6aSMatthew Dillon 
16111c7c3c6aSMatthew Dillon static void
16121c7c3c6aSMatthew Dillon swp_pager_meta_free_all(vm_object_t object)
16131c7c3c6aSMatthew Dillon {
16141c7c3c6aSMatthew Dillon 	daddr_t index = 0;
16151c7c3c6aSMatthew Dillon 
16161c7c3c6aSMatthew Dillon 	if (object->type != OBJT_SWAP)
16171c7c3c6aSMatthew Dillon 		return;
16181c7c3c6aSMatthew Dillon 
16191c7c3c6aSMatthew Dillon 	while (object->un_pager.swp.swp_bcount) {
16201c7c3c6aSMatthew Dillon 		struct swblock **pswap;
16211c7c3c6aSMatthew Dillon 		struct swblock *swap;
16221c7c3c6aSMatthew Dillon 
16231c7c3c6aSMatthew Dillon 		pswap = swp_pager_hash(object, index);
16241c7c3c6aSMatthew Dillon 		if ((swap = *pswap) != NULL) {
16251c7c3c6aSMatthew Dillon 			int i;
16261c7c3c6aSMatthew Dillon 
16271c7c3c6aSMatthew Dillon 			for (i = 0; i < SWAP_META_PAGES; ++i) {
16281c7c3c6aSMatthew Dillon 				daddr_t v = swap->swb_pages[i];
16291c7c3c6aSMatthew Dillon 				if (v != SWAPBLK_NONE) {
16301c7c3c6aSMatthew Dillon #if !defined(MAX_PERF)
16311c7c3c6aSMatthew Dillon 					--swap->swb_count;
16321c7c3c6aSMatthew Dillon #endif
16331c7c3c6aSMatthew Dillon 					swp_pager_freeswapspace(
16341c7c3c6aSMatthew Dillon 					    v,
16351c7c3c6aSMatthew Dillon 					    1
16361c7c3c6aSMatthew Dillon 					);
16371c7c3c6aSMatthew Dillon 				}
16381c7c3c6aSMatthew Dillon 			}
16391c7c3c6aSMatthew Dillon #if !defined(MAX_PERF)
16401c7c3c6aSMatthew Dillon 			if (swap->swb_count != 0)
16411c7c3c6aSMatthew Dillon 				panic("swap_pager_meta_free_all: swb_count != 0");
16421c7c3c6aSMatthew Dillon #endif
16431c7c3c6aSMatthew Dillon 			*pswap = swap->swb_hnext;
16441c7c3c6aSMatthew Dillon 			zfree(swap_zone, swap);
16451c7c3c6aSMatthew Dillon 			--object->un_pager.swp.swp_bcount;
16461c7c3c6aSMatthew Dillon 		}
16471c7c3c6aSMatthew Dillon 		index += SWAP_META_PAGES;
16481c7c3c6aSMatthew Dillon #if !defined(MAX_PERF)
16491c7c3c6aSMatthew Dillon 		if (index > 0x20000000)
16501c7c3c6aSMatthew Dillon 			panic("swp_pager_meta_free_all: failed to locate all swap meta blocks");
16511c7c3c6aSMatthew Dillon #endif
16521c7c3c6aSMatthew Dillon 	}
16531c7c3c6aSMatthew Dillon }
16541c7c3c6aSMatthew Dillon 
16551c7c3c6aSMatthew Dillon /*
16561c7c3c6aSMatthew Dillon  * SWP_PAGER_METACTL() -  misc control of swap and vm_page_t meta data.
16571c7c3c6aSMatthew Dillon  *
16581c7c3c6aSMatthew Dillon  *	This routine is capable of looking up, popping, or freeing
16591c7c3c6aSMatthew Dillon  *	swapblk assignments in the swap meta data or in the vm_page_t.
16601c7c3c6aSMatthew Dillon  *	The routine typically returns the swapblk being looked-up, or popped,
16611c7c3c6aSMatthew Dillon  *	or SWAPBLK_NONE if the block was freed, or SWAPBLK_NONE if the block
16621c7c3c6aSMatthew Dillon  *	was invalid.  This routine will automatically free any invalid
16631c7c3c6aSMatthew Dillon  *	meta-data swapblks.
16641c7c3c6aSMatthew Dillon  *
16651c7c3c6aSMatthew Dillon  *	It is not possible to store invalid swapblks in the swap meta data
16661c7c3c6aSMatthew Dillon  *	(other then a literal 'SWAPBLK_NONE'), so we don't bother checking.
16671c7c3c6aSMatthew Dillon  *
16681c7c3c6aSMatthew Dillon  *	When acting on a busy resident page and paging is in progress, we
16691c7c3c6aSMatthew Dillon  *	have to wait until paging is complete but otherwise can act on the
16701c7c3c6aSMatthew Dillon  *	busy page.
16711c7c3c6aSMatthew Dillon  *
16721c7c3c6aSMatthew Dillon  *	SWM_FREE	remove and free swap block from metadata
16731c7c3c6aSMatthew Dillon  *
16741c7c3c6aSMatthew Dillon  *	SWM_POP		remove from meta data but do not free.. pop it out
16751c7c3c6aSMatthew Dillon  */
16761c7c3c6aSMatthew Dillon 
16771c7c3c6aSMatthew Dillon static daddr_t
16781c7c3c6aSMatthew Dillon swp_pager_meta_ctl(
16791c7c3c6aSMatthew Dillon 	vm_object_t object,
16801c7c3c6aSMatthew Dillon 	vm_pindex_t index,
16811c7c3c6aSMatthew Dillon 	int flags
16821c7c3c6aSMatthew Dillon ) {
16831c7c3c6aSMatthew Dillon 	/*
16841c7c3c6aSMatthew Dillon 	 * The meta data only exists of the object is OBJT_SWAP
16851c7c3c6aSMatthew Dillon 	 * and even then might not be allocated yet.
16861c7c3c6aSMatthew Dillon 	 */
16871c7c3c6aSMatthew Dillon 
16881c7c3c6aSMatthew Dillon 	if (
16891c7c3c6aSMatthew Dillon 	    object->type != OBJT_SWAP ||
16901c7c3c6aSMatthew Dillon 	    object->un_pager.swp.swp_bcount == 0
16911c7c3c6aSMatthew Dillon 	) {
16921c7c3c6aSMatthew Dillon 		return(SWAPBLK_NONE);
16931c7c3c6aSMatthew Dillon 	}
16941c7c3c6aSMatthew Dillon 
16951c7c3c6aSMatthew Dillon 	{
16961c7c3c6aSMatthew Dillon 		struct swblock **pswap;
16971c7c3c6aSMatthew Dillon 		struct swblock *swap;
16981c7c3c6aSMatthew Dillon 		daddr_t r1 = SWAPBLK_NONE;
16991c7c3c6aSMatthew Dillon 
17001c7c3c6aSMatthew Dillon 		pswap = swp_pager_hash(object, index);
17011c7c3c6aSMatthew Dillon 
17021c7c3c6aSMatthew Dillon 		index &= SWAP_META_MASK;
17031c7c3c6aSMatthew Dillon 
17041c7c3c6aSMatthew Dillon 		if ((swap = *pswap) != NULL) {
17051c7c3c6aSMatthew Dillon 			r1 = swap->swb_pages[index];
17061c7c3c6aSMatthew Dillon 
17071c7c3c6aSMatthew Dillon 			if (r1 != SWAPBLK_NONE) {
17081c7c3c6aSMatthew Dillon 				if (flags & SWM_FREE) {
17091c7c3c6aSMatthew Dillon 					swp_pager_freeswapspace(
17101c7c3c6aSMatthew Dillon 					    r1,
17111c7c3c6aSMatthew Dillon 					    1
17121c7c3c6aSMatthew Dillon 					);
17131c7c3c6aSMatthew Dillon 					r1 = SWAPBLK_NONE;
17141c7c3c6aSMatthew Dillon 				}
17151c7c3c6aSMatthew Dillon 				if (flags & (SWM_FREE|SWM_POP)) {
17161c7c3c6aSMatthew Dillon 					swap->swb_pages[index] = SWAPBLK_NONE;
17171c7c3c6aSMatthew Dillon 					if (--swap->swb_count == 0) {
17181c7c3c6aSMatthew Dillon 						*pswap = swap->swb_hnext;
17191c7c3c6aSMatthew Dillon 						zfree(swap_zone, swap);
17201c7c3c6aSMatthew Dillon 						--object->un_pager.swp.swp_bcount;
17211c7c3c6aSMatthew Dillon 					}
17221c7c3c6aSMatthew Dillon 				}
17231c7c3c6aSMatthew Dillon 	 		}
17241c7c3c6aSMatthew Dillon 		}
17251c7c3c6aSMatthew Dillon 
17261c7c3c6aSMatthew Dillon 		return(r1);
17271c7c3c6aSMatthew Dillon 	}
17281c7c3c6aSMatthew Dillon 	/* not reached */
17291c7c3c6aSMatthew Dillon }
17301c7c3c6aSMatthew Dillon 
1731