Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

tty/serial: do not free trasnmit buffer page under port lock

LKP has hit yet another circular locking dependency between uart
console drivers and debugobjects [1]:

CPU0 CPU1

rhltable_init()
__init_work()
debug_object_init
uart_shutdown() /* db->lock */
/* uart_port->lock */ debug_print_object()
free_page() printk()
call_console_drivers()
debug_check_no_obj_freed() /* uart_port->lock */
/* db->lock */
debug_print_object()

So there are two dependency chains:
uart_port->lock -> db->lock
And
db->lock -> uart_port->lock

This particular circular locking dependency can be addressed in several
ways:

a) One way would be to move debug_print_object() out of db->lock scope
and, thus, break the db->lock -> uart_port->lock chain.
b) Another one would be to free() transmit buffer page out of db->lock
in UART code; which is what this patch does.

It makes sense to apply a) and b) independently: there are too many things
going on behind free(), none of which depend on uart_port->lock.

The patch fixes transmit buffer page free() in uart_shutdown() and,
additionally, in uart_port_startup() (as was suggested by Dmitry Safonov).

[1] https://lore.kernel.org/lkml/20181211091154.GL23332@shao2-debian/T/#u
Signed-off-by: Sergey Senozhatsky <sergey.senozhatsky@gmail.com>
Reviewed-by: Petr Mladek <pmladek@suse.com>
Acked-by: Peter Zijlstra (Intel) <peterz@infradead.org>
Cc: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
Cc: Jiri Slaby <jslaby@suse.com>
Cc: Andrew Morton <akpm@linux-foundation.org>
Cc: Waiman Long <longman@redhat.com>
Cc: Dmitry Safonov <dima@arista.com>
Cc: Steven Rostedt <rostedt@goodmis.org>
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>

authored by

Sergey Senozhatsky and committed by
Greg Kroah-Hartman
d7240214 6d7f677a

+16 -6
+16 -6
drivers/tty/serial/serial_core.c
··· 205 205 if (!state->xmit.buf) { 206 206 state->xmit.buf = (unsigned char *) page; 207 207 uart_circ_clear(&state->xmit); 208 + uart_port_unlock(uport, flags); 208 209 } else { 210 + uart_port_unlock(uport, flags); 211 + /* 212 + * Do not free() the page under the port lock, see 213 + * uart_shutdown(). 214 + */ 209 215 free_page(page); 210 216 } 211 - uart_port_unlock(uport, flags); 212 217 213 218 retval = uport->ops->startup(uport); 214 219 if (retval == 0) { ··· 273 268 struct uart_port *uport = uart_port_check(state); 274 269 struct tty_port *port = &state->port; 275 270 unsigned long flags = 0; 271 + char *xmit_buf = NULL; 276 272 277 273 /* 278 274 * Set the TTY IO error marker ··· 304 298 tty_port_set_suspended(port, 0); 305 299 306 300 /* 307 - * Free the transmit buffer page. 301 + * Do not free() the transmit buffer page under the port lock since 302 + * this can create various circular locking scenarios. For instance, 303 + * console driver may need to allocate/free a debug object, which 304 + * can endup in printk() recursion. 308 305 */ 309 306 uart_port_lock(state, flags); 310 - if (state->xmit.buf) { 311 - free_page((unsigned long)state->xmit.buf); 312 - state->xmit.buf = NULL; 313 - } 307 + xmit_buf = state->xmit.buf; 308 + state->xmit.buf = NULL; 314 309 uart_port_unlock(uport, flags); 310 + 311 + if (xmit_buf) 312 + free_page((unsigned long)xmit_buf); 315 313 } 316 314 317 315 /**