ECHOCTL | ECHOKE | IEXTEN,
.c_cc = INIT_C_CC,
.c_ispeed = 38400,
- .c_ospeed = 38400
+ .c_ospeed = 38400,
+ /* .c_line = N_TTY, */
};
EXPORT_SYMBOL(tty_std_termios);
while (refs--)
tty_kref_put(tty);
- tty_ldisc_hangup(tty);
+ tty_ldisc_hangup(tty, cons_filp != NULL);
spin_lock_irq(&tty->ctrl_lock);
clear_bit(TTY_THROTTLED, &tty->flags);
} else if (tty->ops->hangup)
tty->ops->hangup(tty);
/*
- * We don't want to have driver/ldisc interactions beyond
- * the ones we did here. The driver layer expects no
- * calls after ->hangup() from the ldisc side. However we
- * can't yet guarantee all that.
+ * We don't want to have driver/ldisc interactions beyond the ones
+ * we did here. The driver layer expects no calls after ->hangup()
+ * from the ldisc side, which is now guaranteed.
*/
set_bit(TTY_HUPPED, &tty->flags);
tty_unlock(tty);
/* We want to wait for the line discipline to sort out in this
situation */
ld = tty_ldisc_ref_wait(tty);
+ if (!ld)
+ return hung_up_tty_read(file, buf, count, ppos);
if (ld->ops->read)
i = ld->ops->read(tty, file, buf, count);
else
if (tty->ops->write_room == NULL)
tty_err(tty, "missing write_room method\n");
ld = tty_ldisc_ref_wait(tty);
+ if (!ld)
+ return hung_up_tty_write(file, buf, count, ppos);
if (!ld->ops->write)
ret = -EIO;
else
else {
/* Check for lazy saved data */
tp = tty->driver->termios[idx];
- if (tp != NULL)
+ if (tp != NULL) {
tty->termios = *tp;
- else
+ tty->termios.c_line = tty->driver->init_termios.c_line;
+ } else
tty->termios = tty->driver->init_termios;
}
/* Compatibility until drivers always set this */
tty->count++;
- WARN_ON(!tty->ldisc);
+ if (!tty->ldisc)
+ return tty_ldisc_reinit(tty, tty->termios.c_line);
return 0;
}
return driver;
}
+/**
+ * tty_open_by_driver - open a tty device
+ * @device: dev_t of device to open
+ * @inode: inode of device file
+ * @filp: file pointer to tty
+ *
+ * Performs the driver lookup, checks for a reopen, or otherwise
+ * performs the first-time tty initialization.
+ *
+ * Returns the locked initialized or re-opened &tty_struct
+ *
+ * Claims the global tty_mutex to serialize:
+ * - concurrent first-time tty initialization
+ * - concurrent tty driver removal w/ lookup
+ * - concurrent tty removal from driver table
+ */
+static struct tty_struct *tty_open_by_driver(dev_t device, struct inode *inode,
+ struct file *filp)
+{
+ struct tty_struct *tty;
+ struct tty_driver *driver = NULL;
+ int index = -1;
+ int retval;
+
+ mutex_lock(&tty_mutex);
+ driver = tty_lookup_driver(device, filp, &index);
+ if (IS_ERR(driver)) {
+ mutex_unlock(&tty_mutex);
+ return ERR_CAST(driver);
+ }
+
+ /* check whether we're reopening an existing tty */
+ tty = tty_driver_lookup_tty(driver, inode, index);
+ if (IS_ERR(tty)) {
+ mutex_unlock(&tty_mutex);
+ goto out;
+ }
+
+ if (tty) {
+ mutex_unlock(&tty_mutex);
+ retval = tty_lock_interruptible(tty);
+ if (retval) {
+ if (retval == -EINTR)
+ retval = -ERESTARTSYS;
+ tty = ERR_PTR(retval);
+ goto out;
+ }
+ /* safe to drop the kref from tty_driver_lookup_tty() */
+ tty_kref_put(tty);
+ retval = tty_reopen(tty);
+ if (retval < 0) {
+ tty_unlock(tty);
+ tty = ERR_PTR(retval);
+ }
+ } else { /* Returns with the tty_lock held for now */
+ tty = tty_init_dev(driver, index);
+ mutex_unlock(&tty_mutex);
+ }
+out:
+ tty_driver_kref_put(driver);
+ return tty;
+}
+
/**
* tty_open - open a tty device
* @inode: inode of device file
{
struct tty_struct *tty;
int noctty, retval;
- struct tty_driver *driver = NULL;
- int index;
dev_t device = inode->i_rdev;
unsigned saved_flags = filp->f_flags;
if (retval)
return -ENOMEM;
- index = -1;
- retval = 0;
-
tty = tty_open_current_tty(device, filp);
- if (!tty) {
- mutex_lock(&tty_mutex);
- driver = tty_lookup_driver(device, filp, &index);
- if (IS_ERR(driver)) {
- retval = PTR_ERR(driver);
- goto err_unlock;
- }
-
- /* check whether we're reopening an existing tty */
- tty = tty_driver_lookup_tty(driver, inode, index);
- if (IS_ERR(tty)) {
- retval = PTR_ERR(tty);
- goto err_unlock;
- }
-
- if (tty) {
- mutex_unlock(&tty_mutex);
- retval = tty_lock_interruptible(tty);
- if (retval) {
- if (retval == -EINTR)
- retval = -ERESTARTSYS;
- goto err_unref;
- }
- /* safe to drop the kref from tty_driver_lookup_tty() */
- tty_kref_put(tty);
- retval = tty_reopen(tty);
- if (retval < 0) {
- tty_unlock(tty);
- tty = ERR_PTR(retval);
- }
- } else { /* Returns with the tty_lock held for now */
- tty = tty_init_dev(driver, index);
- mutex_unlock(&tty_mutex);
- }
-
- tty_driver_kref_put(driver);
- }
+ if (!tty)
+ tty = tty_open_by_driver(device, inode, filp);
if (IS_ERR(tty)) {
+ tty_free_file(filp);
retval = PTR_ERR(tty);
if (retval != -EAGAIN || signal_pending(current))
- goto err_file;
- tty_free_file(filp);
+ return retval;
schedule();
goto retry_open;
}
read_unlock(&tasklist_lock);
tty_unlock(tty);
return 0;
-err_unlock:
- mutex_unlock(&tty_mutex);
-err_unref:
- /* after locks to avoid deadlock */
- if (!IS_ERR_OR_NULL(driver))
- tty_driver_kref_put(driver);
-err_file:
- tty_free_file(filp);
- return retval;
}
return 0;
ld = tty_ldisc_ref_wait(tty);
+ if (!ld)
+ return hung_up_tty_poll(filp, wait);
if (ld->ops->poll)
ret = ld->ops->poll(tty, filp, wait);
tty_ldisc_deref(ld);
return -EFAULT;
tty_audit_tiocsti(tty, ch);
ld = tty_ldisc_ref_wait(tty);
+ if (!ld)
+ return -EIO;
ld->ops->receive_buf(tty, &ch, &mbz, 1);
tty_ldisc_deref(ld);
return 0;
static int tiocsetd(struct tty_struct *tty, int __user *p)
{
- int ldisc;
+ int disc;
int ret;
- if (get_user(ldisc, p))
+ if (get_user(disc, p))
return -EFAULT;
- ret = tty_set_ldisc(tty, ldisc);
+ ret = tty_set_ldisc(tty, disc);
return ret;
}
int ret;
ld = tty_ldisc_ref_wait(tty);
+ if (!ld)
+ return -EIO;
ret = put_user(ld->ops->num, p);
tty_ldisc_deref(ld);
return ret;
return retval;
}
ld = tty_ldisc_ref_wait(tty);
+ if (!ld)
+ return hung_up_tty_ioctl(file, cmd, arg);
retval = -EINVAL;
if (ld->ops->ioctl) {
retval = ld->ops->ioctl(tty, file, cmd, arg);
}
ld = tty_ldisc_ref_wait(tty);
+ if (!ld)
+ return hung_up_tty_compat_ioctl(file, cmd, arg);
if (ld->ops->compat_ioctl)
retval = ld->ops->compat_ioctl(tty, file, cmd, arg);
else