diff options
Diffstat (limited to 'sys/vm/vnode_pager.c')
-rw-r--r-- | sys/vm/vnode_pager.c | 610 |
1 files changed, 207 insertions, 403 deletions
diff --git a/sys/vm/vnode_pager.c b/sys/vm/vnode_pager.c index 2768260..eedef9e 100644 --- a/sys/vm/vnode_pager.c +++ b/sys/vm/vnode_pager.c @@ -37,7 +37,7 @@ * SUCH DAMAGE. * * from: @(#)vnode_pager.c 7.5 (Berkeley) 4/20/91 - * $Id: vnode_pager.c,v 1.17 1994/11/17 01:22:45 gibbs Exp $ + * $Id: vnode_pager.c,v 1.18 1994/11/24 14:43:22 davidg Exp $ */ /* @@ -68,6 +68,7 @@ #include <sys/param.h> #include <sys/systm.h> +#include <sys/kernel.h> #include <sys/proc.h> #include <sys/malloc.h> #include <sys/vnode.h> @@ -81,14 +82,14 @@ #include <sys/buf.h> #include <miscfs/specfs/specdev.h> -int vnode_pager_putmulti(); +int vnode_pager_putmulti(); -void vnode_pager_init(); +void vnode_pager_init(); vm_pager_t vnode_pager_alloc(caddr_t, vm_offset_t, vm_prot_t, vm_offset_t); -void vnode_pager_dealloc(); -int vnode_pager_getpage(); -int vnode_pager_getmulti(); -int vnode_pager_putpage(); +void vnode_pager_dealloc(); +int vnode_pager_getpage(); +int vnode_pager_getmulti(); +int vnode_pager_putpage(); boolean_t vnode_pager_haspage(); struct pagerops vnodepagerops = { @@ -132,10 +133,11 @@ vnode_pager_alloc(handle, size, prot, offset) { register vm_pager_t pager; register vn_pager_t vnp; - vm_object_t object; + vm_object_t object, tobject; struct vattr vattr; struct vnode *vp; struct proc *p = curproc; /* XXX */ + int rtval; /* * Pageout to vnode, no can do yet. @@ -148,9 +150,11 @@ vnode_pager_alloc(handle, size, prot, offset) * with vm_pager_lookup. */ vp = (struct vnode *) handle; - object = (vm_object_t) vp->v_vmdata; + while ((object = (vm_object_t) vp->v_vmdata) && (object->flags & OBJ_DEAD)) + tsleep((caddr_t) object, PVM, "vadead", 0); + pager = NULL; - if( object != NULL) + if (object != NULL) pager = object->pager; if (pager == NULL) { @@ -165,15 +169,15 @@ vnode_pager_alloc(handle, size, prot, offset) free((caddr_t) pager, M_VMPAGER); return (NULL); } - /* * And an object of the appropriate size */ - if (VOP_GETATTR(vp, &vattr, p->p_ucred, p) == 0) { + if ((rtval = VOP_GETATTR(vp, &vattr, p->p_ucred, p)) == 0) { object = vm_object_allocate(round_page(vattr.va_size)); vm_object_enter(object, pager); vm_object_setpager(object, pager, 0, TRUE); } else { + printf("Error in getattr: %d\n", rtval); free((caddr_t) vnp, M_VMPGDATA); free((caddr_t) pager, M_VMPAGER); return (NULL); @@ -210,11 +214,22 @@ vnode_pager_dealloc(pager) { register vn_pager_t vnp = (vn_pager_t) pager->pg_data; register struct vnode *vp; + vm_object_t object; vp = vnp->vnp_vp; if (vp) { + int s = splbio(); + + object = (vm_object_t) vp->v_vmdata; + if (object) { + while (object->paging_in_progress) { + tsleep(object, PVM, "vnpdea", 0); + } + } + splx(s); + vp->v_vmdata = NULL; - vp->v_flag &= ~(VTEXT|VVMIO); + vp->v_flag &= ~(VTEXT | VVMIO); vrele(vp); } TAILQ_REMOVE(&vnode_pager_list, pager, pg_list); @@ -226,8 +241,8 @@ int vnode_pager_getmulti(pager, m, count, reqpage, sync) vm_pager_t pager; vm_page_t *m; - int count; - int reqpage; + int count; + int reqpage; boolean_t sync; { @@ -257,7 +272,7 @@ vnode_pager_putpage(pager, m, sync) boolean_t sync; { vm_page_t marray[1]; - int rtvals[1]; + int rtvals[1]; if (pager == NULL) return FALSE; @@ -270,9 +285,9 @@ int vnode_pager_putmulti(pager, m, c, sync, rtvals) vm_pager_t pager; vm_page_t *m; - int c; + int c; boolean_t sync; - int *rtvals; + int *rtvals; { return vnode_pager_output((vn_pager_t) pager->pg_data, m, c, rtvals); } @@ -286,12 +301,12 @@ vnode_pager_haspage(pager, offset) register vn_pager_t vnp = (vn_pager_t) pager->pg_data; register struct vnode *vp = vnp->vnp_vp; daddr_t bn; - int err; + int err; daddr_t block; /* - * If filesystem no longer mounted or offset beyond end of - * file we do not have the page. + * If filesystem no longer mounted or offset beyond end of file we do + * not have the page. */ if ((vp->v_mount == NULL) || (offset >= vnp->vnp_size)) return FALSE; @@ -306,13 +321,8 @@ vnode_pager_haspage(pager, offset) * Assumes that the vnode has whole page or nothing. */ err = VOP_BMAP(vp, block, (struct vnode **) 0, &bn, 0); -/* - printf("vnode_pager_haspage: (%d)0x%x: err: %d, bn: %d\n", - offset, offset, err, bn); -*/ - if (err) { + if (err) return (TRUE); - } return ((long) bn < 0 ? FALSE : TRUE); } @@ -328,7 +338,7 @@ vnode_pager_haspage(pager, offset) void vnode_pager_setsize(vp, nsize) struct vnode *vp; - u_long nsize; + u_long nsize; { register vn_pager_t vnp; register vm_object_t object; @@ -344,9 +354,9 @@ vnode_pager_setsize(vp, nsize) * Hasn't changed size */ object = (vm_object_t) vp->v_vmdata; - if( object == NULL) + if (object == NULL) return; - if( (pager = object->pager) == NULL) + if ((pager = object->pager) == NULL) return; vnp = (vn_pager_t) pager->pg_data; if (nsize == vnp->vnp_size) @@ -366,11 +376,12 @@ vnode_pager_setsize(vp, nsize) * File has shrunk. Toss any cached pages beyond the new EOF. */ if (nsize < vnp->vnp_size) { - vm_object_lock(object); - vm_object_page_remove(object, - round_page((vm_offset_t) nsize), vnp->vnp_size); - vm_object_unlock(object); - + if (round_page((vm_offset_t) nsize) < vnp->vnp_size) { + vm_object_lock(object); + vm_object_page_remove(object, + round_page((vm_offset_t) nsize), vnp->vnp_size); + vm_object_unlock(object); + } /* * this gets rid of garbage at the end of a page that is now * only partially backed by the vnode... @@ -383,29 +394,10 @@ vnode_pager_setsize(vp, nsize) if (m) { kva = vm_pager_map_page(m); bzero((caddr_t) kva + (nsize & PAGE_MASK), - round_page(nsize) - nsize); + round_page(nsize) - nsize); vm_pager_unmap_page(kva); } } - } else { - - /* - * this allows the filesystem and VM cache to stay in sync if - * the VM page hasn't been modified... After the page is - * removed -- it will be faulted back in from the filesystem - * cache. - */ - if (vnp->vnp_size & PAGE_MASK) { - vm_page_t m; - - m = vm_page_lookup(object, trunc_page(vnp->vnp_size)); - if (m && (m->flags & PG_CLEAN)) { - vm_object_lock(object); - vm_object_page_remove(object, - vnp->vnp_size, vnp->vnp_size); - vm_object_unlock(object); - } - } } vnp->vnp_size = (vm_offset_t) nsize; object->size = round_page(nsize); @@ -453,8 +445,9 @@ vnode_pager_uncache(vp) * Not a mapped vnode */ object = (vm_object_t) vp->v_vmdata; - if( object == NULL) - return(TRUE); + if (object == NULL) + return (TRUE); + pager = object->pager; if (pager == NULL) return (TRUE); @@ -501,12 +494,15 @@ vnode_pager_addr(vp, address) struct vnode *vp; vm_offset_t address; { - int rtaddress; - int bsize; + int rtaddress; + int bsize; vm_offset_t block; struct vnode *rtvp; - int err; - int vblock, voffset; + int err; + int vblock, voffset; + + if ((int) address < 0) + return -1; bsize = vp->v_mount->mnt_stat.f_iosize; vblock = address / bsize; @@ -531,7 +527,7 @@ vnode_pager_iodone(bp) { bp->b_flags |= B_DONE; wakeup((caddr_t) bp); - if( bp->b_flags & B_ASYNC) { + if (bp->b_flags & B_ASYNC) { vm_offset_t paddr; vm_page_t m; vm_object_t obj = 0; @@ -539,35 +535,32 @@ vnode_pager_iodone(bp) int npages; paddr = (vm_offset_t) bp->b_data; - if( bp->b_bufsize != bp->b_bcount) - bzero( bp->b_data + bp->b_bcount, - bp->b_bufsize - bp->b_bcount); + if (bp->b_bufsize != bp->b_bcount) + bzero(bp->b_data + bp->b_bcount, + bp->b_bufsize - bp->b_bcount); npages = (bp->b_bufsize + PAGE_SIZE - 1) / PAGE_SIZE; -/* - printf("bcount: %d, bufsize: %d, npages: %d\n", - bp->b_bcount, bp->b_bufsize, npages); -*/ - for( i = 0; i < npages; i++) { + for (i = 0; i < npages; i++) { m = PHYS_TO_VM_PAGE(pmap_kextract(paddr + i * PAGE_SIZE)); obj = m->object; - if( m) { - m->flags |= PG_CLEAN; - m->flags &= ~(PG_LAUNDRY|PG_FAKE); + if (m) { + m->dirty = 0; + m->valid = VM_PAGE_BITS_ALL; + if (m->flags & PG_WANTED) + m->flags |= PG_REFERENCED; PAGE_WAKEUP(m); } else { panic("vnode_pager_iodone: page is gone!!!"); } } - pmap_qremove( paddr, npages); - if( obj) { + pmap_qremove(paddr, npages); + if (obj) { --obj->paging_in_progress; - if( obj->paging_in_progress == 0) + if (obj->paging_in_progress == 0) wakeup((caddr_t) obj); } else { panic("vnode_pager_iodone: object is gone???"); } - HOLDRELE(bp->b_vp); relpbuf(bp); } } @@ -580,74 +573,31 @@ vnode_pager_input_smlfs(vnp, m) vn_pager_t vnp; vm_page_t m; { - int i; - int s; - vm_offset_t paging_offset; + int i; + int s; struct vnode *dp, *vp; struct buf *bp; - vm_offset_t foff; vm_offset_t kva; - int fileaddr; - int block; + int fileaddr; + int block; vm_offset_t bsize; - int error = 0; + int error = 0; - paging_offset = m->object->paging_offset; vp = vnp->vnp_vp; bsize = vp->v_mount->mnt_stat.f_iosize; - foff = m->offset + paging_offset; - VOP_BMAP(vp, foff, &dp, 0, 0); + VOP_BMAP(vp, 0, &dp, 0, 0); kva = vm_pager_map_page(m); for (i = 0; i < PAGE_SIZE / bsize; i++) { - /* - * calculate logical block and offset - */ - block = foff / bsize + i; - s = splbio(); - while ((bp = incore(vp, block)) != 0) { - int amount; - - /* - * wait until the buffer is avail or gone - */ - if (bp->b_flags & B_BUSY) { - bp->b_flags |= B_WANTED; - tsleep((caddr_t) bp, PVM, "vnwblk", 0); - continue; - } - amount = bsize; - if ((foff + bsize) > vnp->vnp_size) - amount = vnp->vnp_size - foff; + if ((vm_page_bits(m->offset + i * bsize, bsize) & m->valid)) + continue; - /* - * make sure that this page is in the buffer - */ - if ((amount > 0) && amount <= bp->b_bcount) { - bp->b_flags |= B_BUSY; - splx(s); - - /* - * copy the data from the buffer - */ - bcopy(bp->b_un.b_addr, (caddr_t) kva + i * bsize, amount); - if (amount < bsize) { - bzero((caddr_t) kva + amount, bsize - amount); - } - bp->b_flags &= ~B_BUSY; - wakeup((caddr_t) bp); - goto nextblock; - } - break; - } - splx(s); - fileaddr = vnode_pager_addr(vp, foff + i * bsize); + fileaddr = vnode_pager_addr(vp, m->offset + i * bsize); if (fileaddr != -1) { bp = getpbuf(); - VHOLD(vp); /* build a minimal buffer header */ bp->b_flags = B_BUSY | B_READ | B_CALL; @@ -660,7 +610,7 @@ vnode_pager_input_smlfs(vnp, m) crhold(bp->b_wcred); bp->b_un.b_addr = (caddr_t) kva + i * bsize; bp->b_blkno = fileaddr / DEV_BSIZE; - bgetvp(dp, bp); + pbgetvp(dp, bp); bp->b_bcount = bsize; bp->b_bufsize = bsize; @@ -684,18 +634,20 @@ vnode_pager_input_smlfs(vnp, m) HOLDRELE(vp); if (error) break; + + vm_page_set_clean(m, i * bsize, bsize); + vm_page_set_valid(m, i * bsize, bsize); } else { + vm_page_set_clean(m, i * bsize, bsize); bzero((caddr_t) kva + i * bsize, bsize); } nextblock: } vm_pager_unmap_page(kva); + pmap_clear_modify(VM_PAGE_TO_PHYS(m)); if (error) { return VM_PAGER_ERROR; } - pmap_clear_modify(VM_PAGE_TO_PHYS(m)); - m->flags |= PG_CLEAN; - m->flags &= ~PG_LAUNDRY; return VM_PAGER_OK; } @@ -711,33 +663,31 @@ vnode_pager_input_old(vnp, m) { struct uio auio; struct iovec aiov; - int error; - int size; - vm_offset_t foff; + int error; + int size; vm_offset_t kva; error = 0; - foff = m->offset + m->object->paging_offset; /* * Return failure if beyond current EOF */ - if (foff >= vnp->vnp_size) { + if (m->offset >= vnp->vnp_size) { return VM_PAGER_BAD; } else { size = PAGE_SIZE; - if (foff + size > vnp->vnp_size) - size = vnp->vnp_size - foff; -/* - * Allocate a kernel virtual address and initialize so that - * we can use VOP_READ/WRITE routines. - */ + if (m->offset + size > vnp->vnp_size) + size = vnp->vnp_size - m->offset; + /* + * Allocate a kernel virtual address and initialize so that + * we can use VOP_READ/WRITE routines. + */ kva = vm_pager_map_page(m); aiov.iov_base = (caddr_t) kva; aiov.iov_len = size; auio.uio_iov = &aiov; auio.uio_iovcnt = 1; - auio.uio_offset = foff; + auio.uio_offset = m->offset; auio.uio_segflg = UIO_SYSSPACE; auio.uio_rw = UIO_READ; auio.uio_resid = size; @@ -755,8 +705,7 @@ vnode_pager_input_old(vnp, m) vm_pager_unmap_page(kva); } pmap_clear_modify(VM_PAGE_TO_PHYS(m)); - m->flags |= PG_CLEAN; - m->flags &= ~PG_LAUNDRY; + m->dirty = 0; return error ? VM_PAGER_ERROR : VM_PAGER_OK; } @@ -767,39 +716,30 @@ int vnode_pager_input(vnp, m, count, reqpage) register vn_pager_t vnp; vm_page_t *m; - int count, reqpage; + int count, reqpage; { - int i; + int i; vm_offset_t kva, foff; - int size, sizea; + int size, sizea; vm_object_t object; - vm_offset_t paging_offset; struct vnode *dp, *vp; - int bsize; + int bsize; - int first, last; - int reqaddr, firstaddr; - int block, offset; + int first, last; + int reqaddr, firstaddr; + int block, offset; struct buf *bp, *bpa; - int counta; - int s; - int failflag; + int counta; + int s; + int failflag; - int error = 0; + int error = 0; object = m[reqpage]->object; /* all vm_page_t items are in same * object */ - paging_offset = object->paging_offset; vp = vnp->vnp_vp; - - /* - * Make sure underlying filesystem is still mounted. - */ - if (vp->v_mount == NULL) - return VM_PAGER_FAIL; - bsize = vp->v_mount->mnt_stat.f_iosize; /* get the UNDERLYING device for the file with VOP_BMAP() */ @@ -808,12 +748,12 @@ vnode_pager_input(vnp, m, count, reqpage) * originally, we did not check for an error return value -- assuming * an fs always has a bmap entry point -- that assumption is wrong!!! */ - foff = m[reqpage]->offset + paging_offset; + foff = m[reqpage]->offset; /* * if we can't bmap, use old VOP code */ - if (VOP_BMAP(vp, foff, &dp, 0, 0)) { + if (VOP_BMAP(vp, 0, &dp, 0, 0)) { for (i = 0; i < count; i++) { if (i != reqpage) { vnode_pager_freepage(m[i]); @@ -829,7 +769,7 @@ vnode_pager_input(vnp, m, count, reqpage) * blocksize, but it can handle large reads itself. */ } else if ((PAGE_SIZE / bsize) > 1 && - (vp->v_mount->mnt_stat.f_type != MOUNT_NFS)) { + (vp->v_mount->mnt_stat.f_type != MOUNT_NFS)) { for (i = 0; i < count; i++) { if (i != reqpage) { @@ -840,111 +780,28 @@ vnode_pager_input(vnp, m, count, reqpage) cnt.v_vnodepgsin++; return vnode_pager_input_smlfs(vnp, m[reqpage]); } -/* - * here on direct device I/O - */ - - -#ifdef NOTYET - if( (vp->v_flag & VVMIO) == 0) { -#endif /* - * This pathetic hack gets data from the buffer cache, if it's there. - * I believe that this is not really necessary, and the ends can be - * gotten by defaulting to the normal vfs read behavior, but this - * might be more efficient, because the will NOT invoke read-aheads - * and one of the purposes of this code is to bypass the buffer cache - * and keep from flushing it by reading in a program. + * if ANY DEV_BSIZE blocks are valid on a large filesystem block + * then, the entire page is valid -- */ - - /* - * calculate logical block and offset - */ - block = foff / bsize; - offset = foff % bsize; - s = splbio(); - - /* - * if we have a buffer in core, then try to use it - */ - while ((bp = incore(vp, block)) != 0) { - int amount; - - /* - * wait until the buffer is avail or gone - */ - if (bp->b_flags & B_BUSY) { - bp->b_flags |= B_WANTED; - tsleep((caddr_t) bp, PVM, "vnwblk", 0); - continue; - } - amount = PAGE_SIZE; - if ((foff + amount) > vnp->vnp_size) - amount = vnp->vnp_size - foff; - - /* - * make sure that this page is in the buffer - */ - if ((amount > 0) && (offset + amount) <= bp->b_bcount) { - bp->b_flags |= B_BUSY; - splx(s); - kva = kmem_alloc_wait( pager_map, PAGE_SIZE); - - /* - * map the requested page - */ - pmap_qenter(kva, &m[reqpage], 1); - - /* - * copy the data from the buffer - */ - bcopy(bp->b_un.b_addr + offset, (caddr_t) kva, amount); - if (amount < PAGE_SIZE) { - bzero((caddr_t) kva + amount, PAGE_SIZE - amount); - } - - /* - * unmap the page and free the kva - */ - pmap_qremove( kva, 1); - kmem_free_wakeup(pager_map, kva, PAGE_SIZE); - - /* - * release the buffer back to the block subsystem - */ - bp->b_flags &= ~B_BUSY; - wakeup((caddr_t) bp); - - /* - * we did not have to do any work to get the requested - * page, the read behind/ahead does not justify a read - */ - for (i = 0; i < count; i++) { - if (i != reqpage) { - vnode_pager_freepage(m[i]); - } - } - count = 1; - reqpage = 0; - m[0] = m[reqpage]; - - /* - * sorry for the goto - */ - goto finishup; - } - - /* - * buffer is nowhere to be found, read from the disk - */ - break; + if (m[reqpage]->valid) { + m[reqpage]->valid = VM_PAGE_BITS_ALL; + for (i = 0; i < count; i++) { + if (i != reqpage) + vnode_pager_freepage(m[i]); } - splx(s); -#ifdef NOTYET + return VM_PAGER_OK; } -#endif + /* + * here on direct device I/O + */ reqaddr = vnode_pager_addr(vp, foff); + if (reqaddr == -1 && foff < vnp->vnp_size) { + printf("reqaddr: %d, foff: %d, vnp_size: %d\n", + reqaddr, foff, vnp->vnp_size); + Debugger(""); + } s = splbio(); /* @@ -956,12 +813,7 @@ vnode_pager_input(vnp, m, count, reqpage) first = reqpage; for (i = reqpage - 1; i >= 0; --i) { if (failflag || -#ifdef NOTYET - ((vp->v_flag & VVMIO) == 0 && incore(vp, (foff + (i - reqpage) * PAGE_SIZE) / bsize)) || -#else - (incore(vp, (foff + (i - reqpage) * PAGE_SIZE) / bsize)) || -#endif - (vnode_pager_addr(vp, m[i]->offset + paging_offset)) + (vnode_pager_addr(vp, m[i]->offset)) != reqaddr + (i - reqpage) * PAGE_SIZE) { vnode_pager_freepage(m[i]); failflag = 1; @@ -978,12 +830,7 @@ vnode_pager_input(vnp, m, count, reqpage) last = reqpage + 1; for (i = reqpage + 1; i < count; i++) { if (failflag || -#ifdef NOTYET - ((vp->v_flag & VVMIO) == 0 && incore(vp, (foff + (i - reqpage) * PAGE_SIZE) / bsize)) || -#else - (incore(vp, (foff + (i - reqpage) * PAGE_SIZE) / bsize)) || -#endif - (vnode_pager_addr(vp, m[i]->offset + paging_offset)) + (vnode_pager_addr(vp, m[i]->offset)) != reqaddr + (i - reqpage) * PAGE_SIZE) { vnode_pager_freepage(m[i]); failflag = 1; @@ -1005,11 +852,10 @@ vnode_pager_input(vnp, m, count, reqpage) count -= first; reqpage -= first; } - /* * calculate the file virtual address for the transfer */ - foff = m[0]->offset + paging_offset; + foff = m[0]->offset; /* * and get the disk physical address (in bytes) @@ -1030,25 +876,23 @@ vnode_pager_input(vnp, m, count, reqpage) size = (size + DEV_BSIZE - 1) & ~(DEV_BSIZE - 1); counta = 0; - if( count*PAGE_SIZE > bsize) + if (count * PAGE_SIZE > bsize) counta = (count - reqpage) - 1; bpa = 0; sizea = 0; - if( counta) { + if (counta) { bpa = getpbuf(); count -= counta; - sizea = size - count*PAGE_SIZE; + sizea = size - count * PAGE_SIZE; size = count * PAGE_SIZE; } - bp = getpbuf(); - kva = (vm_offset_t)bp->b_data; + kva = (vm_offset_t) bp->b_data; /* * and map the pages to be read into the kva */ pmap_qenter(kva, m, count); - VHOLD(vp); /* build a minimal buffer header */ bp->b_flags = B_BUSY | B_READ | B_CALL; @@ -1061,7 +905,7 @@ vnode_pager_input(vnp, m, count, reqpage) if (bp->b_wcred != NOCRED) crhold(bp->b_wcred); bp->b_blkno = firstaddr / DEV_BSIZE; - bgetvp(dp, bp); + pbgetvp(dp, bp); bp->b_bcount = size; bp->b_bufsize = size; @@ -1071,13 +915,12 @@ vnode_pager_input(vnp, m, count, reqpage) /* do the input */ VOP_STRATEGY(bp); - if( counta) { - for(i=0;i<counta;i++) { - vm_page_deactivate(m[count+i]); + if (counta) { + for (i = 0; i < counta; i++) { + vm_page_deactivate(m[count + i]); } - pmap_qenter((vm_offset_t)bpa->b_data, &m[count], counta); + pmap_qenter((vm_offset_t) bpa->b_data, &m[count], counta); ++m[count]->object->paging_in_progress; - VHOLD(vp); bpa->b_flags = B_BUSY | B_READ | B_CALL | B_ASYNC; bpa->b_iodone = vnode_pager_iodone; /* B_PHYS is not set, but it is nice to fill this in */ @@ -1088,14 +931,13 @@ vnode_pager_input(vnp, m, count, reqpage) if (bpa->b_wcred != NOCRED) crhold(bpa->b_wcred); bpa->b_blkno = (firstaddr + count * PAGE_SIZE) / DEV_BSIZE; - bgetvp(dp, bpa); + pbgetvp(dp, bpa); bpa->b_bcount = sizea; - bpa->b_bufsize = counta*PAGE_SIZE; + bpa->b_bufsize = counta * PAGE_SIZE; cnt.v_vnodepgsin += counta; VOP_STRATEGY(bpa); } - s = splbio(); /* we definitely need to be at splbio here */ @@ -1110,7 +952,7 @@ vnode_pager_input(vnp, m, count, reqpage) if (size != count * PAGE_SIZE) bzero((caddr_t) kva + size, PAGE_SIZE * count - size); } - pmap_qremove( kva, count); + pmap_qremove(kva, count); /* * free the buffer header back to the swap buffer pool @@ -1121,8 +963,8 @@ vnode_pager_input(vnp, m, count, reqpage) finishup: for (i = 0; i < count; i++) { pmap_clear_modify(VM_PAGE_TO_PHYS(m[i])); - m[i]->flags |= PG_CLEAN; - m[i]->flags &= ~PG_LAUNDRY; + m[i]->dirty = 0; + m[i]->valid = VM_PAGE_BITS_ALL; if (i != reqpage) { /* @@ -1138,9 +980,11 @@ finishup: * now tell them that it is ok to use */ if (!error) { - vm_page_deactivate(m[i]); + if (i != reqpage - 1) + vm_page_deactivate(m[i]); + else + vm_page_activate(m[i]); PAGE_WAKEUP(m[i]); - m[i]->flags &= ~PG_FAKE; } else { vnode_pager_freepage(m[i]); } @@ -1160,36 +1004,41 @@ vnode_pager_output_old(vnp, m) register vn_pager_t vnp; vm_page_t m; { - vm_offset_t foff; - vm_offset_t kva; + vm_offset_t kva, kva2; vm_offset_t size; struct iovec aiov; struct uio auio; struct vnode *vp; - int error; + int error; vp = vnp->vnp_vp; - foff = m->offset + m->object->paging_offset; /* - * Return failure if beyond current EOF + * Dont return failure if beyond current EOF placate the VM system. */ - if (foff >= vnp->vnp_size) { - return VM_PAGER_BAD; + if (m->offset >= vnp->vnp_size) { + return VM_PAGER_OK; } else { size = PAGE_SIZE; - if (foff + size > vnp->vnp_size) - size = vnp->vnp_size - foff; -/* - * Allocate a kernel virtual address and initialize so that - * we can use VOP_WRITE routines. - */ + if (m->offset + size > vnp->vnp_size) + size = vnp->vnp_size - m->offset; + + kva2 = kmem_alloc(pager_map, PAGE_SIZE); + /* + * Allocate a kernel virtual address and initialize so that + * we can use VOP_WRITE routines. + */ kva = vm_pager_map_page(m); - aiov.iov_base = (caddr_t) kva; + bcopy((caddr_t) kva, (caddr_t) kva2, size); + vm_pager_unmap_page(kva); + pmap_clear_modify(VM_PAGE_TO_PHYS(m)); + PAGE_WAKEUP(m); + + aiov.iov_base = (caddr_t) kva2; aiov.iov_len = size; auio.uio_iov = &aiov; auio.uio_iovcnt = 1; - auio.uio_offset = foff; + auio.uio_offset = m->offset; auio.uio_segflg = UIO_SYSSPACE; auio.uio_rw = UIO_WRITE; auio.uio_resid = size; @@ -1197,13 +1046,13 @@ vnode_pager_output_old(vnp, m) error = VOP_WRITE(vp, &auio, 0, curproc->p_ucred); + kmem_free_wakeup(pager_map, kva2, PAGE_SIZE); if (!error) { if ((size - auio.uio_resid) == 0) { error = EINVAL; } } - vm_pager_unmap_page(kva); - return error ? VM_PAGER_ERROR: VM_PAGER_OK; + return error ? VM_PAGER_ERROR : VM_PAGER_OK; } } @@ -1215,42 +1064,31 @@ vnode_pager_output_smlfs(vnp, m) vn_pager_t vnp; vm_page_t m; { - int i; - int s; - vm_offset_t paging_offset; + int i; + int s; struct vnode *dp, *vp; struct buf *bp; - vm_offset_t foff; vm_offset_t kva; - int fileaddr; + int fileaddr; vm_offset_t bsize; - int error = 0; + int error = 0; - paging_offset = m->object->paging_offset; vp = vnp->vnp_vp; bsize = vp->v_mount->mnt_stat.f_iosize; - foff = m->offset + paging_offset; - VOP_BMAP(vp, foff, &dp, 0, 0); + VOP_BMAP(vp, 0, &dp, 0, 0); kva = vm_pager_map_page(m); for (i = 0; !error && i < (PAGE_SIZE / bsize); i++) { + if ((vm_page_bits(m->offset + i * bsize, bsize) & m->valid & m->dirty) == 0) + continue; /* * calculate logical block and offset */ - fileaddr = vnode_pager_addr(vp, foff + i * bsize); + fileaddr = vnode_pager_addr(vp, m->offset + i * bsize); if (fileaddr != -1) { - s = splbio(); - bp = incore(vp, (foff / bsize) + i); - if (bp) { - bp = getblk(vp, (foff / bsize) + i, bp->b_bufsize, 0, 0); - bp->b_flags |= B_INVAL; - brelse(bp); - } - splx(s); bp = getpbuf(); - VHOLD(vp); /* build a minimal buffer header */ bp->b_flags = B_BUSY | B_CALL | B_WRITE; @@ -1263,7 +1101,7 @@ vnode_pager_output_smlfs(vnp, m) crhold(bp->b_wcred); bp->b_un.b_addr = (caddr_t) kva + i * bsize; bp->b_blkno = fileaddr / DEV_BSIZE; - bgetvp(dp, bp); + pbgetvp(dp, bp); ++dp->v_numoutput; /* for NFS */ bp->b_dirtyoff = 0; @@ -1284,6 +1122,7 @@ vnode_pager_output_smlfs(vnp, m) if ((bp->b_flags & B_ERROR) != 0) error = EIO; + vm_page_set_clean(m, i * bsize, bsize); /* * free the buffer header back to the swap buffer pool */ @@ -1305,25 +1144,25 @@ int vnode_pager_output(vnp, m, count, rtvals) vn_pager_t vnp; vm_page_t *m; - int count; - int *rtvals; + int count; + int *rtvals; { - int i, j; + int i, j; vm_offset_t kva, foff; - int size; + int size; vm_object_t object; - vm_offset_t paging_offset; struct vnode *dp, *vp; struct buf *bp; vm_offset_t reqaddr; - int bsize; - int s; + int bsize; + int s; + daddr_t block; + struct timeval tv; - int error = 0; + int error = 0; retryoutput: object = m[0]->object; /* all vm_page_t items are in same object */ - paging_offset = object->paging_offset; vp = vnp->vnp_vp; @@ -1338,20 +1177,27 @@ retryoutput: for (i = 0; i < count; i++) rtvals[i] = VM_PAGER_AGAIN; + if ((int) m[0]->offset < 0) { + printf("vnode_pager_output: attempt to write meta-data!!! -- 0x%x\n", m[0]->offset); + m[0]->dirty = 0; + rtvals[0] = VM_PAGER_OK; + return VM_PAGER_OK; + } /* * if the filesystem does not have a bmap, then use the old code */ - if (VOP_BMAP(vp, m[0]->offset + paging_offset, &dp, 0, 0)) { + if (VOP_BMAP(vp, (m[0]->offset / bsize), &dp, &block, 0) || + (block == -1)) { rtvals[0] = vnode_pager_output_old(vnp, m[0]); - pmap_clear_modify(VM_PAGE_TO_PHYS(m[0])); - m[0]->flags |= PG_CLEAN; - m[0]->flags &= ~PG_LAUNDRY; + m[0]->dirty = 0; cnt.v_vnodeout++; cnt.v_vnodepgsout++; return rtvals[0]; } + tv = time; + VOP_UPDATE(vp, &tv, &tv, 0); /* * if the filesystem has a small blocksize, then use the small block @@ -1364,17 +1210,14 @@ retryoutput: rtvals[i] = vnode_pager_output_smlfs(vnp, m[i]); if (rtvals[i] == VM_PAGER_OK) { pmap_clear_modify(VM_PAGE_TO_PHYS(m[i])); - m[i]->flags |= PG_CLEAN; - m[i]->flags &= ~PG_LAUNDRY; } } cnt.v_vnodeout++; cnt.v_vnodepgsout += count; return rtvals[0]; } - for (i = 0; i < count; i++) { - foff = m[i]->offset + paging_offset; + foff = m[i]->offset; if (foff >= vnp->vnp_size) { for (j = i; j < count; j++) rtvals[j] = VM_PAGER_BAD; @@ -1385,7 +1228,7 @@ retryoutput: if (count == 0) { return rtvals[0]; } - foff = m[0]->offset + paging_offset; + foff = m[0]->offset; reqaddr = vnode_pager_addr(vp, foff); /* @@ -1393,7 +1236,7 @@ retryoutput: * for a page being in buffer cache. */ for (i = 1; i < count; i++) { - if (vnode_pager_addr(vp, m[i]->offset + paging_offset) + if (vnode_pager_addr(vp, m[i]->offset) != reqaddr + i * PAGE_SIZE) { count = i; break; @@ -1414,50 +1257,12 @@ retryoutput: size = (size + DEV_BSIZE - 1) & ~(DEV_BSIZE - 1); bp = getpbuf(); - kva = (vm_offset_t)bp->b_data; + kva = (vm_offset_t) bp->b_data; /* * and map the pages to be read into the kva */ pmap_qenter(kva, m, count); -#if 0 - printf("vnode: writing foff: %d, devoff: %d, size: %d\n", - foff, reqaddr, size); -#endif - - /* - * next invalidate the incore vfs_bio data - */ -#ifdef NOTYET - if( (vp->v_flag & VVMIO) == 0) { -#endif - for (i = 0; i < count; i++) { - int filblock = (foff + i * PAGE_SIZE) / bsize; - struct buf *fbp; - s = splbio(); - fbp = incore(vp, filblock); - if (fbp) { - fbp = getblk(vp, filblock, fbp->b_bufsize, 0, 0); - if (fbp->b_flags & B_DELWRI) { - if (fbp->b_bufsize <= PAGE_SIZE) - fbp->b_flags &= ~B_DELWRI; - else { - bwrite(fbp); - fbp = getblk(vp, filblock, - fbp->b_bufsize, 0, 0); - } - } - fbp->b_flags |= B_INVAL; - brelse(fbp); - } - splx(s); - } -#ifdef NOTYET - } -#endif - - - VHOLD(vp); /* build a minimal buffer header */ bp->b_flags = B_BUSY | B_WRITE | B_CALL; bp->b_iodone = vnode_pager_iodone; @@ -1470,7 +1275,7 @@ retryoutput: if (bp->b_wcred != NOCRED) crhold(bp->b_wcred); bp->b_blkno = reqaddr / DEV_BSIZE; - bgetvp(dp, bp); + pbgetvp(dp, bp); ++dp->v_numoutput; /* for NFS */ @@ -1498,7 +1303,7 @@ retryoutput: if ((bp->b_flags & B_ERROR) != 0) error = EIO; - pmap_qremove( kva, count); + pmap_qremove(kva, count); /* * free the buffer header back to the swap buffer pool @@ -1509,8 +1314,7 @@ retryoutput: if (!error) { for (i = 0; i < count; i++) { pmap_clear_modify(VM_PAGE_TO_PHYS(m[i])); - m[i]->flags |= PG_CLEAN; - m[i]->flags &= ~PG_LAUNDRY; + m[i]->dirty = 0; rtvals[i] = VM_PAGER_OK; } } else if (count != 1) { @@ -1521,5 +1325,5 @@ retryoutput: if (error) { printf("vnode_pager_output: I/O write error\n"); } - return (error ? VM_PAGER_ERROR: VM_PAGER_OK); + return (error ? VM_PAGER_ERROR : VM_PAGER_OK); } |