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); }