mirror of
https://github.com/AuxXxilium/linux_dsm_epyc7002.git
synced 2024-11-25 19:31:09 +07:00
Merge branch 'serial'
* serial: imx: Check for NULL pointer deref before calling tty_encode_baud_rate atmel_serial: fix hang in set_termios when crtscts is enabled MAINTAINERS: update 8250 section, give Alan Cox a name tty: fix sanity check pty: Narrow the race on ldisc locking tty: fix unused warning when TCGETX is not defined ldisc: debug aids ldisc: Make sure the ldisc isn't active when we close it tty: Fix leaks introduced by the shift to separate ldisc objects Fix conflicts in drivers/char/pty.c due to earlier version of the ldisc race narrowing.
This commit is contained in:
commit
15bdb56526
@ -157,9 +157,10 @@ S: Maintained
|
||||
F: drivers/net/r8169.c
|
||||
|
||||
8250/16?50 (AND CLONE UARTS) SERIAL DRIVER
|
||||
P: Alan Cox
|
||||
M: alan@lxorguk.ukuu.org.uk
|
||||
L: linux-serial@vger.kernel.org
|
||||
W: http://serial.sourceforge.net
|
||||
M: alan@lxorguk.ukuu.org.uk
|
||||
S: Odd Fixes
|
||||
F: drivers/serial/8250*
|
||||
F: include/linux/serial_8250.h
|
||||
|
@ -95,23 +95,34 @@ static void pty_unthrottle(struct tty_struct *tty)
|
||||
* a count.
|
||||
*
|
||||
* FIXME: Our pty_write method is called with our ldisc lock held but
|
||||
* not our partners. We can't just take the other one blindly without
|
||||
* risking deadlocks.
|
||||
* not our partners. We can't just wait on the other one blindly without
|
||||
* risking deadlocks. At some point when everything has settled down we need
|
||||
* to look into making pty_write at least able to sleep over an ldisc change.
|
||||
*
|
||||
* The return on no ldisc is a bit counter intuitive but the logic works
|
||||
* like this. During an ldisc change the other end will flush its buffers. We
|
||||
* thus return the full length which is identical to the case where we had
|
||||
* proper locking and happened to queue the bytes just before the flush during
|
||||
* the ldisc change.
|
||||
*/
|
||||
static int pty_write(struct tty_struct *tty, const unsigned char *buf,
|
||||
int count)
|
||||
{
|
||||
struct tty_struct *to = tty->link;
|
||||
int c;
|
||||
struct tty_ldisc *ld;
|
||||
int c = count;
|
||||
|
||||
if (!to || !to->ldisc || tty->stopped)
|
||||
if (!to || tty->stopped)
|
||||
return 0;
|
||||
ld = tty_ldisc_ref(to);
|
||||
|
||||
c = to->receive_room;
|
||||
if (c > count)
|
||||
c = count;
|
||||
to->ldisc->ops->receive_buf(to, buf, NULL, c);
|
||||
|
||||
if (ld) {
|
||||
c = to->receive_room;
|
||||
if (c > count)
|
||||
c = count;
|
||||
ld->ops->receive_buf(to, buf, NULL, c);
|
||||
tty_ldisc_deref(ld);
|
||||
}
|
||||
return c;
|
||||
}
|
||||
|
||||
@ -145,14 +156,23 @@ static int pty_write_room(struct tty_struct *tty)
|
||||
static int pty_chars_in_buffer(struct tty_struct *tty)
|
||||
{
|
||||
struct tty_struct *to = tty->link;
|
||||
int count;
|
||||
struct tty_ldisc *ld;
|
||||
int count = 0;
|
||||
|
||||
/* We should get the line discipline lock for "tty->link" */
|
||||
if (!to || !to->ldisc || !to->ldisc->ops->chars_in_buffer)
|
||||
if (!to)
|
||||
return 0;
|
||||
/* We cannot take a sleeping reference here without deadlocking with
|
||||
an ldisc change - but it doesn't really matter */
|
||||
ld = tty_ldisc_ref(to);
|
||||
if (ld == NULL)
|
||||
return 0;
|
||||
|
||||
/* The ldisc must report 0 if no characters available to be read */
|
||||
count = to->ldisc->ops->chars_in_buffer(to);
|
||||
if (ld->ops->chars_in_buffer)
|
||||
count = ld->ops->chars_in_buffer(to);
|
||||
|
||||
tty_ldisc_deref(ld);
|
||||
|
||||
if (tty->driver->subtype == PTY_TYPE_SLAVE)
|
||||
return count;
|
||||
@ -182,12 +202,19 @@ static void pty_flush_buffer(struct tty_struct *tty)
|
||||
{
|
||||
struct tty_struct *to = tty->link;
|
||||
unsigned long flags;
|
||||
struct tty_ldisc *ld;
|
||||
|
||||
if (!to || !to->ldisc)
|
||||
if (!to)
|
||||
return;
|
||||
ld = tty_ldisc_ref(to);
|
||||
|
||||
/* The other end is changing discipline */
|
||||
if (!ld)
|
||||
return;
|
||||
|
||||
if (to->ldisc->ops->flush_buffer)
|
||||
if (ld->ops->flush_buffer)
|
||||
to->ldisc->ops->flush_buffer(to);
|
||||
tty_ldisc_deref(ld);
|
||||
|
||||
if (to->packet) {
|
||||
spin_lock_irqsave(&tty->ctrl_lock, flags);
|
||||
|
@ -1263,7 +1263,9 @@ static int tty_reopen(struct tty_struct *tty)
|
||||
tty->count++;
|
||||
tty->driver = driver; /* N.B. why do this every time?? */
|
||||
|
||||
mutex_lock(&tty->ldisc_mutex);
|
||||
WARN_ON(!test_bit(TTY_LDISC, &tty->flags));
|
||||
mutex_unlock(&tty->ldisc_mutex);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
@ -947,7 +947,6 @@ int tty_mode_ioctl(struct tty_struct *tty, struct file *file,
|
||||
void __user *p = (void __user *)arg;
|
||||
int ret = 0;
|
||||
struct ktermios kterm;
|
||||
struct termiox ktermx;
|
||||
|
||||
if (tty->driver->type == TTY_DRIVER_TYPE_PTY &&
|
||||
tty->driver->subtype == PTY_TYPE_MASTER)
|
||||
@ -1049,7 +1048,8 @@ int tty_mode_ioctl(struct tty_struct *tty, struct file *file,
|
||||
return ret;
|
||||
#endif
|
||||
#ifdef TCGETX
|
||||
case TCGETX:
|
||||
case TCGETX: {
|
||||
struct termiox ktermx;
|
||||
if (real_tty->termiox == NULL)
|
||||
return -EINVAL;
|
||||
mutex_lock(&real_tty->termios_mutex);
|
||||
@ -1058,6 +1058,7 @@ int tty_mode_ioctl(struct tty_struct *tty, struct file *file,
|
||||
if (copy_to_user(p, &ktermx, sizeof(struct termiox)))
|
||||
ret = -EFAULT;
|
||||
return ret;
|
||||
}
|
||||
case TCSETX:
|
||||
return set_termiox(real_tty, p, 0);
|
||||
case TCSETXW:
|
||||
|
@ -207,6 +207,7 @@ static void tty_ldisc_put(struct tty_ldisc *ld)
|
||||
ldo->refcount--;
|
||||
module_put(ldo->owner);
|
||||
spin_unlock_irqrestore(&tty_ldisc_lock, flags);
|
||||
WARN_ON(ld->refcount);
|
||||
kfree(ld);
|
||||
}
|
||||
|
||||
@ -793,6 +794,8 @@ void tty_ldisc_hangup(struct tty_struct *tty)
|
||||
/* Avoid racing set_ldisc */
|
||||
mutex_lock(&tty->ldisc_mutex);
|
||||
/* Switch back to N_TTY */
|
||||
tty_ldisc_halt(tty);
|
||||
tty_ldisc_wait_idle(tty);
|
||||
tty_ldisc_reinit(tty);
|
||||
/* At this point we have a closed ldisc and we want to
|
||||
reopen it. We could defer this to the next open but
|
||||
|
@ -1104,11 +1104,13 @@ static void atmel_set_termios(struct uart_port *port, struct ktermios *termios,
|
||||
/* update the per-port timeout */
|
||||
uart_update_timeout(port, termios->c_cflag, baud);
|
||||
|
||||
/* save/disable interrupts and drain transmitter */
|
||||
/*
|
||||
* save/disable interrupts. The tty layer will ensure that the
|
||||
* transmitter is empty if requested by the caller, so there's
|
||||
* no need to wait for it here.
|
||||
*/
|
||||
imr = UART_GET_IMR(port);
|
||||
UART_PUT_IDR(port, -1);
|
||||
while (!(UART_GET_CSR(port) & ATMEL_US_TXEMPTY))
|
||||
cpu_relax();
|
||||
|
||||
/* disable receiver and transmitter */
|
||||
UART_PUT_CR(port, ATMEL_US_TXDIS | ATMEL_US_RXDIS);
|
||||
|
@ -924,11 +924,13 @@ imx_set_termios(struct uart_port *port, struct ktermios *termios,
|
||||
rational_best_approximation(16 * div * baud, sport->port.uartclk,
|
||||
1 << 16, 1 << 16, &num, &denom);
|
||||
|
||||
tdiv64 = sport->port.uartclk;
|
||||
tdiv64 *= num;
|
||||
do_div(tdiv64, denom * 16 * div);
|
||||
tty_encode_baud_rate(sport->port.info->port.tty,
|
||||
(speed_t)tdiv64, (speed_t)tdiv64);
|
||||
if (port->info && port->info->port.tty) {
|
||||
tdiv64 = sport->port.uartclk;
|
||||
tdiv64 *= num;
|
||||
do_div(tdiv64, denom * 16 * div);
|
||||
tty_encode_baud_rate(sport->port.info->port.tty,
|
||||
(speed_t)tdiv64, (speed_t)tdiv64);
|
||||
}
|
||||
|
||||
num -= 1;
|
||||
denom -= 1;
|
||||
|
Loading…
Reference in New Issue
Block a user