[PATCH] psi oom

From: Johannes Weiner
Date: Mon Aug 05 2019 - 13:15:16 EST


---
include/linux/psi_types.h | 4 +++
kernel/sched/psi.c | 52 +++++++++++++++++++++++++++++++++++++++
2 files changed, 56 insertions(+)

diff --git a/include/linux/psi_types.h b/include/linux/psi_types.h
index 07aaf9b82241..390446b07ac7 100644
--- a/include/linux/psi_types.h
+++ b/include/linux/psi_types.h
@@ -162,6 +162,10 @@ struct psi_group {
u64 polling_total[NR_PSI_STATES - 1];
u64 polling_next_update;
u64 polling_until;
+
+ /* Out-of-memory situation tracking */
+ bool oom_pressure;
+ u64 oom_pressure_start;
};

#else /* CONFIG_PSI */
diff --git a/kernel/sched/psi.c b/kernel/sched/psi.c
index f28342dc65ec..1027b6611ec2 100644
--- a/kernel/sched/psi.c
+++ b/kernel/sched/psi.c
@@ -139,6 +139,7 @@
#include <linux/ctype.h>
#include <linux/file.h>
#include <linux/poll.h>
+#include <linux/oom.h>
#include <linux/psi.h>
#include "sched.h"

@@ -177,6 +178,8 @@ struct psi_group psi_system = {
.pcpu = &system_group_pcpu,
};

+static void psi_oom_tick(struct psi_group *group, u64 now);
+
static void psi_avgs_work(struct work_struct *work);

static void group_init(struct psi_group *group)
@@ -403,6 +406,8 @@ static u64 update_averages(struct psi_group *group, u64 now)
calc_avgs(group->avg[s], missed_periods, sample, period);
}

+ psi_oom_tick(group, now);
+
return avg_next_update;
}

@@ -1280,3 +1285,50 @@ static int __init psi_proc_init(void)
return 0;
}
module_init(psi_proc_init);
+
+#define OOM_PRESSURE_LEVEL 80
+#define OOM_PRESSURE_PERIOD (10 * NSEC_PER_SEC)
+
+static void psi_oom_tick(struct psi_group *group, u64 now)
+{
+ struct oom_control oc = {
+ .order = 0,
+ };
+ unsigned long pressure;
+ bool high;
+
+ /*
+ * Protect the system from livelocking due to thrashing. Leave
+ * per-cgroup policies to oomd, lmkd etc.
+ */
+ if (group != &psi_system)
+ return;
+
+ pressure = LOAD_INT(group->avg[PSI_MEM_FULL][0]);
+ high = pressure >= OOM_PRESSURE_LEVEL;
+
+ if (!group->oom_pressure && !high)
+ return;
+
+ if (!group->oom_pressure && high) {
+ group->oom_pressure = true;
+ group->oom_pressure_start = now;
+ return;
+ }
+
+ if (group->oom_pressure && !high) {
+ group->oom_pressure = false;
+ return;
+ }
+
+ if (now < group->oom_pressure_start + OOM_PRESSURE_PERIOD)
+ return;
+
+ group->oom_pressure = false;
+
+ if (!mutex_trylock(&oom_lock))
+ return;
+ pr_warn("Excessive and sustained system-wide memory pressure!\n");
+ out_of_memory(&oc);
+ mutex_unlock(&oom_lock);
+}
--
2.22.0