Changeset View
Changeset View
Standalone View
Standalone View
head/sys/vm/vm_fault.c
Show First 20 Lines • Show All 622 Lines • ▼ Show 20 Lines | default: | ||||
KASSERT(0, ("Unexpected Mach error %d from vm_fault()", | KASSERT(0, ("Unexpected Mach error %d from vm_fault()", | ||||
result)); | result)); | ||||
break; | break; | ||||
} | } | ||||
} | } | ||||
return (result); | return (result); | ||||
} | } | ||||
static int | |||||
vm_fault_lock_vnode(struct faultstate *fs) | |||||
{ | |||||
struct vnode *vp; | |||||
int error, locked; | |||||
if (fs->object->type != OBJT_VNODE) | |||||
return (KERN_SUCCESS); | |||||
vp = fs->object->handle; | |||||
if (vp == fs->vp) | |||||
return (KERN_SUCCESS); | |||||
/* | |||||
* Perform an unlock in case the desired vnode changed while | |||||
* the map was unlocked during a retry. | |||||
*/ | |||||
unlock_vp(fs); | |||||
locked = VOP_ISLOCKED(vp); | |||||
if (locked != LK_EXCLUSIVE) | |||||
locked = LK_SHARED; | |||||
/* | |||||
* We must not sleep acquiring the vnode lock while we have | |||||
* the page exclusive busied or the object's | |||||
* paging-in-progress count incremented. Otherwise, we could | |||||
* deadlock. | |||||
*/ | |||||
error = vget(vp, locked | LK_CANRECURSE | LK_NOWAIT, curthread); | |||||
if (error == 0) { | |||||
fs->vp = vp; | |||||
return (KERN_SUCCESS); | |||||
} | |||||
vhold(vp); | |||||
release_page(fs); | |||||
unlock_and_deallocate(fs); | |||||
error = vget(vp, locked | LK_RETRY | LK_CANRECURSE, curthread); | |||||
vdrop(vp); | |||||
fs->vp = vp; | |||||
KASSERT(error == 0, ("vm_fault: vget failed %d", error)); | |||||
return (KERN_RESOURCE_SHORTAGE); | |||||
} | |||||
int | int | ||||
vm_fault(vm_map_t map, vm_offset_t vaddr, vm_prot_t fault_type, | vm_fault(vm_map_t map, vm_offset_t vaddr, vm_prot_t fault_type, | ||||
int fault_flags, vm_page_t *m_hold) | int fault_flags, vm_page_t *m_hold) | ||||
{ | { | ||||
struct faultstate fs; | struct faultstate fs; | ||||
struct vnode *vp; | |||||
struct domainset *dset; | struct domainset *dset; | ||||
vm_object_t next_object, retry_object; | vm_object_t next_object, retry_object; | ||||
vm_offset_t e_end, e_start; | vm_offset_t e_end, e_start; | ||||
vm_pindex_t retry_pindex; | vm_pindex_t retry_pindex; | ||||
vm_prot_t prot, retry_prot; | vm_prot_t prot, retry_prot; | ||||
int ahead, alloc_req, behind, cluster_offset, error, era, faultcount; | int ahead, alloc_req, behind, cluster_offset, era, faultcount; | ||||
int locked, nera, oom, result, rv; | int nera, oom, result, rv; | ||||
u_char behavior; | u_char behavior; | ||||
boolean_t wired; /* Passed by reference. */ | boolean_t wired; /* Passed by reference. */ | ||||
bool dead, hardfault, is_first_object_locked; | bool dead, hardfault, is_first_object_locked; | ||||
VM_CNT_INC(v_vm_faults); | VM_CNT_INC(v_vm_faults); | ||||
if ((curthread->td_pflags & TDP_NOFAULTING) != 0) | if ((curthread->td_pflags & TDP_NOFAULTING) != 0) | ||||
return (KERN_PROTECTION_FAILURE); | return (KERN_PROTECTION_FAILURE); | ||||
▲ Show 20 Lines • Show All 344 Lines • ▼ Show 20 Lines | if (fs.object->type != OBJT_DEFAULT) { | ||||
/* | /* | ||||
* Release the map lock before locking the vnode or | * Release the map lock before locking the vnode or | ||||
* sleeping in the pager. (If the current object has | * sleeping in the pager. (If the current object has | ||||
* a shadow, then an earlier iteration of this loop | * a shadow, then an earlier iteration of this loop | ||||
* may have already unlocked the map.) | * may have already unlocked the map.) | ||||
*/ | */ | ||||
unlock_map(&fs); | unlock_map(&fs); | ||||
if (fs.object->type == OBJT_VNODE && | rv = vm_fault_lock_vnode(&fs); | ||||
(vp = fs.object->handle) != fs.vp) { | MPASS(rv == KERN_SUCCESS || | ||||
/* | rv == KERN_RESOURCE_SHORTAGE); | ||||
* Perform an unlock in case the desired vnode | if (rv == KERN_RESOURCE_SHORTAGE) | ||||
* changed while the map was unlocked during a | |||||
* retry. | |||||
*/ | |||||
unlock_vp(&fs); | |||||
locked = VOP_ISLOCKED(vp); | |||||
if (locked != LK_EXCLUSIVE) | |||||
locked = LK_SHARED; | |||||
/* | |||||
* We must not sleep acquiring the vnode lock | |||||
* while we have the page exclusive busied or | |||||
* the object's paging-in-progress count | |||||
* incremented. Otherwise, we could deadlock. | |||||
*/ | |||||
error = vget(vp, locked | LK_CANRECURSE | | |||||
LK_NOWAIT, curthread); | |||||
if (error != 0) { | |||||
vhold(vp); | |||||
release_page(&fs); | |||||
unlock_and_deallocate(&fs); | |||||
error = vget(vp, locked | LK_RETRY | | |||||
LK_CANRECURSE, curthread); | |||||
vdrop(vp); | |||||
fs.vp = vp; | |||||
KASSERT(error == 0, | |||||
("vm_fault: vget failed")); | |||||
goto RetryFault; | goto RetryFault; | ||||
} | |||||
fs.vp = vp; | |||||
} | |||||
KASSERT(fs.vp == NULL || !fs.map->system_map, | KASSERT(fs.vp == NULL || !fs.map->system_map, | ||||
("vm_fault: vnode-backed object mapped by system map")); | ("vm_fault: vnode-backed object mapped by system map")); | ||||
/* | /* | ||||
* Page in the requested page and hint the pager, | * Page in the requested page and hint the pager, | ||||
* that it may bring up surrounding pages. | * that it may bring up surrounding pages. | ||||
*/ | */ | ||||
if (nera == -1 || behavior == MAP_ENTRY_BEHAV_RANDOM || | if (nera == -1 || behavior == MAP_ENTRY_BEHAV_RANDOM || | ||||
▲ Show 20 Lines • Show All 859 Lines • Show Last 20 Lines |