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