Here's another refactoring that moves the remaining logic of uvm_fault()
handling lower faults, case 2, to its own function. This logic shouldn't
be modified in the first step of unlocking amap & anon and will still be
executed under KERNEL_LOCK(). Having a separate function will however
help to turn the 'ReFault' goto into a more readable loop. This will be
the next step.
ok?
Index: uvm/uvm_fault.c
===================================================================
RCS file: /cvs/src/sys/uvm/uvm_fault.c,v
retrieving revision 1.107
diff -u -p -r1.107 uvm_fault.c
--- uvm/uvm_fault.c 16 Nov 2020 12:30:16 -0000 1.107
+++ uvm/uvm_fault.c 16 Nov 2020 13:27:32 -0000
@@ -484,6 +484,9 @@ struct uvm_faultctx {
paddr_t pa_flags;
};
+int uvm_fault_lower(struct uvm_faultinfo *, struct uvm_faultctx *,
+ struct vm_page **, vm_fault_t, vm_prot_t);
+
/*
* uvm_fault_check: check prot, handle needs-copy, etc.
*
@@ -901,19 +904,11 @@ uvm_fault(vm_map_t orig_map, vaddr_t vad
{
struct uvm_faultinfo ufi;
struct uvm_faultctx flt;
- boolean_t promote, locked, shadowed;
- int result, lcv, gotpages;
- vaddr_t currva;
- voff_t uoff;
- struct vm_amap *amap;
- struct uvm_object *uobj;
- struct vm_anon *anons_store[UVM_MAXRANGE], **anons, *anon;
- struct vm_page *pages[UVM_MAXRANGE], *pg, *uobjpage;
+ boolean_t shadowed;
+ struct vm_anon *anons_store[UVM_MAXRANGE], **anons;
+ struct vm_page *pages[UVM_MAXRANGE];
int error;
- anon = NULL;
- pg = NULL;
-
uvmexp.faults++; /* XXX: locking? */
TRACEPOINT(uvm, fault, vaddr, fault_type, access_type, NULL);
@@ -957,8 +952,28 @@ ReFault:
}
}
- amap = ufi.entry->aref.ar_amap;
- uobj = ufi.entry->object.uvm_obj;
+ /* handle case 2: faulting on backing object or zero fill */
+ error = uvm_fault_lower(&ufi, &flt, pages, fault_type, access_type);
+ switch (error) {
+ case ERESTART:
+ goto ReFault;
+ default:
+ return error;
+ }
+}
+
+int
+uvm_fault_lower(struct uvm_faultinfo *ufi, struct uvm_faultctx *flt,
+ struct vm_page **pages, vm_fault_t fault_type, vm_prot_t access_type)
+{
+ struct vm_amap *amap = ufi->entry->aref.ar_amap;
+ struct uvm_object *uobj = ufi->entry->object.uvm_obj;
+ boolean_t promote, locked;
+ int result, lcv, gotpages;
+ struct vm_page *uobjpage, *pg = NULL;
+ struct vm_anon *anon = NULL;
+ vaddr_t currva;
+ voff_t uoff;
/*
* if the desired page is not shadowed by the amap and we have a
@@ -967,15 +982,15 @@ ReFault:
* with the usual pgo_get hook). the backing object signals this by
* providing a pgo_fault routine.
*/
- if (uobj && shadowed == FALSE && uobj->pgops->pgo_fault != NULL) {
- result = uobj->pgops->pgo_fault(&ufi, flt.startva, pages,
- flt.npages, flt.centeridx, fault_type, access_type,
+ if (uobj != NULL && uobj->pgops->pgo_fault != NULL) {
+ result = uobj->pgops->pgo_fault(ufi, flt->startva, pages,
+ flt->npages, flt->centeridx, fault_type, access_type,
PGO_LOCKED);
if (result == VM_PAGER_OK)
return (0); /* pgo_fault did pmap enter */
else if (result == VM_PAGER_REFAULT)
- goto ReFault; /* try again! */
+ return ERESTART; /* try again! */
else
return (EACCES);
}
@@ -989,20 +1004,20 @@ ReFault:
*
* ("get" has the option of doing a pmap_enter for us)
*/
- if (uobj && shadowed == FALSE) {
+ if (uobj != NULL) {
uvmexp.fltlget++;
- gotpages = flt.npages;
- (void) uobj->pgops->pgo_get(uobj, ufi.entry->offset +
- (flt.startva - ufi.entry->start),
- pages, &gotpages, flt.centeridx,
- access_type & MASK(ufi.entry),
- ufi.entry->advice, PGO_LOCKED);
+ gotpages = flt->npages;
+ (void) uobj->pgops->pgo_get(uobj, ufi->entry->offset +
+ (flt->startva - ufi->entry->start),
+ pages, &gotpages, flt->centeridx,
+ access_type & MASK(ufi->entry),
+ ufi->entry->advice, PGO_LOCKED);
/* check for pages to map, if we got any */
uobjpage = NULL;
if (gotpages) {
- currva = flt.startva;
- for (lcv = 0 ; lcv < flt.npages ;
+ currva = flt->startva;
+ for (lcv = 0 ; lcv < flt->npages ;
lcv++, currva += PAGE_SIZE) {
if (pages[lcv] == NULL ||
pages[lcv] == PGO_DONTCARE)
@@ -1017,7 +1032,7 @@ ReFault:
* remember this page as "uobjpage."
* (for later use).
*/
- if (lcv == flt.centeridx) {
+ if (lcv == flt->centeridx) {
uobjpage = pages[lcv];
continue;
}
@@ -1042,11 +1057,11 @@ ReFault:
* failures; it's not critical that we
* enter these right now.
*/
- (void) pmap_enter(ufi.orig_map->pmap, currva,
- VM_PAGE_TO_PHYS(pages[lcv]) | flt.pa_flags,
- flt.enter_prot & MASK(ufi.entry),
+ (void) pmap_enter(ufi->orig_map->pmap, currva,
+ VM_PAGE_TO_PHYS(pages[lcv]) | flt->pa_flags,
+ flt->enter_prot & MASK(ufi->entry),
PMAP_CANFAIL |
- (flt.wired ? PMAP_WIRED : 0));
+ (flt->wired ? PMAP_WIRED : 0));
/*
* NOTE: page can't be PG_WANTED because
@@ -1057,7 +1072,7 @@ ReFault:
PG_BUSY);
UVM_PAGE_OWN(pages[lcv], NULL);
} /* for "lcv" loop */
- pmap_update(ufi.orig_map->pmap);
+ pmap_update(ufi->orig_map->pmap);
} /* "gotpages" != 0 */
/* note: object still _locked_ */
} else {
@@ -1073,7 +1088,6 @@ ReFault:
* made it BUSY.
*/
- /* handle case 2: faulting on backing object or zero fill */
/*
* note that uobjpage can not be PGO_DONTCARE at this point. we now
* set uobjpage to PGO_DONTCARE if we are doing a zero fill. if we
@@ -1086,7 +1100,7 @@ ReFault:
} else {
KASSERT(uobjpage != PGO_DONTCARE);
promote = (access_type & PROT_WRITE) &&
- UVM_ET_ISCOPYONWRITE(ufi.entry);
+ UVM_ET_ISCOPYONWRITE(ufi->entry);
}
/*
@@ -1104,13 +1118,13 @@ ReFault:
/* update rusage counters */
curproc->p_ru.ru_majflt++;
- uvmfault_unlockall(&ufi, amap, NULL);
+ uvmfault_unlockall(ufi, amap, NULL);
uvmexp.fltget++;
gotpages = 1;
- uoff = (ufi.orig_rvaddr - ufi.entry->start) + ufi.entry->offset;
+ uoff = (ufi->orig_rvaddr - ufi->entry->start) +
ufi->entry->offset;
result = uobj->pgops->pgo_get(uobj, uoff, &uobjpage, &gotpages,
- 0, access_type & MASK(ufi.entry), ufi.entry->advice,
+ 0, access_type & MASK(ufi->entry), ufi->entry->advice,
PGO_SYNCIO);
/* recover from I/O */
@@ -1119,10 +1133,10 @@ ReFault:
if (result == VM_PAGER_AGAIN) {
tsleep_nsec(&lbolt, PVM, "fltagain2", INFSLP);
- goto ReFault;
+ return ERESTART;
}
- if (!UVM_ET_ISNOFAULT(ufi.entry))
+ if (!UVM_ET_ISNOFAULT(ufi->entry))
return (EIO);
uobjpage = PGO_DONTCARE;
@@ -1130,16 +1144,16 @@ ReFault:
}
/* re-verify the state of the world. */
- locked = uvmfault_relock(&ufi);
+ locked = uvmfault_relock(ufi);
/*
* Re-verify that amap slot is still free. if there is
* a problem, we clean up.
*/
- if (locked && amap && amap_lookup(&ufi.entry->aref,
- ufi.orig_rvaddr - ufi.entry->start)) {
+ if (locked && amap && amap_lookup(&ufi->entry->aref,
+ ufi->orig_rvaddr - ufi->entry->start)) {
if (locked)
- uvmfault_unlockall(&ufi, amap, NULL);
+ uvmfault_unlockall(ufi, amap, NULL);
locked = FALSE;
}
@@ -1156,10 +1170,10 @@ ReFault:
atomic_clearbits_int(&uobjpage->pg_flags,
PG_BUSY|PG_WANTED);
UVM_PAGE_OWN(uobjpage, NULL);
- goto ReFault;
+ return ERESTART;
}
if (locked == FALSE)
- goto ReFault;
+ return ERESTART;
/*
* we have the data in uobjpage which is PG_BUSY
@@ -1181,8 +1195,8 @@ ReFault:
* set "pg" to the page we want to map in (uobjpage, usually)
*/
uvmexp.flt_obj++;
- if (UVM_ET_ISCOPYONWRITE(ufi.entry))
- flt.enter_prot &= ~PROT_WRITE;
+ if (UVM_ET_ISCOPYONWRITE(ufi->entry))
+ flt->enter_prot &= ~PROT_WRITE;
pg = uobjpage; /* map in the actual object */
/* assert(uobjpage != PGO_DONTCARE) */
@@ -1230,7 +1244,7 @@ ReFault:
}
/* unlock and fail ... */
- uvmfault_unlockall(&ufi, amap, uobj);
+ uvmfault_unlockall(ufi, amap, uobj);
if (anon == NULL)
uvmexp.fltnoanon++;
else {
@@ -1246,7 +1260,7 @@ ReFault:
uvm_anwait();
else
uvm_wait("flt_noram5");
- goto ReFault;
+ return ERESTART;
}
/* fill in the data */
@@ -1281,18 +1295,18 @@ ReFault:
*/
}
- if (amap_add(&ufi.entry->aref,
- ufi.orig_rvaddr - ufi.entry->start, anon, 0)) {
- uvmfault_unlockall(&ufi, amap, NULL);
+ if (amap_add(&ufi->entry->aref,
+ ufi->orig_rvaddr - ufi->entry->start, anon, 0)) {
+ uvmfault_unlockall(ufi, amap, NULL);
uvm_anfree(anon);
uvmexp.fltnoamap++;
if (uvm_swapisfull())
return (ENOMEM);
- amap_populate(&ufi.entry->aref,
- ufi.orig_rvaddr - ufi.entry->start);
- goto ReFault;
+ amap_populate(&ufi->entry->aref,
+ ufi->orig_rvaddr - ufi->entry->start);
+ return ERESTART;
}
}
@@ -1301,9 +1315,9 @@ ReFault:
* all resources are present. we can now map it in and free our
* resources.
*/
- if (pmap_enter(ufi.orig_map->pmap, ufi.orig_rvaddr,
- VM_PAGE_TO_PHYS(pg) | flt.pa_flags, flt.enter_prot,
- access_type | PMAP_CANFAIL | (flt.wired ? PMAP_WIRED : 0)) != 0) {
+ if (pmap_enter(ufi->orig_map->pmap, ufi->orig_rvaddr,
+ VM_PAGE_TO_PHYS(pg) | flt->pa_flags, flt->enter_prot,
+ access_type | PMAP_CANFAIL | (flt->wired ? PMAP_WIRED : 0)) != 0) {
/*
* No need to undo what we did; we can simply think of
* this as the pmap throwing away the mapping information.
@@ -1316,14 +1330,14 @@ ReFault:
atomic_clearbits_int(&pg->pg_flags, PG_BUSY|PG_FAKE|PG_WANTED);
UVM_PAGE_OWN(pg, NULL);
- uvmfault_unlockall(&ufi, amap, uobj);
+ uvmfault_unlockall(ufi, amap, uobj);
if (uvm_swapisfull()) {
/* XXX instrumentation */
return (ENOMEM);
}
/* XXX instrumentation */
uvm_wait("flt_pmfail2");
- goto ReFault;
+ return ERESTART;
}
uvm_lock_pageq();
@@ -1351,8 +1365,8 @@ ReFault:
atomic_clearbits_int(&pg->pg_flags, PG_BUSY|PG_FAKE|PG_WANTED);
UVM_PAGE_OWN(pg, NULL);
- uvmfault_unlockall(&ufi, amap, uobj);
- pmap_update(ufi.orig_map->pmap);
+ uvmfault_unlockall(ufi, amap, uobj);
+ pmap_update(ufi->orig_map->pmap);
return (0);
}