xref: /csrg-svn/sys/vm/swap_pager.c (revision 65682)
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*65682Shibler  *	@(#)swap_pager.c	8.6 (Berkeley) 01/12/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 */
40*65682Shibler #define MAXDADDRS	64	/* max # of disk addrs for fixed allocations */
41*65682Shibler #ifndef NPENDINGIO
4245749Smckusick #define NPENDINGIO	64	/* max # of pending cleans */
43*65682Shibler #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
57*65682Shibler #define SDB_CLUSTER	0x400
58*65682Shibler #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;
70*65682Shibler 	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 
94*65682Shibler int		swap_pager_maxcluster;	/* maximum cluster size */
95*65682Shibler int		swap_pager_npendingio;	/* number of pager clean structs */
96*65682Shibler 
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 int		swap_pager_finish __P((swp_clean_t));
10253341Sbostic static void 		swap_pager_init __P((void));
10364827Storek static vm_pager_t	swap_pager_alloc
10464827Storek 			    __P((caddr_t, vm_size_t, vm_prot_t, vm_offset_t));
105*65682Shibler static void		swap_pager_clean __P((int));
106*65682Shibler #ifdef DEBUG
107*65682Shibler static void		swap_pager_clean_check __P((vm_page_t *, int, int));
108*65682Shibler #endif
109*65682Shibler static void		swap_pager_cluster
110*65682Shibler 			    __P((vm_pager_t, vm_offset_t,
111*65682Shibler 				 vm_offset_t *, vm_offset_t *));
11253341Sbostic static void		swap_pager_dealloc __P((vm_pager_t));
11353341Sbostic static int		swap_pager_getpage
114*65682Shibler 			    __P((vm_pager_t, vm_page_t *, int, boolean_t));
11553341Sbostic static boolean_t	swap_pager_haspage __P((vm_pager_t, vm_offset_t));
116*65682Shibler static int		swap_pager_io __P((sw_pager_t, vm_page_t *, int, int));
11753341Sbostic static void		swap_pager_iodone __P((struct buf *));
11853341Sbostic static int		swap_pager_putpage
119*65682Shibler 			    __P((vm_pager_t, vm_page_t *, int, boolean_t));
12053341Sbostic 
12153341Sbostic struct pagerops swappagerops = {
12253341Sbostic 	swap_pager_init,
12353341Sbostic 	swap_pager_alloc,
12453341Sbostic 	swap_pager_dealloc,
12553341Sbostic 	swap_pager_getpage,
12653341Sbostic 	swap_pager_putpage,
127*65682Shibler 	swap_pager_haspage,
128*65682Shibler 	swap_pager_cluster
12953341Sbostic };
13053341Sbostic 
13153341Sbostic static void
13245749Smckusick swap_pager_init()
13345749Smckusick {
13445749Smckusick 	register swp_clean_t spc;
13545749Smckusick 	register int i, bsize;
13645749Smckusick 	extern int dmmin, dmmax;
13745749Smckusick 	int maxbsize;
13845749Smckusick 
13945749Smckusick #ifdef DEBUG
14045749Smckusick 	if (swpagerdebug & (SDB_FOLLOW|SDB_INIT))
14145749Smckusick 		printf("swpg_init()\n");
14245749Smckusick #endif
14345749Smckusick 	dfltpagerops = &swappagerops;
14465231Smckusick 	TAILQ_INIT(&swap_pager_list);
14545749Smckusick 
14645749Smckusick 	/*
147*65682Shibler 	 * Allocate async IO structures.
148*65682Shibler 	 *
149*65682Shibler 	 * XXX it would be nice if we could do this dynamically based on
150*65682Shibler 	 * the value of nswbuf (since we are ultimately limited by that)
151*65682Shibler 	 * but neither nswbuf or malloc has been initialized yet.  So the
152*65682Shibler 	 * structs are statically allocated above.
153*65682Shibler 	 */
154*65682Shibler 	swap_pager_npendingio = NPENDINGIO;
155*65682Shibler 
156*65682Shibler 	/*
15745749Smckusick 	 * Initialize clean lists
15845749Smckusick 	 */
15965231Smckusick 	TAILQ_INIT(&swap_pager_inuse);
16065231Smckusick 	TAILQ_INIT(&swap_pager_free);
161*65682Shibler 	for (i = 0, spc = swcleanlist; i < swap_pager_npendingio; i++, spc++) {
16265231Smckusick 		TAILQ_INSERT_TAIL(&swap_pager_free, spc, spc_list);
16345749Smckusick 		spc->spc_flags = SPC_FREE;
16445749Smckusick 	}
16545749Smckusick 
16645749Smckusick 	/*
16745749Smckusick 	 * Calculate the swap allocation constants.
16845749Smckusick 	 */
16945749Smckusick         if (dmmin == 0) {
17045749Smckusick                 dmmin = DMMIN;
17145749Smckusick 		if (dmmin < CLBYTES/DEV_BSIZE)
17245749Smckusick 			dmmin = CLBYTES/DEV_BSIZE;
17345749Smckusick 	}
17445749Smckusick         if (dmmax == 0)
17545749Smckusick                 dmmax = DMMAX;
17645749Smckusick 
17745749Smckusick 	/*
17845749Smckusick 	 * Fill in our table of object size vs. allocation size
17945749Smckusick 	 */
18045749Smckusick 	bsize = btodb(PAGE_SIZE);
18145749Smckusick 	if (bsize < dmmin)
18245749Smckusick 		bsize = dmmin;
18345749Smckusick 	maxbsize = btodb(sizeof(sw_bm_t) * NBBY * PAGE_SIZE);
18445749Smckusick 	if (maxbsize > dmmax)
18545749Smckusick 		maxbsize = dmmax;
18645749Smckusick 	for (i = 0; i < NSWSIZES; i++) {
18745749Smckusick 		swtab[i].st_osize = (vm_size_t) (MAXDADDRS * dbtob(bsize));
18845749Smckusick 		swtab[i].st_bsize = bsize;
189*65682Shibler 		if (bsize <= btodb(MAXPHYS))
190*65682Shibler 			swap_pager_maxcluster = dbtob(bsize);
19145749Smckusick #ifdef DEBUG
19245749Smckusick 		if (swpagerdebug & SDB_INIT)
19345749Smckusick 			printf("swpg_init: ix %d, size %x, bsize %x\n",
19445749Smckusick 			       i, swtab[i].st_osize, swtab[i].st_bsize);
19545749Smckusick #endif
19645749Smckusick 		if (bsize >= maxbsize)
19745749Smckusick 			break;
19845749Smckusick 		bsize *= 2;
19945749Smckusick 	}
20045749Smckusick 	swtab[i].st_osize = 0;
20145749Smckusick 	swtab[i].st_bsize = bsize;
20245749Smckusick }
20345749Smckusick 
20445749Smckusick /*
20545749Smckusick  * Allocate a pager structure and associated resources.
20645749Smckusick  * Note that if we are called from the pageout daemon (handle == NULL)
20745749Smckusick  * we should not wait for memory as it could resulting in deadlock.
20845749Smckusick  */
20953341Sbostic static vm_pager_t
21064827Storek swap_pager_alloc(handle, size, prot, foff)
21145749Smckusick 	caddr_t handle;
21245749Smckusick 	register vm_size_t size;
21345749Smckusick 	vm_prot_t prot;
21464827Storek 	vm_offset_t foff;
21545749Smckusick {
21645749Smckusick 	register vm_pager_t pager;
21745749Smckusick 	register sw_pager_t swp;
21845749Smckusick 	struct swtab *swt;
21945749Smckusick 	int waitok;
22045749Smckusick 
22145749Smckusick #ifdef DEBUG
22245749Smckusick 	if (swpagerdebug & (SDB_FOLLOW|SDB_ALLOC))
22345749Smckusick 		printf("swpg_alloc(%x, %x, %x)\n", handle, size, prot);
22445749Smckusick #endif
22545749Smckusick 	/*
22645749Smckusick 	 * If this is a "named" anonymous region, look it up and
22745749Smckusick 	 * return the appropriate pager if it exists.
22845749Smckusick 	 */
22945749Smckusick 	if (handle) {
23045749Smckusick 		pager = vm_pager_lookup(&swap_pager_list, handle);
23148386Skarels 		if (pager != NULL) {
23245749Smckusick 			/*
23345749Smckusick 			 * Use vm_object_lookup to gain a reference
23445749Smckusick 			 * to the object and also to remove from the
23545749Smckusick 			 * object cache.
23645749Smckusick 			 */
23748386Skarels 			if (vm_object_lookup(pager) == NULL)
23845749Smckusick 				panic("swap_pager_alloc: bad object");
23945749Smckusick 			return(pager);
24045749Smckusick 		}
24145749Smckusick 	}
24245749Smckusick 	/*
24345749Smckusick 	 * Pager doesn't exist, allocate swap management resources
24445749Smckusick 	 * and initialize.
24545749Smckusick 	 */
24645749Smckusick 	waitok = handle ? M_WAITOK : M_NOWAIT;
24745749Smckusick 	pager = (vm_pager_t)malloc(sizeof *pager, M_VMPAGER, waitok);
24848386Skarels 	if (pager == NULL)
24948386Skarels 		return(NULL);
25045749Smckusick 	swp = (sw_pager_t)malloc(sizeof *swp, M_VMPGDATA, waitok);
25145749Smckusick 	if (swp == NULL) {
25245749Smckusick #ifdef DEBUG
25345749Smckusick 		if (swpagerdebug & SDB_FAIL)
25445749Smckusick 			printf("swpg_alloc: swpager malloc failed\n");
25545749Smckusick #endif
25645749Smckusick 		free((caddr_t)pager, M_VMPAGER);
25748386Skarels 		return(NULL);
25845749Smckusick 	}
25945749Smckusick 	size = round_page(size);
26045749Smckusick 	for (swt = swtab; swt->st_osize; swt++)
26145749Smckusick 		if (size <= swt->st_osize)
26245749Smckusick 			break;
26345749Smckusick #ifdef DEBUG
26445749Smckusick 	swt->st_inuse++;
26545749Smckusick 	swt->st_usecnt++;
26645749Smckusick #endif
26745749Smckusick 	swp->sw_osize = size;
26845749Smckusick 	swp->sw_bsize = swt->st_bsize;
26945749Smckusick 	swp->sw_nblocks = (btodb(size) + swp->sw_bsize - 1) / swp->sw_bsize;
27045749Smckusick 	swp->sw_blocks = (sw_blk_t)
27145749Smckusick 		malloc(swp->sw_nblocks*sizeof(*swp->sw_blocks),
27245749Smckusick 		       M_VMPGDATA, M_NOWAIT);
27345749Smckusick 	if (swp->sw_blocks == NULL) {
27445749Smckusick 		free((caddr_t)swp, M_VMPGDATA);
27545749Smckusick 		free((caddr_t)pager, M_VMPAGER);
27645749Smckusick #ifdef DEBUG
27745749Smckusick 		if (swpagerdebug & SDB_FAIL)
27845749Smckusick 			printf("swpg_alloc: sw_blocks malloc failed\n");
27945749Smckusick 		swt->st_inuse--;
28045749Smckusick 		swt->st_usecnt--;
28145749Smckusick #endif
28245749Smckusick 		return(FALSE);
28345749Smckusick 	}
28445749Smckusick 	bzero((caddr_t)swp->sw_blocks,
28545749Smckusick 	      swp->sw_nblocks * sizeof(*swp->sw_blocks));
28645749Smckusick 	swp->sw_poip = 0;
28745749Smckusick 	if (handle) {
28845749Smckusick 		vm_object_t object;
28945749Smckusick 
29045749Smckusick 		swp->sw_flags = SW_NAMED;
29165231Smckusick 		TAILQ_INSERT_TAIL(&swap_pager_list, pager, pg_list);
29245749Smckusick 		/*
29345749Smckusick 		 * Consistant with other pagers: return with object
29445749Smckusick 		 * referenced.  Can't do this with handle == NULL
29545749Smckusick 		 * since it might be the pageout daemon calling.
29645749Smckusick 		 */
29745749Smckusick 		object = vm_object_allocate(size);
29845749Smckusick 		vm_object_enter(object, pager);
29945749Smckusick 		vm_object_setpager(object, pager, 0, FALSE);
30045749Smckusick 	} else {
30145749Smckusick 		swp->sw_flags = 0;
30265231Smckusick 		pager->pg_list.tqe_next = NULL;
30365231Smckusick 		pager->pg_list.tqe_prev = NULL;
30445749Smckusick 	}
30545749Smckusick 	pager->pg_handle = handle;
30645749Smckusick 	pager->pg_ops = &swappagerops;
30745749Smckusick 	pager->pg_type = PG_SWAP;
308*65682Shibler 	pager->pg_flags = PG_CLUSTERPUT;
30964860Shibler 	pager->pg_data = swp;
31045749Smckusick 
31145749Smckusick #ifdef DEBUG
31245749Smckusick 	if (swpagerdebug & SDB_ALLOC)
31345749Smckusick 		printf("swpg_alloc: pg_data %x, %x of %x at %x\n",
31445749Smckusick 		       swp, swp->sw_nblocks, swp->sw_bsize, swp->sw_blocks);
31545749Smckusick #endif
31645749Smckusick 	return(pager);
31745749Smckusick }
31845749Smckusick 
31953341Sbostic static void
32045749Smckusick swap_pager_dealloc(pager)
32145749Smckusick 	vm_pager_t pager;
32245749Smckusick {
32345749Smckusick 	register int i;
32445749Smckusick 	register sw_blk_t bp;
32545749Smckusick 	register sw_pager_t swp;
32645749Smckusick 	struct swtab *swt;
32745749Smckusick 	int s;
32845749Smckusick 
32945749Smckusick #ifdef DEBUG
33045749Smckusick 	/* save panic time state */
33145749Smckusick 	if ((swpagerdebug & SDB_ANOMPANIC) && panicstr)
33245749Smckusick 		return;
33345749Smckusick 	if (swpagerdebug & (SDB_FOLLOW|SDB_ALLOC))
33445749Smckusick 		printf("swpg_dealloc(%x)\n", pager);
33545749Smckusick #endif
33645749Smckusick 	/*
33745749Smckusick 	 * Remove from list right away so lookups will fail if we
33845749Smckusick 	 * block for pageout completion.
33945749Smckusick 	 */
34045749Smckusick 	swp = (sw_pager_t) pager->pg_data;
34145749Smckusick 	if (swp->sw_flags & SW_NAMED) {
34265231Smckusick 		TAILQ_REMOVE(&swap_pager_list, pager, pg_list);
34345749Smckusick 		swp->sw_flags &= ~SW_NAMED;
34445749Smckusick 	}
34545749Smckusick #ifdef DEBUG
34645749Smckusick 	for (swt = swtab; swt->st_osize; swt++)
34745749Smckusick 		if (swp->sw_osize <= swt->st_osize)
34845749Smckusick 			break;
34945749Smckusick 	swt->st_inuse--;
35045749Smckusick #endif
35145749Smckusick 
35245749Smckusick 	/*
35345749Smckusick 	 * Wait for all pageouts to finish and remove
35445749Smckusick 	 * all entries from cleaning list.
35545749Smckusick 	 */
35645749Smckusick 	s = splbio();
35745749Smckusick 	while (swp->sw_poip) {
35845749Smckusick 		swp->sw_flags |= SW_WANTED;
359*65682Shibler 		(void) tsleep(swp, PVM, "swpgdealloc", 0);
36045749Smckusick 	}
36145749Smckusick 	splx(s);
362*65682Shibler 	swap_pager_clean(B_WRITE);
36345749Smckusick 
36445749Smckusick 	/*
36545749Smckusick 	 * Free left over swap blocks
36645749Smckusick 	 */
36745749Smckusick 	for (i = 0, bp = swp->sw_blocks; i < swp->sw_nblocks; i++, bp++)
36845749Smckusick 		if (bp->swb_block) {
36945749Smckusick #ifdef DEBUG
37045749Smckusick 			if (swpagerdebug & (SDB_ALLOCBLK|SDB_FULL))
37145749Smckusick 				printf("swpg_dealloc: blk %x\n",
37245749Smckusick 				       bp->swb_block);
37345749Smckusick #endif
37445749Smckusick 			rmfree(swapmap, swp->sw_bsize, bp->swb_block);
37545749Smckusick 		}
37645749Smckusick 	/*
37745749Smckusick 	 * Free swap management resources
37845749Smckusick 	 */
37945749Smckusick 	free((caddr_t)swp->sw_blocks, M_VMPGDATA);
38045749Smckusick 	free((caddr_t)swp, M_VMPGDATA);
38145749Smckusick 	free((caddr_t)pager, M_VMPAGER);
38245749Smckusick }
38345749Smckusick 
38453341Sbostic static int
385*65682Shibler swap_pager_getpage(pager, mlist, npages, sync)
38645749Smckusick 	vm_pager_t pager;
387*65682Shibler 	vm_page_t *mlist;
388*65682Shibler 	int npages;
38945749Smckusick 	boolean_t sync;
39045749Smckusick {
39145749Smckusick #ifdef DEBUG
39245749Smckusick 	if (swpagerdebug & SDB_FOLLOW)
393*65682Shibler 		printf("swpg_getpage(%x, %x, %x, %x)\n",
394*65682Shibler 		       pager, mlist, npages, sync);
39545749Smckusick #endif
396*65682Shibler 	return(swap_pager_io((sw_pager_t)pager->pg_data,
397*65682Shibler 			     mlist, npages, B_READ));
39845749Smckusick }
39945749Smckusick 
40053341Sbostic static int
401*65682Shibler swap_pager_putpage(pager, mlist, npages, sync)
40245749Smckusick 	vm_pager_t pager;
403*65682Shibler 	vm_page_t *mlist;
404*65682Shibler 	int npages;
40545749Smckusick 	boolean_t sync;
40645749Smckusick {
40745749Smckusick 	int flags;
40845749Smckusick 
40945749Smckusick #ifdef DEBUG
41045749Smckusick 	if (swpagerdebug & SDB_FOLLOW)
411*65682Shibler 		printf("swpg_putpage(%x, %x, %x, %x)\n",
412*65682Shibler 		       pager, mlist, npages, sync);
41345749Smckusick #endif
41448386Skarels 	if (pager == NULL) {
415*65682Shibler 		swap_pager_clean(B_WRITE);
41654817Storek 		return (VM_PAGER_OK);		/* ??? */
41745749Smckusick 	}
41845749Smckusick 	flags = B_WRITE;
41945749Smckusick 	if (!sync)
42045749Smckusick 		flags |= B_ASYNC;
421*65682Shibler 	return(swap_pager_io((sw_pager_t)pager->pg_data,
422*65682Shibler 			     mlist, npages, flags));
42345749Smckusick }
42445749Smckusick 
42553341Sbostic static boolean_t
42645749Smckusick swap_pager_haspage(pager, offset)
42745749Smckusick 	vm_pager_t pager;
42845749Smckusick 	vm_offset_t offset;
42945749Smckusick {
43045749Smckusick 	register sw_pager_t swp;
43145749Smckusick 	register sw_blk_t swb;
43245749Smckusick 	int ix;
43345749Smckusick 
43445749Smckusick #ifdef DEBUG
43545749Smckusick 	if (swpagerdebug & (SDB_FOLLOW|SDB_ALLOCBLK))
43645749Smckusick 		printf("swpg_haspage(%x, %x) ", pager, offset);
43745749Smckusick #endif
43845749Smckusick 	swp = (sw_pager_t) pager->pg_data;
43945749Smckusick 	ix = offset / dbtob(swp->sw_bsize);
44045749Smckusick 	if (swp->sw_blocks == NULL || ix >= swp->sw_nblocks) {
44145749Smckusick #ifdef DEBUG
44245749Smckusick 		if (swpagerdebug & (SDB_FAIL|SDB_FOLLOW|SDB_ALLOCBLK))
44345749Smckusick 			printf("swpg_haspage: %x bad offset %x, ix %x\n",
44445749Smckusick 			       swp->sw_blocks, offset, ix);
44545749Smckusick #endif
44645749Smckusick 		return(FALSE);
44745749Smckusick 	}
44845749Smckusick 	swb = &swp->sw_blocks[ix];
44945749Smckusick 	if (swb->swb_block)
45045749Smckusick 		ix = atop(offset % dbtob(swp->sw_bsize));
45145749Smckusick #ifdef DEBUG
45245749Smckusick 	if (swpagerdebug & SDB_ALLOCBLK)
45345749Smckusick 		printf("%x blk %x+%x ", swp->sw_blocks, swb->swb_block, ix);
45445749Smckusick 	if (swpagerdebug & (SDB_FOLLOW|SDB_ALLOCBLK))
45545749Smckusick 		printf("-> %c\n",
45645749Smckusick 		       "FT"[swb->swb_block && (swb->swb_mask & (1 << ix))]);
45745749Smckusick #endif
45845749Smckusick 	if (swb->swb_block && (swb->swb_mask & (1 << ix)))
45945749Smckusick 		return(TRUE);
46045749Smckusick 	return(FALSE);
46145749Smckusick }
46245749Smckusick 
463*65682Shibler static void
464*65682Shibler swap_pager_cluster(pager, offset, loffset, hoffset)
465*65682Shibler 	vm_pager_t	pager;
466*65682Shibler 	vm_offset_t	offset;
467*65682Shibler 	vm_offset_t	*loffset;
468*65682Shibler 	vm_offset_t	*hoffset;
469*65682Shibler {
470*65682Shibler 	sw_pager_t swp;
471*65682Shibler 	register int bsize;
472*65682Shibler 	vm_offset_t loff, hoff;
473*65682Shibler 
474*65682Shibler #ifdef DEBUG
475*65682Shibler 	if (swpagerdebug & (SDB_FOLLOW|SDB_CLUSTER))
476*65682Shibler 		printf("swpg_cluster(%x, %x) ", pager, offset);
477*65682Shibler #endif
478*65682Shibler 	swp = (sw_pager_t) pager->pg_data;
479*65682Shibler 	bsize = dbtob(swp->sw_bsize);
480*65682Shibler 	if (bsize > swap_pager_maxcluster)
481*65682Shibler 		bsize = swap_pager_maxcluster;
482*65682Shibler 
483*65682Shibler 	loff = offset - (offset % bsize);
484*65682Shibler 	if (loff >= swp->sw_osize)
485*65682Shibler 		panic("swap_pager_cluster: bad offset");
486*65682Shibler 
487*65682Shibler 	hoff = loff + bsize;
488*65682Shibler 	if (hoff > swp->sw_osize)
489*65682Shibler 		hoff = swp->sw_osize;
490*65682Shibler 
491*65682Shibler 	*loffset = loff;
492*65682Shibler 	*hoffset = hoff;
493*65682Shibler #ifdef DEBUG
494*65682Shibler 	if (swpagerdebug & (SDB_FOLLOW|SDB_CLUSTER))
495*65682Shibler 		printf("returns [%x-%x]\n", loff, hoff);
496*65682Shibler #endif
497*65682Shibler }
498*65682Shibler 
49945749Smckusick /*
50045749Smckusick  * Scaled down version of swap().
50145749Smckusick  * Assumes that PAGE_SIZE < MAXPHYS; i.e. only one operation needed.
50245749Smckusick  * BOGUS:  lower level IO routines expect a KVA so we have to map our
50345749Smckusick  * provided physical page into the KVA to keep them happy.
50445749Smckusick  */
50553341Sbostic static int
506*65682Shibler swap_pager_io(swp, mlist, npages, flags)
50745749Smckusick 	register sw_pager_t swp;
508*65682Shibler 	vm_page_t *mlist;
509*65682Shibler 	int npages;
51045749Smckusick 	int flags;
51145749Smckusick {
51245749Smckusick 	register struct buf *bp;
51345749Smckusick 	register sw_blk_t swb;
51445749Smckusick 	register int s;
515*65682Shibler 	int ix, mask;
51645749Smckusick 	boolean_t rv;
51745749Smckusick 	vm_offset_t kva, off;
51845749Smckusick 	swp_clean_t spc;
519*65682Shibler 	vm_page_t m;
52045749Smckusick 
52145749Smckusick #ifdef DEBUG
52245749Smckusick 	/* save panic time state */
52345749Smckusick 	if ((swpagerdebug & SDB_ANOMPANIC) && panicstr)
52453341Sbostic 		return (VM_PAGER_FAIL);		/* XXX: correct return? */
52545749Smckusick 	if (swpagerdebug & (SDB_FOLLOW|SDB_IO))
526*65682Shibler 		printf("swpg_io(%x, %x, %x, %x)\n", swp, mlist, npages, flags);
527*65682Shibler 	if (flags & B_READ) {
528*65682Shibler 		if (flags & B_ASYNC)
529*65682Shibler 			panic("swap_pager_io: cannot do ASYNC reads");
530*65682Shibler 		if (npages != 1)
531*65682Shibler 			panic("swap_pager_io: cannot do clustered reads");
532*65682Shibler 	}
53345749Smckusick #endif
53445749Smckusick 
53545749Smckusick 	/*
53664860Shibler 	 * First determine if the page exists in the pager if this is
53764860Shibler 	 * a sync read.  This quickly handles cases where we are
53864860Shibler 	 * following shadow chains looking for the top level object
53964860Shibler 	 * with the page.
54064860Shibler 	 */
541*65682Shibler 	m = *mlist;
54264860Shibler 	off = m->offset + m->object->paging_offset;
54364860Shibler 	ix = off / dbtob(swp->sw_bsize);
544*65682Shibler 	if (swp->sw_blocks == NULL || ix >= swp->sw_nblocks) {
545*65682Shibler #ifdef DEBUG
546*65682Shibler 		if ((flags & B_READ) == 0 && (swpagerdebug & SDB_ANOM)) {
547*65682Shibler 			printf("swap_pager_io: no swap block on write\n");
548*65682Shibler 			return(VM_PAGER_BAD);
549*65682Shibler 		}
550*65682Shibler #endif
55164860Shibler 		return(VM_PAGER_FAIL);
552*65682Shibler 	}
55364860Shibler 	swb = &swp->sw_blocks[ix];
55464860Shibler 	off = off % dbtob(swp->sw_bsize);
55564860Shibler 	if ((flags & B_READ) &&
55664860Shibler 	    (swb->swb_block == 0 || (swb->swb_mask & (1 << atop(off))) == 0))
55764860Shibler 		return(VM_PAGER_FAIL);
55864860Shibler 
55964860Shibler 	/*
56045749Smckusick 	 * For reads (pageins) and synchronous writes, we clean up
56149289Shibler 	 * all completed async pageouts.
56245749Smckusick 	 */
56345749Smckusick 	if ((flags & B_ASYNC) == 0) {
56445749Smckusick 		s = splbio();
565*65682Shibler 		swap_pager_clean(flags&B_READ);
56649289Shibler #ifdef DEBUG
567*65682Shibler 		if (swpagerdebug & SDB_PARANOIA)
568*65682Shibler 			swap_pager_clean_check(mlist, npages, flags&B_READ);
56949289Shibler #endif
57045749Smckusick 		splx(s);
57145749Smckusick 	}
57245749Smckusick 	/*
57345749Smckusick 	 * For async writes (pageouts), we cleanup completed pageouts so
57445749Smckusick 	 * that all available resources are freed.  Also tells us if this
57545749Smckusick 	 * page is already being cleaned.  If it is, or no resources
57645749Smckusick 	 * are available, we try again later.
57745749Smckusick 	 */
578*65682Shibler 	else {
579*65682Shibler 		swap_pager_clean(B_WRITE);
58049289Shibler #ifdef DEBUG
581*65682Shibler 		if (swpagerdebug & SDB_PARANOIA)
582*65682Shibler 			swap_pager_clean_check(mlist, npages, B_WRITE);
58349289Shibler #endif
584*65682Shibler 		if (swap_pager_free.tqh_first == NULL) {
585*65682Shibler #ifdef DEBUG
586*65682Shibler 			if (swpagerdebug & SDB_FAIL)
587*65682Shibler 				printf("%s: no available io headers\n",
588*65682Shibler 				       "swap_pager_io");
589*65682Shibler #endif
590*65682Shibler 			return(VM_PAGER_AGAIN);
591*65682Shibler 		}
59249289Shibler 	}
59345749Smckusick 
59445749Smckusick 	/*
59564860Shibler 	 * Allocate a swap block if necessary.
59645749Smckusick 	 */
59764860Shibler 	if (swb->swb_block == 0) {
59845749Smckusick 		swb->swb_block = rmalloc(swapmap, swp->sw_bsize);
59945749Smckusick 		if (swb->swb_block == 0) {
60045749Smckusick #ifdef DEBUG
60145749Smckusick 			if (swpagerdebug & SDB_FAIL)
60245749Smckusick 				printf("swpg_io: rmalloc of %x failed\n",
60345749Smckusick 				       swp->sw_bsize);
60445749Smckusick #endif
605*65682Shibler 			/*
606*65682Shibler 			 * XXX this is technically a resource shortage that
607*65682Shibler 			 * should return AGAIN, but the situation isn't likely
608*65682Shibler 			 * to be remedied just by delaying a little while and
609*65682Shibler 			 * trying again (the pageout daemon's current response
610*65682Shibler 			 * to AGAIN) so we just return FAIL.
611*65682Shibler 			 */
61245749Smckusick 			return(VM_PAGER_FAIL);
61345749Smckusick 		}
61445749Smckusick #ifdef DEBUG
61545749Smckusick 		if (swpagerdebug & (SDB_FULL|SDB_ALLOCBLK))
61645749Smckusick 			printf("swpg_io: %x alloc blk %x at ix %x\n",
61745749Smckusick 			       swp->sw_blocks, swb->swb_block, ix);
61845749Smckusick #endif
61945749Smckusick 	}
62045749Smckusick 
62145749Smckusick 	/*
62245749Smckusick 	 * Allocate a kernel virtual address and initialize so that PTE
62345749Smckusick 	 * is available for lower level IO drivers.
62445749Smckusick 	 */
625*65682Shibler 	kva = vm_pager_map_pages(mlist, npages, !(flags & B_ASYNC));
626*65682Shibler 	if (kva == NULL) {
627*65682Shibler #ifdef DEBUG
628*65682Shibler 		if (swpagerdebug & SDB_FAIL)
629*65682Shibler 			printf("%s: no KVA space to map pages\n",
630*65682Shibler 			       "swap_pager_io");
631*65682Shibler #endif
632*65682Shibler 		return(VM_PAGER_AGAIN);
633*65682Shibler 	}
63445749Smckusick 
63545749Smckusick 	/*
636*65682Shibler 	 * Get a swap buffer header and initialize it.
63745749Smckusick 	 */
63845749Smckusick 	s = splbio();
63956393Smckusick 	while (bswlist.b_actf == NULL) {
64045749Smckusick #ifdef DEBUG
64145749Smckusick 		if (swpagerdebug & SDB_ANOM)
64249289Shibler 			printf("swap_pager_io: wait on swbuf for %x (%d)\n",
64345749Smckusick 			       m, flags);
64445749Smckusick #endif
64545749Smckusick 		bswlist.b_flags |= B_WANTED;
646*65682Shibler 		tsleep((caddr_t)&bswlist, PSWP+1, "swpgiobuf", 0);
64745749Smckusick 	}
64856393Smckusick 	bp = bswlist.b_actf;
64956393Smckusick 	bswlist.b_actf = bp->b_actf;
65045749Smckusick 	splx(s);
65145749Smckusick 	bp->b_flags = B_BUSY | (flags & B_READ);
65248386Skarels 	bp->b_proc = &proc0;	/* XXX (but without B_PHYS set this is ok) */
65364546Sbostic 	bp->b_data = (caddr_t)kva;
65445749Smckusick 	bp->b_blkno = swb->swb_block + btodb(off);
65545749Smckusick 	VHOLD(swapdev_vp);
65645749Smckusick 	bp->b_vp = swapdev_vp;
65746985Smckusick 	if (swapdev_vp->v_type == VBLK)
65846985Smckusick 		bp->b_dev = swapdev_vp->v_rdev;
659*65682Shibler 	bp->b_bcount = npages * PAGE_SIZE;
660*65682Shibler 
661*65682Shibler 	/*
662*65682Shibler 	 * For writes we set up additional buffer fields, record a pageout
663*65682Shibler 	 * in progress and mark that these swap blocks are now allocated.
664*65682Shibler 	 */
66553213Smckusick 	if ((bp->b_flags & B_READ) == 0) {
66653213Smckusick 		bp->b_dirtyoff = 0;
667*65682Shibler 		bp->b_dirtyend = npages * PAGE_SIZE;
66845749Smckusick 		swapdev_vp->v_numoutput++;
669*65682Shibler 		s = splbio();
670*65682Shibler 		swp->sw_poip++;
671*65682Shibler 		splx(s);
672*65682Shibler 		mask = (~(~0 << npages)) << atop(off);
673*65682Shibler #ifdef DEBUG
674*65682Shibler 		swap_pager_poip++;
675*65682Shibler 		if (swpagerdebug & SDB_WRITE)
676*65682Shibler 			printf("swpg_io: write: bp=%x swp=%x poip=%d\n",
677*65682Shibler 			       bp, swp, swp->sw_poip);
678*65682Shibler 		if ((swpagerdebug & SDB_ALLOCBLK) &&
679*65682Shibler 		    (swb->swb_mask & mask) != mask)
680*65682Shibler 			printf("swpg_io: %x write %d pages at %x+%x\n",
681*65682Shibler 			       swp->sw_blocks, npages, swb->swb_block,
682*65682Shibler 			       atop(off));
683*65682Shibler 		if (swpagerdebug & SDB_CLUSTER)
684*65682Shibler 			printf("swpg_io: off=%x, npg=%x, mask=%x, bmask=%x\n",
685*65682Shibler 			       off, npages, mask, swb->swb_mask);
686*65682Shibler #endif
687*65682Shibler 		swb->swb_mask |= mask;
68853213Smckusick 	}
68945749Smckusick 	/*
690*65682Shibler 	 * If this is an async write we set up still more buffer fields
69145749Smckusick 	 * and place a "cleaning" entry on the inuse queue.
69245749Smckusick 	 */
69345749Smckusick 	if ((flags & (B_READ|B_ASYNC)) == B_ASYNC) {
69445749Smckusick #ifdef DEBUG
69565231Smckusick 		if (swap_pager_free.tqh_first == NULL)
69645749Smckusick 			panic("swpg_io: lost spc");
69745749Smckusick #endif
69865231Smckusick 		spc = swap_pager_free.tqh_first;
69965231Smckusick 		TAILQ_REMOVE(&swap_pager_free, spc, spc_list);
70045749Smckusick #ifdef DEBUG
70145749Smckusick 		if (spc->spc_flags != SPC_FREE)
70245749Smckusick 			panic("swpg_io: bad free spc");
70345749Smckusick #endif
70445749Smckusick 		spc->spc_flags = SPC_BUSY;
70545749Smckusick 		spc->spc_bp = bp;
70645749Smckusick 		spc->spc_swp = swp;
70745749Smckusick 		spc->spc_kva = kva;
708*65682Shibler 		/*
709*65682Shibler 		 * Record the first page.  This allows swap_pager_finish
710*65682Shibler 		 * to efficiently handle the common case of a single page.
711*65682Shibler 		 * For clusters, it allows us to locate the object easily
712*65682Shibler 		 * and we then reconstruct the rest of the mlist from spc_kva.
713*65682Shibler 		 */
71445749Smckusick 		spc->spc_m = m;
715*65682Shibler 		spc->spc_npages = npages;
71645749Smckusick 		bp->b_flags |= B_CALL;
71745749Smckusick 		bp->b_iodone = swap_pager_iodone;
71845749Smckusick 		s = splbio();
71965231Smckusick 		TAILQ_INSERT_TAIL(&swap_pager_inuse, spc, spc_list);
72045749Smckusick 		splx(s);
72145749Smckusick 	}
722*65682Shibler 
723*65682Shibler 	/*
724*65682Shibler 	 * Finally, start the IO operation.
725*65682Shibler 	 * If it is async we are all done, otherwise we must wait for
726*65682Shibler 	 * completion and cleanup afterwards.
727*65682Shibler 	 */
72845749Smckusick #ifdef DEBUG
72945749Smckusick 	if (swpagerdebug & SDB_IO)
73045749Smckusick 		printf("swpg_io: IO start: bp %x, db %x, va %x, pa %x\n",
73145749Smckusick 		       bp, swb->swb_block+btodb(off), kva, VM_PAGE_TO_PHYS(m));
73245749Smckusick #endif
73345749Smckusick 	VOP_STRATEGY(bp);
73445749Smckusick 	if ((flags & (B_READ|B_ASYNC)) == B_ASYNC) {
73545749Smckusick #ifdef DEBUG
73645749Smckusick 		if (swpagerdebug & SDB_IO)
73745749Smckusick 			printf("swpg_io:  IO started: bp %x\n", bp);
73845749Smckusick #endif
73945749Smckusick 		return(VM_PAGER_PEND);
74045749Smckusick 	}
74145749Smckusick 	s = splbio();
74245749Smckusick #ifdef DEBUG
74345749Smckusick 	if (flags & B_READ)
74445749Smckusick 		swap_pager_piip++;
74545749Smckusick 	else
74645749Smckusick 		swap_pager_poip++;
74745749Smckusick #endif
748*65682Shibler 	while ((bp->b_flags & B_DONE) == 0)
749*65682Shibler 		(void) tsleep(bp, PVM, "swpgio", 0);
750*65682Shibler 	if ((flags & B_READ) == 0)
751*65682Shibler 		--swp->sw_poip;
75245749Smckusick #ifdef DEBUG
75345749Smckusick 	if (flags & B_READ)
75445749Smckusick 		--swap_pager_piip;
75545749Smckusick 	else
75645749Smckusick 		--swap_pager_poip;
75745749Smckusick #endif
75856320Shibler 	rv = (bp->b_flags & B_ERROR) ? VM_PAGER_ERROR : VM_PAGER_OK;
75945749Smckusick 	bp->b_flags &= ~(B_BUSY|B_WANTED|B_PHYS|B_PAGET|B_UAREA|B_DIRTY);
76056393Smckusick 	bp->b_actf = bswlist.b_actf;
76156393Smckusick 	bswlist.b_actf = bp;
76245749Smckusick 	if (bp->b_vp)
76345749Smckusick 		brelvp(bp);
76445749Smckusick 	if (bswlist.b_flags & B_WANTED) {
76545749Smckusick 		bswlist.b_flags &= ~B_WANTED;
766*65682Shibler 		wakeup(&bswlist);
76745749Smckusick 	}
76845749Smckusick 	if ((flags & B_READ) == 0 && rv == VM_PAGER_OK) {
76956382Smckusick 		m->flags |= PG_CLEAN;
77045749Smckusick 		pmap_clear_modify(VM_PAGE_TO_PHYS(m));
77145749Smckusick 	}
77245749Smckusick 	splx(s);
77345749Smckusick #ifdef DEBUG
77445749Smckusick 	if (swpagerdebug & SDB_IO)
77545749Smckusick 		printf("swpg_io:  IO done: bp %x, rv %d\n", bp, rv);
77656320Shibler 	if ((swpagerdebug & SDB_FAIL) && rv == VM_PAGER_ERROR)
77745749Smckusick 		printf("swpg_io: IO error\n");
77845749Smckusick #endif
779*65682Shibler 	vm_pager_unmap_pages(kva, npages);
78045749Smckusick 	return(rv);
78145749Smckusick }
78245749Smckusick 
783*65682Shibler static void
784*65682Shibler swap_pager_clean(rw)
78545749Smckusick 	int rw;
78645749Smckusick {
787*65682Shibler 	register swp_clean_t spc;
788*65682Shibler 	register int s, i;
789*65682Shibler 	vm_object_t object;
790*65682Shibler 	vm_page_t m;
79145749Smckusick 
79245749Smckusick #ifdef DEBUG
79345749Smckusick 	/* save panic time state */
79445749Smckusick 	if ((swpagerdebug & SDB_ANOMPANIC) && panicstr)
795*65682Shibler 		return;
79645749Smckusick 	if (swpagerdebug & SDB_FOLLOW)
797*65682Shibler 		printf("swpg_clean(%x)\n", rw);
79845749Smckusick #endif
799*65682Shibler 
80045749Smckusick 	for (;;) {
80145749Smckusick 		/*
80245749Smckusick 		 * Look up and removal from inuse list must be done
80345749Smckusick 		 * at splbio() to avoid conflicts with swap_pager_iodone.
80445749Smckusick 		 */
80545749Smckusick 		s = splbio();
80665231Smckusick 		for (spc = swap_pager_inuse.tqh_first;
80765231Smckusick 		     spc != NULL;
80865231Smckusick 		     spc = spc->spc_list.tqe_next) {
809*65682Shibler 			/*
810*65682Shibler 			 * If the operation is done, remove it from the
811*65682Shibler 			 * list and process it.
812*65682Shibler 			 *
813*65682Shibler 			 * XXX if we can't get the object lock we also
814*65682Shibler 			 * leave it on the list and try again later.
815*65682Shibler 			 * Is there something better we could do?
816*65682Shibler 			 */
81745749Smckusick 			if ((spc->spc_flags & SPC_DONE) &&
818*65682Shibler 			    vm_object_lock_try(spc->spc_m->object)) {
81965231Smckusick 				TAILQ_REMOVE(&swap_pager_inuse, spc, spc_list);
82045749Smckusick 				break;
82145749Smckusick 			}
82245749Smckusick 		}
82345749Smckusick 
82445749Smckusick 		/*
82545749Smckusick 		 * No operations done, thats all we can do for now.
82645749Smckusick 		 */
827*65682Shibler 		if (spc == NULL) {
828*65682Shibler 			splx(s);
82945749Smckusick 			break;
830*65682Shibler 		}
83145749Smckusick 		splx(s);
83245749Smckusick 
83345749Smckusick 		/*
834*65682Shibler 		 * Found a completed operation so finish it off.
835*65682Shibler 		 * Note: no longer at splbio since entry is off the list.
83645749Smckusick 		 */
837*65682Shibler 		m = spc->spc_m;
838*65682Shibler 		object = m->object;
839*65682Shibler 
840*65682Shibler 		/*
841*65682Shibler 		 * Process each page in the cluster.
842*65682Shibler 		 * The first page is explicitly kept in the cleaning
843*65682Shibler 		 * entry, others must be reconstructed from the KVA.
844*65682Shibler 		 */
845*65682Shibler 		for (i = 0; i < spc->spc_npages; i++) {
846*65682Shibler 			if (i)
847*65682Shibler 				m = vm_pager_atop(spc->spc_kva + ptoa(i));
848*65682Shibler 			/*
849*65682Shibler 			 * If no error mark as clean and inform the pmap
850*65682Shibler 			 * system.  If there was an error, mark as dirty
851*65682Shibler 			 * so we will try again.
852*65682Shibler 			 *
853*65682Shibler 			 * XXX could get stuck doing this, should give up
854*65682Shibler 			 * after awhile.
855*65682Shibler 			 */
856*65682Shibler 			if (spc->spc_flags & SPC_ERROR) {
857*65682Shibler 				printf("%s: clean of page %x failed\n",
858*65682Shibler 				       "swap_pager_clean",
859*65682Shibler 				       VM_PAGE_TO_PHYS(m));
860*65682Shibler 				m->flags |= PG_LAUNDRY;
861*65682Shibler 			} else {
862*65682Shibler 				m->flags |= PG_CLEAN;
863*65682Shibler 				pmap_clear_modify(VM_PAGE_TO_PHYS(m));
864*65682Shibler 			}
865*65682Shibler 			m->flags &= ~PG_BUSY;
866*65682Shibler 			PAGE_WAKEUP(m);
86745749Smckusick 		}
868*65682Shibler 
869*65682Shibler 		/*
870*65682Shibler 		 * Done with the object, decrement the paging count
871*65682Shibler 		 * and unlock it.
872*65682Shibler 		 */
873*65682Shibler 		if (--object->paging_in_progress == 0)
874*65682Shibler 			wakeup(object);
875*65682Shibler 		vm_object_unlock(object);
876*65682Shibler 
877*65682Shibler 		/*
878*65682Shibler 		 * Free up KVM used and put the entry back on the list.
879*65682Shibler 		 */
880*65682Shibler 		vm_pager_unmap_pages(spc->spc_kva, spc->spc_npages);
88145749Smckusick 		spc->spc_flags = SPC_FREE;
88265231Smckusick 		TAILQ_INSERT_TAIL(&swap_pager_free, spc, spc_list);
88345749Smckusick #ifdef DEBUG
88445749Smckusick 		if (swpagerdebug & SDB_WRITE)
88545749Smckusick 			printf("swpg_clean: free spc %x\n", spc);
88645749Smckusick #endif
88745749Smckusick 	}
888*65682Shibler }
88945749Smckusick 
89045749Smckusick #ifdef DEBUG
891*65682Shibler static void
892*65682Shibler swap_pager_clean_check(mlist, npages, rw)
893*65682Shibler 	vm_page_t *mlist;
894*65682Shibler 	int npages;
895*65682Shibler 	int rw;
896*65682Shibler {
89745749Smckusick 	register swp_clean_t spc;
898*65682Shibler 	boolean_t bad;
899*65682Shibler 	int i, j, s;
900*65682Shibler 	vm_page_t m;
90145749Smckusick 
902*65682Shibler 	if (panicstr)
903*65682Shibler 		return;
90445749Smckusick 
905*65682Shibler 	bad = FALSE;
906*65682Shibler 	s = splbio();
907*65682Shibler 	for (spc = swap_pager_inuse.tqh_first;
908*65682Shibler 	     spc != NULL;
909*65682Shibler 	     spc = spc->spc_list.tqe_next) {
910*65682Shibler 		for (j = 0; j < spc->spc_npages; j++) {
911*65682Shibler 			m = vm_pager_atop(spc->spc_kva + ptoa(j));
912*65682Shibler 			for (i = 0; i < npages; i++)
913*65682Shibler 				if (m == mlist[i]) {
914*65682Shibler 					if (swpagerdebug & SDB_ANOM)
915*65682Shibler 						printf(
916*65682Shibler 		"swpg_clean_check: %s: page %x on list, flags %x\n",
917*65682Shibler 		rw == B_WRITE ? "write" : "read", mlist[i], spc->spc_flags);
918*65682Shibler 					bad = TRUE;
919*65682Shibler 				}
920*65682Shibler 		}
92145749Smckusick 	}
922*65682Shibler 	splx(s);
923*65682Shibler 	if (bad)
924*65682Shibler 		panic("swpg_clean_check");
925*65682Shibler }
92649289Shibler #endif
92745749Smckusick 
92853341Sbostic static void
92945749Smckusick swap_pager_iodone(bp)
93045749Smckusick 	register struct buf *bp;
93145749Smckusick {
93245749Smckusick 	register swp_clean_t spc;
93345749Smckusick 	daddr_t blk;
93445749Smckusick 	int s;
93545749Smckusick 
93645749Smckusick #ifdef DEBUG
93745749Smckusick 	/* save panic time state */
93845749Smckusick 	if ((swpagerdebug & SDB_ANOMPANIC) && panicstr)
93945749Smckusick 		return;
94045749Smckusick 	if (swpagerdebug & SDB_FOLLOW)
94145749Smckusick 		printf("swpg_iodone(%x)\n", bp);
94245749Smckusick #endif
94345749Smckusick 	s = splbio();
94465231Smckusick 	for (spc = swap_pager_inuse.tqh_first;
94565231Smckusick 	     spc != NULL;
94665231Smckusick 	     spc = spc->spc_list.tqe_next)
94745749Smckusick 		if (spc->spc_bp == bp)
94845749Smckusick 			break;
94945749Smckusick #ifdef DEBUG
95065231Smckusick 	if (spc == NULL)
95149289Shibler 		panic("swap_pager_iodone: bp not found");
95245749Smckusick #endif
95345749Smckusick 
95445749Smckusick 	spc->spc_flags &= ~SPC_BUSY;
95545749Smckusick 	spc->spc_flags |= SPC_DONE;
95645749Smckusick 	if (bp->b_flags & B_ERROR)
95745749Smckusick 		spc->spc_flags |= SPC_ERROR;
95845749Smckusick 	spc->spc_bp = NULL;
95945749Smckusick 	blk = bp->b_blkno;
96045749Smckusick 
96145749Smckusick #ifdef DEBUG
96245749Smckusick 	--swap_pager_poip;
96345749Smckusick 	if (swpagerdebug & SDB_WRITE)
96445749Smckusick 		printf("swpg_iodone: bp=%x swp=%x flags=%x spc=%x poip=%x\n",
96545749Smckusick 		       bp, spc->spc_swp, spc->spc_swp->sw_flags,
96645749Smckusick 		       spc, spc->spc_swp->sw_poip);
96745749Smckusick #endif
96845749Smckusick 
96945749Smckusick 	spc->spc_swp->sw_poip--;
97045749Smckusick 	if (spc->spc_swp->sw_flags & SW_WANTED) {
97145749Smckusick 		spc->spc_swp->sw_flags &= ~SW_WANTED;
972*65682Shibler 		wakeup(spc->spc_swp);
97345749Smckusick 	}
97445749Smckusick 
97545749Smckusick 	bp->b_flags &= ~(B_BUSY|B_WANTED|B_PHYS|B_PAGET|B_UAREA|B_DIRTY);
97656393Smckusick 	bp->b_actf = bswlist.b_actf;
97756393Smckusick 	bswlist.b_actf = bp;
97845749Smckusick 	if (bp->b_vp)
97945749Smckusick 		brelvp(bp);
98045749Smckusick 	if (bswlist.b_flags & B_WANTED) {
98145749Smckusick 		bswlist.b_flags &= ~B_WANTED;
982*65682Shibler 		wakeup(&bswlist);
98345749Smckusick 	}
984*65682Shibler 	wakeup(&vm_pages_needed);
98545749Smckusick 	splx(s);
98645749Smckusick }
987