xref: /freebsd/sys/vm/swap_pager.c (revision 26f9a76710a312a951848542b9ca1f44100450e2)
1df8bae1dSRodney W. Grimes /*
226f9a767SRodney W. Grimes  * Copyright (c) 1994 John S. Dyson
3df8bae1dSRodney W. Grimes  * Copyright (c) 1990 University of Utah.
4df8bae1dSRodney W. Grimes  * Copyright (c) 1991, 1993
5df8bae1dSRodney W. Grimes  *	The Regents of the University of California.  All rights reserved.
6df8bae1dSRodney W. Grimes  *
7df8bae1dSRodney W. Grimes  * This code is derived from software contributed to Berkeley by
8df8bae1dSRodney W. Grimes  * the Systems Programming Group of the University of Utah Computer
9df8bae1dSRodney W. Grimes  * Science Department.
10df8bae1dSRodney W. Grimes  *
11df8bae1dSRodney W. Grimes  * Redistribution and use in source and binary forms, with or without
12df8bae1dSRodney W. Grimes  * modification, are permitted provided that the following conditions
13df8bae1dSRodney W. Grimes  * are met:
14df8bae1dSRodney W. Grimes  * 1. Redistributions of source code must retain the above copyright
15df8bae1dSRodney W. Grimes  *    notice, this list of conditions and the following disclaimer.
16df8bae1dSRodney W. Grimes  * 2. Redistributions in binary form must reproduce the above copyright
17df8bae1dSRodney W. Grimes  *    notice, this list of conditions and the following disclaimer in the
18df8bae1dSRodney W. Grimes  *    documentation and/or other materials provided with the distribution.
19df8bae1dSRodney W. Grimes  * 3. All advertising materials mentioning features or use of this software
20df8bae1dSRodney W. Grimes  *    must display the following acknowledgement:
21df8bae1dSRodney W. Grimes  *	This product includes software developed by the University of
22df8bae1dSRodney W. Grimes  *	California, Berkeley and its contributors.
23df8bae1dSRodney W. Grimes  * 4. Neither the name of the University nor the names of its contributors
24df8bae1dSRodney W. Grimes  *    may be used to endorse or promote products derived from this software
25df8bae1dSRodney W. Grimes  *    without specific prior written permission.
26df8bae1dSRodney W. Grimes  *
27df8bae1dSRodney W. Grimes  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
28df8bae1dSRodney W. Grimes  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
29df8bae1dSRodney W. Grimes  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
30df8bae1dSRodney W. Grimes  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
31df8bae1dSRodney W. Grimes  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
32df8bae1dSRodney W. Grimes  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
33df8bae1dSRodney W. Grimes  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
34df8bae1dSRodney W. Grimes  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
35df8bae1dSRodney W. Grimes  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
36df8bae1dSRodney W. Grimes  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
37df8bae1dSRodney W. Grimes  * SUCH DAMAGE.
38df8bae1dSRodney W. Grimes  *
39df8bae1dSRodney W. Grimes  * from: Utah $Hdr: swap_pager.c 1.4 91/04/30$
40df8bae1dSRodney W. Grimes  *
41df8bae1dSRodney W. Grimes  *	@(#)swap_pager.c	8.9 (Berkeley) 3/21/94
42df8bae1dSRodney W. Grimes  */
43df8bae1dSRodney W. Grimes 
44df8bae1dSRodney W. Grimes /*
45df8bae1dSRodney W. Grimes  * Quick hack to page to dedicated partition(s).
46df8bae1dSRodney W. Grimes  * TODO:
47df8bae1dSRodney W. Grimes  *	Add multiprocessor locks
48df8bae1dSRodney W. Grimes  *	Deal with async writes in a better fashion
49df8bae1dSRodney W. Grimes  */
50df8bae1dSRodney W. Grimes 
51df8bae1dSRodney W. Grimes #include <sys/param.h>
52df8bae1dSRodney W. Grimes #include <sys/systm.h>
53df8bae1dSRodney W. Grimes #include <sys/proc.h>
54df8bae1dSRodney W. Grimes #include <sys/buf.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>
5926f9a767SRodney W. Grimes #include <sys/rlist.h>
60df8bae1dSRodney W. Grimes 
61df8bae1dSRodney W. Grimes #include <vm/vm.h>
6226f9a767SRodney W. Grimes #include <vm/vm_pager.h>
63df8bae1dSRodney W. Grimes #include <vm/vm_page.h>
64df8bae1dSRodney W. Grimes #include <vm/vm_pageout.h>
65df8bae1dSRodney W. Grimes #include <vm/swap_pager.h>
66df8bae1dSRodney W. Grimes 
67df8bae1dSRodney W. Grimes #ifndef NPENDINGIO
6826f9a767SRodney W. Grimes #define NPENDINGIO	16
69df8bae1dSRodney W. Grimes #endif
70df8bae1dSRodney W. Grimes 
7126f9a767SRodney W. Grimes extern int nswbuf;
7226f9a767SRodney W. Grimes int nswiodone;
7326f9a767SRodney W. Grimes extern int vm_pageout_rate_limit;
7426f9a767SRodney W. Grimes static int cleandone;
7526f9a767SRodney W. Grimes extern int hz;
7626f9a767SRodney W. Grimes int swap_pager_full;
7726f9a767SRodney W. Grimes extern vm_map_t pager_map;
7826f9a767SRodney W. Grimes extern int vm_pageout_pages_needed;
7926f9a767SRodney W. Grimes extern int vm_swap_size;
8026f9a767SRodney W. Grimes extern struct vnode *swapdev_vp;
8126f9a767SRodney W. Grimes 
8226f9a767SRodney W. Grimes #define MAX_PAGEOUT_CLUSTER 8
83df8bae1dSRodney W. Grimes 
84df8bae1dSRodney W. Grimes TAILQ_HEAD(swpclean, swpagerclean);
85df8bae1dSRodney W. Grimes 
8626f9a767SRodney W. Grimes typedef	struct swpagerclean	*swp_clean_t;
8726f9a767SRodney W. Grimes 
88df8bae1dSRodney W. Grimes struct swpagerclean {
89df8bae1dSRodney W. Grimes 	TAILQ_ENTRY(swpagerclean)	spc_list;
90df8bae1dSRodney W. Grimes 	int				spc_flags;
91df8bae1dSRodney W. Grimes 	struct buf			*spc_bp;
92df8bae1dSRodney W. Grimes 	sw_pager_t			spc_swp;
93df8bae1dSRodney W. Grimes 	vm_offset_t			spc_kva;
9426f9a767SRodney W. Grimes 	vm_offset_t			spc_altkva;
9526f9a767SRodney W. Grimes 	int				spc_count;
9626f9a767SRodney W. Grimes 	vm_page_t			spc_m[MAX_PAGEOUT_CLUSTER];
97df8bae1dSRodney W. Grimes } swcleanlist [NPENDINGIO] ;
9826f9a767SRodney W. Grimes 
9926f9a767SRodney W. Grimes 
10026f9a767SRodney W. Grimes extern vm_map_t kernel_map;
101df8bae1dSRodney W. Grimes 
102df8bae1dSRodney W. Grimes /* spc_flags values */
10326f9a767SRodney W. Grimes #define SPC_ERROR	0x01
104df8bae1dSRodney W. Grimes 
10526f9a767SRodney W. Grimes #define SWB_EMPTY (-1)
106df8bae1dSRodney W. Grimes 
10726f9a767SRodney W. Grimes void		swap_pager_init(void);
10826f9a767SRodney W. Grimes vm_pager_t	swap_pager_alloc(caddr_t, vm_size_t, vm_prot_t, vm_offset_t);
10926f9a767SRodney W. Grimes void		swap_pager_dealloc(vm_pager_t);
11026f9a767SRodney W. Grimes boolean_t	swap_pager_getpage(vm_pager_t, vm_page_t, boolean_t);
11126f9a767SRodney W. Grimes boolean_t	swap_pager_putpage(vm_pager_t, vm_page_t, boolean_t);
11226f9a767SRodney W. Grimes boolean_t	swap_pager_getmulti(vm_pager_t, vm_page_t *, int, int, boolean_t);
11326f9a767SRodney W. Grimes boolean_t	swap_pager_haspage(vm_pager_t, vm_offset_t);
11426f9a767SRodney W. Grimes int		swap_pager_io(sw_pager_t, vm_page_t *, int, int, int);
11526f9a767SRodney W. Grimes void		swap_pager_iodone(struct buf *);
11626f9a767SRodney W. Grimes boolean_t	swap_pager_clean();
117df8bae1dSRodney W. Grimes 
11826f9a767SRodney W. Grimes extern struct pagerops swappagerops;
119df8bae1dSRodney W. Grimes 
12026f9a767SRodney W. Grimes struct swpclean swap_pager_done;	/* list of compileted page cleans */
121df8bae1dSRodney W. Grimes struct swpclean swap_pager_inuse;	/* list of pending page cleans */
122df8bae1dSRodney W. Grimes struct swpclean swap_pager_free;	/* list of free pager clean structs */
123df8bae1dSRodney W. Grimes struct pagerlst swap_pager_list;	/* list of "named" anon regions */
12426f9a767SRodney W. Grimes struct pagerlst swap_pager_un_list;	/* list of "unnamed" anon pagers */
125df8bae1dSRodney W. Grimes 
12626f9a767SRodney W. Grimes #define	SWAP_FREE_NEEDED	0x1	/* need a swap block */
12726f9a767SRodney W. Grimes int swap_pager_needflags;
12826f9a767SRodney W. Grimes struct rlist *swapfrag;
12926f9a767SRodney W. Grimes 
13026f9a767SRodney W. Grimes struct pagerlst *swp_qs[]={
13126f9a767SRodney W. Grimes 	&swap_pager_list, &swap_pager_un_list, (struct pagerlst *) 0
13226f9a767SRodney W. Grimes };
13326f9a767SRodney W. Grimes 
13426f9a767SRodney W. Grimes int swap_pager_putmulti();
135df8bae1dSRodney W. Grimes 
136df8bae1dSRodney W. Grimes struct pagerops swappagerops = {
137df8bae1dSRodney W. Grimes 	swap_pager_init,
138df8bae1dSRodney W. Grimes 	swap_pager_alloc,
139df8bae1dSRodney W. Grimes 	swap_pager_dealloc,
140df8bae1dSRodney W. Grimes 	swap_pager_getpage,
14126f9a767SRodney W. Grimes 	swap_pager_getmulti,
142df8bae1dSRodney W. Grimes 	swap_pager_putpage,
14326f9a767SRodney W. Grimes 	swap_pager_putmulti,
14426f9a767SRodney W. Grimes 	swap_pager_haspage
145df8bae1dSRodney W. Grimes };
146df8bae1dSRodney W. Grimes 
14726f9a767SRodney W. Grimes extern int nswbuf;
14826f9a767SRodney W. Grimes 
14926f9a767SRodney W. Grimes int npendingio = NPENDINGIO;
15026f9a767SRodney W. Grimes int pendingiowait;
15126f9a767SRodney W. Grimes int require_swap_init;
15226f9a767SRodney W. Grimes void swap_pager_finish();
15326f9a767SRodney W. Grimes int dmmin, dmmax;
15426f9a767SRodney W. Grimes extern int vm_page_count;
15526f9a767SRodney W. Grimes 
15626f9a767SRodney W. Grimes struct buf * getpbuf() ;
15726f9a767SRodney W. Grimes void relpbuf(struct buf *bp) ;
15826f9a767SRodney W. Grimes 
15926f9a767SRodney W. Grimes static inline void swapsizecheck() {
16026f9a767SRodney W. Grimes 	if( vm_swap_size < 128*btodb(PAGE_SIZE)) {
16126f9a767SRodney W. Grimes 		if( swap_pager_full)
16226f9a767SRodney W. Grimes 			printf("swap_pager: out of space\n");
16326f9a767SRodney W. Grimes 		swap_pager_full = 1;
16426f9a767SRodney W. Grimes 	} else if( vm_swap_size > 192*btodb(PAGE_SIZE))
16526f9a767SRodney W. Grimes 		swap_pager_full = 0;
16626f9a767SRodney W. Grimes }
16726f9a767SRodney W. Grimes 
16826f9a767SRodney W. Grimes void
169df8bae1dSRodney W. Grimes swap_pager_init()
170df8bae1dSRodney W. Grimes {
171df8bae1dSRodney W. Grimes 	extern int dmmin, dmmax;
172df8bae1dSRodney W. Grimes 
173df8bae1dSRodney W. Grimes 	dfltpagerops = &swappagerops;
174df8bae1dSRodney W. Grimes 
17526f9a767SRodney W. Grimes 	TAILQ_INIT(&swap_pager_list);
17626f9a767SRodney W. Grimes 	TAILQ_INIT(&swap_pager_un_list);
177df8bae1dSRodney W. Grimes 
178df8bae1dSRodney W. Grimes 	/*
179df8bae1dSRodney W. Grimes 	 * Initialize clean lists
180df8bae1dSRodney W. Grimes 	 */
181df8bae1dSRodney W. Grimes 	TAILQ_INIT(&swap_pager_inuse);
18226f9a767SRodney W. Grimes 	TAILQ_INIT(&swap_pager_done);
183df8bae1dSRodney W. Grimes 	TAILQ_INIT(&swap_pager_free);
18426f9a767SRodney W. Grimes 
18526f9a767SRodney W. Grimes 	require_swap_init = 1;
186df8bae1dSRodney W. Grimes 
187df8bae1dSRodney W. Grimes 	/*
188df8bae1dSRodney W. Grimes 	 * Calculate the swap allocation constants.
189df8bae1dSRodney W. Grimes 	 */
190df8bae1dSRodney W. Grimes 
19126f9a767SRodney W. Grimes 	dmmin = CLBYTES/DEV_BSIZE;
19226f9a767SRodney W. Grimes 	dmmax = btodb(SWB_NPAGES*PAGE_SIZE)*2;
19326f9a767SRodney W. Grimes 
194df8bae1dSRodney W. Grimes }
195df8bae1dSRodney W. Grimes 
196df8bae1dSRodney W. Grimes /*
197df8bae1dSRodney W. Grimes  * Allocate a pager structure and associated resources.
198df8bae1dSRodney W. Grimes  * Note that if we are called from the pageout daemon (handle == NULL)
199df8bae1dSRodney W. Grimes  * we should not wait for memory as it could resulting in deadlock.
200df8bae1dSRodney W. Grimes  */
20126f9a767SRodney W. Grimes vm_pager_t
20226f9a767SRodney W. Grimes swap_pager_alloc(handle, size, prot, offset)
203df8bae1dSRodney W. Grimes 	caddr_t handle;
204df8bae1dSRodney W. Grimes 	register vm_size_t size;
205df8bae1dSRodney W. Grimes 	vm_prot_t prot;
20626f9a767SRodney W. Grimes 	vm_offset_t offset;
207df8bae1dSRodney W. Grimes {
208df8bae1dSRodney W. Grimes 	register vm_pager_t pager;
209df8bae1dSRodney W. Grimes 	register sw_pager_t swp;
210df8bae1dSRodney W. Grimes 	int waitok;
21126f9a767SRodney W. Grimes 	int i,j;
212df8bae1dSRodney W. Grimes 
21326f9a767SRodney W. Grimes 	if (require_swap_init) {
21426f9a767SRodney W. Grimes 		swp_clean_t spc;
21526f9a767SRodney W. Grimes 		struct buf *bp;
21626f9a767SRodney W. Grimes 		/*
21726f9a767SRodney W. Grimes 		 * kva's are allocated here so that we dont need to keep
21826f9a767SRodney W. Grimes 		 * doing kmem_alloc pageables at runtime
21926f9a767SRodney W. Grimes 		 */
22026f9a767SRodney W. Grimes 		for (i = 0, spc = swcleanlist; i < npendingio ; i++, spc++) {
22126f9a767SRodney W. Grimes 			spc->spc_kva = kmem_alloc_pageable(pager_map, PAGE_SIZE);
22226f9a767SRodney W. Grimes 			if (!spc->spc_kva) {
22326f9a767SRodney W. Grimes 				break;
22426f9a767SRodney W. Grimes 			}
22526f9a767SRodney W. Grimes 			spc->spc_bp = malloc( sizeof( *bp), M_TEMP, M_NOWAIT);
22626f9a767SRodney W. Grimes 			if (!spc->spc_bp) {
22726f9a767SRodney W. Grimes 				kmem_free_wakeup(pager_map, spc->spc_kva, PAGE_SIZE);
22826f9a767SRodney W. Grimes 				break;
22926f9a767SRodney W. Grimes 			}
23026f9a767SRodney W. Grimes 			spc->spc_flags = 0;
23126f9a767SRodney W. Grimes 			TAILQ_INSERT_TAIL(&swap_pager_free, spc, spc_list);
23226f9a767SRodney W. Grimes 		}
23326f9a767SRodney W. Grimes 		require_swap_init = 0;
23426f9a767SRodney W. Grimes 		if( size == 0)
23526f9a767SRodney W. Grimes 			return(NULL);
23626f9a767SRodney W. Grimes 	}
23726f9a767SRodney W. Grimes 
238df8bae1dSRodney W. Grimes 	/*
239df8bae1dSRodney W. Grimes 	 * If this is a "named" anonymous region, look it up and
240df8bae1dSRodney W. Grimes 	 * return the appropriate pager if it exists.
241df8bae1dSRodney W. Grimes 	 */
242df8bae1dSRodney W. Grimes 	if (handle) {
243df8bae1dSRodney W. Grimes 		pager = vm_pager_lookup(&swap_pager_list, handle);
244df8bae1dSRodney W. Grimes 		if (pager != NULL) {
245df8bae1dSRodney W. Grimes 			/*
246df8bae1dSRodney W. Grimes 			 * Use vm_object_lookup to gain a reference
247df8bae1dSRodney W. Grimes 			 * to the object and also to remove from the
248df8bae1dSRodney W. Grimes 			 * object cache.
249df8bae1dSRodney W. Grimes 			 */
250df8bae1dSRodney W. Grimes 			if (vm_object_lookup(pager) == NULL)
251df8bae1dSRodney W. Grimes 				panic("swap_pager_alloc: bad object");
252df8bae1dSRodney W. Grimes 			return(pager);
253df8bae1dSRodney W. Grimes 		}
254df8bae1dSRodney W. Grimes 	}
25526f9a767SRodney W. Grimes 
25626f9a767SRodney W. Grimes 	if (swap_pager_full) {
25726f9a767SRodney W. Grimes 		return(NULL);
25826f9a767SRodney W. Grimes 	}
25926f9a767SRodney W. Grimes 
260df8bae1dSRodney W. Grimes 	/*
261df8bae1dSRodney W. Grimes 	 * Pager doesn't exist, allocate swap management resources
262df8bae1dSRodney W. Grimes 	 * and initialize.
263df8bae1dSRodney W. Grimes 	 */
264df8bae1dSRodney W. Grimes 	waitok = handle ? M_WAITOK : M_NOWAIT;
265df8bae1dSRodney W. Grimes 	pager = (vm_pager_t)malloc(sizeof *pager, M_VMPAGER, waitok);
266df8bae1dSRodney W. Grimes 	if (pager == NULL)
267df8bae1dSRodney W. Grimes 		return(NULL);
268df8bae1dSRodney W. Grimes 	swp = (sw_pager_t)malloc(sizeof *swp, M_VMPGDATA, waitok);
269df8bae1dSRodney W. Grimes 	if (swp == NULL) {
270df8bae1dSRodney W. Grimes 		free((caddr_t)pager, M_VMPAGER);
271df8bae1dSRodney W. Grimes 		return(NULL);
272df8bae1dSRodney W. Grimes 	}
273df8bae1dSRodney W. Grimes 	size = round_page(size);
274df8bae1dSRodney W. Grimes 	swp->sw_osize = size;
27526f9a767SRodney W. Grimes 	swp->sw_nblocks = (btodb(size) + btodb(SWB_NPAGES * PAGE_SIZE) - 1) / btodb(SWB_NPAGES*PAGE_SIZE);
276df8bae1dSRodney W. Grimes 	swp->sw_blocks = (sw_blk_t)
277df8bae1dSRodney W. Grimes 		malloc(swp->sw_nblocks*sizeof(*swp->sw_blocks),
27826f9a767SRodney W. Grimes 		       M_VMPGDATA, waitok);
279df8bae1dSRodney W. Grimes 	if (swp->sw_blocks == NULL) {
280df8bae1dSRodney W. Grimes 		free((caddr_t)swp, M_VMPGDATA);
281df8bae1dSRodney W. Grimes 		free((caddr_t)pager, M_VMPAGER);
28226f9a767SRodney W. Grimes 		return(NULL);
283df8bae1dSRodney W. Grimes 	}
28426f9a767SRodney W. Grimes 
28526f9a767SRodney W. Grimes 	for (i = 0; i < swp->sw_nblocks; i++) {
28626f9a767SRodney W. Grimes 		swp->sw_blocks[i].swb_valid = 0;
28726f9a767SRodney W. Grimes 		swp->sw_blocks[i].swb_locked = 0;
28826f9a767SRodney W. Grimes 		for (j = 0; j < SWB_NPAGES; j++)
28926f9a767SRodney W. Grimes 			swp->sw_blocks[i].swb_block[j] = SWB_EMPTY;
29026f9a767SRodney W. Grimes 	}
29126f9a767SRodney W. Grimes 
292df8bae1dSRodney W. Grimes 	swp->sw_poip = 0;
293df8bae1dSRodney W. Grimes 	if (handle) {
294df8bae1dSRodney W. Grimes 		vm_object_t object;
295df8bae1dSRodney W. Grimes 
296df8bae1dSRodney W. Grimes 		swp->sw_flags = SW_NAMED;
297df8bae1dSRodney W. Grimes 		TAILQ_INSERT_TAIL(&swap_pager_list, pager, pg_list);
298df8bae1dSRodney W. Grimes 		/*
299df8bae1dSRodney W. Grimes 		 * Consistant with other pagers: return with object
300df8bae1dSRodney W. Grimes 		 * referenced.  Can't do this with handle == NULL
301df8bae1dSRodney W. Grimes 		 * since it might be the pageout daemon calling.
302df8bae1dSRodney W. Grimes 		 */
303df8bae1dSRodney W. Grimes 		object = vm_object_allocate(size);
304df8bae1dSRodney W. Grimes 		vm_object_enter(object, pager);
305df8bae1dSRodney W. Grimes 		vm_object_setpager(object, pager, 0, FALSE);
306df8bae1dSRodney W. Grimes 	} else {
307df8bae1dSRodney W. Grimes 		swp->sw_flags = 0;
30826f9a767SRodney W. Grimes 		TAILQ_INSERT_TAIL(&swap_pager_un_list, pager, pg_list);
309df8bae1dSRodney W. Grimes 	}
310df8bae1dSRodney W. Grimes 	pager->pg_handle = handle;
311df8bae1dSRodney W. Grimes 	pager->pg_ops = &swappagerops;
312df8bae1dSRodney W. Grimes 	pager->pg_type = PG_SWAP;
31326f9a767SRodney W. Grimes 	pager->pg_data = (caddr_t)swp;
314df8bae1dSRodney W. Grimes 
315df8bae1dSRodney W. Grimes 	return(pager);
316df8bae1dSRodney W. Grimes }
317df8bae1dSRodney W. Grimes 
31826f9a767SRodney W. Grimes /*
31926f9a767SRodney W. Grimes  * returns disk block associated with pager and offset
32026f9a767SRodney W. Grimes  * additionally, as a side effect returns a flag indicating
32126f9a767SRodney W. Grimes  * if the block has been written
32226f9a767SRodney W. Grimes  */
32326f9a767SRodney W. Grimes 
32426f9a767SRodney W. Grimes static int *
32526f9a767SRodney W. Grimes swap_pager_diskaddr(swp, offset, valid)
32626f9a767SRodney W. Grimes 	sw_pager_t swp;
32726f9a767SRodney W. Grimes 	vm_offset_t offset;
32826f9a767SRodney W. Grimes 	int *valid;
32926f9a767SRodney W. Grimes {
33026f9a767SRodney W. Grimes 	register sw_blk_t swb;
33126f9a767SRodney W. Grimes 	int ix;
33226f9a767SRodney W. Grimes 
33326f9a767SRodney W. Grimes 	if (valid)
33426f9a767SRodney W. Grimes 		*valid = 0;
33526f9a767SRodney W. Grimes 	ix = offset / (SWB_NPAGES*PAGE_SIZE);
33626f9a767SRodney W. Grimes 	if (swp->sw_blocks == NULL || ix >= swp->sw_nblocks) {
33726f9a767SRodney W. Grimes 		return(FALSE);
33826f9a767SRodney W. Grimes 	}
33926f9a767SRodney W. Grimes 	swb = &swp->sw_blocks[ix];
34026f9a767SRodney W. Grimes 	ix = (offset % (SWB_NPAGES*PAGE_SIZE)) / PAGE_SIZE;
34126f9a767SRodney W. Grimes 	if (valid)
34226f9a767SRodney W. Grimes 		*valid = swb->swb_valid & (1<<ix);
34326f9a767SRodney W. Grimes 	return &swb->swb_block[ix];
34426f9a767SRodney W. Grimes }
34526f9a767SRodney W. Grimes 
34626f9a767SRodney W. Grimes /*
34726f9a767SRodney W. Grimes  * Utility routine to set the valid (written) bit for
34826f9a767SRodney W. Grimes  * a block associated with a pager and offset
34926f9a767SRodney W. Grimes  */
350df8bae1dSRodney W. Grimes static void
35126f9a767SRodney W. Grimes swap_pager_setvalid(swp, offset, valid)
35226f9a767SRodney W. Grimes 	sw_pager_t swp;
35326f9a767SRodney W. Grimes 	vm_offset_t offset;
35426f9a767SRodney W. Grimes 	int valid;
35526f9a767SRodney W. Grimes {
35626f9a767SRodney W. Grimes 	register sw_blk_t swb;
35726f9a767SRodney W. Grimes 	int ix;
35826f9a767SRodney W. Grimes 
35926f9a767SRodney W. Grimes 	ix = offset / (SWB_NPAGES*PAGE_SIZE);
36026f9a767SRodney W. Grimes 	if (swp->sw_blocks == NULL || ix >= swp->sw_nblocks)
36126f9a767SRodney W. Grimes 		return;
36226f9a767SRodney W. Grimes 
36326f9a767SRodney W. Grimes 	swb = &swp->sw_blocks[ix];
36426f9a767SRodney W. Grimes 	ix = (offset % (SWB_NPAGES*PAGE_SIZE)) / PAGE_SIZE;
36526f9a767SRodney W. Grimes 	if (valid)
36626f9a767SRodney W. Grimes 		swb->swb_valid |= (1 << ix);
36726f9a767SRodney W. Grimes 	else
36826f9a767SRodney W. Grimes 		swb->swb_valid &= ~(1 << ix);
36926f9a767SRodney W. Grimes 	return;
37026f9a767SRodney W. Grimes }
37126f9a767SRodney W. Grimes 
37226f9a767SRodney W. Grimes /*
37326f9a767SRodney W. Grimes  * this routine allocates swap space with a fragmentation
37426f9a767SRodney W. Grimes  * minimization policy.
37526f9a767SRodney W. Grimes  */
37626f9a767SRodney W. Grimes int
37726f9a767SRodney W. Grimes swap_pager_getswapspace( unsigned amount, unsigned *rtval) {
37826f9a767SRodney W. Grimes 	unsigned tmpalloc;
37926f9a767SRodney W. Grimes 	unsigned nblocksfrag = btodb(SWB_NPAGES*PAGE_SIZE);
38026f9a767SRodney W. Grimes 	if( amount < nblocksfrag) {
38126f9a767SRodney W. Grimes 		if( rlist_alloc(&swapfrag, amount, rtval))
38226f9a767SRodney W. Grimes 			return 1;
38326f9a767SRodney W. Grimes 		if( !rlist_alloc(&swapmap, nblocksfrag, &tmpalloc))
38426f9a767SRodney W. Grimes 			return 0;
38526f9a767SRodney W. Grimes 		rlist_free( &swapfrag, tmpalloc+amount, tmpalloc + nblocksfrag - 1);
38626f9a767SRodney W. Grimes 		*rtval = tmpalloc;
38726f9a767SRodney W. Grimes 		return 1;
38826f9a767SRodney W. Grimes 	}
38926f9a767SRodney W. Grimes 	if( !rlist_alloc(&swapmap, amount, rtval))
39026f9a767SRodney W. Grimes 		return 0;
39126f9a767SRodney W. Grimes 	else
39226f9a767SRodney W. Grimes 		return 1;
39326f9a767SRodney W. Grimes }
39426f9a767SRodney W. Grimes 
39526f9a767SRodney W. Grimes /*
39626f9a767SRodney W. Grimes  * this routine frees swap space with a fragmentation
39726f9a767SRodney W. Grimes  * minimization policy.
39826f9a767SRodney W. Grimes  */
39926f9a767SRodney W. Grimes void
40026f9a767SRodney W. Grimes swap_pager_freeswapspace( unsigned from, unsigned to) {
40126f9a767SRodney W. Grimes 	unsigned nblocksfrag = btodb(SWB_NPAGES*PAGE_SIZE);
40226f9a767SRodney W. Grimes 	unsigned tmpalloc;
40326f9a767SRodney W. Grimes 	if( ((to + 1) - from) >= nblocksfrag) {
40426f9a767SRodney W. Grimes 		while( (from + nblocksfrag) <= to + 1) {
40526f9a767SRodney W. Grimes 			rlist_free(&swapmap, from, from + nblocksfrag - 1);
40626f9a767SRodney W. Grimes 			from += nblocksfrag;
40726f9a767SRodney W. Grimes 		}
40826f9a767SRodney W. Grimes 	}
40926f9a767SRodney W. Grimes 	if( from >= to)
41026f9a767SRodney W. Grimes 		return;
41126f9a767SRodney W. Grimes 	rlist_free(&swapfrag, from, to);
41226f9a767SRodney W. Grimes 	while( rlist_alloc(&swapfrag, nblocksfrag, &tmpalloc)) {
41326f9a767SRodney W. Grimes 		rlist_free(&swapmap, tmpalloc, tmpalloc + nblocksfrag-1);
41426f9a767SRodney W. Grimes 	}
41526f9a767SRodney W. Grimes }
41626f9a767SRodney W. Grimes /*
41726f9a767SRodney W. Grimes  * this routine frees swap blocks from a specified pager
41826f9a767SRodney W. Grimes  */
41926f9a767SRodney W. Grimes void
42026f9a767SRodney W. Grimes _swap_pager_freespace(swp, start, size)
42126f9a767SRodney W. Grimes 	sw_pager_t swp;
42226f9a767SRodney W. Grimes 	vm_offset_t start;
42326f9a767SRodney W. Grimes 	vm_offset_t size;
42426f9a767SRodney W. Grimes {
42526f9a767SRodney W. Grimes 	vm_offset_t i;
42626f9a767SRodney W. Grimes 	int s;
42726f9a767SRodney W. Grimes 
42826f9a767SRodney W. Grimes 	s = splbio();
42926f9a767SRodney W. Grimes 	for (i = start; i < round_page(start + size - 1); i += PAGE_SIZE) {
43026f9a767SRodney W. Grimes 		int valid;
43126f9a767SRodney W. Grimes 		int *addr = swap_pager_diskaddr(swp, i, &valid);
43226f9a767SRodney W. Grimes 		if (addr && *addr != SWB_EMPTY) {
43326f9a767SRodney W. Grimes 			swap_pager_freeswapspace(*addr, *addr+btodb(PAGE_SIZE) - 1);
43426f9a767SRodney W. Grimes 			if( valid) {
43526f9a767SRodney W. Grimes 				vm_swap_size += btodb(PAGE_SIZE);
43626f9a767SRodney W. Grimes 				swap_pager_setvalid(swp, i, 0);
43726f9a767SRodney W. Grimes 			}
43826f9a767SRodney W. Grimes 			*addr = SWB_EMPTY;
43926f9a767SRodney W. Grimes 		}
44026f9a767SRodney W. Grimes 	}
44126f9a767SRodney W. Grimes 	swapsizecheck();
44226f9a767SRodney W. Grimes 	splx(s);
44326f9a767SRodney W. Grimes }
44426f9a767SRodney W. Grimes 
44526f9a767SRodney W. Grimes void
44626f9a767SRodney W. Grimes swap_pager_freespace(pager, start, size)
44726f9a767SRodney W. Grimes 	vm_pager_t pager;
44826f9a767SRodney W. Grimes 	vm_offset_t start;
44926f9a767SRodney W. Grimes 	vm_offset_t size;
45026f9a767SRodney W. Grimes {
45126f9a767SRodney W. Grimes 	_swap_pager_freespace((sw_pager_t) pager->pg_data, start, size);
45226f9a767SRodney W. Grimes }
45326f9a767SRodney W. Grimes 
45426f9a767SRodney W. Grimes /*
45526f9a767SRodney W. Grimes  * swap_pager_reclaim frees up over-allocated space from all pagers
45626f9a767SRodney W. Grimes  * this eliminates internal fragmentation due to allocation of space
45726f9a767SRodney W. Grimes  * for segments that are never swapped to. It has been written so that
45826f9a767SRodney W. Grimes  * it does not block until the rlist_free operation occurs; it keeps
45926f9a767SRodney W. Grimes  * the queues consistant.
46026f9a767SRodney W. Grimes  */
46126f9a767SRodney W. Grimes 
46226f9a767SRodney W. Grimes /*
46326f9a767SRodney W. Grimes  * Maximum number of blocks (pages) to reclaim per pass
46426f9a767SRodney W. Grimes  */
46526f9a767SRodney W. Grimes #define MAXRECLAIM 256
46626f9a767SRodney W. Grimes 
46726f9a767SRodney W. Grimes void
46826f9a767SRodney W. Grimes swap_pager_reclaim()
46926f9a767SRodney W. Grimes {
47026f9a767SRodney W. Grimes 	vm_pager_t p;
47126f9a767SRodney W. Grimes 	sw_pager_t swp;
47226f9a767SRodney W. Grimes 	int i, j, k;
47326f9a767SRodney W. Grimes 	int s;
47426f9a767SRodney W. Grimes 	int reclaimcount;
47526f9a767SRodney W. Grimes 	static int reclaims[MAXRECLAIM];
47626f9a767SRodney W. Grimes 	static int in_reclaim;
47726f9a767SRodney W. Grimes 
47826f9a767SRodney W. Grimes /*
47926f9a767SRodney W. Grimes  * allow only one process to be in the swap_pager_reclaim subroutine
48026f9a767SRodney W. Grimes  */
48126f9a767SRodney W. Grimes 	s = splbio();
48226f9a767SRodney W. Grimes 	if (in_reclaim) {
48326f9a767SRodney W. Grimes 		tsleep((caddr_t) &in_reclaim, PSWP, "swrclm", 0);
48426f9a767SRodney W. Grimes 		splx(s);
48526f9a767SRodney W. Grimes 		return;
48626f9a767SRodney W. Grimes 	}
48726f9a767SRodney W. Grimes 	in_reclaim = 1;
48826f9a767SRodney W. Grimes 	reclaimcount = 0;
48926f9a767SRodney W. Grimes 
49026f9a767SRodney W. Grimes 	/* for each pager queue */
49126f9a767SRodney W. Grimes 	for (k = 0; swp_qs[k]; k++) {
49226f9a767SRodney W. Grimes 
49326f9a767SRodney W. Grimes 		p = swp_qs[k]->tqh_first;
49426f9a767SRodney W. Grimes 		while (p && (reclaimcount < MAXRECLAIM)) {
49526f9a767SRodney W. Grimes 
49626f9a767SRodney W. Grimes 			/*
49726f9a767SRodney W. Grimes 			 * see if any blocks associated with a pager has been
49826f9a767SRodney W. Grimes 			 * allocated but not used (written)
49926f9a767SRodney W. Grimes 			 */
50026f9a767SRodney W. Grimes 			swp = (sw_pager_t) p->pg_data;
50126f9a767SRodney W. Grimes 			for (i = 0; i < swp->sw_nblocks; i++) {
50226f9a767SRodney W. Grimes 				sw_blk_t swb = &swp->sw_blocks[i];
50326f9a767SRodney W. Grimes 				if( swb->swb_locked)
50426f9a767SRodney W. Grimes 					continue;
50526f9a767SRodney W. Grimes 				for (j = 0; j < SWB_NPAGES; j++) {
50626f9a767SRodney W. Grimes 					if (swb->swb_block[j] != SWB_EMPTY &&
50726f9a767SRodney W. Grimes 						(swb->swb_valid & (1 << j)) == 0) {
50826f9a767SRodney W. Grimes 						reclaims[reclaimcount++] = swb->swb_block[j];
50926f9a767SRodney W. Grimes 						swb->swb_block[j] = SWB_EMPTY;
51026f9a767SRodney W. Grimes 						if (reclaimcount >= MAXRECLAIM)
51126f9a767SRodney W. Grimes 							goto rfinished;
51226f9a767SRodney W. Grimes 					}
51326f9a767SRodney W. Grimes 				}
51426f9a767SRodney W. Grimes 			}
51526f9a767SRodney W. Grimes 			p = p->pg_list.tqe_next;
51626f9a767SRodney W. Grimes 		}
51726f9a767SRodney W. Grimes 	}
51826f9a767SRodney W. Grimes 
51926f9a767SRodney W. Grimes rfinished:
52026f9a767SRodney W. Grimes 
52126f9a767SRodney W. Grimes /*
52226f9a767SRodney W. Grimes  * free the blocks that have been added to the reclaim list
52326f9a767SRodney W. Grimes  */
52426f9a767SRodney W. Grimes 	for (i = 0; i < reclaimcount; i++) {
52526f9a767SRodney W. Grimes 		swap_pager_freeswapspace(reclaims[i], reclaims[i]+btodb(PAGE_SIZE) - 1);
52626f9a767SRodney W. Grimes 		swapsizecheck();
52726f9a767SRodney W. Grimes 		wakeup((caddr_t) &in_reclaim);
52826f9a767SRodney W. Grimes 	}
52926f9a767SRodney W. Grimes 
53026f9a767SRodney W. Grimes 	splx(s);
53126f9a767SRodney W. Grimes 	in_reclaim = 0;
53226f9a767SRodney W. Grimes 	wakeup((caddr_t) &in_reclaim);
53326f9a767SRodney W. Grimes }
53426f9a767SRodney W. Grimes 
53526f9a767SRodney W. Grimes 
53626f9a767SRodney W. Grimes /*
53726f9a767SRodney W. Grimes  * swap_pager_copy copies blocks from one pager to another and
53826f9a767SRodney W. Grimes  * destroys the source pager
53926f9a767SRodney W. Grimes  */
54026f9a767SRodney W. Grimes 
54126f9a767SRodney W. Grimes void
54226f9a767SRodney W. Grimes swap_pager_copy(srcpager, srcoffset, dstpager, dstoffset, offset)
54326f9a767SRodney W. Grimes 	vm_pager_t srcpager;
54426f9a767SRodney W. Grimes 	vm_offset_t srcoffset;
54526f9a767SRodney W. Grimes 	vm_pager_t dstpager;
54626f9a767SRodney W. Grimes 	vm_offset_t dstoffset;
54726f9a767SRodney W. Grimes 	vm_offset_t offset;
54826f9a767SRodney W. Grimes {
54926f9a767SRodney W. Grimes 	sw_pager_t srcswp, dstswp;
55026f9a767SRodney W. Grimes 	vm_offset_t i;
55126f9a767SRodney W. Grimes 	int s;
55226f9a767SRodney W. Grimes 
55326f9a767SRodney W. Grimes 	srcswp = (sw_pager_t) srcpager->pg_data;
55426f9a767SRodney W. Grimes 	dstswp = (sw_pager_t) dstpager->pg_data;
55526f9a767SRodney W. Grimes 
55626f9a767SRodney W. Grimes /*
55726f9a767SRodney W. Grimes  * remove the source pager from the swap_pager internal queue
55826f9a767SRodney W. Grimes  */
55926f9a767SRodney W. Grimes 	s = splbio();
56026f9a767SRodney W. Grimes 	if (srcswp->sw_flags & SW_NAMED) {
56126f9a767SRodney W. Grimes 		TAILQ_REMOVE(&swap_pager_list, srcpager, pg_list);
56226f9a767SRodney W. Grimes 		srcswp->sw_flags &= ~SW_NAMED;
56326f9a767SRodney W. Grimes 	} else {
56426f9a767SRodney W. Grimes 		TAILQ_REMOVE(&swap_pager_un_list, srcpager, pg_list);
56526f9a767SRodney W. Grimes 	}
56626f9a767SRodney W. Grimes 
56726f9a767SRodney W. Grimes 	while (srcswp->sw_poip) {
56826f9a767SRodney W. Grimes 		tsleep((caddr_t)srcswp, PVM, "spgout", 0);
56926f9a767SRodney W. Grimes 	}
57026f9a767SRodney W. Grimes 	splx(s);
57126f9a767SRodney W. Grimes 
57226f9a767SRodney W. Grimes /*
57326f9a767SRodney W. Grimes  * clean all of the pages that are currently active and finished
57426f9a767SRodney W. Grimes  */
57526f9a767SRodney W. Grimes 	(void) swap_pager_clean();
57626f9a767SRodney W. Grimes 
57726f9a767SRodney W. Grimes 	s = splbio();
57826f9a767SRodney W. Grimes /*
57926f9a767SRodney W. Grimes  * clear source block before destination object
58026f9a767SRodney W. Grimes  * (release allocated space)
58126f9a767SRodney W. Grimes  */
58226f9a767SRodney W. Grimes 	for (i = 0; i < offset + srcoffset; i += PAGE_SIZE) {
58326f9a767SRodney W. Grimes 		int valid;
58426f9a767SRodney W. Grimes 		int *addr = swap_pager_diskaddr(srcswp, i, &valid);
58526f9a767SRodney W. Grimes 		if (addr && *addr != SWB_EMPTY) {
58626f9a767SRodney W. Grimes 			swap_pager_freeswapspace(*addr, *addr+btodb(PAGE_SIZE) - 1);
58726f9a767SRodney W. Grimes 			if( valid)
58826f9a767SRodney W. Grimes 				vm_swap_size += btodb(PAGE_SIZE);
58926f9a767SRodney W. Grimes 			swapsizecheck();
59026f9a767SRodney W. Grimes 			*addr = SWB_EMPTY;
59126f9a767SRodney W. Grimes 		}
59226f9a767SRodney W. Grimes 	}
59326f9a767SRodney W. Grimes /*
59426f9a767SRodney W. Grimes  * transfer source to destination
59526f9a767SRodney W. Grimes  */
59626f9a767SRodney W. Grimes 	for (i = 0; i < dstswp->sw_osize; i += PAGE_SIZE) {
59726f9a767SRodney W. Grimes 		int srcvalid, dstvalid;
59826f9a767SRodney W. Grimes 		int *srcaddrp = swap_pager_diskaddr(srcswp, i + offset + srcoffset,
59926f9a767SRodney W. Grimes 			&srcvalid);
60026f9a767SRodney W. Grimes 		int *dstaddrp;
60126f9a767SRodney W. Grimes 	/*
60226f9a767SRodney W. Grimes 	 * see if the source has space allocated
60326f9a767SRodney W. Grimes 	 */
60426f9a767SRodney W. Grimes 		if (srcaddrp && *srcaddrp != SWB_EMPTY) {
60526f9a767SRodney W. Grimes 		/*
60626f9a767SRodney W. Grimes 		 * if the source is valid and the dest has no space, then
60726f9a767SRodney W. Grimes 		 * copy the allocation from the srouce to the dest.
60826f9a767SRodney W. Grimes 		 */
60926f9a767SRodney W. Grimes 			if (srcvalid) {
61026f9a767SRodney W. Grimes 				dstaddrp = swap_pager_diskaddr(dstswp, i + dstoffset, &dstvalid);
61126f9a767SRodney W. Grimes 				/*
61226f9a767SRodney W. Grimes 				 * if the dest already has a valid block, deallocate the
61326f9a767SRodney W. Grimes 				 * source block without copying.
61426f9a767SRodney W. Grimes 				 */
61526f9a767SRodney W. Grimes 				if (!dstvalid && dstaddrp && *dstaddrp != SWB_EMPTY) {
61626f9a767SRodney W. Grimes 					swap_pager_freeswapspace(*dstaddrp, *dstaddrp+btodb(PAGE_SIZE) - 1);
61726f9a767SRodney W. Grimes 					*dstaddrp = SWB_EMPTY;
61826f9a767SRodney W. Grimes 				}
61926f9a767SRodney W. Grimes 				if (dstaddrp && *dstaddrp == SWB_EMPTY) {
62026f9a767SRodney W. Grimes 					*dstaddrp = *srcaddrp;
62126f9a767SRodney W. Grimes 					*srcaddrp = SWB_EMPTY;
62226f9a767SRodney W. Grimes 					swap_pager_setvalid(dstswp, i + dstoffset, 1);
62326f9a767SRodney W. Grimes 					vm_swap_size -= btodb(PAGE_SIZE);
62426f9a767SRodney W. Grimes 				}
62526f9a767SRodney W. Grimes 			}
62626f9a767SRodney W. Grimes 		/*
62726f9a767SRodney W. Grimes 		 * if the source is not empty at this point, then deallocate the space.
62826f9a767SRodney W. Grimes 		 */
62926f9a767SRodney W. Grimes 			if (*srcaddrp != SWB_EMPTY) {
63026f9a767SRodney W. Grimes 				swap_pager_freeswapspace(*srcaddrp, *srcaddrp+btodb(PAGE_SIZE) - 1);
63126f9a767SRodney W. Grimes 				if( srcvalid)
63226f9a767SRodney W. Grimes 					vm_swap_size += btodb(PAGE_SIZE);
63326f9a767SRodney W. Grimes 				*srcaddrp = SWB_EMPTY;
63426f9a767SRodney W. Grimes 			}
63526f9a767SRodney W. Grimes 		}
63626f9a767SRodney W. Grimes 	}
63726f9a767SRodney W. Grimes 
63826f9a767SRodney W. Grimes /*
63926f9a767SRodney W. Grimes  * deallocate the rest of the source object
64026f9a767SRodney W. Grimes  */
64126f9a767SRodney W. Grimes 	for (i = dstswp->sw_osize + offset + srcoffset; i < srcswp->sw_osize; i += PAGE_SIZE) {
64226f9a767SRodney W. Grimes 		int valid;
64326f9a767SRodney W. Grimes 		int *srcaddrp = swap_pager_diskaddr(srcswp, i, &valid);
64426f9a767SRodney W. Grimes 		if (srcaddrp && *srcaddrp != SWB_EMPTY) {
64526f9a767SRodney W. Grimes 			swap_pager_freeswapspace(*srcaddrp, *srcaddrp+btodb(PAGE_SIZE) - 1);
64626f9a767SRodney W. Grimes 			if( valid)
64726f9a767SRodney W. Grimes 				vm_swap_size += btodb(PAGE_SIZE);
64826f9a767SRodney W. Grimes 			*srcaddrp = SWB_EMPTY;
64926f9a767SRodney W. Grimes 		}
65026f9a767SRodney W. Grimes 	}
65126f9a767SRodney W. Grimes 
65226f9a767SRodney W. Grimes 	swapsizecheck();
65326f9a767SRodney W. Grimes 	splx(s);
65426f9a767SRodney W. Grimes 
65526f9a767SRodney W. Grimes 	free((caddr_t)srcswp->sw_blocks, M_VMPGDATA);
65626f9a767SRodney W. Grimes 	srcswp->sw_blocks = 0;
65726f9a767SRodney W. Grimes 	free((caddr_t)srcswp, M_VMPGDATA);
65826f9a767SRodney W. Grimes 	srcpager->pg_data = 0;
65926f9a767SRodney W. Grimes 	free((caddr_t)srcpager, M_VMPAGER);
66026f9a767SRodney W. Grimes 
66126f9a767SRodney W. Grimes 	return;
66226f9a767SRodney W. Grimes }
66326f9a767SRodney W. Grimes 
66426f9a767SRodney W. Grimes 
66526f9a767SRodney W. Grimes void
666df8bae1dSRodney W. Grimes swap_pager_dealloc(pager)
667df8bae1dSRodney W. Grimes 	vm_pager_t pager;
668df8bae1dSRodney W. Grimes {
66926f9a767SRodney W. Grimes 	register int i,j;
670df8bae1dSRodney W. Grimes 	register sw_blk_t bp;
671df8bae1dSRodney W. Grimes 	register sw_pager_t swp;
672df8bae1dSRodney W. Grimes 	int s;
673df8bae1dSRodney W. Grimes 
674df8bae1dSRodney W. Grimes 	/*
675df8bae1dSRodney W. Grimes 	 * Remove from list right away so lookups will fail if we
676df8bae1dSRodney W. Grimes 	 * block for pageout completion.
677df8bae1dSRodney W. Grimes 	 */
67826f9a767SRodney W. Grimes 	s = splbio();
679df8bae1dSRodney W. Grimes 	swp = (sw_pager_t) pager->pg_data;
680df8bae1dSRodney W. Grimes 	if (swp->sw_flags & SW_NAMED) {
681df8bae1dSRodney W. Grimes 		TAILQ_REMOVE(&swap_pager_list, pager, pg_list);
682df8bae1dSRodney W. Grimes 		swp->sw_flags &= ~SW_NAMED;
68326f9a767SRodney W. Grimes 	} else {
68426f9a767SRodney W. Grimes 		TAILQ_REMOVE(&swap_pager_un_list, pager, pg_list);
685df8bae1dSRodney W. Grimes 	}
686df8bae1dSRodney W. Grimes 	/*
687df8bae1dSRodney W. Grimes 	 * Wait for all pageouts to finish and remove
688df8bae1dSRodney W. Grimes 	 * all entries from cleaning list.
689df8bae1dSRodney W. Grimes 	 */
69026f9a767SRodney W. Grimes 
691df8bae1dSRodney W. Grimes 	while (swp->sw_poip) {
69226f9a767SRodney W. Grimes 		tsleep((caddr_t)swp, PVM, "swpout", 0);
693df8bae1dSRodney W. Grimes 	}
694df8bae1dSRodney W. Grimes 	splx(s);
69526f9a767SRodney W. Grimes 
69626f9a767SRodney W. Grimes 
69726f9a767SRodney W. Grimes 	(void) swap_pager_clean();
698df8bae1dSRodney W. Grimes 
699df8bae1dSRodney W. Grimes 	/*
700df8bae1dSRodney W. Grimes 	 * Free left over swap blocks
701df8bae1dSRodney W. Grimes 	 */
70226f9a767SRodney W. Grimes 	s = splbio();
70326f9a767SRodney W. Grimes 	for (i = 0, bp = swp->sw_blocks; i < swp->sw_nblocks; i++, bp++) {
70426f9a767SRodney W. Grimes 		for (j = 0; j < SWB_NPAGES; j++)
70526f9a767SRodney W. Grimes 		if (bp->swb_block[j] != SWB_EMPTY) {
70626f9a767SRodney W. Grimes 			swap_pager_freeswapspace((unsigned)bp->swb_block[j],
70726f9a767SRodney W. Grimes 				(unsigned)bp->swb_block[j] + btodb(PAGE_SIZE) - 1);
70826f9a767SRodney W. Grimes 			if( bp->swb_valid & (1<<j))
70926f9a767SRodney W. Grimes 				vm_swap_size += btodb(PAGE_SIZE);
71026f9a767SRodney W. Grimes 			bp->swb_block[j] = SWB_EMPTY;
711df8bae1dSRodney W. Grimes 		}
71226f9a767SRodney W. Grimes 	}
71326f9a767SRodney W. Grimes 	splx(s);
71426f9a767SRodney W. Grimes 	swapsizecheck();
71526f9a767SRodney W. Grimes 
716df8bae1dSRodney W. Grimes 	/*
717df8bae1dSRodney W. Grimes 	 * Free swap management resources
718df8bae1dSRodney W. Grimes 	 */
719df8bae1dSRodney W. Grimes 	free((caddr_t)swp->sw_blocks, M_VMPGDATA);
72026f9a767SRodney W. Grimes 	swp->sw_blocks = 0;
721df8bae1dSRodney W. Grimes 	free((caddr_t)swp, M_VMPGDATA);
72226f9a767SRodney W. Grimes 	pager->pg_data = 0;
723df8bae1dSRodney W. Grimes 	free((caddr_t)pager, M_VMPAGER);
724df8bae1dSRodney W. Grimes }
725df8bae1dSRodney W. Grimes 
72626f9a767SRodney W. Grimes /*
72726f9a767SRodney W. Grimes  * swap_pager_getmulti can get multiple pages.
72826f9a767SRodney W. Grimes  */
72926f9a767SRodney W. Grimes int
73026f9a767SRodney W. Grimes swap_pager_getmulti(pager, m, count, reqpage, sync)
731df8bae1dSRodney W. Grimes 	vm_pager_t pager;
73226f9a767SRodney W. Grimes 	vm_page_t *m;
73326f9a767SRodney W. Grimes 	int count;
73426f9a767SRodney W. Grimes 	int reqpage;
735df8bae1dSRodney W. Grimes 	boolean_t sync;
736df8bae1dSRodney W. Grimes {
73726f9a767SRodney W. Grimes 	if( reqpage >= count)
73826f9a767SRodney W. Grimes 		panic("swap_pager_getmulti: reqpage >= count\n");
73926f9a767SRodney W. Grimes 	return swap_pager_input((sw_pager_t) pager->pg_data, m, count, reqpage);
740df8bae1dSRodney W. Grimes }
741df8bae1dSRodney W. Grimes 
74226f9a767SRodney W. Grimes /*
74326f9a767SRodney W. Grimes  * swap_pager_getpage gets individual pages
74426f9a767SRodney W. Grimes  */
74526f9a767SRodney W. Grimes int
74626f9a767SRodney W. Grimes swap_pager_getpage(pager, m, sync)
747df8bae1dSRodney W. Grimes 	vm_pager_t pager;
74826f9a767SRodney W. Grimes 	vm_page_t m;
749df8bae1dSRodney W. Grimes 	boolean_t sync;
750df8bae1dSRodney W. Grimes {
75126f9a767SRodney W. Grimes 	vm_page_t marray[1];
75226f9a767SRodney W. Grimes 
75326f9a767SRodney W. Grimes 	marray[0] = m;
75426f9a767SRodney W. Grimes 	return swap_pager_input((sw_pager_t)pager->pg_data, marray, 1, 0);
75526f9a767SRodney W. Grimes }
75626f9a767SRodney W. Grimes 
75726f9a767SRodney W. Grimes int
75826f9a767SRodney W. Grimes swap_pager_putmulti(pager, m, c, sync, rtvals)
75926f9a767SRodney W. Grimes 	vm_pager_t pager;
76026f9a767SRodney W. Grimes 	vm_page_t *m;
76126f9a767SRodney W. Grimes 	int c;
76226f9a767SRodney W. Grimes 	boolean_t sync;
76326f9a767SRodney W. Grimes 	int *rtvals;
76426f9a767SRodney W. Grimes {
765df8bae1dSRodney W. Grimes 	int flags;
766df8bae1dSRodney W. Grimes 
767df8bae1dSRodney W. Grimes 	if (pager == NULL) {
76826f9a767SRodney W. Grimes 		(void) swap_pager_clean();
76926f9a767SRodney W. Grimes 		return VM_PAGER_OK;
770df8bae1dSRodney W. Grimes 	}
77126f9a767SRodney W. Grimes 
772df8bae1dSRodney W. Grimes 	flags = B_WRITE;
773df8bae1dSRodney W. Grimes 	if (!sync)
774df8bae1dSRodney W. Grimes 		flags |= B_ASYNC;
77526f9a767SRodney W. Grimes 
77626f9a767SRodney W. Grimes 	return swap_pager_output((sw_pager_t)pager->pg_data, m, c, flags, rtvals);
777df8bae1dSRodney W. Grimes }
778df8bae1dSRodney W. Grimes 
77926f9a767SRodney W. Grimes /*
78026f9a767SRodney W. Grimes  * swap_pager_putpage writes individual pages
78126f9a767SRodney W. Grimes  */
78226f9a767SRodney W. Grimes int
78326f9a767SRodney W. Grimes swap_pager_putpage(pager, m, sync)
78426f9a767SRodney W. Grimes 	vm_pager_t pager;
78526f9a767SRodney W. Grimes 	vm_page_t m;
78626f9a767SRodney W. Grimes 	boolean_t sync;
78726f9a767SRodney W. Grimes {
78826f9a767SRodney W. Grimes 	int flags;
78926f9a767SRodney W. Grimes 	vm_page_t marray[1];
79026f9a767SRodney W. Grimes 	int rtvals[1];
79126f9a767SRodney W. Grimes 
79226f9a767SRodney W. Grimes 
79326f9a767SRodney W. Grimes 	if (pager == NULL) {
79426f9a767SRodney W. Grimes 		(void) swap_pager_clean();
79526f9a767SRodney W. Grimes 		return VM_PAGER_OK;
79626f9a767SRodney W. Grimes 	}
79726f9a767SRodney W. Grimes 
79826f9a767SRodney W. Grimes 	marray[0] = m;
79926f9a767SRodney W. Grimes 	flags = B_WRITE;
80026f9a767SRodney W. Grimes 	if (!sync)
80126f9a767SRodney W. Grimes 		flags |= B_ASYNC;
80226f9a767SRodney W. Grimes 
80326f9a767SRodney W. Grimes 	swap_pager_output((sw_pager_t)pager->pg_data, marray, 1, flags, rtvals);
80426f9a767SRodney W. Grimes 
80526f9a767SRodney W. Grimes 	return rtvals[0];
80626f9a767SRodney W. Grimes }
80726f9a767SRodney W. Grimes 
80826f9a767SRodney W. Grimes static inline int
80926f9a767SRodney W. Grimes const swap_pager_block_index(swp, offset)
81026f9a767SRodney W. Grimes 	sw_pager_t swp;
81126f9a767SRodney W. Grimes 	vm_offset_t offset;
81226f9a767SRodney W. Grimes {
81326f9a767SRodney W. Grimes 	return (offset / (SWB_NPAGES*PAGE_SIZE));
81426f9a767SRodney W. Grimes }
81526f9a767SRodney W. Grimes 
81626f9a767SRodney W. Grimes static inline int
81726f9a767SRodney W. Grimes const swap_pager_block_offset(swp, offset)
81826f9a767SRodney W. Grimes 	sw_pager_t swp;
81926f9a767SRodney W. Grimes 	vm_offset_t offset;
82026f9a767SRodney W. Grimes {
82126f9a767SRodney W. Grimes 	return ((offset % (PAGE_SIZE*SWB_NPAGES)) / PAGE_SIZE);
82226f9a767SRodney W. Grimes }
82326f9a767SRodney W. Grimes 
82426f9a767SRodney W. Grimes /*
82526f9a767SRodney W. Grimes  * _swap_pager_haspage returns TRUE if the pager has data that has
82626f9a767SRodney W. Grimes  * been written out.
82726f9a767SRodney W. Grimes  */
828df8bae1dSRodney W. Grimes static boolean_t
82926f9a767SRodney W. Grimes _swap_pager_haspage(swp, offset)
83026f9a767SRodney W. Grimes 	sw_pager_t swp;
83126f9a767SRodney W. Grimes 	vm_offset_t offset;
83226f9a767SRodney W. Grimes {
83326f9a767SRodney W. Grimes 	register sw_blk_t swb;
83426f9a767SRodney W. Grimes 	int ix;
83526f9a767SRodney W. Grimes 
83626f9a767SRodney W. Grimes 	ix = offset / (SWB_NPAGES*PAGE_SIZE);
83726f9a767SRodney W. Grimes 	if (swp->sw_blocks == NULL || ix >= swp->sw_nblocks) {
83826f9a767SRodney W. Grimes 		return(FALSE);
83926f9a767SRodney W. Grimes 	}
84026f9a767SRodney W. Grimes 	swb = &swp->sw_blocks[ix];
84126f9a767SRodney W. Grimes 	ix = (offset % (SWB_NPAGES*PAGE_SIZE)) / PAGE_SIZE;
84226f9a767SRodney W. Grimes 	if (swb->swb_block[ix] != SWB_EMPTY) {
84326f9a767SRodney W. Grimes 		if (swb->swb_valid & (1 << ix))
84426f9a767SRodney W. Grimes 			return TRUE;
84526f9a767SRodney W. Grimes 	}
84626f9a767SRodney W. Grimes 
84726f9a767SRodney W. Grimes 	return(FALSE);
84826f9a767SRodney W. Grimes }
84926f9a767SRodney W. Grimes 
85026f9a767SRodney W. Grimes /*
85126f9a767SRodney W. Grimes  * swap_pager_haspage is the externally accessible version of
85226f9a767SRodney W. Grimes  * _swap_pager_haspage above.  this routine takes a vm_pager_t
85326f9a767SRodney W. Grimes  * for an argument instead of sw_pager_t.
85426f9a767SRodney W. Grimes  */
85526f9a767SRodney W. Grimes boolean_t
856df8bae1dSRodney W. Grimes swap_pager_haspage(pager, offset)
857df8bae1dSRodney W. Grimes 	vm_pager_t pager;
858df8bae1dSRodney W. Grimes 	vm_offset_t offset;
859df8bae1dSRodney W. Grimes {
86026f9a767SRodney W. Grimes 	return _swap_pager_haspage((sw_pager_t) pager->pg_data, offset);
861df8bae1dSRodney W. Grimes }
862df8bae1dSRodney W. Grimes 
863df8bae1dSRodney W. Grimes /*
86426f9a767SRodney W. Grimes  * swap_pager_freepage is a convienience routine that clears the busy
86526f9a767SRodney W. Grimes  * bit and deallocates a page.
866df8bae1dSRodney W. Grimes  */
86726f9a767SRodney W. Grimes static void
86826f9a767SRodney W. Grimes swap_pager_freepage(m)
86926f9a767SRodney W. Grimes 	vm_page_t m;
87026f9a767SRodney W. Grimes {
87126f9a767SRodney W. Grimes 	PAGE_WAKEUP(m);
87226f9a767SRodney W. Grimes 	vm_page_free(m);
87326f9a767SRodney W. Grimes }
87426f9a767SRodney W. Grimes 
87526f9a767SRodney W. Grimes /*
87626f9a767SRodney W. Grimes  * swap_pager_ridpages is a convienience routine that deallocates all
87726f9a767SRodney W. Grimes  * but the required page.  this is usually used in error returns that
87826f9a767SRodney W. Grimes  * need to invalidate the "extra" readahead pages.
87926f9a767SRodney W. Grimes  */
88026f9a767SRodney W. Grimes static void
88126f9a767SRodney W. Grimes swap_pager_ridpages(m, count, reqpage)
88226f9a767SRodney W. Grimes 	vm_page_t *m;
88326f9a767SRodney W. Grimes 	int count;
88426f9a767SRodney W. Grimes 	int reqpage;
88526f9a767SRodney W. Grimes {
88626f9a767SRodney W. Grimes 	int i;
88726f9a767SRodney W. Grimes 	for (i = 0; i < count; i++)
88826f9a767SRodney W. Grimes 		if (i != reqpage)
88926f9a767SRodney W. Grimes 			swap_pager_freepage(m[i]);
89026f9a767SRodney W. Grimes }
89126f9a767SRodney W. Grimes 
89226f9a767SRodney W. Grimes int swapwritecount=0;
89326f9a767SRodney W. Grimes 
89426f9a767SRodney W. Grimes /*
89526f9a767SRodney W. Grimes  * swap_pager_iodone1 is the completion routine for both reads and async writes
89626f9a767SRodney W. Grimes  */
89726f9a767SRodney W. Grimes void
89826f9a767SRodney W. Grimes swap_pager_iodone1(bp)
89926f9a767SRodney W. Grimes 	struct buf *bp;
90026f9a767SRodney W. Grimes {
90126f9a767SRodney W. Grimes 	bp->b_flags |= B_DONE;
90226f9a767SRodney W. Grimes 	bp->b_flags &= ~B_ASYNC;
90326f9a767SRodney W. Grimes 	wakeup((caddr_t)bp);
90426f9a767SRodney W. Grimes /*
90526f9a767SRodney W. Grimes 	if ((bp->b_flags & B_READ) == 0)
90626f9a767SRodney W. Grimes 		vwakeup(bp);
90726f9a767SRodney W. Grimes */
90826f9a767SRodney W. Grimes }
90926f9a767SRodney W. Grimes 
91026f9a767SRodney W. Grimes 
91126f9a767SRodney W. Grimes int
91226f9a767SRodney W. Grimes swap_pager_input(swp, m, count, reqpage)
913df8bae1dSRodney W. Grimes 	register sw_pager_t swp;
91426f9a767SRodney W. Grimes 	vm_page_t *m;
91526f9a767SRodney W. Grimes 	int count, reqpage;
916df8bae1dSRodney W. Grimes {
917df8bae1dSRodney W. Grimes 	register struct buf *bp;
91826f9a767SRodney W. Grimes 	sw_blk_t swb[count];
919df8bae1dSRodney W. Grimes 	register int s;
92026f9a767SRodney W. Grimes 	int i;
921df8bae1dSRodney W. Grimes 	boolean_t rv;
92226f9a767SRodney W. Grimes 	vm_offset_t kva, off[count];
923df8bae1dSRodney W. Grimes 	swp_clean_t spc;
92426f9a767SRodney W. Grimes 	vm_offset_t paging_offset;
92526f9a767SRodney W. Grimes 	vm_object_t object;
92626f9a767SRodney W. Grimes 	int reqaddr[count];
927df8bae1dSRodney W. Grimes 
92826f9a767SRodney W. Grimes 	int first, last;
92926f9a767SRodney W. Grimes 	int failed;
93026f9a767SRodney W. Grimes 	int reqdskregion;
931df8bae1dSRodney W. Grimes 
93226f9a767SRodney W. Grimes 	object = m[reqpage]->object;
93326f9a767SRodney W. Grimes 	paging_offset = object->paging_offset;
934df8bae1dSRodney W. Grimes 	/*
935df8bae1dSRodney W. Grimes 	 * First determine if the page exists in the pager if this is
936df8bae1dSRodney W. Grimes 	 * a sync read.  This quickly handles cases where we are
937df8bae1dSRodney W. Grimes 	 * following shadow chains looking for the top level object
938df8bae1dSRodney W. Grimes 	 * with the page.
939df8bae1dSRodney W. Grimes 	 */
94026f9a767SRodney W. Grimes 	if (swp->sw_blocks == NULL) {
94126f9a767SRodney W. Grimes 		swap_pager_ridpages(m, count, reqpage);
942df8bae1dSRodney W. Grimes 		return(VM_PAGER_FAIL);
943df8bae1dSRodney W. Grimes 	}
94426f9a767SRodney W. Grimes 
94526f9a767SRodney W. Grimes 	for(i = 0; i < count; i++) {
94626f9a767SRodney W. Grimes 		vm_offset_t foff = m[i]->offset + paging_offset;
94726f9a767SRodney W. Grimes 		int ix = swap_pager_block_index(swp, foff);
94826f9a767SRodney W. Grimes 		if (ix >= swp->sw_nblocks) {
94926f9a767SRodney W. Grimes 			int j;
95026f9a767SRodney W. Grimes 			if( i <= reqpage) {
95126f9a767SRodney W. Grimes 				swap_pager_ridpages(m, count, reqpage);
952df8bae1dSRodney W. Grimes 				return(VM_PAGER_FAIL);
95326f9a767SRodney W. Grimes 			}
95426f9a767SRodney W. Grimes 			for(j = i; j < count; j++) {
95526f9a767SRodney W. Grimes 				swap_pager_freepage(m[j]);
95626f9a767SRodney W. Grimes 			}
95726f9a767SRodney W. Grimes 			count = i;
95826f9a767SRodney W. Grimes 			break;
95926f9a767SRodney W. Grimes 		}
96026f9a767SRodney W. Grimes 
96126f9a767SRodney W. Grimes 		swb[i] = &swp->sw_blocks[ix];
96226f9a767SRodney W. Grimes 		off[i] = swap_pager_block_offset(swp, foff);
96326f9a767SRodney W. Grimes 		reqaddr[i] = swb[i]->swb_block[off[i]];
96426f9a767SRodney W. Grimes 	}
96526f9a767SRodney W. Grimes 
96626f9a767SRodney W. Grimes 	/* make sure that our required input request is existant */
96726f9a767SRodney W. Grimes 
96826f9a767SRodney W. Grimes 	if (reqaddr[reqpage] == SWB_EMPTY ||
96926f9a767SRodney W. Grimes 		(swb[reqpage]->swb_valid & (1 << off[reqpage])) == 0) {
97026f9a767SRodney W. Grimes 		swap_pager_ridpages(m, count, reqpage);
97126f9a767SRodney W. Grimes 		return(VM_PAGER_FAIL);
97226f9a767SRodney W. Grimes 	}
97326f9a767SRodney W. Grimes 
97426f9a767SRodney W. Grimes 
97526f9a767SRodney W. Grimes 	reqdskregion = reqaddr[reqpage] / dmmax;
976df8bae1dSRodney W. Grimes 
977df8bae1dSRodney W. Grimes 	/*
97826f9a767SRodney W. Grimes 	 * search backwards for the first contiguous page to transfer
979df8bae1dSRodney W. Grimes 	 */
98026f9a767SRodney W. Grimes 	failed = 0;
98126f9a767SRodney W. Grimes 	first = 0;
98226f9a767SRodney W. Grimes 	for (i = reqpage - 1; i >= 0; --i) {
98326f9a767SRodney W. Grimes 		if ( failed || (reqaddr[i] == SWB_EMPTY) ||
98426f9a767SRodney W. Grimes 			(swb[i]->swb_valid & (1 << off[i])) == 0 ||
98526f9a767SRodney W. Grimes 			(reqaddr[i] != (reqaddr[reqpage] + (i - reqpage) * btodb(PAGE_SIZE))) ||
98626f9a767SRodney W. Grimes 			((reqaddr[i] / dmmax) != reqdskregion)) {
98726f9a767SRodney W. Grimes 				failed = 1;
98826f9a767SRodney W. Grimes 				swap_pager_freepage(m[i]);
98926f9a767SRodney W. Grimes 				if (first == 0)
99026f9a767SRodney W. Grimes 					first = i + 1;
99126f9a767SRodney W. Grimes 		}
992df8bae1dSRodney W. Grimes 	}
993df8bae1dSRodney W. Grimes 	/*
99426f9a767SRodney W. Grimes 	 * search forwards for the last contiguous page to transfer
995df8bae1dSRodney W. Grimes 	 */
99626f9a767SRodney W. Grimes 	failed = 0;
99726f9a767SRodney W. Grimes 	last = count;
99826f9a767SRodney W. Grimes 	for (i = reqpage + 1; i < count; i++) {
99926f9a767SRodney W. Grimes 		if ( failed || (reqaddr[i] == SWB_EMPTY) ||
100026f9a767SRodney W. Grimes 			(swb[i]->swb_valid & (1 << off[i])) == 0 ||
100126f9a767SRodney W. Grimes 			(reqaddr[i] != (reqaddr[reqpage] + (i - reqpage) * btodb(PAGE_SIZE))) ||
100226f9a767SRodney W. Grimes 			((reqaddr[i] / dmmax) != reqdskregion)) {
100326f9a767SRodney W. Grimes 				failed = 1;
100426f9a767SRodney W. Grimes 				swap_pager_freepage(m[i]);
100526f9a767SRodney W. Grimes 				if (last == count)
100626f9a767SRodney W. Grimes 					last = i;
100726f9a767SRodney W. Grimes 		}
100826f9a767SRodney W. Grimes 	}
100926f9a767SRodney W. Grimes 
101026f9a767SRodney W. Grimes 	count = last;
101126f9a767SRodney W. Grimes 	if (first != 0) {
101226f9a767SRodney W. Grimes 		for (i = first; i < count; i++) {
101326f9a767SRodney W. Grimes 			m[i-first] = m[i];
101426f9a767SRodney W. Grimes 			reqaddr[i-first] = reqaddr[i];
101526f9a767SRodney W. Grimes 			off[i-first] = off[i];
101626f9a767SRodney W. Grimes 		}
101726f9a767SRodney W. Grimes 		count -= first;
101826f9a767SRodney W. Grimes 		reqpage -= first;
101926f9a767SRodney W. Grimes 	}
102026f9a767SRodney W. Grimes 
102126f9a767SRodney W. Grimes 	++swb[reqpage]->swb_locked;
102226f9a767SRodney W. Grimes 
102326f9a767SRodney W. Grimes 	/*
102426f9a767SRodney W. Grimes 	 * at this point:
102526f9a767SRodney W. Grimes 	 * "m" is a pointer to the array of vm_page_t for paging I/O
102626f9a767SRodney W. Grimes 	 * "count" is the number of vm_page_t entries represented by "m"
102726f9a767SRodney W. Grimes 	 * "object" is the vm_object_t for I/O
102826f9a767SRodney W. Grimes 	 * "reqpage" is the index into "m" for the page actually faulted
102926f9a767SRodney W. Grimes 	 */
103026f9a767SRodney W. Grimes 
103126f9a767SRodney W. Grimes 	spc = NULL;	/* we might not use an spc data structure */
103226f9a767SRodney W. Grimes 	kva = 0;
103326f9a767SRodney W. Grimes 
103426f9a767SRodney W. Grimes 	/*
103526f9a767SRodney W. Grimes 	 * we allocate a new kva for transfers > 1 page
103626f9a767SRodney W. Grimes 	 * but for transfers == 1 page, the swap_pager_free list contains
103726f9a767SRodney W. Grimes 	 * entries that have pre-allocated kva's (for efficiency).
103826f9a767SRodney W. Grimes 	 */
103926f9a767SRodney W. Grimes 	if (count > 1) {
104026f9a767SRodney W. Grimes 		kva = kmem_alloc_pageable(pager_map, count*PAGE_SIZE);
104126f9a767SRodney W. Grimes 	}
104226f9a767SRodney W. Grimes 
104326f9a767SRodney W. Grimes 
104426f9a767SRodney W. Grimes 	if (!kva) {
104526f9a767SRodney W. Grimes 		/*
104626f9a767SRodney W. Grimes 		 * if a kva has not been allocated, we can only do a one page transfer,
104726f9a767SRodney W. Grimes 		 * so we free the other pages that might have been allocated by
104826f9a767SRodney W. Grimes 		 * vm_fault.
104926f9a767SRodney W. Grimes 		 */
105026f9a767SRodney W. Grimes 		swap_pager_ridpages(m, count, reqpage);
105126f9a767SRodney W. Grimes 		m[0] = m[reqpage];
105226f9a767SRodney W. Grimes 		reqaddr[0] = reqaddr[reqpage];
105326f9a767SRodney W. Grimes 
105426f9a767SRodney W. Grimes 		count = 1;
105526f9a767SRodney W. Grimes 		reqpage = 0;
105626f9a767SRodney W. Grimes 	/*
105726f9a767SRodney W. Grimes 	 * get a swap pager clean data structure, block until we get it
105826f9a767SRodney W. Grimes 	 */
1059df8bae1dSRodney W. Grimes 		if (swap_pager_free.tqh_first == NULL) {
1060df8bae1dSRodney W. Grimes 			s = splbio();
106126f9a767SRodney W. Grimes 			if( curproc == pageproc)
106226f9a767SRodney W. Grimes 				(void) swap_pager_clean();
106326f9a767SRodney W. Grimes 			else
106426f9a767SRodney W. Grimes 				wakeup((caddr_t) &vm_pages_needed);
106526f9a767SRodney W. Grimes 			while (swap_pager_free.tqh_first == NULL) {
106626f9a767SRodney W. Grimes 				swap_pager_needflags |= SWAP_FREE_NEEDED;
106726f9a767SRodney W. Grimes 				tsleep((caddr_t)&swap_pager_free,
106826f9a767SRodney W. Grimes 					PVM, "swpfre", 0);
106926f9a767SRodney W. Grimes 				if( curproc == pageproc)
107026f9a767SRodney W. Grimes 					(void) swap_pager_clean();
107126f9a767SRodney W. Grimes 				else
107226f9a767SRodney W. Grimes 					wakeup((caddr_t) &vm_pages_needed);
1073df8bae1dSRodney W. Grimes 			}
1074df8bae1dSRodney W. Grimes 			splx(s);
107526f9a767SRodney W. Grimes 		}
107626f9a767SRodney W. Grimes 		spc = swap_pager_free.tqh_first;
107726f9a767SRodney W. Grimes 		TAILQ_REMOVE(&swap_pager_free, spc, spc_list);
107826f9a767SRodney W. Grimes 		kva = spc->spc_kva;
107926f9a767SRodney W. Grimes 	}
108026f9a767SRodney W. Grimes 
108126f9a767SRodney W. Grimes 
108226f9a767SRodney W. Grimes 	/*
108326f9a767SRodney W. Grimes 	 * map our page(s) into kva for input
108426f9a767SRodney W. Grimes 	 */
108526f9a767SRodney W. Grimes 	for (i = 0; i < count; i++) {
108626f9a767SRodney W. Grimes 		pmap_kenter( kva + PAGE_SIZE * i, VM_PAGE_TO_PHYS(m[i]));
108726f9a767SRodney W. Grimes 	}
108826f9a767SRodney W. Grimes 	pmap_update();
108926f9a767SRodney W. Grimes 
109026f9a767SRodney W. Grimes 
109126f9a767SRodney W. Grimes 	/*
109226f9a767SRodney W. Grimes 	 * Get a swap buffer header and perform the IO
109326f9a767SRodney W. Grimes 	 */
109426f9a767SRodney W. Grimes 	if( spc) {
109526f9a767SRodney W. Grimes 		bp = spc->spc_bp;
109626f9a767SRodney W. Grimes 		bzero(bp, sizeof *bp);
109726f9a767SRodney W. Grimes 		bp->b_spc = spc;
109826f9a767SRodney W. Grimes 	} else {
109926f9a767SRodney W. Grimes 		bp = getpbuf();
110026f9a767SRodney W. Grimes 	}
110126f9a767SRodney W. Grimes 
110226f9a767SRodney W. Grimes 	s = splbio();
110326f9a767SRodney W. Grimes 	bp->b_flags = B_BUSY | B_READ | B_CALL;
110426f9a767SRodney W. Grimes 	bp->b_iodone = swap_pager_iodone1;
1105df8bae1dSRodney W. Grimes 	bp->b_proc = &proc0;	/* XXX (but without B_PHYS set this is ok) */
110626f9a767SRodney W. Grimes 	bp->b_rcred = bp->b_wcred = bp->b_proc->p_ucred;
110726f9a767SRodney W. Grimes 	crhold(bp->b_rcred);
110826f9a767SRodney W. Grimes 	crhold(bp->b_wcred);
110926f9a767SRodney W. Grimes 	bp->b_un.b_addr = (caddr_t) kva;
111026f9a767SRodney W. Grimes 	bp->b_blkno = reqaddr[0];
111126f9a767SRodney W. Grimes 	bp->b_bcount = PAGE_SIZE*count;
111226f9a767SRodney W. Grimes 	bp->b_bufsize = PAGE_SIZE*count;
111326f9a767SRodney W. Grimes 
111426f9a767SRodney W. Grimes /*
1115df8bae1dSRodney W. Grimes 	VHOLD(swapdev_vp);
1116df8bae1dSRodney W. Grimes 	bp->b_vp = swapdev_vp;
1117df8bae1dSRodney W. Grimes 	if (swapdev_vp->v_type == VBLK)
1118df8bae1dSRodney W. Grimes 		bp->b_dev = swapdev_vp->v_rdev;
111926f9a767SRodney W. Grimes */
112026f9a767SRodney W. Grimes 	bgetvp( swapdev_vp, bp);
112126f9a767SRodney W. Grimes 
112226f9a767SRodney W. Grimes 	swp->sw_piip++;
1123df8bae1dSRodney W. Grimes 
1124df8bae1dSRodney W. Grimes 	/*
112526f9a767SRodney W. Grimes 	 * perform the I/O
1126df8bae1dSRodney W. Grimes 	 */
1127df8bae1dSRodney W. Grimes 	VOP_STRATEGY(bp);
112826f9a767SRodney W. Grimes 
112926f9a767SRodney W. Grimes 	/*
113026f9a767SRodney W. Grimes 	 * wait for the sync I/O to complete
113126f9a767SRodney W. Grimes 	 */
113226f9a767SRodney W. Grimes 	while ((bp->b_flags & B_DONE) == 0) {
113326f9a767SRodney W. Grimes 		tsleep((caddr_t)bp, PVM, "swread", 0);
1134df8bae1dSRodney W. Grimes 	}
113526f9a767SRodney W. Grimes 	rv = (bp->b_flags & B_ERROR) ? VM_PAGER_FAIL : VM_PAGER_OK;
113626f9a767SRodney W. Grimes 	bp->b_flags &= ~(B_BUSY|B_WANTED|B_PHYS|B_DIRTY|B_CALL|B_DONE);
113726f9a767SRodney W. Grimes 
113826f9a767SRodney W. Grimes 	--swp->sw_piip;
113926f9a767SRodney W. Grimes 	if (swp->sw_piip == 0)
114026f9a767SRodney W. Grimes 		wakeup((caddr_t) swp);
114126f9a767SRodney W. Grimes 
114226f9a767SRodney W. Grimes 	/*
114326f9a767SRodney W. Grimes 	 * relpbuf does this, but we maintain our own buffer
114426f9a767SRodney W. Grimes 	 * list also...
114526f9a767SRodney W. Grimes 	 */
1146df8bae1dSRodney W. Grimes 	if (bp->b_vp)
1147df8bae1dSRodney W. Grimes 		brelvp(bp);
114826f9a767SRodney W. Grimes 
1149df8bae1dSRodney W. Grimes 	splx(s);
115026f9a767SRodney W. Grimes 	--swb[reqpage]->swb_locked;
115126f9a767SRodney W. Grimes 
115226f9a767SRodney W. Grimes 	/*
115326f9a767SRodney W. Grimes 	 * remove the mapping for kernel virtual
115426f9a767SRodney W. Grimes 	 */
115526f9a767SRodney W. Grimes 	pmap_remove(vm_map_pmap(pager_map), kva, kva + count * PAGE_SIZE);
115626f9a767SRodney W. Grimes 
115726f9a767SRodney W. Grimes 	if (spc) {
115826f9a767SRodney W. Grimes 		/*
115926f9a767SRodney W. Grimes 		 * if we have used an spc, we need to free it.
116026f9a767SRodney W. Grimes 		 */
116126f9a767SRodney W. Grimes 		if( bp->b_rcred != NOCRED)
116226f9a767SRodney W. Grimes 			crfree(bp->b_rcred);
116326f9a767SRodney W. Grimes 		if( bp->b_wcred != NOCRED)
116426f9a767SRodney W. Grimes 			crfree(bp->b_wcred);
116526f9a767SRodney W. Grimes 		TAILQ_INSERT_TAIL(&swap_pager_free, spc, spc_list);
116626f9a767SRodney W. Grimes 		if (swap_pager_needflags & SWAP_FREE_NEEDED) {
116726f9a767SRodney W. Grimes 			swap_pager_needflags &= ~SWAP_FREE_NEEDED;
116826f9a767SRodney W. Grimes 			wakeup((caddr_t)&swap_pager_free);
116926f9a767SRodney W. Grimes 		}
117026f9a767SRodney W. Grimes 	} else {
117126f9a767SRodney W. Grimes 		/*
117226f9a767SRodney W. Grimes 		 * free the kernel virtual addresses
117326f9a767SRodney W. Grimes 		 */
117426f9a767SRodney W. Grimes 		kmem_free_wakeup(pager_map, kva, count * PAGE_SIZE);
117526f9a767SRodney W. Grimes 		/*
117626f9a767SRodney W. Grimes 		 * release the physical I/O buffer
117726f9a767SRodney W. Grimes 		 */
117826f9a767SRodney W. Grimes 		relpbuf(bp);
117926f9a767SRodney W. Grimes 		/*
118026f9a767SRodney W. Grimes 		 * finish up input if everything is ok
118126f9a767SRodney W. Grimes 		 */
118226f9a767SRodney W. Grimes 		if( rv == VM_PAGER_OK) {
118326f9a767SRodney W. Grimes 			for (i = 0; i < count; i++) {
118426f9a767SRodney W. Grimes 				pmap_clear_modify(VM_PAGE_TO_PHYS(m[i]));
118526f9a767SRodney W. Grimes 				m[i]->flags |= PG_CLEAN;
118626f9a767SRodney W. Grimes 				m[i]->flags &= ~PG_LAUNDRY;
118726f9a767SRodney W. Grimes 				if (i != reqpage) {
118826f9a767SRodney W. Grimes 					/*
118926f9a767SRodney W. Grimes 					 * whether or not to leave the page activated
119026f9a767SRodney W. Grimes 					 * is up in the air, but we should put the page
119126f9a767SRodney W. Grimes 					 * on a page queue somewhere. (it already is in
119226f9a767SRodney W. Grimes 					 * the object).
119326f9a767SRodney W. Grimes 					 * After some emperical results, it is best
119426f9a767SRodney W. Grimes 					 * to deactivate the readahead pages.
119526f9a767SRodney W. Grimes 					 */
119626f9a767SRodney W. Grimes 					vm_page_deactivate(m[i]);
119726f9a767SRodney W. Grimes 					m[i]->act_count = 2;
119826f9a767SRodney W. Grimes 
119926f9a767SRodney W. Grimes 					/*
120026f9a767SRodney W. Grimes 					 * just in case someone was asking for this
120126f9a767SRodney W. Grimes 					 * page we now tell them that it is ok to use
120226f9a767SRodney W. Grimes 					 */
120326f9a767SRodney W. Grimes 					m[i]->flags &= ~PG_FAKE;
120426f9a767SRodney W. Grimes 					PAGE_WAKEUP(m[i]);
120526f9a767SRodney W. Grimes 				}
120626f9a767SRodney W. Grimes 			}
120726f9a767SRodney W. Grimes 			if( swap_pager_full) {
120826f9a767SRodney W. Grimes 				_swap_pager_freespace( swp, m[0]->offset+paging_offset, count*PAGE_SIZE);
120926f9a767SRodney W. Grimes 			}
121026f9a767SRodney W. Grimes 		} else {
121126f9a767SRodney W. Grimes 			swap_pager_ridpages(m, count, reqpage);
121226f9a767SRodney W. Grimes 		}
121326f9a767SRodney W. Grimes 	}
1214df8bae1dSRodney W. Grimes 	return(rv);
1215df8bae1dSRodney W. Grimes }
1216df8bae1dSRodney W. Grimes 
121726f9a767SRodney W. Grimes int
121826f9a767SRodney W. Grimes swap_pager_output(swp, m, count, flags, rtvals)
121926f9a767SRodney W. Grimes 	register sw_pager_t swp;
122026f9a767SRodney W. Grimes 	vm_page_t *m;
122126f9a767SRodney W. Grimes 	int count;
122226f9a767SRodney W. Grimes 	int flags;
122326f9a767SRodney W. Grimes 	int *rtvals;
1224df8bae1dSRodney W. Grimes {
122526f9a767SRodney W. Grimes 	register struct buf *bp;
122626f9a767SRodney W. Grimes 	sw_blk_t swb[count];
122726f9a767SRodney W. Grimes 	register int s;
122826f9a767SRodney W. Grimes 	int i, j, ix;
122926f9a767SRodney W. Grimes 	boolean_t rv;
123026f9a767SRodney W. Grimes 	vm_offset_t kva, off, foff;
123126f9a767SRodney W. Grimes 	swp_clean_t spc;
123226f9a767SRodney W. Grimes 	vm_offset_t paging_offset;
1233df8bae1dSRodney W. Grimes 	vm_object_t object;
123426f9a767SRodney W. Grimes 	int reqaddr[count];
123526f9a767SRodney W. Grimes 	int failed;
1236df8bae1dSRodney W. Grimes 
1237df8bae1dSRodney W. Grimes /*
123826f9a767SRodney W. Grimes 	if( count > 1)
123926f9a767SRodney W. Grimes 		printf("off: 0x%x, count: %d\n", m[0]->offset, count);
1240df8bae1dSRodney W. Grimes */
124126f9a767SRodney W. Grimes 	spc = NULL;
124226f9a767SRodney W. Grimes 
124326f9a767SRodney W. Grimes 	object = m[0]->object;
124426f9a767SRodney W. Grimes 	paging_offset = object->paging_offset;
124526f9a767SRodney W. Grimes 
124626f9a767SRodney W. Grimes 	failed = 0;
124726f9a767SRodney W. Grimes 	for(j=0;j<count;j++) {
124826f9a767SRodney W. Grimes 		foff = m[j]->offset + paging_offset;
124926f9a767SRodney W. Grimes 		ix = swap_pager_block_index(swp, foff);
125026f9a767SRodney W. Grimes 		swb[j] = 0;
125126f9a767SRodney W. Grimes 		if( swp->sw_blocks == NULL || ix >= swp->sw_nblocks) {
125226f9a767SRodney W. Grimes 			rtvals[j] = VM_PAGER_FAIL;
125326f9a767SRodney W. Grimes 			failed = 1;
125426f9a767SRodney W. Grimes 			continue;
125526f9a767SRodney W. Grimes 		} else {
125626f9a767SRodney W. Grimes 			rtvals[j] = VM_PAGER_OK;
125726f9a767SRodney W. Grimes 		}
125826f9a767SRodney W. Grimes 		swb[j] = &swp->sw_blocks[ix];
125926f9a767SRodney W. Grimes 		++swb[j]->swb_locked;
126026f9a767SRodney W. Grimes 		if( failed) {
126126f9a767SRodney W. Grimes 			rtvals[j] = VM_PAGER_FAIL;
126226f9a767SRodney W. Grimes 			continue;
126326f9a767SRodney W. Grimes 		}
126426f9a767SRodney W. Grimes 		off = swap_pager_block_offset(swp, foff);
126526f9a767SRodney W. Grimes 		reqaddr[j] = swb[j]->swb_block[off];
126626f9a767SRodney W. Grimes 		if( reqaddr[j] == SWB_EMPTY) {
126726f9a767SRodney W. Grimes 			int blk;
126826f9a767SRodney W. Grimes 			int tries;
126926f9a767SRodney W. Grimes 			int ntoget;
127026f9a767SRodney W. Grimes 			tries = 0;
1271df8bae1dSRodney W. Grimes 			s = splbio();
127226f9a767SRodney W. Grimes 
1273df8bae1dSRodney W. Grimes 			/*
127426f9a767SRodney W. Grimes 			 * if any other pages have been allocated in this block, we
127526f9a767SRodney W. Grimes 			 * only try to get one page.
1276df8bae1dSRodney W. Grimes 			 */
127726f9a767SRodney W. Grimes 			for (i = 0; i < SWB_NPAGES; i++) {
127826f9a767SRodney W. Grimes 				if (swb[j]->swb_block[i] != SWB_EMPTY)
1279df8bae1dSRodney W. Grimes 					break;
1280df8bae1dSRodney W. Grimes 			}
128126f9a767SRodney W. Grimes 
128226f9a767SRodney W. Grimes 
128326f9a767SRodney W. Grimes 			ntoget = (i == SWB_NPAGES) ? SWB_NPAGES : 1;
128426f9a767SRodney W. Grimes 			/*
128526f9a767SRodney W. Grimes 			 * this code is alittle conservative, but works
128626f9a767SRodney W. Grimes 			 * (the intent of this code is to allocate small chunks
128726f9a767SRodney W. Grimes 			 *  for small objects)
128826f9a767SRodney W. Grimes 			 */
128926f9a767SRodney W. Grimes 			if( (m[j]->offset == 0) && (ntoget*PAGE_SIZE > object->size)) {
129026f9a767SRodney W. Grimes 				ntoget = (object->size + (PAGE_SIZE-1))/PAGE_SIZE;
129126f9a767SRodney W. Grimes 			}
129226f9a767SRodney W. Grimes 
129326f9a767SRodney W. Grimes retrygetspace:
129426f9a767SRodney W. Grimes 			if (!swap_pager_full && ntoget > 1 &&
129526f9a767SRodney W. Grimes 				swap_pager_getswapspace(ntoget * btodb(PAGE_SIZE), &blk)) {
129626f9a767SRodney W. Grimes 
129726f9a767SRodney W. Grimes 				for (i = 0; i < ntoget; i++) {
129826f9a767SRodney W. Grimes 					swb[j]->swb_block[i] = blk + btodb(PAGE_SIZE) * i;
129926f9a767SRodney W. Grimes 					swb[j]->swb_valid = 0;
130026f9a767SRodney W. Grimes 				}
130126f9a767SRodney W. Grimes 
130226f9a767SRodney W. Grimes 				reqaddr[j] = swb[j]->swb_block[off];
130326f9a767SRodney W. Grimes 			} else if (!swap_pager_getswapspace(btodb(PAGE_SIZE),
130426f9a767SRodney W. Grimes 				&swb[j]->swb_block[off])) {
130526f9a767SRodney W. Grimes 				/*
130626f9a767SRodney W. Grimes 				 * if the allocation has failed, we try to reclaim space and
130726f9a767SRodney W. Grimes 				 * retry.
130826f9a767SRodney W. Grimes 				 */
130926f9a767SRodney W. Grimes 				if (++tries == 1) {
131026f9a767SRodney W. Grimes 					swap_pager_reclaim();
131126f9a767SRodney W. Grimes 					goto retrygetspace;
131226f9a767SRodney W. Grimes 				}
131326f9a767SRodney W. Grimes 				rtvals[j] = VM_PAGER_AGAIN;
131426f9a767SRodney W. Grimes 				failed = 1;
131526f9a767SRodney W. Grimes 			} else {
131626f9a767SRodney W. Grimes 				reqaddr[j] = swb[j]->swb_block[off];
131726f9a767SRodney W. Grimes 				swb[j]->swb_valid &= ~(1<<off);
1318df8bae1dSRodney W. Grimes 			}
1319df8bae1dSRodney W. Grimes 			splx(s);
132026f9a767SRodney W. Grimes 		}
132126f9a767SRodney W. Grimes 	}
132226f9a767SRodney W. Grimes 
132326f9a767SRodney W. Grimes 	/*
132426f9a767SRodney W. Grimes 	 * search forwards for the last contiguous page to transfer
132526f9a767SRodney W. Grimes 	 */
132626f9a767SRodney W. Grimes 	failed = 0;
132726f9a767SRodney W. Grimes 	for (i = 0; i < count; i++) {
132826f9a767SRodney W. Grimes 		if( failed || (reqaddr[i] != reqaddr[0] + i*btodb(PAGE_SIZE)) ||
132926f9a767SRodney W. Grimes 			(reqaddr[i] / dmmax) != (reqaddr[0] / dmmax) ||
133026f9a767SRodney W. Grimes 			(rtvals[i] != VM_PAGER_OK)) {
133126f9a767SRodney W. Grimes 			failed = 1;
133226f9a767SRodney W. Grimes 			if( rtvals[i] == VM_PAGER_OK)
133326f9a767SRodney W. Grimes 				rtvals[i] = VM_PAGER_AGAIN;
133426f9a767SRodney W. Grimes 		}
133526f9a767SRodney W. Grimes 	}
133626f9a767SRodney W. Grimes 
133726f9a767SRodney W. Grimes 	for(i = 0; i < count; i++) {
133826f9a767SRodney W. Grimes 		if( rtvals[i] != VM_PAGER_OK) {
133926f9a767SRodney W. Grimes 			if( swb[i])
134026f9a767SRodney W. Grimes 				--swb[i]->swb_locked;
134126f9a767SRodney W. Grimes 		}
134226f9a767SRodney W. Grimes 	}
134326f9a767SRodney W. Grimes 
134426f9a767SRodney W. Grimes 	for(i = 0; i < count; i++)
134526f9a767SRodney W. Grimes 		if( rtvals[i] != VM_PAGER_OK)
134626f9a767SRodney W. Grimes 			break;
134726f9a767SRodney W. Grimes 
134826f9a767SRodney W. Grimes 	if( i == 0) {
134926f9a767SRodney W. Grimes 		return VM_PAGER_AGAIN;
135026f9a767SRodney W. Grimes 	}
135126f9a767SRodney W. Grimes 
135226f9a767SRodney W. Grimes 	count = i;
135326f9a767SRodney W. Grimes 	for(i=0;i<count;i++) {
135426f9a767SRodney W. Grimes 		if( reqaddr[i] == SWB_EMPTY)
135526f9a767SRodney W. Grimes 			printf("I/O to empty block????\n");
135626f9a767SRodney W. Grimes 	}
135726f9a767SRodney W. Grimes 
135826f9a767SRodney W. Grimes 	/*
135926f9a767SRodney W. Grimes 	 */
136026f9a767SRodney W. Grimes 
136126f9a767SRodney W. Grimes 	/*
136226f9a767SRodney W. Grimes 	 * For synchronous writes, we clean up
136326f9a767SRodney W. Grimes 	 * all completed async pageouts.
136426f9a767SRodney W. Grimes 	 */
136526f9a767SRodney W. Grimes 	if ((flags & B_ASYNC) == 0) {
136626f9a767SRodney W. Grimes 		swap_pager_clean();
136726f9a767SRodney W. Grimes 	}
136826f9a767SRodney W. Grimes 
136926f9a767SRodney W. Grimes 	kva = 0;
137026f9a767SRodney W. Grimes 
137126f9a767SRodney W. Grimes 	/*
137226f9a767SRodney W. Grimes 	 * we allocate a new kva for transfers > 1 page
137326f9a767SRodney W. Grimes 	 * but for transfers == 1 page, the swap_pager_free list contains
137426f9a767SRodney W. Grimes 	 * entries that have pre-allocated kva's (for efficiency).
137526f9a767SRodney W. Grimes 	 */
137626f9a767SRodney W. Grimes 	if ( count > 1) {
137726f9a767SRodney W. Grimes 		kva = kmem_alloc_pageable(pager_map, count*PAGE_SIZE);
137826f9a767SRodney W. Grimes 		if( !kva) {
137926f9a767SRodney W. Grimes 			for (i = 0; i < count; i++) {
138026f9a767SRodney W. Grimes 				if( swb[i])
138126f9a767SRodney W. Grimes 					--swb[i]->swb_locked;
138226f9a767SRodney W. Grimes 				rtvals[i] = VM_PAGER_AGAIN;
138326f9a767SRodney W. Grimes 			}
138426f9a767SRodney W. Grimes 			return VM_PAGER_AGAIN;
138526f9a767SRodney W. Grimes 		}
138626f9a767SRodney W. Grimes 	}
138726f9a767SRodney W. Grimes 
138826f9a767SRodney W. Grimes 	/*
138926f9a767SRodney W. Grimes 	 * get a swap pager clean data structure, block until we get it
139026f9a767SRodney W. Grimes 	 */
139126f9a767SRodney W. Grimes 	if (swap_pager_free.tqh_first == NULL) {
139226f9a767SRodney W. Grimes /*
139326f9a767SRodney W. Grimes 		if (flags & B_ASYNC) {
139426f9a767SRodney W. Grimes 			for(i=0;i<count;i++) {
139526f9a767SRodney W. Grimes 				rtvals[i] = VM_PAGER_AGAIN;
139626f9a767SRodney W. Grimes 				if( swb[i])
139726f9a767SRodney W. Grimes 					--swb[i]->swb_locked;
139826f9a767SRodney W. Grimes 			}
139926f9a767SRodney W. Grimes 			return VM_PAGER_AGAIN;
140026f9a767SRodney W. Grimes 		}
140126f9a767SRodney W. Grimes */
140226f9a767SRodney W. Grimes 
140326f9a767SRodney W. Grimes 		s = splbio();
140426f9a767SRodney W. Grimes 		if( curproc == pageproc)
140526f9a767SRodney W. Grimes 			(void) swap_pager_clean();
140626f9a767SRodney W. Grimes 		else
140726f9a767SRodney W. Grimes 			wakeup((caddr_t) &vm_pages_needed);
140826f9a767SRodney W. Grimes 		while (swap_pager_free.tqh_first == NULL) {
140926f9a767SRodney W. Grimes 			swap_pager_needflags |= SWAP_FREE_NEEDED;
141026f9a767SRodney W. Grimes 			tsleep((caddr_t)&swap_pager_free,
141126f9a767SRodney W. Grimes 				PVM, "swpfre", 0);
141226f9a767SRodney W. Grimes 			if( curproc == pageproc)
141326f9a767SRodney W. Grimes 				(void) swap_pager_clean();
141426f9a767SRodney W. Grimes 			else
141526f9a767SRodney W. Grimes 				wakeup((caddr_t) &vm_pages_needed);
141626f9a767SRodney W. Grimes 		}
141726f9a767SRodney W. Grimes 		splx(s);
141826f9a767SRodney W. Grimes 	}
141926f9a767SRodney W. Grimes 
142026f9a767SRodney W. Grimes 	spc = swap_pager_free.tqh_first;
142126f9a767SRodney W. Grimes 	TAILQ_REMOVE(&swap_pager_free, spc, spc_list);
142226f9a767SRodney W. Grimes 	if( !kva) {
142326f9a767SRodney W. Grimes 		kva = spc->spc_kva;
142426f9a767SRodney W. Grimes 		spc->spc_altkva = 0;
142526f9a767SRodney W. Grimes 	} else {
142626f9a767SRodney W. Grimes 		spc->spc_altkva = kva;
142726f9a767SRodney W. Grimes 	}
142826f9a767SRodney W. Grimes 
142926f9a767SRodney W. Grimes 	/*
143026f9a767SRodney W. Grimes 	 * map our page(s) into kva for I/O
143126f9a767SRodney W. Grimes 	 */
143226f9a767SRodney W. Grimes 	for (i = 0; i < count; i++) {
143326f9a767SRodney W. Grimes 		pmap_kenter( kva + PAGE_SIZE * i, VM_PAGE_TO_PHYS(m[i]));
143426f9a767SRodney W. Grimes 	}
143526f9a767SRodney W. Grimes 	pmap_update();
143626f9a767SRodney W. Grimes 
143726f9a767SRodney W. Grimes 	/*
143826f9a767SRodney W. Grimes 	 * get the base I/O offset into the swap file
143926f9a767SRodney W. Grimes 	 */
144026f9a767SRodney W. Grimes 	for(i=0;i<count;i++) {
144126f9a767SRodney W. Grimes 		foff = m[i]->offset + paging_offset;
144226f9a767SRodney W. Grimes 		off = swap_pager_block_offset(swp, foff);
144326f9a767SRodney W. Grimes 		/*
144426f9a767SRodney W. Grimes 		 * if we are setting the valid bit anew,
144526f9a767SRodney W. Grimes 		 * then diminish the swap free space
144626f9a767SRodney W. Grimes 		 */
144726f9a767SRodney W. Grimes 		if( (swb[i]->swb_valid & (1 << off)) == 0)
144826f9a767SRodney W. Grimes 			vm_swap_size -= btodb(PAGE_SIZE);
144926f9a767SRodney W. Grimes 
145026f9a767SRodney W. Grimes 		/*
145126f9a767SRodney W. Grimes 		 * set the valid bit
145226f9a767SRodney W. Grimes 		 */
145326f9a767SRodney W. Grimes 		swb[i]->swb_valid |= (1 << off);
145426f9a767SRodney W. Grimes 		/*
145526f9a767SRodney W. Grimes 		 * and unlock the data structure
145626f9a767SRodney W. Grimes 		 */
145726f9a767SRodney W. Grimes 		--swb[i]->swb_locked;
145826f9a767SRodney W. Grimes 	}
145926f9a767SRodney W. Grimes 
146026f9a767SRodney W. Grimes 	s = splbio();
146126f9a767SRodney W. Grimes 	/*
146226f9a767SRodney W. Grimes 	 * Get a swap buffer header and perform the IO
146326f9a767SRodney W. Grimes 	 */
146426f9a767SRodney W. Grimes 	bp = spc->spc_bp;
146526f9a767SRodney W. Grimes 	bzero(bp, sizeof *bp);
146626f9a767SRodney W. Grimes 	bp->b_spc = spc;
146726f9a767SRodney W. Grimes 
146826f9a767SRodney W. Grimes 	bp->b_flags = B_BUSY;
146926f9a767SRodney W. Grimes 	bp->b_proc = &proc0;	/* XXX (but without B_PHYS set this is ok) */
147026f9a767SRodney W. Grimes 	bp->b_rcred = bp->b_wcred = bp->b_proc->p_ucred;
147126f9a767SRodney W. Grimes 	crhold(bp->b_rcred);
147226f9a767SRodney W. Grimes 	crhold(bp->b_wcred);
147326f9a767SRodney W. Grimes 	bp->b_un.b_addr = (caddr_t) kva;
147426f9a767SRodney W. Grimes 	bp->b_blkno = reqaddr[0];
147526f9a767SRodney W. Grimes 	bgetvp( swapdev_vp, bp);
147626f9a767SRodney W. Grimes /*
147726f9a767SRodney W. Grimes 	VHOLD(swapdev_vp);
147826f9a767SRodney W. Grimes 	bp->b_vp = swapdev_vp;
147926f9a767SRodney W. Grimes 	if (swapdev_vp->v_type == VBLK)
148026f9a767SRodney W. Grimes 		bp->b_dev = swapdev_vp->v_rdev;
148126f9a767SRodney W. Grimes */
148226f9a767SRodney W. Grimes 	bp->b_bcount = PAGE_SIZE*count;
148326f9a767SRodney W. Grimes 	bp->b_bufsize = PAGE_SIZE*count;
148426f9a767SRodney W. Grimes 	swapdev_vp->v_numoutput++;
148526f9a767SRodney W. Grimes 
148626f9a767SRodney W. Grimes 	/*
148726f9a767SRodney W. Grimes 	 * If this is an async write we set up additional buffer fields
148826f9a767SRodney W. Grimes 	 * and place a "cleaning" entry on the inuse queue.
148926f9a767SRodney W. Grimes 	 */
149026f9a767SRodney W. Grimes 	if ( flags & B_ASYNC ) {
149126f9a767SRodney W. Grimes 		spc->spc_flags = 0;
149226f9a767SRodney W. Grimes 		spc->spc_swp = swp;
149326f9a767SRodney W. Grimes 		for(i=0;i<count;i++)
149426f9a767SRodney W. Grimes 			spc->spc_m[i] = m[i];
149526f9a767SRodney W. Grimes 		spc->spc_count = count;
149626f9a767SRodney W. Grimes 		/*
149726f9a767SRodney W. Grimes 		 * the completion routine for async writes
149826f9a767SRodney W. Grimes 		 */
149926f9a767SRodney W. Grimes 		bp->b_flags |= B_CALL;
150026f9a767SRodney W. Grimes 		bp->b_iodone = swap_pager_iodone;
150126f9a767SRodney W. Grimes 		bp->b_dirtyoff = 0;
150226f9a767SRodney W. Grimes 		bp->b_dirtyend = bp->b_bcount;
150326f9a767SRodney W. Grimes 		swp->sw_poip++;
150426f9a767SRodney W. Grimes 		TAILQ_INSERT_TAIL(&swap_pager_inuse, spc, spc_list);
150526f9a767SRodney W. Grimes 	} else {
150626f9a767SRodney W. Grimes 		swp->sw_poip++;
150726f9a767SRodney W. Grimes 		bp->b_flags |= B_CALL;
150826f9a767SRodney W. Grimes 		bp->b_iodone = swap_pager_iodone1;
150926f9a767SRodney W. Grimes 	}
151026f9a767SRodney W. Grimes 	/*
151126f9a767SRodney W. Grimes 	 * perform the I/O
151226f9a767SRodney W. Grimes 	 */
151326f9a767SRodney W. Grimes 	VOP_STRATEGY(bp);
151426f9a767SRodney W. Grimes 	if ((flags & (B_READ|B_ASYNC)) == B_ASYNC ) {
151526f9a767SRodney W. Grimes 		if ((bp->b_flags & B_DONE) == B_DONE) {
151626f9a767SRodney W. Grimes 			swap_pager_clean();
151726f9a767SRodney W. Grimes 		}
151826f9a767SRodney W. Grimes 		splx(s);
151926f9a767SRodney W. Grimes 		for(i=0;i<count;i++) {
152026f9a767SRodney W. Grimes 			rtvals[i] = VM_PAGER_PEND;
152126f9a767SRodney W. Grimes 		}
152226f9a767SRodney W. Grimes 		return VM_PAGER_PEND;
152326f9a767SRodney W. Grimes 	}
152426f9a767SRodney W. Grimes 
152526f9a767SRodney W. Grimes 	/*
152626f9a767SRodney W. Grimes 	 * wait for the sync I/O to complete
152726f9a767SRodney W. Grimes 	 */
152826f9a767SRodney W. Grimes 	while ((bp->b_flags & B_DONE) == 0) {
152926f9a767SRodney W. Grimes 		tsleep((caddr_t)bp, PVM, "swwrt", 0);
153026f9a767SRodney W. Grimes 	}
153126f9a767SRodney W. Grimes 	rv = (bp->b_flags & B_ERROR) ? VM_PAGER_FAIL : VM_PAGER_OK;
153226f9a767SRodney W. Grimes 	bp->b_flags &= ~(B_BUSY|B_WANTED|B_PHYS|B_DIRTY|B_CALL|B_DONE);
153326f9a767SRodney W. Grimes 
153426f9a767SRodney W. Grimes 	--swp->sw_poip;
153526f9a767SRodney W. Grimes 	if (swp->sw_poip == 0)
153626f9a767SRodney W. Grimes 		wakeup((caddr_t) swp);
153726f9a767SRodney W. Grimes 
153826f9a767SRodney W. Grimes 	if (bp->b_vp)
153926f9a767SRodney W. Grimes 		brelvp(bp);
154026f9a767SRodney W. Grimes 
154126f9a767SRodney W. Grimes 	splx(s);
154226f9a767SRodney W. Grimes 
154326f9a767SRodney W. Grimes 	/*
154426f9a767SRodney W. Grimes 	 * remove the mapping for kernel virtual
154526f9a767SRodney W. Grimes 	 */
154626f9a767SRodney W. Grimes 	pmap_remove(vm_map_pmap(pager_map), kva, kva + count * PAGE_SIZE);
154726f9a767SRodney W. Grimes 
154826f9a767SRodney W. Grimes 	/*
154926f9a767SRodney W. Grimes 	 * if we have written the page, then indicate that the page
155026f9a767SRodney W. Grimes 	 * is clean.
155126f9a767SRodney W. Grimes 	 */
155226f9a767SRodney W. Grimes 	if (rv == VM_PAGER_OK) {
155326f9a767SRodney W. Grimes 		for(i=0;i<count;i++) {
155426f9a767SRodney W. Grimes 			if( rtvals[i] == VM_PAGER_OK) {
155526f9a767SRodney W. Grimes 				m[i]->flags |= PG_CLEAN;
155626f9a767SRodney W. Grimes 				m[i]->flags &= ~PG_LAUNDRY;
155726f9a767SRodney W. Grimes 				pmap_clear_modify(VM_PAGE_TO_PHYS(m[i]));
155826f9a767SRodney W. Grimes 				/*
155926f9a767SRodney W. Grimes 				 * optimization, if a page has been read during the
156026f9a767SRodney W. Grimes 				 * pageout process, we activate it.
156126f9a767SRodney W. Grimes 				 */
156226f9a767SRodney W. Grimes 				if ( (m[i]->flags & PG_ACTIVE) == 0 &&
156326f9a767SRodney W. Grimes 					pmap_is_referenced(VM_PAGE_TO_PHYS(m[i])))
156426f9a767SRodney W. Grimes 					vm_page_activate(m[i]);
156526f9a767SRodney W. Grimes 			}
156626f9a767SRodney W. Grimes 		}
156726f9a767SRodney W. Grimes 	} else {
156826f9a767SRodney W. Grimes 		for(i=0;i<count;i++) {
156926f9a767SRodney W. Grimes 			rtvals[i] = rv;
157026f9a767SRodney W. Grimes 			m[i]->flags |= PG_LAUNDRY;
157126f9a767SRodney W. Grimes 		}
157226f9a767SRodney W. Grimes 	}
157326f9a767SRodney W. Grimes 
157426f9a767SRodney W. Grimes 	if( spc->spc_altkva)
157526f9a767SRodney W. Grimes 		kmem_free_wakeup(pager_map, kva, count * PAGE_SIZE);
157626f9a767SRodney W. Grimes 
157726f9a767SRodney W. Grimes 	if( bp->b_rcred != NOCRED)
157826f9a767SRodney W. Grimes 		crfree(bp->b_rcred);
157926f9a767SRodney W. Grimes 	if( bp->b_wcred != NOCRED)
158026f9a767SRodney W. Grimes 		crfree(bp->b_wcred);
158126f9a767SRodney W. Grimes 	TAILQ_INSERT_TAIL(&swap_pager_free, spc, spc_list);
158226f9a767SRodney W. Grimes 	if (swap_pager_needflags & SWAP_FREE_NEEDED) {
158326f9a767SRodney W. Grimes 		swap_pager_needflags &= ~SWAP_FREE_NEEDED;
158426f9a767SRodney W. Grimes 		wakeup((caddr_t)&swap_pager_free);
158526f9a767SRodney W. Grimes 	}
158626f9a767SRodney W. Grimes 
158726f9a767SRodney W. Grimes 	return(rv);
158826f9a767SRodney W. Grimes }
158926f9a767SRodney W. Grimes 
159026f9a767SRodney W. Grimes boolean_t
159126f9a767SRodney W. Grimes swap_pager_clean()
159226f9a767SRodney W. Grimes {
159326f9a767SRodney W. Grimes 	register swp_clean_t spc, tspc;
159426f9a767SRodney W. Grimes 	register int s;
159526f9a767SRodney W. Grimes 
159626f9a767SRodney W. Grimes 	tspc = NULL;
159726f9a767SRodney W. Grimes 	if (swap_pager_done.tqh_first == NULL)
159826f9a767SRodney W. Grimes 		return FALSE;
159926f9a767SRodney W. Grimes 	for (;;) {
160026f9a767SRodney W. Grimes 		s = splbio();
160126f9a767SRodney W. Grimes 		/*
160226f9a767SRodney W. Grimes 		 * Look up and removal from done list must be done
160326f9a767SRodney W. Grimes 		 * at splbio() to avoid conflicts with swap_pager_iodone.
160426f9a767SRodney W. Grimes 		 */
160526f9a767SRodney W. Grimes 		while (spc = swap_pager_done.tqh_first) {
160626f9a767SRodney W. Grimes 			if( spc->spc_altkva) {
160726f9a767SRodney W. Grimes 				pmap_remove(vm_map_pmap(pager_map), spc->spc_altkva, spc->spc_altkva + spc->spc_count * PAGE_SIZE);
160826f9a767SRodney W. Grimes 				kmem_free_wakeup(pager_map, spc->spc_altkva, spc->spc_count * PAGE_SIZE);
160926f9a767SRodney W. Grimes 				spc->spc_altkva = 0;
161026f9a767SRodney W. Grimes 			} else {
161126f9a767SRodney W. Grimes 				pmap_remove(vm_map_pmap(pager_map), spc->spc_kva, spc->spc_kva + PAGE_SIZE);
161226f9a767SRodney W. Grimes 			}
161326f9a767SRodney W. Grimes 			swap_pager_finish(spc);
161426f9a767SRodney W. Grimes 			TAILQ_REMOVE(&swap_pager_done, spc, spc_list);
161526f9a767SRodney W. Grimes 			goto doclean;
161626f9a767SRodney W. Grimes 		}
1617df8bae1dSRodney W. Grimes 
1618df8bae1dSRodney W. Grimes 		/*
1619df8bae1dSRodney W. Grimes 		 * No operations done, thats all we can do for now.
1620df8bae1dSRodney W. Grimes 		 */
162126f9a767SRodney W. Grimes 
162226f9a767SRodney W. Grimes 		splx(s);
1623df8bae1dSRodney W. Grimes 		break;
1624df8bae1dSRodney W. Grimes 
1625df8bae1dSRodney W. Grimes 		/*
162626f9a767SRodney W. Grimes 		 * The desired page was found to be busy earlier in
162726f9a767SRodney W. Grimes 		 * the scan but has since completed.
1628df8bae1dSRodney W. Grimes 		 */
162926f9a767SRodney W. Grimes doclean:
163026f9a767SRodney W. Grimes 		if (tspc && tspc == spc) {
163126f9a767SRodney W. Grimes 			tspc = NULL;
163226f9a767SRodney W. Grimes 		}
163326f9a767SRodney W. Grimes 		spc->spc_flags = 0;
163426f9a767SRodney W. Grimes 		TAILQ_INSERT_TAIL(&swap_pager_free, spc, spc_list);
163526f9a767SRodney W. Grimes 		if (swap_pager_needflags & SWAP_FREE_NEEDED) {
163626f9a767SRodney W. Grimes 			swap_pager_needflags &= ~SWAP_FREE_NEEDED;
163726f9a767SRodney W. Grimes 			wakeup((caddr_t)&swap_pager_free);
163826f9a767SRodney W. Grimes 		}
163926f9a767SRodney W. Grimes 		++cleandone;
164026f9a767SRodney W. Grimes 		splx(s);
164126f9a767SRodney W. Grimes 	}
164226f9a767SRodney W. Grimes 
164326f9a767SRodney W. Grimes 	return(tspc ? TRUE : FALSE);
164426f9a767SRodney W. Grimes }
164526f9a767SRodney W. Grimes 
164626f9a767SRodney W. Grimes void
164726f9a767SRodney W. Grimes swap_pager_finish(spc)
164826f9a767SRodney W. Grimes 	register swp_clean_t spc;
164926f9a767SRodney W. Grimes {
165026f9a767SRodney W. Grimes 	vm_object_t object = spc->spc_m[0]->object;
165126f9a767SRodney W. Grimes 	int i;
165226f9a767SRodney W. Grimes 
165326f9a767SRodney W. Grimes 	if ((object->paging_in_progress -= spc->spc_count) == 0)
165426f9a767SRodney W. Grimes 		thread_wakeup((int) object);
1655df8bae1dSRodney W. Grimes 
1656df8bae1dSRodney W. Grimes 	/*
165726f9a767SRodney W. Grimes 	 * If no error mark as clean and inform the pmap system.
165826f9a767SRodney W. Grimes 	 * If error, mark as dirty so we will try again.
165926f9a767SRodney W. Grimes 	 * (XXX could get stuck doing this, should give up after awhile)
1660df8bae1dSRodney W. Grimes 	 */
1661df8bae1dSRodney W. Grimes 	if (spc->spc_flags & SPC_ERROR) {
166226f9a767SRodney W. Grimes 		for(i=0;i<spc->spc_count;i++) {
166326f9a767SRodney W. Grimes 			printf("swap_pager_finish: clean of page %x failed\n",
166426f9a767SRodney W. Grimes 			       VM_PAGE_TO_PHYS(spc->spc_m[i]));
166526f9a767SRodney W. Grimes 			spc->spc_m[i]->flags |= PG_LAUNDRY;
166626f9a767SRodney W. Grimes 		}
1667df8bae1dSRodney W. Grimes 	} else {
166826f9a767SRodney W. Grimes 		for(i=0;i<spc->spc_count;i++) {
166926f9a767SRodney W. Grimes 			pmap_clear_modify(VM_PAGE_TO_PHYS(spc->spc_m[i]));
167026f9a767SRodney W. Grimes 			spc->spc_m[i]->flags |= PG_CLEAN;
1671df8bae1dSRodney W. Grimes 		}
1672df8bae1dSRodney W. Grimes 	}
1673df8bae1dSRodney W. Grimes 
167426f9a767SRodney W. Grimes 
167526f9a767SRodney W. Grimes 	for(i=0;i<spc->spc_count;i++) {
1676df8bae1dSRodney W. Grimes 		/*
167726f9a767SRodney W. Grimes 		 * we wakeup any processes that are waiting on
167826f9a767SRodney W. Grimes 		 * these pages.
1679df8bae1dSRodney W. Grimes 		 */
168026f9a767SRodney W. Grimes 		PAGE_WAKEUP(spc->spc_m[i]);
1681df8bae1dSRodney W. Grimes 	}
168226f9a767SRodney W. Grimes 	nswiodone -= spc->spc_count;
1683df8bae1dSRodney W. Grimes 
1684df8bae1dSRodney W. Grimes 	return;
168526f9a767SRodney W. Grimes }
1686df8bae1dSRodney W. Grimes 
168726f9a767SRodney W. Grimes /*
168826f9a767SRodney W. Grimes  * swap_pager_iodone
168926f9a767SRodney W. Grimes  */
169026f9a767SRodney W. Grimes void
1691df8bae1dSRodney W. Grimes swap_pager_iodone(bp)
1692df8bae1dSRodney W. Grimes 	register struct buf *bp;
1693df8bae1dSRodney W. Grimes {
1694df8bae1dSRodney W. Grimes 	register swp_clean_t spc;
1695df8bae1dSRodney W. Grimes 	int s;
1696df8bae1dSRodney W. Grimes 
1697df8bae1dSRodney W. Grimes 	s = splbio();
169826f9a767SRodney W. Grimes 	spc = (swp_clean_t) bp->b_spc;
169926f9a767SRodney W. Grimes 	TAILQ_REMOVE(&swap_pager_inuse, spc, spc_list);
170026f9a767SRodney W. Grimes 	TAILQ_INSERT_TAIL(&swap_pager_done, spc, spc_list);
170126f9a767SRodney W. Grimes 	if (bp->b_flags & B_ERROR) {
1702df8bae1dSRodney W. Grimes 		spc->spc_flags |= SPC_ERROR;
170326f9a767SRodney W. Grimes 		printf("error %d blkno %d sz %d ",
170426f9a767SRodney W. Grimes 			bp->b_error, bp->b_blkno, bp->b_bcount);
1705df8bae1dSRodney W. Grimes 	}
1706df8bae1dSRodney W. Grimes 
170726f9a767SRodney W. Grimes /*
170826f9a767SRodney W. Grimes 	if ((bp->b_flags & B_READ) == 0)
170926f9a767SRodney W. Grimes 		vwakeup(bp);
171026f9a767SRodney W. Grimes */
171126f9a767SRodney W. Grimes 
171226f9a767SRodney W. Grimes 	bp->b_flags &= ~(B_BUSY|B_WANTED|B_PHYS|B_DIRTY|B_ASYNC);
171326f9a767SRodney W. Grimes 	if (bp->b_vp) {
171426f9a767SRodney W. Grimes 		brelvp(bp);
171526f9a767SRodney W. Grimes 	}
171626f9a767SRodney W. Grimes 	if( bp->b_rcred != NOCRED)
171726f9a767SRodney W. Grimes 		crfree(bp->b_rcred);
171826f9a767SRodney W. Grimes 	if( bp->b_wcred != NOCRED)
171926f9a767SRodney W. Grimes 		crfree(bp->b_wcred);
172026f9a767SRodney W. Grimes 
172126f9a767SRodney W. Grimes 	nswiodone += spc->spc_count;
172226f9a767SRodney W. Grimes 	if (--spc->spc_swp->sw_poip == 0) {
172326f9a767SRodney W. Grimes 		wakeup((caddr_t)spc->spc_swp);
172426f9a767SRodney W. Grimes 	}
172526f9a767SRodney W. Grimes 
172626f9a767SRodney W. Grimes 	if ((swap_pager_needflags & SWAP_FREE_NEEDED) ||
172726f9a767SRodney W. Grimes 	    swap_pager_inuse.tqh_first == 0) {
172826f9a767SRodney W. Grimes 		swap_pager_needflags &= ~SWAP_FREE_NEEDED;
172926f9a767SRodney W. Grimes 		wakeup((caddr_t)&swap_pager_free);
173026f9a767SRodney W. Grimes 		wakeup((caddr_t)&vm_pages_needed);
173126f9a767SRodney W. Grimes 	}
173226f9a767SRodney W. Grimes 
173326f9a767SRodney W. Grimes 	if (vm_pageout_pages_needed) {
173426f9a767SRodney W. Grimes 		wakeup((caddr_t)&vm_pageout_pages_needed);
173526f9a767SRodney W. Grimes 	}
173626f9a767SRodney W. Grimes 
173726f9a767SRodney W. Grimes 	if ((swap_pager_inuse.tqh_first == NULL) ||
173826f9a767SRodney W. Grimes 	    (cnt.v_free_count < cnt.v_free_min &&
173926f9a767SRodney W. Grimes 	    nswiodone + cnt.v_free_count >= cnt.v_free_min) ) {
174026f9a767SRodney W. Grimes 		wakeup((caddr_t)&vm_pages_needed);
174126f9a767SRodney W. Grimes 	}
174226f9a767SRodney W. Grimes 	splx(s);
174326f9a767SRodney W. Grimes }
174426f9a767SRodney W. Grimes 
174526f9a767SRodney W. Grimes int bswneeded;
174626f9a767SRodney W. Grimes /* TAILQ_HEAD(swqueue, buf) bswlist; */
174726f9a767SRodney W. Grimes /*
174826f9a767SRodney W. Grimes  * allocate a physical buffer
174926f9a767SRodney W. Grimes  */
175026f9a767SRodney W. Grimes struct buf *
175126f9a767SRodney W. Grimes getpbuf() {
175226f9a767SRodney W. Grimes 	int s;
175326f9a767SRodney W. Grimes 	struct buf *bp;
175426f9a767SRodney W. Grimes 
175526f9a767SRodney W. Grimes 	s = splbio();
175626f9a767SRodney W. Grimes 	/* get a bp from the swap buffer header pool */
175726f9a767SRodney W. Grimes 	while ((bp = bswlist.tqh_first) == NULL) {
175826f9a767SRodney W. Grimes 		bswneeded = 1;
175926f9a767SRodney W. Grimes 		tsleep((caddr_t)&bswneeded, PVM, "wswbuf", 0);
176026f9a767SRodney W. Grimes 	}
176126f9a767SRodney W. Grimes 	TAILQ_REMOVE(&bswlist, bp, b_freelist);
176226f9a767SRodney W. Grimes 
176326f9a767SRodney W. Grimes 	splx(s);
176426f9a767SRodney W. Grimes 
176526f9a767SRodney W. Grimes 	bzero(bp, sizeof *bp);
176626f9a767SRodney W. Grimes 	bp->b_rcred = NOCRED;
176726f9a767SRodney W. Grimes 	bp->b_wcred = NOCRED;
176826f9a767SRodney W. Grimes 	return bp;
176926f9a767SRodney W. Grimes }
177026f9a767SRodney W. Grimes 
177126f9a767SRodney W. Grimes /*
177226f9a767SRodney W. Grimes  * allocate a physical buffer, if one is available
177326f9a767SRodney W. Grimes  */
177426f9a767SRodney W. Grimes struct buf *
177526f9a767SRodney W. Grimes trypbuf() {
177626f9a767SRodney W. Grimes 	int s;
177726f9a767SRodney W. Grimes 	struct buf *bp;
177826f9a767SRodney W. Grimes 
177926f9a767SRodney W. Grimes 	s = splbio();
178026f9a767SRodney W. Grimes 	if ((bp = bswlist.tqh_first) == NULL) {
178126f9a767SRodney W. Grimes 		splx(s);
178226f9a767SRodney W. Grimes 		return NULL;
178326f9a767SRodney W. Grimes 	}
178426f9a767SRodney W. Grimes 	TAILQ_REMOVE(&bswlist, bp, b_freelist);
178526f9a767SRodney W. Grimes 	splx(s);
178626f9a767SRodney W. Grimes 
178726f9a767SRodney W. Grimes 	bzero(bp, sizeof *bp);
178826f9a767SRodney W. Grimes 	bp->b_rcred = NOCRED;
178926f9a767SRodney W. Grimes 	bp->b_wcred = NOCRED;
179026f9a767SRodney W. Grimes 	return bp;
179126f9a767SRodney W. Grimes }
179226f9a767SRodney W. Grimes 
179326f9a767SRodney W. Grimes /*
179426f9a767SRodney W. Grimes  * release a physical buffer
179526f9a767SRodney W. Grimes  */
179626f9a767SRodney W. Grimes void
179726f9a767SRodney W. Grimes relpbuf(bp)
179826f9a767SRodney W. Grimes 	struct buf *bp;
179926f9a767SRodney W. Grimes {
180026f9a767SRodney W. Grimes 	int s;
180126f9a767SRodney W. Grimes 
180226f9a767SRodney W. Grimes 	s = splbio();
180326f9a767SRodney W. Grimes 
180426f9a767SRodney W. Grimes 	if (bp->b_rcred != NOCRED) {
180526f9a767SRodney W. Grimes 		crfree(bp->b_rcred);
180626f9a767SRodney W. Grimes 		bp->b_rcred = NOCRED;
180726f9a767SRodney W. Grimes 	}
180826f9a767SRodney W. Grimes 	if (bp->b_wcred != NOCRED) {
180926f9a767SRodney W. Grimes 		crfree(bp->b_wcred);
181026f9a767SRodney W. Grimes 		bp->b_wcred = NOCRED;
181126f9a767SRodney W. Grimes 	}
181226f9a767SRodney W. Grimes 
1813df8bae1dSRodney W. Grimes 	if (bp->b_vp)
1814df8bae1dSRodney W. Grimes 		brelvp(bp);
181526f9a767SRodney W. Grimes 
181626f9a767SRodney W. Grimes 	TAILQ_INSERT_HEAD(&bswlist, bp, b_freelist);
181726f9a767SRodney W. Grimes 
181826f9a767SRodney W. Grimes 	if (bswneeded) {
181926f9a767SRodney W. Grimes 		bswneeded = 0;
182026f9a767SRodney W. Grimes 		wakeup((caddr_t)&bswlist);
1821df8bae1dSRodney W. Grimes 	}
1822df8bae1dSRodney W. Grimes 	splx(s);
1823df8bae1dSRodney W. Grimes }
182426f9a767SRodney W. Grimes 
182526f9a767SRodney W. Grimes /*
182626f9a767SRodney W. Grimes  * return true if any swap control structures can be allocated
182726f9a767SRodney W. Grimes  */
182826f9a767SRodney W. Grimes int
182926f9a767SRodney W. Grimes swap_pager_ready() {
183026f9a767SRodney W. Grimes 	if( swap_pager_free.tqh_first)
183126f9a767SRodney W. Grimes 		return 1;
183226f9a767SRodney W. Grimes 	else
183326f9a767SRodney W. Grimes 		return 0;
183426f9a767SRodney W. Grimes }
1835