Messages in this thread Patch in this message | | | Date | Mon, 12 Oct 2009 12:45:01 +0100 | From | Alan Cox <> | Subject | Re: [crash] NULL pointer dereference at IP: [<ffffffff812e9ccb>] uart_close+0x2a/0x1e4 |
| |
> Unfortunately 46d57a449aa13d9c6adcc9d1dbc7b9a0ecfb69d8 is not easy to > revert, at all. Would be glad to try any patch - fixes or some manual > revert as well (if that's feasible).
The patch doesn't do anything but create local variables of state->port. I'm now glad I did it that way as it makes it easy to spot the mistake.
the tty_port lock is ->lock, the uart lock is ->lock both are different..
Spot the mistake:
if (state->flags & UIF_INITIALIZED) { unsigned long flags; spin_lock_irqsave(&port->lock, flags); - port->ops->stop_rx(port); + uport->ops->stop_rx(uport); spin_unlock_irqrestore(&port->lock, flags); /* * Before we drop DTR, make sure the UART transmitter * has completely drained; this is especially * important if there is a transmit FIFO! */ - uart_wait_until_sent(tty, port->timeout); + uart_wait_until_sent(tty, uport->timeout); }
so uart_close takes the wrong lock. I've checked the rest of the patch for the same error and I don't see any other screwups.
uart: uart_close crash fix
From: Alan Cox <alan@linux.intel.com>
uart_close takes the wrong lock at one point due to a bug introduced in the port/uport renaming and tty_port local introduction in 46d57a449aa13d9c6adcc9d1dbc7b9a0ecfb69d8. The race in question is very hard to hit but fortunately Ingo hit it twice..
Signed-off-by: Alan Cox <alan@linux.intel.com> ---
drivers/serial/serial_core.c | 4 ++-- 1 files changed, 2 insertions(+), 2 deletions(-)
diff --git a/drivers/serial/serial_core.c b/drivers/serial/serial_core.c index 1689bda..3005231 100644 --- a/drivers/serial/serial_core.c +++ b/drivers/serial/serial_core.c @@ -1316,9 +1316,9 @@ static void uart_close(struct tty_struct *tty, struct file *filp) */ if (port->flags & ASYNC_INITIALIZED) { unsigned long flags; - spin_lock_irqsave(&port->lock, flags); + spin_lock_irqsave(&uport->lock, flags); uport->ops->stop_rx(uport); - spin_unlock_irqrestore(&port->lock, flags); + spin_unlock_irqrestore(&uport->lock, flags); /* * Before we drop DTR, make sure the UART transmitter * has completely drained; this is especially
| |