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