|
|
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: */
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 "map.h"
57: #include "systm.h"
58: #include "specdev.h"
59: #include "vnode.h"
60: #include "malloc.h"
61: #include "queue.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:
72: #define NSWSIZES 16 /* size of swtab */
73: #define NPENDINGIO 64 /* max # of pending cleans */
74: #define MAXDADDRS 64 /* max # of disk addrs for fixed allocations */
75:
76: #ifdef DEBUG
77: int swpagerdebug = 0x100;
78: #define SDB_FOLLOW 0x001
79: #define SDB_INIT 0x002
80: #define SDB_ALLOC 0x004
81: #define SDB_IO 0x008
82: #define SDB_WRITE 0x010
83: #define SDB_FAIL 0x020
84: #define SDB_ALLOCBLK 0x040
85: #define SDB_FULL 0x080
86: #define SDB_ANOM 0x100
87: #define SDB_ANOMPANIC 0x200
88: #endif
89:
90: struct swpagerclean {
91: queue_head_t spc_list;
92: int spc_flags;
93: struct buf *spc_bp;
94: sw_pager_t spc_swp;
95: vm_offset_t spc_kva;
96: vm_page_t spc_m;
97: } swcleanlist[NPENDINGIO];
98: typedef struct swpagerclean *swp_clean_t;
99:
100: /* spc_flags values */
101: #define SPC_FREE 0x00
102: #define SPC_BUSY 0x01
103: #define SPC_DONE 0x02
104: #define SPC_ERROR 0x04
105: #define SPC_DIRTY 0x08
106:
107: struct swtab {
108: vm_size_t st_osize; /* size of object (bytes) */
109: int st_bsize; /* vs. size of swap block (DEV_BSIZE units) */
110: #ifdef DEBUG
111: u_long st_inuse; /* number in this range in use */
112: u_long st_usecnt; /* total used of this size */
113: #endif
114: } swtab[NSWSIZES+1];
115:
116: #ifdef DEBUG
117: int swap_pager_pendingio; /* max pending async "clean" ops */
118: int swap_pager_poip; /* pageouts in progress */
119: int swap_pager_piip; /* pageins in progress */
120: #endif
121:
122: queue_head_t swap_pager_inuse; /* list of pending page cleans */
123: queue_head_t swap_pager_free; /* list of free pager clean structs */
124: queue_head_t swap_pager_list; /* list of "named" anon regions */
125:
126: void
127: swap_pager_init()
128: {
129: register swp_clean_t spc;
130: register int i, bsize;
131: extern int dmmin, dmmax;
132: int maxbsize;
133:
134: #ifdef DEBUG
135: if (swpagerdebug & (SDB_FOLLOW|SDB_INIT))
136: printf("swpg_init()\n");
137: #endif
138: dfltpagerops = &swappagerops;
139: queue_init(&swap_pager_list);
140:
141: /*
142: * Initialize clean lists
143: */
144: queue_init(&swap_pager_inuse);
145: queue_init(&swap_pager_free);
146: for (i = 0, spc = swcleanlist; i < NPENDINGIO; i++, spc++) {
147: queue_enter(&swap_pager_free, spc, swp_clean_t, spc_list);
148: spc->spc_flags = SPC_FREE;
149: }
150:
151: /*
152: * Calculate the swap allocation constants.
153: */
154: if (dmmin == 0) {
155: dmmin = DMMIN;
156: if (dmmin < CLBYTES/DEV_BSIZE)
157: dmmin = CLBYTES/DEV_BSIZE;
158: }
159: if (dmmax == 0)
160: dmmax = DMMAX;
161:
162: /*
163: * Fill in our table of object size vs. allocation size
164: */
165: bsize = btodb(PAGE_SIZE);
166: if (bsize < dmmin)
167: bsize = dmmin;
168: maxbsize = btodb(sizeof(sw_bm_t) * NBBY * PAGE_SIZE);
169: if (maxbsize > dmmax)
170: maxbsize = dmmax;
171: for (i = 0; i < NSWSIZES; i++) {
172: swtab[i].st_osize = (vm_size_t) (MAXDADDRS * dbtob(bsize));
173: swtab[i].st_bsize = bsize;
174: #ifdef DEBUG
175: if (swpagerdebug & SDB_INIT)
176: printf("swpg_init: ix %d, size %x, bsize %x\n",
177: i, swtab[i].st_osize, swtab[i].st_bsize);
178: #endif
179: if (bsize >= maxbsize)
180: break;
181: bsize *= 2;
182: }
183: swtab[i].st_osize = 0;
184: swtab[i].st_bsize = bsize;
185: }
186:
187: /*
188: * Allocate a pager structure and associated resources.
189: * Note that if we are called from the pageout daemon (handle == NULL)
190: * we should not wait for memory as it could resulting in deadlock.
191: */
192: vm_pager_t
193: swap_pager_alloc(handle, size, prot)
194: caddr_t handle;
195: register vm_size_t size;
196: vm_prot_t prot;
197: {
198: register vm_pager_t pager;
199: register sw_pager_t swp;
200: struct swtab *swt;
201: int waitok;
202:
203: #ifdef DEBUG
204: if (swpagerdebug & (SDB_FOLLOW|SDB_ALLOC))
205: printf("swpg_alloc(%x, %x, %x)\n", handle, size, prot);
206: #endif
207: /*
208: * If this is a "named" anonymous region, look it up and
209: * return the appropriate pager if it exists.
210: */
211: if (handle) {
212: pager = vm_pager_lookup(&swap_pager_list, handle);
213: if (pager != NULL) {
214: /*
215: * Use vm_object_lookup to gain a reference
216: * to the object and also to remove from the
217: * object cache.
218: */
219: if (vm_object_lookup(pager) == NULL)
220: panic("swap_pager_alloc: bad object");
221: return(pager);
222: }
223: }
224: /*
225: * Pager doesn't exist, allocate swap management resources
226: * and initialize.
227: */
228: waitok = handle ? M_WAITOK : M_NOWAIT;
229: pager = (vm_pager_t)malloc(sizeof *pager, M_VMPAGER, waitok);
230: if (pager == NULL)
231: return(NULL);
232: swp = (sw_pager_t)malloc(sizeof *swp, M_VMPGDATA, waitok);
233: if (swp == NULL) {
234: #ifdef DEBUG
235: if (swpagerdebug & SDB_FAIL)
236: printf("swpg_alloc: swpager malloc failed\n");
237: #endif
238: free((caddr_t)pager, M_VMPAGER);
239: return(NULL);
240: }
241: size = round_page(size);
242: for (swt = swtab; swt->st_osize; swt++)
243: if (size <= swt->st_osize)
244: break;
245: #ifdef DEBUG
246: swt->st_inuse++;
247: swt->st_usecnt++;
248: #endif
249: swp->sw_osize = size;
250: swp->sw_bsize = swt->st_bsize;
251: swp->sw_nblocks = (btodb(size) + swp->sw_bsize - 1) / swp->sw_bsize;
252: swp->sw_blocks = (sw_blk_t)
253: malloc(swp->sw_nblocks*sizeof(*swp->sw_blocks),
254: M_VMPGDATA, M_NOWAIT);
255: if (swp->sw_blocks == NULL) {
256: free((caddr_t)swp, M_VMPGDATA);
257: free((caddr_t)pager, M_VMPAGER);
258: #ifdef DEBUG
259: if (swpagerdebug & SDB_FAIL)
260: printf("swpg_alloc: sw_blocks malloc failed\n");
261: swt->st_inuse--;
262: swt->st_usecnt--;
263: #endif
264: return(FALSE);
265: }
266: bzero((caddr_t)swp->sw_blocks,
267: swp->sw_nblocks * sizeof(*swp->sw_blocks));
268: swp->sw_poip = 0;
269: if (handle) {
270: vm_object_t object;
271:
272: swp->sw_flags = SW_NAMED;
273: queue_enter(&swap_pager_list, pager, vm_pager_t, pg_list);
274: /*
275: * Consistant with other pagers: return with object
276: * referenced. Can't do this with handle == NULL
277: * since it might be the pageout daemon calling.
278: */
279: object = vm_object_allocate(size);
280: vm_object_enter(object, pager);
281: vm_object_setpager(object, pager, 0, FALSE);
282: } else {
283: swp->sw_flags = 0;
284: queue_init(&pager->pg_list);
285: }
286: pager->pg_handle = handle;
287: pager->pg_ops = &swappagerops;
288: pager->pg_type = PG_SWAP;
289: pager->pg_data = (caddr_t)swp;
290:
291: #ifdef DEBUG
292: if (swpagerdebug & SDB_ALLOC)
293: printf("swpg_alloc: pg_data %x, %x of %x at %x\n",
294: swp, swp->sw_nblocks, swp->sw_bsize, swp->sw_blocks);
295: #endif
296: return(pager);
297: }
298:
299: void
300: swap_pager_dealloc(pager)
301: vm_pager_t pager;
302: {
303: register int i;
304: register sw_blk_t bp;
305: register sw_pager_t swp;
306: struct swtab *swt;
307: int s;
308:
309: #ifdef DEBUG
310: /* save panic time state */
311: if ((swpagerdebug & SDB_ANOMPANIC) && panicstr)
312: return;
313: if (swpagerdebug & (SDB_FOLLOW|SDB_ALLOC))
314: printf("swpg_dealloc(%x)\n", pager);
315: #endif
316: /*
317: * Remove from list right away so lookups will fail if we
318: * block for pageout completion.
319: */
320: swp = (sw_pager_t) pager->pg_data;
321: if (swp->sw_flags & SW_NAMED) {
322: queue_remove(&swap_pager_list, pager, vm_pager_t, pg_list);
323: swp->sw_flags &= ~SW_NAMED;
324: }
325: #ifdef DEBUG
326: for (swt = swtab; swt->st_osize; swt++)
327: if (swp->sw_osize <= swt->st_osize)
328: break;
329: swt->st_inuse--;
330: #endif
331:
332: /*
333: * Wait for all pageouts to finish and remove
334: * all entries from cleaning list.
335: */
336: s = splbio();
337: while (swp->sw_poip) {
338: swp->sw_flags |= SW_WANTED;
339: assert_wait((int)swp);
340: thread_block();
341: }
342: splx(s);
343: (void) swap_pager_clean(NULL, B_WRITE);
344:
345: /*
346: * Free left over swap blocks
347: */
348: for (i = 0, bp = swp->sw_blocks; i < swp->sw_nblocks; i++, bp++)
349: if (bp->swb_block) {
350: #ifdef DEBUG
351: if (swpagerdebug & (SDB_ALLOCBLK|SDB_FULL))
352: printf("swpg_dealloc: blk %x\n",
353: bp->swb_block);
354: #endif
355: rmfree(swapmap, swp->sw_bsize, bp->swb_block);
356: }
357: /*
358: * Free swap management resources
359: */
360: free((caddr_t)swp->sw_blocks, M_VMPGDATA);
361: free((caddr_t)swp, M_VMPGDATA);
362: free((caddr_t)pager, M_VMPAGER);
363: }
364:
365: swap_pager_getpage(pager, m, sync)
366: vm_pager_t pager;
367: vm_page_t m;
368: boolean_t sync;
369: {
370: #ifdef DEBUG
371: if (swpagerdebug & SDB_FOLLOW)
372: printf("swpg_getpage(%x, %x, %d)\n", pager, m, sync);
373: #endif
374: return(swap_pager_io((sw_pager_t)pager->pg_data, m, B_READ));
375: }
376:
377: swap_pager_putpage(pager, m, sync)
378: vm_pager_t pager;
379: vm_page_t m;
380: boolean_t sync;
381: {
382: int flags;
383:
384: #ifdef DEBUG
385: if (swpagerdebug & SDB_FOLLOW)
386: printf("swpg_putpage(%x, %x, %d)\n", pager, m, sync);
387: #endif
388: if (pager == NULL) {
389: (void) swap_pager_clean(NULL, B_WRITE);
390: return;
391: }
392: flags = B_WRITE;
393: if (!sync)
394: flags |= B_ASYNC;
395: return(swap_pager_io((sw_pager_t)pager->pg_data, m, flags));
396: }
397:
398: boolean_t
399: swap_pager_haspage(pager, offset)
400: vm_pager_t pager;
401: vm_offset_t offset;
402: {
403: register sw_pager_t swp;
404: register sw_blk_t swb;
405: int ix;
406:
407: #ifdef DEBUG
408: if (swpagerdebug & (SDB_FOLLOW|SDB_ALLOCBLK))
409: printf("swpg_haspage(%x, %x) ", pager, offset);
410: #endif
411: swp = (sw_pager_t) pager->pg_data;
412: ix = offset / dbtob(swp->sw_bsize);
413: if (swp->sw_blocks == NULL || ix >= swp->sw_nblocks) {
414: #ifdef DEBUG
415: if (swpagerdebug & (SDB_FAIL|SDB_FOLLOW|SDB_ALLOCBLK))
416: printf("swpg_haspage: %x bad offset %x, ix %x\n",
417: swp->sw_blocks, offset, ix);
418: #endif
419: return(FALSE);
420: }
421: swb = &swp->sw_blocks[ix];
422: if (swb->swb_block)
423: ix = atop(offset % dbtob(swp->sw_bsize));
424: #ifdef DEBUG
425: if (swpagerdebug & SDB_ALLOCBLK)
426: printf("%x blk %x+%x ", swp->sw_blocks, swb->swb_block, ix);
427: if (swpagerdebug & (SDB_FOLLOW|SDB_ALLOCBLK))
428: printf("-> %c\n",
429: "FT"[swb->swb_block && (swb->swb_mask & (1 << ix))]);
430: #endif
431: if (swb->swb_block && (swb->swb_mask & (1 << ix)))
432: return(TRUE);
433: return(FALSE);
434: }
435:
436: /*
437: * Scaled down version of swap().
438: * Assumes that PAGE_SIZE < MAXPHYS; i.e. only one operation needed.
439: * BOGUS: lower level IO routines expect a KVA so we have to map our
440: * provided physical page into the KVA to keep them happy.
441: */
442: swap_pager_io(swp, m, flags)
443: register sw_pager_t swp;
444: vm_page_t m;
445: int flags;
446: {
447: register struct buf *bp;
448: register sw_blk_t swb;
449: register int s;
450: int ix;
451: boolean_t rv;
452: vm_offset_t kva, off;
453: swp_clean_t spc;
454:
455: #ifdef DEBUG
456: /* save panic time state */
457: if ((swpagerdebug & SDB_ANOMPANIC) && panicstr)
458: return;
459: if (swpagerdebug & (SDB_FOLLOW|SDB_IO))
460: printf("swpg_io(%x, %x, %x)\n", swp, m, flags);
461: #endif
462:
463: /*
464: * For reads (pageins) and synchronous writes, we clean up
465: * all completed async pageouts.
466: */
467: if ((flags & B_ASYNC) == 0) {
468: s = splbio();
469: #ifdef DEBUG
470: /*
471: * Check to see if this page is currently being cleaned.
472: * If it is, we just wait til the operation is done before
473: * continuing.
474: */
475: while (swap_pager_clean(m, flags&B_READ)) {
476: if (swpagerdebug & SDB_ANOM)
477: printf("swap_pager_io: page %x cleaning\n", m);
478:
479: swp->sw_flags |= SW_WANTED;
480: assert_wait((int)swp);
481: thread_block();
482: }
483: #else
484: (void) swap_pager_clean(m, flags&B_READ);
485: #endif
486: splx(s);
487: }
488: /*
489: * For async writes (pageouts), we cleanup completed pageouts so
490: * that all available resources are freed. Also tells us if this
491: * page is already being cleaned. If it is, or no resources
492: * are available, we try again later.
493: */
494: else if (swap_pager_clean(m, B_WRITE) ||
495: queue_empty(&swap_pager_free)) {
496: #ifdef DEBUG
497: if ((swpagerdebug & SDB_ANOM) &&
498: !queue_empty(&swap_pager_free))
499: printf("swap_pager_io: page %x already cleaning\n", m);
500: #endif
501: return(VM_PAGER_FAIL);
502: }
503:
504: /*
505: * Determine swap block and allocate as necessary.
506: */
507: off = m->offset + m->object->paging_offset;
508: ix = off / dbtob(swp->sw_bsize);
509: if (swp->sw_blocks == NULL || ix >= swp->sw_nblocks) {
510: #ifdef DEBUG
511: if (swpagerdebug & SDB_FAIL)
512: printf("swpg_io: bad offset %x+%x(%d) in %x\n",
513: m->offset, m->object->paging_offset,
514: ix, swp->sw_blocks);
515: #endif
516: return(VM_PAGER_FAIL);
517: }
518: swb = &swp->sw_blocks[ix];
519: off = off % dbtob(swp->sw_bsize);
520: if (flags & B_READ) {
521: if (swb->swb_block == 0 ||
522: (swb->swb_mask & (1 << atop(off))) == 0) {
523: #ifdef DEBUG
524: if (swpagerdebug & (SDB_ALLOCBLK|SDB_FAIL))
525: printf("swpg_io: %x bad read: blk %x+%x, mask %x, off %x+%x\n",
526: swp->sw_blocks,
527: swb->swb_block, atop(off),
528: swb->swb_mask,
529: m->offset, m->object->paging_offset);
530: #endif
531: /* XXX: should we zero page here?? */
532: return(VM_PAGER_FAIL);
533: }
534: } else if (swb->swb_block == 0) {
535: swb->swb_block = rmalloc(swapmap, swp->sw_bsize);
536: if (swb->swb_block == 0) {
537: #ifdef DEBUG
538: if (swpagerdebug & SDB_FAIL)
539: printf("swpg_io: rmalloc of %x failed\n",
540: swp->sw_bsize);
541: #endif
542: return(VM_PAGER_FAIL);
543: }
544: #ifdef DEBUG
545: if (swpagerdebug & (SDB_FULL|SDB_ALLOCBLK))
546: printf("swpg_io: %x alloc blk %x at ix %x\n",
547: swp->sw_blocks, swb->swb_block, ix);
548: #endif
549: }
550:
551: /*
552: * Allocate a kernel virtual address and initialize so that PTE
553: * is available for lower level IO drivers.
554: */
555: kva = vm_pager_map_page(m);
556:
557: /*
558: * Get a swap buffer header and perform the IO
559: */
560: s = splbio();
561: while (bswlist.av_forw == NULL) {
562: #ifdef DEBUG
563: if (swpagerdebug & SDB_ANOM)
564: printf("swap_pager_io: wait on swbuf for %x (%d)\n",
565: m, flags);
566: #endif
567: bswlist.b_flags |= B_WANTED;
568: sleep((caddr_t)&bswlist, PSWP+1);
569: }
570: bp = bswlist.av_forw;
571: bswlist.av_forw = bp->av_forw;
572: splx(s);
573: bp->b_flags = B_BUSY | (flags & B_READ);
574: bp->b_proc = &proc0; /* XXX (but without B_PHYS set this is ok) */
575: bp->b_un.b_addr = (caddr_t)kva;
576: bp->b_blkno = swb->swb_block + btodb(off);
577: VHOLD(swapdev_vp);
578: bp->b_vp = swapdev_vp;
579: if (swapdev_vp->v_type == VBLK)
580: bp->b_dev = swapdev_vp->v_rdev;
581: bp->b_bcount = PAGE_SIZE;
582: if ((bp->b_flags & B_READ) == 0)
583: swapdev_vp->v_numoutput++;
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;
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));
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) {
645: assert_wait((int)bp);
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) {
665: m->clean = TRUE;
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:
679: boolean_t
680: swap_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
694: tspc = NULL;
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)
712: printf("swap_pager_clean: page %x on list, flags %x\n",
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)
734: printf("swap_pager_clean: page %x done while looking\n",
735: m);
736: #endif
737: tspc = NULL;
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: }
747: #ifdef DEBUG
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) {
754: if (swpagerdebug & SDB_ANOM)
755: printf("swap_pager_clean: page %x on clean list\n",
756: tspc);
757: tspc->spc_flags |= SPC_DIRTY;
758: }
759: #endif
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:
772: swap_pager_finish(spc)
773: register swp_clean_t spc;
774: {
775: vm_object_t object = spc->spc_m->object;
776:
777: /*
778: * Mark the paging operation as done.
779: * (XXX) If we cannot get the lock, leave it til later.
780: * (XXX) Also we are assuming that an async write is a
781: * pageout operation that has incremented the counter.
782: */
783: if (!vm_object_lock_try(object))
784: return(0);
785:
786: if (--object->paging_in_progress == 0)
787: thread_wakeup((int) object);
788:
789: #ifdef DEBUG
790: /*
791: * XXX: this isn't even close to the right thing to do,
792: * introduces a variety of race conditions.
793: *
794: * If dirty, vm_pageout() has attempted to clean the page
795: * again. In this case we do not do anything as we will
796: * see the page again shortly.
797: */
798: if (spc->spc_flags & SPC_DIRTY) {
799: if (swpagerdebug & SDB_ANOM)
800: printf("swap_pager_finish: page %x dirty again\n",
801: spc->spc_m);
802: spc->spc_m->busy = FALSE;
803: PAGE_WAKEUP(spc->spc_m);
804: vm_object_unlock(object);
805: return(1);
806: }
807: #endif
808: /*
809: * If no error mark as clean and inform the pmap system.
810: * If error, mark as dirty so we will try again.
811: * (XXX could get stuck doing this, should give up after awhile)
812: */
813: if (spc->spc_flags & SPC_ERROR) {
814: printf("swap_pager_finish: clean of page %x failed\n",
815: VM_PAGE_TO_PHYS(spc->spc_m));
816: spc->spc_m->laundry = TRUE;
817: } else {
818: spc->spc_m->clean = TRUE;
819: pmap_clear_modify(VM_PAGE_TO_PHYS(spc->spc_m));
820: }
821: spc->spc_m->busy = FALSE;
822: PAGE_WAKEUP(spc->spc_m);
823:
824: vm_object_unlock(object);
825: return(1);
826: }
827:
828: swap_pager_iodone(bp)
829: register struct buf *bp;
830: {
831: register swp_clean_t spc;
832: daddr_t blk;
833: int s;
834:
835: #ifdef DEBUG
836: /* save panic time state */
837: if ((swpagerdebug & SDB_ANOMPANIC) && panicstr)
838: return;
839: if (swpagerdebug & SDB_FOLLOW)
840: printf("swpg_iodone(%x)\n", bp);
841: #endif
842: s = splbio();
843: spc = (swp_clean_t) queue_first(&swap_pager_inuse);
844: while (!queue_end(&swap_pager_inuse, (queue_entry_t)spc)) {
845: if (spc->spc_bp == bp)
846: break;
847: spc = (swp_clean_t) queue_next(&spc->spc_list);
848: }
849: #ifdef DEBUG
850: if (queue_end(&swap_pager_inuse, (queue_entry_t)spc))
851: panic("swap_pager_iodone: bp not found");
852: #endif
853:
854: spc->spc_flags &= ~SPC_BUSY;
855: spc->spc_flags |= SPC_DONE;
856: if (bp->b_flags & B_ERROR)
857: spc->spc_flags |= SPC_ERROR;
858: spc->spc_bp = NULL;
859: blk = bp->b_blkno;
860:
861: #ifdef DEBUG
862: --swap_pager_poip;
863: if (swpagerdebug & SDB_WRITE)
864: printf("swpg_iodone: bp=%x swp=%x flags=%x spc=%x poip=%x\n",
865: bp, spc->spc_swp, spc->spc_swp->sw_flags,
866: spc, spc->spc_swp->sw_poip);
867: #endif
868:
869: spc->spc_swp->sw_poip--;
870: if (spc->spc_swp->sw_flags & SW_WANTED) {
871: spc->spc_swp->sw_flags &= ~SW_WANTED;
872: thread_wakeup((int)spc->spc_swp);
873: }
874:
875: bp->b_flags &= ~(B_BUSY|B_WANTED|B_PHYS|B_PAGET|B_UAREA|B_DIRTY);
876: bp->av_forw = bswlist.av_forw;
877: bswlist.av_forw = bp;
878: if (bp->b_vp)
879: brelvp(bp);
880: if (bswlist.b_flags & B_WANTED) {
881: bswlist.b_flags &= ~B_WANTED;
882: thread_wakeup((int)&bswlist);
883: }
884: thread_wakeup((int) &vm_pages_needed);
885: splx(s);
886: }
887: #endif
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.