so all allocators obey it, not just uvm_pagealloc (which is increasingly
rarely called). This actually makes it a lot harder to deadlock the
machine under very heavy memory pressure (uvm_pglistalloc for 7 pages
when you have 7 pages left, for example).
I have been using variants of this diff on my machines for months.
I have discussed doing this with ariane@ many many times. here's the
diff:
ok?
-0-
Index: uvm/uvm_page.c
===================================================================
RCS file: /cvs/src/sys/uvm/uvm_page.c,v
retrieving revision 1.111
diff -u -p -r1.111 uvm_page.c
--- uvm/uvm_page.c 3 Jul 2011 18:34:14 -0000 1.111
+++ uvm/uvm_page.c 3 Jul 2011 20:14:37 -0000
@@ -76,7 +76,6 @@
#include <sys/sched.h>
#include <sys/kernel.h>
#include <sys/vnode.h>
-#include <sys/mount.h>
#include <sys/proc.h>
#include <uvm/uvm.h>
@@ -885,43 +884,19 @@ uvm_pagealloc(struct uvm_object *obj, vo
struct vm_page *pg;
struct pglist pgl;
int pmr_flags;
- boolean_t use_reserve;
KASSERT(obj == NULL || anon == NULL);
KASSERT(off == trunc_page(off));
- /*
- * check to see if we need to generate some free pages waking
- * the pagedaemon.
- */
- if ((uvmexp.free - BUFPAGES_DEFICIT) < uvmexp.freemin ||
- ((uvmexp.free - BUFPAGES_DEFICIT) < uvmexp.freetarg &&
- (uvmexp.inactive + BUFPAGES_INACT) < uvmexp.inactarg))
- wakeup(&uvm.pagedaemon);
-
- /*
- * fail if any of these conditions is true:
- * [1] there really are no free pages, or
- * [2] only kernel "reserved" pages remain and
- * the page isn't being allocated to a kernel object.
- * [3] only pagedaemon "reserved" pages remain and
- * the requestor isn't the pagedaemon.
- */
-
- use_reserve = (flags & UVM_PGA_USERESERVE) ||
- (obj && UVM_OBJ_IS_KERN_OBJECT(obj));
- if ((uvmexp.free <= uvmexp.reserve_kernel && !use_reserve) ||
- (uvmexp.free <= uvmexp.reserve_pagedaemon &&
- !((curproc == uvm.pagedaemon_proc) ||
- (curproc == syncerproc))))
- goto fail;
-
+ /* XXX these functions should share flags */
pmr_flags = UVM_PLA_NOWAIT;
if (flags & UVM_PGA_ZERO)
pmr_flags |= UVM_PLA_ZERO;
+ if (flags & UVM_PGA_USERESERVE)
+ pmr_flags |= UVM_PLA_USERESERVE;
TAILQ_INIT(&pgl);
if (uvm_pmr_getpages(1, 0, 0, 1, 0, 1, pmr_flags, &pgl) != 0)
- goto fail;
+ return (NULL);
pg = TAILQ_FIRST(&pgl);
KASSERT(pg != NULL && TAILQ_NEXT(pg, pageq) == NULL);
@@ -932,10 +907,7 @@ uvm_pagealloc(struct uvm_object *obj, vo
if (flags & UVM_PGA_ZERO)
atomic_clearbits_int(&pg->pg_flags, PG_CLEAN);
- return(pg);
-
- fail:
- return (NULL);
+ return (pg);
}
/*
Index: uvm/uvm_pmemrange.c
===================================================================
RCS file: /cvs/src/sys/uvm/uvm_pmemrange.c,v
retrieving revision 1.25
diff -u -p -r1.25 uvm_pmemrange.c
--- uvm/uvm_pmemrange.c 22 Jun 2011 00:16:47 -0000 1.25
+++ uvm/uvm_pmemrange.c 3 Jul 2011 20:14:37 -0000
@@ -19,6 +19,7 @@
#include <sys/param.h>
#include <uvm/uvm.h>
#include <sys/malloc.h>
+#include <sys/mount.h> /* for BUFPAGES defines */
#include <sys/proc.h> /* XXX for atomic */
/*
@@ -747,6 +748,7 @@ uvm_pmr_getpages(psize_t count, paddr_t
int memtype; /* Requested memtype. */
int memtype_init; /* Best memtype. */
int desperate; /* True if allocation failed. */
+ int is_pdaemon;
#ifdef DIAGNOSTIC
struct vm_page *diag_prev; /* Used during validation. */
#endif /* DIAGNOSTIC */
@@ -762,6 +764,27 @@ uvm_pmr_getpages(psize_t count, paddr_t
(boundary == 0 || maxseg * boundary >= count) &&
TAILQ_EMPTY(result));
+ is_pdaemon = ((curproc == uvm.pagedaemon_proc) ||
+ (curproc == syncerproc));
+
+ /*
+ * All allocations by the pagedaemon automatically get access to
+ * the kernel reserve of pages so swapping can catch up with memory
+ * exhaustion
+ */
+ if (is_pdaemon)
+ flags |= UVM_PLA_USERESERVE;
+
+ /*
+ * check to see if we need to generate some free pages waking
+ * the pagedaemon.
+ */
+ if ((uvmexp.free - BUFPAGES_DEFICIT) < uvmexp.freemin ||
+ ((uvmexp.free - BUFPAGES_DEFICIT) < uvmexp.freetarg &&
+ (uvmexp.inactive + BUFPAGES_INACT) < uvmexp.inactarg))
+ wakeup(&uvm.pagedaemon);
+
+
/*
* TRYCONTIG is a noop if you only want a single segment.
* Remove it if that's the case: otherwise it'll deny the fast
@@ -835,6 +858,20 @@ retry: /* Return point after sleeping.
fnsegs = 0;
uvm_lock_fpageq();
+
+ /*
+ * fail if any of these conditions are true:
+ * [1] there really are no free pages, or
+ * [2] only kernel "reserved" pages remain and
+ * the we are not allowed to use them.
+ * [3] only pagedaemon "reserved" pages remain and
+ * the requestor isn't the pagedaemon.
+ */
+ if (((uvmexp.free - ptoa(count)) <= uvmexp.reserve_kernel &&
+ (flags & UVM_PLA_USERESERVE) == 0) ||
+ ((uvmexp.free -ptoa(count)) <= uvmexp.reserve_pagedaemon &&
+ !is_pdaemon))
+ goto fail;
retry_desperate:
/*
--
He flung himself on his horse and rode madly off in all directions
-- Stephen Leacock