xref: /original-bsd/sys/vm/swap_pager.c (revision e0c0d005)
1 /*
2  * Copyright (c) 1990 University of Utah.
3  * Copyright (c) 1991 The Regents of the University of California.
4  * All rights reserved.
5  *
6  * This code is derived from software contributed to Berkeley by
7  * the Systems Programming Group of the University of Utah Computer
8  * Science Department.
9  *
10  * %sccs.include.redist.c%
11  *
12  *	@(#)swap_pager.c	7.1 (Berkeley) 12/05/90
13  */
14 
15 /*
16  * Quick hack to page to dedicated partition(s).
17  * TODO:
18  *	Add multiprocessor locks
19  *	Deal with async writes in a better fashion
20  */
21 
22 #include "swappager.h"
23 #if NSWAPPAGER > 0
24 
25 #include "param.h"
26 #include "user.h"
27 #include "proc.h"
28 #include "buf.h"
29 #include "map.h"
30 #include "systm.h"
31 #include "specdev.h"
32 #include "vnode.h"
33 #include "malloc.h"
34 #include "queue.h"
35 
36 #include "../vm/vm_param.h"
37 #include "../vm/vm_pager.h"
38 #include "../vm/vm_page.h"
39 #include "../vm/vm_pageout.h"
40 #include "../vm/swap_pager.h"
41 
42 #define NSWSIZES	16	/* size of swtab */
43 #define NPENDINGIO	64	/* max # of pending cleans */
44 #define MAXDADDRS	64	/* max # of disk addrs for fixed allocations */
45 
46 #ifdef DEBUG
47 int	swpagerdebug = 0x100;
48 #define	SDB_FOLLOW	0x001
49 #define SDB_INIT	0x002
50 #define SDB_ALLOC	0x004
51 #define SDB_IO		0x008
52 #define SDB_WRITE	0x010
53 #define SDB_FAIL	0x020
54 #define SDB_ALLOCBLK	0x040
55 #define SDB_FULL	0x080
56 #define SDB_ANOM	0x100
57 #define SDB_ANOMPANIC	0x200
58 #endif
59 
60 struct swpagerclean {
61 	queue_head_t		spc_list;
62 	int			spc_flags;
63 	struct buf		*spc_bp;
64 	sw_pager_t		spc_swp;
65 	vm_offset_t		spc_kva;
66 	vm_page_t		spc_m;
67 } swcleanlist[NPENDINGIO];
68 typedef	struct swpagerclean	*swp_clean_t;
69 
70 #define SWP_CLEAN_NULL		((swp_clean_t)0)
71 
72 /* spc_flags values */
73 #define SPC_FREE	0x00
74 #define SPC_BUSY	0x01
75 #define SPC_DONE	0x02
76 #define SPC_ERROR	0x04
77 #define SPC_DIRTY	0x08
78 
79 struct swtab {
80 	vm_size_t st_osize;	/* size of object (bytes) */
81 	int	  st_bsize;	/* vs. size of swap block (DEV_BSIZE units) */
82 #ifdef DEBUG
83 	u_long	  st_inuse;	/* number in this range in use */
84 	u_long	  st_usecnt;	/* total used of this size */
85 #endif
86 } swtab[NSWSIZES+1];
87 
88 #ifdef DEBUG
89 int		swap_pager_pendingio;	/* max pending async "clean" ops */
90 int		swap_pager_poip;	/* pageouts in progress */
91 int		swap_pager_piip;	/* pageins in progress */
92 #endif
93 
94 queue_head_t	swap_pager_inuse;	/* list of pending page cleans */
95 queue_head_t	swap_pager_free;	/* list of free pager clean structs */
96 queue_head_t	swap_pager_list;	/* list of "named" anon regions */
97 
98 void
99 swap_pager_init()
100 {
101 	register swp_clean_t spc;
102 	register int i, bsize;
103 	extern int dmmin, dmmax;
104 	int maxbsize;
105 
106 #ifdef DEBUG
107 	if (swpagerdebug & (SDB_FOLLOW|SDB_INIT))
108 		printf("swpg_init()\n");
109 #endif
110 	dfltpagerops = &swappagerops;
111 	queue_init(&swap_pager_list);
112 
113 	/*
114 	 * Initialize clean lists
115 	 */
116 	queue_init(&swap_pager_inuse);
117 	queue_init(&swap_pager_free);
118 	for (i = 0, spc = swcleanlist; i < NPENDINGIO; i++, spc++) {
119 		queue_enter(&swap_pager_free, spc, swp_clean_t, spc_list);
120 		spc->spc_flags = SPC_FREE;
121 	}
122 
123 	/*
124 	 * Calculate the swap allocation constants.
125 	 */
126         if (dmmin == 0) {
127                 dmmin = DMMIN;
128 		if (dmmin < CLBYTES/DEV_BSIZE)
129 			dmmin = CLBYTES/DEV_BSIZE;
130 	}
131         if (dmmax == 0)
132                 dmmax = DMMAX;
133 
134 	/*
135 	 * Fill in our table of object size vs. allocation size
136 	 */
137 	bsize = btodb(PAGE_SIZE);
138 	if (bsize < dmmin)
139 		bsize = dmmin;
140 	maxbsize = btodb(sizeof(sw_bm_t) * NBBY * PAGE_SIZE);
141 	if (maxbsize > dmmax)
142 		maxbsize = dmmax;
143 	for (i = 0; i < NSWSIZES; i++) {
144 		swtab[i].st_osize = (vm_size_t) (MAXDADDRS * dbtob(bsize));
145 		swtab[i].st_bsize = bsize;
146 #ifdef DEBUG
147 		if (swpagerdebug & SDB_INIT)
148 			printf("swpg_init: ix %d, size %x, bsize %x\n",
149 			       i, swtab[i].st_osize, swtab[i].st_bsize);
150 #endif
151 		if (bsize >= maxbsize)
152 			break;
153 		bsize *= 2;
154 	}
155 	swtab[i].st_osize = 0;
156 	swtab[i].st_bsize = bsize;
157 }
158 
159 /*
160  * Allocate a pager structure and associated resources.
161  * Note that if we are called from the pageout daemon (handle == NULL)
162  * we should not wait for memory as it could resulting in deadlock.
163  */
164 vm_pager_t
165 swap_pager_alloc(handle, size, prot)
166 	caddr_t handle;
167 	register vm_size_t size;
168 	vm_prot_t prot;
169 {
170 	register vm_pager_t pager;
171 	register sw_pager_t swp;
172 	struct swtab *swt;
173 	int waitok;
174 
175 #ifdef DEBUG
176 	if (swpagerdebug & (SDB_FOLLOW|SDB_ALLOC))
177 		printf("swpg_alloc(%x, %x, %x)\n", handle, size, prot);
178 #endif
179 	/*
180 	 * If this is a "named" anonymous region, look it up and
181 	 * return the appropriate pager if it exists.
182 	 */
183 	if (handle) {
184 		pager = vm_pager_lookup(&swap_pager_list, handle);
185 		if (pager != VM_PAGER_NULL) {
186 			/*
187 			 * Use vm_object_lookup to gain a reference
188 			 * to the object and also to remove from the
189 			 * object cache.
190 			 */
191 			if (vm_object_lookup(pager) == VM_OBJECT_NULL)
192 				panic("swap_pager_alloc: bad object");
193 			return(pager);
194 		}
195 	}
196 	/*
197 	 * Pager doesn't exist, allocate swap management resources
198 	 * and initialize.
199 	 */
200 	waitok = handle ? M_WAITOK : M_NOWAIT;
201 	pager = (vm_pager_t)malloc(sizeof *pager, M_VMPAGER, waitok);
202 	if (pager == VM_PAGER_NULL)
203 		return(VM_PAGER_NULL);
204 	swp = (sw_pager_t)malloc(sizeof *swp, M_VMPGDATA, waitok);
205 	if (swp == NULL) {
206 #ifdef DEBUG
207 		if (swpagerdebug & SDB_FAIL)
208 			printf("swpg_alloc: swpager malloc failed\n");
209 #endif
210 		free((caddr_t)pager, M_VMPAGER);
211 		return(VM_PAGER_NULL);
212 	}
213 	size = round_page(size);
214 	for (swt = swtab; swt->st_osize; swt++)
215 		if (size <= swt->st_osize)
216 			break;
217 #ifdef DEBUG
218 	swt->st_inuse++;
219 	swt->st_usecnt++;
220 #endif
221 	swp->sw_osize = size;
222 	swp->sw_bsize = swt->st_bsize;
223 	swp->sw_nblocks = (btodb(size) + swp->sw_bsize - 1) / swp->sw_bsize;
224 	swp->sw_blocks = (sw_blk_t)
225 		malloc(swp->sw_nblocks*sizeof(*swp->sw_blocks),
226 		       M_VMPGDATA, M_NOWAIT);
227 	if (swp->sw_blocks == NULL) {
228 		free((caddr_t)swp, M_VMPGDATA);
229 		free((caddr_t)pager, M_VMPAGER);
230 #ifdef DEBUG
231 		if (swpagerdebug & SDB_FAIL)
232 			printf("swpg_alloc: sw_blocks malloc failed\n");
233 		swt->st_inuse--;
234 		swt->st_usecnt--;
235 #endif
236 		return(FALSE);
237 	}
238 	bzero((caddr_t)swp->sw_blocks,
239 	      swp->sw_nblocks * sizeof(*swp->sw_blocks));
240 	swp->sw_poip = 0;
241 	if (handle) {
242 		vm_object_t object;
243 
244 		swp->sw_flags = SW_NAMED;
245 		queue_enter(&swap_pager_list, pager, vm_pager_t, pg_list);
246 		/*
247 		 * Consistant with other pagers: return with object
248 		 * referenced.  Can't do this with handle == NULL
249 		 * since it might be the pageout daemon calling.
250 		 */
251 		object = vm_object_allocate(size);
252 		vm_object_enter(object, pager);
253 		vm_object_setpager(object, pager, 0, FALSE);
254 	} else {
255 		swp->sw_flags = 0;
256 		queue_init(&pager->pg_list);
257 	}
258 	pager->pg_handle = handle;
259 	pager->pg_ops = &swappagerops;
260 	pager->pg_type = PG_SWAP;
261 	pager->pg_data = (caddr_t)swp;
262 
263 #ifdef DEBUG
264 	if (swpagerdebug & SDB_ALLOC)
265 		printf("swpg_alloc: pg_data %x, %x of %x at %x\n",
266 		       swp, swp->sw_nblocks, swp->sw_bsize, swp->sw_blocks);
267 #endif
268 	return(pager);
269 }
270 
271 void
272 swap_pager_dealloc(pager)
273 	vm_pager_t pager;
274 {
275 	register int i;
276 	register sw_blk_t bp;
277 	register sw_pager_t swp;
278 	struct swtab *swt;
279 	int s;
280 
281 #ifdef DEBUG
282 	/* save panic time state */
283 	if ((swpagerdebug & SDB_ANOMPANIC) && panicstr)
284 		return;
285 	if (swpagerdebug & (SDB_FOLLOW|SDB_ALLOC))
286 		printf("swpg_dealloc(%x)\n", pager);
287 #endif
288 	/*
289 	 * Remove from list right away so lookups will fail if we
290 	 * block for pageout completion.
291 	 */
292 	swp = (sw_pager_t) pager->pg_data;
293 	if (swp->sw_flags & SW_NAMED) {
294 		queue_remove(&swap_pager_list, pager, vm_pager_t, pg_list);
295 		swp->sw_flags &= ~SW_NAMED;
296 	}
297 #ifdef DEBUG
298 	for (swt = swtab; swt->st_osize; swt++)
299 		if (swp->sw_osize <= swt->st_osize)
300 			break;
301 	swt->st_inuse--;
302 #endif
303 
304 	/*
305 	 * Wait for all pageouts to finish and remove
306 	 * all entries from cleaning list.
307 	 */
308 	s = splbio();
309 	while (swp->sw_poip) {
310 		swp->sw_flags |= SW_WANTED;
311 		assert_wait((int)swp);
312 		thread_block();
313 	}
314 	splx(s);
315 	(void) swap_pager_clean(VM_PAGE_NULL, B_WRITE);
316 
317 	/*
318 	 * Free left over swap blocks
319 	 */
320 	for (i = 0, bp = swp->sw_blocks; i < swp->sw_nblocks; i++, bp++)
321 		if (bp->swb_block) {
322 #ifdef DEBUG
323 			if (swpagerdebug & (SDB_ALLOCBLK|SDB_FULL))
324 				printf("swpg_dealloc: blk %x\n",
325 				       bp->swb_block);
326 #endif
327 			rmfree(swapmap, swp->sw_bsize, bp->swb_block);
328 		}
329 	/*
330 	 * Free swap management resources
331 	 */
332 	free((caddr_t)swp->sw_blocks, M_VMPGDATA);
333 	free((caddr_t)swp, M_VMPGDATA);
334 	free((caddr_t)pager, M_VMPAGER);
335 }
336 
337 swap_pager_getpage(pager, m, sync)
338 	vm_pager_t pager;
339 	vm_page_t m;
340 	boolean_t sync;
341 {
342 #ifdef DEBUG
343 	if (swpagerdebug & SDB_FOLLOW)
344 		printf("swpg_getpage(%x, %x, %d)\n", pager, m, sync);
345 #endif
346 	return(swap_pager_io((sw_pager_t)pager->pg_data, m, B_READ));
347 }
348 
349 swap_pager_putpage(pager, m, sync)
350 	vm_pager_t pager;
351 	vm_page_t m;
352 	boolean_t sync;
353 {
354 	int flags;
355 
356 #ifdef DEBUG
357 	if (swpagerdebug & SDB_FOLLOW)
358 		printf("swpg_putpage(%x, %x, %d)\n", pager, m, sync);
359 #endif
360 	if (pager == VM_PAGER_NULL) {
361 		(void) swap_pager_clean(VM_PAGE_NULL, B_WRITE);
362 		return;
363 	}
364 	flags = B_WRITE;
365 	if (!sync)
366 		flags |= B_ASYNC;
367 	return(swap_pager_io((sw_pager_t)pager->pg_data, m, flags));
368 }
369 
370 boolean_t
371 swap_pager_haspage(pager, offset)
372 	vm_pager_t pager;
373 	vm_offset_t offset;
374 {
375 	register sw_pager_t swp;
376 	register sw_blk_t swb;
377 	int ix;
378 
379 #ifdef DEBUG
380 	if (swpagerdebug & (SDB_FOLLOW|SDB_ALLOCBLK))
381 		printf("swpg_haspage(%x, %x) ", pager, offset);
382 #endif
383 	swp = (sw_pager_t) pager->pg_data;
384 	ix = offset / dbtob(swp->sw_bsize);
385 	if (swp->sw_blocks == NULL || ix >= swp->sw_nblocks) {
386 #ifdef DEBUG
387 		if (swpagerdebug & (SDB_FAIL|SDB_FOLLOW|SDB_ALLOCBLK))
388 			printf("swpg_haspage: %x bad offset %x, ix %x\n",
389 			       swp->sw_blocks, offset, ix);
390 #endif
391 		return(FALSE);
392 	}
393 	swb = &swp->sw_blocks[ix];
394 	if (swb->swb_block)
395 		ix = atop(offset % dbtob(swp->sw_bsize));
396 #ifdef DEBUG
397 	if (swpagerdebug & SDB_ALLOCBLK)
398 		printf("%x blk %x+%x ", swp->sw_blocks, swb->swb_block, ix);
399 	if (swpagerdebug & (SDB_FOLLOW|SDB_ALLOCBLK))
400 		printf("-> %c\n",
401 		       "FT"[swb->swb_block && (swb->swb_mask & (1 << ix))]);
402 #endif
403 	if (swb->swb_block && (swb->swb_mask & (1 << ix)))
404 		return(TRUE);
405 	return(FALSE);
406 }
407 
408 /*
409  * Scaled down version of swap().
410  * Assumes that PAGE_SIZE < MAXPHYS; i.e. only one operation needed.
411  * BOGUS:  lower level IO routines expect a KVA so we have to map our
412  * provided physical page into the KVA to keep them happy.
413  */
414 swap_pager_io(swp, m, flags)
415 	register sw_pager_t swp;
416 	vm_page_t m;
417 	int flags;
418 {
419 	register struct buf *bp;
420 	register sw_blk_t swb;
421 	register int s;
422 	int ix;
423 	boolean_t rv;
424 	vm_offset_t kva, off;
425 	swp_clean_t spc;
426 
427 #ifdef DEBUG
428 	/* save panic time state */
429 	if ((swpagerdebug & SDB_ANOMPANIC) && panicstr)
430 		return;
431 	if (swpagerdebug & (SDB_FOLLOW|SDB_IO))
432 		printf("swpg_io(%x, %x, %x)\n", swp, m, flags);
433 #endif
434 
435 	/*
436 	 * For reads (pageins) and synchronous writes, we clean up
437 	 * all completed async pageouts and check to see if this
438 	 * page is currently being cleaned.  If it is, we just wait
439 	 * til the operation is done before continuing.
440 	 */
441 	if ((flags & B_ASYNC) == 0) {
442 		s = splbio();
443 		while (swap_pager_clean(m, flags&B_READ)) {
444 			swp->sw_flags |= SW_WANTED;
445 			assert_wait((int)swp);
446 			thread_block();
447 		}
448 		splx(s);
449 	}
450 	/*
451 	 * For async writes (pageouts), we cleanup completed pageouts so
452 	 * that all available resources are freed.  Also tells us if this
453 	 * page is already being cleaned.  If it is, or no resources
454 	 * are available, we try again later.
455 	 */
456 	else if (swap_pager_clean(m, B_WRITE) || queue_empty(&swap_pager_free))
457 		return(VM_PAGER_FAIL);
458 
459 	/*
460 	 * Determine swap block and allocate as necessary.
461 	 */
462 	off = m->offset + m->object->paging_offset;
463 	ix = off / dbtob(swp->sw_bsize);
464 	if (swp->sw_blocks == NULL || ix >= swp->sw_nblocks) {
465 #ifdef DEBUG
466 		if (swpagerdebug & SDB_FAIL)
467 			printf("swpg_io: bad offset %x+%x(%d) in %x\n",
468 			       m->offset, m->object->paging_offset,
469 			       ix, swp->sw_blocks);
470 #endif
471 		return(VM_PAGER_FAIL);
472 	}
473 	swb = &swp->sw_blocks[ix];
474 	off = off % dbtob(swp->sw_bsize);
475 	if (flags & B_READ) {
476 		if (swb->swb_block == 0 ||
477 		    (swb->swb_mask & (1 << atop(off))) == 0) {
478 #ifdef DEBUG
479 			if (swpagerdebug & (SDB_ALLOCBLK|SDB_FAIL))
480 				printf("swpg_io: %x bad read: blk %x+%x, mask %x, off %x+%x\n",
481 				       swp->sw_blocks,
482 				       swb->swb_block, atop(off),
483 				       swb->swb_mask,
484 				       m->offset, m->object->paging_offset);
485 #endif
486 			/* XXX: should we zero page here?? */
487 			return(VM_PAGER_FAIL);
488 		}
489 	} else if (swb->swb_block == 0) {
490 		swb->swb_block = rmalloc(swapmap, swp->sw_bsize);
491 		if (swb->swb_block == 0) {
492 #ifdef DEBUG
493 			if (swpagerdebug & SDB_FAIL)
494 				printf("swpg_io: rmalloc of %x failed\n",
495 				       swp->sw_bsize);
496 #endif
497 			return(VM_PAGER_FAIL);
498 		}
499 #ifdef DEBUG
500 		if (swpagerdebug & (SDB_FULL|SDB_ALLOCBLK))
501 			printf("swpg_io: %x alloc blk %x at ix %x\n",
502 			       swp->sw_blocks, swb->swb_block, ix);
503 #endif
504 	}
505 
506 	/*
507 	 * Allocate a kernel virtual address and initialize so that PTE
508 	 * is available for lower level IO drivers.
509 	 */
510 	kva = vm_pager_map_page(m);
511 
512 	/*
513 	 * Get a swap buffer header and perform the IO
514 	 */
515 	s = splbio();
516 	while (bswlist.av_forw == NULL) {
517 #ifdef DEBUG
518 		if (swpagerdebug & SDB_ANOM)
519 			printf("swpg_io: wait on swbuf for %x (%d)\n",
520 			       m, flags);
521 #endif
522 		bswlist.b_flags |= B_WANTED;
523 		sleep((caddr_t)&bswlist, PSWP+1);
524 	}
525 	bp = bswlist.av_forw;
526 	bswlist.av_forw = bp->av_forw;
527 	splx(s);
528 	bp->b_flags = B_BUSY | (flags & B_READ);
529 	bp->b_proc = &proc[0];	/* XXX (but without B_PHYS set this is ok) */
530 	bp->b_un.b_addr = (caddr_t)kva;
531 	bp->b_blkno = swb->swb_block + btodb(off);
532 	VHOLD(swapdev_vp);
533 	bp->b_vp = swapdev_vp;
534 	bp->b_dev = swapdev_vp->v_rdev;
535 	bp->b_bcount = PAGE_SIZE;
536 	if ((bp->b_flags & B_READ) == 0)
537 		swapdev_vp->v_numoutput++;
538 
539 	/*
540 	 * If this is an async write we set up additional buffer fields
541 	 * and place a "cleaning" entry on the inuse queue.
542 	 */
543 	if ((flags & (B_READ|B_ASYNC)) == B_ASYNC) {
544 #ifdef DEBUG
545 		if (queue_empty(&swap_pager_free))
546 			panic("swpg_io: lost spc");
547 #endif
548 		queue_remove_first(&swap_pager_free,
549 				   spc, swp_clean_t, spc_list);
550 #ifdef DEBUG
551 		if (spc->spc_flags != SPC_FREE)
552 			panic("swpg_io: bad free spc");
553 #endif
554 		spc->spc_flags = SPC_BUSY;
555 		spc->spc_bp = bp;
556 		spc->spc_swp = swp;
557 		spc->spc_kva = kva;
558 		spc->spc_m = m;
559 #ifdef DEBUG
560 		m->pagerowned = 1;
561 #endif
562 		bp->b_flags |= B_CALL;
563 		bp->b_iodone = swap_pager_iodone;
564 		s = splbio();
565 		swp->sw_poip++;
566 		queue_enter(&swap_pager_inuse, spc, swp_clean_t, spc_list);
567 
568 #ifdef DEBUG
569 		swap_pager_poip++;
570 		if (swpagerdebug & SDB_WRITE)
571 			printf("swpg_io: write: bp=%x swp=%x spc=%x poip=%d\n",
572 			       bp, swp, spc, swp->sw_poip);
573 		if ((swpagerdebug & SDB_ALLOCBLK) &&
574 		    (swb->swb_mask & (1 << atop(off))) == 0)
575 			printf("swpg_io: %x write blk %x+%x\n",
576 			       swp->sw_blocks, swb->swb_block, atop(off));
577 #endif
578 		swb->swb_mask |= (1 << atop(off));
579 		/*
580 		 * XXX: Block write faults til we are done.
581 		 */
582 		m->page_lock = VM_PROT_WRITE;
583 		m->unlock_request = VM_PROT_ALL;
584 		pmap_copy_on_write(VM_PAGE_TO_PHYS(m));
585 		splx(s);
586 	}
587 #ifdef DEBUG
588 	if (swpagerdebug & SDB_IO)
589 		printf("swpg_io: IO start: bp %x, db %x, va %x, pa %x\n",
590 		       bp, swb->swb_block+btodb(off), kva, VM_PAGE_TO_PHYS(m));
591 #endif
592 	VOP_STRATEGY(bp);
593 	if ((flags & (B_READ|B_ASYNC)) == B_ASYNC) {
594 #ifdef DEBUG
595 		if (swpagerdebug & SDB_IO)
596 			printf("swpg_io:  IO started: bp %x\n", bp);
597 #endif
598 		return(VM_PAGER_PEND);
599 	}
600 	s = splbio();
601 #ifdef DEBUG
602 	if (flags & B_READ)
603 		swap_pager_piip++;
604 	else
605 		swap_pager_poip++;
606 #endif
607 	while ((bp->b_flags & B_DONE) == 0) {
608 		assert_wait((int)bp);
609 		thread_block();
610 	}
611 #ifdef DEBUG
612 	if (flags & B_READ)
613 		--swap_pager_piip;
614 	else
615 		--swap_pager_poip;
616 #endif
617 	rv = (bp->b_flags & B_ERROR) ? VM_PAGER_FAIL : VM_PAGER_OK;
618 	bp->b_flags &= ~(B_BUSY|B_WANTED|B_PHYS|B_PAGET|B_UAREA|B_DIRTY);
619 	bp->av_forw = bswlist.av_forw;
620 	bswlist.av_forw = bp;
621 	if (bp->b_vp)
622 		brelvp(bp);
623 	if (bswlist.b_flags & B_WANTED) {
624 		bswlist.b_flags &= ~B_WANTED;
625 		thread_wakeup((int)&bswlist);
626 	}
627 	if ((flags & B_READ) == 0 && rv == VM_PAGER_OK) {
628 		m->clean = 1;
629 		pmap_clear_modify(VM_PAGE_TO_PHYS(m));
630 	}
631 	splx(s);
632 #ifdef DEBUG
633 	if (swpagerdebug & SDB_IO)
634 		printf("swpg_io:  IO done: bp %x, rv %d\n", bp, rv);
635 	if ((swpagerdebug & SDB_FAIL) && rv == VM_PAGER_FAIL)
636 		printf("swpg_io: IO error\n");
637 #endif
638 	vm_pager_unmap_page(kva);
639 	return(rv);
640 }
641 
642 boolean_t
643 swap_pager_clean(m, rw)
644 	vm_page_t m;
645 	int rw;
646 {
647 	register swp_clean_t spc, tspc;
648 	register int s;
649 
650 #ifdef DEBUG
651 	/* save panic time state */
652 	if ((swpagerdebug & SDB_ANOMPANIC) && panicstr)
653 		return;
654 	if (swpagerdebug & SDB_FOLLOW)
655 		printf("swpg_clean(%x, %d)\n", m, rw);
656 #endif
657 	tspc = SWP_CLEAN_NULL;
658 	for (;;) {
659 		/*
660 		 * Look up and removal from inuse list must be done
661 		 * at splbio() to avoid conflicts with swap_pager_iodone.
662 		 */
663 		s = splbio();
664 		spc = (swp_clean_t) queue_first(&swap_pager_inuse);
665 		while (!queue_end(&swap_pager_inuse, (queue_entry_t)spc)) {
666 			if ((spc->spc_flags & SPC_DONE) &&
667 			    swap_pager_finish(spc)) {
668 				queue_remove(&swap_pager_inuse, spc,
669 					     swp_clean_t, spc_list);
670 				break;
671 			}
672 			if (m && m == spc->spc_m) {
673 #ifdef DEBUG
674 				if (swpagerdebug & SDB_ANOM)
675 					printf("swpg_clean: %x on list, flags %x\n",
676 					       m, spc->spc_flags);
677 #endif
678 				tspc = spc;
679 			}
680 			spc = (swp_clean_t) queue_next(&spc->spc_list);
681 		}
682 
683 		/*
684 		 * No operations done, thats all we can do for now.
685 		 */
686 		if (queue_end(&swap_pager_inuse, (queue_entry_t)spc))
687 			break;
688 		splx(s);
689 
690 		/*
691 		 * The desired page was found to be busy earlier in
692 		 * the scan but has since completed.
693 		 */
694 		if (tspc && tspc == spc) {
695 #ifdef DEBUG
696 			if (swpagerdebug & SDB_ANOM)
697 				printf("swpg_clean: %x done while looking\n",
698 				       m);
699 #endif
700 			tspc = SWP_CLEAN_NULL;
701 		}
702 		spc->spc_flags = SPC_FREE;
703 		vm_pager_unmap_page(spc->spc_kva);
704 		queue_enter(&swap_pager_free, spc, swp_clean_t, spc_list);
705 #ifdef DEBUG
706 		if (swpagerdebug & SDB_WRITE)
707 			printf("swpg_clean: free spc %x\n", spc);
708 #endif
709 	}
710 	/*
711 	 * If we found that the desired page is already being cleaned
712 	 * mark it so that swap_pager_iodone() will not set the clean
713 	 * flag before the pageout daemon has another chance to clean it.
714 	 */
715 	if (tspc && rw == B_WRITE) {
716 #ifdef DEBUG
717 		if (swpagerdebug & SDB_ANOM)
718 			printf("swpg_clean: %x on clean list\n", tspc);
719 #endif
720 		tspc->spc_flags |= SPC_DIRTY;
721 	}
722 	splx(s);
723 
724 #ifdef DEBUG
725 	if (swpagerdebug & SDB_WRITE)
726 		printf("swpg_clean: return %d\n", tspc ? TRUE : FALSE);
727 	if ((swpagerdebug & SDB_ANOM) && tspc)
728 		printf("swpg_clean: %s of cleaning page %x\n",
729 		       rw == B_READ ? "get" : "put", m);
730 #endif
731 	return(tspc ? TRUE : FALSE);
732 }
733 
734 swap_pager_finish(spc)
735 	register swp_clean_t spc;
736 {
737 	vm_object_t object = spc->spc_m->object;
738 
739 	/*
740 	 * Mark the paging operation as done.
741 	 * (XXX) If we cannot get the lock, leave it til later.
742 	 * (XXX) Also we are assuming that an async write is a
743 	 *       pageout operation that has incremented the counter.
744 	 */
745 	if (!vm_object_lock_try(object))
746 		return(0);
747 
748 #ifdef DEBUG
749 	spc->spc_m->pagerowned = 0;
750 #endif
751 
752 	if (--object->paging_in_progress == 0)
753 		thread_wakeup((int) object);
754 
755 	/*
756 	 * XXX: this isn't even close to the right thing to do,
757 	 * introduces a variety of race conditions.
758 	 *
759 	 * If dirty, vm_pageout() has attempted to clean the page
760 	 * again.  In this case we do not do anything as we will
761 	 * see the page again shortly.  Otherwise, if no error mark
762 	 * as clean and inform the pmap system.  If error, mark as
763 	 * dirty so we will try again (XXX: could get stuck doing
764 	 * this, should give up after awhile).
765 	 */
766 	if ((spc->spc_flags & SPC_DIRTY) == 0) {
767 		if (spc->spc_flags & SPC_ERROR) {
768 			printf("swap_pager: clean of %x failed\n",
769 			       VM_PAGE_TO_PHYS(spc->spc_m));
770 			spc->spc_m->laundry = TRUE;
771 		} else {
772 			spc->spc_m->clean = TRUE;
773 			pmap_clear_modify(VM_PAGE_TO_PHYS(spc->spc_m));
774 		}
775 	}
776 	/*
777 	 * XXX: allow blocked write faults to continue
778 	 */
779 	spc->spc_m->page_lock = spc->spc_m->unlock_request = VM_PROT_NONE;
780 	PAGE_WAKEUP(spc->spc_m);
781 
782 	vm_object_unlock(object);
783 	return(1);
784 }
785 
786 swap_pager_iodone(bp)
787 	register struct buf *bp;
788 {
789 	register swp_clean_t spc;
790 	daddr_t blk;
791 	int s;
792 
793 #ifdef DEBUG
794 	/* save panic time state */
795 	if ((swpagerdebug & SDB_ANOMPANIC) && panicstr)
796 		return;
797 	if (swpagerdebug & SDB_FOLLOW)
798 		printf("swpg_iodone(%x)\n", bp);
799 #endif
800 	s = splbio();
801 	spc = (swp_clean_t) queue_first(&swap_pager_inuse);
802 	while (!queue_end(&swap_pager_inuse, (queue_entry_t)spc)) {
803 		if (spc->spc_bp == bp)
804 			break;
805 		spc = (swp_clean_t) queue_next(&spc->spc_list);
806 	}
807 #ifdef DEBUG
808 	if (queue_end(&swap_pager_inuse, (queue_entry_t)spc))
809 		panic("swpg_iodone: bp not found");
810 #endif
811 
812 	spc->spc_flags &= ~SPC_BUSY;
813 	spc->spc_flags |= SPC_DONE;
814 	if (bp->b_flags & B_ERROR)
815 		spc->spc_flags |= SPC_ERROR;
816 	spc->spc_bp = NULL;
817 	blk = bp->b_blkno;
818 
819 #ifdef DEBUG
820 	--swap_pager_poip;
821 	if (swpagerdebug & SDB_WRITE)
822 		printf("swpg_iodone: bp=%x swp=%x flags=%x spc=%x poip=%x\n",
823 		       bp, spc->spc_swp, spc->spc_swp->sw_flags,
824 		       spc, spc->spc_swp->sw_poip);
825 #endif
826 
827 	spc->spc_swp->sw_poip--;
828 	if (spc->spc_swp->sw_flags & SW_WANTED) {
829 		spc->spc_swp->sw_flags &= ~SW_WANTED;
830 		thread_wakeup((int)spc->spc_swp);
831 	}
832 
833 	bp->b_flags &= ~(B_BUSY|B_WANTED|B_PHYS|B_PAGET|B_UAREA|B_DIRTY);
834 	bp->av_forw = bswlist.av_forw;
835 	bswlist.av_forw = bp;
836 	if (bp->b_vp)
837 		brelvp(bp);
838 	if (bswlist.b_flags & B_WANTED) {
839 		bswlist.b_flags &= ~B_WANTED;
840 		thread_wakeup((int)&bswlist);
841 	}
842 #if 0
843 	/*
844 	 * XXX: this isn't even close to the right thing to do,
845 	 * introduces a variety of race conditions.
846 	 *
847 	 * If dirty, vm_pageout() has attempted to clean the page
848 	 * again.  In this case we do not do anything as we will
849 	 * see the page again shortly.  Otherwise, if no error mark
850 	 * as clean and inform the pmap system.  If error, mark as
851 	 * dirty so we will try again (XXX: could get stuck doing
852 	 * this, should give up after awhile).
853 	 */
854 	if ((spc->spc_flags & SPC_DIRTY) == 0) {
855 		if (spc->spc_flags & SPC_ERROR) {
856 			printf("swap_pager: clean of %x (block %x) failed\n",
857 			       VM_PAGE_TO_PHYS(spc->spc_m), blk);
858 			spc->spc_m->laundry = TRUE;
859 		} else {
860 			spc->spc_m->clean = TRUE;
861 			pmap_clear_modify(VM_PAGE_TO_PHYS(spc->spc_m));
862 		}
863 	}
864 	/*
865 	 * XXX: allow blocked write faults to continue
866 	 */
867 	spc->spc_m->page_lock = spc->spc_m->unlock_request = VM_PROT_NONE;
868 	PAGE_WAKEUP(spc->spc_m);
869 #endif
870 
871 	thread_wakeup((int) &vm_pages_needed);
872 	splx(s);
873 }
874 #endif
875