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 /sys/kern | |
| parent | b1f26c738c3a2433f1759099fceb31d741e4f462 (diff) | |
Notes
Diffstat (limited to 'sys/kern')
| -rw-r--r-- | sys/kern/vfs_bio.c | 47 |
1 files changed, 36 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; } |
