When we specify __GFP_NOWARN, we only expect that no warnings will be issued for current caller. But in the __should_failslab() and __should_fail_alloc_page(), the local GFP flags alter the global {failslab|fail_page_alloc}.attr, which is persistent and shared by all tasks. This is not what we expected, let's fix it. [akpm@linux-foundation.org: unexport should_fail_ex()] Link: https://lkml.kernel.org/r/20221118100011.2634-1-zhengqi.arch@bytedance.com Fixes: 3f913fc5f974 ("mm: fix missing handler for __GFP_NOWARN") Signed-off-by: Qi Zheng <zhengqi.arch@bytedance.com> Reported-by: Dmitry Vyukov <dvyukov@google.com> Reviewed-by: Akinobu Mita <akinobu.mita@gmail.com> Reviewed-by: Jason Gunthorpe <jgg@nvidia.com> Cc: Akinobu Mita <akinobu.mita@gmail.com> Cc: Matthew Wilcox <willy@infradead.org> Cc: <stable@vger.kernel.org> Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
Unified · Split
| @@ -20,7 +20,6 @@ struct fault_attr { · 19 unmodified lines | ||
| 20 | 20 | atomic_t space; |
| 21 | 21 | unsigned long verbose; |
| 22 | 22 | bool task_filter; |
| 23 | − bool no_warn; | |
| 24 | 23 | unsigned long stacktrace_depth; |
| 25 | 24 | unsigned long require_start; |
| 26 | 25 | unsigned long require_end; |
| @@ -32,6 +31,10 @@ struct fault_attr { · 5 unmodified lines | ||
| 32 | 31 | struct dentry *dname; |
| 33 | 32 | }; |
| 34 | 33 | |
| 34 | +enum fault_flags { | |
| 35 | + FAULT_NOWARN = 1 << 0, | |
| 36 | +}; | |
| 37 | + | |
| 35 | 38 | #define FAULT_ATTR_INITIALIZER { \ |
| 36 | 39 | .interval = 1, \ |
| 37 | 40 | .times = ATOMIC_INIT(1), \ |
| @@ -40,11 +43,11 @@ struct fault_attr { · 2 unmodified lines | ||
| 40 | 43 | .ratelimit_state = RATELIMIT_STATE_INIT_DISABLED, \ |
| 41 | 44 | .verbose = 2, \ |
| 42 | 45 | .dname = NULL, \ |
| 43 | − .no_warn = false, \ | |
| 44 | 46 | } |
| 45 | 47 | |
| 46 | 48 | #define DECLARE_FAULT_ATTR(name) struct fault_attr name = FAULT_ATTR_INITIALIZER |
| 47 | 49 | int setup_fault_attr(struct fault_attr *attr, char *str); |
| 50 | +bool should_fail_ex(struct fault_attr *attr, ssize_t size, int flags); | |
| 48 | 51 | bool should_fail(struct fault_attr *attr, ssize_t size); |
| 49 | 52 | |
| 50 | 53 | #ifdef CONFIG_FAULT_INJECTION_DEBUG_FS |
| @@ -41,9 +41,6 @@ EXPORT_SYMBOL_GPL(setup_fault_attr); · 40 unmodified lines | ||
| 41 | 41 | |
| 42 | 42 | static void fail_dump(struct fault_attr *attr) |
| 43 | 43 | { |
| 44 | − if (attr->no_warn) | |
| 45 | − return; | |
| 46 | − | |
| 47 | 44 | if (attr->verbose > 0 && __ratelimit(&attr->ratelimit_state)) { |
| 48 | 45 | printk(KERN_NOTICE "FAULT_INJECTION: forcing a failure.\n" |
| 49 | 46 | "name %pd, interval %lu, probability %lu, " |
| @@ -103,7 +100,7 @@ static inline bool fail_stacktrace(struct fault_attr *attr) · 53 unmodified lines | ||
| 103 | 100 | * http://www.nongnu.org/failmalloc/ |
| 104 | 101 | */ |
| 105 | 102 | |
| 106 | −bool should_fail(struct fault_attr *attr, ssize_t size) | |
| 103 | +bool should_fail_ex(struct fault_attr *attr, ssize_t size, int flags) | |
| 107 | 104 | { |
| 108 | 105 | if (in_task()) { |
| 109 | 106 | unsigned int fail_nth = READ_ONCE(current->fail_nth); |
| @@ -146,13 +143,19 @@ bool should_fail(struct fault_attr *attr, ssize_t size) · 36 unmodified lines | ||
| 146 | 143 | return false; |
| 147 | 144 | |
| 148 | 145 | fail: |
| 149 | − fail_dump(attr); | |
| 146 | + if (!(flags & FAULT_NOWARN)) | |
| 147 | + fail_dump(attr); | |
| 150 | 148 | |
| 151 | 149 | if (atomic_read(&attr->times) != -1) |
| 152 | 150 | atomic_dec_not_zero(&attr->times); |
| 153 | 151 | |
| 154 | 152 | return true; |
| 155 | 153 | } |
| 154 | + | |
| 155 | +bool should_fail(struct fault_attr *attr, ssize_t size) | |
| 156 | +{ | |
| 157 | + return should_fail_ex(attr, size, 0); | |
| 158 | +} | |
| 156 | 159 | EXPORT_SYMBOL_GPL(should_fail); |
| 157 | 160 | |
| 158 | 161 | #ifdef CONFIG_FAULT_INJECTION_DEBUG_FS |
| @@ -16,6 +16,8 @@ static struct { · 15 unmodified lines | ||
| 16 | 16 | |
| 17 | 17 | bool __should_failslab(struct kmem_cache *s, gfp_t gfpflags) |
| 18 | 18 | { |
| 19 | + int flags = 0; | |
| 20 | + | |
| 19 | 21 | /* No fault-injection for bootstrap cache */ |
| 20 | 22 | if (unlikely(s == kmem_cache)) |
| 21 | 23 | return false; |
| @@ -30,10 +32,16 @@ bool __should_failslab(struct kmem_cache *s, gfp_t gfpflags) · 8 unmodified lines | ||
| 30 | 32 | if (failslab.cache_filter && !(s->flags & SLAB_FAILSLAB)) |
| 31 | 33 | return false; |
| 32 | 34 | |
| 35 | + /* | |
| 36 | + * In some cases, it expects to specify __GFP_NOWARN | |
| 37 | + * to avoid printing any information(not just a warning), | |
| 38 | + * thus avoiding deadlocks. See commit 6b9dbedbe349 for | |
| 39 | + * details. | |
| 40 | + */ | |
| 33 | 41 | if (gfpflags & __GFP_NOWARN) |
| 34 | − failslab.attr.no_warn = true; | |
| 42 | + flags |= FAULT_NOWARN; | |
| 35 | 43 | |
| 36 | − return should_fail(&failslab.attr, s->object_size); | |
| 44 | + return should_fail_ex(&failslab.attr, s->object_size, flags); | |
| 37 | 45 | } |
| 38 | 46 | |
| 39 | 47 | static int __init setup_failslab(char *str) |
| @@ -3887,6 +3887,8 @@ __setup("fail_page_alloc=", setup_fail_page_alloc); · 3886 unmodified lines | ||
| 3887 | 3887 | |
| 3888 | 3888 | static bool __should_fail_alloc_page(gfp_t gfp_mask, unsigned int order) |
| 3889 | 3889 | { |
| 3890 | + int flags = 0; | |
| 3891 | + | |
| 3890 | 3892 | if (order < fail_page_alloc.min_order) |
| 3891 | 3893 | return false; |
| 3892 | 3894 | if (gfp_mask & __GFP_NOFAIL) |
| @@ -3897,10 +3899,11 @@ static bool __should_fail_alloc_page(gfp_t gfp_mask, unsigned int order) · 4 unmodified lines | ||
| 3897 | 3899 | (gfp_mask & __GFP_DIRECT_RECLAIM)) |
| 3898 | 3900 | return false; |
| 3899 | 3901 | |
| 3902 | + /* See comment in __should_failslab() */ | |
| 3900 | 3903 | if (gfp_mask & __GFP_NOWARN) |
| 3901 | − fail_page_alloc.attr.no_warn = true; | |
| 3904 | + flags |= FAULT_NOWARN; | |
| 3902 | 3905 | |
| 3903 | − return should_fail(&fail_page_alloc.attr, 1 << order); | |
| 3906 | + return should_fail_ex(&fail_page_alloc.attr, 1 << order, flags); | |
| 3904 | 3907 | } |
| 3905 | 3908 | |
| 3906 | 3909 | #ifdef CONFIG_FAULT_INJECTION_DEBUG_FS |