From patchwork Sat Nov 20 04:50:08 2021 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Mina Almasry X-Patchwork-Id: 12630061 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org Received: from kanga.kvack.org (kanga.kvack.org [205.233.56.17]) by smtp.lore.kernel.org (Postfix) with ESMTP id 98A78C433FE for ; Sat, 20 Nov 2021 04:51:33 +0000 (UTC) Received: by kanga.kvack.org (Postfix) id 79ED16B0073; Fri, 19 Nov 2021 23:50:33 -0500 (EST) Received: by kanga.kvack.org (Postfix, from userid 40) id 726F66B0074; Fri, 19 Nov 2021 23:50:33 -0500 (EST) X-Delivered-To: int-list-linux-mm@kvack.org Received: by kanga.kvack.org (Postfix, from userid 63042) id 5A23A6B0075; Fri, 19 Nov 2021 23:50:33 -0500 (EST) X-Delivered-To: linux-mm@kvack.org Received: from forelay.hostedemail.com (smtprelay0246.hostedemail.com [216.40.44.246]) by kanga.kvack.org (Postfix) with ESMTP id 49F756B0073 for ; Fri, 19 Nov 2021 23:50:33 -0500 (EST) Received: from smtpin22.hostedemail.com (10.5.19.251.rfc1918.com [10.5.19.251]) by forelay05.hostedemail.com (Postfix) with ESMTP id 0DFC618512164 for ; Sat, 20 Nov 2021 04:50:23 +0000 (UTC) X-FDA: 78828082326.22.67C8510 Received: from mail-pl1-f201.google.com (mail-pl1-f201.google.com [209.85.214.201]) by imf05.hostedemail.com (Postfix) with ESMTP id D01335092EDF for ; Sat, 20 Nov 2021 04:50:19 +0000 (UTC) Received: by mail-pl1-f201.google.com with SMTP id x18-20020a170902ec9200b00143c6409dbcso5715228plg.5 for ; Fri, 19 Nov 2021 20:50:22 -0800 (PST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=20210112; h=date:in-reply-to:message-id:mime-version:references:subject:from:to :cc; bh=79UaOzjGTX1bdBbuOK6OGZYuNHbD+Y6LGP3VMZPWWfo=; b=n+LvozaE5Q8BNCS3fqbqo3irax1e6z+BA7Db8d98bRsEGw60v1DGmfPfVE+O44XNGV rVwVHQDGp+B/FpyiQCK2k19VRTVEyntKdNaWzv+HFUGu+xeemoywhDpiO46vsBL0LzyO CLjU7WusWss/FqNR7Jr324wGgsFJOXNE8X8a8Lh8VTxzYuMgRpH4zYgvIkemxnyBE7ah NCcaiY38b6Fdlu7p1vAPSX4GJAx6ugjvXDdTq25+LSYxa3OkEDzLDT11bfizQZ0Et8vR 417XJRFAOrmVlqwhi/X0zItDeqXEYQ7OMZ7T68e+zwx+iTSa3ex4R3LL8lq/UYh4GWF3 r/5A== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20210112; h=x-gm-message-state:date:in-reply-to:message-id:mime-version :references:subject:from:to:cc; bh=79UaOzjGTX1bdBbuOK6OGZYuNHbD+Y6LGP3VMZPWWfo=; b=vr/Ioj7ARwSoR76eZ1pFPEpcsYlJvwdlP4JjxiFo5tYVaVrv3Yoj8BZt7hBrmnxpdE xjkktPjcMCMDjNdCW6wvCb40ed3dkXfI5F+OkrK1QOUeXYSf6AWFxNwD8FYjFYuGL7MZ QsSYfZLVhQlhm9uinETwaJkH34BZ4/II64sr8TA9JY6/vKPrMwbsNP0aMH71hEvlsNnh OoUqtQoFPpjkuOmIuyD/BNoBHwyDLJuyWKNV9Q0p7YvvU2tLJj14o3vu2Bj/pp05LFXO Syij9ZZqYUmKnu7rnHRKvt7QEDAvbfsSjeZoB9vPvRmaCNpLW6h5RYO03Y6ccD0tK9nY +YMA== X-Gm-Message-State: AOAM533wMWFpa2t1tExz9voFnVmt6eAOqpVcJyBGpOYQJC2Wq9d2vUsy V2ledXFlk7rRt75MtRHoYYfa98yneGEpmYI2NA== X-Google-Smtp-Source: ABdhPJzXoftBTXQvnJs8EFAoaTwcP0Br6rSCWqmYFOoLP3v+C0fEMkZmUYYmYcCbMQC53bT7Z87J4j5MwXLcZk2+VQ== X-Received: from almasrymina.svl.corp.google.com ([2620:15c:2cd:202:fa91:560a:d7b4:93]) (user=almasrymina job=sendgmr) by 2002:a17:902:7005:b0:142:4452:25de with SMTP id y5-20020a170902700500b00142445225demr84357056plk.3.1637383821734; Fri, 19 Nov 2021 20:50:21 -0800 (PST) Date: Fri, 19 Nov 2021 20:50:08 -0800 In-Reply-To: <20211120045011.3074840-1-almasrymina@google.com> Message-Id: <20211120045011.3074840-3-almasrymina@google.com> Mime-Version: 1.0 References: <20211120045011.3074840-1-almasrymina@google.com> X-Mailer: git-send-email 2.34.0.rc2.393.gf8c9666880-goog Subject: [PATCH v4 2/4] mm/oom: handle remote ooms From: Mina Almasry To: Johannes Weiner , Michal Hocko , Vladimir Davydov , Andrew Morton Cc: Mina Almasry , Jonathan Corbet , Alexander Viro , Hugh Dickins , Shuah Khan , Shakeel Butt , Greg Thelen , Dave Chinner , Matthew Wilcox , Roman Gushchin , "Theodore Ts'o" , linux-kernel@vger.kernel.org, linux-fsdevel@vger.kernel.org, linux-mm@kvack.org, cgroups@vger.kernel.org X-Rspamd-Server: rspam10 X-Rspamd-Queue-Id: D01335092EDF X-Stat-Signature: icwgz73d9mrgdi9xq4fm5yikzqh576zz Authentication-Results: imf05.hostedemail.com; dkim=pass header.d=google.com header.s=20210112 header.b=n+LvozaE; dmarc=pass (policy=reject) header.from=google.com; spf=pass (imf05.hostedemail.com: domain of 3jX6YYQsKCP4grsgyx4sotgmuumrk.iusrot03-ssq1giq.uxm@flex--almasrymina.bounces.google.com designates 209.85.214.201 as permitted sender) smtp.mailfrom=3jX6YYQsKCP4grsgyx4sotgmuumrk.iusrot03-ssq1giq.uxm@flex--almasrymina.bounces.google.com X-HE-Tag: 1637383819-891514 X-Bogosity: Ham, tests=bogofilter, spamicity=0.000000, version=1.2.4 Sender: owner-linux-mm@kvack.org Precedence: bulk X-Loop: owner-majordomo@kvack.org List-ID: On remote ooms (OOMs due to remote charging), the oom-killer will attempt to find a task to kill in the memcg under oom. The oom-killer may be unable to find a process to kill if there are no killable processes in the remote memcg. In this case, the oom-killer (out_of_memory()) will return false, and depending on the gfp, that will generally get bubbled up to mem_cgroup_charge_mapping() as an ENOMEM. A few considerations on how to handle this edge case: 1. memcg= is an opt-in feature, so we have some flexibility with the behavior that we export to userspace using this feature to carry out remote charges that may result in remote ooms. The critical thing is to document this behavior so the userspace knows what to expect and handle the edge cases. 2. It is generally not desirable to kill the allocating process, because it's not a member of the remote memcg which is under oom, and so killing it will almost certainly not free any memory in the memcg under oom. 3. There are allocations that happen in pagefault paths, as well as those that happen in non-pagefault paths, and the error returned from mem_cgroup_charge_mapping() will be handled by the caller resulting in different behavior seen by the userspace in the pagefault and non-pagefault paths. For example, currently if mem_cgroup_charge_mapping() returns ENOMEM, the caller will generally get an ENOMEM on non-pagefault paths, and the caller will be stuck looping the pagefault forever in the pagefault path. 4. In general, it's desirable to give userspace the option to gracefully handle and recover from a failed remote charge rather than kill the process or put it into a situation that's hard to recover from. With these considerations, the thing that makes most sense here is to handle this edge case similarly to how we handle ENOSPC error, and to return ENOSPC from mem_cgroup_charge_mapping() when the remote charge fails. This has the desirable properties: 1. On pagefault allocations, the userspace will get a SIGBUS if the remote charge fails, and the userspace is able to catch this signal and handle it to recover gracefully as desired. 2. On non-pagefault paths, the userspace will get an ENOSPC error which it can also handle gracefully, if desired. 3. We would not leave the remote charging process in a looping pagetfault (a state somewhat hard to recover from) or kill it. Implementation notes: 1. To get the ENOSPC behavior we alegedly want, in mem_cgroup_charge_mapping() we detect whether charge_memcg() has failed, and we return ENOSPC here. 2. If the oom-killer is invoked and finds nothing to kill, it prints out the "Out of memory and no killable processes..." message, which can be spammy if the system is executing many remote charges and generally will cause worry as it will likely be seen as a scary looking kernel warning, even though this is somewhat of an expected edge case to run into and we handle it adequately. Therefore, in out_of_memory() we return early to not print this warning. This is not necessary for the functionality of the remote charges. Signed-off-by: Mina Almasry --- Changes in v4: - Greatly expanded on the commit message to include all my current thinking. - Converted the patch to handle remote ooms similarly to ENOSPC, rather than ENOMEM. Changes in v3: - Fixed build failures/warnings Reported-by: kernel test robot Changes in v2: - Moved the remote oom handling as Roman requested. - Used mem_cgroup_from_task(current) instead of grabbing the memcg from current->mm --- include/linux/memcontrol.h | 6 ++++++ mm/memcontrol.c | 31 ++++++++++++++++++++++++++++++- mm/oom_kill.c | 9 +++++++++ 3 files changed, 45 insertions(+), 1 deletion(-) -- 2.34.0.rc2.393.gf8c9666880-goog diff --git a/include/linux/memcontrol.h b/include/linux/memcontrol.h index 0a9b0bba5f3c8..451feebabf160 100644 --- a/include/linux/memcontrol.h +++ b/include/linux/memcontrol.h @@ -932,6 +932,7 @@ int mem_cgroup_charge_mapping(struct folio *folio, struct mm_struct *mm, struct mem_cgroup *mem_cgroup_get_from_path(const char *path); void mem_cgroup_put_name_in_seq(struct seq_file *seq, struct super_block *sb); +bool is_remote_oom(struct mem_cgroup *memcg_under_oom); void mem_cgroup_update_lru_size(struct lruvec *lruvec, enum lru_list lru, int zid, int nr_pages); @@ -1255,6 +1256,11 @@ static inline void mem_cgroup_put_name_in_seq(struct seq_file *seq, { } +static inline bool is_remote_oom(struct mem_cgroup *memcg_under_oom) +{ + return false; +} + static inline int mem_cgroup_swapin_charge_page(struct page *page, struct mm_struct *mm, gfp_t gfp, swp_entry_t entry) { diff --git a/mm/memcontrol.c b/mm/memcontrol.c index c4ba7f364c214..3e5bc2c32c9b7 100644 --- a/mm/memcontrol.c +++ b/mm/memcontrol.c @@ -2668,6 +2668,35 @@ void mem_cgroup_put_name_in_seq(struct seq_file *m, struct super_block *sb) __putname(buf); } +/* + * Returns true if current's mm is a descendant of the memcg_under_oom (or + * equal to it). False otherwise. This is used by the oom-killer to detect + * ooms due to remote charging. + */ +bool is_remote_oom(struct mem_cgroup *memcg_under_oom) +{ + struct mem_cgroup *current_memcg; + bool is_remote_oom; + + if (!memcg_under_oom) + return false; + + rcu_read_lock(); + current_memcg = mem_cgroup_from_task(current); + if (current_memcg && !css_tryget_online(¤t_memcg->css)) + current_memcg = NULL; + rcu_read_unlock(); + + if (!current_memcg) + return false; + + is_remote_oom = + !mem_cgroup_is_descendant(current_memcg, memcg_under_oom); + css_put(¤t_memcg->css); + + return is_remote_oom; +} + /* * Set or clear (if @memcg is NULL) charge association from file system to * memcg. If @memcg != NULL, then a css reference must be held by the caller to @@ -6814,7 +6843,7 @@ int mem_cgroup_charge_mapping(struct folio *folio, struct mm_struct *mm, if (mapping_memcg) { ret = charge_memcg(folio, mapping_memcg, gfp); css_put(&mapping_memcg->css); - return ret; + return ret == -ENOMEM ? -ENOSPC : ret; } return mem_cgroup_charge(folio, mm, gfp); diff --git a/mm/oom_kill.c b/mm/oom_kill.c index 0a7e16b16b8c3..8db500b337415 100644 --- a/mm/oom_kill.c +++ b/mm/oom_kill.c @@ -1108,6 +1108,15 @@ bool out_of_memory(struct oom_control *oc) select_bad_process(oc); /* Found nothing?!?! */ if (!oc->chosen) { + if (is_remote_oom(oc->memcg)) { + /* + * For remote ooms with no killable processes, return + * false here without logging the warning below as we + * expect the caller to handle this as they please. + */ + return false; + } + dump_header(oc, NULL); pr_warn("Out of memory and no killable processes...\n"); /*