2022-05-11 09:46:56

by Qi Zheng

[permalink] [raw]
Subject: [PATCH v2 1/2] mm: fix missing handler for __GFP_NOWARN

We expect no warnings to be issued when we specify __GFP_NOWARN, but
currently in paths like alloc_pages() and kmalloc(), there are still
some warnings printed, fix it.

But for some warnings that report usage problems, we don't deal with
them. If such warnings are printed, then we should fix the usage
problems. Such as the following case:

WARN_ON_ONCE((gfp_flags & __GFP_NOFAIL) && (order > 1));

Signed-off-by: Qi Zheng <[email protected]>
---
include/linux/fault-inject.h | 2 ++
lib/fault-inject.c | 3 +++
mm/failslab.c | 3 +++
mm/internal.h | 15 +++++++++++++++
mm/page_alloc.c | 18 ++++++++++--------
5 files changed, 33 insertions(+), 8 deletions(-)

diff --git a/include/linux/fault-inject.h b/include/linux/fault-inject.h
index 2d04f6448cde..9f6e25467844 100644
--- a/include/linux/fault-inject.h
+++ b/include/linux/fault-inject.h
@@ -20,6 +20,7 @@ struct fault_attr {
atomic_t space;
unsigned long verbose;
bool task_filter;
+ bool no_warn;
unsigned long stacktrace_depth;
unsigned long require_start;
unsigned long require_end;
@@ -39,6 +40,7 @@ struct fault_attr {
.ratelimit_state = RATELIMIT_STATE_INIT_DISABLED, \
.verbose = 2, \
.dname = NULL, \
+ .no_warn = false, \
}

#define DECLARE_FAULT_ATTR(name) struct fault_attr name = FAULT_ATTR_INITIALIZER
diff --git a/lib/fault-inject.c b/lib/fault-inject.c
index ce12621b4275..423784d9c058 100644
--- a/lib/fault-inject.c
+++ b/lib/fault-inject.c
@@ -41,6 +41,9 @@ EXPORT_SYMBOL_GPL(setup_fault_attr);

static void fail_dump(struct fault_attr *attr)
{
+ if (attr->no_warn)
+ return;
+
if (attr->verbose > 0 && __ratelimit(&attr->ratelimit_state)) {
printk(KERN_NOTICE "FAULT_INJECTION: forcing a failure.\n"
"name %pd, interval %lu, probability %lu, "
diff --git a/mm/failslab.c b/mm/failslab.c
index f92fed91ac23..58df9789f1d2 100644
--- a/mm/failslab.c
+++ b/mm/failslab.c
@@ -30,6 +30,9 @@ bool __should_failslab(struct kmem_cache *s, gfp_t gfpflags)
if (failslab.cache_filter && !(s->flags & SLAB_FAILSLAB))
return false;

+ if (gfpflags & __GFP_NOWARN)
+ failslab.attr.no_warn = true;
+
return should_fail(&failslab.attr, s->object_size);
}

diff --git a/mm/internal.h b/mm/internal.h
index e3e50af20706..34fdedb9986f 100644
--- a/mm/internal.h
+++ b/mm/internal.h
@@ -35,6 +35,21 @@ struct folio_batch;
/* Do not use these with a slab allocator */
#define GFP_SLAB_BUG_MASK (__GFP_DMA32|__GFP_HIGHMEM|~__GFP_BITS_MASK)

+/*
+ * Different from WARN_ON_ONCE(), no warning will be issued
+ * when we specify __GFP_NOWARN.
+ */
+#define WARN_ON_ONCE_GFP(cond, gfp) ({ \
+ static bool __section(".data.once") __warned; \
+ int __ret_warn_once = !!(cond); \
+ \
+ if (unlikely(!(gfp & __GFP_NOWARN) && __ret_warn_once && !__warned)) { \
+ __warned = true; \
+ WARN_ON(1); \
+ } \
+ unlikely(__ret_warn_once); \
+})
+
void page_writeback_init(void);

static inline void *folio_raw_mapping(struct folio *folio)
diff --git a/mm/page_alloc.c b/mm/page_alloc.c
index 65f892af1d4f..f9f329403d76 100644
--- a/mm/page_alloc.c
+++ b/mm/page_alloc.c
@@ -3789,6 +3789,9 @@ static bool __should_fail_alloc_page(gfp_t gfp_mask, unsigned int order)
(gfp_mask & __GFP_DIRECT_RECLAIM))
return false;

+ if (gfp_mask & __GFP_NOWARN)
+ fail_page_alloc.attr.no_warn = true;
+
return should_fail(&fail_page_alloc.attr, 1 << order);
}

