diff options
| author | Alan Cox <alc@FreeBSD.org> | 2009-05-13 05:39:39 +0000 |
|---|---|---|
| committer | Alan Cox <alc@FreeBSD.org> | 2009-05-13 05:39:39 +0000 |
| commit | 1c1b26f276f85b086bc6e579c452e52231c234ac (patch) | |
| tree | de540785bb7f52f8c0b6353b22a06e54fff788d1 | |
| parent | b1f26c738c3a2433f1759099fceb31d741e4f462 (diff) | |
Notes
| -rw-r--r-- | sys/kern/vfs_bio.c | 47 | ||||
| -rw-r--r-- | sys/vm/vm_page.c | 45 | ||||
| -rw-r--r-- | sys/vm/vm_page.h | 1 |
3 files changed, 82 insertions, 11 deletions
diff --git a/sys/kern/vfs_bio.c b/sys/kern/vfs_bio.c index 58e349147ba6..2979f61f24ce 100644 --- a/sys/kern/vfs_bio.c +++ b/sys/kern/vfs_bio.c @@ -98,7 +98,8 @@ static void vm_hold_free_pages(struct buf *bp, vm_offset_t from, vm_offset_t to); static void vm_hold_load_pages(struct buf *bp, vm_offset_t from, vm_offset_t to); -static void vfs_page_set_valid(struct buf *bp, vm_ooffset_t off, +static void vfs_page_set_valid(struct buf *bp, vm_ooffset_t off, vm_page_t m); +static void vfs_page_set_validclean(struct buf *bp, vm_ooffset_t off, vm_page_t m); static void vfs_clean_pages(struct buf *bp); static void vfs_setdirty(struct buf *bp); @@ -3277,7 +3278,6 @@ bufdone_finish(struct buf *bp) vm_object_t obj; int iosize; struct vnode *vp = bp->b_vp; - boolean_t are_queues_locked; obj = bp->b_bufobj->bo_object; @@ -3314,11 +3314,6 @@ bufdone_finish(struct buf *bp) !(bp->b_ioflags & BIO_ERROR)) { bp->b_flags |= B_CACHE; } - if (bp->b_iocmd == BIO_READ) { - vm_page_lock_queues(); - are_queues_locked = TRUE; - } else - are_queues_locked = FALSE; for (i = 0; i < bp->b_npages; i++) { int bogusflag = 0; int resid; @@ -3354,6 +3349,9 @@ bufdone_finish(struct buf *bp) * only need to do this here in the read case. */ if ((bp->b_iocmd == BIO_READ) && !bogusflag && resid > 0) { + KASSERT((m->dirty & vm_page_bits(foff & + PAGE_MASK, resid)) == 0, ("bufdone_finish:" + " page %p has unexpected dirty bits", m)); vfs_page_set_valid(bp, foff, m); } @@ -3387,8 +3385,6 @@ bufdone_finish(struct buf *bp) foff = (foff + PAGE_SIZE) & ~(off_t)PAGE_MASK; iosize -= resid; } - if (are_queues_locked) - vm_page_unlock_queues(); vm_object_pip_wakeupn(obj, 0); VM_OBJECT_UNLOCK(obj); } @@ -3454,6 +3450,35 @@ vfs_unbusy_pages(struct buf *bp) static void vfs_page_set_valid(struct buf *bp, vm_ooffset_t off, vm_page_t m) { + vm_ooffset_t eoff; + + /* + * Compute the end offset, eoff, such that [off, eoff) does not span a + * page boundary and eoff is not greater than the end of the buffer. + * The end of the buffer, in this case, is our file EOF, not the + * allocation size of the buffer. + */ + eoff = (off + PAGE_SIZE) & ~(vm_ooffset_t)PAGE_MASK; + if (eoff > bp->b_offset + bp->b_bcount) + eoff = bp->b_offset + bp->b_bcount; + + /* + * Set valid range. This is typically the entire buffer and thus the + * entire page. + */ + if (eoff > off) + vm_page_set_valid(m, off & PAGE_MASK, eoff - off); +} + +/* + * vfs_page_set_validclean: + * + * Set the valid bits and clear the dirty bits in a page based on the + * supplied offset. The range is restricted to the buffer's size. + */ +static void +vfs_page_set_validclean(struct buf *bp, vm_ooffset_t off, vm_page_t m) +{ vm_ooffset_t soff, eoff; mtx_assert(&vm_page_queue_mtx, MA_OWNED); @@ -3545,7 +3570,7 @@ retry: */ if (clear_modify) { pmap_remove_write(m); - vfs_page_set_valid(bp, foff, m); + vfs_page_set_validclean(bp, foff, m); } else if (m->valid == VM_PAGE_BITS_ALL && (bp->b_flags & B_CACHE) == 0) { bp->b_pages[i] = bogus_page; @@ -3591,7 +3616,7 @@ vfs_clean_pages(struct buf *bp) if (eoff > bp->b_offset + bp->b_bufsize) eoff = bp->b_offset + bp->b_bufsize; - vfs_page_set_valid(bp, foff, m); + vfs_page_set_validclean(bp, foff, m); /* vm_page_clear_dirty(m, foff & PAGE_MASK, eoff - foff); */ foff = noff; } diff --git a/sys/vm/vm_page.c b/sys/vm/vm_page.c index 8befdd56705a..f0f90425a13a 100644 --- a/sys/vm/vm_page.c +++ b/sys/vm/vm_page.c @@ -1852,6 +1852,51 @@ vm_page_bits(int base, int size) } /* + * vm_page_set_valid: + * + * Sets portions of a page valid. The arguments are expected + * to be DEV_BSIZE aligned but if they aren't the bitmap is inclusive + * of any partial chunks touched by the range. The invalid portion of + * such chunks will be zeroed. + * + * (base + size) must be less then or equal to PAGE_SIZE. + */ +void +vm_page_set_valid(vm_page_t m, int base, int size) +{ + int endoff, frag; + + VM_OBJECT_LOCK_ASSERT(m->object, MA_OWNED); + if (size == 0) /* handle degenerate case */ + return; + + /* + * If the base is not DEV_BSIZE aligned and the valid + * bit is clear, we have to zero out a portion of the + * first block. + */ + if ((frag = base & ~(DEV_BSIZE - 1)) != base && + (m->valid & (1 << (base >> DEV_BSHIFT))) == 0) + pmap_zero_page_area(m, frag, base - frag); + + /* + * If the ending offset is not DEV_BSIZE aligned and the + * valid bit is clear, we have to zero out a portion of + * the last block. + */ + endoff = base + size; + if ((frag = endoff & ~(DEV_BSIZE - 1)) != endoff && + (m->valid & (1 << (endoff >> DEV_BSHIFT))) == 0) + pmap_zero_page_area(m, endoff, + DEV_BSIZE - (endoff & (DEV_BSIZE - 1))); + + /* + * Set valid bits inclusive of any overlap. + */ + m->valid |= vm_page_bits(base, size); +} + +/* * vm_page_set_validclean: * * Sets portions of a page valid and clean. The arguments are expected diff --git a/sys/vm/vm_page.h b/sys/vm/vm_page.h index 7f996ea9bfab..8bbbaee192f4 100644 --- a/sys/vm/vm_page.h +++ b/sys/vm/vm_page.h @@ -321,6 +321,7 @@ vm_page_t vm_page_lookup (vm_object_t, vm_pindex_t); void vm_page_remove (vm_page_t); void vm_page_rename (vm_page_t, vm_object_t, vm_pindex_t); void vm_page_requeue(vm_page_t m); +void vm_page_set_valid(vm_page_t m, int base, int size); void vm_page_sleep(vm_page_t m, const char *msg); vm_page_t vm_page_splay(vm_pindex_t, vm_page_t); vm_offset_t vm_page_startup(vm_offset_t vaddr); |
