|
@@ -142,7 +142,6 @@ ssize_t redirected_tty_write(struct file *, const char __user *,
|
|
|
size_t, loff_t *);
|
|
|
static unsigned int tty_poll(struct file *, poll_table *);
|
|
|
static int tty_open(struct inode *, struct file *);
|
|
|
-static int tty_release(struct inode *, struct file *);
|
|
|
long tty_ioctl(struct file *file, unsigned int cmd, unsigned long arg);
|
|
|
#ifdef CONFIG_COMPAT
|
|
|
static long tty_compat_ioctl(struct file *file, unsigned int cmd,
|
|
@@ -1017,14 +1016,16 @@ out:
|
|
|
|
|
|
void tty_write_message(struct tty_struct *tty, char *msg)
|
|
|
{
|
|
|
- lock_kernel();
|
|
|
if (tty) {
|
|
|
mutex_lock(&tty->atomic_write_lock);
|
|
|
- if (tty->ops->write && !test_bit(TTY_CLOSING, &tty->flags))
|
|
|
+ lock_kernel();
|
|
|
+ if (tty->ops->write && !test_bit(TTY_CLOSING, &tty->flags)) {
|
|
|
+ unlock_kernel();
|
|
|
tty->ops->write(tty, msg, strlen(msg));
|
|
|
+ } else
|
|
|
+ unlock_kernel();
|
|
|
tty_write_unlock(tty);
|
|
|
}
|
|
|
- unlock_kernel();
|
|
|
return;
|
|
|
}
|
|
|
|
|
@@ -1202,14 +1203,21 @@ static int tty_driver_install_tty(struct tty_driver *driver,
|
|
|
struct tty_struct *tty)
|
|
|
{
|
|
|
int idx = tty->index;
|
|
|
+ int ret;
|
|
|
|
|
|
- if (driver->ops->install)
|
|
|
- return driver->ops->install(driver, tty);
|
|
|
+ if (driver->ops->install) {
|
|
|
+ lock_kernel();
|
|
|
+ ret = driver->ops->install(driver, tty);
|
|
|
+ unlock_kernel();
|
|
|
+ return ret;
|
|
|
+ }
|
|
|
|
|
|
if (tty_init_termios(tty) == 0) {
|
|
|
+ lock_kernel();
|
|
|
tty_driver_kref_get(driver);
|
|
|
tty->count++;
|
|
|
driver->ttys[idx] = tty;
|
|
|
+ unlock_kernel();
|
|
|
return 0;
|
|
|
}
|
|
|
return -ENOMEM;
|
|
@@ -1302,10 +1310,14 @@ struct tty_struct *tty_init_dev(struct tty_driver *driver, int idx,
|
|
|
struct tty_struct *tty;
|
|
|
int retval;
|
|
|
|
|
|
+ lock_kernel();
|
|
|
/* Check if pty master is being opened multiple times */
|
|
|
if (driver->subtype == PTY_TYPE_MASTER &&
|
|
|
- (driver->flags & TTY_DRIVER_DEVPTS_MEM) && !first_ok)
|
|
|
+ (driver->flags & TTY_DRIVER_DEVPTS_MEM) && !first_ok) {
|
|
|
+ unlock_kernel();
|
|
|
return ERR_PTR(-EIO);
|
|
|
+ }
|
|
|
+ unlock_kernel();
|
|
|
|
|
|
/*
|
|
|
* First time open is complex, especially for PTY devices.
|
|
@@ -1335,8 +1347,9 @@ struct tty_struct *tty_init_dev(struct tty_driver *driver, int idx,
|
|
|
* If we fail here just call release_tty to clean up. No need
|
|
|
* to decrement the use counts, as release_tty doesn't care.
|
|
|
*/
|
|
|
-
|
|
|
+ lock_kernel();
|
|
|
retval = tty_ldisc_setup(tty, tty->link);
|
|
|
+ unlock_kernel();
|
|
|
if (retval)
|
|
|
goto release_mem_out;
|
|
|
return tty;
|
|
@@ -1350,7 +1363,9 @@ release_mem_out:
|
|
|
if (printk_ratelimit())
|
|
|
printk(KERN_INFO "tty_init_dev: ldisc open failed, "
|
|
|
"clearing slot %d\n", idx);
|
|
|
+ lock_kernel();
|
|
|
release_tty(tty, idx);
|
|
|
+ unlock_kernel();
|
|
|
return ERR_PTR(retval);
|
|
|
}
|
|
|
|
|
@@ -1464,7 +1479,17 @@ static void release_tty(struct tty_struct *tty, int idx)
|
|
|
tty_kref_put(tty);
|
|
|
}
|
|
|
|
|
|
-/*
|
|
|
+/**
|
|
|
+ * tty_release - vfs callback for close
|
|
|
+ * @inode: inode of tty
|
|
|
+ * @filp: file pointer for handle to tty
|
|
|
+ *
|
|
|
+ * Called the last time each file handle is closed that references
|
|
|
+ * this tty. There may however be several such references.
|
|
|
+ *
|
|
|
+ * Locking:
|
|
|
+ * Takes bkl. See tty_release_dev
|
|
|
+ *
|
|
|
* Even releasing the tty structures is a tricky business.. We have
|
|
|
* to be very careful that the structures are all released at the
|
|
|
* same time, as interrupts might otherwise get the wrong pointers.
|
|
@@ -1472,20 +1497,20 @@ static void release_tty(struct tty_struct *tty, int idx)
|
|
|
* WSH 09/09/97: rewritten to avoid some nasty race conditions that could
|
|
|
* lead to double frees or releasing memory still in use.
|
|
|
*/
|
|
|
-void tty_release_dev(struct file *filp)
|
|
|
+
|
|
|
+int tty_release(struct inode *inode, struct file *filp)
|
|
|
{
|
|
|
struct tty_struct *tty, *o_tty;
|
|
|
int pty_master, tty_closing, o_tty_closing, do_sleep;
|
|
|
int devpts;
|
|
|
int idx;
|
|
|
char buf[64];
|
|
|
- struct inode *inode;
|
|
|
|
|
|
- inode = filp->f_path.dentry->d_inode;
|
|
|
tty = (struct tty_struct *)filp->private_data;
|
|
|
if (tty_paranoia_check(tty, inode, "tty_release_dev"))
|
|
|
- return;
|
|
|
+ return 0;
|
|
|
|
|
|
+ lock_kernel();
|
|
|
check_tty_count(tty, "tty_release_dev");
|
|
|
|
|
|
tty_fasync(-1, filp, 0);
|
|
@@ -1500,19 +1525,22 @@ void tty_release_dev(struct file *filp)
|
|
|
if (idx < 0 || idx >= tty->driver->num) {
|
|
|
printk(KERN_DEBUG "tty_release_dev: bad idx when trying to "
|
|
|
"free (%s)\n", tty->name);
|
|
|
- return;
|
|
|
+ unlock_kernel();
|
|
|
+ return 0;
|
|
|
}
|
|
|
if (!devpts) {
|
|
|
if (tty != tty->driver->ttys[idx]) {
|
|
|
+ unlock_kernel();
|
|
|
printk(KERN_DEBUG "tty_release_dev: driver.table[%d] not tty "
|
|
|
"for (%s)\n", idx, tty->name);
|
|
|
- return;
|
|
|
+ return 0;
|
|
|
}
|
|
|
if (tty->termios != tty->driver->termios[idx]) {
|
|
|
+ unlock_kernel();
|
|
|
printk(KERN_DEBUG "tty_release_dev: driver.termios[%d] not termios "
|
|
|
"for (%s)\n",
|
|
|
idx, tty->name);
|
|
|
- return;
|
|
|
+ return 0;
|
|
|
}
|
|
|
}
|
|
|
#endif
|
|
@@ -1526,26 +1554,30 @@ void tty_release_dev(struct file *filp)
|
|
|
if (tty->driver->other &&
|
|
|
!(tty->driver->flags & TTY_DRIVER_DEVPTS_MEM)) {
|
|
|
if (o_tty != tty->driver->other->ttys[idx]) {
|
|
|
+ unlock_kernel();
|
|
|
printk(KERN_DEBUG "tty_release_dev: other->table[%d] "
|
|
|
"not o_tty for (%s)\n",
|
|
|
idx, tty->name);
|
|
|
- return;
|
|
|
+ return 0 ;
|
|
|
}
|
|
|
if (o_tty->termios != tty->driver->other->termios[idx]) {
|
|
|
+ unlock_kernel();
|
|
|
printk(KERN_DEBUG "tty_release_dev: other->termios[%d] "
|
|
|
"not o_termios for (%s)\n",
|
|
|
idx, tty->name);
|
|
|
- return;
|
|
|
+ return 0;
|
|
|
}
|
|
|
if (o_tty->link != tty) {
|
|
|
+ unlock_kernel();
|
|
|
printk(KERN_DEBUG "tty_release_dev: bad pty pointers\n");
|
|
|
- return;
|
|
|
+ return 0;
|
|
|
}
|
|
|
}
|
|
|
#endif
|
|
|
if (tty->ops->close)
|
|
|
tty->ops->close(tty, filp);
|
|
|
|
|
|
+ unlock_kernel();
|
|
|
/*
|
|
|
* Sanity check: if tty->count is going to zero, there shouldn't be
|
|
|
* any waiters on tty->read_wait or tty->write_wait. We test the
|
|
@@ -1568,6 +1600,7 @@ void tty_release_dev(struct file *filp)
|
|
|
opens on /dev/tty */
|
|
|
|
|
|
mutex_lock(&tty_mutex);
|
|
|
+ lock_kernel();
|
|
|
tty_closing = tty->count <= 1;
|
|
|
o_tty_closing = o_tty &&
|
|
|
(o_tty->count <= (pty_master ? 1 : 0));
|
|
@@ -1598,6 +1631,7 @@ void tty_release_dev(struct file *filp)
|
|
|
|
|
|
printk(KERN_WARNING "tty_release_dev: %s: read/write wait queue "
|
|
|
"active!\n", tty_name(tty, buf));
|
|
|
+ unlock_kernel();
|
|
|
mutex_unlock(&tty_mutex);
|
|
|
schedule();
|
|
|
}
|
|
@@ -1661,8 +1695,10 @@ void tty_release_dev(struct file *filp)
|
|
|
mutex_unlock(&tty_mutex);
|
|
|
|
|
|
/* check whether both sides are closing ... */
|
|
|
- if (!tty_closing || (o_tty && !o_tty_closing))
|
|
|
- return;
|
|
|
+ if (!tty_closing || (o_tty && !o_tty_closing)) {
|
|
|
+ unlock_kernel();
|
|
|
+ return 0;
|
|
|
+ }
|
|
|
|
|
|
#ifdef TTY_DEBUG_HANGUP
|
|
|
printk(KERN_DEBUG "freeing tty structure...");
|
|
@@ -1680,10 +1716,12 @@ void tty_release_dev(struct file *filp)
|
|
|
/* Make this pty number available for reallocation */
|
|
|
if (devpts)
|
|
|
devpts_kill_index(inode, idx);
|
|
|
+ unlock_kernel();
|
|
|
+ return 0;
|
|
|
}
|
|
|
|
|
|
/**
|
|
|
- * __tty_open - open a tty device
|
|
|
+ * tty_open - open a tty device
|
|
|
* @inode: inode of device file
|
|
|
* @filp: file pointer to tty
|
|
|
*
|
|
@@ -1703,7 +1741,7 @@ void tty_release_dev(struct file *filp)
|
|
|
* ->siglock protects ->signal/->sighand
|
|
|
*/
|
|
|
|
|
|
-static int __tty_open(struct inode *inode, struct file *filp)
|
|
|
+static int tty_open(struct inode *inode, struct file *filp)
|
|
|
{
|
|
|
struct tty_struct *tty = NULL;
|
|
|
int noctty, retval;
|
|
@@ -1720,10 +1758,12 @@ retry_open:
|
|
|
retval = 0;
|
|
|
|
|
|
mutex_lock(&tty_mutex);
|
|
|
+ lock_kernel();
|
|
|
|
|
|
if (device == MKDEV(TTYAUX_MAJOR, 0)) {
|
|
|
tty = get_current_tty();
|
|
|
if (!tty) {
|
|
|
+ unlock_kernel();
|
|
|
mutex_unlock(&tty_mutex);
|
|
|
return -ENXIO;
|
|
|
}
|
|
@@ -1755,12 +1795,14 @@ retry_open:
|
|
|
goto got_driver;
|
|
|
}
|
|
|
}
|
|
|
+ unlock_kernel();
|
|
|
mutex_unlock(&tty_mutex);
|
|
|
return -ENODEV;
|
|
|
}
|
|
|
|
|
|
driver = get_tty_driver(device, &index);
|
|
|
if (!driver) {
|
|
|
+ unlock_kernel();
|
|
|
mutex_unlock(&tty_mutex);
|
|
|
return -ENODEV;
|
|
|
}
|
|
@@ -1770,6 +1812,7 @@ got_driver:
|
|
|
tty = tty_driver_lookup_tty(driver, inode, index);
|
|
|
|
|
|
if (IS_ERR(tty)) {
|
|
|
+ unlock_kernel();
|
|
|
mutex_unlock(&tty_mutex);
|
|
|
return PTR_ERR(tty);
|
|
|
}
|
|
@@ -1784,8 +1827,10 @@ got_driver:
|
|
|
|
|
|
mutex_unlock(&tty_mutex);
|
|
|
tty_driver_kref_put(driver);
|
|
|
- if (IS_ERR(tty))
|
|
|
+ if (IS_ERR(tty)) {
|
|
|
+ unlock_kernel();
|
|
|
return PTR_ERR(tty);
|
|
|
+ }
|
|
|
|
|
|
filp->private_data = tty;
|
|
|
file_move(filp, &tty->tty_files);
|
|
@@ -1813,11 +1858,15 @@ got_driver:
|
|
|
printk(KERN_DEBUG "error %d in opening %s...", retval,
|
|
|
tty->name);
|
|
|
#endif
|
|
|
- tty_release_dev(filp);
|
|
|
- if (retval != -ERESTARTSYS)
|
|
|
+ tty_release(inode, filp);
|
|
|
+ if (retval != -ERESTARTSYS) {
|
|
|
+ unlock_kernel();
|
|
|
return retval;
|
|
|
- if (signal_pending(current))
|
|
|
+ }
|
|
|
+ if (signal_pending(current)) {
|
|
|
+ unlock_kernel();
|
|
|
return retval;
|
|
|
+ }
|
|
|
schedule();
|
|
|
/*
|
|
|
* Need to reset f_op in case a hangup happened.
|
|
@@ -1826,8 +1875,11 @@ got_driver:
|
|
|
filp->f_op = &tty_fops;
|
|
|
goto retry_open;
|
|
|
}
|
|
|
+ unlock_kernel();
|
|
|
+
|
|
|
|
|
|
mutex_lock(&tty_mutex);
|
|
|
+ lock_kernel();
|
|
|
spin_lock_irq(¤t->sighand->siglock);
|
|
|
if (!noctty &&
|
|
|
current->signal->leader &&
|
|
@@ -1835,44 +1887,13 @@ got_driver:
|
|
|
tty->session == NULL)
|
|
|
__proc_set_tty(current, tty);
|
|
|
spin_unlock_irq(¤t->sighand->siglock);
|
|
|
+ unlock_kernel();
|
|
|
mutex_unlock(&tty_mutex);
|
|
|
return 0;
|
|
|
}
|
|
|
|
|
|
-/* BKL pushdown: scary code avoidance wrapper */
|
|
|
-static int tty_open(struct inode *inode, struct file *filp)
|
|
|
-{
|
|
|
- int ret;
|
|
|
-
|
|
|
- lock_kernel();
|
|
|
- ret = __tty_open(inode, filp);
|
|
|
- unlock_kernel();
|
|
|
- return ret;
|
|
|
-}
|
|
|
|
|
|
|
|
|
-
|
|
|
-
|
|
|
-/**
|
|
|
- * tty_release - vfs callback for close
|
|
|
- * @inode: inode of tty
|
|
|
- * @filp: file pointer for handle to tty
|
|
|
- *
|
|
|
- * Called the last time each file handle is closed that references
|
|
|
- * this tty. There may however be several such references.
|
|
|
- *
|
|
|
- * Locking:
|
|
|
- * Takes bkl. See tty_release_dev
|
|
|
- */
|
|
|
-
|
|
|
-static int tty_release(struct inode *inode, struct file *filp)
|
|
|
-{
|
|
|
- lock_kernel();
|
|
|
- tty_release_dev(filp);
|
|
|
- unlock_kernel();
|
|
|
- return 0;
|
|
|
-}
|
|
|
-
|
|
|
/**
|
|
|
* tty_poll - check tty status
|
|
|
* @filp: file being polled
|
|
@@ -2317,9 +2338,7 @@ static int tiocsetd(struct tty_struct *tty, int __user *p)
|
|
|
if (get_user(ldisc, p))
|
|
|
return -EFAULT;
|
|
|
|
|
|
- lock_kernel();
|
|
|
ret = tty_set_ldisc(tty, ldisc);
|
|
|
- unlock_kernel();
|
|
|
|
|
|
return ret;
|
|
|
}
|