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