📄 swap_pag.c
字号:
bsize = swap_pager_maxcluster; loff = offset - (offset % bsize); if (loff >= swp->sw_osize) panic("swap_pager_cluster: bad offset"); hoff = loff + bsize; if (hoff > swp->sw_osize) hoff = swp->sw_osize; *loffset = loff; *hoffset = hoff;#ifdef DEBUG if (swpagerdebug & (SDB_FOLLOW|SDB_CLUSTER)) printf("returns [%x-%x]\n", loff, hoff);#endif}/* * Scaled down version of swap(). * Assumes that PAGE_SIZE < MAXPHYS; i.e. only one operation needed. * BOGUS: lower level IO routines expect a KVA so we have to map our * provided physical page into the KVA to keep them happy. */static intswap_pager_io(swp, mlist, npages, flags) register sw_pager_t swp; vm_page_t *mlist; int npages; int flags;{ register struct buf *bp; register sw_blk_t swb; register int s; int ix, mask; boolean_t rv; vm_offset_t kva, off; swp_clean_t spc; vm_page_t m;#ifdef DEBUG /* save panic time state */ if ((swpagerdebug & SDB_ANOMPANIC) && panicstr) return (VM_PAGER_FAIL); /* XXX: correct return? */ if (swpagerdebug & (SDB_FOLLOW|SDB_IO)) printf("swpg_io(%x, %x, %x, %x)\n", swp, mlist, npages, flags); if (flags & B_READ) { if (flags & B_ASYNC) panic("swap_pager_io: cannot do ASYNC reads"); if (npages != 1) panic("swap_pager_io: cannot do clustered reads"); }#endif /* * First determine if the page exists in the pager if this is * a sync read. This quickly handles cases where we are * following shadow chains looking for the top level object * with the page. */ m = *mlist; off = m->offset + m->object->paging_offset; ix = off / dbtob(swp->sw_bsize); if (swp->sw_blocks == NULL || ix >= swp->sw_nblocks) {#ifdef DEBUG if ((flags & B_READ) == 0 && (swpagerdebug & SDB_ANOM)) { printf("swap_pager_io: no swap block on write\n"); return(VM_PAGER_BAD); }#endif return(VM_PAGER_FAIL); } swb = &swp->sw_blocks[ix]; off = off % dbtob(swp->sw_bsize); if ((flags & B_READ) && (swb->swb_block == 0 || (swb->swb_mask & (1 << atop(off))) == 0)) return(VM_PAGER_FAIL); /* * For reads (pageins) and synchronous writes, we clean up * all completed async pageouts. */ if ((flags & B_ASYNC) == 0) { s = splbio(); swap_pager_clean(flags&B_READ);#ifdef DEBUG if (swpagerdebug & SDB_PARANOIA) swap_pager_clean_check(mlist, npages, flags&B_READ);#endif splx(s); } /* * For async writes (pageouts), we cleanup completed pageouts so * that all available resources are freed. Also tells us if this * page is already being cleaned. If it is, or no resources * are available, we try again later. */ else { swap_pager_clean(B_WRITE);#ifdef DEBUG if (swpagerdebug & SDB_PARANOIA) swap_pager_clean_check(mlist, npages, B_WRITE);#endif if (swap_pager_free.tqh_first == NULL) {#ifdef DEBUG if (swpagerdebug & SDB_FAIL) printf("%s: no available io headers\n", "swap_pager_io");#endif return(VM_PAGER_AGAIN); } } /* * Allocate a swap block if necessary. */ if (swb->swb_block == 0) { swb->swb_block = rmalloc(swapmap, swp->sw_bsize); if (swb->swb_block == 0) {#ifdef DEBUG if (swpagerdebug & SDB_FAIL) printf("swpg_io: rmalloc of %x failed\n", swp->sw_bsize);#endif /* * XXX this is technically a resource shortage that * should return AGAIN, but the situation isn't likely * to be remedied just by delaying a little while and * trying again (the pageout daemon's current response * to AGAIN) so we just return FAIL. */ return(VM_PAGER_FAIL); }#ifdef DEBUG if (swpagerdebug & (SDB_FULL|SDB_ALLOCBLK)) printf("swpg_io: %x alloc blk %x at ix %x\n", swp->sw_blocks, swb->swb_block, ix);#endif } /* * Allocate a kernel virtual address and initialize so that PTE * is available for lower level IO drivers. */ kva = vm_pager_map_pages(mlist, npages, !(flags & B_ASYNC)); if (kva == NULL) {#ifdef DEBUG if (swpagerdebug & SDB_FAIL) printf("%s: no KVA space to map pages\n", "swap_pager_io");#endif return(VM_PAGER_AGAIN); } /* * Get a swap buffer header and initialize it. */ s = splbio(); while (bswlist.b_actf == NULL) {#ifdef DEBUG if (swpagerdebug & SDB_ANOM) printf("swap_pager_io: wait on swbuf for %x (%d)\n", m, flags);#endif bswlist.b_flags |= B_WANTED; tsleep((caddr_t)&bswlist, PSWP+1, "swpgiobuf", 0); } bp = bswlist.b_actf; bswlist.b_actf = bp->b_actf; splx(s); bp->b_flags = B_BUSY | (flags & B_READ); bp->b_proc = &proc0; /* XXX (but without B_PHYS set this is ok) */ bp->b_data = (caddr_t)kva; bp->b_blkno = swb->swb_block + btodb(off); VHOLD(swapdev_vp); bp->b_vp = swapdev_vp; if (swapdev_vp->v_type == VBLK) bp->b_dev = swapdev_vp->v_rdev; bp->b_bcount = npages * PAGE_SIZE; /* * For writes we set up additional buffer fields, record a pageout * in progress and mark that these swap blocks are now allocated. */ if ((bp->b_flags & B_READ) == 0) { bp->b_dirtyoff = 0; bp->b_dirtyend = npages * PAGE_SIZE; swapdev_vp->v_numoutput++; s = splbio(); swp->sw_poip++; splx(s); mask = (~(~0 << npages)) << atop(off);#ifdef DEBUG swap_pager_poip++; if (swpagerdebug & SDB_WRITE) printf("swpg_io: write: bp=%x swp=%x poip=%d\n", bp, swp, swp->sw_poip); if ((swpagerdebug & SDB_ALLOCBLK) && (swb->swb_mask & mask) != mask) printf("swpg_io: %x write %d pages at %x+%x\n", swp->sw_blocks, npages, swb->swb_block, atop(off)); if (swpagerdebug & SDB_CLUSTER) printf("swpg_io: off=%x, npg=%x, mask=%x, bmask=%x\n", off, npages, mask, swb->swb_mask);#endif swb->swb_mask |= mask; } /* * If this is an async write we set up still more buffer fields * and place a "cleaning" entry on the inuse queue. */ if ((flags & (B_READ|B_ASYNC)) == B_ASYNC) {#ifdef DEBUG if (swap_pager_free.tqh_first == NULL) panic("swpg_io: lost spc");#endif spc = swap_pager_free.tqh_first; TAILQ_REMOVE(&swap_pager_free, spc, spc_list);#ifdef DEBUG if (spc->spc_flags != SPC_FREE) panic("swpg_io: bad free spc");#endif spc->spc_flags = SPC_BUSY; spc->spc_bp = bp; spc->spc_swp = swp; spc->spc_kva = kva; /* * Record the first page. This allows swap_pager_clean * to efficiently handle the common case of a single page. * For clusters, it allows us to locate the object easily * and we then reconstruct the rest of the mlist from spc_kva. */ spc->spc_m = m; spc->spc_npages = npages; bp->b_flags |= B_CALL; bp->b_iodone = swap_pager_iodone; s = splbio(); TAILQ_INSERT_TAIL(&swap_pager_inuse, spc, spc_list); splx(s); } /* * Finally, start the IO operation. * If it is async we are all done, otherwise we must wait for * completion and cleanup afterwards. */#ifdef DEBUG if (swpagerdebug & SDB_IO) printf("swpg_io: IO start: bp %x, db %x, va %x, pa %x\n", bp, swb->swb_block+btodb(off), kva, VM_PAGE_TO_PHYS(m));#endif VOP_STRATEGY(bp); if ((flags & (B_READ|B_ASYNC)) == B_ASYNC) {#ifdef DEBUG if (swpagerdebug & SDB_IO) printf("swpg_io: IO started: bp %x\n", bp);#endif return(VM_PAGER_PEND); } s = splbio();#ifdef DEBUG if (flags & B_READ) swap_pager_piip++; else swap_pager_poip++;#endif while ((bp->b_flags & B_DONE) == 0) (void) tsleep(bp, PVM, "swpgio", 0); if ((flags & B_READ) == 0) --swp->sw_poip;#ifdef DEBUG if (flags & B_READ) --swap_pager_piip; else --swap_pager_poip;#endif rv = (bp->b_flags & B_ERROR) ? VM_PAGER_ERROR : VM_PAGER_OK; bp->b_flags &= ~(B_BUSY|B_WANTED|B_PHYS|B_PAGET|B_UAREA|B_DIRTY); bp->b_actf = bswlist.b_actf; bswlist.b_actf = bp; if (bp->b_vp) brelvp(bp); if (bswlist.b_flags & B_WANTED) { bswlist.b_flags &= ~B_WANTED; wakeup(&bswlist); } if ((flags & B_READ) == 0 && rv == VM_PAGER_OK) { m->flags |= PG_CLEAN; pmap_clear_modify(VM_PAGE_TO_PHYS(m)); } splx(s);#ifdef DEBUG if (swpagerdebug & SDB_IO) printf("swpg_io: IO done: bp %x, rv %d\n", bp, rv); if ((swpagerdebug & SDB_FAIL) && rv == VM_PAGER_ERROR) printf("swpg_io: IO error\n");#endif vm_pager_unmap_pages(kva, npages); return(rv);}static voidswap_pager_clean(rw) int rw;{ register swp_clean_t spc; register int s, i; vm_object_t object; vm_page_t m;#ifdef DEBUG /* save panic time state */ if ((swpagerdebug & SDB_ANOMPANIC) && panicstr) return; if (swpagerdebug & SDB_FOLLOW) printf("swpg_clean(%x)\n", rw);#endif for (;;) { /* * Look up and removal from inuse list must be done * at splbio() to avoid conflicts with swap_pager_iodone. */ s = splbio(); for (spc = swap_pager_inuse.tqh_first; spc != NULL; spc = spc->spc_list.tqe_next) { /* * If the operation is done, remove it from the * list and process it. * * XXX if we can't get the object lock we also * leave it on the list and try again later. * Is there something better we could do? */ if ((spc->spc_flags & SPC_DONE) && vm_object_lock_try(spc->spc_m->object)) { TAILQ_REMOVE(&swap_pager_inuse, spc, spc_list); break; } } splx(s); /* * No operations done, thats all we can do for now. */ if (spc == NULL) break; /* * Found a completed operation so finish it off. * Note: no longer at splbio since entry is off the list. */ m = spc->spc_m; object = m->object; /* * Process each page in the cluster. * The first page is explicitly kept in the cleaning * entry, others must be reconstructed from the KVA. */ for (i = 0; i < spc->spc_npages; i++) { if (i) m = vm_pager_atop(spc->spc_kva + ptoa(i)); /* * If no error mark as clean and inform the pmap * system. If there was an error, mark as dirty * so we will try again. * * XXX could get stuck doing this, should give up * after awhile. */ if (spc->spc_flags & SPC_ERROR) { printf("%s: clean of page %x failed\n", "swap_pager_clean", VM_PAGE_TO_PHYS(m)); m->flags |= PG_LAUNDRY; } else { m->flags |= PG_CLEAN; pmap_clear_modify(VM_PAGE_TO_PHYS(m)); } m->flags &= ~PG_BUSY; PAGE_WAKEUP(m); } /* * Done with the object, decrement the paging count * and unlock it. */ if (--object->paging_in_progress == 0) wakeup(object); vm_object_unlock(object); /* * Free up KVM used and put the entry back on the list. */ vm_pager_unmap_pages(spc->spc_kva, spc->spc_npages); spc->spc_flags = SPC_FREE; TAILQ_INSERT_TAIL(&swap_pager_free, spc, spc_list);#ifdef DEBUG if (swpagerdebug & SDB_WRITE) printf("swpg_clean: free spc %x\n", spc);#endif }}#ifdef DEBUGstatic voidswap_pager_clean_check(mlist, npages, rw) vm_page_t *mlist; int npages; int rw;{ register swp_clean_t spc; boolean_t bad; int i, j, s; vm_page_t m; if (panicstr) return; bad = FALSE; s = splbio(); for (spc = swap_pager_inuse.tqh_first; spc != NULL; spc = spc->spc_list.tqe_next) { for (j = 0; j < spc->spc_npages; j++) { m = vm_pager_atop(spc->spc_kva + ptoa(j)); for (i = 0; i < npages; i++) if (m == mlist[i]) { if (swpagerdebug & SDB_ANOM) printf( "swpg_clean_check: %s: page %x on list, flags %x\n", rw == B_WRITE ? "write" : "read", mlist[i], spc->spc_flags); bad = TRUE; } } } splx(s); if (bad) panic("swpg_clean_check");}#endifstatic voidswap_pager_iodone(bp) register struct buf *bp;{ register swp_clean_t spc; daddr_t blk; int s;#ifdef DEBUG /* save panic time state */ if ((swpagerdebug & SDB_ANOMPANIC) && panicstr) return; if (swpagerdebug & SDB_FOLLOW) printf("swpg_iodone(%x)\n", bp);#endif s = splbio(); for (spc = swap_pager_inuse.tqh_first; spc != NULL; spc = spc->spc_list.tqe_next) if (spc->spc_bp == bp) break;#ifdef DEBUG if (spc == NULL) panic("swap_pager_iodone: bp not found");#endif spc->spc_flags &= ~SPC_BUSY; spc->spc_flags |= SPC_DONE; if (bp->b_flags & B_ERROR) spc->spc_flags |= SPC_ERROR; spc->spc_bp = NULL; blk = bp->b_blkno;#ifdef DEBUG --swap_pager_poip; if (swpagerdebug & SDB_WRITE) printf("swpg_iodone: bp=%x swp=%x flags=%x spc=%x poip=%x\n", bp, spc->spc_swp, spc->spc_swp->sw_flags, spc, spc->spc_swp->sw_poip);#endif spc->spc_swp->sw_poip--; if (spc->spc_swp->sw_flags & SW_WANTED) { spc->spc_swp->sw_flags &= ~SW_WANTED; wakeup(spc->spc_swp); } bp->b_flags &= ~(B_BUSY|B_WANTED|B_PHYS|B_PAGET|B_UAREA|B_DIRTY); bp->b_actf = bswlist.b_actf; bswlist.b_actf = bp; if (bp->b_vp) brelvp(bp); if (bswlist.b_flags & B_WANTED) { bswlist.b_flags &= ~B_WANTED; wakeup(&bswlist); } wakeup(&vm_pages_needed); splx(s);}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -