Changeset View
Changeset View
Standalone View
Standalone View
sys/vm/vm_pageout.c
Show First 20 Lines • Show All 1,650 Lines • ▼ Show 20 Lines | for (entry = map->header.next; entry != &map->header; | ||||
case OBJT_VNODE: | case OBJT_VNODE: | ||||
res += obj->resident_page_count; | res += obj->resident_page_count; | ||||
break; | break; | ||||
} | } | ||||
} | } | ||||
return (res); | return (res); | ||||
} | } | ||||
static int vm_oom_ratelim_count; | |||||
static int vm_oom_ratelim_last; | |||||
static int vm_oom_pf_secs = 10; | |||||
SYSCTL_INT(_vm, OID_AUTO, oom_pf_secs, CTLFLAG_RWTUN, &vm_oom_pf_secs, 0, | |||||
""); | |||||
static struct mtx vm_oom_ratelim_mtx; | |||||
void | void | ||||
vm_pageout_oom(int shortage) | vm_pageout_oom(int shortage) | ||||
{ | { | ||||
struct proc *p, *bigproc; | struct proc *p, *bigproc; | ||||
vm_offset_t size, bigsize; | vm_offset_t size, bigsize; | ||||
struct thread *td; | struct thread *td; | ||||
struct vmspace *vm; | struct vmspace *vm; | ||||
int now; | |||||
bool breakout; | bool breakout; | ||||
/* | /* | ||||
* For OOM requests originating from vm_fault(), there is a high | |||||
* chance that a single large process faults simultaneously in | |||||
* several threads. Also, on an active system running many | |||||
* processes of middle-size, like buildworld, all of them | |||||
* could fault almost simultaneously as well. | |||||
* | |||||
* To avoid killing too many processes, rate-limit OOMs | |||||
* initiated by vm_fault() time-outs on the waits for free | |||||
* pages. | |||||
*/ | |||||
mtx_lock(&vm_oom_ratelim_mtx); | |||||
now = ticks; | |||||
if ((u_int)(now - vm_oom_ratelim_last) >= hz * vm_oom_pf_secs) { | |||||
vm_oom_ratelim_last = now; | |||||
vm_oom_ratelim_count = 0; | |||||
} else if (vm_oom_ratelim_count++ > 0 && shortage == VM_OOM_MEM_PF) { | |||||
mtx_unlock(&vm_oom_ratelim_mtx); | |||||
return; | |||||
} | |||||
markj: Suppose the page daemon performs the first OOM kill since boot. ratelim_count is set to 0. | |||||
Done Inline ActionsI believe vm_oom_ratelim_count is a leftover from earlier more complicated scheme. I do not see any use of it now: I should remember the time of the last OOM run in vm_oom_ratelim_last always, and for VM_OOM_MEM_PF, compare now with _last. kib: I believe vm_oom_ratelim_count is a leftover from earlier more complicated scheme. I do not… | |||||
mtx_unlock(&vm_oom_ratelim_mtx); | |||||
/* | |||||
* We keep the process bigproc locked once we find it to keep anyone | * We keep the process bigproc locked once we find it to keep anyone | ||||
* from messing with it; however, there is a possibility of | * from messing with it; however, there is a possibility of | ||||
* deadlock if process B is bigproc and one of its child processes | * deadlock if process B is bigproc and one of its child processes | ||||
* attempts to propagate a signal to B while we are waiting for A's | * attempts to propagate a signal to B while we are waiting for A's | ||||
* lock while walking this list. To avoid this, we don't block on | * lock while walking this list. To avoid this, we don't block on | ||||
* the process lock but just skip a process if it is already locked. | * the process lock but just skip a process if it is already locked. | ||||
*/ | */ | ||||
bigproc = NULL; | bigproc = NULL; | ||||
▲ Show 20 Lines • Show All 47 Lines • ▼ Show 20 Lines | FOREACH_PROC_IN_SYSTEM(p) { | ||||
sx_sunlock(&allproc_lock); | sx_sunlock(&allproc_lock); | ||||
if (!vm_map_trylock_read(&vm->vm_map)) { | if (!vm_map_trylock_read(&vm->vm_map)) { | ||||
vmspace_free(vm); | vmspace_free(vm); | ||||
sx_slock(&allproc_lock); | sx_slock(&allproc_lock); | ||||
PRELE(p); | PRELE(p); | ||||
continue; | continue; | ||||
} | } | ||||
size = vmspace_swap_count(vm); | size = vmspace_swap_count(vm); | ||||
if (shortage == VM_OOM_MEM) | if (shortage == VM_OOM_MEM || shortage == VM_OOM_MEM_PF) | ||||
size += vm_pageout_oom_pagecount(vm); | size += vm_pageout_oom_pagecount(vm); | ||||
vm_map_unlock_read(&vm->vm_map); | vm_map_unlock_read(&vm->vm_map); | ||||
vmspace_free(vm); | vmspace_free(vm); | ||||
sx_slock(&allproc_lock); | sx_slock(&allproc_lock); | ||||
/* | /* | ||||
* If this process is bigger than the biggest one, | * If this process is bigger than the biggest one, | ||||
* remember it. | * remember it. | ||||
▲ Show 20 Lines • Show All 200 Lines • ▼ Show 20 Lines | |||||
* vm_pageout is the high level pageout daemon. | * vm_pageout is the high level pageout daemon. | ||||
*/ | */ | ||||
static void | static void | ||||
vm_pageout(void) | vm_pageout(void) | ||||
{ | { | ||||
int error; | int error; | ||||
int i; | int i; | ||||
mtx_init(&vm_oom_ratelim_mtx, "vmoomr", NULL, MTX_DEF); | |||||
swap_pager_swap_init(); | swap_pager_swap_init(); | ||||
snprintf(curthread->td_name, sizeof(curthread->td_name), "dom0"); | snprintf(curthread->td_name, sizeof(curthread->td_name), "dom0"); | ||||
error = kthread_add(vm_pageout_laundry_worker, NULL, curproc, NULL, | error = kthread_add(vm_pageout_laundry_worker, NULL, curproc, NULL, | ||||
0, 0, "laundry: dom0"); | 0, 0, "laundry: dom0"); | ||||
if (error != 0) | if (error != 0) | ||||
panic("starting laundry for domain 0, error %d", error); | panic("starting laundry for domain 0, error %d", error); | ||||
for (i = 1; i < vm_ndomains; i++) { | for (i = 1; i < vm_ndomains; i++) { | ||||
error = kthread_add(vm_pageout_worker, (void *)(uintptr_t)i, | error = kthread_add(vm_pageout_worker, (void *)(uintptr_t)i, | ||||
Show All 39 Lines |
Suppose the page daemon performs the first OOM kill since boot. ratelim_count is set to 0. Suppose a thread attempts a PF OOM kill within vm_oom_pf_secs after the first kill. It will succeed after setting ratelim_count = 1, so multiple OOM kills within the window are permitted. Shouldn't ratelim_count be reset to 1, not 0?