|
@@ -630,6 +630,44 @@ void clear_zonelist_oom(struct zonelist *zonelist, gfp_t gfp_mask)
|
|
spin_unlock(&zone_scan_lock);
|
|
spin_unlock(&zone_scan_lock);
|
|
}
|
|
}
|
|
|
|
|
|
|
|
+/*
|
|
|
|
+ * Try to acquire the oom killer lock for all system zones. Returns zero if a
|
|
|
|
+ * parallel oom killing is taking place, otherwise locks all zones and returns
|
|
|
|
+ * non-zero.
|
|
|
|
+ */
|
|
|
|
+static int try_set_system_oom(void)
|
|
|
|
+{
|
|
|
|
+ struct zone *zone;
|
|
|
|
+ int ret = 1;
|
|
|
|
+
|
|
|
|
+ spin_lock(&zone_scan_lock);
|
|
|
|
+ for_each_populated_zone(zone)
|
|
|
|
+ if (zone_is_oom_locked(zone)) {
|
|
|
|
+ ret = 0;
|
|
|
|
+ goto out;
|
|
|
|
+ }
|
|
|
|
+ for_each_populated_zone(zone)
|
|
|
|
+ zone_set_flag(zone, ZONE_OOM_LOCKED);
|
|
|
|
+out:
|
|
|
|
+ spin_unlock(&zone_scan_lock);
|
|
|
|
+ return ret;
|
|
|
|
+}
|
|
|
|
+
|
|
|
|
+/*
|
|
|
|
+ * Clears ZONE_OOM_LOCKED for all system zones so that failed allocation
|
|
|
|
+ * attempts or page faults may now recall the oom killer, if necessary.
|
|
|
|
+ */
|
|
|
|
+static void clear_system_oom(void)
|
|
|
|
+{
|
|
|
|
+ struct zone *zone;
|
|
|
|
+
|
|
|
|
+ spin_lock(&zone_scan_lock);
|
|
|
|
+ for_each_populated_zone(zone)
|
|
|
|
+ zone_clear_flag(zone, ZONE_OOM_LOCKED);
|
|
|
|
+ spin_unlock(&zone_scan_lock);
|
|
|
|
+}
|
|
|
|
+
|
|
|
|
+
|
|
/*
|
|
/*
|
|
* Must be called with tasklist_lock held for read.
|
|
* Must be called with tasklist_lock held for read.
|
|
*/
|
|
*/
|
|
@@ -665,33 +703,6 @@ retry:
|
|
goto retry;
|
|
goto retry;
|
|
}
|
|
}
|
|
|
|
|
|
-/*
|
|
|
|
- * pagefault handler calls into here because it is out of memory but
|
|
|
|
- * doesn't know exactly how or why.
|
|
|
|
- */
|
|
|
|
-void pagefault_out_of_memory(void)
|
|
|
|
-{
|
|
|
|
- unsigned long freed = 0;
|
|
|
|
-
|
|
|
|
- blocking_notifier_call_chain(&oom_notify_list, 0, &freed);
|
|
|
|
- if (freed > 0)
|
|
|
|
- /* Got some memory back in the last second. */
|
|
|
|
- return;
|
|
|
|
-
|
|
|
|
- check_panic_on_oom(CONSTRAINT_NONE, 0, 0);
|
|
|
|
- read_lock(&tasklist_lock);
|
|
|
|
- /* unknown gfp_mask and order */
|
|
|
|
- __out_of_memory(0, 0, CONSTRAINT_NONE, NULL);
|
|
|
|
- read_unlock(&tasklist_lock);
|
|
|
|
-
|
|
|
|
- /*
|
|
|
|
- * Give "p" a good chance of killing itself before we
|
|
|
|
- * retry to allocate memory.
|
|
|
|
- */
|
|
|
|
- if (!test_thread_flag(TIF_MEMDIE))
|
|
|
|
- schedule_timeout_uninterruptible(1);
|
|
|
|
-}
|
|
|
|
-
|
|
|
|
/**
|
|
/**
|
|
* out_of_memory - kill the "best" process when we run out of memory
|
|
* out_of_memory - kill the "best" process when we run out of memory
|
|
* @zonelist: zonelist pointer
|
|
* @zonelist: zonelist pointer
|
|
@@ -708,7 +719,7 @@ void out_of_memory(struct zonelist *zonelist, gfp_t gfp_mask,
|
|
int order, nodemask_t *nodemask)
|
|
int order, nodemask_t *nodemask)
|
|
{
|
|
{
|
|
unsigned long freed = 0;
|
|
unsigned long freed = 0;
|
|
- enum oom_constraint constraint;
|
|
|
|
|
|
+ enum oom_constraint constraint = CONSTRAINT_NONE;
|
|
|
|
|
|
blocking_notifier_call_chain(&oom_notify_list, 0, &freed);
|
|
blocking_notifier_call_chain(&oom_notify_list, 0, &freed);
|
|
if (freed > 0)
|
|
if (freed > 0)
|
|
@@ -729,7 +740,8 @@ void out_of_memory(struct zonelist *zonelist, gfp_t gfp_mask,
|
|
* Check if there were limitations on the allocation (only relevant for
|
|
* Check if there were limitations on the allocation (only relevant for
|
|
* NUMA) that may require different handling.
|
|
* NUMA) that may require different handling.
|
|
*/
|
|
*/
|
|
- constraint = constrained_alloc(zonelist, gfp_mask, nodemask);
|
|
|
|
|
|
+ if (zonelist)
|
|
|
|
+ constraint = constrained_alloc(zonelist, gfp_mask, nodemask);
|
|
check_panic_on_oom(constraint, gfp_mask, order);
|
|
check_panic_on_oom(constraint, gfp_mask, order);
|
|
read_lock(&tasklist_lock);
|
|
read_lock(&tasklist_lock);
|
|
__out_of_memory(gfp_mask, order, constraint, nodemask);
|
|
__out_of_memory(gfp_mask, order, constraint, nodemask);
|
|
@@ -742,3 +754,19 @@ void out_of_memory(struct zonelist *zonelist, gfp_t gfp_mask,
|
|
if (!test_thread_flag(TIF_MEMDIE))
|
|
if (!test_thread_flag(TIF_MEMDIE))
|
|
schedule_timeout_uninterruptible(1);
|
|
schedule_timeout_uninterruptible(1);
|
|
}
|
|
}
|
|
|
|
+
|
|
|
|
+/*
|
|
|
|
+ * The pagefault handler calls here because it is out of memory, so kill a
|
|
|
|
+ * memory-hogging task. If a populated zone has ZONE_OOM_LOCKED set, a parallel
|
|
|
|
+ * oom killing is already in progress so do nothing. If a task is found with
|
|
|
|
+ * TIF_MEMDIE set, it has been killed so do nothing and allow it to exit.
|
|
|
|
+ */
|
|
|
|
+void pagefault_out_of_memory(void)
|
|
|
|
+{
|
|
|
|
+ if (try_set_system_oom()) {
|
|
|
|
+ out_of_memory(NULL, 0, 0, NULL);
|
|
|
|
+ clear_system_oom();
|
|
|
|
+ }
|
|
|
|
+ if (!test_thread_flag(TIF_MEMDIE))
|
|
|
|
+ schedule_timeout_uninterruptible(1);
|
|
|
|
+}
|