diff options
author | dg <dg@FreeBSD.org> | 1994-10-04 07:32:08 +0000 |
---|---|---|
committer | dg <dg@FreeBSD.org> | 1994-10-04 07:32:08 +0000 |
commit | 2745117c81d4d4116cfd520ca52051fd3fdda1cf (patch) | |
tree | bcf7660c597a4af7e770f0000424e46c682e15d7 | |
parent | ddf9ae441960dcf931d0ab91aa12ff5fcb741433 (diff) | |
download | FreeBSD-src-2745117c81d4d4116cfd520ca52051fd3fdda1cf.zip FreeBSD-src-2745117c81d4d4116cfd520ca52051fd3fdda1cf.tar.gz |
John Dyson's work in progress. Not currently used.
-rw-r--r-- | sys/vm/vm_vmio.c | 389 |
1 files changed, 389 insertions, 0 deletions
diff --git a/sys/vm/vm_vmio.c b/sys/vm/vm_vmio.c new file mode 100644 index 0000000..8450c92 --- /dev/null +++ b/sys/vm/vm_vmio.c @@ -0,0 +1,389 @@ +/* + * 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;i<pagecount;i++) { + vm_page_t m; + m = vm_page_lookup( object, start + i * PAGE_SIZE); + if( m) { + /* + * See if something else has already gotten this page + */ + if( m->busy || (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;j<i;j++) { + vm_page_t n; + n = ms[j]; + if( n) { + PAGE_WAKEUP(n); + if( n->flags & PG_FAKE) + vm_page_free(n); + } + } + return -1; + } + } + ms[i] = m; + } + /* + * hold the pages and assign them to the mapping + */ + for(i=0;i<pagecount;i++) { + m = ms[i]; + vm_page_hold(m); + if( m->flags & 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;i<pgcnt;i++) { + ++lbp->b_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;i<lbp->b_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; +} |