fix two problems:

- when yielding the cpu while using the vnode's page list, use a marker page
   to keep our place in the list (like the other cases where we drop the lock).
 - wait until no one else has the page busy before deciding if the page needs
   to be cleaned.  a page will be dirty while it's being initialized but will
   be marked clean before PG_BUSY is cleared.
both found by enami.
This commit is contained in:
chs 2002-02-19 15:49:39 +00:00
parent dd2075f14d
commit 96f907f394

View File

@ -1,4 +1,4 @@
/* $NetBSD: genfs_vnops.c,v 1.48 2002/02/13 05:20:41 enami Exp $ */
/* $NetBSD: genfs_vnops.c,v 1.49 2002/02/19 15:49:39 chs Exp $ */
/*
* Copyright (c) 1982, 1986, 1989, 1993
@ -35,7 +35,7 @@
*/
#include <sys/cdefs.h>
__KERNEL_RCSID(0, "$NetBSD: genfs_vnops.c,v 1.48 2002/02/13 05:20:41 enami Exp $");
__KERNEL_RCSID(0, "$NetBSD: genfs_vnops.c,v 1.49 2002/02/19 15:49:39 chs Exp $");
#include "opt_nfsserver.h"
@ -1013,7 +1013,7 @@ genfs_putpages(v)
int i, s, error, npages, nback;
int freeflag;
struct vm_page *pgs[n], *pg, *nextpg, *tpg, curmp, endmp;
boolean_t wasclean, by_list, needs_clean;
boolean_t wasclean, by_list, needs_clean, yield;
boolean_t async = (flags & PGO_SYNCIO) == 0;
UVMHIST_FUNC("genfs_putpages"); UVMHIST_CALLED(ubchist);
@ -1071,12 +1071,6 @@ genfs_putpages(v)
}
nextpg = NULL;
while (by_list || off < endoff) {
if (curproc->p_cpu->ci_schedstate.spc_flags &
SPCF_SHOULDYIELD) {
simple_unlock(slock);
preempt(NULL);
simple_lock(slock);
}
/*
* if the current page is not interesting, move on to the next.
@ -1109,17 +1103,9 @@ genfs_putpages(v)
* wait for it to become unbusy.
*/
if (flags & PGO_FREE) {
pmap_page_protect(pg, VM_PROT_NONE);
}
if (flags & PGO_CLEANIT) {
needs_clean = pmap_clear_modify(pg) ||
(pg->flags & PG_CLEAN) == 0;
pg->flags |= PG_CLEAN;
} else {
needs_clean = FALSE;
}
if (needs_clean && pg->flags & PG_BUSY) {
yield = curproc->p_cpu->ci_schedstate.spc_flags &
SPCF_SHOULDYIELD;
if (pg->flags & PG_BUSY || yield) {
KASSERT(curproc != uvm.pagedaemon_proc);
UVMHIST_LOG(ubchist, "busy %p", pg,0,0,0);
if (by_list) {
@ -1127,10 +1113,15 @@ genfs_putpages(v)
UVMHIST_LOG(ubchist, "curmp next %p",
TAILQ_NEXT(&curmp, listq), 0,0,0);
}
pg->flags |= PG_WANTED;
pg->flags &= ~PG_CLEAN;
UVM_UNLOCK_AND_WAIT(pg, slock, 0, "genput", 0);
simple_lock(slock);
if (yield) {
simple_unlock(slock);
preempt(NULL);
simple_lock(slock);
} else {
pg->flags |= PG_WANTED;
UVM_UNLOCK_AND_WAIT(pg, slock, 0, "genput", 0);
simple_lock(slock);
}
if (by_list) {
UVMHIST_LOG(ubchist, "after next %p",
TAILQ_NEXT(&curmp, listq), 0,0,0);
@ -1142,6 +1133,22 @@ genfs_putpages(v)
continue;
}
/*
* if we're freeing, remove all mappings of the page now.
* if we're cleaning, check if the page is needs to be cleaned.
*/
if (flags & PGO_FREE) {
pmap_page_protect(pg, VM_PROT_NONE);
}
if (flags & PGO_CLEANIT) {
needs_clean = pmap_clear_modify(pg) ||
(pg->flags & PG_CLEAN) == 0;
pg->flags |= PG_CLEAN;
} else {
needs_clean = FALSE;
}
/*
* if we're cleaning, build a cluster.
* the cluster will consist of pages which are currently dirty,