vm_fault: do not trigger OOM too early
Wakeup in vm_waitpfault() does not mean that the thread would get the page on the next vm_page_alloc() call, other thread might steal the free page we were waiting for. On the other hand, this wakeup might come much earlier than just vm_pfault_oom_wait seconds, if the rate of the page reclamation is high enough. If wakeups come fast and we loose the allocation race enough times, OOM could be undeservably triggered much earlier than vm_pfault_oom_attempts x vm_pfault_oom_wait seconds. Fix it by not counting the number of sleeps, but measuring the time to th first allocation failure, and triggering OOM when it was older than oom_attempts x oom_wait seconds. Reviewed by: markj Tested by: pho Sponsored by: The FreeBSD Foundation MFC after: 2 weeks Differential revision: https://reviews.freebsd.org/D32287
This commit is contained in:
parent
7e64580b5f
commit
174aad047e
@ -125,7 +125,8 @@ struct faultstate {
|
|||||||
vm_prot_t fault_type;
|
vm_prot_t fault_type;
|
||||||
vm_prot_t prot;
|
vm_prot_t prot;
|
||||||
int fault_flags;
|
int fault_flags;
|
||||||
int oom;
|
struct timeval oom_start_time;
|
||||||
|
bool oom_started;
|
||||||
boolean_t wired;
|
boolean_t wired;
|
||||||
|
|
||||||
/* Page reference for cow. */
|
/* Page reference for cow. */
|
||||||
@ -1073,6 +1074,38 @@ vm_fault_zerofill(struct faultstate *fs)
|
|||||||
vm_page_valid(fs->m);
|
vm_page_valid(fs->m);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Initiate page fault after timeout. Returns true if caller should
|
||||||
|
* do vm_waitpfault() after the call.
|
||||||
|
*/
|
||||||
|
static bool
|
||||||
|
vm_fault_allocate_oom(struct faultstate *fs)
|
||||||
|
{
|
||||||
|
struct timeval now;
|
||||||
|
|
||||||
|
unlock_and_deallocate(fs);
|
||||||
|
if (vm_pfault_oom_attempts < 0)
|
||||||
|
return (true);
|
||||||
|
if (!fs->oom_started) {
|
||||||
|
fs->oom_started = true;
|
||||||
|
getmicrotime(&fs->oom_start_time);
|
||||||
|
return (true);
|
||||||
|
}
|
||||||
|
|
||||||
|
getmicrotime(&now);
|
||||||
|
timevalsub(&now, &fs->oom_start_time);
|
||||||
|
if (now.tv_sec < vm_pfault_oom_attempts * vm_pfault_oom_wait)
|
||||||
|
return (true);
|
||||||
|
|
||||||
|
if (bootverbose)
|
||||||
|
printf(
|
||||||
|
"proc %d (%s) failed to alloc page on fault, starting OOM\n",
|
||||||
|
curproc->p_pid, curproc->p_comm);
|
||||||
|
vm_pageout_oom(VM_OOM_MEM_PF);
|
||||||
|
fs->oom_started = false;
|
||||||
|
return (false);
|
||||||
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Allocate a page directly or via the object populate method.
|
* Allocate a page directly or via the object populate method.
|
||||||
*/
|
*/
|
||||||
@ -1136,22 +1169,11 @@ vm_fault_allocate(struct faultstate *fs)
|
|||||||
fs->m = vm_page_alloc(fs->object, fs->pindex, alloc_req);
|
fs->m = vm_page_alloc(fs->object, fs->pindex, alloc_req);
|
||||||
}
|
}
|
||||||
if (fs->m == NULL) {
|
if (fs->m == NULL) {
|
||||||
unlock_and_deallocate(fs);
|
if (vm_fault_allocate_oom(fs))
|
||||||
if (vm_pfault_oom_attempts < 0 ||
|
|
||||||
fs->oom < vm_pfault_oom_attempts) {
|
|
||||||
fs->oom++;
|
|
||||||
vm_waitpfault(dset, vm_pfault_oom_wait * hz);
|
vm_waitpfault(dset, vm_pfault_oom_wait * hz);
|
||||||
} else {
|
|
||||||
if (bootverbose)
|
|
||||||
printf(
|
|
||||||
"proc %d (%s) failed to alloc page on fault, starting OOM\n",
|
|
||||||
curproc->p_pid, curproc->p_comm);
|
|
||||||
vm_pageout_oom(VM_OOM_MEM_PF);
|
|
||||||
fs->oom = 0;
|
|
||||||
}
|
|
||||||
return (KERN_RESOURCE_SHORTAGE);
|
return (KERN_RESOURCE_SHORTAGE);
|
||||||
}
|
}
|
||||||
fs->oom = 0;
|
fs->oom_started = false;
|
||||||
|
|
||||||
return (KERN_NOT_RECEIVER);
|
return (KERN_NOT_RECEIVER);
|
||||||
}
|
}
|
||||||
@ -1300,7 +1322,7 @@ vm_fault(vm_map_t map, vm_offset_t vaddr, vm_prot_t fault_type,
|
|||||||
fs.fault_flags = fault_flags;
|
fs.fault_flags = fault_flags;
|
||||||
fs.map = map;
|
fs.map = map;
|
||||||
fs.lookup_still_valid = false;
|
fs.lookup_still_valid = false;
|
||||||
fs.oom = 0;
|
fs.oom_started = false;
|
||||||
faultcount = 0;
|
faultcount = 0;
|
||||||
nera = -1;
|
nera = -1;
|
||||||
hardfault = false;
|
hardfault = false;
|
||||||
|
Loading…
Reference in New Issue
Block a user