kflags |= NOTE_WRITE;
/*
- * Always try to flush the page if the request is coming
- * from the pageout daemon (IO_ASYNC), else buwrite() the
- * buffer.
+ * Always try to flush the page in the UIO_NOCOPY case. This
+ * can come from the pageout daemon or during vnode eviction.
+ * It is not necessarily going to be marked IO_ASYNC/IO_SYNC.
*
- * buwrite() dirties the underlying VM pages instead of
- * dirtying the buffer, releasing the buffer as a clean
- * buffer. This allows tmpfs to use essentially all
- * available memory to cache file data. If we used bdwrite()
- * the buffer cache would wind up flushing the data to
- * swap too quickly.
+ * For the normal case we buwrite(), dirtying the underlying
+ * VM pages instead of dirtying the buffer and releasing the
+ * buffer as a clean buffer. This allows tmpfs to use
+ * essentially all available memory to cache file data.
+ * If we used bdwrite() the buffer cache would wind up
+ * flushing the data to swap too quickly.
*/
bp->b_flags |= B_AGE;
- if (ap->a_ioflag & IO_ASYNC) {
+ if (uio->uio_segflg == UIO_NOCOPY) {
bawrite(bp);
} else {
buwrite(bp);
}
/* --------------------------------------------------------------------- */
+#include <vm/vm_object.h>
+#include <vm/vm_page.h>
int
tmpfs_reclaim(struct vop_reclaim_args *v)
/*
* Clean pages and flush buffers.
+ *
+ * NOTE! TMPFS buffer flushes do not typically flush the
+ * actual page to swap as this would be highly
+ * inefficient, and normal filesystems usually wrap
+ * page flushes with buffer cache buffers.
+ *
+ * To deal with this we have to call vinvalbuf() both
+ * before and after the vm_object_page_clean().
*/
- vm_object_page_clean(object, 0, 0, OBJPC_SYNC);
-
vp = (struct vnode *) object->handle;
vinvalbuf(vp, V_SAVE, 0, 0);
+ vm_object_page_clean(object, 0, 0, OBJPC_SYNC);
+ vinvalbuf(vp, V_SAVE, 0, 0);
}
/*
vm_page_wakeup(p);
} else if (p->wire_count == 0) {
/*
- * NOTE: PG_NEED_COMMIT is ignored.
+ * NOTE: p->dirty and PG_NEED_COMMIT are ignored.
*/
vm_page_free(p);
mycpu->gd_cnt.v_pfree++;
* cases where the page cannot be dirty.
*/
if (p->valid == 0 || (p->queue - p->pc) == PQ_CACHE) {
- KKASSERT((p->dirty & p->valid) == 0);
+ KKASSERT((p->dirty & p->valid) == 0 &&
+ (p->flags & PG_NEED_COMMIT) == 0);
vm_page_wakeup(p);
goto done;
}
* page.
*/
vm_page_test_dirty(p);
- if ((p->dirty & p->valid) == 0) {
+ if ((p->dirty & p->valid) == 0 && (p->flags & PG_NEED_COMMIT) == 0) {
vm_page_flag_clear(p, PG_CLEANCHK);
vm_page_wakeup(p);
goto done;
break;
}
vm_page_test_dirty(tp);
- if ((tp->dirty & tp->valid) == 0) {
+ if ((tp->dirty & tp->valid) == 0 &&
+ (tp->flags & PG_NEED_COMMIT) == 0) {
vm_page_flag_clear(tp, PG_CLEANCHK);
vm_page_wakeup(tp);
break;
break;
}
vm_page_test_dirty(tp);
- if ((tp->dirty & tp->valid) == 0) {
+ if ((tp->dirty & tp->valid) == 0 &&
+ (tp->flags & PG_NEED_COMMIT) == 0) {
vm_page_flag_clear(tp, PG_CLEANCHK);
vm_page_wakeup(tp);
break;
}
runlen = maxb + maxf + 1;
- for (i = 0; i < runlen; i++)
+ for (i = 0; i < runlen; i++) /* XXX need this any more? */
vm_page_hold(ma[i]);
vm_pageout_flush(ma, runlen, pagerflags);
- /*
- * WARNING: Related pages are still held but the BUSY was inherited
- * by the pageout I/O, so the pages might not be busy any
- * more. We cannot re-protect the page without waiting
- * for the I/O to complete and then busying it again.
- */
- for (i = 0; i < runlen; i++) {
- if (ma[i]->valid & ma[i]->dirty) {
- /*vm_page_protect(ma[i], VM_PROT_READ);*/
- vm_page_flag_set(ma[i], PG_CLEANCHK);
-
- /*
- * maxf will end up being the actual number of pages
- * we wrote out contiguously, non-inclusive of the
- * first page. We do not count look-behind pages.
- */
- if (i >= maxb + 1 && (maxf > i - maxb - 1))
- maxf = i - maxb - 1;
- }
+ for (i = 0; i < runlen; i++) /* XXX need this any more? */
vm_page_unhold(ma[i]);
- }
- /*return(maxf + 1);*/
}
/*
}
/*
- * limit is our clean_only flag. If set and the page is dirty, do
- * not free it. If set and the page is being held by someone, do
- * not free it.
+ * limit is our clean_only flag. If set and the page is dirty or
+ * requires a commit, do not free it. If set and the page is being
+ * held by someone, do not free it.
*/
if (info->limit && p->valid) {
vm_page_test_dirty(p);
- if (p->valid & p->dirty) {
+ if ((p->valid & p->dirty) || (p->flags & PG_NEED_COMMIT)) {
vm_page_wakeup(p);
return(0);
}
* Since we are inserting a new and possibly dirty page,
* update the object's OBJ_WRITEABLE and OBJ_MIGHTBEDIRTY flags.
*/
- if ((m->valid & m->dirty) || (m->flags & PG_WRITEABLE))
+ if ((m->valid & m->dirty) ||
+ (m->flags & (PG_WRITEABLE | PG_NEED_COMMIT)))
vm_object_set_writeable_dirty(object);
/*
* be moved to the cache.
*/
vm_page_test_dirty(m);
- if (m->dirty) {
+ if (m->dirty || (m->flags & PG_NEED_COMMIT)) {
vm_page_wakeup(m);
return(0);
}
* dirty bit after cleaning out the pmaps.
*/
vm_page_test_dirty(m);
- if (m->dirty) {
+ if (m->dirty || (m->flags & PG_NEED_COMMIT)) {
vm_page_wakeup(m);
return(0);
}
vm_page_protect(m, VM_PROT_NONE);
- if (m->dirty) {
+ if (m->dirty || (m->flags & PG_NEED_COMMIT)) {
vm_page_wakeup(m);
return(0);
}
vm_page_need_commit(vm_page_t m)
{
vm_page_flag_set(m, PG_NEED_COMMIT);
+ vm_object_set_writeable_dirty(m->object);
}
void