1 | // SPDX-License-Identifier: GPL-2.0 |
2 | #include <linux/fault-inject.h> |
3 | #include <linux/error-injection.h> |
4 | #include <linux/debugfs.h> |
5 | #include <linux/slab.h> |
6 | #include <linux/mm.h> |
7 | #include "slab.h" |
8 | |
9 | static struct { |
10 | struct fault_attr attr; |
11 | bool ignore_gfp_reclaim; |
12 | bool cache_filter; |
13 | } failslab = { |
14 | .attr = FAULT_ATTR_INITIALIZER, |
15 | .ignore_gfp_reclaim = true, |
16 | .cache_filter = false, |
17 | }; |
18 | |
19 | int should_failslab(struct kmem_cache *s, gfp_t gfpflags) |
20 | { |
21 | int flags = 0; |
22 | |
23 | /* No fault-injection for bootstrap cache */ |
24 | if (unlikely(s == kmem_cache)) |
25 | return 0; |
26 | |
27 | if (gfpflags & __GFP_NOFAIL) |
28 | return 0; |
29 | |
30 | if (failslab.ignore_gfp_reclaim && |
31 | (gfpflags & __GFP_DIRECT_RECLAIM)) |
32 | return 0; |
33 | |
34 | if (failslab.cache_filter && !(s->flags & SLAB_FAILSLAB)) |
35 | return 0; |
36 | |
37 | /* |
38 | * In some cases, it expects to specify __GFP_NOWARN |
39 | * to avoid printing any information(not just a warning), |
40 | * thus avoiding deadlocks. See commit 6b9dbedbe349 for |
41 | * details. |
42 | */ |
43 | if (gfpflags & __GFP_NOWARN) |
44 | flags |= FAULT_NOWARN; |
45 | |
46 | return should_fail_ex(attr: &failslab.attr, size: s->object_size, flags) ? -ENOMEM : 0; |
47 | } |
48 | ALLOW_ERROR_INJECTION(should_failslab, ERRNO); |
49 | |
50 | static int __init setup_failslab(char *str) |
51 | { |
52 | return setup_fault_attr(attr: &failslab.attr, str); |
53 | } |
54 | __setup("failslab=" , setup_failslab); |
55 | |
56 | #ifdef CONFIG_FAULT_INJECTION_DEBUG_FS |
57 | static int __init failslab_debugfs_init(void) |
58 | { |
59 | struct dentry *dir; |
60 | umode_t mode = S_IFREG | 0600; |
61 | |
62 | dir = fault_create_debugfs_attr(name: "failslab" , NULL, attr: &failslab.attr); |
63 | if (IS_ERR(ptr: dir)) |
64 | return PTR_ERR(ptr: dir); |
65 | |
66 | debugfs_create_bool(name: "ignore-gfp-wait" , mode, parent: dir, |
67 | value: &failslab.ignore_gfp_reclaim); |
68 | debugfs_create_bool(name: "cache-filter" , mode, parent: dir, |
69 | value: &failslab.cache_filter); |
70 | |
71 | return 0; |
72 | } |
73 | |
74 | late_initcall(failslab_debugfs_init); |
75 | |
76 | #endif /* CONFIG_FAULT_INJECTION_DEBUG_FS */ |
77 | |