|
@@ -1776,6 +1776,62 @@ cleanup:
|
|
|
return true;
|
|
|
}
|
|
|
|
|
|
+/**
|
|
|
+ * mem_cgroup_get_oom_group - get a memory cgroup to clean up after OOM
|
|
|
+ * @victim: task to be killed by the OOM killer
|
|
|
+ * @oom_domain: memcg in case of memcg OOM, NULL in case of system-wide OOM
|
|
|
+ *
|
|
|
+ * Returns a pointer to a memory cgroup, which has to be cleaned up
|
|
|
+ * by killing all belonging OOM-killable tasks.
|
|
|
+ *
|
|
|
+ * Caller has to call mem_cgroup_put() on the returned non-NULL memcg.
|
|
|
+ */
|
|
|
+struct mem_cgroup *mem_cgroup_get_oom_group(struct task_struct *victim,
|
|
|
+ struct mem_cgroup *oom_domain)
|
|
|
+{
|
|
|
+ struct mem_cgroup *oom_group = NULL;
|
|
|
+ struct mem_cgroup *memcg;
|
|
|
+
|
|
|
+ if (!cgroup_subsys_on_dfl(memory_cgrp_subsys))
|
|
|
+ return NULL;
|
|
|
+
|
|
|
+ if (!oom_domain)
|
|
|
+ oom_domain = root_mem_cgroup;
|
|
|
+
|
|
|
+ rcu_read_lock();
|
|
|
+
|
|
|
+ memcg = mem_cgroup_from_task(victim);
|
|
|
+ if (memcg == root_mem_cgroup)
|
|
|
+ goto out;
|
|
|
+
|
|
|
+ /*
|
|
|
+ * Traverse the memory cgroup hierarchy from the victim task's
|
|
|
+ * cgroup up to the OOMing cgroup (or root) to find the
|
|
|
+ * highest-level memory cgroup with oom.group set.
|
|
|
+ */
|
|
|
+ for (; memcg; memcg = parent_mem_cgroup(memcg)) {
|
|
|
+ if (memcg->oom_group)
|
|
|
+ oom_group = memcg;
|
|
|
+
|
|
|
+ if (memcg == oom_domain)
|
|
|
+ break;
|
|
|
+ }
|
|
|
+
|
|
|
+ if (oom_group)
|
|
|
+ css_get(&oom_group->css);
|
|
|
+out:
|
|
|
+ rcu_read_unlock();
|
|
|
+
|
|
|
+ return oom_group;
|
|
|
+}
|
|
|
+
|
|
|
+void mem_cgroup_print_oom_group(struct mem_cgroup *memcg)
|
|
|
+{
|
|
|
+ pr_info("Tasks in ");
|
|
|
+ pr_cont_cgroup_path(memcg->css.cgroup);
|
|
|
+ pr_cont(" are going to be killed due to memory.oom.group set\n");
|
|
|
+}
|
|
|
+
|
|
|
/**
|
|
|
* lock_page_memcg - lock a page->mem_cgroup binding
|
|
|
* @page: the page
|
|
@@ -5561,6 +5617,37 @@ static int memory_stat_show(struct seq_file *m, void *v)
|
|
|
return 0;
|
|
|
}
|
|
|
|
|
|
+static int memory_oom_group_show(struct seq_file *m, void *v)
|
|
|
+{
|
|
|
+ struct mem_cgroup *memcg = mem_cgroup_from_css(seq_css(m));
|
|
|
+
|
|
|
+ seq_printf(m, "%d\n", memcg->oom_group);
|
|
|
+
|
|
|
+ return 0;
|
|
|
+}
|
|
|
+
|
|
|
+static ssize_t memory_oom_group_write(struct kernfs_open_file *of,
|
|
|
+ char *buf, size_t nbytes, loff_t off)
|
|
|
+{
|
|
|
+ struct mem_cgroup *memcg = mem_cgroup_from_css(of_css(of));
|
|
|
+ int ret, oom_group;
|
|
|
+
|
|
|
+ buf = strstrip(buf);
|
|
|
+ if (!buf)
|
|
|
+ return -EINVAL;
|
|
|
+
|
|
|
+ ret = kstrtoint(buf, 0, &oom_group);
|
|
|
+ if (ret)
|
|
|
+ return ret;
|
|
|
+
|
|
|
+ if (oom_group != 0 && oom_group != 1)
|
|
|
+ return -EINVAL;
|
|
|
+
|
|
|
+ memcg->oom_group = oom_group;
|
|
|
+
|
|
|
+ return nbytes;
|
|
|
+}
|
|
|
+
|
|
|
static struct cftype memory_files[] = {
|
|
|
{
|
|
|
.name = "current",
|
|
@@ -5602,6 +5689,12 @@ static struct cftype memory_files[] = {
|
|
|
.flags = CFTYPE_NOT_ON_ROOT,
|
|
|
.seq_show = memory_stat_show,
|
|
|
},
|
|
|
+ {
|
|
|
+ .name = "oom.group",
|
|
|
+ .flags = CFTYPE_NOT_ON_ROOT | CFTYPE_NS_DELEGATABLE,
|
|
|
+ .seq_show = memory_oom_group_show,
|
|
|
+ .write = memory_oom_group_write,
|
|
|
+ },
|
|
|
{ } /* terminate */
|
|
|
};
|
|
|
|