From: Weilong Chen chenweilong@huawei.com
ascend inclusion category: feature bugzilla: https://gitee.com/openeuler/kernel/issues/I8OX3P 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)
Signed-off-by: Weilong Chen chenweilong@huawei.com --- include/linux/oom.h | 24 +++++++++++++++++++ mm/Kconfig | 10 ++++++++ mm/memcontrol.c | 20 ++++++++++++++++ mm/oom_kill.c | 57 +++++++++++++++++++++++++++++++++++++++++++++ mm/util.c | 2 ++ 5 files changed, 113 insertions(+)
diff --git a/include/linux/oom.h b/include/linux/oom.h index 7d0c9c48a0c5..b9210e272651 100644 --- a/include/linux/oom.h +++ b/include/linux/oom.h @@ -112,4 +112,28 @@ extern void oom_killer_enable(void);
extern struct task_struct *find_lock_task_mm(struct task_struct *p);
+#define OOM_TYPE_NOMEM 0 +#define OOM_TYPE_OVERCOMMIT 1 +#define OOM_TYPE_CGROUP 2 + +#ifdef CONFIG_ASCEND_OOM +int register_hisi_oom_notifier(struct notifier_block *nb); +int unregister_hisi_oom_notifier(struct notifier_block *nb); +int oom_type_notifier_call(unsigned int type, struct oom_control *oc); +#else +static inline int register_hisi_oom_notifier(struct notifier_block *nb) +{ + return -EINVAL; +} + +static inline int unregister_hisi_oom_notifier(struct notifier_block *nb) +{ + return -EINVAL; +} + +static inline int oom_type_notifier_call(unsigned int type, struct oom_control *oc) +{ + return -EINVAL; +} +#endif #endif /* _INCLUDE_LINUX_OOM_H */ diff --git a/mm/Kconfig b/mm/Kconfig index 822c2ded2e26..ff0c36f42ca8 100644 --- a/mm/Kconfig +++ b/mm/Kconfig @@ -1312,6 +1312,16 @@ config SHARE_POOL in kernel and user level, which is only enabled for ascend platform. To enable this feature, enable_ascend_share_pool bootarg is needed.
+config ASCEND_OOM + bool "Enable support for disable oom killer" + default n + 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)
source "mm/damon/Kconfig"
diff --git a/mm/memcontrol.c b/mm/memcontrol.c index 8a881ab21f6c..fec6f37e61da 100644 --- a/mm/memcontrol.c +++ b/mm/memcontrol.c @@ -1955,6 +1955,7 @@ static bool mem_cgroup_oom(struct mem_cgroup *memcg, gfp_t mask, int order) current->memcg_in_oom = memcg; current->memcg_oom_gfp_mask = mask; current->memcg_oom_order = order; + oom_type_notifier_call(OOM_TYPE_CGROUP, NULL); } return false; } @@ -2019,6 +2020,8 @@ bool mem_cgroup_oom_synchronize(bool handle) if (locked) mem_cgroup_oom_notify(memcg);
+ oom_type_notifier_call(OOM_TYPE_CGROUP, NULL); + schedule(); mem_cgroup_unmark_under_oom(memcg); finish_wait(&memcg_oom_waitq, &owait.wait); @@ -3140,6 +3143,20 @@ int __memcg_kmem_charge_page(struct page *page, gfp_t gfp, int order) return ret; }
+#ifdef CONFIG_ASCEND_OOM +void hisi_oom_recover(struct obj_cgroup *objcg) +{ + struct mem_cgroup *memcg; + + memcg = get_mem_cgroup_from_objcg(objcg); + if (!mem_cgroup_is_root(memcg)) + memcg_oom_recover(memcg); + css_put(&memcg->css); +} +#else +static inline void hisi_oom_recover(struct obj_cgroup *objcg) { } +#endif + /** * __memcg_kmem_uncharge_page: uncharge a kmem page * @page: page to uncharge @@ -3156,6 +3173,9 @@ void __memcg_kmem_uncharge_page(struct page *page, int order)
objcg = __folio_objcg(folio); obj_cgroup_uncharge_pages(objcg, nr_pages); + + hisi_oom_recover(objcg); + folio->memcg_data = 0; obj_cgroup_put(objcg); } diff --git a/mm/oom_kill.c b/mm/oom_kill.c index 44bde56ecd02..601ee56cc7d7 100644 --- a/mm/oom_kill.c +++ b/mm/oom_kill.c @@ -55,6 +55,7 @@ static int sysctl_panic_on_oom; static int sysctl_oom_kill_allocating_task; static int sysctl_oom_dump_tasks = 1; +static int sysctl_enable_oom_killer = 1;
/* * Serializes oom killer invocations (out_of_memory()) from all contexts to @@ -724,6 +725,17 @@ static struct ctl_table vm_oom_kill_table[] = { .mode = 0644, .proc_handler = proc_dointvec, }, +#ifdef CONFIG_ASCEND_OOM + { + .procname = "enable_oom_killer", + .data = &sysctl_enable_oom_killer, + .maxlen = sizeof(sysctl_enable_oom_killer), + .mode = 0644, + .proc_handler = proc_dointvec_minmax, + .extra1 = SYSCTL_ZERO, + .extra2 = SYSCTL_ONE, + }, +#endif {} }; #endif @@ -1073,6 +1085,7 @@ static void check_panic_on_oom(struct oom_control *oc) if (is_sysrq_oom(oc)) return; dump_header(oc, NULL); + oom_type_notifier_call(OOM_TYPE_NOMEM, oc); panic("Out of memory: %s panic_on_oom is enabled\n", sysctl_panic_on_oom == 2 ? "compulsory" : "system-wide"); } @@ -1091,6 +1104,45 @@ int unregister_oom_notifier(struct notifier_block *nb) } EXPORT_SYMBOL_GPL(unregister_oom_notifier);
+#ifdef CONFIG_ASCEND_OOM +static BLOCKING_NOTIFIER_HEAD(oom_type_notify_list); + +int register_hisi_oom_notifier(struct notifier_block *nb) +{ + return blocking_notifier_chain_register(&oom_type_notify_list, nb); +} +EXPORT_SYMBOL_GPL(register_hisi_oom_notifier); + +int unregister_hisi_oom_notifier(struct notifier_block *nb) +{ + return blocking_notifier_chain_unregister(&oom_type_notify_list, nb); +} +EXPORT_SYMBOL_GPL(unregister_hisi_oom_notifier); + +int oom_type_notifier_call(unsigned int type, struct oom_control *oc) +{ + struct oom_control oc_tmp = { 0 }; + static unsigned long caller_jiffies; + + if (sysctl_enable_oom_killer) + return -EINVAL; + + if (oc) + type = is_memcg_oom(oc) ? OOM_TYPE_CGROUP : OOM_TYPE_NOMEM; + else + oc = &oc_tmp; + + if (printk_timed_ratelimit(&caller_jiffies, 10000)) { + pr_err("OOM_NOTIFIER: oom type %u\n", type); + dump_stack(); + show_mem(); + dump_tasks(oc); + } + + return blocking_notifier_call_chain(&oom_type_notify_list, type, NULL); +} +#endif + /** * out_of_memory - kill the "best" process when we run out of memory * @oc: pointer to struct oom_control @@ -1107,6 +1159,11 @@ bool out_of_memory(struct oom_control *oc) if (oom_killer_disabled) return false;
+ if (!sysctl_enable_oom_killer) { + oom_type_notifier_call(OOM_TYPE_NOMEM, oc); + return false; + } + if (!is_memcg_oom(oc)) { blocking_notifier_call_chain(&oom_notify_list, 0, &freed); if (freed > 0 && !is_sysrq_oom(oc)) diff --git a/mm/util.c b/mm/util.c index 90250cbc82fe..e41ac8a58eb5 100644 --- a/mm/util.c +++ b/mm/util.c @@ -26,6 +26,7 @@ #include <linux/share_pool.h>
#include <linux/uaccess.h> +#include <linux/oom.h>
#include "internal.h" #include "swap.h" @@ -981,6 +982,7 @@ int __vm_enough_memory(struct mm_struct *mm, long pages, int cap_sys_admin) error: pr_warn_ratelimited("%s: pid: %d, comm: %s, not enough memory for the allocation\n", __func__, current->pid, current->comm); + oom_type_notifier_call(OOM_TYPE_OVERCOMMIT, NULL); vm_unacct_memory(pages);
return -ENOMEM;