* [PATCH 1/2] mm, slab: put should_failslab() back behind CONFIG_SHOULD_FAILSLAB
2024-07-11 16:35 [PATCH 0/2] revert unconditional slab and page allocator fault injection calls Vlastimil Babka
@ 2024-07-11 16:35 ` Vlastimil Babka
2024-07-11 16:35 ` [PATCH 2/2] mm, page_alloc: put should_fail_alloc_page() back behing CONFIG_FAIL_PAGE_ALLOC Vlastimil Babka
2024-07-11 19:36 ` [PATCH 0/2] revert unconditional slab and page allocator fault injection calls Andrew Morton
2 siblings, 0 replies; 5+ messages in thread
From: Vlastimil Babka @ 2024-07-11 16:35 UTC (permalink / raw)
To: Andrew Morton
Cc: Mateusz Guzik, Akinobu Mita, Alexei Starovoitov, Daniel Borkmann,
John Fastabend, Andrii Nakryiko, Martin KaFai Lau,
Eduard Zingerman, Song Liu, Yonghong Song, KP Singh,
Stanislav Fomichev, Hao Luo, Jiri Olsa, Christoph Lameter,
David Rientjes, Roman Gushchin, Hyeonggon Yoo, linux-kernel, bpf,
linux-mm, Vlastimil Babka
This mostly reverts commit 4f6923fbb352 ("mm: make should_failslab
always available for fault injection"). The commit made
should_failslab() a noinline function that's always called from the slab
allocation hotpath, even if it's empty because CONFIG_SHOULD_FAILSLAB is
not enabled, and there is no option to disable that call. This is
visible in profiles and the function call overhead can be noticeable
especially with cpu mitigations.
Meanwhile the bpftrace program example in the commit silently does not
work without CONFIG_SHOULD_FAILSLAB anyway with a recent gcc, because
the empty function gets a .constprop clone that is actually being called
(uselessly) from the slab hotpath, while the error injection is hooked
to the original function that's not being called at all [1].
Thus put the whole should_failslab() function back behind
CONFIG_SHOULD_FAILSLAB. It's not a complete revert of 4f6923fbb352 - the
int return type that returns -ENOMEM on failure is preserved, as well
ALLOW_ERROR_INJECTION annotation. The BTF_ID() record that was meanwhile
added is also guarded by CONFIG_SHOULD_FAILSLAB.
[1] https://github.com/bpftrace/bpftrace/issues/3258
Signed-off-by: Vlastimil Babka <vbabka@suse.cz>
---
include/linux/fault-inject.h | 5 ++---
kernel/bpf/verifier.c | 2 ++
mm/failslab.c | 14 ++++++++------
mm/slub.c | 8 --------
4 files changed, 12 insertions(+), 17 deletions(-)
diff --git a/include/linux/fault-inject.h b/include/linux/fault-inject.h
index 6d5edef09d45..be6d0bc111ad 100644
--- a/include/linux/fault-inject.h
+++ b/include/linux/fault-inject.h
@@ -102,11 +102,10 @@ static inline bool __should_fail_alloc_page(gfp_t gfp_mask, unsigned int order)
}
#endif /* CONFIG_FAIL_PAGE_ALLOC */
-int should_failslab(struct kmem_cache *s, gfp_t gfpflags);
#ifdef CONFIG_FAILSLAB
-extern bool __should_failslab(struct kmem_cache *s, gfp_t gfpflags);
+int should_failslab(struct kmem_cache *s, gfp_t gfpflags);
#else
-static inline bool __should_failslab(struct kmem_cache *s, gfp_t gfpflags)
+static inline int should_failslab(struct kmem_cache *s, gfp_t gfpflags)
{
return false;
}
diff --git a/kernel/bpf/verifier.c b/kernel/bpf/verifier.c
index 214a9fa8c6fb..e455654f3b91 100644
--- a/kernel/bpf/verifier.c
+++ b/kernel/bpf/verifier.c
@@ -21123,7 +21123,9 @@ BTF_SET_START(btf_non_sleepable_error_inject)
*/
BTF_ID(func, __filemap_add_folio)
BTF_ID(func, should_fail_alloc_page)
+#ifdef CONFIG_FAILSLAB
BTF_ID(func, should_failslab)
+#endif
BTF_SET_END(btf_non_sleepable_error_inject)
static int check_non_sleepable_error_inject(u32 btf_id)
diff --git a/mm/failslab.c b/mm/failslab.c
index ffc420c0e767..af16c2ed578f 100644
--- a/mm/failslab.c
+++ b/mm/failslab.c
@@ -1,5 +1,6 @@
// SPDX-License-Identifier: GPL-2.0
#include <linux/fault-inject.h>
+#include <linux/error-injection.h>
#include <linux/slab.h>
#include <linux/mm.h>
#include "slab.h"
@@ -14,23 +15,23 @@ static struct {
.cache_filter = false,
};
-bool __should_failslab(struct kmem_cache *s, gfp_t gfpflags)
+int should_failslab(struct kmem_cache *s, gfp_t gfpflags)
{
int flags = 0;
/* No fault-injection for bootstrap cache */
if (unlikely(s == kmem_cache))
- return false;
+ return 0;
if (gfpflags & __GFP_NOFAIL)
- return false;
+ return 0;
if (failslab.ignore_gfp_reclaim &&
(gfpflags & __GFP_DIRECT_RECLAIM))
- return false;
+ return 0;
if (failslab.cache_filter && !(s->flags & SLAB_FAILSLAB))
- return false;
+ return 0;
/*
* In some cases, it expects to specify __GFP_NOWARN
@@ -41,8 +42,9 @@ bool __should_failslab(struct kmem_cache *s, gfp_t gfpflags)
if (gfpflags & __GFP_NOWARN)
flags |= FAULT_NOWARN;
- return should_fail_ex(&failslab.attr, s->object_size, flags);
+ return should_fail_ex(&failslab.attr, s->object_size, flags) ? -ENOMEM : 0;
}
+ALLOW_ERROR_INJECTION(should_failslab, ERRNO);
static int __init setup_failslab(char *str)
{
diff --git a/mm/slub.c b/mm/slub.c
index 4927edec6a8c..2e7c7289de91 100644
--- a/mm/slub.c
+++ b/mm/slub.c
@@ -3875,14 +3875,6 @@ static __always_inline void maybe_wipe_obj_freeptr(struct kmem_cache *s,
0, sizeof(void *));
}
-noinline int should_failslab(struct kmem_cache *s, gfp_t gfpflags)
-{
- if (__should_failslab(s, gfpflags))
- return -ENOMEM;
- return 0;
-}
-ALLOW_ERROR_INJECTION(should_failslab, ERRNO);
-
static __fastpath_inline
struct kmem_cache *slab_pre_alloc_hook(struct kmem_cache *s, gfp_t flags)
{
--
2.45.2
^ permalink raw reply related [flat|nested] 5+ messages in thread* [PATCH 2/2] mm, page_alloc: put should_fail_alloc_page() back behing CONFIG_FAIL_PAGE_ALLOC
2024-07-11 16:35 [PATCH 0/2] revert unconditional slab and page allocator fault injection calls Vlastimil Babka
2024-07-11 16:35 ` [PATCH 1/2] mm, slab: put should_failslab() back behind CONFIG_SHOULD_FAILSLAB Vlastimil Babka
@ 2024-07-11 16:35 ` Vlastimil Babka
2024-07-11 19:36 ` [PATCH 0/2] revert unconditional slab and page allocator fault injection calls Andrew Morton
2 siblings, 0 replies; 5+ messages in thread
From: Vlastimil Babka @ 2024-07-11 16:35 UTC (permalink / raw)
To: Andrew Morton
Cc: Mateusz Guzik, Akinobu Mita, Alexei Starovoitov, Daniel Borkmann,
John Fastabend, Andrii Nakryiko, Martin KaFai Lau,
Eduard Zingerman, Song Liu, Yonghong Song, KP Singh,
Stanislav Fomichev, Hao Luo, Jiri Olsa, Christoph Lameter,
David Rientjes, Roman Gushchin, Hyeonggon Yoo, linux-kernel, bpf,
linux-mm, Vlastimil Babka
This mostly reverts commit af3b854492f3 ("mm/page_alloc.c: allow error
injection"). The commit made should_fail_alloc_page() a noinline
function that's always called from the page allocation hotpath,
even if it's empty because CONFIG_FAIL_PAGE_ALLOC is not enabled, and
there is no option to disable it and prevent the associated function
call overhead.
As with the preceding patch "mm, slab: put should_failslab back behind
CONFIG_SHOULD_FAILSLAB" and for the same reasons, put the
should_fail_alloc_page() back behind the config option. When enabled,
the ALLOW_ERROR_INJECTION and BTF_ID records are preserved so it's not
a complete revert.
Signed-off-by: Vlastimil Babka <vbabka@suse.cz>
---
include/linux/fault-inject.h | 6 ++----
kernel/bpf/verifier.c | 2 ++
mm/fail_page_alloc.c | 4 +++-
mm/page_alloc.c | 6 ------
4 files changed, 7 insertions(+), 11 deletions(-)
diff --git a/include/linux/fault-inject.h b/include/linux/fault-inject.h
index be6d0bc111ad..354413950d34 100644
--- a/include/linux/fault-inject.h
+++ b/include/linux/fault-inject.h
@@ -91,12 +91,10 @@ static inline void fault_config_init(struct fault_config *config,
struct kmem_cache;
-bool should_fail_alloc_page(gfp_t gfp_mask, unsigned int order);
-
#ifdef CONFIG_FAIL_PAGE_ALLOC
-bool __should_fail_alloc_page(gfp_t gfp_mask, unsigned int order);
+bool should_fail_alloc_page(gfp_t gfp_mask, unsigned int order);
#else
-static inline bool __should_fail_alloc_page(gfp_t gfp_mask, unsigned int order)
+static inline bool should_fail_alloc_page(gfp_t gfp_mask, unsigned int order)
{
return false;
}
diff --git a/kernel/bpf/verifier.c b/kernel/bpf/verifier.c
index e455654f3b91..a81e18409ec9 100644
--- a/kernel/bpf/verifier.c
+++ b/kernel/bpf/verifier.c
@@ -21122,7 +21122,9 @@ BTF_SET_START(btf_non_sleepable_error_inject)
* Assume non-sleepable from bpf safety point of view.
*/
BTF_ID(func, __filemap_add_folio)
+#ifdef CONFIG_FAIL_PAGE_ALLOC
BTF_ID(func, should_fail_alloc_page)
+#endif
#ifdef CONFIG_FAILSLAB
BTF_ID(func, should_failslab)
#endif
diff --git a/mm/fail_page_alloc.c b/mm/fail_page_alloc.c
index b1b09cce9394..532851ce5132 100644
--- a/mm/fail_page_alloc.c
+++ b/mm/fail_page_alloc.c
@@ -1,5 +1,6 @@
// SPDX-License-Identifier: GPL-2.0
#include <linux/fault-inject.h>
+#include <linux/error-injection.h>
#include <linux/mm.h>
static struct {
@@ -21,7 +22,7 @@ static int __init setup_fail_page_alloc(char *str)
}
__setup("fail_page_alloc=", setup_fail_page_alloc);
-bool __should_fail_alloc_page(gfp_t gfp_mask, unsigned int order)
+bool should_fail_alloc_page(gfp_t gfp_mask, unsigned int order)
{
int flags = 0;
@@ -41,6 +42,7 @@ bool __should_fail_alloc_page(gfp_t gfp_mask, unsigned int order)
return should_fail_ex(&fail_page_alloc.attr, 1 << order, flags);
}
+ALLOW_ERROR_INJECTION(should_fail_alloc_page, TRUE);
#ifdef CONFIG_FAULT_INJECTION_DEBUG_FS
diff --git a/mm/page_alloc.c b/mm/page_alloc.c
index 9ecf99190ea2..91b7234f1d7e 100644
--- a/mm/page_alloc.c
+++ b/mm/page_alloc.c
@@ -3031,12 +3031,6 @@ struct page *rmqueue(struct zone *preferred_zone,
return page;
}
-noinline bool should_fail_alloc_page(gfp_t gfp_mask, unsigned int order)
-{
- return __should_fail_alloc_page(gfp_mask, order);
-}
-ALLOW_ERROR_INJECTION(should_fail_alloc_page, TRUE);
-
static inline long __zone_watermark_unusable_free(struct zone *z,
unsigned int order, unsigned int alloc_flags)
{
--
2.45.2
^ permalink raw reply related [flat|nested] 5+ messages in thread* Re: [PATCH 0/2] revert unconditional slab and page allocator fault injection calls
2024-07-11 16:35 [PATCH 0/2] revert unconditional slab and page allocator fault injection calls Vlastimil Babka
2024-07-11 16:35 ` [PATCH 1/2] mm, slab: put should_failslab() back behind CONFIG_SHOULD_FAILSLAB Vlastimil Babka
2024-07-11 16:35 ` [PATCH 2/2] mm, page_alloc: put should_fail_alloc_page() back behing CONFIG_FAIL_PAGE_ALLOC Vlastimil Babka
@ 2024-07-11 19:36 ` Andrew Morton
2024-07-12 7:19 ` Vlastimil Babka
2 siblings, 1 reply; 5+ messages in thread
From: Andrew Morton @ 2024-07-11 19:36 UTC (permalink / raw)
To: Vlastimil Babka
Cc: Mateusz Guzik, Akinobu Mita, Alexei Starovoitov, Daniel Borkmann,
John Fastabend, Andrii Nakryiko, Martin KaFai Lau,
Eduard Zingerman, Song Liu, Yonghong Song, KP Singh,
Stanislav Fomichev, Hao Luo, Jiri Olsa, Christoph Lameter,
David Rientjes, Roman Gushchin, Hyeonggon Yoo, linux-kernel, bpf,
linux-mm
On Thu, 11 Jul 2024 18:35:29 +0200 Vlastimil Babka <vbabka@suse.cz> wrote:
> These two patches largely revert commits that added function call
> overhead into slab and page allocation hotpaths and that cannot be
> currently disabled even though related CONFIG_ options do exist.
Five years ago. I assume the overall overhead is small?
^ permalink raw reply [flat|nested] 5+ messages in thread
* Re: [PATCH 0/2] revert unconditional slab and page allocator fault injection calls
2024-07-11 19:36 ` [PATCH 0/2] revert unconditional slab and page allocator fault injection calls Andrew Morton
@ 2024-07-12 7:19 ` Vlastimil Babka
0 siblings, 0 replies; 5+ messages in thread
From: Vlastimil Babka @ 2024-07-12 7:19 UTC (permalink / raw)
To: Andrew Morton
Cc: Mateusz Guzik, Akinobu Mita, Alexei Starovoitov, Daniel Borkmann,
John Fastabend, Andrii Nakryiko, Martin KaFai Lau,
Eduard Zingerman, Song Liu, Yonghong Song, KP Singh,
Stanislav Fomichev, Hao Luo, Jiri Olsa, Christoph Lameter,
David Rientjes, Roman Gushchin, Hyeonggon Yoo, linux-kernel, bpf,
linux-mm
On 7/11/24 9:36 PM, Andrew Morton wrote:
> On Thu, 11 Jul 2024 18:35:29 +0200 Vlastimil Babka <vbabka@suse.cz> wrote:
>
>> These two patches largely revert commits that added function call
>> overhead into slab and page allocation hotpaths and that cannot be
>> currently disabled even though related CONFIG_ options do exist.
>
> Five years ago. I assume the overall overhead is small?
Well, what made me look into this in the first place was seeing
should_failslab() in perf profiles at 1-2% even though it was an empty
function that just immediately returned.
In [1] I posted some measurements that was not even a microbenchmark:
To demonstrate the reduced overhead of calling an empty
should_failslab() function, a kernel build with
CONFIG_FUNCTION_ERROR_INJECTION enabled but CONFIG_FAILSLAB disabled,
and CPU mitigations enabled, was used in a qemu-kvm (virtme-ng) on AMD
Ryzen 7 2700 machine, and execution of a program trying to open() a
non-existent file was measured 3 times:
for (int i = 0; i < 10000000; i++) {
open("non_existent", O_RDONLY);
}
After this patch, the measured real time was 4.3% smaller. Using perf
profiling it was verified that should_failslab was gone from the
profile.
Later I found that this CPU mitigations were really important here as
function calls are more expensive. With them disabled that benchmark was in
a noise, so I wasn't sure about claiming that number in the patch itself.
But I assume a microbenchmark would still demonstrate some overhead. Yet
ultimately I think the overhead is just plain unnecessary to pay when error
injection is not being performed, and also CPU mitigations enabled are
usually the default, so it's best get rid of it.
[1]
https://lore.kernel.org/all/20240620-fault-injection-statickeys-v2-0-e23947d3d84b@suse.cz/#t
^ permalink raw reply [flat|nested] 5+ messages in thread