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