@@ -4337,7 +4340,8 @@ __alloc_pages_may_oom(gfp_t gfp_mask, unsigned int order,
*/

/* Exhausted what can be done so it's blame time */
- if (out_of_memory(&oc) || WARN_ON_ONCE(gfp_mask & __GFP_NOFAIL)) {
+ if (out_of_memory(&oc) ||
+ WARN_ON_ONCE_GFP(gfp_mask & __GFP_NOFAIL, gfp_mask)) {
*did_some_progress = 1;

/*
@@ -5103,7 +5107,7 @@ __alloc_pages_slowpath(gfp_t gfp_mask, unsigned int order,
* All existing users of the __GFP_NOFAIL are blockable, so warn
* of any new users that actually require GFP_NOWAIT
*/
- if (WARN_ON_ONCE(!can_direct_reclaim))
+ if (WARN_ON_ONCE_GFP(!can_direct_reclaim, gfp_mask))
goto fail;

/*
@@ -5111,7 +5115,7 @@ __alloc_pages_slowpath(gfp_t gfp_mask, unsigned int order,
* because we cannot reclaim anything and only can loop waiting
* for somebody to do a work for us
*/
- WARN_ON_ONCE(current->flags & PF_MEMALLOC);
+ WARN_ON_ONCE_GFP(current->flags & PF_MEMALLOC, gfp_mask);

/*
* non failing costly orders are a hard requirement which we
@@ -5119,7 +5123,7 @@ __alloc_pages_slowpath(gfp_t gfp_mask, unsigned int order,
* so that we can identify them and convert them to something
* else.
*/
- WARN_ON_ONCE(order > PAGE_ALLOC_COSTLY_ORDER);
+ WARN_ON_ONCE_GFP(order > PAGE_ALLOC_COSTLY_ORDER, gfp_mask);

/*
* Help non-failing allocations by giving them access to memory
@@ -5365,10 +5369,8 @@ struct page *__alloc_pages(gfp_t gfp, unsigned int order, int preferred_nid,
* There are several places where we assume that the order value is sane
* so bail out early if the request is out of bound.
*/
- if (unlikely(order >= MAX_ORDER)) {
- WARN_ON_ONCE(!(gfp & __GFP_NOWARN));
+ if (WARN_ON_ONCE_GFP(order >= MAX_ORDER, gfp))
return NULL;
- }

gfp &= gfp_allowed_mask;
/*
@@ -9020,7 +9022,7 @@ int __alloc_contig_migrate_range(struct compact_control *cc,

lru_cache_enable();
if (ret < 0) {
- if (ret == -EBUSY)
+ if (!(cc->gfp_mask & __GFP_NOWARN) && ret == -EBUSY)
alloc_contig_dump_pages(&cc->migratepages);
putback_movable_pages(&cc->migratepages);
return ret;
--
2.20.1



2022-05-11 09:50:56

by Qi Zheng

[permalink] [raw]
Subject: [PATCH v2 2/2] tty: fix deadlock caused by calling printk() under tty_port->lock

The pty_write() invokes kmalloc() which may invoke a normal printk() to
print failure message. This can cause a deadlock in the scenario reported
by syz-bot below:

CPU0 CPU1 CPU2
---- ---- ----
lock(console_owner);
lock(&port_lock_key);
lock(&port->lock);
lock(&port_lock_key);
lock(&port->lock);
lock(console_owner);

As commit dbdda842fe96 ("printk: Add console owner and waiter logic to
load balance console writes") said, such deadlock can be prevented by
using printk_deferred() in kmalloc() (which is invoked in the section
guarded by the port->lock). But there are too many printk() on the
kmalloc() path, and kmalloc() can be called from anywhere, so changing
printk() to printk_deferred() is too complicated and inelegant.

Therefore, this patch chooses to specify __GFP_NOWARN to kmalloc(), so
that printk() will not be called, and this deadlock problem can be avoided.

Syz-bot reported the following lockdep error:

======================================================
WARNING: possible circular locking dependency detected
5.4.143-00237-g08ccc19a-dirty #10 Not tainted
------------------------------------------------------
syz-executor.4/29420 is trying to acquire lock:
ffffffff8aedb2a0 (console_owner){....}-{0:0}, at: console_trylock_spinning kernel/printk/printk.c:1752 [inline]
ffffffff8aedb2a0 (console_owner){....}-{0:0}, at: vprintk_emit+0x2ca/0x470 kernel/printk/printk.c:2023

but task is already holding lock:
ffff8880119c9158 (&port->lock){-.-.}-{2:2}, at: pty_write+0xf4/0x1f0 drivers/tty/pty.c:120

which lock already depends on the new lock.

the existing dependency chain (in reverse order) is:

-> #2 (&port->lock){-.-.}-{2:2}:
__raw_spin_lock_irqsave include/linux/spinlock_api_smp.h:110 [inline]
_raw_spin_lock_irqsave+0x35/0x50 kernel/locking/spinlock.c:159
tty_port_tty_get drivers/tty/tty_port.c:288 [inline] <-- lock(&port->lock);
tty_port_default_wakeup+0x1d/0xb0 drivers/tty/tty_port.c:47
serial8250_tx_chars+0x530/0xa80 drivers/tty/serial/8250/8250_port.c:1767
serial8250_handle_irq.part.0+0x31f/0x3d0 drivers/tty/serial/8250/8250_port.c:1854
serial8250_handle_irq drivers/tty/serial/8250/8250_port.c:1827 [inline] <-- lock(&port_lock_key);
serial8250_default_handle_irq+0xb2/0x220 drivers/tty/serial/8250/8250_port.c:1870
serial8250_interrupt+0xfd/0x200 drivers/tty/serial/8250/8250_core.c:126
__handle_irq_event_percpu+0x109/0xa50 kernel/irq/handle.c:156
[...]

-> #1 (&port_lock_key){-.-.}-{2:2}:
__raw_spin_lock_irqsave include/linux/spinlock_api_smp.h:110 [inline]
_raw_spin_lock_irqsave+0x35/0x50 kernel/locking/spinlock.c:159
serial8250_console_write+0x184/0xa40 drivers/tty/serial/8250/8250_port.c:3198
<-- lock(&port_lock_key);
call_console_drivers kernel/printk/printk.c:1819 [inline]
console_unlock+0x8cb/0xd00 kernel/printk/printk.c:2504
vprintk_emit+0x1b5/0x470 kernel/printk/printk.c:2024 <-- lock(console_owner);
vprintk_func+0x8d/0x250 kernel/printk/printk_safe.c:394
printk+0xba/0xed kernel/printk/printk.c:2084
register_console+0x8b3/0xc10 kernel/printk/printk.c:2829
univ8250_console_init+0x3a/0x46 drivers/tty/serial/8250/8250_core.c:681
console_init+0x49d/0x6d3 kernel/printk/printk.c:2915
start_kernel+0x5e9/0x879 init/main.c:713
secondary_startup_64+0xa4/0xb0 arch/x86/kernel/head_64.S:241

-> #0 (console_owner){....}-{0:0}:
[...]
lock_acquire+0x127/0x340 kernel/locking/lockdep.c:4734
console_trylock_spinning kernel/printk/printk.c:1773 [inline] <-- lock(console_owner);
vprintk_emit+0x307/0x470 kernel/printk/printk.c:2023
vprintk_func+0x8d/0x250 kernel/printk/printk_safe.c:394
printk+0xba/0xed kernel/printk/printk.c:2084
fail_dump lib/fault-inject.c:45 [inline]
should_fail+0x67b/0x7c0 lib/fault-inject.c:144
__should_failslab+0x152/0x1c0 mm/failslab.c:33
should_failslab+0x5/0x10 mm/slab_common.c:1224
slab_pre_alloc_hook mm/slab.h:468 [inline]
slab_alloc_node mm/slub.c:2723 [inline]
slab_alloc mm/slub.c:2807 [inline]
__kmalloc+0x72/0x300 mm/slub.c:3871
kmalloc include/linux/slab.h:582 [inline]
tty_buffer_alloc+0x23f/0x2a0 drivers/tty/tty_buffer.c:175
__tty_buffer_request_room+0x156/0x2a0 drivers/tty/tty_buffer.c:273
tty_insert_flip_string_fixed_flag+0x93/0x250 drivers/tty/tty_buffer.c:318
tty_insert_flip_string include/linux/tty_flip.h:37 [inline]
pty_write+0x126/0x1f0 drivers/tty/pty.c:122 <-- lock(&port->lock);
n_tty_write+0xa7a/0xfc0 drivers/tty/n_tty.c:2356
do_tty_write drivers/tty/tty_io.c:961 [inline]
tty_write+0x512/0x930 drivers/tty/tty_io.c:1045
__vfs_write+0x76/0x100 fs/read_write.c:494
[...]

other info that might help us debug this:

Chain exists of:
console_owner --> &port_lock_key --> &port->lock

Fixes: b6da31b2c07c ("tty: Fix data race in tty_insert_flip_string_fixed_flag")
Signed-off-by: Qi Zheng <[email protected]>
Acked-by: Jiri Slaby <[email protected]>
---
drivers/tty/tty_buffer.c | 3 ++-
1 file changed, 2 insertions(+), 1 deletion(-)

diff --git a/drivers/tty/tty_buffer.c b/drivers/tty/tty_buffer.c
index 646510476c30..bfa431a8e690 100644
--- a/drivers/tty/tty_buffer.c
+++ b/drivers/tty/tty_buffer.c
@@ -175,7 +175,8 @@ static struct tty_buffer *tty_buffer_alloc(struct tty_port *port, size_t size)
*/
if (atomic_read(&port->buf.mem_used) > port->buf.mem_limit)
return NULL;
- p = kmalloc(sizeof(struct tty_buffer) + 2 * size, GFP_ATOMIC);
+ p = kmalloc(sizeof(struct tty_buffer) + 2 * size,
+ GFP_ATOMIC | __GFP_NOWARN);
if (p == NULL)
return NULL;

--
2.20.1


2022-05-11 09:59:21

by Qi Zheng

[permalink] [raw]
Subject: Re: [PATCH v2 2/2] tty: fix deadlock caused by calling printk() under tty_port->lock



On 2022/5/11 2:19 PM, Qi Zheng wrote:
> The pty_write() invokes kmalloc() which may invoke a normal printk() to
> print failure message. This can cause a deadlock in the scenario reported
> by syz-bot below:
>
> CPU0 CPU1 CPU2
> ---- ---- ----
> lock(console_owner);
> lock(&port_lock_key);
> lock(&port->lock);
> lock(&port_lock_key);
> lock(&port->lock);
> lock(console_owner);
>
> As commit dbdda842fe96 ("printk: Add console owner and waiter logic to
> load balance console writes") said, such deadlock can be prevented by
> using printk_deferred() in kmalloc() (which is invoked in the section
> guarded by the port->lock). But there are too many printk() on the
> kmalloc() path, and kmalloc() can be called from anywhere, so changing
> printk() to printk_deferred() is too complicated and inelegant.
>
> Therefore, this patch chooses to specify __GFP_NOWARN to kmalloc(), so
> that printk() will not be called, and this deadlock problem can be avoided.
>
> Syz-bot reported the following lockdep error:
>
> ======================================================
> WARNING: possible circular locking dependency detected
> 5.4.143-00237-g08ccc19a-dirty #10 Not tainted
> ------------------------------------------------------
> syz-executor.4/29420 is trying to acquire lock:
> ffffffff8aedb2a0 (console_owner){....}-{0:0}, at: console_trylock_spinning kernel/printk/printk.c:1752 [inline]
> ffffffff8aedb2a0 (console_owner){....}-{0:0}, at: vprintk_emit+0x2ca/0x470 kernel/printk/printk.c:2023
>
> but task is already holding lock:
> ffff8880119c9158 (&port->lock){-.-.}-{2:2}, at: pty_write+0xf4/0x1f0 drivers/tty/pty.c:120
>
> which lock already depends on the new lock.
>
> the existing dependency chain (in reverse order) is:
>
> -> #2 (&port->lock){-.-.}-{2:2}:
> __raw_spin_lock_irqsave include/linux/spinlock_api_smp.h:110 [inline]
> _raw_spin_lock_irqsave+0x35/0x50 kernel/locking/spinlock.c:159
> tty_port_tty_get drivers/tty/tty_port.c:288 [inline] <-- lock(&port->lock);
> tty_port_default_wakeup+0x1d/0xb0 drivers/tty/tty_port.c:47
> serial8250_tx_chars+0x530/0xa80 drivers/tty/serial/8250/8250_port.c:1767
> serial8250_handle_irq.part.0+0x31f/0x3d0 drivers/tty/serial/8250/8250_port.c:1854
> serial8250_handle_irq drivers/tty/serial/8250/8250_port.c:1827 [inline] <-- lock(&port_lock_key);
> serial8250_default_handle_irq+0xb2/0x220 drivers/tty/serial/8250/8250_port.c:1870
> serial8250_interrupt+0xfd/0x200 drivers/tty/serial/8250/8250_core.c:126
> __handle_irq_event_percpu+0x109/0xa50 kernel/irq/handle.c:156
> [...]
>
> -> #1 (&port_lock_key){-.-.}-{2:2}:
> __raw_spin_lock_irqsave include/linux/spinlock_api_smp.h:110 [inline]
> _raw_spin_lock_irqsave+0x35/0x50 kernel/locking/spinlock.c:159
> serial8250_console_write+0x184/0xa40 drivers/tty/serial/8250/8250_port.c:3198
> <-- lock(&port_lock_key);
> call_console_drivers kernel/printk/printk.c:1819 [inline]
> console_unlock+0x8cb/0xd00 kernel/printk/printk.c:2504
> vprintk_emit+0x1b5/0x470 kernel/printk/printk.c:2024 <-- lock(console_owner);
> vprintk_func+0x8d/0x250 kernel/printk/printk_safe.c:394
> printk+0xba/0xed kernel/printk/printk.c:2084
> register_console+0x8b3/0xc10 kernel/printk/printk.c:2829
> univ8250_console_init+0x3a/0x46 drivers/tty/serial/8250/8250_core.c:681
> console_init+0x49d/0x6d3 kernel/printk/printk.c:2915
> start_kernel+0x5e9/0x879 init/main.c:713
> secondary_startup_64+0xa4/0xb0 arch/x86/kernel/head_64.S:241
>
> -> #0 (console_owner){....}-{0:0}:
> [...]
> lock_acquire+0x127/0x340 kernel/locking/lockdep.c:4734
> console_trylock_spinning kernel/printk/printk.c:1773 [inline] <-- lock(console_owner);
> vprintk_emit+0x307/0x470 kernel/printk/printk.c:2023
> vprintk_func+0x8d/0x250 kernel/printk/printk_safe.c:394
> printk+0xba/0xed kernel/printk/printk.c:2084
> fail_dump lib/fault-inject.c:45 [inline]
> should_fail+0x67b/0x7c0 lib/fault-inject.c:144
> __should_failslab+0x152/0x1c0 mm/failslab.c:33
> should_failslab+0x5/0x10 mm/slab_common.c:1224
> slab_pre_alloc_hook mm/slab.h:468 [inline]
> slab_alloc_node mm/slub.c:2723 [inline]
> slab_alloc mm/slub.c:2807 [inline]
> __kmalloc+0x72/0x300 mm/slub.c:3871
> kmalloc include/linux/slab.h:582 [inline]
> tty_buffer_alloc+0x23f/0x2a0 drivers/tty/tty_buffer.c:175
> __tty_buffer_request_room+0x156/0x2a0 drivers/tty/tty_buffer.c:273
> tty_insert_flip_string_fixed_flag+0x93/0x250 drivers/tty/tty_buffer.c:318
> tty_insert_flip_string include/linux/tty_flip.h:37 [inline]
> pty_write+0x126/0x1f0 drivers/tty/pty.c:122 <-- lock(&port->lock);
> n_tty_write+0xa7a/0xfc0 drivers/tty/n_tty.c:2356
> do_tty_write drivers/tty/tty_io.c:961 [inline]
> tty_write+0x512/0x930 drivers/tty/tty_io.c:1045
> __vfs_write+0x76/0x100 fs/read_write.c:494
> [...]
>
> other info that might help us debug this:
>
> Chain exists of:
> console_owner --> &port_lock_key --> &port->lock
>
> Fixes: b6da31b2c07c ("tty: Fix data race in tty_insert_flip_string_fixed_flag")
> Signed-off-by: Qi Zheng <[email protected]>
> Acked-by: Jiri Slaby <[email protected]>
> ---

Changelog in v1 -> v2:
- Update commit log

> drivers/tty/tty_buffer.c | 3 ++-
> 1 file changed, 2 insertions(+), 1 deletion(-)
>
> diff --git a/drivers/tty/tty_buffer.c b/drivers/tty/tty_buffer.c
> index 646510476c30..bfa431a8e690 100644
> --- a/drivers/tty/tty_buffer.c
> +++ b/drivers/tty/tty_buffer.c
> @@ -175,7 +175,8 @@ static struct tty_buffer *tty_buffer_alloc(struct tty_port *port, size_t size)
> */
> if (atomic_read(&port->buf.mem_used) > port->buf.mem_limit)
> return NULL;
> - p = kmalloc(sizeof(struct tty_buffer) + 2 * size, GFP_ATOMIC);
> + p = kmalloc(sizeof(struct tty_buffer) + 2 * size,
> + GFP_ATOMIC | __GFP_NOWARN);
> if (p == NULL)
> return NULL;
>

--
Thanks,
Qi

2022-05-11 10:43:06

by Greg Kroah-Hartman

[permalink] [raw]
Subject: Re: [PATCH v2 2/2] tty: fix deadlock caused by calling printk() under tty_port->lock

On Wed, May 11, 2022 at 02:19:51PM +0800, Qi Zheng wrote:
> The pty_write() invokes kmalloc() which may invoke a normal printk() to
> print failure message. This can cause a deadlock in the scenario reported
> by syz-bot below:
>
> CPU0 CPU1 CPU2
> ---- ---- ----
> lock(console_owner);
> lock(&port_lock_key);
> lock(&port->lock);
> lock(&port_lock_key);
> lock(&port->lock);
> lock(console_owner);
>
> As commit dbdda842fe96 ("printk: Add console owner and waiter logic to
> load balance console writes") said, such deadlock can be prevented by
> using printk_deferred() in kmalloc() (which is invoked in the section
> guarded by the port->lock). But there are too many printk() on the
> kmalloc() path, and kmalloc() can be called from anywhere, so changing
> printk() to printk_deferred() is too complicated and inelegant.
>
> Therefore, this patch chooses to specify __GFP_NOWARN to kmalloc(), so
> that printk() will not be called, and this deadlock problem can be avoided.
>
> Syz-bot reported the following lockdep error:
>
> ======================================================
> WARNING: possible circular locking dependency detected
> 5.4.143-00237-g08ccc19a-dirty #10 Not tainted
> ------------------------------------------------------
> syz-executor.4/29420 is trying to acquire lock:
> ffffffff8aedb2a0 (console_owner){....}-{0:0}, at: console_trylock_spinning kernel/printk/printk.c:1752 [inline]
> ffffffff8aedb2a0 (console_owner){....}-{0:0}, at: vprintk_emit+0x2ca/0x470 kernel/printk/printk.c:2023
>
> but task is already holding lock:
> ffff8880119c9158 (&port->lock){-.-.}-{2:2}, at: pty_write+0xf4/0x1f0 drivers/tty/pty.c:120
>
> which lock already depends on the new lock.
>
> the existing dependency chain (in reverse order) is:
>
> -> #2 (&port->lock){-.-.}-{2:2}:
> __raw_spin_lock_irqsave include/linux/spinlock_api_smp.h:110 [inline]
> _raw_spin_lock_irqsave+0x35/0x50 kernel/locking/spinlock.c:159
> tty_port_tty_get drivers/tty/tty_port.c:288 [inline] <-- lock(&port->lock);
> tty_port_default_wakeup+0x1d/0xb0 drivers/tty/tty_port.c:47
> serial8250_tx_chars+0x530/0xa80 drivers/tty/serial/8250/8250_port.c:1767
> serial8250_handle_irq.part.0+0x31f/0x3d0 drivers/tty/serial/8250/8250_port.c:1854
> serial8250_handle_irq drivers/tty/serial/8250/8250_port.c:1827 [inline] <-- lock(&port_lock_key);
> serial8250_default_handle_irq+0xb2/0x220 drivers/tty/serial/8250/8250_port.c:1870
> serial8250_interrupt+0xfd/0x200 drivers/tty/serial/8250/8250_core.c:126
> __handle_irq_event_percpu+0x109/0xa50 kernel/irq/handle.c:156
> [...]
>
> -> #1 (&port_lock_key){-.-.}-{2:2}:
> __raw_spin_lock_irqsave include/linux/spinlock_api_smp.h:110 [inline]
> _raw_spin_lock_irqsave+0x35/0x50 kernel/locking/spinlock.c:159
> serial8250_console_write+0x184/0xa40 drivers/tty/serial/8250/8250_port.c:3198
> <-- lock(&port_lock_key);
> call_console_drivers kernel/printk/printk.c:1819 [inline]
> console_unlock+0x8cb/0xd00 kernel/printk/printk.c:2504
> vprintk_emit+0x1b5/0x470 kernel/printk/printk.c:2024 <-- lock(console_owner);
> vprintk_func+0x8d/0x250 kernel/printk/printk_safe.c:394
> printk+0xba/0xed kernel/printk/printk.c:2084
> register_console+0x8b3/0xc10 kernel/printk/printk.c:2829
> univ8250_console_init+0x3a/0x46 drivers/tty/serial/8250/8250_core.c:681
> console_init+0x49d/0x6d3 kernel/printk/printk.c:2915
> start_kernel+0x5e9/0x879 init/main.c:713
> secondary_startup_64+0xa4/0xb0 arch/x86/kernel/head_64.S:241
>
> -> #0 (console_owner){....}-{0:0}:
> [...]
> lock_acquire+0x127/0x340 kernel/locking/lockdep.c:4734
> console_trylock_spinning kernel/printk/printk.c:1773 [inline] <-- lock(console_owner);
> vprintk_emit+0x307/0x470 kernel/printk/printk.c:2023
> vprintk_func+0x8d/0x250 kernel/printk/printk_safe.c:394
> printk+0xba/0xed kernel/printk/printk.c:2084
> fail_dump lib/fault-inject.c:45 [inline]
> should_fail+0x67b/0x7c0 lib/fault-inject.c:144
> __should_failslab+0x152/0x1c0 mm/failslab.c:33
> should_failslab+0x5/0x10 mm/slab_common.c:1224
> slab_pre_alloc_hook mm/slab.h:468 [inline]
> slab_alloc_node mm/slub.c:2723 [inline]
> slab_alloc mm/slub.c:2807 [inline]
> __kmalloc+0x72/0x300 mm/slub.c:3871
> kmalloc include/linux/slab.h:582 [inline]
> tty_buffer_alloc+0x23f/0x2a0 drivers/tty/tty_buffer.c:175
> __tty_buffer_request_room+0x156/0x2a0 drivers/tty/tty_buffer.c:273
> tty_insert_flip_string_fixed_flag+0x93/0x250 drivers/tty/tty_buffer.c:318
> tty_insert_flip_string include/linux/tty_flip.h:37 [inline]
> pty_write+0x126/0x1f0 drivers/tty/pty.c:122 <-- lock(&port->lock);
> n_tty_write+0xa7a/0xfc0 drivers/tty/n_tty.c:2356
> do_tty_write drivers/tty/tty_io.c:961 [inline]
> tty_write+0x512/0x930 drivers/tty/tty_io.c:1045
> __vfs_write+0x76/0x100 fs/read_write.c:494
> [...]
>
> other info that might help us debug this:
>
> Chain exists of:
> console_owner --> &port_lock_key --> &port->lock
>
> Fixes: b6da31b2c07c ("tty: Fix data race in tty_insert_flip_string_fixed_flag")
> Signed-off-by: Qi Zheng <[email protected]>
> Acked-by: Jiri Slaby <[email protected]>

Acked-by: Greg Kroah-Hartman <[email protected]>

2022-05-11 11:30:43

by Qi Zheng

[permalink] [raw]
Subject: Re: [PATCH v2 1/2] mm: fix missing handler for __GFP_NOWARN



On 2022/5/11 2:19 PM, Qi Zheng wrote:
> We expect no warnings to be issued when we specify __GFP_NOWARN, but
> currently in paths like alloc_pages() and kmalloc(), there are still
> some warnings printed, fix it.
>
> But for some warnings that report usage problems, we don't deal with
> them. If such warnings are printed, then we should fix the usage
> problems. Such as the following case:
>
> WARN_ON_ONCE((gfp_flags & __GFP_NOFAIL) && (order > 1));
>
> Signed-off-by: Qi Zheng <[email protected]>
> ---

Changelog in v1 -> v2:
- add comment to WARN_ON_ONCE_GFP
- handle __alloc_contig_migrate_range() case
- do not deal with:
WARN_ON_ONCE((gfp_flags & __GFP_NOFAIL) && (order > 1));

> include/linux/fault-inject.h | 2 ++
> lib/fault-inject.c | 3 +++
> mm/failslab.c | 3 +++
> mm/internal.h | 15 +++++++++++++++
> mm/page_alloc.c | 18 ++++++++++--------
> 5 files changed, 33 insertions(+), 8 deletions(-)
>
> diff --git a/include/linux/fault-inject.h b/include/linux/fault-inject.h
> index 2d04f6448cde..9f6e25467844 100644
> --- a/include/linux/fault-inject.h
> +++ b/include/linux/fault-inject.h
> @@ -20,6 +20,7 @@ struct fault_attr {
> atomic_t space;
> unsigned long verbose;
> bool task_filter;
> + bool no_warn;
> unsigned long stacktrace_depth;
> unsigned long require_start;
> unsigned long require_end;
> @@ -39,6 +40,7 @@ struct fault_attr {
> .ratelimit_state = RATELIMIT_STATE_INIT_DISABLED, \
> .verbose = 2, \
> .dname = NULL, \
> + .no_warn = false, \
> }
>
> #define DECLARE_FAULT_ATTR(name) struct fault_attr name = FAULT_ATTR_INITIALIZER
> diff --git a/lib/fault-inject.c b/lib/fault-inject.c
> index ce12621b4275..423784d9c058 100644
> --- a/lib/fault-inject.c
> +++ b/lib/fault-inject.c
> @@ -41,6 +41,9 @@ EXPORT_SYMBOL_GPL(setup_fault_attr);
>
> static void fail_dump(struct fault_attr *attr)
> {
> + if (attr->no_warn)
> + return;
> +
> if (attr->verbose > 0 && __ratelimit(&attr->ratelimit_state)) {
> printk(KERN_NOTICE "FAULT_INJECTION: forcing a failure.\n"
> "name %pd, interval %lu, probability %lu, "
> diff --git a/mm/failslab.c b/mm/failslab.c
> index f92fed91ac23..58df9789f1d2 100644
> --- a/mm/failslab.c
> +++ b/mm/failslab.c
> @@ -30,6 +30,9 @@ bool __should_failslab(struct kmem_cache *s, gfp_t gfpflags)
> if (failslab.cache_filter && !(s->flags & SLAB_FAILSLAB))
> return false;
>
> + if (gfpflags & __GFP_NOWARN)
> + failslab.attr.no_warn = true;
> +
> return should_fail(&failslab.attr, s->object_size);
> }
>
> diff --git a/mm/internal.h b/mm/internal.h
> index e3e50af20706..34fdedb9986f 100644
> --- a/mm/internal.h
> +++ b/mm/internal.h
> @@ -35,6 +35,21 @@ struct folio_batch;
> /* Do not use these with a slab allocator */
> #define GFP_SLAB_BUG_MASK (__GFP_DMA32|__GFP_HIGHMEM|~__GFP_BITS_MASK)
>
> +/*
> + * Different from WARN_ON_ONCE(), no warning will be issued
> + * when we specify __GFP_NOWARN.
> + */
> +#define WARN_ON_ONCE_GFP(cond, gfp) ({ \
> + static bool __section(".data.once") __warned; \
> + int __ret_warn_once = !!(cond); \
> + \
> + if (unlikely(!(gfp & __GFP_NOWARN) && __ret_warn_once && !__warned)) { \
> + __warned = true; \
> + WARN_ON(1); \
> + } \
> + unlikely(__ret_warn_once); \
> +})
> +
> void page_writeback_init(void);
>
> static inline void *folio_raw_mapping(struct folio *folio)
> diff --git a/mm/page_alloc.c b/mm/page_alloc.c
> index 65f892af1d4f..f9f329403d76 100644
> --- a/mm/page_alloc.c
> +++ b/mm/page_alloc.c
> @@ -3789,6 +3789,9 @@ static bool __should_fail_alloc_page(gfp_t gfp_mask, unsigned int order)
> (gfp_mask & __GFP_DIRECT_RECLAIM))
> return false;
>
> + if (gfp_mask & __GFP_NOWARN)
> + fail_page_alloc.attr.no_warn = true;
> +
> return should_fail(&fail_page_alloc.attr, 1 << order);
> }
>
> @@ -4337,7 +4340,8 @@ __alloc_pages_may_oom(gfp_t gfp_mask, unsigned int order,
> */
>
> /* Exhausted what can be done so it's blame time */
> - if (out_of_memory(&oc) || WARN_ON_ONCE(gfp_mask & __GFP_NOFAIL)) {
> + if (out_of_memory(&oc) ||
> + WARN_ON_ONCE_GFP(gfp_mask & __GFP_NOFAIL, gfp_mask)) {
> *did_some_progress = 1;
>
> /*
> @@ -5103,7 +5107,7 @@ __alloc_pages_slowpath(gfp_t gfp_mask, unsigned int order,
> * All existing users of the __GFP_NOFAIL are blockable, so warn
> * of any new users that actually require GFP_NOWAIT
> */
> - if (WARN_ON_ONCE(!can_direct_reclaim))
> + if (WARN_ON_ONCE_GFP(!can_direct_reclaim, gfp_mask))
> goto fail;
>
> /*
> @@ -5111,7 +5115,7 @@ __alloc_pages_slowpath(gfp_t gfp_mask, unsigned int order,
> * because we cannot reclaim anything and only can loop waiting
> * for somebody to do a work for us
> */
> - WARN_ON_ONCE(current->flags & PF_MEMALLOC);
> + WARN_ON_ONCE_GFP(current->flags & PF_MEMALLOC, gfp_mask);
>
> /*
> * non failing costly orders are a hard requirement which we
> @@ -5119,7 +5123,7 @@ __alloc_pages_slowpath(gfp_t gfp_mask, unsigned int order,
> * so that we can identify them and convert them to something
> * else.
> */
> - WARN_ON_ONCE(order > PAGE_ALLOC_COSTLY_ORDER);
> + WARN_ON_ONCE_GFP(order > PAGE_ALLOC_COSTLY_ORDER, gfp_mask);
>
> /*
> * Help non-failing allocations by giving them access to memory
> @@ -5365,10 +5369,8 @@ struct page *__alloc_pages(gfp_t gfp, unsigned int order, int preferred_nid,
> * There are several places where we assume that the order value is sane
> * so bail out early if the request is out of bound.
> */
> - if (unlikely(order >= MAX_ORDER)) {
> - WARN_ON_ONCE(!(gfp & __GFP_NOWARN));
> + if (WARN_ON_ONCE_GFP(order >= MAX_ORDER, gfp))
> return NULL;
> - }
>
> gfp &= gfp_allowed_mask;
> /*
> @@ -9020,7 +9022,7 @@ int __alloc_contig_migrate_range(struct compact_control *cc,
>
> lru_cache_enable();
> if (ret < 0) {
> - if (ret == -EBUSY)
> + if (!(cc->gfp_mask & __GFP_NOWARN) && ret == -EBUSY)
> alloc_contig_dump_pages(&cc->migratepages);
> putback_movable_pages(&cc->migratepages);
> return ret;

--
Thanks,
Qi