Skip to content

Commit

Permalink
tty_port: add "tty_port_open" helper
Browse files Browse the repository at this point in the history
For the moment this just moves the USB logic over and fixes the 'what if
we open and hangup at the same time' race noticed by Oliver Neukum.

Signed-off-by: Alan Cox <[email protected]>
Cc: Alan Stern <[email protected]>
Cc: Oliver Neukum <[email protected]>
Signed-off-by: Greg Kroah-Hartman <[email protected]>
  • Loading branch information
Alan Cox authored and gregkh committed Dec 11, 2009
1 parent 894cb91 commit 64bc397
Show file tree
Hide file tree
Showing 3 changed files with 64 additions and 31 deletions.
36 changes: 35 additions & 1 deletion drivers/char/tty_port.c
Original file line number Diff line number Diff line change
Expand Up @@ -99,10 +99,11 @@ EXPORT_SYMBOL(tty_port_tty_set);

static void tty_port_shutdown(struct tty_port *port)
{
mutex_lock(&port->mutex);
if (port->ops->shutdown &&
test_and_clear_bit(ASYNCB_INITIALIZED, &port->flags))
port->ops->shutdown(port);

mutex_unlock(&port->mutex);
}

/**
Expand Down Expand Up @@ -381,3 +382,36 @@ void tty_port_close(struct tty_port *port, struct tty_struct *tty,
tty_port_tty_set(port, NULL);
}
EXPORT_SYMBOL(tty_port_close);

int tty_port_open(struct tty_port *port, struct tty_struct *tty,
struct file *filp)
{
spin_lock_irq(&port->lock);
if (!tty_hung_up_p(filp))
++port->count;
spin_unlock_irq(&port->lock);
tty_port_tty_set(port, tty);

/*
* Do the device-specific open only if the hardware isn't
* already initialized. Serialize open and shutdown using the
* port mutex.
*/

mutex_lock(&port->mutex);

if (!test_bit(ASYNCB_INITIALIZED, &port->flags)) {
if (port->ops->activate) {
int retval = port->ops->activate(port, tty);
if (retval) {
mutex_unlock(&port->mutex);
return retval;
}
}
set_bit(ASYNCB_INITIALIZED, &port->flags);
}
mutex_unlock(&port->mutex);
return tty_port_block_til_ready(port, tty, filp);
}

EXPORT_SYMBOL(tty_port_open);
49 changes: 20 additions & 29 deletions drivers/usb/serial/usb-serial.c
Original file line number Diff line number Diff line change
Expand Up @@ -247,41 +247,31 @@ static int serial_install(struct tty_driver *driver, struct tty_struct *tty)
return retval;
}

static int serial_open(struct tty_struct *tty, struct file *filp)
static int serial_activate(struct tty_port *tport, struct tty_struct *tty)
{
struct usb_serial_port *port = tty->driver_data;
struct usb_serial_port *port =
container_of(tport, struct usb_serial_port, port);
struct usb_serial *serial = port->serial;
int retval;

dbg("%s - port %d", __func__, port->number);

spin_lock_irq(&port->port.lock);
if (!tty_hung_up_p(filp))
++port->port.count;
spin_unlock_irq(&port->port.lock);
tty_port_tty_set(&port->port, tty);
if (mutex_lock_interruptible(&port->mutex))
return -ERESTARTSYS;
mutex_lock(&serial->disc_mutex);
if (serial->disconnected)
retval = -ENODEV;
else
retval = port->serial->type->open(tty, port);
mutex_unlock(&serial->disc_mutex);
mutex_unlock(&port->mutex);
return retval;
}

/* Do the device-specific open only if the hardware isn't
* already initialized.
*/
if (!test_bit(ASYNCB_INITIALIZED, &port->port.flags)) {
if (mutex_lock_interruptible(&port->mutex))
return -ERESTARTSYS;
mutex_lock(&serial->disc_mutex);
if (serial->disconnected)
retval = -ENODEV;
else
retval = port->serial->type->open(tty, port);
mutex_unlock(&serial->disc_mutex);
mutex_unlock(&port->mutex);
if (retval)
return retval;
set_bit(ASYNCB_INITIALIZED, &port->port.flags);
}
static int serial_open(struct tty_struct *tty, struct file *filp)
{
struct usb_serial_port *port = tty->driver_data;

/* Now do the correct tty layer semantics */
retval = tty_port_block_til_ready(&port->port, tty, filp);
return retval;
dbg("%s - port %d", __func__, port->number);
return tty_port_open(&port->port, tty, filp);
}

/**
Expand Down Expand Up @@ -725,6 +715,7 @@ static void serial_dtr_rts(struct tty_port *port, int on)
static const struct tty_port_operations serial_port_ops = {
.carrier_raised = serial_carrier_raised,
.dtr_rts = serial_dtr_rts,
.activate = serial_activate,
};

int usb_serial_probe(struct usb_interface *interface,
Expand Down
10 changes: 9 additions & 1 deletion include/linux/tty.h
Original file line number Diff line number Diff line change
Expand Up @@ -190,9 +190,15 @@ struct tty_port_operations {
/* Control the DTR line */
void (*dtr_rts)(struct tty_port *port, int raise);
/* Called when the last close completes or a hangup finishes
IFF the port was initialized. Do not use to free resources */
IFF the port was initialized. Do not use to free resources. Called
under the port mutex to serialize against activate/shutdowns */
void (*shutdown)(struct tty_port *port);
void (*drop)(struct tty_port *port);
/* Called under the port mutex from tty_port_open, serialized using
the port mutex */
/* FIXME: long term getting the tty argument *out* of this would be
good for consoles */
int (*activate)(struct tty_port *port, struct tty_struct *tty);
};

struct tty_port {
Expand Down Expand Up @@ -467,6 +473,8 @@ extern int tty_port_close_start(struct tty_port *port,
extern void tty_port_close_end(struct tty_port *port, struct tty_struct *tty);
extern void tty_port_close(struct tty_port *port,
struct tty_struct *tty, struct file *filp);
extern int tty_port_open(struct tty_port *port,
struct tty_struct *tty, struct file *filp);
extern inline int tty_port_users(struct tty_port *port)
{
return port->count + port->blocked_open;
Expand Down

0 comments on commit 64bc397

Please sign in to comment.