Skip to content

Commit

Permalink
tty: mxser: Use the new locking rules to fix setserial properly
Browse files Browse the repository at this point in the history
Propogate the init/shutdown mutex through the setserial logic. Use the proper
locks for the various bits still using the BKL. Kill the BKL in this driver.

Updated to fix the bug noted by Dan Carpenter

Signed-off-by: Alan Cox <alan@linux.intel.com>
Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
  • Loading branch information
Alan Cox authored and gregkh committed Dec 11, 2009
1 parent 6769140 commit 07f86c0
Showing 1 changed file with 78 additions and 67 deletions.
145 changes: 78 additions & 67 deletions drivers/char/mxser.c
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,6 @@
#include <linux/errno.h>
#include <linux/signal.h>
#include <linux/sched.h>
#include <linux/smp_lock.h>
#include <linux/timer.h>
#include <linux/interrupt.h>
#include <linux/tty.h>
Expand Down Expand Up @@ -1229,6 +1228,7 @@ static int mxser_set_serial_info(struct tty_struct *tty,
struct serial_struct __user *new_info)
{
struct mxser_port *info = tty->driver_data;
struct tty_port *port = &info->port;
struct serial_struct new_serial;
speed_t baud;
unsigned long sl_flags;
Expand All @@ -1244,7 +1244,7 @@ static int mxser_set_serial_info(struct tty_struct *tty,
new_serial.port != info->ioaddr)
return -EINVAL;

flags = info->port.flags & ASYNC_SPD_MASK;
flags = port->flags & ASYNC_SPD_MASK;

if (!capable(CAP_SYS_ADMIN)) {
if ((new_serial.baud_base != info->baud_base) ||
Expand All @@ -1258,16 +1258,17 @@ static int mxser_set_serial_info(struct tty_struct *tty,
* OK, past this point, all the error checking has been done.
* At this point, we start making changes.....
*/
info->port.flags = ((info->port.flags & ~ASYNC_FLAGS) |
port->flags = ((port->flags & ~ASYNC_FLAGS) |
(new_serial.flags & ASYNC_FLAGS));
info->port.close_delay = new_serial.close_delay * HZ / 100;
info->port.closing_wait = new_serial.closing_wait * HZ / 100;
tty->low_latency = (info->port.flags & ASYNC_LOW_LATENCY)
? 1 : 0;
if ((info->port.flags & ASYNC_SPD_MASK) == ASYNC_SPD_CUST &&
port->close_delay = new_serial.close_delay * HZ / 100;
port->closing_wait = new_serial.closing_wait * HZ / 100;
tty->low_latency = (port->flags & ASYNC_LOW_LATENCY) ? 1 : 0;
if ((port->flags & ASYNC_SPD_MASK) == ASYNC_SPD_CUST &&
(new_serial.baud_base != info->baud_base ||
new_serial.custom_divisor !=
info->custom_divisor)) {
if (new_serial.custom_divisor == 0)
return -EINVAL;
baud = new_serial.baud_base / new_serial.custom_divisor;
tty_encode_baud_rate(tty, baud, baud);
}
Expand All @@ -1277,18 +1278,16 @@ static int mxser_set_serial_info(struct tty_struct *tty,

process_txrx_fifo(info);

if (info->port.flags & ASYNC_INITIALIZED) {
if (flags != (info->port.flags & ASYNC_SPD_MASK)) {
if (test_bit(ASYNCB_INITIALIZED, &port->flags)) {
if (flags != (port->flags & ASYNC_SPD_MASK)) {
spin_lock_irqsave(&info->slock, sl_flags);
mxser_change_speed(tty, NULL);
spin_unlock_irqrestore(&info->slock, sl_flags);
}
} else {
mutex_lock(&info->port.mutex);
retval = mxser_activate(&info->port, tty);
retval = mxser_activate(port, tty);
if (retval == 0)
set_bit(ASYNCB_INITIALIZED, &info->port.flags);
mutex_unlock(&info->port.mutex);
set_bit(ASYNCB_INITIALIZED, &port->flags);
}
return retval;
}
Expand Down Expand Up @@ -1478,7 +1477,8 @@ static int __init mxser_read_register(int port, unsigned short *regs)

static int mxser_ioctl_special(unsigned int cmd, void __user *argp)
{
struct mxser_port *port;
struct mxser_port *ip;
struct tty_port *port;
struct tty_struct *tty;
int result, status;
unsigned int i, j;
Expand All @@ -1494,52 +1494,51 @@ static int mxser_ioctl_special(unsigned int cmd, void __user *argp)

case MOXA_CHKPORTENABLE:
result = 0;
lock_kernel();
for (i = 0; i < MXSER_BOARDS; i++)
for (j = 0; j < MXSER_PORTS_PER_BOARD; j++)
if (mxser_boards[i].ports[j].ioaddr)
result |= (1 << i);
unlock_kernel();
return put_user(result, (unsigned long __user *)argp);
case MOXA_GETDATACOUNT:
lock_kernel();
/* The receive side is locked by port->slock but it isn't
clear that an exact snapshot is worth copying here */
if (copy_to_user(argp, &mxvar_log, sizeof(mxvar_log)))
ret = -EFAULT;
unlock_kernel();
return ret;
case MOXA_GETMSTATUS: {
struct mxser_mstatus ms, __user *msu = argp;
lock_kernel();
for (i = 0; i < MXSER_BOARDS; i++)
for (j = 0; j < MXSER_PORTS_PER_BOARD; j++) {
port = &mxser_boards[i].ports[j];
ip = &mxser_boards[i].ports[j];
port = &ip->port;
memset(&ms, 0, sizeof(ms));

if (!port->ioaddr)
mutex_lock(&port->mutex);
if (!ip->ioaddr)
goto copy;

tty = tty_port_tty_get(&port->port);
tty = tty_port_tty_get(port);

if (!tty || !tty->termios)
ms.cflag = port->normal_termios.c_cflag;
ms.cflag = ip->normal_termios.c_cflag;
else
ms.cflag = tty->termios->c_cflag;
tty_kref_put(tty);
status = inb(port->ioaddr + UART_MSR);
spin_lock_irq(&ip->slock);
status = inb(ip->ioaddr + UART_MSR);
spin_unlock_irq(&ip->slock);
if (status & UART_MSR_DCD)
ms.dcd = 1;
if (status & UART_MSR_DSR)
ms.dsr = 1;
if (status & UART_MSR_CTS)
ms.cts = 1;
copy:
if (copy_to_user(msu, &ms, sizeof(ms))) {
unlock_kernel();
mutex_unlock(&port->mutex);
if (copy_to_user(msu, &ms, sizeof(ms)))
return -EFAULT;
}
msu++;
}
unlock_kernel();
return 0;
}
case MOXA_ASPP_MON_EXT: {
Expand All @@ -1551,41 +1550,48 @@ static int mxser_ioctl_special(unsigned int cmd, void __user *argp)
if (!me)
return -ENOMEM;

lock_kernel();
for (i = 0, p = 0; i < MXSER_BOARDS; i++) {
for (j = 0; j < MXSER_PORTS_PER_BOARD; j++, p++) {
if (p >= ARRAY_SIZE(me->rx_cnt)) {
i = MXSER_BOARDS;
break;
}
port = &mxser_boards[i].ports[j];
if (!port->ioaddr)
ip = &mxser_boards[i].ports[j];
port = &ip->port;

mutex_lock(&port->mutex);
if (!ip->ioaddr) {
mutex_unlock(&port->mutex);
continue;
}

status = mxser_get_msr(port->ioaddr, 0, p);
spin_lock_irq(&ip->slock);
status = mxser_get_msr(ip->ioaddr, 0, p);

if (status & UART_MSR_TERI)
port->icount.rng++;
ip->icount.rng++;
if (status & UART_MSR_DDSR)
port->icount.dsr++;
ip->icount.dsr++;
if (status & UART_MSR_DDCD)
port->icount.dcd++;
ip->icount.dcd++;
if (status & UART_MSR_DCTS)
port->icount.cts++;
ip->icount.cts++;

port->mon_data.modem_status = status;
me->rx_cnt[p] = port->mon_data.rxcnt;
me->tx_cnt[p] = port->mon_data.txcnt;
me->up_rxcnt[p] = port->mon_data.up_rxcnt;
me->up_txcnt[p] = port->mon_data.up_txcnt;
ip->mon_data.modem_status = status;
me->rx_cnt[p] = ip->mon_data.rxcnt;
me->tx_cnt[p] = ip->mon_data.txcnt;
me->up_rxcnt[p] = ip->mon_data.up_rxcnt;
me->up_txcnt[p] = ip->mon_data.up_txcnt;
me->modem_status[p] =
port->mon_data.modem_status;
tty = tty_port_tty_get(&port->port);
ip->mon_data.modem_status;
spin_unlock_irq(&ip->slock);

tty = tty_port_tty_get(&ip->port);

if (!tty || !tty->termios) {
cflag = port->normal_termios.c_cflag;
iflag = port->normal_termios.c_iflag;
me->baudrate[p] = tty_termios_baud_rate(&port->normal_termios);
cflag = ip->normal_termios.c_cflag;
iflag = ip->normal_termios.c_iflag;
me->baudrate[p] = tty_termios_baud_rate(&ip->normal_termios);
} else {
cflag = tty->termios->c_cflag;
iflag = tty->termios->c_iflag;
Expand All @@ -1604,16 +1610,15 @@ static int mxser_ioctl_special(unsigned int cmd, void __user *argp)
if (iflag & (IXON | IXOFF))
me->flowctrl[p] |= 0x0C;

if (port->type == PORT_16550A)
if (ip->type == PORT_16550A)
me->fifo[p] = 1;

opmode = inb(port->opmode_ioaddr) >>
((p % 4) * 2);
opmode = inb(ip->opmode_ioaddr)>>((p % 4) * 2);
opmode &= OP_MODE_MASK;
me->iftype[p] = opmode;
mutex_unlock(&port->mutex);
}
}
unlock_kernel();
if (copy_to_user(argp, me, sizeof(*me)))
ret = -EFAULT;
kfree(me);
Expand Down Expand Up @@ -1650,6 +1655,7 @@ static int mxser_ioctl(struct tty_struct *tty, struct file *file,
unsigned int cmd, unsigned long arg)
{
struct mxser_port *info = tty->driver_data;
struct tty_port *port = &info->port;
struct async_icount cnow;
unsigned long flags;
void __user *argp = (void __user *)arg;
Expand All @@ -1674,20 +1680,20 @@ static int mxser_ioctl(struct tty_struct *tty, struct file *file,
opmode != RS422_MODE &&
opmode != RS485_4WIRE_MODE)
return -EFAULT;
lock_kernel();
mask = ModeMask[p];
shiftbit = p * 2;
spin_lock_irq(&info->slock);
val = inb(info->opmode_ioaddr);
val &= mask;
val |= (opmode << shiftbit);
outb(val, info->opmode_ioaddr);
unlock_kernel();
spin_unlock_irq(&info->slock);
} else {
lock_kernel();
shiftbit = p * 2;
spin_lock_irq(&info->slock);
opmode = inb(info->opmode_ioaddr) >> shiftbit;
spin_unlock_irq(&info->slock);
opmode &= OP_MODE_MASK;
unlock_kernel();
if (put_user(opmode, (int __user *)argp))
return -EFAULT;
}
Expand All @@ -1700,14 +1706,14 @@ static int mxser_ioctl(struct tty_struct *tty, struct file *file,

switch (cmd) {
case TIOCGSERIAL:
lock_kernel();
mutex_lock(&port->mutex);
retval = mxser_get_serial_info(tty, argp);
unlock_kernel();
mutex_unlock(&port->mutex);
return retval;
case TIOCSSERIAL:
lock_kernel();
mutex_lock(&port->mutex);
retval = mxser_set_serial_info(tty, argp);
unlock_kernel();
mutex_unlock(&port->mutex);
return retval;
case TIOCSERGETLSR: /* Get line status register */
return mxser_get_lsr_info(info, argp);
Expand Down Expand Up @@ -1753,31 +1759,33 @@ static int mxser_ioctl(struct tty_struct *tty, struct file *file,
case MOXA_HighSpeedOn:
return put_user(info->baud_base != 115200 ? 1 : 0, (int __user *)argp);
case MOXA_SDS_RSTICOUNTER:
lock_kernel();
spin_lock_irq(&info->slock);
info->mon_data.rxcnt = 0;
info->mon_data.txcnt = 0;
unlock_kernel();
spin_unlock_irq(&info->slock);
return 0;

case MOXA_ASPP_OQUEUE:{
int len, lsr;

lock_kernel();
len = mxser_chars_in_buffer(tty);
spin_lock(&info->slock);
lsr = inb(info->ioaddr + UART_LSR) & UART_LSR_THRE;
spin_unlock_irq(&info->slock);
len += (lsr ? 0 : 1);
unlock_kernel();

return put_user(len, (int __user *)argp);
}
case MOXA_ASPP_MON: {
int mcr, status;

lock_kernel();
spin_lock(&info->slock);
status = mxser_get_msr(info->ioaddr, 1, tty->index);
mxser_check_modem_status(tty, info, status);

mcr = inb(info->ioaddr + UART_MCR);
spin_unlock(&info->slock);

if (mcr & MOXA_MUST_MCR_XON_FLAG)
info->mon_data.hold_reason &= ~NPPI_NOTIFY_XOFFHOLD;
else
Expand All @@ -1792,7 +1800,7 @@ static int mxser_ioctl(struct tty_struct *tty, struct file *file,
info->mon_data.hold_reason |= NPPI_NOTIFY_CTSHOLD;
else
info->mon_data.hold_reason &= ~NPPI_NOTIFY_CTSHOLD;
unlock_kernel();

if (copy_to_user(argp, &info->mon_data,
sizeof(struct mxser_mon)))
return -EFAULT;
Expand Down Expand Up @@ -1951,6 +1959,7 @@ static void mxser_wait_until_sent(struct tty_struct *tty, int timeout)
{
struct mxser_port *info = tty->driver_data;
unsigned long orig_jiffies, char_time;
unsigned long flags;
int lsr;

if (info->type == PORT_UNKNOWN)
Expand Down Expand Up @@ -1990,19 +1999,21 @@ static void mxser_wait_until_sent(struct tty_struct *tty, int timeout)
timeout, char_time);
printk("jiff=%lu...", jiffies);
#endif
lock_kernel();
spin_lock_irqsave(&info->slock, flags);
while (!((lsr = inb(info->ioaddr + UART_LSR)) & UART_LSR_TEMT)) {
#ifdef SERIAL_DEBUG_RS_WAIT_UNTIL_SENT
printk("lsr = %d (jiff=%lu)...", lsr, jiffies);
#endif
spin_unlock_irqrestore(&info->slock, flags);
schedule_timeout_interruptible(char_time);
spin_lock_irqsave(&info->slock, flags);
if (signal_pending(current))
break;
if (timeout && time_after(jiffies, orig_jiffies + timeout))
break;
}
spin_unlock_irqrestore(&info->slock, flags);
set_current_state(TASK_RUNNING);
unlock_kernel();

#ifdef SERIAL_DEBUG_RS_WAIT_UNTIL_SENT
printk("lsr = %d (jiff=%lu)...done\n", lsr, jiffies);
Expand Down

0 comments on commit 07f86c0

Please sign in to comment.