[PATCH] Char: mxser_new, alter locking in isr
Avoid oopsing when stress-testing open/close -- port->tty is NULL sometimes, but is expected to be non-NULL, since dereferencing. Receive/transmit chars iff ASYNC_CLOSING is not set and ASYNC_INITIALIZED is set. Thanks Sergei for pointing this out and testing. Cc: Sergei Organov <osv@javad.com> Signed-off-by: Jiri Slaby <jirislaby@gmail.com> Signed-off-by: Andrew Morton <akpm@linux-foundation.org> Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
This commit is contained in:
parent
765d94c1b3
commit
f574874bc8
@ -2073,9 +2073,6 @@ static void mxser_receive_chars(struct mxser_port *port, int *status)
|
|||||||
int cnt = 0;
|
int cnt = 0;
|
||||||
int recv_room;
|
int recv_room;
|
||||||
int max = 256;
|
int max = 256;
|
||||||
unsigned long flags;
|
|
||||||
|
|
||||||
spin_lock_irqsave(&port->slock, flags);
|
|
||||||
|
|
||||||
recv_room = tty->receive_room;
|
recv_room = tty->receive_room;
|
||||||
if ((recv_room == 0) && (!port->ldisc_stop_rx))
|
if ((recv_room == 0) && (!port->ldisc_stop_rx))
|
||||||
@ -2159,7 +2156,6 @@ static void mxser_receive_chars(struct mxser_port *port, int *status)
|
|||||||
mxvar_log.rxcnt[port->tty->index] += cnt;
|
mxvar_log.rxcnt[port->tty->index] += cnt;
|
||||||
port->mon_data.rxcnt += cnt;
|
port->mon_data.rxcnt += cnt;
|
||||||
port->mon_data.up_rxcnt += cnt;
|
port->mon_data.up_rxcnt += cnt;
|
||||||
spin_unlock_irqrestore(&port->slock, flags);
|
|
||||||
|
|
||||||
tty_flip_buffer_push(tty);
|
tty_flip_buffer_push(tty);
|
||||||
}
|
}
|
||||||
@ -2167,9 +2163,6 @@ static void mxser_receive_chars(struct mxser_port *port, int *status)
|
|||||||
static void mxser_transmit_chars(struct mxser_port *port)
|
static void mxser_transmit_chars(struct mxser_port *port)
|
||||||
{
|
{
|
||||||
int count, cnt;
|
int count, cnt;
|
||||||
unsigned long flags;
|
|
||||||
|
|
||||||
spin_lock_irqsave(&port->slock, flags);
|
|
||||||
|
|
||||||
if (port->x_char) {
|
if (port->x_char) {
|
||||||
outb(port->x_char, port->ioaddr + UART_TX);
|
outb(port->x_char, port->ioaddr + UART_TX);
|
||||||
@ -2178,11 +2171,11 @@ static void mxser_transmit_chars(struct mxser_port *port)
|
|||||||
port->mon_data.txcnt++;
|
port->mon_data.txcnt++;
|
||||||
port->mon_data.up_txcnt++;
|
port->mon_data.up_txcnt++;
|
||||||
port->icount.tx++;
|
port->icount.tx++;
|
||||||
goto unlock;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (port->xmit_buf == 0)
|
if (port->xmit_buf == 0)
|
||||||
goto unlock;
|
return;
|
||||||
|
|
||||||
if ((port->xmit_cnt <= 0) || port->tty->stopped ||
|
if ((port->xmit_cnt <= 0) || port->tty->stopped ||
|
||||||
(port->tty->hw_stopped &&
|
(port->tty->hw_stopped &&
|
||||||
@ -2190,7 +2183,7 @@ static void mxser_transmit_chars(struct mxser_port *port)
|
|||||||
(!port->board->chip_flag))) {
|
(!port->board->chip_flag))) {
|
||||||
port->IER &= ~UART_IER_THRI;
|
port->IER &= ~UART_IER_THRI;
|
||||||
outb(port->IER, port->ioaddr + UART_IER);
|
outb(port->IER, port->ioaddr + UART_IER);
|
||||||
goto unlock;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
cnt = port->xmit_cnt;
|
cnt = port->xmit_cnt;
|
||||||
@ -2215,8 +2208,6 @@ static void mxser_transmit_chars(struct mxser_port *port)
|
|||||||
port->IER &= ~UART_IER_THRI;
|
port->IER &= ~UART_IER_THRI;
|
||||||
outb(port->IER, port->ioaddr + UART_IER);
|
outb(port->IER, port->ioaddr + UART_IER);
|
||||||
}
|
}
|
||||||
unlock:
|
|
||||||
spin_unlock_irqrestore(&port->slock, flags);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@ -2257,12 +2248,16 @@ static irqreturn_t mxser_interrupt(int irq, void *dev_id)
|
|||||||
port = &brd->ports[i];
|
port = &brd->ports[i];
|
||||||
|
|
||||||
int_cnt = 0;
|
int_cnt = 0;
|
||||||
|
spin_lock(&port->slock);
|
||||||
do {
|
do {
|
||||||
iir = inb(port->ioaddr + UART_IIR);
|
iir = inb(port->ioaddr + UART_IIR);
|
||||||
if (iir & UART_IIR_NO_INT)
|
if (iir & UART_IIR_NO_INT)
|
||||||
break;
|
break;
|
||||||
iir &= MOXA_MUST_IIR_MASK;
|
iir &= MOXA_MUST_IIR_MASK;
|
||||||
if (!port->tty) {
|
if (!port->tty ||
|
||||||
|
(port->flags & ASYNC_CLOSING) ||
|
||||||
|
!(port->flags &
|
||||||
|
ASYNC_INITIALIZED)) {
|
||||||
status = inb(port->ioaddr + UART_LSR);
|
status = inb(port->ioaddr + UART_LSR);
|
||||||
outb(0x27, port->ioaddr + UART_FCR);
|
outb(0x27, port->ioaddr + UART_FCR);
|
||||||
inb(port->ioaddr + UART_MSR);
|
inb(port->ioaddr + UART_MSR);
|
||||||
@ -2308,6 +2303,7 @@ static irqreturn_t mxser_interrupt(int irq, void *dev_id)
|
|||||||
mxser_transmit_chars(port);
|
mxser_transmit_chars(port);
|
||||||
}
|
}
|
||||||
} while (int_cnt++ < MXSER_ISR_PASS_LIMIT);
|
} while (int_cnt++ < MXSER_ISR_PASS_LIMIT);
|
||||||
|
spin_unlock(&port->slock);
|
||||||
}
|
}
|
||||||
if (pass_counter++ > MXSER_ISR_PASS_LIMIT)
|
if (pass_counter++ > MXSER_ISR_PASS_LIMIT)
|
||||||
break; /* Prevent infinite loops */
|
break; /* Prevent infinite loops */
|
||||||
|
Loading…
Reference in New Issue
Block a user