xref: /freebsd/sys/vm/swap_pager.c (revision df8bae1de4b67ccf57f4afebd4e2bf258c38910d)
1df8bae1dSRodney W. Grimes /*
2df8bae1dSRodney W. Grimes  * Copyright (c) 1990 University of Utah.
3df8bae1dSRodney W. Grimes  * Copyright (c) 1991, 1993
4df8bae1dSRodney W. Grimes  *	The Regents of the University of California.  All rights reserved.
5df8bae1dSRodney W. Grimes  *
6df8bae1dSRodney W. Grimes  * This code is derived from software contributed to Berkeley by
7df8bae1dSRodney W. Grimes  * the Systems Programming Group of the University of Utah Computer
8df8bae1dSRodney W. Grimes  * Science Department.
9df8bae1dSRodney W. Grimes  *
10df8bae1dSRodney W. Grimes  * Redistribution and use in source and binary forms, with or without
11df8bae1dSRodney W. Grimes  * modification, are permitted provided that the following conditions
12df8bae1dSRodney W. Grimes  * are met:
13df8bae1dSRodney W. Grimes  * 1. Redistributions of source code must retain the above copyright
14df8bae1dSRodney W. Grimes  *    notice, this list of conditions and the following disclaimer.
15df8bae1dSRodney W. Grimes  * 2. Redistributions in binary form must reproduce the above copyright
16df8bae1dSRodney W. Grimes  *    notice, this list of conditions and the following disclaimer in the
17df8bae1dSRodney W. Grimes  *    documentation and/or other materials provided with the distribution.
18df8bae1dSRodney W. Grimes  * 3. All advertising materials mentioning features or use of this software
19df8bae1dSRodney W. Grimes  *    must display the following acknowledgement:
20df8bae1dSRodney W. Grimes  *	This product includes software developed by the University of
21df8bae1dSRodney W. Grimes  *	California, Berkeley and its contributors.
22df8bae1dSRodney W. Grimes  * 4. Neither the name of the University nor the names of its contributors
23df8bae1dSRodney W. Grimes  *    may be used to endorse or promote products derived from this software
24df8bae1dSRodney W. Grimes  *    without specific prior written permission.
25df8bae1dSRodney W. Grimes  *
26df8bae1dSRodney W. Grimes  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
27df8bae1dSRodney W. Grimes  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
28df8bae1dSRodney W. Grimes  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
29df8bae1dSRodney W. Grimes  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
30df8bae1dSRodney W. Grimes  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
31df8bae1dSRodney W. Grimes  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
32df8bae1dSRodney W. Grimes  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
33df8bae1dSRodney W. Grimes  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
34df8bae1dSRodney W. Grimes  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
35df8bae1dSRodney W. Grimes  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
36df8bae1dSRodney W. Grimes  * SUCH DAMAGE.
37df8bae1dSRodney W. Grimes  *
38df8bae1dSRodney W. Grimes  * from: Utah $Hdr: swap_pager.c 1.4 91/04/30$
39df8bae1dSRodney W. Grimes  *
40df8bae1dSRodney W. Grimes  *	@(#)swap_pager.c	8.9 (Berkeley) 3/21/94
41df8bae1dSRodney W. Grimes  */
42df8bae1dSRodney W. Grimes 
43df8bae1dSRodney W. Grimes /*
44df8bae1dSRodney W. Grimes  * Quick hack to page to dedicated partition(s).
45df8bae1dSRodney W. Grimes  * TODO:
46df8bae1dSRodney W. Grimes  *	Add multiprocessor locks
47df8bae1dSRodney W. Grimes  *	Deal with async writes in a better fashion
48df8bae1dSRodney W. Grimes  */
49df8bae1dSRodney W. Grimes 
50df8bae1dSRodney W. Grimes #include <sys/param.h>
51df8bae1dSRodney W. Grimes #include <sys/systm.h>
52df8bae1dSRodney W. Grimes #include <sys/proc.h>
53df8bae1dSRodney W. Grimes #include <sys/buf.h>
54df8bae1dSRodney W. Grimes #include <sys/map.h>
55df8bae1dSRodney W. Grimes #include <sys/vnode.h>
56df8bae1dSRodney W. Grimes #include <sys/malloc.h>
57df8bae1dSRodney W. Grimes 
58df8bae1dSRodney W. Grimes #include <miscfs/specfs/specdev.h>
59df8bae1dSRodney W. Grimes 
60df8bae1dSRodney W. Grimes #include <vm/vm.h>
61df8bae1dSRodney W. Grimes #include <vm/vm_page.h>
62df8bae1dSRodney W. Grimes #include <vm/vm_pageout.h>
63df8bae1dSRodney W. Grimes #include <vm/swap_pager.h>
64df8bae1dSRodney W. Grimes 
65df8bae1dSRodney W. Grimes #define NSWSIZES	16	/* size of swtab */
66df8bae1dSRodney W. Grimes #define MAXDADDRS	64	/* max # of disk addrs for fixed allocations */
67df8bae1dSRodney W. Grimes #ifndef NPENDINGIO
68df8bae1dSRodney W. Grimes #define NPENDINGIO	64	/* max # of pending cleans */
69df8bae1dSRodney W. Grimes #endif
70df8bae1dSRodney W. Grimes 
71df8bae1dSRodney W. Grimes #ifdef DEBUG
72df8bae1dSRodney W. Grimes int	swpagerdebug = 0x100;
73df8bae1dSRodney W. Grimes #define	SDB_FOLLOW	0x001
74df8bae1dSRodney W. Grimes #define SDB_INIT	0x002
75df8bae1dSRodney W. Grimes #define SDB_ALLOC	0x004
76df8bae1dSRodney W. Grimes #define SDB_IO		0x008
77df8bae1dSRodney W. Grimes #define SDB_WRITE	0x010
78df8bae1dSRodney W. Grimes #define SDB_FAIL	0x020
79df8bae1dSRodney W. Grimes #define SDB_ALLOCBLK	0x040
80df8bae1dSRodney W. Grimes #define SDB_FULL	0x080
81df8bae1dSRodney W. Grimes #define SDB_ANOM	0x100
82df8bae1dSRodney W. Grimes #define SDB_ANOMPANIC	0x200
83df8bae1dSRodney W. Grimes #define SDB_CLUSTER	0x400
84df8bae1dSRodney W. Grimes #define SDB_PARANOIA	0x800
85df8bae1dSRodney W. Grimes #endif
86df8bae1dSRodney W. Grimes 
87df8bae1dSRodney W. Grimes TAILQ_HEAD(swpclean, swpagerclean);
88df8bae1dSRodney W. Grimes 
89df8bae1dSRodney W. Grimes struct swpagerclean {
90df8bae1dSRodney W. Grimes 	TAILQ_ENTRY(swpagerclean)	spc_list;
91df8bae1dSRodney W. Grimes 	int				spc_flags;
92df8bae1dSRodney W. Grimes 	struct buf			*spc_bp;
93df8bae1dSRodney W. Grimes 	sw_pager_t			spc_swp;
94df8bae1dSRodney W. Grimes 	vm_offset_t			spc_kva;
95df8bae1dSRodney W. Grimes 	vm_page_t			spc_m;
96df8bae1dSRodney W. Grimes 	int				spc_npages;
97df8bae1dSRodney W. Grimes } swcleanlist[NPENDINGIO];
98df8bae1dSRodney W. Grimes typedef struct swpagerclean *swp_clean_t;
99df8bae1dSRodney W. Grimes 
100df8bae1dSRodney W. Grimes /* spc_flags values */
101df8bae1dSRodney W. Grimes #define SPC_FREE	0x00
102df8bae1dSRodney W. Grimes #define SPC_BUSY	0x01
103df8bae1dSRodney W. Grimes #define SPC_DONE	0x02
104df8bae1dSRodney W. Grimes #define SPC_ERROR	0x04
105df8bae1dSRodney W. Grimes 
106df8bae1dSRodney W. Grimes struct swtab {
107df8bae1dSRodney W. Grimes 	vm_size_t st_osize;	/* size of object (bytes) */
108df8bae1dSRodney W. Grimes 	int	  st_bsize;	/* vs. size of swap block (DEV_BSIZE units) */
109df8bae1dSRodney W. Grimes #ifdef DEBUG
110df8bae1dSRodney W. Grimes 	u_long	  st_inuse;	/* number in this range in use */
111df8bae1dSRodney W. Grimes 	u_long	  st_usecnt;	/* total used of this size */
112df8bae1dSRodney W. Grimes #endif
113df8bae1dSRodney W. Grimes } swtab[NSWSIZES+1];
114df8bae1dSRodney W. Grimes 
115df8bae1dSRodney W. Grimes #ifdef DEBUG
116df8bae1dSRodney W. Grimes int		swap_pager_poip;	/* pageouts in progress */
117df8bae1dSRodney W. Grimes int		swap_pager_piip;	/* pageins in progress */
118df8bae1dSRodney W. Grimes #endif
119df8bae1dSRodney W. Grimes 
120df8bae1dSRodney W. Grimes int		swap_pager_maxcluster;	/* maximum cluster size */
121df8bae1dSRodney W. Grimes int		swap_pager_npendingio;	/* number of pager clean structs */
122df8bae1dSRodney W. Grimes 
123df8bae1dSRodney W. Grimes struct swpclean	swap_pager_inuse;	/* list of pending page cleans */
124df8bae1dSRodney W. Grimes struct swpclean	swap_pager_free;	/* list of free pager clean structs */
125df8bae1dSRodney W. Grimes struct pagerlst	swap_pager_list;	/* list of "named" anon regions */
126df8bae1dSRodney W. Grimes 
127df8bae1dSRodney W. Grimes static void 		swap_pager_init __P((void));
128df8bae1dSRodney W. Grimes static vm_pager_t	swap_pager_alloc
129df8bae1dSRodney W. Grimes 			    __P((caddr_t, vm_size_t, vm_prot_t, vm_offset_t));
130df8bae1dSRodney W. Grimes static void		swap_pager_clean __P((int));
131df8bae1dSRodney W. Grimes #ifdef DEBUG
132df8bae1dSRodney W. Grimes static void		swap_pager_clean_check __P((vm_page_t *, int, int));
133df8bae1dSRodney W. Grimes #endif
134df8bae1dSRodney W. Grimes static void		swap_pager_cluster
135df8bae1dSRodney W. Grimes 			    __P((vm_pager_t, vm_offset_t,
136df8bae1dSRodney W. Grimes 				 vm_offset_t *, vm_offset_t *));
137df8bae1dSRodney W. Grimes static void		swap_pager_dealloc __P((vm_pager_t));
138df8bae1dSRodney W. Grimes static int		swap_pager_getpage
139df8bae1dSRodney W. Grimes 			    __P((vm_pager_t, vm_page_t *, int, boolean_t));
140df8bae1dSRodney W. Grimes static boolean_t	swap_pager_haspage __P((vm_pager_t, vm_offset_t));
141df8bae1dSRodney W. Grimes static int		swap_pager_io __P((sw_pager_t, vm_page_t *, int, int));
142df8bae1dSRodney W. Grimes static void		swap_pager_iodone __P((struct buf *));
143df8bae1dSRodney W. Grimes static int		swap_pager_putpage
144df8bae1dSRodney W. Grimes 			    __P((vm_pager_t, vm_page_t *, int, boolean_t));
145df8bae1dSRodney W. Grimes 
146df8bae1dSRodney W. Grimes struct pagerops swappagerops = {
147df8bae1dSRodney W. Grimes 	swap_pager_init,
148df8bae1dSRodney W. Grimes 	swap_pager_alloc,
149df8bae1dSRodney W. Grimes 	swap_pager_dealloc,
150df8bae1dSRodney W. Grimes 	swap_pager_getpage,
151df8bae1dSRodney W. Grimes 	swap_pager_putpage,
152df8bae1dSRodney W. Grimes 	swap_pager_haspage,
153df8bae1dSRodney W. Grimes 	swap_pager_cluster
154df8bae1dSRodney W. Grimes };
155df8bae1dSRodney W. Grimes 
156df8bae1dSRodney W. Grimes static void
157df8bae1dSRodney W. Grimes swap_pager_init()
158df8bae1dSRodney W. Grimes {
159df8bae1dSRodney W. Grimes 	register swp_clean_t spc;
160df8bae1dSRodney W. Grimes 	register int i, bsize;
161df8bae1dSRodney W. Grimes 	extern int dmmin, dmmax;
162df8bae1dSRodney W. Grimes 	int maxbsize;
163df8bae1dSRodney W. Grimes 
164df8bae1dSRodney W. Grimes #ifdef DEBUG
165df8bae1dSRodney W. Grimes 	if (swpagerdebug & (SDB_FOLLOW|SDB_INIT))
166df8bae1dSRodney W. Grimes 		printf("swpg_init()\n");
167df8bae1dSRodney W. Grimes #endif
168df8bae1dSRodney W. Grimes 	dfltpagerops = &swappagerops;
169df8bae1dSRodney W. Grimes 	TAILQ_INIT(&swap_pager_list);
170df8bae1dSRodney W. Grimes 
171df8bae1dSRodney W. Grimes 	/*
172df8bae1dSRodney W. Grimes 	 * Allocate async IO structures.
173df8bae1dSRodney W. Grimes 	 *
174df8bae1dSRodney W. Grimes 	 * XXX it would be nice if we could do this dynamically based on
175df8bae1dSRodney W. Grimes 	 * the value of nswbuf (since we are ultimately limited by that)
176df8bae1dSRodney W. Grimes 	 * but neither nswbuf or malloc has been initialized yet.  So the
177df8bae1dSRodney W. Grimes 	 * structs are statically allocated above.
178df8bae1dSRodney W. Grimes 	 */
179df8bae1dSRodney W. Grimes 	swap_pager_npendingio = NPENDINGIO;
180df8bae1dSRodney W. Grimes 
181df8bae1dSRodney W. Grimes 	/*
182df8bae1dSRodney W. Grimes 	 * Initialize clean lists
183df8bae1dSRodney W. Grimes 	 */
184df8bae1dSRodney W. Grimes 	TAILQ_INIT(&swap_pager_inuse);
185df8bae1dSRodney W. Grimes 	TAILQ_INIT(&swap_pager_free);
186df8bae1dSRodney W. Grimes 	for (i = 0, spc = swcleanlist; i < swap_pager_npendingio; i++, spc++) {
187df8bae1dSRodney W. Grimes 		TAILQ_INSERT_TAIL(&swap_pager_free, spc, spc_list);
188df8bae1dSRodney W. Grimes 		spc->spc_flags = SPC_FREE;
189df8bae1dSRodney W. Grimes 	}
190df8bae1dSRodney W. Grimes 
191df8bae1dSRodney W. Grimes 	/*
192df8bae1dSRodney W. Grimes 	 * Calculate the swap allocation constants.
193df8bae1dSRodney W. Grimes 	 */
194df8bae1dSRodney W. Grimes         if (dmmin == 0) {
195df8bae1dSRodney W. Grimes                 dmmin = DMMIN;
196df8bae1dSRodney W. Grimes 		if (dmmin < CLBYTES/DEV_BSIZE)
197df8bae1dSRodney W. Grimes 			dmmin = CLBYTES/DEV_BSIZE;
198df8bae1dSRodney W. Grimes 	}
199df8bae1dSRodney W. Grimes         if (dmmax == 0)
200df8bae1dSRodney W. Grimes                 dmmax = DMMAX;
201df8bae1dSRodney W. Grimes 
202df8bae1dSRodney W. Grimes 	/*
203df8bae1dSRodney W. Grimes 	 * Fill in our table of object size vs. allocation size
204df8bae1dSRodney W. Grimes 	 */
205df8bae1dSRodney W. Grimes 	bsize = btodb(PAGE_SIZE);
206df8bae1dSRodney W. Grimes 	if (bsize < dmmin)
207df8bae1dSRodney W. Grimes 		bsize = dmmin;
208df8bae1dSRodney W. Grimes 	maxbsize = btodb(sizeof(sw_bm_t) * NBBY * PAGE_SIZE);
209df8bae1dSRodney W. Grimes 	if (maxbsize > dmmax)
210df8bae1dSRodney W. Grimes 		maxbsize = dmmax;
211df8bae1dSRodney W. Grimes 	for (i = 0; i < NSWSIZES; i++) {
212df8bae1dSRodney W. Grimes 		swtab[i].st_osize = (vm_size_t) (MAXDADDRS * dbtob(bsize));
213df8bae1dSRodney W. Grimes 		swtab[i].st_bsize = bsize;
214df8bae1dSRodney W. Grimes 		if (bsize <= btodb(MAXPHYS))
215df8bae1dSRodney W. Grimes 			swap_pager_maxcluster = dbtob(bsize);
216df8bae1dSRodney W. Grimes #ifdef DEBUG
217df8bae1dSRodney W. Grimes 		if (swpagerdebug & SDB_INIT)
218df8bae1dSRodney W. Grimes 			printf("swpg_init: ix %d, size %x, bsize %x\n",
219df8bae1dSRodney W. Grimes 			       i, swtab[i].st_osize, swtab[i].st_bsize);
220df8bae1dSRodney W. Grimes #endif
221df8bae1dSRodney W. Grimes 		if (bsize >= maxbsize)
222df8bae1dSRodney W. Grimes 			break;
223df8bae1dSRodney W. Grimes 		bsize *= 2;
224df8bae1dSRodney W. Grimes 	}
225df8bae1dSRodney W. Grimes 	swtab[i].st_osize = 0;
226df8bae1dSRodney W. Grimes 	swtab[i].st_bsize = bsize;
227df8bae1dSRodney W. Grimes }
228df8bae1dSRodney W. Grimes 
229df8bae1dSRodney W. Grimes /*
230df8bae1dSRodney W. Grimes  * Allocate a pager structure and associated resources.
231df8bae1dSRodney W. Grimes  * Note that if we are called from the pageout daemon (handle == NULL)
232df8bae1dSRodney W. Grimes  * we should not wait for memory as it could resulting in deadlock.
233df8bae1dSRodney W. Grimes  */
234df8bae1dSRodney W. Grimes static vm_pager_t
235df8bae1dSRodney W. Grimes swap_pager_alloc(handle, size, prot, foff)
236df8bae1dSRodney W. Grimes 	caddr_t handle;
237df8bae1dSRodney W. Grimes 	register vm_size_t size;
238df8bae1dSRodney W. Grimes 	vm_prot_t prot;
239df8bae1dSRodney W. Grimes 	vm_offset_t foff;
240df8bae1dSRodney W. Grimes {
241df8bae1dSRodney W. Grimes 	register vm_pager_t pager;
242df8bae1dSRodney W. Grimes 	register sw_pager_t swp;
243df8bae1dSRodney W. Grimes 	struct swtab *swt;
244df8bae1dSRodney W. Grimes 	int waitok;
245df8bae1dSRodney W. Grimes 
246df8bae1dSRodney W. Grimes #ifdef DEBUG
247df8bae1dSRodney W. Grimes 	if (swpagerdebug & (SDB_FOLLOW|SDB_ALLOC))
248df8bae1dSRodney W. Grimes 		printf("swpg_alloc(%x, %x, %x)\n", handle, size, prot);
249df8bae1dSRodney W. Grimes #endif
250df8bae1dSRodney W. Grimes 	/*
251df8bae1dSRodney W. Grimes 	 * If this is a "named" anonymous region, look it up and
252df8bae1dSRodney W. Grimes 	 * return the appropriate pager if it exists.
253df8bae1dSRodney W. Grimes 	 */
254df8bae1dSRodney W. Grimes 	if (handle) {
255df8bae1dSRodney W. Grimes 		pager = vm_pager_lookup(&swap_pager_list, handle);
256df8bae1dSRodney W. Grimes 		if (pager != NULL) {
257df8bae1dSRodney W. Grimes 			/*
258df8bae1dSRodney W. Grimes 			 * Use vm_object_lookup to gain a reference
259df8bae1dSRodney W. Grimes 			 * to the object and also to remove from the
260df8bae1dSRodney W. Grimes 			 * object cache.
261df8bae1dSRodney W. Grimes 			 */
262df8bae1dSRodney W. Grimes 			if (vm_object_lookup(pager) == NULL)
263df8bae1dSRodney W. Grimes 				panic("swap_pager_alloc: bad object");
264df8bae1dSRodney W. Grimes 			return(pager);
265df8bae1dSRodney W. Grimes 		}
266df8bae1dSRodney W. Grimes 	}
267df8bae1dSRodney W. Grimes 	/*
268df8bae1dSRodney W. Grimes 	 * Pager doesn't exist, allocate swap management resources
269df8bae1dSRodney W. Grimes 	 * and initialize.
270df8bae1dSRodney W. Grimes 	 */
271df8bae1dSRodney W. Grimes 	waitok = handle ? M_WAITOK : M_NOWAIT;
272df8bae1dSRodney W. Grimes 	pager = (vm_pager_t)malloc(sizeof *pager, M_VMPAGER, waitok);
273df8bae1dSRodney W. Grimes 	if (pager == NULL)
274df8bae1dSRodney W. Grimes 		return(NULL);
275df8bae1dSRodney W. Grimes 	swp = (sw_pager_t)malloc(sizeof *swp, M_VMPGDATA, waitok);
276df8bae1dSRodney W. Grimes 	if (swp == NULL) {
277df8bae1dSRodney W. Grimes #ifdef DEBUG
278df8bae1dSRodney W. Grimes 		if (swpagerdebug & SDB_FAIL)
279df8bae1dSRodney W. Grimes 			printf("swpg_alloc: swpager malloc failed\n");
280df8bae1dSRodney W. Grimes #endif
281df8bae1dSRodney W. Grimes 		free((caddr_t)pager, M_VMPAGER);
282df8bae1dSRodney W. Grimes 		return(NULL);
283df8bae1dSRodney W. Grimes 	}
284df8bae1dSRodney W. Grimes 	size = round_page(size);
285df8bae1dSRodney W. Grimes 	for (swt = swtab; swt->st_osize; swt++)
286df8bae1dSRodney W. Grimes 		if (size <= swt->st_osize)
287df8bae1dSRodney W. Grimes 			break;
288df8bae1dSRodney W. Grimes #ifdef DEBUG
289df8bae1dSRodney W. Grimes 	swt->st_inuse++;
290df8bae1dSRodney W. Grimes 	swt->st_usecnt++;
291df8bae1dSRodney W. Grimes #endif
292df8bae1dSRodney W. Grimes 	swp->sw_osize = size;
293df8bae1dSRodney W. Grimes 	swp->sw_bsize = swt->st_bsize;
294df8bae1dSRodney W. Grimes 	swp->sw_nblocks = (btodb(size) + swp->sw_bsize - 1) / swp->sw_bsize;
295df8bae1dSRodney W. Grimes 	swp->sw_blocks = (sw_blk_t)
296df8bae1dSRodney W. Grimes 		malloc(swp->sw_nblocks*sizeof(*swp->sw_blocks),
297df8bae1dSRodney W. Grimes 		       M_VMPGDATA, M_NOWAIT);
298df8bae1dSRodney W. Grimes 	if (swp->sw_blocks == NULL) {
299df8bae1dSRodney W. Grimes 		free((caddr_t)swp, M_VMPGDATA);
300df8bae1dSRodney W. Grimes 		free((caddr_t)pager, M_VMPAGER);
301df8bae1dSRodney W. Grimes #ifdef DEBUG
302df8bae1dSRodney W. Grimes 		if (swpagerdebug & SDB_FAIL)
303df8bae1dSRodney W. Grimes 			printf("swpg_alloc: sw_blocks malloc failed\n");
304df8bae1dSRodney W. Grimes 		swt->st_inuse--;
305df8bae1dSRodney W. Grimes 		swt->st_usecnt--;
306df8bae1dSRodney W. Grimes #endif
307df8bae1dSRodney W. Grimes 		return(FALSE);
308df8bae1dSRodney W. Grimes 	}
309df8bae1dSRodney W. Grimes 	bzero((caddr_t)swp->sw_blocks,
310df8bae1dSRodney W. Grimes 	      swp->sw_nblocks * sizeof(*swp->sw_blocks));
311df8bae1dSRodney W. Grimes 	swp->sw_poip = 0;
312df8bae1dSRodney W. Grimes 	if (handle) {
313df8bae1dSRodney W. Grimes 		vm_object_t object;
314df8bae1dSRodney W. Grimes 
315df8bae1dSRodney W. Grimes 		swp->sw_flags = SW_NAMED;
316df8bae1dSRodney W. Grimes 		TAILQ_INSERT_TAIL(&swap_pager_list, pager, pg_list);
317df8bae1dSRodney W. Grimes 		/*
318df8bae1dSRodney W. Grimes 		 * Consistant with other pagers: return with object
319df8bae1dSRodney W. Grimes 		 * referenced.  Can't do this with handle == NULL
320df8bae1dSRodney W. Grimes 		 * since it might be the pageout daemon calling.
321df8bae1dSRodney W. Grimes 		 */
322df8bae1dSRodney W. Grimes 		object = vm_object_allocate(size);
323df8bae1dSRodney W. Grimes 		vm_object_enter(object, pager);
324df8bae1dSRodney W. Grimes 		vm_object_setpager(object, pager, 0, FALSE);
325df8bae1dSRodney W. Grimes 	} else {
326df8bae1dSRodney W. Grimes 		swp->sw_flags = 0;
327df8bae1dSRodney W. Grimes 		pager->pg_list.tqe_next = NULL;
328df8bae1dSRodney W. Grimes 		pager->pg_list.tqe_prev = NULL;
329df8bae1dSRodney W. Grimes 	}
330df8bae1dSRodney W. Grimes 	pager->pg_handle = handle;
331df8bae1dSRodney W. Grimes 	pager->pg_ops = &swappagerops;
332df8bae1dSRodney W. Grimes 	pager->pg_type = PG_SWAP;
333df8bae1dSRodney W. Grimes 	pager->pg_flags = PG_CLUSTERPUT;
334df8bae1dSRodney W. Grimes 	pager->pg_data = swp;
335df8bae1dSRodney W. Grimes 
336df8bae1dSRodney W. Grimes #ifdef DEBUG
337df8bae1dSRodney W. Grimes 	if (swpagerdebug & SDB_ALLOC)
338df8bae1dSRodney W. Grimes 		printf("swpg_alloc: pg_data %x, %x of %x at %x\n",
339df8bae1dSRodney W. Grimes 		       swp, swp->sw_nblocks, swp->sw_bsize, swp->sw_blocks);
340df8bae1dSRodney W. Grimes #endif
341df8bae1dSRodney W. Grimes 	return(pager);
342df8bae1dSRodney W. Grimes }
343df8bae1dSRodney W. Grimes 
344df8bae1dSRodney W. Grimes static void
345df8bae1dSRodney W. Grimes swap_pager_dealloc(pager)
346df8bae1dSRodney W. Grimes 	vm_pager_t pager;
347df8bae1dSRodney W. Grimes {
348df8bae1dSRodney W. Grimes 	register int i;
349df8bae1dSRodney W. Grimes 	register sw_blk_t bp;
350df8bae1dSRodney W. Grimes 	register sw_pager_t swp;
351df8bae1dSRodney W. Grimes 	struct swtab *swt;
352df8bae1dSRodney W. Grimes 	int s;
353df8bae1dSRodney W. Grimes 
354df8bae1dSRodney W. Grimes #ifdef DEBUG
355df8bae1dSRodney W. Grimes 	/* save panic time state */
356df8bae1dSRodney W. Grimes 	if ((swpagerdebug & SDB_ANOMPANIC) && panicstr)
357df8bae1dSRodney W. Grimes 		return;
358df8bae1dSRodney W. Grimes 	if (swpagerdebug & (SDB_FOLLOW|SDB_ALLOC))
359df8bae1dSRodney W. Grimes 		printf("swpg_dealloc(%x)\n", pager);
360df8bae1dSRodney W. Grimes #endif
361df8bae1dSRodney W. Grimes 	/*
362df8bae1dSRodney W. Grimes 	 * Remove from list right away so lookups will fail if we
363df8bae1dSRodney W. Grimes 	 * block for pageout completion.
364df8bae1dSRodney W. Grimes 	 */
365df8bae1dSRodney W. Grimes 	swp = (sw_pager_t) pager->pg_data;
366df8bae1dSRodney W. Grimes 	if (swp->sw_flags & SW_NAMED) {
367df8bae1dSRodney W. Grimes 		TAILQ_REMOVE(&swap_pager_list, pager, pg_list);
368df8bae1dSRodney W. Grimes 		swp->sw_flags &= ~SW_NAMED;
369df8bae1dSRodney W. Grimes 	}
370df8bae1dSRodney W. Grimes #ifdef DEBUG
371df8bae1dSRodney W. Grimes 	for (swt = swtab; swt->st_osize; swt++)
372df8bae1dSRodney W. Grimes 		if (swp->sw_osize <= swt->st_osize)
373df8bae1dSRodney W. Grimes 			break;
374df8bae1dSRodney W. Grimes 	swt->st_inuse--;
375df8bae1dSRodney W. Grimes #endif
376df8bae1dSRodney W. Grimes 
377df8bae1dSRodney W. Grimes 	/*
378df8bae1dSRodney W. Grimes 	 * Wait for all pageouts to finish and remove
379df8bae1dSRodney W. Grimes 	 * all entries from cleaning list.
380df8bae1dSRodney W. Grimes 	 */
381df8bae1dSRodney W. Grimes 	s = splbio();
382df8bae1dSRodney W. Grimes 	while (swp->sw_poip) {
383df8bae1dSRodney W. Grimes 		swp->sw_flags |= SW_WANTED;
384df8bae1dSRodney W. Grimes 		(void) tsleep(swp, PVM, "swpgdealloc", 0);
385df8bae1dSRodney W. Grimes 	}
386df8bae1dSRodney W. Grimes 	splx(s);
387df8bae1dSRodney W. Grimes 	swap_pager_clean(B_WRITE);
388df8bae1dSRodney W. Grimes 
389df8bae1dSRodney W. Grimes 	/*
390df8bae1dSRodney W. Grimes 	 * Free left over swap blocks
391df8bae1dSRodney W. Grimes 	 */
392df8bae1dSRodney W. Grimes 	for (i = 0, bp = swp->sw_blocks; i < swp->sw_nblocks; i++, bp++)
393df8bae1dSRodney W. Grimes 		if (bp->swb_block) {
394df8bae1dSRodney W. Grimes #ifdef DEBUG
395df8bae1dSRodney W. Grimes 			if (swpagerdebug & (SDB_ALLOCBLK|SDB_FULL))
396df8bae1dSRodney W. Grimes 				printf("swpg_dealloc: blk %x\n",
397df8bae1dSRodney W. Grimes 				       bp->swb_block);
398df8bae1dSRodney W. Grimes #endif
399df8bae1dSRodney W. Grimes 			rmfree(swapmap, swp->sw_bsize, bp->swb_block);
400df8bae1dSRodney W. Grimes 		}
401df8bae1dSRodney W. Grimes 	/*
402df8bae1dSRodney W. Grimes 	 * Free swap management resources
403df8bae1dSRodney W. Grimes 	 */
404df8bae1dSRodney W. Grimes 	free((caddr_t)swp->sw_blocks, M_VMPGDATA);
405df8bae1dSRodney W. Grimes 	free((caddr_t)swp, M_VMPGDATA);
406df8bae1dSRodney W. Grimes 	free((caddr_t)pager, M_VMPAGER);
407df8bae1dSRodney W. Grimes }
408df8bae1dSRodney W. Grimes 
409df8bae1dSRodney W. Grimes static int
410df8bae1dSRodney W. Grimes swap_pager_getpage(pager, mlist, npages, sync)
411df8bae1dSRodney W. Grimes 	vm_pager_t pager;
412df8bae1dSRodney W. Grimes 	vm_page_t *mlist;
413df8bae1dSRodney W. Grimes 	int npages;
414df8bae1dSRodney W. Grimes 	boolean_t sync;
415df8bae1dSRodney W. Grimes {
416df8bae1dSRodney W. Grimes #ifdef DEBUG
417df8bae1dSRodney W. Grimes 	if (swpagerdebug & SDB_FOLLOW)
418df8bae1dSRodney W. Grimes 		printf("swpg_getpage(%x, %x, %x, %x)\n",
419df8bae1dSRodney W. Grimes 		       pager, mlist, npages, sync);
420df8bae1dSRodney W. Grimes #endif
421df8bae1dSRodney W. Grimes 	return(swap_pager_io((sw_pager_t)pager->pg_data,
422df8bae1dSRodney W. Grimes 			     mlist, npages, B_READ));
423df8bae1dSRodney W. Grimes }
424df8bae1dSRodney W. Grimes 
425df8bae1dSRodney W. Grimes static int
426df8bae1dSRodney W. Grimes swap_pager_putpage(pager, mlist, npages, sync)
427df8bae1dSRodney W. Grimes 	vm_pager_t pager;
428df8bae1dSRodney W. Grimes 	vm_page_t *mlist;
429df8bae1dSRodney W. Grimes 	int npages;
430df8bae1dSRodney W. Grimes 	boolean_t sync;
431df8bae1dSRodney W. Grimes {
432df8bae1dSRodney W. Grimes 	int flags;
433df8bae1dSRodney W. Grimes 
434df8bae1dSRodney W. Grimes #ifdef DEBUG
435df8bae1dSRodney W. Grimes 	if (swpagerdebug & SDB_FOLLOW)
436df8bae1dSRodney W. Grimes 		printf("swpg_putpage(%x, %x, %x, %x)\n",
437df8bae1dSRodney W. Grimes 		       pager, mlist, npages, sync);
438df8bae1dSRodney W. Grimes #endif
439df8bae1dSRodney W. Grimes 	if (pager == NULL) {
440df8bae1dSRodney W. Grimes 		swap_pager_clean(B_WRITE);
441df8bae1dSRodney W. Grimes 		return (VM_PAGER_OK);		/* ??? */
442df8bae1dSRodney W. Grimes 	}
443df8bae1dSRodney W. Grimes 	flags = B_WRITE;
444df8bae1dSRodney W. Grimes 	if (!sync)
445df8bae1dSRodney W. Grimes 		flags |= B_ASYNC;
446df8bae1dSRodney W. Grimes 	return(swap_pager_io((sw_pager_t)pager->pg_data,
447df8bae1dSRodney W. Grimes 			     mlist, npages, flags));
448df8bae1dSRodney W. Grimes }
449df8bae1dSRodney W. Grimes 
450df8bae1dSRodney W. Grimes static boolean_t
451df8bae1dSRodney W. Grimes swap_pager_haspage(pager, offset)
452df8bae1dSRodney W. Grimes 	vm_pager_t pager;
453df8bae1dSRodney W. Grimes 	vm_offset_t offset;
454df8bae1dSRodney W. Grimes {
455df8bae1dSRodney W. Grimes 	register sw_pager_t swp;
456df8bae1dSRodney W. Grimes 	register sw_blk_t swb;
457df8bae1dSRodney W. Grimes 	int ix;
458df8bae1dSRodney W. Grimes 
459df8bae1dSRodney W. Grimes #ifdef DEBUG
460df8bae1dSRodney W. Grimes 	if (swpagerdebug & (SDB_FOLLOW|SDB_ALLOCBLK))
461df8bae1dSRodney W. Grimes 		printf("swpg_haspage(%x, %x) ", pager, offset);
462df8bae1dSRodney W. Grimes #endif
463df8bae1dSRodney W. Grimes 	swp = (sw_pager_t) pager->pg_data;
464df8bae1dSRodney W. Grimes 	ix = offset / dbtob(swp->sw_bsize);
465df8bae1dSRodney W. Grimes 	if (swp->sw_blocks == NULL || ix >= swp->sw_nblocks) {
466df8bae1dSRodney W. Grimes #ifdef DEBUG
467df8bae1dSRodney W. Grimes 		if (swpagerdebug & (SDB_FAIL|SDB_FOLLOW|SDB_ALLOCBLK))
468df8bae1dSRodney W. Grimes 			printf("swpg_haspage: %x bad offset %x, ix %x\n",
469df8bae1dSRodney W. Grimes 			       swp->sw_blocks, offset, ix);
470df8bae1dSRodney W. Grimes #endif
471df8bae1dSRodney W. Grimes 		return(FALSE);
472df8bae1dSRodney W. Grimes 	}
473df8bae1dSRodney W. Grimes 	swb = &swp->sw_blocks[ix];
474df8bae1dSRodney W. Grimes 	if (swb->swb_block)
475df8bae1dSRodney W. Grimes 		ix = atop(offset % dbtob(swp->sw_bsize));
476df8bae1dSRodney W. Grimes #ifdef DEBUG
477df8bae1dSRodney W. Grimes 	if (swpagerdebug & SDB_ALLOCBLK)
478df8bae1dSRodney W. Grimes 		printf("%x blk %x+%x ", swp->sw_blocks, swb->swb_block, ix);
479df8bae1dSRodney W. Grimes 	if (swpagerdebug & (SDB_FOLLOW|SDB_ALLOCBLK))
480df8bae1dSRodney W. Grimes 		printf("-> %c\n",
481df8bae1dSRodney W. Grimes 		       "FT"[swb->swb_block && (swb->swb_mask & (1 << ix))]);
482df8bae1dSRodney W. Grimes #endif
483df8bae1dSRodney W. Grimes 	if (swb->swb_block && (swb->swb_mask & (1 << ix)))
484df8bae1dSRodney W. Grimes 		return(TRUE);
485df8bae1dSRodney W. Grimes 	return(FALSE);
486df8bae1dSRodney W. Grimes }
487df8bae1dSRodney W. Grimes 
488df8bae1dSRodney W. Grimes static void
489df8bae1dSRodney W. Grimes swap_pager_cluster(pager, offset, loffset, hoffset)
490df8bae1dSRodney W. Grimes 	vm_pager_t	pager;
491df8bae1dSRodney W. Grimes 	vm_offset_t	offset;
492df8bae1dSRodney W. Grimes 	vm_offset_t	*loffset;
493df8bae1dSRodney W. Grimes 	vm_offset_t	*hoffset;
494df8bae1dSRodney W. Grimes {
495df8bae1dSRodney W. Grimes 	sw_pager_t swp;
496df8bae1dSRodney W. Grimes 	register int bsize;
497df8bae1dSRodney W. Grimes 	vm_offset_t loff, hoff;
498df8bae1dSRodney W. Grimes 
499df8bae1dSRodney W. Grimes #ifdef DEBUG
500df8bae1dSRodney W. Grimes 	if (swpagerdebug & (SDB_FOLLOW|SDB_CLUSTER))
501df8bae1dSRodney W. Grimes 		printf("swpg_cluster(%x, %x) ", pager, offset);
502df8bae1dSRodney W. Grimes #endif
503df8bae1dSRodney W. Grimes 	swp = (sw_pager_t) pager->pg_data;
504df8bae1dSRodney W. Grimes 	bsize = dbtob(swp->sw_bsize);
505df8bae1dSRodney W. Grimes 	if (bsize > swap_pager_maxcluster)
506df8bae1dSRodney W. Grimes 		bsize = swap_pager_maxcluster;
507df8bae1dSRodney W. Grimes 
508df8bae1dSRodney W. Grimes 	loff = offset - (offset % bsize);
509df8bae1dSRodney W. Grimes 	if (loff >= swp->sw_osize)
510df8bae1dSRodney W. Grimes 		panic("swap_pager_cluster: bad offset");
511df8bae1dSRodney W. Grimes 
512df8bae1dSRodney W. Grimes 	hoff = loff + bsize;
513df8bae1dSRodney W. Grimes 	if (hoff > swp->sw_osize)
514df8bae1dSRodney W. Grimes 		hoff = swp->sw_osize;
515df8bae1dSRodney W. Grimes 
516df8bae1dSRodney W. Grimes 	*loffset = loff;
517df8bae1dSRodney W. Grimes 	*hoffset = hoff;
518df8bae1dSRodney W. Grimes #ifdef DEBUG
519df8bae1dSRodney W. Grimes 	if (swpagerdebug & (SDB_FOLLOW|SDB_CLUSTER))
520df8bae1dSRodney W. Grimes 		printf("returns [%x-%x]\n", loff, hoff);
521df8bae1dSRodney W. Grimes #endif
522df8bae1dSRodney W. Grimes }
523df8bae1dSRodney W. Grimes 
524df8bae1dSRodney W. Grimes /*
525df8bae1dSRodney W. Grimes  * Scaled down version of swap().
526df8bae1dSRodney W. Grimes  * Assumes that PAGE_SIZE < MAXPHYS; i.e. only one operation needed.
527df8bae1dSRodney W. Grimes  * BOGUS:  lower level IO routines expect a KVA so we have to map our
528df8bae1dSRodney W. Grimes  * provided physical page into the KVA to keep them happy.
529df8bae1dSRodney W. Grimes  */
530df8bae1dSRodney W. Grimes static int
531df8bae1dSRodney W. Grimes swap_pager_io(swp, mlist, npages, flags)
532df8bae1dSRodney W. Grimes 	register sw_pager_t swp;
533df8bae1dSRodney W. Grimes 	vm_page_t *mlist;
534df8bae1dSRodney W. Grimes 	int npages;
535df8bae1dSRodney W. Grimes 	int flags;
536df8bae1dSRodney W. Grimes {
537df8bae1dSRodney W. Grimes 	register struct buf *bp;
538df8bae1dSRodney W. Grimes 	register sw_blk_t swb;
539df8bae1dSRodney W. Grimes 	register int s;
540df8bae1dSRodney W. Grimes 	int ix, mask;
541df8bae1dSRodney W. Grimes 	boolean_t rv;
542df8bae1dSRodney W. Grimes 	vm_offset_t kva, off;
543df8bae1dSRodney W. Grimes 	swp_clean_t spc;
544df8bae1dSRodney W. Grimes 	vm_page_t m;
545df8bae1dSRodney W. Grimes 
546df8bae1dSRodney W. Grimes #ifdef DEBUG
547df8bae1dSRodney W. Grimes 	/* save panic time state */
548df8bae1dSRodney W. Grimes 	if ((swpagerdebug & SDB_ANOMPANIC) && panicstr)
549df8bae1dSRodney W. Grimes 		return (VM_PAGER_FAIL);		/* XXX: correct return? */
550df8bae1dSRodney W. Grimes 	if (swpagerdebug & (SDB_FOLLOW|SDB_IO))
551df8bae1dSRodney W. Grimes 		printf("swpg_io(%x, %x, %x, %x)\n", swp, mlist, npages, flags);
552df8bae1dSRodney W. Grimes 	if (flags & B_READ) {
553df8bae1dSRodney W. Grimes 		if (flags & B_ASYNC)
554df8bae1dSRodney W. Grimes 			panic("swap_pager_io: cannot do ASYNC reads");
555df8bae1dSRodney W. Grimes 		if (npages != 1)
556df8bae1dSRodney W. Grimes 			panic("swap_pager_io: cannot do clustered reads");
557df8bae1dSRodney W. Grimes 	}
558df8bae1dSRodney W. Grimes #endif
559df8bae1dSRodney W. Grimes 
560df8bae1dSRodney W. Grimes 	/*
561df8bae1dSRodney W. Grimes 	 * First determine if the page exists in the pager if this is
562df8bae1dSRodney W. Grimes 	 * a sync read.  This quickly handles cases where we are
563df8bae1dSRodney W. Grimes 	 * following shadow chains looking for the top level object
564df8bae1dSRodney W. Grimes 	 * with the page.
565df8bae1dSRodney W. Grimes 	 */
566df8bae1dSRodney W. Grimes 	m = *mlist;
567df8bae1dSRodney W. Grimes 	off = m->offset + m->object->paging_offset;
568df8bae1dSRodney W. Grimes 	ix = off / dbtob(swp->sw_bsize);
569df8bae1dSRodney W. Grimes 	if (swp->sw_blocks == NULL || ix >= swp->sw_nblocks) {
570df8bae1dSRodney W. Grimes #ifdef DEBUG
571df8bae1dSRodney W. Grimes 		if ((flags & B_READ) == 0 && (swpagerdebug & SDB_ANOM)) {
572df8bae1dSRodney W. Grimes 			printf("swap_pager_io: no swap block on write\n");
573df8bae1dSRodney W. Grimes 			return(VM_PAGER_BAD);
574df8bae1dSRodney W. Grimes 		}
575df8bae1dSRodney W. Grimes #endif
576df8bae1dSRodney W. Grimes 		return(VM_PAGER_FAIL);
577df8bae1dSRodney W. Grimes 	}
578df8bae1dSRodney W. Grimes 	swb = &swp->sw_blocks[ix];
579df8bae1dSRodney W. Grimes 	off = off % dbtob(swp->sw_bsize);
580df8bae1dSRodney W. Grimes 	if ((flags & B_READ) &&
581df8bae1dSRodney W. Grimes 	    (swb->swb_block == 0 || (swb->swb_mask & (1 << atop(off))) == 0))
582df8bae1dSRodney W. Grimes 		return(VM_PAGER_FAIL);
583df8bae1dSRodney W. Grimes 
584df8bae1dSRodney W. Grimes 	/*
585df8bae1dSRodney W. Grimes 	 * For reads (pageins) and synchronous writes, we clean up
586df8bae1dSRodney W. Grimes 	 * all completed async pageouts.
587df8bae1dSRodney W. Grimes 	 */
588df8bae1dSRodney W. Grimes 	if ((flags & B_ASYNC) == 0) {
589df8bae1dSRodney W. Grimes 		s = splbio();
590df8bae1dSRodney W. Grimes 		swap_pager_clean(flags&B_READ);
591df8bae1dSRodney W. Grimes #ifdef DEBUG
592df8bae1dSRodney W. Grimes 		if (swpagerdebug & SDB_PARANOIA)
593df8bae1dSRodney W. Grimes 			swap_pager_clean_check(mlist, npages, flags&B_READ);
594df8bae1dSRodney W. Grimes #endif
595df8bae1dSRodney W. Grimes 		splx(s);
596df8bae1dSRodney W. Grimes 	}
597df8bae1dSRodney W. Grimes 	/*
598df8bae1dSRodney W. Grimes 	 * For async writes (pageouts), we cleanup completed pageouts so
599df8bae1dSRodney W. Grimes 	 * that all available resources are freed.  Also tells us if this
600df8bae1dSRodney W. Grimes 	 * page is already being cleaned.  If it is, or no resources
601df8bae1dSRodney W. Grimes 	 * are available, we try again later.
602df8bae1dSRodney W. Grimes 	 */
603df8bae1dSRodney W. Grimes 	else {
604df8bae1dSRodney W. Grimes 		swap_pager_clean(B_WRITE);
605df8bae1dSRodney W. Grimes #ifdef DEBUG
606df8bae1dSRodney W. Grimes 		if (swpagerdebug & SDB_PARANOIA)
607df8bae1dSRodney W. Grimes 			swap_pager_clean_check(mlist, npages, B_WRITE);
608df8bae1dSRodney W. Grimes #endif
609df8bae1dSRodney W. Grimes 		if (swap_pager_free.tqh_first == NULL) {
610df8bae1dSRodney W. Grimes #ifdef DEBUG
611df8bae1dSRodney W. Grimes 			if (swpagerdebug & SDB_FAIL)
612df8bae1dSRodney W. Grimes 				printf("%s: no available io headers\n",
613df8bae1dSRodney W. Grimes 				       "swap_pager_io");
614df8bae1dSRodney W. Grimes #endif
615df8bae1dSRodney W. Grimes 			return(VM_PAGER_AGAIN);
616df8bae1dSRodney W. Grimes 		}
617df8bae1dSRodney W. Grimes 	}
618df8bae1dSRodney W. Grimes 
619df8bae1dSRodney W. Grimes 	/*
620df8bae1dSRodney W. Grimes 	 * Allocate a swap block if necessary.
621df8bae1dSRodney W. Grimes 	 */
622df8bae1dSRodney W. Grimes 	if (swb->swb_block == 0) {
623df8bae1dSRodney W. Grimes 		swb->swb_block = rmalloc(swapmap, swp->sw_bsize);
624df8bae1dSRodney W. Grimes 		if (swb->swb_block == 0) {
625df8bae1dSRodney W. Grimes #ifdef DEBUG
626df8bae1dSRodney W. Grimes 			if (swpagerdebug & SDB_FAIL)
627df8bae1dSRodney W. Grimes 				printf("swpg_io: rmalloc of %x failed\n",
628df8bae1dSRodney W. Grimes 				       swp->sw_bsize);
629df8bae1dSRodney W. Grimes #endif
630df8bae1dSRodney W. Grimes 			/*
631df8bae1dSRodney W. Grimes 			 * XXX this is technically a resource shortage that
632df8bae1dSRodney W. Grimes 			 * should return AGAIN, but the situation isn't likely
633df8bae1dSRodney W. Grimes 			 * to be remedied just by delaying a little while and
634df8bae1dSRodney W. Grimes 			 * trying again (the pageout daemon's current response
635df8bae1dSRodney W. Grimes 			 * to AGAIN) so we just return FAIL.
636df8bae1dSRodney W. Grimes 			 */
637df8bae1dSRodney W. Grimes 			return(VM_PAGER_FAIL);
638df8bae1dSRodney W. Grimes 		}
639df8bae1dSRodney W. Grimes #ifdef DEBUG
640df8bae1dSRodney W. Grimes 		if (swpagerdebug & (SDB_FULL|SDB_ALLOCBLK))
641df8bae1dSRodney W. Grimes 			printf("swpg_io: %x alloc blk %x at ix %x\n",
642df8bae1dSRodney W. Grimes 			       swp->sw_blocks, swb->swb_block, ix);
643df8bae1dSRodney W. Grimes #endif
644df8bae1dSRodney W. Grimes 	}
645df8bae1dSRodney W. Grimes 
646df8bae1dSRodney W. Grimes 	/*
647df8bae1dSRodney W. Grimes 	 * Allocate a kernel virtual address and initialize so that PTE
648df8bae1dSRodney W. Grimes 	 * is available for lower level IO drivers.
649df8bae1dSRodney W. Grimes 	 */
650df8bae1dSRodney W. Grimes 	kva = vm_pager_map_pages(mlist, npages, !(flags & B_ASYNC));
651df8bae1dSRodney W. Grimes 	if (kva == NULL) {
652df8bae1dSRodney W. Grimes #ifdef DEBUG
653df8bae1dSRodney W. Grimes 		if (swpagerdebug & SDB_FAIL)
654df8bae1dSRodney W. Grimes 			printf("%s: no KVA space to map pages\n",
655df8bae1dSRodney W. Grimes 			       "swap_pager_io");
656df8bae1dSRodney W. Grimes #endif
657df8bae1dSRodney W. Grimes 		return(VM_PAGER_AGAIN);
658df8bae1dSRodney W. Grimes 	}
659df8bae1dSRodney W. Grimes 
660df8bae1dSRodney W. Grimes 	/*
661df8bae1dSRodney W. Grimes 	 * Get a swap buffer header and initialize it.
662df8bae1dSRodney W. Grimes 	 */
663df8bae1dSRodney W. Grimes 	s = splbio();
664df8bae1dSRodney W. Grimes 	while (bswlist.b_actf == NULL) {
665df8bae1dSRodney W. Grimes #ifdef DEBUG
666df8bae1dSRodney W. Grimes 		if (swpagerdebug & SDB_ANOM)
667df8bae1dSRodney W. Grimes 			printf("swap_pager_io: wait on swbuf for %x (%d)\n",
668df8bae1dSRodney W. Grimes 			       m, flags);
669df8bae1dSRodney W. Grimes #endif
670df8bae1dSRodney W. Grimes 		bswlist.b_flags |= B_WANTED;
671df8bae1dSRodney W. Grimes 		tsleep((caddr_t)&bswlist, PSWP+1, "swpgiobuf", 0);
672df8bae1dSRodney W. Grimes 	}
673df8bae1dSRodney W. Grimes 	bp = bswlist.b_actf;
674df8bae1dSRodney W. Grimes 	bswlist.b_actf = bp->b_actf;
675df8bae1dSRodney W. Grimes 	splx(s);
676df8bae1dSRodney W. Grimes 	bp->b_flags = B_BUSY | (flags & B_READ);
677df8bae1dSRodney W. Grimes 	bp->b_proc = &proc0;	/* XXX (but without B_PHYS set this is ok) */
678df8bae1dSRodney W. Grimes 	bp->b_data = (caddr_t)kva;
679df8bae1dSRodney W. Grimes 	bp->b_blkno = swb->swb_block + btodb(off);
680df8bae1dSRodney W. Grimes 	VHOLD(swapdev_vp);
681df8bae1dSRodney W. Grimes 	bp->b_vp = swapdev_vp;
682df8bae1dSRodney W. Grimes 	if (swapdev_vp->v_type == VBLK)
683df8bae1dSRodney W. Grimes 		bp->b_dev = swapdev_vp->v_rdev;
684df8bae1dSRodney W. Grimes 	bp->b_bcount = npages * PAGE_SIZE;
685df8bae1dSRodney W. Grimes 
686df8bae1dSRodney W. Grimes 	/*
687df8bae1dSRodney W. Grimes 	 * For writes we set up additional buffer fields, record a pageout
688df8bae1dSRodney W. Grimes 	 * in progress and mark that these swap blocks are now allocated.
689df8bae1dSRodney W. Grimes 	 */
690df8bae1dSRodney W. Grimes 	if ((bp->b_flags & B_READ) == 0) {
691df8bae1dSRodney W. Grimes 		bp->b_dirtyoff = 0;
692df8bae1dSRodney W. Grimes 		bp->b_dirtyend = npages * PAGE_SIZE;
693df8bae1dSRodney W. Grimes 		swapdev_vp->v_numoutput++;
694df8bae1dSRodney W. Grimes 		s = splbio();
695df8bae1dSRodney W. Grimes 		swp->sw_poip++;
696df8bae1dSRodney W. Grimes 		splx(s);
697df8bae1dSRodney W. Grimes 		mask = (~(~0 << npages)) << atop(off);
698df8bae1dSRodney W. Grimes #ifdef DEBUG
699df8bae1dSRodney W. Grimes 		swap_pager_poip++;
700df8bae1dSRodney W. Grimes 		if (swpagerdebug & SDB_WRITE)
701df8bae1dSRodney W. Grimes 			printf("swpg_io: write: bp=%x swp=%x poip=%d\n",
702df8bae1dSRodney W. Grimes 			       bp, swp, swp->sw_poip);
703df8bae1dSRodney W. Grimes 		if ((swpagerdebug & SDB_ALLOCBLK) &&
704df8bae1dSRodney W. Grimes 		    (swb->swb_mask & mask) != mask)
705df8bae1dSRodney W. Grimes 			printf("swpg_io: %x write %d pages at %x+%x\n",
706df8bae1dSRodney W. Grimes 			       swp->sw_blocks, npages, swb->swb_block,
707df8bae1dSRodney W. Grimes 			       atop(off));
708df8bae1dSRodney W. Grimes 		if (swpagerdebug & SDB_CLUSTER)
709df8bae1dSRodney W. Grimes 			printf("swpg_io: off=%x, npg=%x, mask=%x, bmask=%x\n",
710df8bae1dSRodney W. Grimes 			       off, npages, mask, swb->swb_mask);
711df8bae1dSRodney W. Grimes #endif
712df8bae1dSRodney W. Grimes 		swb->swb_mask |= mask;
713df8bae1dSRodney W. Grimes 	}
714df8bae1dSRodney W. Grimes 	/*
715df8bae1dSRodney W. Grimes 	 * If this is an async write we set up still more buffer fields
716df8bae1dSRodney W. Grimes 	 * and place a "cleaning" entry on the inuse queue.
717df8bae1dSRodney W. Grimes 	 */
718df8bae1dSRodney W. Grimes 	if ((flags & (B_READ|B_ASYNC)) == B_ASYNC) {
719df8bae1dSRodney W. Grimes #ifdef DEBUG
720df8bae1dSRodney W. Grimes 		if (swap_pager_free.tqh_first == NULL)
721df8bae1dSRodney W. Grimes 			panic("swpg_io: lost spc");
722df8bae1dSRodney W. Grimes #endif
723df8bae1dSRodney W. Grimes 		spc = swap_pager_free.tqh_first;
724df8bae1dSRodney W. Grimes 		TAILQ_REMOVE(&swap_pager_free, spc, spc_list);
725df8bae1dSRodney W. Grimes #ifdef DEBUG
726df8bae1dSRodney W. Grimes 		if (spc->spc_flags != SPC_FREE)
727df8bae1dSRodney W. Grimes 			panic("swpg_io: bad free spc");
728df8bae1dSRodney W. Grimes #endif
729df8bae1dSRodney W. Grimes 		spc->spc_flags = SPC_BUSY;
730df8bae1dSRodney W. Grimes 		spc->spc_bp = bp;
731df8bae1dSRodney W. Grimes 		spc->spc_swp = swp;
732df8bae1dSRodney W. Grimes 		spc->spc_kva = kva;
733df8bae1dSRodney W. Grimes 		/*
734df8bae1dSRodney W. Grimes 		 * Record the first page.  This allows swap_pager_clean
735df8bae1dSRodney W. Grimes 		 * to efficiently handle the common case of a single page.
736df8bae1dSRodney W. Grimes 		 * For clusters, it allows us to locate the object easily
737df8bae1dSRodney W. Grimes 		 * and we then reconstruct the rest of the mlist from spc_kva.
738df8bae1dSRodney W. Grimes 		 */
739df8bae1dSRodney W. Grimes 		spc->spc_m = m;
740df8bae1dSRodney W. Grimes 		spc->spc_npages = npages;
741df8bae1dSRodney W. Grimes 		bp->b_flags |= B_CALL;
742df8bae1dSRodney W. Grimes 		bp->b_iodone = swap_pager_iodone;
743df8bae1dSRodney W. Grimes 		s = splbio();
744df8bae1dSRodney W. Grimes 		TAILQ_INSERT_TAIL(&swap_pager_inuse, spc, spc_list);
745df8bae1dSRodney W. Grimes 		splx(s);
746df8bae1dSRodney W. Grimes 	}
747df8bae1dSRodney W. Grimes 
748df8bae1dSRodney W. Grimes 	/*
749df8bae1dSRodney W. Grimes 	 * Finally, start the IO operation.
750df8bae1dSRodney W. Grimes 	 * If it is async we are all done, otherwise we must wait for
751df8bae1dSRodney W. Grimes 	 * completion and cleanup afterwards.
752df8bae1dSRodney W. Grimes 	 */
753df8bae1dSRodney W. Grimes #ifdef DEBUG
754df8bae1dSRodney W. Grimes 	if (swpagerdebug & SDB_IO)
755df8bae1dSRodney W. Grimes 		printf("swpg_io: IO start: bp %x, db %x, va %x, pa %x\n",
756df8bae1dSRodney W. Grimes 		       bp, swb->swb_block+btodb(off), kva, VM_PAGE_TO_PHYS(m));
757df8bae1dSRodney W. Grimes #endif
758df8bae1dSRodney W. Grimes 	VOP_STRATEGY(bp);
759df8bae1dSRodney W. Grimes 	if ((flags & (B_READ|B_ASYNC)) == B_ASYNC) {
760df8bae1dSRodney W. Grimes #ifdef DEBUG
761df8bae1dSRodney W. Grimes 		if (swpagerdebug & SDB_IO)
762df8bae1dSRodney W. Grimes 			printf("swpg_io:  IO started: bp %x\n", bp);
763df8bae1dSRodney W. Grimes #endif
764df8bae1dSRodney W. Grimes 		return(VM_PAGER_PEND);
765df8bae1dSRodney W. Grimes 	}
766df8bae1dSRodney W. Grimes 	s = splbio();
767df8bae1dSRodney W. Grimes #ifdef DEBUG
768df8bae1dSRodney W. Grimes 	if (flags & B_READ)
769df8bae1dSRodney W. Grimes 		swap_pager_piip++;
770df8bae1dSRodney W. Grimes 	else
771df8bae1dSRodney W. Grimes 		swap_pager_poip++;
772df8bae1dSRodney W. Grimes #endif
773df8bae1dSRodney W. Grimes 	while ((bp->b_flags & B_DONE) == 0)
774df8bae1dSRodney W. Grimes 		(void) tsleep(bp, PVM, "swpgio", 0);
775df8bae1dSRodney W. Grimes 	if ((flags & B_READ) == 0)
776df8bae1dSRodney W. Grimes 		--swp->sw_poip;
777df8bae1dSRodney W. Grimes #ifdef DEBUG
778df8bae1dSRodney W. Grimes 	if (flags & B_READ)
779df8bae1dSRodney W. Grimes 		--swap_pager_piip;
780df8bae1dSRodney W. Grimes 	else
781df8bae1dSRodney W. Grimes 		--swap_pager_poip;
782df8bae1dSRodney W. Grimes #endif
783df8bae1dSRodney W. Grimes 	rv = (bp->b_flags & B_ERROR) ? VM_PAGER_ERROR : VM_PAGER_OK;
784df8bae1dSRodney W. Grimes 	bp->b_flags &= ~(B_BUSY|B_WANTED|B_PHYS|B_PAGET|B_UAREA|B_DIRTY);
785df8bae1dSRodney W. Grimes 	bp->b_actf = bswlist.b_actf;
786df8bae1dSRodney W. Grimes 	bswlist.b_actf = bp;
787df8bae1dSRodney W. Grimes 	if (bp->b_vp)
788df8bae1dSRodney W. Grimes 		brelvp(bp);
789df8bae1dSRodney W. Grimes 	if (bswlist.b_flags & B_WANTED) {
790df8bae1dSRodney W. Grimes 		bswlist.b_flags &= ~B_WANTED;
791df8bae1dSRodney W. Grimes 		wakeup(&bswlist);
792df8bae1dSRodney W. Grimes 	}
793df8bae1dSRodney W. Grimes 	if ((flags & B_READ) == 0 && rv == VM_PAGER_OK) {
794df8bae1dSRodney W. Grimes 		m->flags |= PG_CLEAN;
795df8bae1dSRodney W. Grimes 		pmap_clear_modify(VM_PAGE_TO_PHYS(m));
796df8bae1dSRodney W. Grimes 	}
797df8bae1dSRodney W. Grimes 	splx(s);
798df8bae1dSRodney W. Grimes #ifdef DEBUG
799df8bae1dSRodney W. Grimes 	if (swpagerdebug & SDB_IO)
800df8bae1dSRodney W. Grimes 		printf("swpg_io:  IO done: bp %x, rv %d\n", bp, rv);
801df8bae1dSRodney W. Grimes 	if ((swpagerdebug & SDB_FAIL) && rv == VM_PAGER_ERROR)
802df8bae1dSRodney W. Grimes 		printf("swpg_io: IO error\n");
803df8bae1dSRodney W. Grimes #endif
804df8bae1dSRodney W. Grimes 	vm_pager_unmap_pages(kva, npages);
805df8bae1dSRodney W. Grimes 	return(rv);
806df8bae1dSRodney W. Grimes }
807df8bae1dSRodney W. Grimes 
808df8bae1dSRodney W. Grimes static void
809df8bae1dSRodney W. Grimes swap_pager_clean(rw)
810df8bae1dSRodney W. Grimes 	int rw;
811df8bae1dSRodney W. Grimes {
812df8bae1dSRodney W. Grimes 	register swp_clean_t spc;
813df8bae1dSRodney W. Grimes 	register int s, i;
814df8bae1dSRodney W. Grimes 	vm_object_t object;
815df8bae1dSRodney W. Grimes 	vm_page_t m;
816df8bae1dSRodney W. Grimes 
817df8bae1dSRodney W. Grimes #ifdef DEBUG
818df8bae1dSRodney W. Grimes 	/* save panic time state */
819df8bae1dSRodney W. Grimes 	if ((swpagerdebug & SDB_ANOMPANIC) && panicstr)
820df8bae1dSRodney W. Grimes 		return;
821df8bae1dSRodney W. Grimes 	if (swpagerdebug & SDB_FOLLOW)
822df8bae1dSRodney W. Grimes 		printf("swpg_clean(%x)\n", rw);
823df8bae1dSRodney W. Grimes #endif
824df8bae1dSRodney W. Grimes 
825df8bae1dSRodney W. Grimes 	for (;;) {
826df8bae1dSRodney W. Grimes 		/*
827df8bae1dSRodney W. Grimes 		 * Look up and removal from inuse list must be done
828df8bae1dSRodney W. Grimes 		 * at splbio() to avoid conflicts with swap_pager_iodone.
829df8bae1dSRodney W. Grimes 		 */
830df8bae1dSRodney W. Grimes 		s = splbio();
831df8bae1dSRodney W. Grimes 		for (spc = swap_pager_inuse.tqh_first;
832df8bae1dSRodney W. Grimes 		     spc != NULL;
833df8bae1dSRodney W. Grimes 		     spc = spc->spc_list.tqe_next) {
834df8bae1dSRodney W. Grimes 			/*
835df8bae1dSRodney W. Grimes 			 * If the operation is done, remove it from the
836df8bae1dSRodney W. Grimes 			 * list and process it.
837df8bae1dSRodney W. Grimes 			 *
838df8bae1dSRodney W. Grimes 			 * XXX if we can't get the object lock we also
839df8bae1dSRodney W. Grimes 			 * leave it on the list and try again later.
840df8bae1dSRodney W. Grimes 			 * Is there something better we could do?
841df8bae1dSRodney W. Grimes 			 */
842df8bae1dSRodney W. Grimes 			if ((spc->spc_flags & SPC_DONE) &&
843df8bae1dSRodney W. Grimes 			    vm_object_lock_try(spc->spc_m->object)) {
844df8bae1dSRodney W. Grimes 				TAILQ_REMOVE(&swap_pager_inuse, spc, spc_list);
845df8bae1dSRodney W. Grimes 				break;
846df8bae1dSRodney W. Grimes 			}
847df8bae1dSRodney W. Grimes 		}
848df8bae1dSRodney W. Grimes 		splx(s);
849df8bae1dSRodney W. Grimes 
850df8bae1dSRodney W. Grimes 		/*
851df8bae1dSRodney W. Grimes 		 * No operations done, thats all we can do for now.
852df8bae1dSRodney W. Grimes 		 */
853df8bae1dSRodney W. Grimes 		if (spc == NULL)
854df8bae1dSRodney W. Grimes 			break;
855df8bae1dSRodney W. Grimes 
856df8bae1dSRodney W. Grimes 		/*
857df8bae1dSRodney W. Grimes 		 * Found a completed operation so finish it off.
858df8bae1dSRodney W. Grimes 		 * Note: no longer at splbio since entry is off the list.
859df8bae1dSRodney W. Grimes 		 */
860df8bae1dSRodney W. Grimes 		m = spc->spc_m;
861df8bae1dSRodney W. Grimes 		object = m->object;
862df8bae1dSRodney W. Grimes 
863df8bae1dSRodney W. Grimes 		/*
864df8bae1dSRodney W. Grimes 		 * Process each page in the cluster.
865df8bae1dSRodney W. Grimes 		 * The first page is explicitly kept in the cleaning
866df8bae1dSRodney W. Grimes 		 * entry, others must be reconstructed from the KVA.
867df8bae1dSRodney W. Grimes 		 */
868df8bae1dSRodney W. Grimes 		for (i = 0; i < spc->spc_npages; i++) {
869df8bae1dSRodney W. Grimes 			if (i)
870df8bae1dSRodney W. Grimes 				m = vm_pager_atop(spc->spc_kva + ptoa(i));
871df8bae1dSRodney W. Grimes 			/*
872df8bae1dSRodney W. Grimes 			 * If no error mark as clean and inform the pmap
873df8bae1dSRodney W. Grimes 			 * system.  If there was an error, mark as dirty
874df8bae1dSRodney W. Grimes 			 * so we will try again.
875df8bae1dSRodney W. Grimes 			 *
876df8bae1dSRodney W. Grimes 			 * XXX could get stuck doing this, should give up
877df8bae1dSRodney W. Grimes 			 * after awhile.
878df8bae1dSRodney W. Grimes 			 */
879df8bae1dSRodney W. Grimes 			if (spc->spc_flags & SPC_ERROR) {
880df8bae1dSRodney W. Grimes 				printf("%s: clean of page %x failed\n",
881df8bae1dSRodney W. Grimes 				       "swap_pager_clean",
882df8bae1dSRodney W. Grimes 				       VM_PAGE_TO_PHYS(m));
883df8bae1dSRodney W. Grimes 				m->flags |= PG_LAUNDRY;
884df8bae1dSRodney W. Grimes 			} else {
885df8bae1dSRodney W. Grimes 				m->flags |= PG_CLEAN;
886df8bae1dSRodney W. Grimes 				pmap_clear_modify(VM_PAGE_TO_PHYS(m));
887df8bae1dSRodney W. Grimes 			}
888df8bae1dSRodney W. Grimes 			m->flags &= ~PG_BUSY;
889df8bae1dSRodney W. Grimes 			PAGE_WAKEUP(m);
890df8bae1dSRodney W. Grimes 		}
891df8bae1dSRodney W. Grimes 
892df8bae1dSRodney W. Grimes 		/*
893df8bae1dSRodney W. Grimes 		 * Done with the object, decrement the paging count
894df8bae1dSRodney W. Grimes 		 * and unlock it.
895df8bae1dSRodney W. Grimes 		 */
896df8bae1dSRodney W. Grimes 		if (--object->paging_in_progress == 0)
897df8bae1dSRodney W. Grimes 			wakeup(object);
898df8bae1dSRodney W. Grimes 		vm_object_unlock(object);
899df8bae1dSRodney W. Grimes 
900df8bae1dSRodney W. Grimes 		/*
901df8bae1dSRodney W. Grimes 		 * Free up KVM used and put the entry back on the list.
902df8bae1dSRodney W. Grimes 		 */
903df8bae1dSRodney W. Grimes 		vm_pager_unmap_pages(spc->spc_kva, spc->spc_npages);
904df8bae1dSRodney W. Grimes 		spc->spc_flags = SPC_FREE;
905df8bae1dSRodney W. Grimes 		TAILQ_INSERT_TAIL(&swap_pager_free, spc, spc_list);
906df8bae1dSRodney W. Grimes #ifdef DEBUG
907df8bae1dSRodney W. Grimes 		if (swpagerdebug & SDB_WRITE)
908df8bae1dSRodney W. Grimes 			printf("swpg_clean: free spc %x\n", spc);
909df8bae1dSRodney W. Grimes #endif
910df8bae1dSRodney W. Grimes 	}
911df8bae1dSRodney W. Grimes }
912df8bae1dSRodney W. Grimes 
913df8bae1dSRodney W. Grimes #ifdef DEBUG
914df8bae1dSRodney W. Grimes static void
915df8bae1dSRodney W. Grimes swap_pager_clean_check(mlist, npages, rw)
916df8bae1dSRodney W. Grimes 	vm_page_t *mlist;
917df8bae1dSRodney W. Grimes 	int npages;
918df8bae1dSRodney W. Grimes 	int rw;
919df8bae1dSRodney W. Grimes {
920df8bae1dSRodney W. Grimes 	register swp_clean_t spc;
921df8bae1dSRodney W. Grimes 	boolean_t bad;
922df8bae1dSRodney W. Grimes 	int i, j, s;
923df8bae1dSRodney W. Grimes 	vm_page_t m;
924df8bae1dSRodney W. Grimes 
925df8bae1dSRodney W. Grimes 	if (panicstr)
926df8bae1dSRodney W. Grimes 		return;
927df8bae1dSRodney W. Grimes 
928df8bae1dSRodney W. Grimes 	bad = FALSE;
929df8bae1dSRodney W. Grimes 	s = splbio();
930df8bae1dSRodney W. Grimes 	for (spc = swap_pager_inuse.tqh_first;
931df8bae1dSRodney W. Grimes 	     spc != NULL;
932df8bae1dSRodney W. Grimes 	     spc = spc->spc_list.tqe_next) {
933df8bae1dSRodney W. Grimes 		for (j = 0; j < spc->spc_npages; j++) {
934df8bae1dSRodney W. Grimes 			m = vm_pager_atop(spc->spc_kva + ptoa(j));
935df8bae1dSRodney W. Grimes 			for (i = 0; i < npages; i++)
936df8bae1dSRodney W. Grimes 				if (m == mlist[i]) {
937df8bae1dSRodney W. Grimes 					if (swpagerdebug & SDB_ANOM)
938df8bae1dSRodney W. Grimes 						printf(
939df8bae1dSRodney W. Grimes 		"swpg_clean_check: %s: page %x on list, flags %x\n",
940df8bae1dSRodney W. Grimes 		rw == B_WRITE ? "write" : "read", mlist[i], spc->spc_flags);
941df8bae1dSRodney W. Grimes 					bad = TRUE;
942df8bae1dSRodney W. Grimes 				}
943df8bae1dSRodney W. Grimes 		}
944df8bae1dSRodney W. Grimes 	}
945df8bae1dSRodney W. Grimes 	splx(s);
946df8bae1dSRodney W. Grimes 	if (bad)
947df8bae1dSRodney W. Grimes 		panic("swpg_clean_check");
948df8bae1dSRodney W. Grimes }
949df8bae1dSRodney W. Grimes #endif
950df8bae1dSRodney W. Grimes 
951df8bae1dSRodney W. Grimes static void
952df8bae1dSRodney W. Grimes swap_pager_iodone(bp)
953df8bae1dSRodney W. Grimes 	register struct buf *bp;
954df8bae1dSRodney W. Grimes {
955df8bae1dSRodney W. Grimes 	register swp_clean_t spc;
956df8bae1dSRodney W. Grimes 	daddr_t blk;
957df8bae1dSRodney W. Grimes 	int s;
958df8bae1dSRodney W. Grimes 
959df8bae1dSRodney W. Grimes #ifdef DEBUG
960df8bae1dSRodney W. Grimes 	/* save panic time state */
961df8bae1dSRodney W. Grimes 	if ((swpagerdebug & SDB_ANOMPANIC) && panicstr)
962df8bae1dSRodney W. Grimes 		return;
963df8bae1dSRodney W. Grimes 	if (swpagerdebug & SDB_FOLLOW)
964df8bae1dSRodney W. Grimes 		printf("swpg_iodone(%x)\n", bp);
965df8bae1dSRodney W. Grimes #endif
966df8bae1dSRodney W. Grimes 	s = splbio();
967df8bae1dSRodney W. Grimes 	for (spc = swap_pager_inuse.tqh_first;
968df8bae1dSRodney W. Grimes 	     spc != NULL;
969df8bae1dSRodney W. Grimes 	     spc = spc->spc_list.tqe_next)
970df8bae1dSRodney W. Grimes 		if (spc->spc_bp == bp)
971df8bae1dSRodney W. Grimes 			break;
972df8bae1dSRodney W. Grimes #ifdef DEBUG
973df8bae1dSRodney W. Grimes 	if (spc == NULL)
974df8bae1dSRodney W. Grimes 		panic("swap_pager_iodone: bp not found");
975df8bae1dSRodney W. Grimes #endif
976df8bae1dSRodney W. Grimes 
977df8bae1dSRodney W. Grimes 	spc->spc_flags &= ~SPC_BUSY;
978df8bae1dSRodney W. Grimes 	spc->spc_flags |= SPC_DONE;
979df8bae1dSRodney W. Grimes 	if (bp->b_flags & B_ERROR)
980df8bae1dSRodney W. Grimes 		spc->spc_flags |= SPC_ERROR;
981df8bae1dSRodney W. Grimes 	spc->spc_bp = NULL;
982df8bae1dSRodney W. Grimes 	blk = bp->b_blkno;
983df8bae1dSRodney W. Grimes 
984df8bae1dSRodney W. Grimes #ifdef DEBUG
985df8bae1dSRodney W. Grimes 	--swap_pager_poip;
986df8bae1dSRodney W. Grimes 	if (swpagerdebug & SDB_WRITE)
987df8bae1dSRodney W. Grimes 		printf("swpg_iodone: bp=%x swp=%x flags=%x spc=%x poip=%x\n",
988df8bae1dSRodney W. Grimes 		       bp, spc->spc_swp, spc->spc_swp->sw_flags,
989df8bae1dSRodney W. Grimes 		       spc, spc->spc_swp->sw_poip);
990df8bae1dSRodney W. Grimes #endif
991df8bae1dSRodney W. Grimes 
992df8bae1dSRodney W. Grimes 	spc->spc_swp->sw_poip--;
993df8bae1dSRodney W. Grimes 	if (spc->spc_swp->sw_flags & SW_WANTED) {
994df8bae1dSRodney W. Grimes 		spc->spc_swp->sw_flags &= ~SW_WANTED;
995df8bae1dSRodney W. Grimes 		wakeup(spc->spc_swp);
996df8bae1dSRodney W. Grimes 	}
997df8bae1dSRodney W. Grimes 
998df8bae1dSRodney W. Grimes 	bp->b_flags &= ~(B_BUSY|B_WANTED|B_PHYS|B_PAGET|B_UAREA|B_DIRTY);
999df8bae1dSRodney W. Grimes 	bp->b_actf = bswlist.b_actf;
1000df8bae1dSRodney W. Grimes 	bswlist.b_actf = bp;
1001df8bae1dSRodney W. Grimes 	if (bp->b_vp)
1002df8bae1dSRodney W. Grimes 		brelvp(bp);
1003df8bae1dSRodney W. Grimes 	if (bswlist.b_flags & B_WANTED) {
1004df8bae1dSRodney W. Grimes 		bswlist.b_flags &= ~B_WANTED;
1005df8bae1dSRodney W. Grimes 		wakeup(&bswlist);
1006df8bae1dSRodney W. Grimes 	}
1007df8bae1dSRodney W. Grimes 	wakeup(&vm_pages_needed);
1008df8bae1dSRodney W. Grimes 	splx(s);
1009df8bae1dSRodney W. Grimes }
1010