xref: /csrg-svn/sys/vm/swap_pager.c (revision 66424)
145749Smckusick /*
245749Smckusick  * Copyright (c) 1990 University of Utah.
363379Sbostic  * Copyright (c) 1991, 1993
463379Sbostic  *	The Regents of the University of California.  All rights reserved.
545749Smckusick  *
645749Smckusick  * This code is derived from software contributed to Berkeley by
745749Smckusick  * the Systems Programming Group of the University of Utah Computer
845749Smckusick  * Science Department.
945749Smckusick  *
1045749Smckusick  * %sccs.include.redist.c%
1145749Smckusick  *
1249289Shibler  * from: Utah $Hdr: swap_pager.c 1.4 91/04/30$
1349289Shibler  *
14*66424Shibler  *	@(#)swap_pager.c	8.9 (Berkeley) 03/21/94
1545749Smckusick  */
1645749Smckusick 
1745749Smckusick /*
1845749Smckusick  * Quick hack to page to dedicated partition(s).
1945749Smckusick  * TODO:
2045749Smckusick  *	Add multiprocessor locks
2145749Smckusick  *	Deal with async writes in a better fashion
2245749Smckusick  */
2345749Smckusick 
2453341Sbostic #include <sys/param.h>
2553341Sbostic #include <sys/systm.h>
2653341Sbostic #include <sys/proc.h>
2753341Sbostic #include <sys/buf.h>
2853341Sbostic #include <sys/map.h>
2953496Sheideman #include <sys/vnode.h>
3053341Sbostic #include <sys/malloc.h>
3145749Smckusick 
3255051Spendry #include <miscfs/specfs/specdev.h>
3355051Spendry 
3453341Sbostic #include <vm/vm.h>
3553341Sbostic #include <vm/vm_page.h>
3653341Sbostic #include <vm/vm_pageout.h>
3753341Sbostic #include <vm/swap_pager.h>
3845749Smckusick 
3945749Smckusick #define NSWSIZES	16	/* size of swtab */
4065682Shibler #define MAXDADDRS	64	/* max # of disk addrs for fixed allocations */
4165682Shibler #ifndef NPENDINGIO
4245749Smckusick #define NPENDINGIO	64	/* max # of pending cleans */
4365682Shibler #endif
4445749Smckusick 
4545749Smckusick #ifdef DEBUG
4645749Smckusick int	swpagerdebug = 0x100;
4745749Smckusick #define	SDB_FOLLOW	0x001
4845749Smckusick #define SDB_INIT	0x002
4945749Smckusick #define SDB_ALLOC	0x004
5045749Smckusick #define SDB_IO		0x008
5145749Smckusick #define SDB_WRITE	0x010
5245749Smckusick #define SDB_FAIL	0x020
5345749Smckusick #define SDB_ALLOCBLK	0x040
5445749Smckusick #define SDB_FULL	0x080
5545749Smckusick #define SDB_ANOM	0x100
5645749Smckusick #define SDB_ANOMPANIC	0x200
5765682Shibler #define SDB_CLUSTER	0x400
5865682Shibler #define SDB_PARANOIA	0x800
5945749Smckusick #endif
6045749Smckusick 
6165231Smckusick TAILQ_HEAD(swpclean, swpagerclean);
6265231Smckusick 
6345749Smckusick struct swpagerclean {
6465231Smckusick 	TAILQ_ENTRY(swpagerclean)	spc_list;
6565231Smckusick 	int				spc_flags;
6665231Smckusick 	struct buf			*spc_bp;
6765231Smckusick 	sw_pager_t			spc_swp;
6865231Smckusick 	vm_offset_t			spc_kva;
6965231Smckusick 	vm_page_t			spc_m;
7065682Shibler 	int				spc_npages;
7145749Smckusick } swcleanlist[NPENDINGIO];
7253341Sbostic typedef struct swpagerclean *swp_clean_t;
7345749Smckusick 
7445749Smckusick /* spc_flags values */
7545749Smckusick #define SPC_FREE	0x00
7645749Smckusick #define SPC_BUSY	0x01
7745749Smckusick #define SPC_DONE	0x02
7845749Smckusick #define SPC_ERROR	0x04
7945749Smckusick 
8045749Smckusick struct swtab {
8145749Smckusick 	vm_size_t st_osize;	/* size of object (bytes) */
8245749Smckusick 	int	  st_bsize;	/* vs. size of swap block (DEV_BSIZE units) */
8345749Smckusick #ifdef DEBUG
8445749Smckusick 	u_long	  st_inuse;	/* number in this range in use */
8545749Smckusick 	u_long	  st_usecnt;	/* total used of this size */
8645749Smckusick #endif
8745749Smckusick } swtab[NSWSIZES+1];
8845749Smckusick 
8945749Smckusick #ifdef DEBUG
9045749Smckusick int		swap_pager_poip;	/* pageouts in progress */
9145749Smckusick int		swap_pager_piip;	/* pageins in progress */
9245749Smckusick #endif
9345749Smckusick 
9465682Shibler int		swap_pager_maxcluster;	/* maximum cluster size */
9565682Shibler int		swap_pager_npendingio;	/* number of pager clean structs */
9665682Shibler 
9765231Smckusick struct swpclean	swap_pager_inuse;	/* list of pending page cleans */
9865231Smckusick struct swpclean	swap_pager_free;	/* list of free pager clean structs */
9965231Smckusick struct pagerlst	swap_pager_list;	/* list of "named" anon regions */
10045749Smckusick 
10153341Sbostic static void 		swap_pager_init __P((void));
10264827Storek static vm_pager_t	swap_pager_alloc
10364827Storek 			    __P((caddr_t, vm_size_t, vm_prot_t, vm_offset_t));
10465682Shibler static void		swap_pager_clean __P((int));
10565682Shibler #ifdef DEBUG
10665682Shibler static void		swap_pager_clean_check __P((vm_page_t *, int, int));
10765682Shibler #endif
10865682Shibler static void		swap_pager_cluster
10965682Shibler 			    __P((vm_pager_t, vm_offset_t,
11065682Shibler 				 vm_offset_t *, vm_offset_t *));
11153341Sbostic static void		swap_pager_dealloc __P((vm_pager_t));
11253341Sbostic static int		swap_pager_getpage
11365682Shibler 			    __P((vm_pager_t, vm_page_t *, int, boolean_t));
11453341Sbostic static boolean_t	swap_pager_haspage __P((vm_pager_t, vm_offset_t));
11565682Shibler static int		swap_pager_io __P((sw_pager_t, vm_page_t *, int, int));
11653341Sbostic static void		swap_pager_iodone __P((struct buf *));
11753341Sbostic static int		swap_pager_putpage
11865682Shibler 			    __P((vm_pager_t, vm_page_t *, int, boolean_t));
11953341Sbostic 
12053341Sbostic struct pagerops swappagerops = {
12153341Sbostic 	swap_pager_init,
12253341Sbostic 	swap_pager_alloc,
12353341Sbostic 	swap_pager_dealloc,
12453341Sbostic 	swap_pager_getpage,
12553341Sbostic 	swap_pager_putpage,
12665682Shibler 	swap_pager_haspage,
12765682Shibler 	swap_pager_cluster
12853341Sbostic };
12953341Sbostic 
13053341Sbostic static void
swap_pager_init()13145749Smckusick swap_pager_init()
13245749Smckusick {
13345749Smckusick 	register swp_clean_t spc;
13445749Smckusick 	register int i, bsize;
13545749Smckusick 	extern int dmmin, dmmax;
13645749Smckusick 	int maxbsize;
13745749Smckusick 
13845749Smckusick #ifdef DEBUG
13945749Smckusick 	if (swpagerdebug & (SDB_FOLLOW|SDB_INIT))
14045749Smckusick 		printf("swpg_init()\n");
14145749Smckusick #endif
14245749Smckusick 	dfltpagerops = &swappagerops;
14365231Smckusick 	TAILQ_INIT(&swap_pager_list);
14445749Smckusick 
14545749Smckusick 	/*
14665682Shibler 	 * Allocate async IO structures.
14765682Shibler 	 *
14865682Shibler 	 * XXX it would be nice if we could do this dynamically based on
14965682Shibler 	 * the value of nswbuf (since we are ultimately limited by that)
15065682Shibler 	 * but neither nswbuf or malloc has been initialized yet.  So the
15165682Shibler 	 * structs are statically allocated above.
15265682Shibler 	 */
15365682Shibler 	swap_pager_npendingio = NPENDINGIO;
15465682Shibler 
15565682Shibler 	/*
15645749Smckusick 	 * Initialize clean lists
15745749Smckusick 	 */
15865231Smckusick 	TAILQ_INIT(&swap_pager_inuse);
15965231Smckusick 	TAILQ_INIT(&swap_pager_free);
16065682Shibler 	for (i = 0, spc = swcleanlist; i < swap_pager_npendingio; i++, spc++) {
16165231Smckusick 		TAILQ_INSERT_TAIL(&swap_pager_free, spc, spc_list);
16245749Smckusick 		spc->spc_flags = SPC_FREE;
16345749Smckusick 	}
16445749Smckusick 
16545749Smckusick 	/*
16645749Smckusick 	 * Calculate the swap allocation constants.
16745749Smckusick 	 */
16845749Smckusick         if (dmmin == 0) {
16945749Smckusick                 dmmin = DMMIN;
17045749Smckusick 		if (dmmin < CLBYTES/DEV_BSIZE)
17145749Smckusick 			dmmin = CLBYTES/DEV_BSIZE;
17245749Smckusick 	}
17345749Smckusick         if (dmmax == 0)
17445749Smckusick                 dmmax = DMMAX;
17545749Smckusick 
17645749Smckusick 	/*
17745749Smckusick 	 * Fill in our table of object size vs. allocation size
17845749Smckusick 	 */
17945749Smckusick 	bsize = btodb(PAGE_SIZE);
18045749Smckusick 	if (bsize < dmmin)
18145749Smckusick 		bsize = dmmin;
18245749Smckusick 	maxbsize = btodb(sizeof(sw_bm_t) * NBBY * PAGE_SIZE);
18345749Smckusick 	if (maxbsize > dmmax)
18445749Smckusick 		maxbsize = dmmax;
18545749Smckusick 	for (i = 0; i < NSWSIZES; i++) {
18645749Smckusick 		swtab[i].st_osize = (vm_size_t) (MAXDADDRS * dbtob(bsize));
18745749Smckusick 		swtab[i].st_bsize = bsize;
18865682Shibler 		if (bsize <= btodb(MAXPHYS))
18965682Shibler 			swap_pager_maxcluster = dbtob(bsize);
19045749Smckusick #ifdef DEBUG
19145749Smckusick 		if (swpagerdebug & SDB_INIT)
19245749Smckusick 			printf("swpg_init: ix %d, size %x, bsize %x\n",
19345749Smckusick 			       i, swtab[i].st_osize, swtab[i].st_bsize);
19445749Smckusick #endif
19545749Smckusick 		if (bsize >= maxbsize)
19645749Smckusick 			break;
19745749Smckusick 		bsize *= 2;
19845749Smckusick 	}
19945749Smckusick 	swtab[i].st_osize = 0;
20045749Smckusick 	swtab[i].st_bsize = bsize;
20145749Smckusick }
20245749Smckusick 
20345749Smckusick /*
20445749Smckusick  * Allocate a pager structure and associated resources.
20545749Smckusick  * Note that if we are called from the pageout daemon (handle == NULL)
20645749Smckusick  * we should not wait for memory as it could resulting in deadlock.
20745749Smckusick  */
20853341Sbostic static vm_pager_t
swap_pager_alloc(handle,size,prot,foff)20964827Storek swap_pager_alloc(handle, size, prot, foff)
21045749Smckusick 	caddr_t handle;
21145749Smckusick 	register vm_size_t size;
21245749Smckusick 	vm_prot_t prot;
21364827Storek 	vm_offset_t foff;
21445749Smckusick {
21545749Smckusick 	register vm_pager_t pager;
21645749Smckusick 	register sw_pager_t swp;
21745749Smckusick 	struct swtab *swt;
21845749Smckusick 	int waitok;
21945749Smckusick 
22045749Smckusick #ifdef DEBUG
22145749Smckusick 	if (swpagerdebug & (SDB_FOLLOW|SDB_ALLOC))
22245749Smckusick 		printf("swpg_alloc(%x, %x, %x)\n", handle, size, prot);
22345749Smckusick #endif
22445749Smckusick 	/*
22545749Smckusick 	 * If this is a "named" anonymous region, look it up and
22645749Smckusick 	 * return the appropriate pager if it exists.
22745749Smckusick 	 */
22845749Smckusick 	if (handle) {
22945749Smckusick 		pager = vm_pager_lookup(&swap_pager_list, handle);
23048386Skarels 		if (pager != NULL) {
23145749Smckusick 			/*
23245749Smckusick 			 * Use vm_object_lookup to gain a reference
23345749Smckusick 			 * to the object and also to remove from the
23445749Smckusick 			 * object cache.
23545749Smckusick 			 */
23648386Skarels 			if (vm_object_lookup(pager) == NULL)
23745749Smckusick 				panic("swap_pager_alloc: bad object");
23845749Smckusick 			return(pager);
23945749Smckusick 		}
24045749Smckusick 	}
24145749Smckusick 	/*
24245749Smckusick 	 * Pager doesn't exist, allocate swap management resources
24345749Smckusick 	 * and initialize.
24445749Smckusick 	 */
24545749Smckusick 	waitok = handle ? M_WAITOK : M_NOWAIT;
24645749Smckusick 	pager = (vm_pager_t)malloc(sizeof *pager, M_VMPAGER, waitok);
24748386Skarels 	if (pager == NULL)
24848386Skarels 		return(NULL);
24945749Smckusick 	swp = (sw_pager_t)malloc(sizeof *swp, M_VMPGDATA, waitok);
25045749Smckusick 	if (swp == NULL) {
25145749Smckusick #ifdef DEBUG
25245749Smckusick 		if (swpagerdebug & SDB_FAIL)
25345749Smckusick 			printf("swpg_alloc: swpager malloc failed\n");
25445749Smckusick #endif
25545749Smckusick 		free((caddr_t)pager, M_VMPAGER);
25648386Skarels 		return(NULL);
25745749Smckusick 	}
25845749Smckusick 	size = round_page(size);
25945749Smckusick 	for (swt = swtab; swt->st_osize; swt++)
26045749Smckusick 		if (size <= swt->st_osize)
26145749Smckusick 			break;
26245749Smckusick #ifdef DEBUG
26345749Smckusick 	swt->st_inuse++;
26445749Smckusick 	swt->st_usecnt++;
26545749Smckusick #endif
26645749Smckusick 	swp->sw_osize = size;
26745749Smckusick 	swp->sw_bsize = swt->st_bsize;
26845749Smckusick 	swp->sw_nblocks = (btodb(size) + swp->sw_bsize - 1) / swp->sw_bsize;
26945749Smckusick 	swp->sw_blocks = (sw_blk_t)
27045749Smckusick 		malloc(swp->sw_nblocks*sizeof(*swp->sw_blocks),
27145749Smckusick 		       M_VMPGDATA, M_NOWAIT);
27245749Smckusick 	if (swp->sw_blocks == NULL) {
27345749Smckusick 		free((caddr_t)swp, M_VMPGDATA);
27445749Smckusick 		free((caddr_t)pager, M_VMPAGER);
27545749Smckusick #ifdef DEBUG
27645749Smckusick 		if (swpagerdebug & SDB_FAIL)
27745749Smckusick 			printf("swpg_alloc: sw_blocks malloc failed\n");
27845749Smckusick 		swt->st_inuse--;
27945749Smckusick 		swt->st_usecnt--;
28045749Smckusick #endif
28145749Smckusick 		return(FALSE);
28245749Smckusick 	}
28345749Smckusick 	bzero((caddr_t)swp->sw_blocks,
28445749Smckusick 	      swp->sw_nblocks * sizeof(*swp->sw_blocks));
28545749Smckusick 	swp->sw_poip = 0;
28645749Smckusick 	if (handle) {
28745749Smckusick 		vm_object_t object;
28845749Smckusick 
28945749Smckusick 		swp->sw_flags = SW_NAMED;
29065231Smckusick 		TAILQ_INSERT_TAIL(&swap_pager_list, pager, pg_list);
29145749Smckusick 		/*
29245749Smckusick 		 * Consistant with other pagers: return with object
29345749Smckusick 		 * referenced.  Can't do this with handle == NULL
29445749Smckusick 		 * since it might be the pageout daemon calling.
29545749Smckusick 		 */
29645749Smckusick 		object = vm_object_allocate(size);
29745749Smckusick 		vm_object_enter(object, pager);
29845749Smckusick 		vm_object_setpager(object, pager, 0, FALSE);
29945749Smckusick 	} else {
30045749Smckusick 		swp->sw_flags = 0;
30165231Smckusick 		pager->pg_list.tqe_next = NULL;
30265231Smckusick 		pager->pg_list.tqe_prev = NULL;
30345749Smckusick 	}
30445749Smckusick 	pager->pg_handle = handle;
30545749Smckusick 	pager->pg_ops = &swappagerops;
30645749Smckusick 	pager->pg_type = PG_SWAP;
30765682Shibler 	pager->pg_flags = PG_CLUSTERPUT;
30864860Shibler 	pager->pg_data = swp;
30945749Smckusick 
31045749Smckusick #ifdef DEBUG
31145749Smckusick 	if (swpagerdebug & SDB_ALLOC)
31245749Smckusick 		printf("swpg_alloc: pg_data %x, %x of %x at %x\n",
31345749Smckusick 		       swp, swp->sw_nblocks, swp->sw_bsize, swp->sw_blocks);
31445749Smckusick #endif
31545749Smckusick 	return(pager);
31645749Smckusick }
31745749Smckusick 
31853341Sbostic static void
swap_pager_dealloc(pager)31945749Smckusick swap_pager_dealloc(pager)
32045749Smckusick 	vm_pager_t pager;
32145749Smckusick {
32245749Smckusick 	register int i;
32345749Smckusick 	register sw_blk_t bp;
32445749Smckusick 	register sw_pager_t swp;
32545749Smckusick 	struct swtab *swt;
32645749Smckusick 	int s;
32745749Smckusick 
32845749Smckusick #ifdef DEBUG
32945749Smckusick 	/* save panic time state */
33045749Smckusick 	if ((swpagerdebug & SDB_ANOMPANIC) && panicstr)
33145749Smckusick 		return;
33245749Smckusick 	if (swpagerdebug & (SDB_FOLLOW|SDB_ALLOC))
33345749Smckusick 		printf("swpg_dealloc(%x)\n", pager);
33445749Smckusick #endif
33545749Smckusick 	/*
33645749Smckusick 	 * Remove from list right away so lookups will fail if we
33745749Smckusick 	 * block for pageout completion.
33845749Smckusick 	 */
33945749Smckusick 	swp = (sw_pager_t) pager->pg_data;
34045749Smckusick 	if (swp->sw_flags & SW_NAMED) {
34165231Smckusick 		TAILQ_REMOVE(&swap_pager_list, pager, pg_list);
34245749Smckusick 		swp->sw_flags &= ~SW_NAMED;
34345749Smckusick 	}
34445749Smckusick #ifdef DEBUG
34545749Smckusick 	for (swt = swtab; swt->st_osize; swt++)
34645749Smckusick 		if (swp->sw_osize <= swt->st_osize)
34745749Smckusick 			break;
34845749Smckusick 	swt->st_inuse--;
34945749Smckusick #endif
35045749Smckusick 
35145749Smckusick 	/*
35245749Smckusick 	 * Wait for all pageouts to finish and remove
35345749Smckusick 	 * all entries from cleaning list.
35445749Smckusick 	 */
35545749Smckusick 	s = splbio();
35645749Smckusick 	while (swp->sw_poip) {
35745749Smckusick 		swp->sw_flags |= SW_WANTED;
35865682Shibler 		(void) tsleep(swp, PVM, "swpgdealloc", 0);
35945749Smckusick 	}
36045749Smckusick 	splx(s);
36165682Shibler 	swap_pager_clean(B_WRITE);
36245749Smckusick 
36345749Smckusick 	/*
36445749Smckusick 	 * Free left over swap blocks
36545749Smckusick 	 */
36645749Smckusick 	for (i = 0, bp = swp->sw_blocks; i < swp->sw_nblocks; i++, bp++)
36745749Smckusick 		if (bp->swb_block) {
36845749Smckusick #ifdef DEBUG
36945749Smckusick 			if (swpagerdebug & (SDB_ALLOCBLK|SDB_FULL))
37045749Smckusick 				printf("swpg_dealloc: blk %x\n",
37145749Smckusick 				       bp->swb_block);
37245749Smckusick #endif
37345749Smckusick 			rmfree(swapmap, swp->sw_bsize, bp->swb_block);
37445749Smckusick 		}
37545749Smckusick 	/*
37645749Smckusick 	 * Free swap management resources
37745749Smckusick 	 */
37845749Smckusick 	free((caddr_t)swp->sw_blocks, M_VMPGDATA);
37945749Smckusick 	free((caddr_t)swp, M_VMPGDATA);
38045749Smckusick 	free((caddr_t)pager, M_VMPAGER);
38145749Smckusick }
38245749Smckusick 
38353341Sbostic static int
swap_pager_getpage(pager,mlist,npages,sync)38465682Shibler swap_pager_getpage(pager, mlist, npages, sync)
38545749Smckusick 	vm_pager_t pager;
38665682Shibler 	vm_page_t *mlist;
38765682Shibler 	int npages;
38845749Smckusick 	boolean_t sync;
38945749Smckusick {
39045749Smckusick #ifdef DEBUG
39145749Smckusick 	if (swpagerdebug & SDB_FOLLOW)
39265682Shibler 		printf("swpg_getpage(%x, %x, %x, %x)\n",
39365682Shibler 		       pager, mlist, npages, sync);
39445749Smckusick #endif
39565682Shibler 	return(swap_pager_io((sw_pager_t)pager->pg_data,
39665682Shibler 			     mlist, npages, B_READ));
39745749Smckusick }
39845749Smckusick 
39953341Sbostic static int
swap_pager_putpage(pager,mlist,npages,sync)40065682Shibler swap_pager_putpage(pager, mlist, npages, sync)
40145749Smckusick 	vm_pager_t pager;
40265682Shibler 	vm_page_t *mlist;
40365682Shibler 	int npages;
40445749Smckusick 	boolean_t sync;
40545749Smckusick {
40645749Smckusick 	int flags;
40745749Smckusick 
40845749Smckusick #ifdef DEBUG
40945749Smckusick 	if (swpagerdebug & SDB_FOLLOW)
41065682Shibler 		printf("swpg_putpage(%x, %x, %x, %x)\n",
41165682Shibler 		       pager, mlist, npages, sync);
41245749Smckusick #endif
41348386Skarels 	if (pager == NULL) {
41465682Shibler 		swap_pager_clean(B_WRITE);
41554817Storek 		return (VM_PAGER_OK);		/* ??? */
41645749Smckusick 	}
41745749Smckusick 	flags = B_WRITE;
41845749Smckusick 	if (!sync)
41945749Smckusick 		flags |= B_ASYNC;
42065682Shibler 	return(swap_pager_io((sw_pager_t)pager->pg_data,
42165682Shibler 			     mlist, npages, flags));
42245749Smckusick }
42345749Smckusick 
42453341Sbostic static boolean_t
swap_pager_haspage(pager,offset)42545749Smckusick swap_pager_haspage(pager, offset)
42645749Smckusick 	vm_pager_t pager;
42745749Smckusick 	vm_offset_t offset;
42845749Smckusick {
42945749Smckusick 	register sw_pager_t swp;
43045749Smckusick 	register sw_blk_t swb;
43145749Smckusick 	int ix;
43245749Smckusick 
43345749Smckusick #ifdef DEBUG
43445749Smckusick 	if (swpagerdebug & (SDB_FOLLOW|SDB_ALLOCBLK))
43545749Smckusick 		printf("swpg_haspage(%x, %x) ", pager, offset);
43645749Smckusick #endif
43745749Smckusick 	swp = (sw_pager_t) pager->pg_data;
43845749Smckusick 	ix = offset / dbtob(swp->sw_bsize);
43945749Smckusick 	if (swp->sw_blocks == NULL || ix >= swp->sw_nblocks) {
44045749Smckusick #ifdef DEBUG
44145749Smckusick 		if (swpagerdebug & (SDB_FAIL|SDB_FOLLOW|SDB_ALLOCBLK))
44245749Smckusick 			printf("swpg_haspage: %x bad offset %x, ix %x\n",
44345749Smckusick 			       swp->sw_blocks, offset, ix);
44445749Smckusick #endif
44545749Smckusick 		return(FALSE);
44645749Smckusick 	}
44745749Smckusick 	swb = &swp->sw_blocks[ix];
44845749Smckusick 	if (swb->swb_block)
44945749Smckusick 		ix = atop(offset % dbtob(swp->sw_bsize));
45045749Smckusick #ifdef DEBUG
45145749Smckusick 	if (swpagerdebug & SDB_ALLOCBLK)
45245749Smckusick 		printf("%x blk %x+%x ", swp->sw_blocks, swb->swb_block, ix);
45345749Smckusick 	if (swpagerdebug & (SDB_FOLLOW|SDB_ALLOCBLK))
45445749Smckusick 		printf("-> %c\n",
45545749Smckusick 		       "FT"[swb->swb_block && (swb->swb_mask & (1 << ix))]);
45645749Smckusick #endif
45745749Smckusick 	if (swb->swb_block && (swb->swb_mask & (1 << ix)))
45845749Smckusick 		return(TRUE);
45945749Smckusick 	return(FALSE);
46045749Smckusick }
46145749Smckusick 
46265682Shibler static void
swap_pager_cluster(pager,offset,loffset,hoffset)46365682Shibler swap_pager_cluster(pager, offset, loffset, hoffset)
46465682Shibler 	vm_pager_t	pager;
46565682Shibler 	vm_offset_t	offset;
46665682Shibler 	vm_offset_t	*loffset;
46765682Shibler 	vm_offset_t	*hoffset;
46865682Shibler {
46965682Shibler 	sw_pager_t swp;
47065682Shibler 	register int bsize;
47165682Shibler 	vm_offset_t loff, hoff;
47265682Shibler 
47365682Shibler #ifdef DEBUG
47465682Shibler 	if (swpagerdebug & (SDB_FOLLOW|SDB_CLUSTER))
47565682Shibler 		printf("swpg_cluster(%x, %x) ", pager, offset);
47665682Shibler #endif
47765682Shibler 	swp = (sw_pager_t) pager->pg_data;
47865682Shibler 	bsize = dbtob(swp->sw_bsize);
47965682Shibler 	if (bsize > swap_pager_maxcluster)
48065682Shibler 		bsize = swap_pager_maxcluster;
48165682Shibler 
48265682Shibler 	loff = offset - (offset % bsize);
48365682Shibler 	if (loff >= swp->sw_osize)
48465682Shibler 		panic("swap_pager_cluster: bad offset");
48565682Shibler 
48665682Shibler 	hoff = loff + bsize;
48765682Shibler 	if (hoff > swp->sw_osize)
48865682Shibler 		hoff = swp->sw_osize;
48965682Shibler 
49065682Shibler 	*loffset = loff;
49165682Shibler 	*hoffset = hoff;
49265682Shibler #ifdef DEBUG
49365682Shibler 	if (swpagerdebug & (SDB_FOLLOW|SDB_CLUSTER))
49465682Shibler 		printf("returns [%x-%x]\n", loff, hoff);
49565682Shibler #endif
49665682Shibler }
49765682Shibler 
49845749Smckusick /*
49945749Smckusick  * Scaled down version of swap().
50045749Smckusick  * Assumes that PAGE_SIZE < MAXPHYS; i.e. only one operation needed.
50145749Smckusick  * BOGUS:  lower level IO routines expect a KVA so we have to map our
50245749Smckusick  * provided physical page into the KVA to keep them happy.
50345749Smckusick  */
50453341Sbostic static int
swap_pager_io(swp,mlist,npages,flags)50565682Shibler swap_pager_io(swp, mlist, npages, flags)
50645749Smckusick 	register sw_pager_t swp;
50765682Shibler 	vm_page_t *mlist;
50865682Shibler 	int npages;
50945749Smckusick 	int flags;
51045749Smckusick {
51145749Smckusick 	register struct buf *bp;
51245749Smckusick 	register sw_blk_t swb;
51345749Smckusick 	register int s;
51465682Shibler 	int ix, mask;
51545749Smckusick 	boolean_t rv;
51645749Smckusick 	vm_offset_t kva, off;
51745749Smckusick 	swp_clean_t spc;
51865682Shibler 	vm_page_t m;
51945749Smckusick 
52045749Smckusick #ifdef DEBUG
52145749Smckusick 	/* save panic time state */
52245749Smckusick 	if ((swpagerdebug & SDB_ANOMPANIC) && panicstr)
52353341Sbostic 		return (VM_PAGER_FAIL);		/* XXX: correct return? */
52445749Smckusick 	if (swpagerdebug & (SDB_FOLLOW|SDB_IO))
52565682Shibler 		printf("swpg_io(%x, %x, %x, %x)\n", swp, mlist, npages, flags);
52665682Shibler 	if (flags & B_READ) {
52765682Shibler 		if (flags & B_ASYNC)
52865682Shibler 			panic("swap_pager_io: cannot do ASYNC reads");
52965682Shibler 		if (npages != 1)
53065682Shibler 			panic("swap_pager_io: cannot do clustered reads");
53165682Shibler 	}
53245749Smckusick #endif
53345749Smckusick 
53445749Smckusick 	/*
53564860Shibler 	 * First determine if the page exists in the pager if this is
53664860Shibler 	 * a sync read.  This quickly handles cases where we are
53764860Shibler 	 * following shadow chains looking for the top level object
53864860Shibler 	 * with the page.
53964860Shibler 	 */
54065682Shibler 	m = *mlist;
54164860Shibler 	off = m->offset + m->object->paging_offset;
54264860Shibler 	ix = off / dbtob(swp->sw_bsize);
54365682Shibler 	if (swp->sw_blocks == NULL || ix >= swp->sw_nblocks) {
54465682Shibler #ifdef DEBUG
54565682Shibler 		if ((flags & B_READ) == 0 && (swpagerdebug & SDB_ANOM)) {
54665682Shibler 			printf("swap_pager_io: no swap block on write\n");
54765682Shibler 			return(VM_PAGER_BAD);
54865682Shibler 		}
54965682Shibler #endif
55064860Shibler 		return(VM_PAGER_FAIL);
55165682Shibler 	}
55264860Shibler 	swb = &swp->sw_blocks[ix];
55364860Shibler 	off = off % dbtob(swp->sw_bsize);
55464860Shibler 	if ((flags & B_READ) &&
55564860Shibler 	    (swb->swb_block == 0 || (swb->swb_mask & (1 << atop(off))) == 0))
55664860Shibler 		return(VM_PAGER_FAIL);
55764860Shibler 
55864860Shibler 	/*
55945749Smckusick 	 * For reads (pageins) and synchronous writes, we clean up
56049289Shibler 	 * all completed async pageouts.
56145749Smckusick 	 */
56245749Smckusick 	if ((flags & B_ASYNC) == 0) {
56345749Smckusick 		s = splbio();
56465682Shibler 		swap_pager_clean(flags&B_READ);
56549289Shibler #ifdef DEBUG
56665682Shibler 		if (swpagerdebug & SDB_PARANOIA)
56765682Shibler 			swap_pager_clean_check(mlist, npages, flags&B_READ);
56849289Shibler #endif
56945749Smckusick 		splx(s);
57045749Smckusick 	}
57145749Smckusick 	/*
57245749Smckusick 	 * For async writes (pageouts), we cleanup completed pageouts so
57345749Smckusick 	 * that all available resources are freed.  Also tells us if this
57445749Smckusick 	 * page is already being cleaned.  If it is, or no resources
57545749Smckusick 	 * are available, we try again later.
57645749Smckusick 	 */
57765682Shibler 	else {
57865682Shibler 		swap_pager_clean(B_WRITE);
57949289Shibler #ifdef DEBUG
58065682Shibler 		if (swpagerdebug & SDB_PARANOIA)
58165682Shibler 			swap_pager_clean_check(mlist, npages, B_WRITE);
58249289Shibler #endif
58365682Shibler 		if (swap_pager_free.tqh_first == NULL) {
58465682Shibler #ifdef DEBUG
58565682Shibler 			if (swpagerdebug & SDB_FAIL)
58665682Shibler 				printf("%s: no available io headers\n",
58765682Shibler 				       "swap_pager_io");
58865682Shibler #endif
58965682Shibler 			return(VM_PAGER_AGAIN);
59065682Shibler 		}
59149289Shibler 	}
59245749Smckusick 
59345749Smckusick 	/*
59464860Shibler 	 * Allocate a swap block if necessary.
59545749Smckusick 	 */
59664860Shibler 	if (swb->swb_block == 0) {
59745749Smckusick 		swb->swb_block = rmalloc(swapmap, swp->sw_bsize);
59845749Smckusick 		if (swb->swb_block == 0) {
59945749Smckusick #ifdef DEBUG
60045749Smckusick 			if (swpagerdebug & SDB_FAIL)
60145749Smckusick 				printf("swpg_io: rmalloc of %x failed\n",
60245749Smckusick 				       swp->sw_bsize);
60345749Smckusick #endif
60465682Shibler 			/*
60565682Shibler 			 * XXX this is technically a resource shortage that
60665682Shibler 			 * should return AGAIN, but the situation isn't likely
60765682Shibler 			 * to be remedied just by delaying a little while and
60865682Shibler 			 * trying again (the pageout daemon's current response
60965682Shibler 			 * to AGAIN) so we just return FAIL.
61065682Shibler 			 */
61145749Smckusick 			return(VM_PAGER_FAIL);
61245749Smckusick 		}
61345749Smckusick #ifdef DEBUG
61445749Smckusick 		if (swpagerdebug & (SDB_FULL|SDB_ALLOCBLK))
61545749Smckusick 			printf("swpg_io: %x alloc blk %x at ix %x\n",
61645749Smckusick 			       swp->sw_blocks, swb->swb_block, ix);
61745749Smckusick #endif
61845749Smckusick 	}
61945749Smckusick 
62045749Smckusick 	/*
62145749Smckusick 	 * Allocate a kernel virtual address and initialize so that PTE
62245749Smckusick 	 * is available for lower level IO drivers.
62345749Smckusick 	 */
62465682Shibler 	kva = vm_pager_map_pages(mlist, npages, !(flags & B_ASYNC));
62565682Shibler 	if (kva == NULL) {
62665682Shibler #ifdef DEBUG
62765682Shibler 		if (swpagerdebug & SDB_FAIL)
62865682Shibler 			printf("%s: no KVA space to map pages\n",
62965682Shibler 			       "swap_pager_io");
63065682Shibler #endif
63165682Shibler 		return(VM_PAGER_AGAIN);
63265682Shibler 	}
63345749Smckusick 
63445749Smckusick 	/*
63565682Shibler 	 * Get a swap buffer header and initialize it.
63645749Smckusick 	 */
63745749Smckusick 	s = splbio();
63856393Smckusick 	while (bswlist.b_actf == NULL) {
63945749Smckusick #ifdef DEBUG
64045749Smckusick 		if (swpagerdebug & SDB_ANOM)
64149289Shibler 			printf("swap_pager_io: wait on swbuf for %x (%d)\n",
64245749Smckusick 			       m, flags);
64345749Smckusick #endif
64445749Smckusick 		bswlist.b_flags |= B_WANTED;
64565682Shibler 		tsleep((caddr_t)&bswlist, PSWP+1, "swpgiobuf", 0);
64645749Smckusick 	}
64756393Smckusick 	bp = bswlist.b_actf;
64856393Smckusick 	bswlist.b_actf = bp->b_actf;
64945749Smckusick 	splx(s);
65045749Smckusick 	bp->b_flags = B_BUSY | (flags & B_READ);
65148386Skarels 	bp->b_proc = &proc0;	/* XXX (but without B_PHYS set this is ok) */
65264546Sbostic 	bp->b_data = (caddr_t)kva;
65345749Smckusick 	bp->b_blkno = swb->swb_block + btodb(off);
65445749Smckusick 	VHOLD(swapdev_vp);
65545749Smckusick 	bp->b_vp = swapdev_vp;
65646985Smckusick 	if (swapdev_vp->v_type == VBLK)
65746985Smckusick 		bp->b_dev = swapdev_vp->v_rdev;
65865682Shibler 	bp->b_bcount = npages * PAGE_SIZE;
65965682Shibler 
66065682Shibler 	/*
66165682Shibler 	 * For writes we set up additional buffer fields, record a pageout
66265682Shibler 	 * in progress and mark that these swap blocks are now allocated.
66365682Shibler 	 */
66453213Smckusick 	if ((bp->b_flags & B_READ) == 0) {
66553213Smckusick 		bp->b_dirtyoff = 0;
66665682Shibler 		bp->b_dirtyend = npages * PAGE_SIZE;
66745749Smckusick 		swapdev_vp->v_numoutput++;
66865682Shibler 		s = splbio();
66965682Shibler 		swp->sw_poip++;
67065682Shibler 		splx(s);
67165682Shibler 		mask = (~(~0 << npages)) << atop(off);
67265682Shibler #ifdef DEBUG
67365682Shibler 		swap_pager_poip++;
67465682Shibler 		if (swpagerdebug & SDB_WRITE)
67565682Shibler 			printf("swpg_io: write: bp=%x swp=%x poip=%d\n",
67665682Shibler 			       bp, swp, swp->sw_poip);
67765682Shibler 		if ((swpagerdebug & SDB_ALLOCBLK) &&
67865682Shibler 		    (swb->swb_mask & mask) != mask)
67965682Shibler 			printf("swpg_io: %x write %d pages at %x+%x\n",
68065682Shibler 			       swp->sw_blocks, npages, swb->swb_block,
68165682Shibler 			       atop(off));
68265682Shibler 		if (swpagerdebug & SDB_CLUSTER)
68365682Shibler 			printf("swpg_io: off=%x, npg=%x, mask=%x, bmask=%x\n",
68465682Shibler 			       off, npages, mask, swb->swb_mask);
68565682Shibler #endif
68665682Shibler 		swb->swb_mask |= mask;
68753213Smckusick 	}
68845749Smckusick 	/*
68965682Shibler 	 * If this is an async write we set up still more buffer fields
69045749Smckusick 	 * and place a "cleaning" entry on the inuse queue.
69145749Smckusick 	 */
69245749Smckusick 	if ((flags & (B_READ|B_ASYNC)) == B_ASYNC) {
69345749Smckusick #ifdef DEBUG
69465231Smckusick 		if (swap_pager_free.tqh_first == NULL)
69545749Smckusick 			panic("swpg_io: lost spc");
69645749Smckusick #endif
69765231Smckusick 		spc = swap_pager_free.tqh_first;
69865231Smckusick 		TAILQ_REMOVE(&swap_pager_free, spc, spc_list);
69945749Smckusick #ifdef DEBUG
70045749Smckusick 		if (spc->spc_flags != SPC_FREE)
70145749Smckusick 			panic("swpg_io: bad free spc");
70245749Smckusick #endif
70345749Smckusick 		spc->spc_flags = SPC_BUSY;
70445749Smckusick 		spc->spc_bp = bp;
70545749Smckusick 		spc->spc_swp = swp;
70645749Smckusick 		spc->spc_kva = kva;
70765682Shibler 		/*
70865723Shibler 		 * Record the first page.  This allows swap_pager_clean
70965682Shibler 		 * to efficiently handle the common case of a single page.
71065682Shibler 		 * For clusters, it allows us to locate the object easily
71165682Shibler 		 * and we then reconstruct the rest of the mlist from spc_kva.
71265682Shibler 		 */
71345749Smckusick 		spc->spc_m = m;
71465682Shibler 		spc->spc_npages = npages;
71545749Smckusick 		bp->b_flags |= B_CALL;
71645749Smckusick 		bp->b_iodone = swap_pager_iodone;
71745749Smckusick 		s = splbio();
71865231Smckusick 		TAILQ_INSERT_TAIL(&swap_pager_inuse, spc, spc_list);
71945749Smckusick 		splx(s);
72045749Smckusick 	}
72165682Shibler 
72265682Shibler 	/*
72365682Shibler 	 * Finally, start the IO operation.
72465682Shibler 	 * If it is async we are all done, otherwise we must wait for
72565682Shibler 	 * completion and cleanup afterwards.
72665682Shibler 	 */
72745749Smckusick #ifdef DEBUG
72845749Smckusick 	if (swpagerdebug & SDB_IO)
72945749Smckusick 		printf("swpg_io: IO start: bp %x, db %x, va %x, pa %x\n",
73045749Smckusick 		       bp, swb->swb_block+btodb(off), kva, VM_PAGE_TO_PHYS(m));
73145749Smckusick #endif
73245749Smckusick 	VOP_STRATEGY(bp);
73345749Smckusick 	if ((flags & (B_READ|B_ASYNC)) == B_ASYNC) {
73445749Smckusick #ifdef DEBUG
73545749Smckusick 		if (swpagerdebug & SDB_IO)
73645749Smckusick 			printf("swpg_io:  IO started: bp %x\n", bp);
73745749Smckusick #endif
73845749Smckusick 		return(VM_PAGER_PEND);
73945749Smckusick 	}
74045749Smckusick 	s = splbio();
74145749Smckusick #ifdef DEBUG
74245749Smckusick 	if (flags & B_READ)
74345749Smckusick 		swap_pager_piip++;
74445749Smckusick 	else
74545749Smckusick 		swap_pager_poip++;
74645749Smckusick #endif
74765682Shibler 	while ((bp->b_flags & B_DONE) == 0)
74865682Shibler 		(void) tsleep(bp, PVM, "swpgio", 0);
74965682Shibler 	if ((flags & B_READ) == 0)
75065682Shibler 		--swp->sw_poip;
75145749Smckusick #ifdef DEBUG
75245749Smckusick 	if (flags & B_READ)
75345749Smckusick 		--swap_pager_piip;
75445749Smckusick 	else
75545749Smckusick 		--swap_pager_poip;
75645749Smckusick #endif
75756320Shibler 	rv = (bp->b_flags & B_ERROR) ? VM_PAGER_ERROR : VM_PAGER_OK;
75845749Smckusick 	bp->b_flags &= ~(B_BUSY|B_WANTED|B_PHYS|B_PAGET|B_UAREA|B_DIRTY);
75956393Smckusick 	bp->b_actf = bswlist.b_actf;
76056393Smckusick 	bswlist.b_actf = bp;
76145749Smckusick 	if (bp->b_vp)
76245749Smckusick 		brelvp(bp);
76345749Smckusick 	if (bswlist.b_flags & B_WANTED) {
76445749Smckusick 		bswlist.b_flags &= ~B_WANTED;
76565682Shibler 		wakeup(&bswlist);
76645749Smckusick 	}
76745749Smckusick 	if ((flags & B_READ) == 0 && rv == VM_PAGER_OK) {
76856382Smckusick 		m->flags |= PG_CLEAN;
76945749Smckusick 		pmap_clear_modify(VM_PAGE_TO_PHYS(m));
77045749Smckusick 	}
77145749Smckusick 	splx(s);
77245749Smckusick #ifdef DEBUG
77345749Smckusick 	if (swpagerdebug & SDB_IO)
77445749Smckusick 		printf("swpg_io:  IO done: bp %x, rv %d\n", bp, rv);
77556320Shibler 	if ((swpagerdebug & SDB_FAIL) && rv == VM_PAGER_ERROR)
77645749Smckusick 		printf("swpg_io: IO error\n");
77745749Smckusick #endif
77865682Shibler 	vm_pager_unmap_pages(kva, npages);
77945749Smckusick 	return(rv);
78045749Smckusick }
78145749Smckusick 
78265682Shibler static void
swap_pager_clean(rw)78365682Shibler swap_pager_clean(rw)
78445749Smckusick 	int rw;
78545749Smckusick {
78665682Shibler 	register swp_clean_t spc;
78765682Shibler 	register int s, i;
78865682Shibler 	vm_object_t object;
78965682Shibler 	vm_page_t m;
79045749Smckusick 
79145749Smckusick #ifdef DEBUG
79245749Smckusick 	/* save panic time state */
79345749Smckusick 	if ((swpagerdebug & SDB_ANOMPANIC) && panicstr)
79465682Shibler 		return;
79545749Smckusick 	if (swpagerdebug & SDB_FOLLOW)
79665682Shibler 		printf("swpg_clean(%x)\n", rw);
79745749Smckusick #endif
79865682Shibler 
79945749Smckusick 	for (;;) {
80045749Smckusick 		/*
80145749Smckusick 		 * Look up and removal from inuse list must be done
80245749Smckusick 		 * at splbio() to avoid conflicts with swap_pager_iodone.
80345749Smckusick 		 */
80445749Smckusick 		s = splbio();
80565231Smckusick 		for (spc = swap_pager_inuse.tqh_first;
80665231Smckusick 		     spc != NULL;
80765231Smckusick 		     spc = spc->spc_list.tqe_next) {
80865682Shibler 			/*
80965682Shibler 			 * If the operation is done, remove it from the
81065682Shibler 			 * list and process it.
81165682Shibler 			 *
81265682Shibler 			 * XXX if we can't get the object lock we also
81365682Shibler 			 * leave it on the list and try again later.
81465682Shibler 			 * Is there something better we could do?
81565682Shibler 			 */
81645749Smckusick 			if ((spc->spc_flags & SPC_DONE) &&
81765682Shibler 			    vm_object_lock_try(spc->spc_m->object)) {
81865231Smckusick 				TAILQ_REMOVE(&swap_pager_inuse, spc, spc_list);
81945749Smckusick 				break;
82045749Smckusick 			}
82145749Smckusick 		}
822*66424Shibler 		splx(s);
82345749Smckusick 
82445749Smckusick 		/*
82545749Smckusick 		 * No operations done, thats all we can do for now.
82645749Smckusick 		 */
827*66424Shibler 		if (spc == NULL)
82845749Smckusick 			break;
82945749Smckusick 
83045749Smckusick 		/*
83165682Shibler 		 * Found a completed operation so finish it off.
83265682Shibler 		 * Note: no longer at splbio since entry is off the list.
83345749Smckusick 		 */
83465682Shibler 		m = spc->spc_m;
83565682Shibler 		object = m->object;
83665682Shibler 
83765682Shibler 		/*
83865682Shibler 		 * Process each page in the cluster.
83965682Shibler 		 * The first page is explicitly kept in the cleaning
84065682Shibler 		 * entry, others must be reconstructed from the KVA.
84165682Shibler 		 */
84265682Shibler 		for (i = 0; i < spc->spc_npages; i++) {
84365682Shibler 			if (i)
84465682Shibler 				m = vm_pager_atop(spc->spc_kva + ptoa(i));
84565682Shibler 			/*
84665682Shibler 			 * If no error mark as clean and inform the pmap
84765682Shibler 			 * system.  If there was an error, mark as dirty
84865682Shibler 			 * so we will try again.
84965682Shibler 			 *
85065682Shibler 			 * XXX could get stuck doing this, should give up
85165682Shibler 			 * after awhile.
85265682Shibler 			 */
85365682Shibler 			if (spc->spc_flags & SPC_ERROR) {
85465682Shibler 				printf("%s: clean of page %x failed\n",
85565682Shibler 				       "swap_pager_clean",
85665682Shibler 				       VM_PAGE_TO_PHYS(m));
85765682Shibler 				m->flags |= PG_LAUNDRY;
85865682Shibler 			} else {
85965682Shibler 				m->flags |= PG_CLEAN;
86065682Shibler 				pmap_clear_modify(VM_PAGE_TO_PHYS(m));
86165682Shibler 			}
86265682Shibler 			m->flags &= ~PG_BUSY;
86365682Shibler 			PAGE_WAKEUP(m);
86445749Smckusick 		}
86565682Shibler 
86665682Shibler 		/*
86765682Shibler 		 * Done with the object, decrement the paging count
86865682Shibler 		 * and unlock it.
86965682Shibler 		 */
87065682Shibler 		if (--object->paging_in_progress == 0)
87165682Shibler 			wakeup(object);
87265682Shibler 		vm_object_unlock(object);
87365682Shibler 
87465682Shibler 		/*
87565682Shibler 		 * Free up KVM used and put the entry back on the list.
87665682Shibler 		 */
87765682Shibler 		vm_pager_unmap_pages(spc->spc_kva, spc->spc_npages);
87845749Smckusick 		spc->spc_flags = SPC_FREE;
87965231Smckusick 		TAILQ_INSERT_TAIL(&swap_pager_free, spc, spc_list);
88045749Smckusick #ifdef DEBUG
88145749Smckusick 		if (swpagerdebug & SDB_WRITE)
88245749Smckusick 			printf("swpg_clean: free spc %x\n", spc);
88345749Smckusick #endif
88445749Smckusick 	}
88565682Shibler }
88645749Smckusick 
88745749Smckusick #ifdef DEBUG
88865682Shibler static void
swap_pager_clean_check(mlist,npages,rw)88965682Shibler swap_pager_clean_check(mlist, npages, rw)
89065682Shibler 	vm_page_t *mlist;
89165682Shibler 	int npages;
89265682Shibler 	int rw;
89365682Shibler {
89445749Smckusick 	register swp_clean_t spc;
89565682Shibler 	boolean_t bad;
89665682Shibler 	int i, j, s;
89765682Shibler 	vm_page_t m;
89845749Smckusick 
89965682Shibler 	if (panicstr)
90065682Shibler 		return;
90145749Smckusick 
90265682Shibler 	bad = FALSE;
90365682Shibler 	s = splbio();
90465682Shibler 	for (spc = swap_pager_inuse.tqh_first;
90565682Shibler 	     spc != NULL;
90665682Shibler 	     spc = spc->spc_list.tqe_next) {
90765682Shibler 		for (j = 0; j < spc->spc_npages; j++) {
90865682Shibler 			m = vm_pager_atop(spc->spc_kva + ptoa(j));
90965682Shibler 			for (i = 0; i < npages; i++)
91065682Shibler 				if (m == mlist[i]) {
91165682Shibler 					if (swpagerdebug & SDB_ANOM)
91265682Shibler 						printf(
91365682Shibler 		"swpg_clean_check: %s: page %x on list, flags %x\n",
91465682Shibler 		rw == B_WRITE ? "write" : "read", mlist[i], spc->spc_flags);
91565682Shibler 					bad = TRUE;
91665682Shibler 				}
91765682Shibler 		}
91845749Smckusick 	}
91965682Shibler 	splx(s);
92065682Shibler 	if (bad)
92165682Shibler 		panic("swpg_clean_check");
92265682Shibler }
92349289Shibler #endif
92445749Smckusick 
92553341Sbostic static void
swap_pager_iodone(bp)92645749Smckusick swap_pager_iodone(bp)
92745749Smckusick 	register struct buf *bp;
92845749Smckusick {
92945749Smckusick 	register swp_clean_t spc;
93045749Smckusick 	daddr_t blk;
93145749Smckusick 	int s;
93245749Smckusick 
93345749Smckusick #ifdef DEBUG
93445749Smckusick 	/* save panic time state */
93545749Smckusick 	if ((swpagerdebug & SDB_ANOMPANIC) && panicstr)
93645749Smckusick 		return;
93745749Smckusick 	if (swpagerdebug & SDB_FOLLOW)
93845749Smckusick 		printf("swpg_iodone(%x)\n", bp);
93945749Smckusick #endif
94045749Smckusick 	s = splbio();
94165231Smckusick 	for (spc = swap_pager_inuse.tqh_first;
94265231Smckusick 	     spc != NULL;
94365231Smckusick 	     spc = spc->spc_list.tqe_next)
94445749Smckusick 		if (spc->spc_bp == bp)
94545749Smckusick 			break;
94645749Smckusick #ifdef DEBUG
94765231Smckusick 	if (spc == NULL)
94849289Shibler 		panic("swap_pager_iodone: bp not found");
94945749Smckusick #endif
95045749Smckusick 
95145749Smckusick 	spc->spc_flags &= ~SPC_BUSY;
95245749Smckusick 	spc->spc_flags |= SPC_DONE;
95345749Smckusick 	if (bp->b_flags & B_ERROR)
95445749Smckusick 		spc->spc_flags |= SPC_ERROR;
95545749Smckusick 	spc->spc_bp = NULL;
95645749Smckusick 	blk = bp->b_blkno;
95745749Smckusick 
95845749Smckusick #ifdef DEBUG
95945749Smckusick 	--swap_pager_poip;
96045749Smckusick 	if (swpagerdebug & SDB_WRITE)
96145749Smckusick 		printf("swpg_iodone: bp=%x swp=%x flags=%x spc=%x poip=%x\n",
96245749Smckusick 		       bp, spc->spc_swp, spc->spc_swp->sw_flags,
96345749Smckusick 		       spc, spc->spc_swp->sw_poip);
96445749Smckusick #endif
96545749Smckusick 
96645749Smckusick 	spc->spc_swp->sw_poip--;
96745749Smckusick 	if (spc->spc_swp->sw_flags & SW_WANTED) {
96845749Smckusick 		spc->spc_swp->sw_flags &= ~SW_WANTED;
96965682Shibler 		wakeup(spc->spc_swp);
97045749Smckusick 	}
97145749Smckusick 
97245749Smckusick 	bp->b_flags &= ~(B_BUSY|B_WANTED|B_PHYS|B_PAGET|B_UAREA|B_DIRTY);
97356393Smckusick 	bp->b_actf = bswlist.b_actf;
97456393Smckusick 	bswlist.b_actf = bp;
97545749Smckusick 	if (bp->b_vp)
97645749Smckusick 		brelvp(bp);
97745749Smckusick 	if (bswlist.b_flags & B_WANTED) {
97845749Smckusick 		bswlist.b_flags &= ~B_WANTED;
97965682Shibler 		wakeup(&bswlist);
98045749Smckusick 	}
98165682Shibler 	wakeup(&vm_pages_needed);
98245749Smckusick 	splx(s);
98345749Smckusick }
984