Subject: Re: patch for handling out-of-swap conditions
To: Bill Sommerfeld <sommerfeld@orchard.arlington.ma.us>
From: Chuck Silvers <chuq@chuq.com>
List: tech-kern
Date: 02/26/1999 08:09:52
I found the problem... I put one of the new bits in the wrong place
when I applied the diff fragments by hand. I also remembered that
I had an alpha sitting in the corner that would work just fine for
debugging this. I also discovered that most ports don't do the right
thing when uvm_fault returns KERN_RESOURCE_SHORTAGE, so I've put in
the bits for that.
Bill Sommerfeld writes:
> I tried this on a dataless shark with filesystems in NFS, 32meg of
> physical memory and 32meg of swap on a local paging disk; it built ok
> and appears to run ok when not under severe memory pressure.
>
> However, under stress, it still wedges up.
>
> The workload was on the order of 15-20 `xterm -sl 10000' processes,
> each running `cat /usr/share/misc/termcap'.
>
> It quickly got to the point where swap was full, according to pstat
> -s. Things kept running for for several minutes after that. However,
> I wasn't able see any process to die due to swap exhaustion; instead,
> things gradually slowed to a crawl to the point that the system might
> as well be hung. I lost patience and hit the reset button.
>
> I *suspect* what's going on is that the more-agressive page
> deactivation is preferentially chasing all text pages out of core
> (since they're read-only and backed by the text vnode), replacing them
> with dirty data pages which can't be swapped out because there isn't
> any swap space. With text pages in really short supply, apps start
> thrashing like crazy.
that right, that's exactly what happens. the difference that these
patches make is that when *all* of the swap space is used up, the
next (user) page allocation that fails will kill the requesting process.
I set up my test alpha to run diskless with a 1 meg swapfile in nfs,
and my test program was a short thing I wrote that just allocates
anonymous memory with mmap() and modifies all the pages.
it took about 3 seconds to exhaust the miniscule swap area
and then the process was killed.
swapping to nfs has big problems... I got various hangs and panics
due to nfs not being able to keep up. at first it was working ok
but eventually I had to put a delay in my test program to avoid
the nfs problems. not sure why these problems didn't show up initially.
anyway, here's the fixed patch.
-Chuck
Index: arch/alpha/alpha/trap.c
===================================================================
RCS file: /cvsroot/src/sys/arch/alpha/alpha/trap.c,v
retrieving revision 1.40
diff -u -r1.40 trap.c
--- trap.c 1999/02/23 03:20:03 1.40
+++ trap.c 1999/02/26 16:01:28
@@ -468,10 +468,15 @@
goto dopanic;
}
ucode = a0;
- i = SIGSEGV;
-#ifdef DEBUG
- printtrap(a0, a1, a2, entry, framep, 1, user);
-#endif
+ if (rv == KERN_RESOURCE_SHORTAGE) {
+ printf("UVM: pid %d (%s), uid %d killed: "
+ "out of swap\n", p->p_pid, p->p_comm,
+ p->p_cred && p->p_ucred ?
+ p->p_ucred->cr_uid : -1);
+ i = SIGKILL;
+ } else {
+ i = SIGSEGV;
+ }
break;
}
Index: arch/amiga/amiga/trap.c
===================================================================
RCS file: /cvsroot/src/sys/arch/amiga/amiga/trap.c,v
retrieving revision 1.67
diff -u -r1.67 trap.c
--- trap.c 1998/12/15 19:36:36 1.67
+++ trap.c 1999/02/26 16:01:28
@@ -542,7 +542,14 @@
type, code);
panictrap(type, code, v, fp);
}
- trapsignal(p, SIGSEGV, v);
+ if (rv == KERN_RESOURCE_SHORTAGE) {
+ printf("UVM: pid %d (%s), uid %d killed: out of swap\n",
+ p->p_pid, p->p_comm,
+ p->p_cred && p->p_ucred ? p->p_ucred->cr_uid : -1);
+ trapsignal(p, SIGKILL, v);
+ } else {
+ trapsignal(p, SIGSEGV, v);
+ }
if ((type & T_USER) == 0)
return;
userret(p, fp->f_pc, sticks);
Index: arch/arm32/arm32/fault.c
===================================================================
RCS file: /cvsroot/src/sys/arch/arm32/arm32/fault.c,v
retrieving revision 1.36
diff -u -r1.36 fault.c
--- fault.c 1999/02/19 22:32:21 1.36
+++ fault.c 1999/02/26 16:01:28
@@ -455,7 +455,15 @@
goto out;
report_abort("", fault_status, fault_address, fault_pc);
- trapsignal(p, SIGSEGV, TRAP_CODE);
+ if (rv = KERN_RESOURCE_SHORTAGE) {
+ printf("UVM: pid %d (%s), uid %d killed: "
+ "out of swap\n", p->p_pid, p->p_comm,
+ p->p_cred && p->p_ucred ?
+ p->p_ucred->cr_uid : -1);
+ trapsignal(p, SIGKILL, TRAP_CODE);
+ } else {
+ trapsignal(p, SIGSEGV, TRAP_CODE);
+ }
break;
}
break;
Index: arch/atari/atari/trap.c
===================================================================
RCS file: /cvsroot/src/sys/arch/atari/atari/trap.c,v
retrieving revision 1.39
diff -u -r1.39 trap.c
--- trap.c 1998/12/15 19:36:58 1.39
+++ trap.c 1999/02/26 16:01:29
@@ -690,7 +690,15 @@
panictrap(type, code, v, &frame);
}
ucode = v;
- i = SIGSEGV;
+ if (rv == KERN_RESOURCE_SHORTAGE) {
+ printf("UVM: pid %d (%s), uid %d killed: out of swap\n",
+ p->p_pid, p->p_comm,
+ p->p_cred && p->p_ucred ?
+ p->p_ucred->cr_uid : -1);
+ i = SIGKILL;
+ } else {
+ i = SIGSEGV;
+ }
break;
}
}
Index: arch/hp300/hp300/trap.c
===================================================================
RCS file: /cvsroot/src/sys/arch/hp300/hp300/trap.c,v
retrieving revision 1.68
diff -u -r1.68 trap.c
--- trap.c 1998/12/15 19:37:01 1.68
+++ trap.c 1999/02/26 16:01:30
@@ -704,7 +704,15 @@
goto dopanic;
}
ucode = v;
- i = SIGSEGV;
+ if (rv == KERN_RESOURCE_SHORTAGE) {
+ printf("UVM: pid %d (%s), uid %d killed: out of swap\n",
+ p->p_pid, p->p_comm,
+ p->p_cred && p->p_ucred ?
+ p->p_ucred->cr_uid : -1);
+ i = SIGKILL;
+ } else {
+ i = SIGSEGV;
+ }
break;
}
}
Index: arch/i386/i386/trap.c
===================================================================
RCS file: /cvsroot/src/sys/arch/i386/i386/trap.c,v
retrieving revision 1.129
diff -u -r1.129 trap.c
--- trap.c 1999/02/13 16:10:44 1.129
+++ trap.c 1999/02/26 16:01:30
@@ -553,8 +553,10 @@
goto we_re_toast;
}
if (rv == KERN_RESOURCE_SHORTAGE) {
- printf("UVM: process %d killed: out of swap space\n",
- p->p_pid);
+ printf("UVM: pid %d (%s), uid %d killed: out of swap\n",
+ p->p_pid, p->p_comm,
+ p->p_cred && p->p_ucred ?
+ p->p_ucred->cr_uid : -1);
trapsignal(p, SIGKILL, T_PAGEFLT);
} else {
trapsignal(p, SIGSEGV, T_PAGEFLT);
Index: arch/mac68k/mac68k/trap.c
===================================================================
RCS file: /cvsroot/src/sys/arch/mac68k/mac68k/trap.c,v
retrieving revision 1.68
diff -u -r1.68 trap.c
--- trap.c 1998/12/22 08:47:07 1.68
+++ trap.c 1999/02/26 16:01:31
@@ -692,7 +692,15 @@
goto dopanic;
}
ucode = v;
- i = SIGSEGV;
+ if (rv == KERN_RESOURCE_SHORTAGE) {
+ printf("UVM: pid %d (%s), uid %d killed: out of swap\n",
+ p->p_pid, p->p_comm,
+ p->p_cred && p->p_ucred ?
+ p->p_ucred->cr_uid : -1);
+ i = SIGKILL;
+ } else {
+ i = SIGSEGV;
+ }
break;
}
}
Index: arch/mips/mips/trap.c
===================================================================
RCS file: /cvsroot/src/sys/arch/mips/mips/trap.c,v
retrieving revision 1.102
diff -u -r1.102 trap.c
--- trap.c 1999/01/29 02:18:42 1.102
+++ trap.c 1999/02/26 16:01:32
@@ -591,7 +591,16 @@
}
if ((type & T_USER) == 0)
goto copyfault;
- sig = (rv == KERN_PROTECTION_FAILURE) ? SIGBUS : SIGSEGV;
+ if (rv == KERN_RESOURCE_SHORTAGE) {
+ printf("UVM: pid %d (%s), uid %d killed: out of swap\n",
+ p->p_pid, p->p_comm,
+ p->p_cred && p->p_ucred ?
+ p->p_ucred->cr_uid : -1);
+ sig = SIGKILL;
+ } else {
+ sig = (rv == KERN_PROTECTION_FAILURE) ?
+ SIGBUS : SIGSEGV;
+ }
ucode = vaddr;
break; /* SIGNAL */
}
Index: arch/mvme68k/mvme68k/trap.c
===================================================================
RCS file: /cvsroot/src/sys/arch/mvme68k/mvme68k/trap.c,v
retrieving revision 1.27
diff -u -r1.27 trap.c
--- trap.c 1999/02/14 17:54:30 1.27
+++ trap.c 1999/02/26 16:01:32
@@ -697,7 +697,15 @@
goto dopanic;
}
ucode = v;
- i = SIGSEGV;
+ if (rv == KERN_RESOURCE_SHORTAGE) {
+ printf("UVM: pid %d (%s), uid %d killed: out of swap\n",
+ p->p_pid, p->p_comm,
+ p->p_cred && p->p_ucred ?
+ p->p_ucred->cr_uid : -1);
+ i = SIGKILL;
+ } else {
+ i = SIGSEGV;
+ }
break;
}
}
Index: arch/next68k/next68k/trap.c
===================================================================
RCS file: /cvsroot/src/sys/arch/next68k/next68k/trap.c,v
retrieving revision 1.10
diff -u -r1.10 trap.c
--- trap.c 1999/01/13 09:26:00 1.10
+++ trap.c 1999/02/26 16:01:32
@@ -641,7 +641,15 @@
goto dopanic;
}
ucode = v;
- i = SIGSEGV;
+ if (rv == KERN_RESOURCE_SHORTAGE) {
+ printf("UVM: pid %d (%s), uid %d killed: out of swap\n",
+ p->p_pid, p->p_comm,
+ p->p_cred && p->p_ucred ?
+ p->p_ucred->cr_uid : -1);
+ i = SIGKILL;
+ } else {
+ i = SIGSEGV;
+ }
break;
}
}
Index: arch/pc532/pc532/trap.c
===================================================================
RCS file: /cvsroot/src/sys/arch/pc532/pc532/trap.c,v
retrieving revision 1.33
diff -u -r1.33 trap.c
--- trap.c 1998/11/11 06:43:50 1.33
+++ trap.c 1999/02/26 16:01:34
@@ -486,8 +486,10 @@
goto we_re_toast;
}
if (rv == KERN_RESOURCE_SHORTAGE) {
- printf("UVM: process %d killed: out of swap space\n",
- p->p_pid);
+ printf("UVM: pid %d (%s), uid %d killed: out of swap\n",
+ p->p_pid, p->p_comm,
+ p->p_cred && p->p_ucred ?
+ p->p_ucred->cr_uid : -1);
trapsignal(p, SIGKILL, T_ABT);
} else {
trapsignal(p, SIGSEGV, T_ABT);
Index: arch/pica/pica/trap.c
===================================================================
RCS file: /cvsroot/src/sys/arch/pica/pica/trap.c,v
retrieving revision 1.14
diff -u -r1.14 trap.c
--- trap.c 1998/07/05 06:49:08 1.14
+++ trap.c 1999/02/26 16:01:34
@@ -558,7 +558,15 @@
goto err;
}
ucode = vadr;
- i = SIGSEGV;
+ if (rv == KERN_RESOURCE_SHORTAGE) {
+ printf("UVM: pid %d (%s), uid %d killed: out of swap\n",
+ p->p_pid, p->p_comm,
+ p->p_cred && p->p_ucred ?
+ p->p_ucred->cr_uid : -1);
+ i = SIGKILL;
+ } else {
+ i = SIGSEGV;
+ }
break;
}
Index: arch/powerpc/powerpc/trap.c
===================================================================
RCS file: /cvsroot/src/sys/arch/powerpc/powerpc/trap.c,v
retrieving revision 1.15
diff -u -r1.15 trap.c
--- trap.c 1999/01/10 10:24:17 1.15
+++ trap.c 1999/02/26 16:01:34
@@ -145,7 +145,15 @@
break;
#endif
}
- trapsignal(p, SIGSEGV, EXC_DSI);
+ if (rv == KERN_RESOURCE_SHORTAGE) {
+ printf("UVM: pid %d (%s), uid %d killed: out of swap\n",
+ p->p_pid, p->p_comm,
+ p->p_cred && p->p_ucred ?
+ p->p_ucred->cr_uid : -1);
+ trapsignal(p, SIGKILL, EXC_DSI);
+ } else {
+ trapsignal(p, SIGSEGV, EXC_DSI);
+ }
break;
case EXC_ISI|EXC_USER:
{
Index: arch/sparc/sparc/trap.c
===================================================================
RCS file: /cvsroot/src/sys/arch/sparc/sparc/trap.c,v
retrieving revision 1.81
diff -u -r1.81 trap.c
--- trap.c 1999/02/23 06:47:05 1.81
+++ trap.c 1999/02/26 16:01:34
@@ -847,8 +847,10 @@
return;
}
if (rv == KERN_RESOURCE_SHORTAGE) {
- printf("UVM: process %d killed: out of swap space\n",
- p->p_pid);
+ printf("UVM: pid %d (%s), uid %d killed: out of swap\n",
+ p->p_pid, p->p_comm,
+ p->p_cred && p->p_ucred ?
+ p->p_ucred->cr_uid : -1);
trapsignal(p, SIGKILL, (u_int)v);
} else
trapsignal(p, SIGSEGV, (u_int)v);
Index: arch/sparc64/sparc64/trap.c
===================================================================
RCS file: /cvsroot/src/sys/arch/sparc64/sparc64/trap.c,v
retrieving revision 1.22
diff -u -r1.22 trap.c
--- trap.c 1999/01/31 09:21:19 1.22
+++ trap.c 1999/02/26 16:01:44
@@ -1146,7 +1146,15 @@
Debugger();
}
#endif
- trapsignal(p, SIGSEGV, (u_long)addr);
+ if (rv == KERN_RESOURCE_SHORTAGE) {
+ printf("UVM: pid %d (%s), uid %d killed: out of swap\n",
+ p->p_pid, p->p_comm,
+ p->p_cred && p->p_ucred ?
+ p->p_ucred->cr_uid : -1);
+ trapsignal(p, SIGKILL, (u_long)addr);
+ } else {
+ trapsignal(p, SIGSEGV, (u_long)addr);
+ }
}
if ((tstate & TSTATE_PRIV) == 0) {
userret(p, pc, sticks);
Index: arch/sun3/sun3/trap.c
===================================================================
RCS file: /cvsroot/src/sys/arch/sun3/sun3/trap.c,v
retrieving revision 1.83
diff -u -r1.83 trap.c
--- trap.c 1998/12/15 19:37:12 1.83
+++ trap.c 1999/02/26 16:01:44
@@ -575,7 +575,15 @@
goto dopanic;
}
ucode = v;
- sig = SIGSEGV;
+ if (rv == KERN_RESOURCE_SHORTAGE) {
+ printf("UVM: pid %d (%s), uid %d killed: out of swap\n",
+ p->p_pid, p->p_comm,
+ p->p_cred && p->p_ucred ?
+ p->p_ucred->cr_uid : -1);
+ sig = SIGKILL;
+ } else {
+ sig = SIGSEGV;
+ }
break;
} /* T_MMUFLT */
} /* switch */
Index: arch/vax/vax/trap.c
===================================================================
RCS file: /cvsroot/src/sys/arch/vax/vax/trap.c,v
retrieving revision 1.41
diff -u -r1.41 trap.c
--- trap.c 1999/01/19 21:04:49 1.41
+++ trap.c 1999/02/26 16:01:44
@@ -226,10 +226,16 @@
panic("Segv in kernel mode: pc %x addr %x",
(u_int)frame->pc, (u_int)frame->code);
}
-ufault: if (rv == KERN_RESOURCE_SHORTAGE)
- printf("Pid %d killed: out of memory.\n",
- p->p_pid);
- sig = SIGSEGV;
+ufault: if (rv == KERN_RESOURCE_SHORTAGE) {
+ printf("UVM: pid %d (%s), uid %d killed: "
+ "out of swap\n",
+ p->p_pid, p->p_comm,
+ p->p_cred && p->p_ucred ?
+ p->p_ucred->cr_uid : -1);
+ sig = SIGKILL;
+ } else {
+ sig = SIGSEGV;
+ }
} else
trapsig = 0;
break;
Index: arch/x68k/x68k/trap.c
===================================================================
RCS file: /cvsroot/src/sys/arch/x68k/x68k/trap.c,v
retrieving revision 1.26
diff -u -r1.26 trap.c
--- trap.c 1998/12/15 19:37:17 1.26
+++ trap.c 1999/02/26 16:01:44
@@ -727,7 +727,15 @@
goto dopanic;
}
ucode = v;
- i = SIGSEGV;
+ if (rv == KERN_RESOURCE_SHORTAGE) {
+ printf("UVM: pid %d (%s), uid %d killed: out of swap\n",
+ p->p_pid, p->p_comm,
+ p->p_cred && p->p_ucred ?
+ p->p_ucred->cr_uid : -1);
+ i = SIGKILL;
+ } else {
+ i = SIGSEGV;
+ }
break;
}
}
Index: uvm/uvm_anon.c
===================================================================
RCS file: /cvsroot/src/sys/uvm/uvm_anon.c,v
retrieving revision 1.1
diff -u -r1.1 uvm_anon.c
--- uvm_anon.c 1999/01/24 23:53:15 1.1
+++ uvm_anon.c 1999/02/26 16:01:48
@@ -235,6 +235,11 @@
anon, anon->an_swslot, 0, 0);
uvm_swap_free(anon->an_swslot, 1);
anon->an_swslot = 0;
+
+ if (pg == NULL) {
+ /* this page is no longer only in swap. */
+ uvmexp.swpguniq--;
+ }
}
/*
Index: uvm/uvm_aobj.c
===================================================================
RCS file: /cvsroot/src/sys/uvm/uvm_aobj.c,v
retrieving revision 1.15
diff -u -r1.15 uvm_aobj.c
--- uvm_aobj.c 1998/10/18 23:49:59 1.15
+++ uvm_aobj.c 1999/02/26 16:01:48
@@ -428,8 +428,15 @@
{
int slot = elt->slots[j];
- if (slot)
+ if (slot) {
uvm_swap_free(slot, 1);
+
+ /*
+ * this page is no longer
+ * only in swap.
+ */
+ uvmexp.swpguniq--;
+ }
}
next = elt->list.le_next;
@@ -448,8 +455,12 @@
{
int slot = aobj->u_swslots[i];
- if (slot)
+ if (slot) {
uvm_swap_free(slot, 1);
+
+ /* this page is no longer only in swap. */
+ uvmexp.swpguniq--;
+ }
}
FREE(aobj->u_swslots, M_UVMAOBJ);
}
Index: uvm/uvm_extern.h
===================================================================
RCS file: /cvsroot/src/sys/uvm/uvm_extern.h,v
retrieving revision 1.21
diff -u -r1.21 uvm_extern.h
--- uvm_extern.h 1998/09/08 23:44:21 1.21
+++ uvm_extern.h 1999/02/26 16:01:48
@@ -181,6 +181,7 @@
int nswapdev; /* number of configured swap devices in system */
int swpages; /* number of PAGE_SIZE'ed swap pages */
int swpginuse; /* number of swap pages in use */
+ int swpguniq; /* number of swap pages in use, not also in RAM */
int nswget; /* number of times fault calls uvm_swap_get() */
int nanon; /* number total of anon's in system */
int nfreeanon; /* number of free anon's */
Index: uvm/uvm_fault.c
===================================================================
RCS file: /cvsroot/src/sys/uvm/uvm_fault.c,v
retrieving revision 1.20
diff -u -r1.20 uvm_fault.c
--- uvm_fault.c 1999/01/31 09:27:18 1.20
+++ uvm_fault.c 1999/02/26 16:01:48
@@ -1150,13 +1150,15 @@
if (anon)
uvm_anfree(anon);
uvmfault_unlockall(&ufi, amap, uobj, oanon);
- if (anon == NULL) {
+
+ if (anon == NULL || uvmexp.swpages == uvmexp.swpguniq) {
UVMHIST_LOG(maphist,
"<- failed. out of VM",0,0,0,0);
uvmexp.fltnoanon++;
/* XXX: OUT OF VM, ??? */
return (KERN_RESOURCE_SHORTAGE);
}
+
uvmexp.fltnoram++;
uvm_wait("flt_noram3"); /* out of RAM, wait for more */
goto ReFault;
@@ -1542,13 +1544,15 @@
/* unlock and fail ... */
uvmfault_unlockall(&ufi, amap, uobj, NULL);
- if (anon == NULL) {
+
+ if (anon == NULL || uvmexp.swpages == uvmexp.swpguniq) {
UVMHIST_LOG(maphist, " promote: out of VM",
0,0,0,0);
uvmexp.fltnoanon++;
/* XXX: out of VM */
return (KERN_RESOURCE_SHORTAGE);
}
+
UVMHIST_LOG(maphist, " out of RAM, waiting for more",
0,0,0,0);
uvm_anfree(anon);
Index: uvm/uvm_pdaemon.c
===================================================================
RCS file: /cvsroot/src/sys/uvm/uvm_pdaemon.c,v
retrieving revision 1.12
diff -u -r1.12 uvm_pdaemon.c
--- uvm_pdaemon.c 1998/11/04 07:06:05 1.12
+++ uvm_pdaemon.c 1999/02/26 16:01:49
@@ -481,6 +481,11 @@
*/
if (p->flags & PG_CLEAN) {
+ if (p->pqflags & PQ_SWAPBACKED) {
+ /* this page now lives only in swap */
+ uvmexp.swpguniq++;
+ }
+
/* zap all mappings with pmap_page_protect... */
pmap_page_protect(PMAP_PGARG(p), VM_PROT_NONE);
uvm_pagefree(p);
@@ -880,7 +885,7 @@
void
uvmpd_scan()
{
- int s, free, pages_freed, page_shortage;
+ int s, free, inactive_shortage, swap_shortage;
struct vm_page *p, *nextpg;
struct uvm_object *uobj;
boolean_t got_it;
@@ -926,7 +931,6 @@
*/
UVMHIST_LOG(pdhist, " starting 'free' loop",0,0,0,0);
- pages_freed = uvmexp.pdfreed; /* so far... */
/*
* do loop #1! alternate starting queue between swap and object based
@@ -943,24 +947,43 @@
/*
* we have done the scan to get free pages. now we work on meeting
- * our inactive target.
+ * our inactive target. if we are still below the free target
+ * and we didn't start any pageouts in the inactive scan above
+ * (perhaps because we're out of swap space) and we've met
+ * the inactive target, then go ahead and deactivate some more
+ * pages anyway. meeting the free target is important enough
+ * that it's worth temporarily reducing the number of active pages.
*/
+
+ inactive_shortage = uvmexp.inactarg - uvmexp.inactive;
+ if (free < uvmexp.freetarg && inactive_shortage <= 0 &&
+ uvmexp.paging == 0) {
+ inactive_shortage = 16;
+ }
- page_shortage = uvmexp.inactarg - uvmexp.inactive;
- pages_freed = uvmexp.pdfreed - pages_freed; /* # pages freed in loop */
- if (page_shortage <= 0 && pages_freed == 0)
- page_shortage = 1;
-
- UVMHIST_LOG(pdhist, " second loop: page_shortage=%d", page_shortage,
- 0, 0, 0);
- for (p = uvm.page_active.tqh_first ;
- p != NULL && page_shortage > 0 ; p = nextpg) {
+ /*
+ * detect if we're not going to be able to page anything out
+ * until we free some swap resources from active pages.
+ */
+ swap_shortage = 0;
+ if (uvmexp.free < uvmexp.freetarg &&
+ uvmexp.swpginuse == uvmexp.swpages &&
+ uvmexp.swpguniq < uvmexp.swpages &&
+ uvmexp.paging == 0) {
+ swap_shortage = uvmexp.freetarg - uvmexp.free;
+ }
+
+ UVMHIST_LOG(pdhist, " loop 2: inactive_shortage=%d swap_shortage=%d",
+ inactive_shortage, swap_shortage,0,0);
+ for (p = TAILQ_FIRST(&uvm.page_active);
+ p != NULL && (inactive_shortage > 0 || swap_shortage > 0);
+ p = nextpg) {
nextpg = p->pageq.tqe_next;
if (p->flags & PG_BUSY)
continue; /* quick check before trying to lock */
/*
- * lock owner
+ * lock the page's owner.
*/
/* is page anon owned or ownerless? */
if ((p->pqflags & PQ_ANON) || p->uobject == NULL) {
@@ -970,36 +993,66 @@
panic("pagedaemon: page with no anon or "
"object detected - loop 2");
#endif
-
if (!simple_lock_try(&p->uanon->an_lock))
continue;
/* take over the page? */
if ((p->pqflags & PQ_ANON) == 0) {
-
#ifdef DIAGNOSTIC
if (p->loan_count < 1)
panic("pagedaemon: non-loaned "
"ownerless page detected - loop 2");
#endif
-
p->loan_count--;
p->pqflags |= PQ_ANON;
}
-
} else {
-
if (!simple_lock_try(&p->uobject->vmobjlock))
continue;
-
}
-
- if ((p->flags & PG_BUSY) == 0) {
+ /*
+ * skip this page if it's busy.
+ */
+ if ((p->flags & PG_BUSY) != 0) {
+ if (p->pqflags & PQ_ANON)
+ simple_unlock(&p->uanon->an_lock);
+ else
+ simple_unlock(&p->uobject->vmobjlock);
+ continue;
+ }
+
+ /*
+ * free any swap allocated to this page
+ * if there's a shortage of swap.
+ */
+ if (swap_shortage > 0) {
+ if (p->pqflags & PQ_ANON && p->uanon->an_swslot) {
+ uvm_swap_free(p->uanon->an_swslot, 1);
+ p->uanon->an_swslot = 0;
+ p->flags &= ~PG_CLEAN;
+ swap_shortage--;
+ }
+ if (p->pqflags & PQ_AOBJ) {
+ int slot = uao_set_swslot(p->uobject,
+ p->offset >> PAGE_SHIFT, 0);
+ if (slot) {
+ uvm_swap_free(slot, 1);
+ p->flags &= ~PG_CLEAN;
+ swap_shortage--;
+ }
+ }
+ }
+
+ /*
+ * deactivate this page if there's a shortage of
+ * inactive pages.
+ */
+ if (inactive_shortage > 0) {
pmap_page_protect(PMAP_PGARG(p), VM_PROT_NONE);
/* no need to check wire_count as pg is "active" */
uvm_pagedeactivate(p);
uvmexp.pddeact++;
- page_shortage--;
+ inactive_shortage--;
}
if (p->pqflags & PQ_ANON)
@@ -1007,8 +1060,4 @@
else
simple_unlock(&p->uobject->vmobjlock);
}
-
- /*
- * done scan
- */
}