Module Name: src
Committed By: yamt
Date: Wed Aug 1 22:34:15 UTC 2012
Modified Files:
src/sys/miscfs/genfs [yamt-pagecache]: genfs_io.c
src/sys/uvm [yamt-pagecache]: uvm_object.h uvm_page_array.c
uvm_page_array.h uvm_page_status.c uvm_pager.c uvm_vnode.c
Log Message:
- fix integrity sync.
putpages for integrity sync (fsync, msync with MS_SYNC, etc) should not
skip pages being written back by other threads.
- adapt to radix tree tag api changes.
To generate a diff of this commit:
cvs rdiff -u -r1.53.2.15 -r1.53.2.16 src/sys/miscfs/genfs/genfs_io.c
cvs rdiff -u -r1.31.2.3 -r1.31.2.4 src/sys/uvm/uvm_object.h
cvs rdiff -u -r1.1.2.5 -r1.1.2.6 src/sys/uvm/uvm_page_array.c \
src/sys/uvm/uvm_page_array.h
cvs rdiff -u -r1.1.2.7 -r1.1.2.8 src/sys/uvm/uvm_page_status.c
cvs rdiff -u -r1.107.2.3 -r1.107.2.4 src/sys/uvm/uvm_pager.c
cvs rdiff -u -r1.97.2.6 -r1.97.2.7 src/sys/uvm/uvm_vnode.c
Please note that diffs are not public domain; they are subject to the
copyright notices on the relevant files.
Modified files:
Index: src/sys/miscfs/genfs/genfs_io.c
diff -u src/sys/miscfs/genfs/genfs_io.c:1.53.2.15 src/sys/miscfs/genfs/genfs_io.c:1.53.2.16
--- src/sys/miscfs/genfs/genfs_io.c:1.53.2.15 Wed Aug 1 21:13:45 2012
+++ src/sys/miscfs/genfs/genfs_io.c Wed Aug 1 22:34:15 2012
@@ -1,4 +1,4 @@
-/* $NetBSD: genfs_io.c,v 1.53.2.15 2012/08/01 21:13:45 yamt Exp $ */
+/* $NetBSD: genfs_io.c,v 1.53.2.16 2012/08/01 22:34:15 yamt Exp $ */
/*
* Copyright (c) 1982, 1986, 1989, 1993
@@ -31,7 +31,7 @@
*/
#include <sys/cdefs.h>
-__KERNEL_RCSID(0, "$NetBSD: genfs_io.c,v 1.53.2.15 2012/08/01 21:13:45 yamt Exp $");
+__KERNEL_RCSID(0, "$NetBSD: genfs_io.c,v 1.53.2.16 2012/08/01 22:34:15 yamt Exp $");
#include <sys/param.h>
#include <sys/systm.h>
@@ -834,8 +834,7 @@ genfs_do_putpages(struct vnode *vp, off_
int error;
struct vm_page *pgs[maxpages], *pg;
struct uvm_page_array a;
- bool wasclean, needs_clean, yld;
- bool async = (origflags & PGO_SYNCIO) == 0;
+ bool wasclean, needs_clean;
bool pagedaemon = curlwp == uvm.pagedaemon_lwp;
struct lwp * const l = curlwp ? curlwp : &lwp0;
int flags;
@@ -844,6 +843,8 @@ genfs_do_putpages(struct vnode *vp, off_
bool has_trans;
bool tryclean; /* try to pull off from the syncer's list */
bool onworklst;
+ const bool integrity_sync =
+ (origflags & (PGO_LAZY|PGO_SYNCIO)) == PGO_SYNCIO;
const bool dirtyonly = (origflags & (PGO_DEACTIVATE|PGO_FREE)) == 0;
UVMHIST_FUNC("genfs_putpages"); UVMHIST_CALLED(ubchist);
@@ -941,45 +942,59 @@ retry:
for (;;) {
bool protected;
+ /*
+ * if we are asked to sync for integrity, we should wait on
+ * pages being written back by another threads as well.
+ */
+
pg = uvm_page_array_fill_and_peek(&a, uobj, nextoff, 0,
- dirtyonly ? UVM_PAGE_ARRAY_FILL_DIRTYONLY : 0);
+ dirtyonly ? (UVM_PAGE_ARRAY_FILL_DIRTY |
+ (integrity_sync ? UVM_PAGE_ARRAY_FILL_WRITEBACK : 0)) : 0);
if (pg == NULL) {
break;
}
- /*
- * if the current page is not interesting, move on to the next.
- */
-
KASSERT(pg->uobject == uobj);
KASSERT((pg->flags & (PG_RELEASED|PG_PAGEOUT)) == 0 ||
(pg->flags & (PG_BUSY)) != 0);
KASSERT(pg->offset >= startoff);
KASSERT(pg->offset >= nextoff);
KASSERT(!dirtyonly ||
- uvm_pagegetdirty(pg) != UVM_PAGE_STATUS_CLEAN);
+ uvm_pagegetdirty(pg) != UVM_PAGE_STATUS_CLEAN ||
+ radix_tree_get_tag(&uobj->uo_pages,
+ pg->offset >> PAGE_SHIFT, UVM_PAGE_WRITEBACK_TAG));
if (pg->offset >= endoff) {
break;
}
- if (pg->flags & (PG_RELEASED|PG_PAGEOUT)) {
- KASSERT((pg->flags & PG_BUSY) != 0);
- wasclean = false;
- nextoff = pg->offset + PAGE_SIZE;
- uvm_page_array_advance(&a);
+
+ /*
+ * a preempt point.
+ */
+
+ if ((l->l_cpu->ci_schedstate.spc_flags & SPCF_SHOULDYIELD)
+ != 0) {
+ nextoff = pg->offset; /* visit this page again */
+ mutex_exit(slock);
+ preempt();
+ /*
+ * as we dropped the object lock, our cached pages can
+ * be stale.
+ */
+ uvm_page_array_clear(&a);
+ mutex_enter(slock);
continue;
}
/*
- * if the current page needs to be cleaned and it's busy,
- * wait for it to become unbusy.
+ * if the current page is busy, wait for it to become unbusy.
*/
- yld = (l->l_cpu->ci_schedstate.spc_flags &
- SPCF_SHOULDYIELD) && !pagedaemon;
- if (pg->flags & PG_BUSY || yld) {
+ if ((pg->flags & PG_BUSY) != 0) {
UVMHIST_LOG(ubchist, "busy %p", pg,0,0,0);
- if (flags & PGO_BUSYFAIL && pg->flags & PG_BUSY) {
- UVMHIST_LOG(ubchist, "busyfail %p", pg, 0,0,0);
+ if ((pg->flags & (PG_RELEASED|PG_PAGEOUT)) != 0
+ && (flags & PGO_BUSYFAIL) != 0) {
+ UVMHIST_LOG(ubchist, "busyfail %p", pg,
+ 0,0,0);
error = EDEADLK;
if (busypg != NULL)
*busypg = pg;
@@ -992,15 +1007,19 @@ retry:
*/
break;
}
- nextoff = pg->offset; /* visit this page again */
- if ((pg->flags & PG_BUSY) != 0) {
- pg->flags |= PG_WANTED;
- UVM_UNLOCK_AND_WAIT(pg, slock, 0, "genput", 0);
- } else {
- KASSERT(yld);
- mutex_exit(slock);
- preempt();
+ /*
+ * don't bother to wait on other's activities
+ * unless we are asked to sync for integrity.
+ */
+ if (!integrity_sync) {
+ wasclean = false;
+ nextoff = pg->offset + PAGE_SIZE;
+ uvm_page_array_advance(&a);
+ continue;
}
+ nextoff = pg->offset; /* visit this page again */
+ pg->flags |= PG_WANTED;
+ UVM_UNLOCK_AND_WAIT(pg, slock, 0, "genput", 0);
/*
* as we dropped the object lock, our cached pages can
* be stale.
@@ -1160,6 +1179,15 @@ retry:
pgs[i-1]->offset + PAGE_SIZE == tpg->offset);
KASSERT(!needs_clean || uvm_pagegetdirty(pgs[i]) !=
UVM_PAGE_STATUS_DIRTY);
+ if (needs_clean) {
+ /*
+ * mark pages as WRITEBACK so that concurrent
+ * fsync can find and wait for our activities.
+ */
+ radix_tree_set_tag(&uobj->uo_pages,
+ pgs[i]->offset >> PAGE_SHIFT,
+ UVM_PAGE_WRITEBACK_TAG);
+ }
if (tpg->offset < startoff || tpg->offset >= endoff)
continue;
if (flags & PGO_DEACTIVATE && tpg->wire_count == 0) {
@@ -1254,11 +1282,11 @@ skip_scan:
#endif /* !defined(DEBUG) */
/*
- * if we found or started any i/o and we're doing sync i/o,
+ * if we found or started any i/o and we're asked to sync for integrity,
* wait for all writes to finish.
*/
- if (!wasclean && !async) {
+ if (!wasclean && integrity_sync) {
while (vp->v_numoutput != 0)
cv_wait(&vp->v_cv, slock);
}
@@ -1379,6 +1407,10 @@ genfs_do_io(struct vnode *vp, off_t off,
KASSERT(bytes != 0);
if (iowrite) {
+ /*
+ * why += 2?
+ * 1 for biodone, 1 for uvm_aio_aiodone.
+ */
mutex_enter(vp->v_interlock);
vp->v_numoutput += 2;
mutex_exit(vp->v_interlock);
Index: src/sys/uvm/uvm_object.h
diff -u src/sys/uvm/uvm_object.h:1.31.2.3 src/sys/uvm/uvm_object.h:1.31.2.4
--- src/sys/uvm/uvm_object.h:1.31.2.3 Tue Apr 17 00:09:00 2012
+++ src/sys/uvm/uvm_object.h Wed Aug 1 22:34:14 2012
@@ -1,4 +1,4 @@
-/* $NetBSD: uvm_object.h,v 1.31.2.3 2012/04/17 00:09:00 yamt Exp $ */
+/* $NetBSD: uvm_object.h,v 1.31.2.4 2012/08/01 22:34:14 yamt Exp $ */
/*
* Copyright (c) 1997 Charles D. Cranor and Washington University.
@@ -60,10 +60,11 @@ struct uvm_object {
};
/*
- * uo_pages
+ * tags for uo_pages
*/
-#define UVM_PAGE_DIRTY_TAG 0 /* might be dirty (!PG_CLEAN) */
+#define UVM_PAGE_DIRTY_TAG 1 /* might be dirty (!PG_CLEAN) */
+#define UVM_PAGE_WRITEBACK_TAG 2 /* being written back */
/*
* UVM_OBJ_KERN is a 'special' uo_refs value which indicates that the
Index: src/sys/uvm/uvm_page_array.c
diff -u src/sys/uvm/uvm_page_array.c:1.1.2.5 src/sys/uvm/uvm_page_array.c:1.1.2.6
--- src/sys/uvm/uvm_page_array.c:1.1.2.5 Wed Apr 18 13:40:44 2012
+++ src/sys/uvm/uvm_page_array.c Wed Aug 1 22:34:14 2012
@@ -1,4 +1,4 @@
-/* $NetBSD: uvm_page_array.c,v 1.1.2.5 2012/04/18 13:40:44 yamt Exp $ */
+/* $NetBSD: uvm_page_array.c,v 1.1.2.6 2012/08/01 22:34:14 yamt Exp $ */
/*-
* Copyright (c)2011 YAMAMOTO Takashi,
@@ -27,7 +27,7 @@
*/
#include <sys/cdefs.h>
-__KERNEL_RCSID(0, "$NetBSD: uvm_page_array.c,v 1.1.2.5 2012/04/18 13:40:44 yamt Exp $");
+__KERNEL_RCSID(0, "$NetBSD: uvm_page_array.c,v 1.1.2.6 2012/08/01 22:34:14 yamt Exp $");
#include <sys/param.h>
#include <sys/systm.h>
@@ -142,12 +142,17 @@ uvm_page_array_fill(struct uvm_page_arra
KASSERT(mutex_owned(uobj->vmobjlock));
#endif
KASSERT(uvm_page_array_peek(ar) == NULL);
- if ((flags & UVM_PAGE_ARRAY_FILL_DIRTYONLY) != 0) {
+ if ((flags & UVM_PAGE_ARRAY_FILL_DIRTY) != 0) {
+ unsigned int tagmask = UVM_PAGE_DIRTY_TAG;
+
+ if ((flags & UVM_PAGE_ARRAY_FILL_WRITEBACK) != 0) {
+ tagmask |= UVM_PAGE_WRITEBACK_TAG;
+ }
npages =
(backward ? radix_tree_gang_lookup_tagged_node_reverse :
radix_tree_gang_lookup_tagged_node)(
&uobj->uo_pages, off >> PAGE_SHIFT, (void **)ar->ar_pages,
- maxpages, dense, UVM_PAGE_DIRTY_TAG);
+ maxpages, dense, tagmask);
} else {
npages =
(backward ? radix_tree_gang_lookup_node_reverse :
Index: src/sys/uvm/uvm_page_array.h
diff -u src/sys/uvm/uvm_page_array.h:1.1.2.5 src/sys/uvm/uvm_page_array.h:1.1.2.6
--- src/sys/uvm/uvm_page_array.h:1.1.2.5 Wed Apr 18 13:39:28 2012
+++ src/sys/uvm/uvm_page_array.h Wed Aug 1 22:34:14 2012
@@ -1,4 +1,4 @@
-/* $NetBSD: uvm_page_array.h,v 1.1.2.5 2012/04/18 13:39:28 yamt Exp $ */
+/* $NetBSD: uvm_page_array.h,v 1.1.2.6 2012/08/01 22:34:14 yamt Exp $ */
/*-
* Copyright (c)2011 YAMAMOTO Takashi,
@@ -71,8 +71,9 @@ struct vm_page *uvm_page_array_fill_and_
/*
* flags for uvm_page_array_fill and uvm_page_array_fill_and_peek
*/
-#define UVM_PAGE_ARRAY_FILL_DIRTYONLY 1 /* skip known-clean pages */
-#define UVM_PAGE_ARRAY_FILL_DENSE 2 /* stop on a hole */
-#define UVM_PAGE_ARRAY_FILL_BACKWARD 4 /* descend order */
+#define UVM_PAGE_ARRAY_FILL_DIRTY 1 /* dirty pages */
+#define UVM_PAGE_ARRAY_FILL_WRITEBACK 2 /* dirty or written-back */
+#define UVM_PAGE_ARRAY_FILL_DENSE 4 /* stop on a hole */
+#define UVM_PAGE_ARRAY_FILL_BACKWARD 8 /* descend order */
#endif /* defined(_UVM_UVM_ARRAY_H_) */
Index: src/sys/uvm/uvm_page_status.c
diff -u src/sys/uvm/uvm_page_status.c:1.1.2.7 src/sys/uvm/uvm_page_status.c:1.1.2.8
--- src/sys/uvm/uvm_page_status.c:1.1.2.7 Tue Jan 24 02:11:33 2012
+++ src/sys/uvm/uvm_page_status.c Wed Aug 1 22:34:14 2012
@@ -1,4 +1,4 @@
-/* $NetBSD: uvm_page_status.c,v 1.1.2.7 2012/01/24 02:11:33 yamt Exp $ */
+/* $NetBSD: uvm_page_status.c,v 1.1.2.8 2012/08/01 22:34:14 yamt Exp $ */
/*-
* Copyright (c)2011 YAMAMOTO Takashi,
@@ -27,7 +27,7 @@
*/
#include <sys/cdefs.h>
-__KERNEL_RCSID(0, "$NetBSD: uvm_page_status.c,v 1.1.2.7 2012/01/24 02:11:33 yamt Exp $");
+__KERNEL_RCSID(0, "$NetBSD: uvm_page_status.c,v 1.1.2.8 2012/08/01 22:34:14 yamt Exp $");
#include <sys/param.h>
#include <sys/systm.h>
@@ -65,7 +65,7 @@ uvm_pagegetdirty(struct vm_page *pg)
KASSERT((~pg->flags & (PG_CLEAN|PG_DIRTY)) != 0);
KASSERT(uvm_page_locked_p(pg));
KASSERT(uobj == NULL || ((pg->flags & PG_CLEAN) == 0) ==
- radix_tree_get_tag(&uobj->uo_pages, idx, UVM_PAGE_DIRTY_TAG));
+ !!radix_tree_get_tag(&uobj->uo_pages, idx, UVM_PAGE_DIRTY_TAG));
return pg->flags & (PG_CLEAN|PG_DIRTY);
}
@@ -104,7 +104,7 @@ uvm_pagemarkdirty(struct vm_page *pg, un
KASSERT((newstatus & ~(PG_CLEAN|PG_DIRTY)) == 0);
KASSERT(uvm_page_locked_p(pg));
KASSERT(uobj == NULL || ((pg->flags & PG_CLEAN) == 0) ==
- radix_tree_get_tag(&uobj->uo_pages, idx, UVM_PAGE_DIRTY_TAG));
+ !!radix_tree_get_tag(&uobj->uo_pages, idx, UVM_PAGE_DIRTY_TAG));
if (oldstatus == newstatus) {
return;
@@ -131,7 +131,7 @@ uvm_pagemarkdirty(struct vm_page *pg, un
pg->flags &= ~(PG_CLEAN|PG_DIRTY);
pg->flags |= newstatus;
KASSERT(uobj == NULL || ((pg->flags & PG_CLEAN) == 0) ==
- radix_tree_get_tag(&uobj->uo_pages, idx, UVM_PAGE_DIRTY_TAG));
+ !!radix_tree_get_tag(&uobj->uo_pages, idx, UVM_PAGE_DIRTY_TAG));
if ((pg->pqflags & PQ_STAT) != 0) {
stat_update((pg->pqflags & PQ_SWAPBACKED) != 0,
oldstatus, newstatus);
Index: src/sys/uvm/uvm_pager.c
diff -u src/sys/uvm/uvm_pager.c:1.107.2.3 src/sys/uvm/uvm_pager.c:1.107.2.4
--- src/sys/uvm/uvm_pager.c:1.107.2.3 Tue Apr 17 00:09:00 2012
+++ src/sys/uvm/uvm_pager.c Wed Aug 1 22:34:14 2012
@@ -1,4 +1,4 @@
-/* $NetBSD: uvm_pager.c,v 1.107.2.3 2012/04/17 00:09:00 yamt Exp $ */
+/* $NetBSD: uvm_pager.c,v 1.107.2.4 2012/08/01 22:34:14 yamt Exp $ */
/*
* Copyright (c) 1997 Charles D. Cranor and Washington University.
@@ -32,7 +32,7 @@
*/
#include <sys/cdefs.h>
-__KERNEL_RCSID(0, "$NetBSD: uvm_pager.c,v 1.107.2.3 2012/04/17 00:09:00 yamt Exp $");
+__KERNEL_RCSID(0, "$NetBSD: uvm_pager.c,v 1.107.2.4 2012/08/01 22:34:14 yamt Exp $");
#include "opt_uvmhist.h"
#include "opt_readahead.h"
@@ -368,6 +368,13 @@ uvm_aio_aiodone_pages(struct vm_page **p
}
#endif /* defined(VMSWAP) */
+ if (write && uobj != NULL) {
+ KASSERT(radix_tree_get_tag(&uobj->uo_pages,
+ pg->offset >> PAGE_SHIFT, UVM_PAGE_WRITEBACK_TAG));
+ radix_tree_clear_tag(&uobj->uo_pages,
+ pg->offset >> PAGE_SHIFT, UVM_PAGE_WRITEBACK_TAG);
+ }
+
/*
* process errors. for reads, just mark the page to be freed.
* for writes, if the error was ENOMEM, we assume this was
Index: src/sys/uvm/uvm_vnode.c
diff -u src/sys/uvm/uvm_vnode.c:1.97.2.6 src/sys/uvm/uvm_vnode.c:1.97.2.7
--- src/sys/uvm/uvm_vnode.c:1.97.2.6 Wed Aug 1 21:12:23 2012
+++ src/sys/uvm/uvm_vnode.c Wed Aug 1 22:34:14 2012
@@ -1,4 +1,4 @@
-/* $NetBSD: uvm_vnode.c,v 1.97.2.6 2012/08/01 21:12:23 yamt Exp $ */
+/* $NetBSD: uvm_vnode.c,v 1.97.2.7 2012/08/01 22:34:14 yamt Exp $ */
/*
* Copyright (c) 1997 Charles D. Cranor and Washington University.
@@ -45,7 +45,7 @@
*/
#include <sys/cdefs.h>
-__KERNEL_RCSID(0, "$NetBSD: uvm_vnode.c,v 1.97.2.6 2012/08/01 21:12:23 yamt Exp $");
+__KERNEL_RCSID(0, "$NetBSD: uvm_vnode.c,v 1.97.2.7 2012/08/01 22:34:14 yamt Exp $");
#include "opt_uvmhist.h"
@@ -245,7 +245,7 @@ uvn_findpage(struct uvm_object *uobj, vo
const unsigned int fillflags =
((flags & UFP_BACKWARD) ? UVM_PAGE_ARRAY_FILL_BACKWARD : 0) |
((flags & UFP_DIRTYONLY) ?
- (UVM_PAGE_ARRAY_FILL_DIRTYONLY|UVM_PAGE_ARRAY_FILL_DENSE) : 0);
+ (UVM_PAGE_ARRAY_FILL_DIRTY|UVM_PAGE_ARRAY_FILL_DENSE) : 0);
UVMHIST_FUNC("uvn_findpage"); UVMHIST_CALLED(ubchist);
UVMHIST_LOG(ubchist, "vp %p off 0x%lx", uobj, offset,0,0);