|
|
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.