⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 swap_pag.c

📁 open bsd vm device design
💻 C
📖 第 1 页 / 共 2 页
字号:
		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 + -