version 1.97, 2011/09/06 16:41:55 |
version 1.97.2.2, 2011/11/26 15:19:06 |
Line 64 __KERNEL_RCSID(0, "$NetBSD$"); |
|
Line 64 __KERNEL_RCSID(0, "$NetBSD$"); |
|
|
|
#include <uvm/uvm.h> |
#include <uvm/uvm.h> |
#include <uvm/uvm_readahead.h> |
#include <uvm/uvm_readahead.h> |
|
#include <uvm/uvm_page_array.h> |
|
|
/* |
/* |
* functions |
* functions |
Line 76 static int uvn_put(struct uvm_object *, |
|
Line 77 static int uvn_put(struct uvm_object *, |
|
static void uvn_reference(struct uvm_object *); |
static void uvn_reference(struct uvm_object *); |
|
|
static int uvn_findpage(struct uvm_object *, voff_t, struct vm_page **, |
static int uvn_findpage(struct uvm_object *, voff_t, struct vm_page **, |
int); |
int, struct uvm_page_array *a, unsigned int); |
|
|
/* |
/* |
* master pager structure |
* master pager structure |
Line 130 uvn_detach(struct uvm_object *uobj) |
|
Line 131 uvn_detach(struct uvm_object *uobj) |
|
* |
* |
* => object must be locked on entry! VOP_PUTPAGES must unlock it. |
* => object must be locked on entry! VOP_PUTPAGES must unlock it. |
* => flags: PGO_SYNCIO -- use sync. I/O |
* => flags: PGO_SYNCIO -- use sync. I/O |
* => note: caller must set PG_CLEAN and pmap_clear_modify (if needed) |
|
*/ |
*/ |
|
|
static int |
static int |
Line 197 uvn_findpages(struct uvm_object *uobj, v |
|
Line 197 uvn_findpages(struct uvm_object *uobj, v |
|
struct vm_page **pgs, int flags) |
struct vm_page **pgs, int flags) |
{ |
{ |
int i, count, found, npages, rv; |
int i, count, found, npages, rv; |
|
struct uvm_page_array a; |
|
|
|
uvm_page_array_init(&a); |
count = found = 0; |
count = found = 0; |
npages = *npagesp; |
npages = *npagesp; |
if (flags & UFP_BACKWARD) { |
if (flags & UFP_BACKWARD) { |
for (i = npages - 1; i >= 0; i--, offset -= PAGE_SIZE) { |
for (i = npages - 1; i >= 0; i--, offset -= PAGE_SIZE) { |
rv = uvn_findpage(uobj, offset, &pgs[i], flags); |
rv = uvn_findpage(uobj, offset, &pgs[i], flags, &a, |
|
npages - i); |
if (rv == 0) { |
if (rv == 0) { |
if (flags & UFP_DIRTYONLY) |
if (flags & UFP_DIRTYONLY) |
break; |
break; |
Line 212 uvn_findpages(struct uvm_object *uobj, v |
|
Line 215 uvn_findpages(struct uvm_object *uobj, v |
|
} |
} |
} else { |
} else { |
for (i = 0; i < npages; i++, offset += PAGE_SIZE) { |
for (i = 0; i < npages; i++, offset += PAGE_SIZE) { |
rv = uvn_findpage(uobj, offset, &pgs[i], flags); |
rv = uvn_findpage(uobj, offset, &pgs[i], flags, &a, |
|
npages - i); |
if (rv == 0) { |
if (rv == 0) { |
if (flags & UFP_DIRTYONLY) |
if (flags & UFP_DIRTYONLY) |
break; |
break; |
Line 221 uvn_findpages(struct uvm_object *uobj, v |
|
Line 225 uvn_findpages(struct uvm_object *uobj, v |
|
count++; |
count++; |
} |
} |
} |
} |
|
uvm_page_array_fini(&a); |
*npagesp = count; |
*npagesp = count; |
return (found); |
return (found); |
} |
} |
|
|
static int |
static int |
uvn_findpage(struct uvm_object *uobj, voff_t offset, struct vm_page **pgp, |
uvn_findpage(struct uvm_object *uobj, voff_t offset, struct vm_page **pgp, |
int flags) |
int flags, struct uvm_page_array *a, unsigned int nleft) |
{ |
{ |
struct vm_page *pg; |
struct vm_page *pg; |
bool dirty; |
bool dirty; |
|
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); |
UVMHIST_FUNC("uvn_findpage"); UVMHIST_CALLED(ubchist); |
UVMHIST_FUNC("uvn_findpage"); UVMHIST_CALLED(ubchist); |
UVMHIST_LOG(ubchist, "vp %p off 0x%lx", uobj, offset,0,0); |
UVMHIST_LOG(ubchist, "vp %p off 0x%lx", uobj, offset,0,0); |
|
|
Line 238 uvn_findpage(struct uvm_object *uobj, vo |
|
Line 247 uvn_findpage(struct uvm_object *uobj, vo |
|
|
|
if (*pgp != NULL) { |
if (*pgp != NULL) { |
UVMHIST_LOG(ubchist, "dontcare", 0,0,0,0); |
UVMHIST_LOG(ubchist, "dontcare", 0,0,0,0); |
return 0; |
goto skip; |
} |
} |
for (;;) { |
for (;;) { |
/* look for an existing page */ |
/* look for an existing page */ |
pg = uvm_pagelookup(uobj, offset); |
pg = uvm_page_array_fill_and_peek(a, uobj, offset, nleft, |
|
fillflags); |
|
if (pg != NULL && pg->offset != offset) { |
|
KASSERT((fillflags & UVM_PAGE_ARRAY_FILL_DENSE) == 0); |
|
KASSERT( |
|
((fillflags & UVM_PAGE_ARRAY_FILL_BACKWARD) != 0) |
|
== (pg->offset < offset)); |
|
pg = NULL; |
|
} |
|
|
/* nope? allocate one now */ |
/* nope? allocate one now */ |
if (pg == NULL) { |
if (pg == NULL) { |
Line 259 uvn_findpage(struct uvm_object *uobj, vo |
|
Line 276 uvn_findpage(struct uvm_object *uobj, vo |
|
} |
} |
mutex_exit(uobj->vmobjlock); |
mutex_exit(uobj->vmobjlock); |
uvm_wait("uvn_fp1"); |
uvm_wait("uvn_fp1"); |
|
uvm_page_array_clear(a); |
mutex_enter(uobj->vmobjlock); |
mutex_enter(uobj->vmobjlock); |
continue; |
continue; |
} |
} |
Line 267 uvn_findpage(struct uvm_object *uobj, vo |
|
Line 285 uvn_findpage(struct uvm_object *uobj, vo |
|
break; |
break; |
} else if (flags & UFP_NOCACHE) { |
} else if (flags & UFP_NOCACHE) { |
UVMHIST_LOG(ubchist, "nocache",0,0,0,0); |
UVMHIST_LOG(ubchist, "nocache",0,0,0,0); |
return 0; |
goto skip; |
} |
} |
|
|
/* page is there, see if we need to wait on it */ |
/* page is there, see if we need to wait on it */ |
if ((pg->flags & PG_BUSY) != 0) { |
if ((pg->flags & PG_BUSY) != 0) { |
if (flags & UFP_NOWAIT) { |
if (flags & UFP_NOWAIT) { |
UVMHIST_LOG(ubchist, "nowait",0,0,0,0); |
UVMHIST_LOG(ubchist, "nowait",0,0,0,0); |
return 0; |
goto skip; |
} |
} |
pg->flags |= PG_WANTED; |
pg->flags |= PG_WANTED; |
UVMHIST_LOG(ubchist, "wait %p (color %u)", pg, |
UVMHIST_LOG(ubchist, "wait %p (color %u)", pg, |
VM_PGCOLOR_BUCKET(pg), 0,0); |
VM_PGCOLOR_BUCKET(pg), 0,0); |
UVM_UNLOCK_AND_WAIT(pg, uobj->vmobjlock, 0, |
UVM_UNLOCK_AND_WAIT(pg, uobj->vmobjlock, 0, |
"uvn_fp2", 0); |
"uvn_fp2", 0); |
|
uvm_page_array_clear(a); |
mutex_enter(uobj->vmobjlock); |
mutex_enter(uobj->vmobjlock); |
continue; |
continue; |
} |
} |
|
|
/* skip PG_RDONLY pages if requested */ |
/* skip PG_RDONLY and PG_HOLE pages if requested */ |
if ((flags & UFP_NORDONLY) && (pg->flags & PG_RDONLY)) { |
if ((flags & UFP_NORDONLY) && |
|
(pg->flags & (PG_RDONLY|PG_HOLE))) { |
UVMHIST_LOG(ubchist, "nordonly",0,0,0,0); |
UVMHIST_LOG(ubchist, "nordonly",0,0,0,0); |
return 0; |
goto skip; |
} |
} |
|
|
/* stop on clean pages if requested */ |
/* stop on clean pages if requested */ |
if (flags & UFP_DIRTYONLY) { |
if (flags & UFP_DIRTYONLY) { |
dirty = pmap_clear_modify(pg) || |
dirty = uvm_pagecheckdirty(pg, false); |
(pg->flags & PG_CLEAN) == 0; |
|
pg->flags |= PG_CLEAN; |
|
if (!dirty) { |
if (!dirty) { |
UVMHIST_LOG(ubchist, "dirtonly", 0,0,0,0); |
UVMHIST_LOG(ubchist, "dirtonly", 0,0,0,0); |
return 0; |
return 0; |
Line 307 uvn_findpage(struct uvm_object *uobj, vo |
|
Line 325 uvn_findpage(struct uvm_object *uobj, vo |
|
UVM_PAGE_OWN(pg, "uvn_findpage"); |
UVM_PAGE_OWN(pg, "uvn_findpage"); |
UVMHIST_LOG(ubchist, "found %p (color %u)", |
UVMHIST_LOG(ubchist, "found %p (color %u)", |
pg, VM_PGCOLOR_BUCKET(pg), 0,0); |
pg, VM_PGCOLOR_BUCKET(pg), 0,0); |
|
uvm_page_array_advance(a); |
break; |
break; |
} |
} |
*pgp = pg; |
*pgp = pg; |
return 1; |
return 1; |
|
|
|
skip: |
|
pg = uvm_page_array_peek(a); |
|
if (pg != NULL) { |
|
if (pg->offset == offset) { |
|
uvm_page_array_advance(a); |
|
} else { |
|
KASSERT((fillflags & UVM_PAGE_ARRAY_FILL_DENSE) == 0); |
|
} |
|
} |
|
return 0; |
} |
} |
|
|
/* |
/* |