summaryrefslogtreecommitdiff
path: root/sys/kern
diff options
context:
space:
mode:
authorAlan Cox <alc@FreeBSD.org>2009-05-13 05:39:39 +0000
committerAlan Cox <alc@FreeBSD.org>2009-05-13 05:39:39 +0000
commit1c1b26f276f85b086bc6e579c452e52231c234ac (patch)
treede540785bb7f52f8c0b6353b22a06e54fff788d1 /sys/kern
parentb1f26c738c3a2433f1759099fceb31d741e4f462 (diff)
Notes
Diffstat (limited to 'sys/kern')
-rw-r--r--sys/kern/vfs_bio.c47
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;
}