From: Weilong Chen chenweilong@huawei.com
ascend inclusion category: feature bugzilla: NA CVE: NA
-------------------------------------------------
Support disable oom-killer, and report oom events to bbox vm.enable_oom_killer: 0: disable oom killer 1: enable oom killer (default,compatible with mainline) 2: disable oom killer and panic on oom
Signed-off-by: Weilong Chen chenweilong@huawei.com Reviewed-by: Kefeng Wang wangkefeng.wang@huawei.com Signed-off-by: Yang Yingliang yangyingliang@huawei.com --- arch/arm64/Kconfig | 11 +++++++++ include/linux/oom.h | 11 +++++++++ kernel/sysctl.c | 12 ++++++++++ mm/memcontrol.c | 6 +++++ mm/oom_kill.c | 56 +++++++++++++++++++++++++++++++++++++++++++++ mm/util.c | 6 +++++ 6 files changed, 102 insertions(+)
diff --git a/arch/arm64/Kconfig b/arch/arm64/Kconfig index 10fabb5f633d..4412f14547af 100644 --- a/arch/arm64/Kconfig +++ b/arch/arm64/Kconfig @@ -1351,6 +1351,17 @@ config ASCEND_DVPP_MMAP special memory for DvPP processor, the new flag is only valid for Ascend platform.
+config ASCEND_OOM + bool "Enable support for disable oom killer" + default y + help + In some cases we hopes that the oom will not kill the process when it occurs, + be able to notify the black box to report the event, and be able to trigger + the panic to locate the problem. + vm.enable_oom_killer: + 0: disable oom killer + 1: enable oom killer (default,compatible with mainline) + 2: disable oom killer and panic on oom endif
endmenu diff --git a/include/linux/oom.h b/include/linux/oom.h index 69864a547663..689d32ab694b 100644 --- a/include/linux/oom.h +++ b/include/linux/oom.h @@ -117,4 +117,15 @@ extern struct task_struct *find_lock_task_mm(struct task_struct *p); extern int sysctl_oom_dump_tasks; extern int sysctl_oom_kill_allocating_task; extern int sysctl_panic_on_oom; + +#ifdef CONFIG_ASCEND_OOM +#define HISI_OOM_TYPE_NOMEM 0 +#define HISI_OOM_TYPE_OVERCOMMIT 1 +#define HISI_OOM_TYPE_CGROUP 2 + +extern int sysctl_enable_oom_killer; +extern int register_hisi_oom_notifier(struct notifier_block *nb); +extern int hisi_oom_notifier_call(unsigned long val, void *v); +extern int unregister_hisi_oom_notifier(struct notifier_block *nb); +#endif #endif /* _INCLUDE_LINUX_OOM_H */ diff --git a/kernel/sysctl.c b/kernel/sysctl.c index 54ae74d3180b..665c9e2a8802 100644 --- a/kernel/sysctl.c +++ b/kernel/sysctl.c @@ -1264,6 +1264,18 @@ static struct ctl_table vm_table[] = { .extra1 = &zero, .extra2 = &two, }, +#ifdef CONFIG_ASCEND_OOM + { + /* 0: diasable, 1: enable, 2: disable and panic on oom */ + .procname = "enable_oom_killer", + .data = &sysctl_enable_oom_killer, + .maxlen = sizeof(sysctl_enable_oom_killer), + .mode = 0644, + .proc_handler = proc_dointvec_minmax, + .extra1 = &zero, + .extra2 = &two, + }, +#endif { .procname = "oom_kill_allocating_task", .data = &sysctl_oom_kill_allocating_task, diff --git a/mm/memcontrol.c b/mm/memcontrol.c index e0377bae0bf6..a63bfd73da9a 100644 --- a/mm/memcontrol.c +++ b/mm/memcontrol.c @@ -1729,6 +1729,9 @@ static enum oom_status mem_cgroup_oom(struct mem_cgroup *memcg, gfp_t mask, int current->memcg_in_oom = memcg; current->memcg_oom_gfp_mask = mask; current->memcg_oom_order = order; +#ifdef CONFIG_ASCEND_OOM + hisi_oom_notifier_call(HISI_OOM_TYPE_CGROUP, NULL); +#endif
return OOM_ASYNC; } @@ -1802,6 +1805,9 @@ bool mem_cgroup_oom_synchronize(bool handle) mem_cgroup_out_of_memory(memcg, current->memcg_oom_gfp_mask, current->memcg_oom_order); } else { +#ifdef CONFIG_ASCEND_OOM + hisi_oom_notifier_call(HISI_OOM_TYPE_CGROUP, NULL); +#endif schedule(); mem_cgroup_unmark_under_oom(memcg); finish_wait(&memcg_oom_waitq, &owait.wait); diff --git a/mm/oom_kill.c b/mm/oom_kill.c index 8a4570c53e83..c08041ecd286 100644 --- a/mm/oom_kill.c +++ b/mm/oom_kill.c @@ -52,6 +52,9 @@ int sysctl_panic_on_oom; int sysctl_oom_kill_allocating_task; int sysctl_oom_dump_tasks = 1; +#ifdef CONFIG_ASCEND_OOM +int sysctl_enable_oom_killer = 1; +#endif
/* * Serializes oom killer invocations (out_of_memory()) from all contexts to @@ -1047,6 +1050,42 @@ int unregister_oom_notifier(struct notifier_block *nb) } EXPORT_SYMBOL_GPL(unregister_oom_notifier);
+#ifdef CONFIG_ASCEND_OOM +static BLOCKING_NOTIFIER_HEAD(hisi_oom_notify_list); + +int register_hisi_oom_notifier(struct notifier_block *nb) +{ + return blocking_notifier_chain_register(&hisi_oom_notify_list, nb); +} +EXPORT_SYMBOL_GPL(register_hisi_oom_notifier); + +static unsigned long last_jiffies; +int hisi_oom_notifier_call(unsigned long val, void *v) +{ + /* when enable oom killer, just return */ + if (sysctl_enable_oom_killer == 1) + return 0; + + /* Print time interval to 10 seconds */ + if (time_after(jiffies, last_jiffies + 10 * HZ)) { + pr_err("OOM_NOTIFIER: oom type %lu\n", val); + dump_stack(); + show_mem(SHOW_MEM_FILTER_NODES, NULL); + dump_tasks(NULL, 0); + last_jiffies = jiffies; + } + + return blocking_notifier_call_chain(&hisi_oom_notify_list, val, v); +} +EXPORT_SYMBOL_GPL(hisi_oom_notifier_call); + +int unregister_hisi_oom_notifier(struct notifier_block *nb) +{ + return blocking_notifier_chain_unregister(&hisi_oom_notify_list, nb); +} +EXPORT_SYMBOL_GPL(unregister_hisi_oom_notifier); +#endif + /** * out_of_memory - kill the "best" process when we run out of memory * @oc: pointer to struct oom_control @@ -1060,10 +1099,27 @@ bool out_of_memory(struct oom_control *oc) { unsigned long freed = 0; enum oom_constraint constraint = CONSTRAINT_NONE; +#ifdef CONFIG_ASCEND_OOM + unsigned long oom_type; +#endif
if (oom_killer_disabled) return false;
+#ifdef CONFIG_ASCEND_OOM + if (sysctl_enable_oom_killer == 0 || sysctl_enable_oom_killer == 2) { + if (is_memcg_oom(oc)) + oom_type = HISI_OOM_TYPE_CGROUP; + else + oom_type = HISI_OOM_TYPE_NOMEM; + + hisi_oom_notifier_call(oom_type, NULL); + if (unlikely(sysctl_enable_oom_killer == 2)) + panic("Out of memory, panic by sysctl_enable_oom_killer"); + return false; + } +#endif + if (!is_memcg_oom(oc)) { blocking_notifier_call_chain(&oom_notify_list, 0, &freed); if (freed > 0) diff --git a/mm/util.c b/mm/util.c index 5515219168e8..ed64ef1f8387 100644 --- a/mm/util.c +++ b/mm/util.c @@ -17,6 +17,9 @@
#include <asm/sections.h> #include <linux/uaccess.h> +#ifdef CONFIG_ASCEND_OOM +#include <linux/oom.h> +#endif
#include "internal.h"
@@ -744,6 +747,9 @@ int __vm_enough_memory(struct mm_struct *mm, long pages, int cap_sys_admin) if (percpu_counter_read_positive(&vm_committed_as) < allowed) return 0; error: +#ifdef CONFIG_ASCEND_OOM + hisi_oom_notifier_call(HISI_OOM_TYPE_OVERCOMMIT, NULL); +#endif vm_unacct_memory(pages);
return -ENOMEM;