/* * Copyright (c) 1994 John S. Dyson * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice immediately at the beginning of the file, without modification, * this list of conditions, and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. Absolutely no warranty of function or purpose is made by the author * John S. Dyson. * 4. Modifications may be freely made to this file if the above conditions * are met. * * $Id$ */ /* * THIS IS PRELIMINARY, BUGGY AND NON-WORKING CODE * WHEN THIS NOTICE IS REMOVED -- IT WILL WORK... :-). * * THINGS TO DO: * COMMENTS, THE SYSTEM ALMOST RUNS WITH IT. THIS IS CURRENTLY MEANT * ONLY AS A PLACEHOLDER!!! */ #define VMIO #include "param.h" #include "proc.h" #include "malloc.h" #include "vm_param.h" #include "vm.h" #include "lock.h" #include "queue.h" #include "vm_prot.h" #include "vm_object.h" #include "vm_page.h" #include "vnode_pager.h" #include "vm_map.h" #include "vm_pageout.h" #include "vnode.h" #include "uio.h" #include "mount.h" /* #include "buf.h" */ #include "miscfs/specfs/specdev.h" /* #include "vmio.h" */ int vnode_pager_initialized; extern vm_map_t pager_map; struct buf * getpbuf(); void relpbuf(struct buf *bp); /* * map an object into kva * return 1 if all are in memory, and 0 if any are fake. */ int vmio_alloc_pages( vm_object_t object, vm_offset_t start, vm_offset_t size, vm_page_t *ms) { int pagecount; vm_page_t m; int i,j; int s; vm_offset_t kva; struct buf *bp; int ioneeded=0; pagecount = size / PAGE_SIZE; for(i=0;ibusy || (m->flags & (PG_VMIO|PG_BUSY))) { /* * Something has the page, so we have to * release all the pages we've gotten to * this point, wait for the page to unbusy * and then start over. */ int j; for(j = 0; j < i; j++) { vm_page_t n; n = ms[j]; if( n) { /* * unbusy the page. */ PAGE_WAKEUP(n); if( n->flags & PG_FAKE) vm_page_free(n); } } m->flags |= PG_WANTED; tsleep((caddr_t)m, PVM, "vngpwt", 0); return -1; } m->flags |= PG_REFERENCED; } else { m = (vm_page_t) vm_page_alloc( object, start + i * PAGE_SIZE); if( !m) { VM_WAIT; for(j=0;jflags & PG_FAKE) vm_page_free(n); } } return -1; } } ms[i] = m; } /* * hold the pages and assign them to the mapping */ for(i=0;iflags & PG_FAKE) ++ioneeded; vm_page_deactivate(m); if( (m->flags & PG_ACTIVE) == 0) vm_page_activate(m); m->flags |= PG_VMIO; m->flags &= ~PG_BUSY; ++m->act_count; pmap_page_protect( VM_PAGE_TO_PHYS(m), VM_PROT_READ); } return ioneeded; } void vmio_rawiodone( struct buf *bp) { int s; int i; vm_object_t object; vm_page_t m; if( bp->b_bufsize != bp->b_bcount) bzero( bp->b_data + bp->b_bcount, bp->b_bufsize - bp->b_bcount); printf("rawdone: (blk: %d, count: %d)\n", bp->b_blkno, bp->b_bcount); s = splbio(); object = bp->b_pages[0]->object; for( i = 0; i < bp->b_npages; i++) { m = bp->b_pages[i]; if( m) { --m->busy; if( m->busy == 0) { m->flags |= PG_CLEAN; m->flags &= ~(PG_LAUNDRY|PG_FAKE); PAGE_WAKEUP(m); } } else { panic("vmio_rawiodone: page is gone!!!"); } } HOLDRELE(bp->b_vp); relpbuf(bp); --object->paging_in_progress; if( object->paging_in_progress == 0) wakeup((caddr_t)object); splx(s); return; } void vmio_get_pager(struct vnode *vp) { if( vp->v_type == VREG) { vm_object_t object; vm_pager_t pager; if((vp->v_vmdata == NULL) || (vp->v_flag & VVMIO) == 0) { pager = (vm_pager_t) vnode_pager_alloc(vp, 0, 0, 0); object = (vm_object_t) vp->v_vmdata; if( object->pager != pager) panic("vmio_get_pager: pager/object mismatch"); (void) vm_object_lookup( pager); pager_cache( object, TRUE); vp->v_flag |= VVMIO; } else { object = (vm_object_t) vp->v_vmdata; pager = object->pager; if( pager == NULL) { panic("vmio_get_pager: pager missing"); } (void) vm_object_lookup( pager); } } } void vmio_free_pager( struct vnode *vp) { if( vp->v_vmdata == NULL) panic("vmio_free_pager: object missing"); vm_object_deallocate( (vm_object_t) vp->v_vmdata); } void vmio_aread( struct buf *lbp) { struct vnode *vp, *dp; vm_object_t object; vm_offset_t offset; vm_offset_t size; vm_offset_t off; int forcemore; int runp; int s; s = splbio(); vp = lbp->b_vp; object = (vm_object_t) vp->v_vmdata; offset = trunc_page(lbp->b_lblkno * vp->v_mount->mnt_stat.f_iosize); size = round_page(lbp->b_bcount); forcemore = 0; printf("queueing read: iosize: %d, b_lblkno: %d, offset: %d, size: %d:", vp->v_mount->mnt_stat.f_iosize, lbp->b_lblkno, offset, size); for(off = 0; off < size; ) { vm_offset_t curoff; int pgidx, pgcnt, i; struct buf *bp; pgidx = off / PAGE_SIZE; if( !forcemore) { while( (off < size) && (lbp->b_pages[pgidx]->flags & PG_FAKE) == 0) { off = trunc_page(off) + PAGE_SIZE; pgidx += 1; } } if( off >= size) break; bp = getpbuf(); ++object->paging_in_progress; curoff = offset + off; VOP_BMAP( vp, curoff / vp->v_mount->mnt_stat.f_iosize, &dp, &bp->b_blkno, &runp); bp->b_bcount = (runp + 1) * vp->v_mount->mnt_stat.f_iosize; if( off + bp->b_bcount > size) bp->b_bcount = size - off; bp->b_bufsize = round_page(bp->b_bcount); pgcnt = bp->b_bufsize / PAGE_SIZE; for(i=0;ib_pages[pgidx+i]->busy; bp->b_pages[i] = lbp->b_pages[pgidx+i]; bp->b_pages[i]->flags |= PG_BUSY; } bp->b_npages = pgcnt; pmap_qenter((vm_offset_t) bp->b_data, &lbp->b_pages[pgidx], pgcnt); bp->b_data += curoff - trunc_page(curoff); off += bp->b_bcount; if( off & (PAGE_SIZE - 1)) forcemore = 1; else forcemore = 0; /* * round up physical size for real devices */ if( dp->v_type == VBLK || dp->v_type == VCHR) { bp->b_bcount = (bp->b_bcount + DEV_BSIZE - 1) & ~(DEV_BSIZE - 1); } /* * and map the pages to be read into the kva */ VHOLD(vp); /* build a minimal buffer header */ bp->b_flags = B_BUSY | B_READ | B_CALL | B_ASYNC; bp->b_iodone = vmio_rawiodone; /* B_PHYS is not set, but it is nice to fill this in */ bp->b_proc = curproc; bp->b_rcred = bp->b_wcred = bp->b_proc->p_ucred; if( bp->b_rcred != NOCRED) crhold(bp->b_rcred); if( bp->b_wcred != NOCRED) crhold(bp->b_wcred); bp->b_lblkno = bp->b_blkno; /* bp->b_vp = dp; */ bgetvp( dp, bp); printf(" p: (blk: %d, coff: %d, off: %d, count: %d)", bp->b_blkno, curoff, off, bp->b_bcount); /* Should be a BLOCK or character DEVICE if we get here */ bp->b_dev = dp->v_rdev; /* do the input */ VOP_STRATEGY(bp); } printf("\n"); splx(s); } int vmio_getblk( struct buf *bp) { struct vnode *vp; vm_object_t object; vm_offset_t offset; vm_offset_t size; vm_page_t ms[(MAXBSIZE + PAGE_SIZE - 1)/PAGE_SIZE]; int rtval; vp = bp->b_vp; if( (object = (vm_object_t) vp->v_vmdata) == NULL) panic("vmio_build_bp: object missing"); offset = trunc_page(bp->b_lblkno * vp->v_mount->mnt_stat.f_iosize); size = round_page(bp->b_bcount); printf("vmio_getblk: off:%d(0x%x) blk: %d, size: %d", offset, offset, bp->b_lblkno, size); bp->b_flags &= ~B_CACHE; if( (rtval = vmio_alloc_pages( object, offset, size, ms)) == 0) { bp->b_flags |= B_CACHE; printf("(cached)\n"); } else { printf("(ioneeded:%d)\n", rtval); } if( rtval < 0) { printf("vmio_getblk: vmio_alloc_pages busy\n"); return 0; } bp->b_npages = size / PAGE_SIZE; pmap_qenter((vm_offset_t) bp->b_data, ms, bp->b_npages); bp->b_flags |= B_VMIO; bp->b_bufsize = size; bcopy( ms, bp->b_pages, bp->b_npages * sizeof(vm_page_t)); return 1; } int vmio_biowait( struct buf *lbp) { int i; int s; printf("vmio_biowait -->"); restart: s = splbio(); for(i=lbp->b_npages-1;i >= 0; --i) { if( lbp->b_pages[i]->busy || (lbp->b_pages[i]->flags & PG_BUSY)) { lbp->b_pages[i]->flags |= PG_WANTED; printf(" waiting on page %d of xfer at %d, flags: 0x%x\n", i, lbp->b_blkno, lbp->b_pages[i]->flags); tsleep( (caddr_t) lbp->b_pages[i], PVM, "vbiowt", 0); splx(s); goto restart; } } splx(s); printf("vmio_biowait: finished\n"); return 1; } void vmio_brelse( struct buf *lbp) { int i; int nfullpages = lbp->b_bcount / PAGE_SIZE; pmap_qremove((vm_offset_t) lbp->b_data, lbp->b_npages); for(i=0;ib_npages;i++) { if( (i < nfullpages) && ((lbp->b_flags & B_DELWRI) == 0)) lbp->b_pages[i]->flags |= PG_CLEAN; if( lbp->b_flags & B_DELWRI) lbp->b_pages[i]->flags &= ~PG_CLEAN; lbp->b_pages[i]->flags &= ~PG_VMIO; vm_page_unhold(lbp->b_pages[i]); PAGE_WAKEUP(lbp->b_pages[i]); } lbp->b_flags &= ~B_VMIO; lbp->b_flags |= B_INVAL; lbp->b_bufsize = 0; }