diff options
author | julian <julian@FreeBSD.org> | 1999-03-14 09:20:01 +0000 |
---|---|---|
committer | julian <julian@FreeBSD.org> | 1999-03-14 09:20:01 +0000 |
commit | 0c3f3973d253c1aedd05a44d33615546f4ea3c9d (patch) | |
tree | 98d1b3e17dccced065927853ce8eff90fe432af1 /sys/vm/vm_pager.c | |
parent | 105e87d9a2deffdb189a0b80eacc001d79ed0fad (diff) | |
download | FreeBSD-src-0c3f3973d253c1aedd05a44d33615546f4ea3c9d.zip FreeBSD-src-0c3f3973d253c1aedd05a44d33615546f4ea3c9d.tar.gz |
Submitted by: Matt Dillon <dillon@freebsd.org>
The old VN device broke in -4.x when the definition of B_PAGING
changed. This patch fixes this plus implements additional capabilities.
The new VN device can be backed by a file ( as per normal ), or it can
be directly backed by swap.
Due to dependencies in VM include files (on opt_xxx options) the new
vn device cannot be a module yet. This will be fixed in a later commit.
This commit delimitted by tags {PRE,POST}_MATT_VNDEV
Diffstat (limited to 'sys/vm/vm_pager.c')
-rw-r--r-- | sys/vm/vm_pager.c | 156 |
1 files changed, 155 insertions, 1 deletions
diff --git a/sys/vm/vm_pager.c b/sys/vm/vm_pager.c index 2b8eb64..4645935 100644 --- a/sys/vm/vm_pager.c +++ b/sys/vm/vm_pager.c @@ -61,7 +61,7 @@ * any improvements or extensions that they make and grant Carnegie the * rights to redistribute these changes. * - * $Id: vm_pager.c,v 1.42 1999/01/21 10:15:24 dillon Exp $ + * $Id: vm_pager.c,v 1.43 1999/01/24 02:32:15 dillon Exp $ */ /* @@ -72,9 +72,11 @@ #include <sys/param.h> #include <sys/systm.h> #include <sys/kernel.h> +#include <sys/vnode.h> #include <sys/buf.h> #include <sys/ucred.h> #include <sys/malloc.h> +#include <sys/proc.h> #include <vm/vm.h> #include <vm/vm_param.h> @@ -252,6 +254,25 @@ vm_pager_deallocate(object) } /* + * vm_pager_strategy: + * + * called with no specific spl + * Execute strategy routine directly to pager. + */ + +void +vm_pager_strategy(vm_object_t object, struct buf *bp) +{ + if (pagertab[object->type]->pgo_strategy) { + (*pagertab[object->type]->pgo_strategy)(object, bp); + } else { + bp->b_flags |= B_ERROR; + bp->b_error = ENXIO; + biodone(bp); + } +} + +/* * vm_pager_get_pages() - inline, see vm/vm_pager.h * vm_pager_put_pages() - inline, see vm/vm_pager.h * vm_pager_has_page() - inline, see vm/vm_pager.h @@ -442,3 +463,136 @@ relpbuf(bp, pfreecnt) } splx(s); } + +/******************************************************** + * CHAINING FUNCTIONS * + ******************************************************** + * + * These functions support recursion of I/O operations + * on bp's, typically by chaining one or more 'child' bp's + * to the parent. Synchronous, asynchronous, and semi-synchronous + * chaining is possible. + */ + +/* + * vm_pager_chain_iodone: + * + * io completion routine for child bp. Currently we fudge a bit + * on dealing with b_resid. Since users of these routines may issue + * multiple children simultaniously, sequencing of the error can be lost. + */ + +static void +vm_pager_chain_iodone(struct buf *nbp) +{ + struct buf *bp; + + if ((bp = nbp->b_chain.parent) != NULL) { + if (nbp->b_flags & B_ERROR) { + bp->b_flags |= B_ERROR; + bp->b_error = nbp->b_error; + } else if (nbp->b_resid != 0) { + bp->b_flags |= B_ERROR; + bp->b_error = EINVAL; + } else { + bp->b_resid -= nbp->b_bcount; + } + nbp->b_chain.parent = NULL; + --bp->b_chain.count; + if (bp->b_flags & B_WANTED) { + bp->b_flags &= ~B_WANTED; + wakeup(bp); + } + if (!bp->b_chain.count && (bp->b_flags & B_AUTOCHAINDONE)) { + bp->b_flags &= ~B_AUTOCHAINDONE; + if (bp->b_resid != 0 && !(bp->b_flags & B_ERROR)) { + bp->b_flags |= B_ERROR; + bp->b_error = EINVAL; + } + biodone(bp); + } + } + nbp->b_flags |= B_DONE; + nbp->b_flags &= ~(B_ASYNC|B_WANTED); + relpbuf(nbp, NULL); +} + +/* + * getchainbuf: + * + * Obtain a physical buffer and chain it to its parent buffer. When + * I/O completes, the parent buffer will be B_SIGNAL'd. Errors are + * automatically propogated to the parent + */ + +struct buf * +getchainbuf(struct buf *bp, struct vnode *vp, int flags) +{ + struct buf *nbp = getpbuf(NULL); + + nbp->b_chain.parent = bp; + ++bp->b_chain.count; + + if (bp->b_chain.count > 4) + waitchainbuf(bp, 4, 0); + + nbp->b_flags = B_BUSY | B_CALL | (bp->b_flags & B_ORDERED) | flags; + nbp->b_proc = &proc0; + nbp->b_rcred = nbp->b_proc->p_ucred; + nbp->b_wcred = nbp->b_proc->p_ucred; + nbp->b_iodone = vm_pager_chain_iodone; + + crhold(nbp->b_rcred); + crhold(nbp->b_wcred); + + if (vp) + pbgetvp(vp, nbp); + return(nbp); +} + +void +flushchainbuf(struct buf *nbp) +{ + if (nbp->b_bcount) { + nbp->b_bufsize = nbp->b_bcount; + if ((nbp->b_flags & B_READ) == 0) + nbp->b_dirtyend = nbp->b_bcount; + VOP_STRATEGY(nbp->b_vp, nbp); + } else { + biodone(nbp); + } +} + +void +waitchainbuf(struct buf *bp, int count, int done) +{ + int s; + + s = splbio(); + while (bp->b_chain.count > count) { + bp->b_flags |= B_WANTED; + tsleep(bp, PRIBIO + 4, "bpchain", 0); + } + if (done) { + if (bp->b_resid != 0 && !(bp->b_flags & B_ERROR)) { + bp->b_flags |= B_ERROR; + bp->b_error = EINVAL; + } + biodone(bp); + } + splx(s); +} + +void +autochaindone(struct buf *bp) +{ + int s; + + s = splbio(); + if (bp->b_chain.count == 0) + biodone(bp); + else + bp->b_flags |= B_AUTOCHAINDONE; + splx(s); +} + |