tty_lock: Localise the lock
In each remaining case the tty_lock is associated with a specific tty. This means we can now lock on a per tty basis. We do need tty_lock_pair() for the pty case. Uglier but still a step in the right direction. [fixed up calls in 3 missing drivers - gregkh] Signed-off-by: Alan Cox <alan@linux.intel.com> Acked-by: Arnd Bergmann <arnd@arndb.de> Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
This commit is contained in:

committed by
Greg Kroah-Hartman

parent
d739e65bb2
commit
d29f3ef39b
@@ -185,6 +185,7 @@ void free_tty_struct(struct tty_struct *tty)
|
||||
put_device(tty->dev);
|
||||
kfree(tty->write_buf);
|
||||
tty_buffer_free_all(tty);
|
||||
tty->magic = 0xDEADDEAD;
|
||||
kfree(tty);
|
||||
}
|
||||
|
||||
@@ -573,7 +574,7 @@ void __tty_hangup(struct tty_struct *tty)
|
||||
}
|
||||
spin_unlock(&redirect_lock);
|
||||
|
||||
tty_lock();
|
||||
tty_lock(tty);
|
||||
|
||||
/* some functions below drop BTM, so we need this bit */
|
||||
set_bit(TTY_HUPPING, &tty->flags);
|
||||
@@ -666,7 +667,7 @@ void __tty_hangup(struct tty_struct *tty)
|
||||
clear_bit(TTY_HUPPING, &tty->flags);
|
||||
tty_ldisc_enable(tty);
|
||||
|
||||
tty_unlock();
|
||||
tty_unlock(tty);
|
||||
|
||||
if (f)
|
||||
fput(f);
|
||||
@@ -1103,12 +1104,12 @@ void tty_write_message(struct tty_struct *tty, char *msg)
|
||||
{
|
||||
if (tty) {
|
||||
mutex_lock(&tty->atomic_write_lock);
|
||||
tty_lock();
|
||||
tty_lock(tty);
|
||||
if (tty->ops->write && !test_bit(TTY_CLOSING, &tty->flags)) {
|
||||
tty_unlock();
|
||||
tty_unlock(tty);
|
||||
tty->ops->write(tty, msg, strlen(msg));
|
||||
} else
|
||||
tty_unlock();
|
||||
tty_unlock(tty);
|
||||
tty_write_unlock(tty);
|
||||
}
|
||||
return;
|
||||
@@ -1403,6 +1404,7 @@ struct tty_struct *tty_init_dev(struct tty_driver *driver, int idx)
|
||||
}
|
||||
initialize_tty_struct(tty, driver, idx);
|
||||
|
||||
tty_lock(tty);
|
||||
retval = tty_driver_install_tty(driver, tty);
|
||||
if (retval < 0)
|
||||
goto err_deinit_tty;
|
||||
@@ -1415,9 +1417,11 @@ struct tty_struct *tty_init_dev(struct tty_driver *driver, int idx)
|
||||
retval = tty_ldisc_setup(tty, tty->link);
|
||||
if (retval)
|
||||
goto err_release_tty;
|
||||
/* Return the tty locked so that it cannot vanish under the caller */
|
||||
return tty;
|
||||
|
||||
err_deinit_tty:
|
||||
tty_unlock(tty);
|
||||
deinitialize_tty_struct(tty);
|
||||
free_tty_struct(tty);
|
||||
err_module_put:
|
||||
@@ -1426,6 +1430,7 @@ err_module_put:
|
||||
|
||||
/* call the tty release_tty routine to clean out this slot */
|
||||
err_release_tty:
|
||||
tty_unlock(tty);
|
||||
printk_ratelimited(KERN_INFO "tty_init_dev: ldisc open failed, "
|
||||
"clearing slot %d\n", idx);
|
||||
release_tty(tty, idx);
|
||||
@@ -1628,7 +1633,7 @@ int tty_release(struct inode *inode, struct file *filp)
|
||||
if (tty_paranoia_check(tty, inode, __func__))
|
||||
return 0;
|
||||
|
||||
tty_lock();
|
||||
tty_lock(tty);
|
||||
check_tty_count(tty, __func__);
|
||||
|
||||
__tty_fasync(-1, filp, 0);
|
||||
@@ -1637,10 +1642,11 @@ int tty_release(struct inode *inode, struct file *filp)
|
||||
pty_master = (tty->driver->type == TTY_DRIVER_TYPE_PTY &&
|
||||
tty->driver->subtype == PTY_TYPE_MASTER);
|
||||
devpts = (tty->driver->flags & TTY_DRIVER_DEVPTS_MEM) != 0;
|
||||
/* Review: parallel close */
|
||||
o_tty = tty->link;
|
||||
|
||||
if (tty_release_checks(tty, o_tty, idx)) {
|
||||
tty_unlock();
|
||||
tty_unlock(tty);
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -1652,7 +1658,7 @@ int tty_release(struct inode *inode, struct file *filp)
|
||||
if (tty->ops->close)
|
||||
tty->ops->close(tty, filp);
|
||||
|
||||
tty_unlock();
|
||||
tty_unlock(tty);
|
||||
/*
|
||||
* 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
|
||||
@@ -1675,7 +1681,7 @@ int tty_release(struct inode *inode, struct file *filp)
|
||||
opens on /dev/tty */
|
||||
|
||||
mutex_lock(&tty_mutex);
|
||||
tty_lock();
|
||||
tty_lock_pair(tty, o_tty);
|
||||
tty_closing = tty->count <= 1;
|
||||
o_tty_closing = o_tty &&
|
||||
(o_tty->count <= (pty_master ? 1 : 0));
|
||||
@@ -1706,7 +1712,7 @@ int tty_release(struct inode *inode, struct file *filp)
|
||||
|
||||
printk(KERN_WARNING "%s: %s: read/write wait queue active!\n",
|
||||
__func__, tty_name(tty, buf));
|
||||
tty_unlock();
|
||||
tty_unlock_pair(tty, o_tty);
|
||||
mutex_unlock(&tty_mutex);
|
||||
schedule();
|
||||
}
|
||||
@@ -1769,7 +1775,7 @@ int tty_release(struct inode *inode, struct file *filp)
|
||||
|
||||
/* check whether both sides are closing ... */
|
||||
if (!tty_closing || (o_tty && !o_tty_closing)) {
|
||||
tty_unlock();
|
||||
tty_unlock_pair(tty, o_tty);
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -1782,14 +1788,16 @@ int tty_release(struct inode *inode, struct file *filp)
|
||||
tty_ldisc_release(tty, o_tty);
|
||||
/*
|
||||
* The release_tty function takes care of the details of clearing
|
||||
* the slots and preserving the termios structure.
|
||||
* the slots and preserving the termios structure. The tty_unlock_pair
|
||||
* should be safe as we keep a kref while the tty is locked (so the
|
||||
* unlock never unlocks a freed tty).
|
||||
*/
|
||||
release_tty(tty, idx);
|
||||
tty_unlock_pair(tty, o_tty);
|
||||
|
||||
/* Make this pty number available for reallocation */
|
||||
if (devpts)
|
||||
devpts_kill_index(inode, idx);
|
||||
tty_unlock();
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -1893,6 +1901,9 @@ static struct tty_driver *tty_lookup_driver(dev_t device, struct file *filp,
|
||||
* Locking: tty_mutex protects tty, tty_lookup_driver and tty_init_dev.
|
||||
* tty->count should protect the rest.
|
||||
* ->siglock protects ->signal/->sighand
|
||||
*
|
||||
* Note: the tty_unlock/lock cases without a ref are only safe due to
|
||||
* tty_mutex
|
||||
*/
|
||||
|
||||
static int tty_open(struct inode *inode, struct file *filp)
|
||||
@@ -1916,8 +1927,7 @@ retry_open:
|
||||
retval = 0;
|
||||
|
||||
mutex_lock(&tty_mutex);
|
||||
tty_lock();
|
||||
|
||||
/* This is protected by the tty_mutex */
|
||||
tty = tty_open_current_tty(device, filp);
|
||||
if (IS_ERR(tty)) {
|
||||
retval = PTR_ERR(tty);
|
||||
@@ -1938,17 +1948,19 @@ retry_open:
|
||||
}
|
||||
|
||||
if (tty) {
|
||||
tty_lock(tty);
|
||||
retval = tty_reopen(tty);
|
||||
if (retval)
|
||||
if (retval < 0) {
|
||||
tty_unlock(tty);
|
||||
tty = ERR_PTR(retval);
|
||||
} else
|
||||
}
|
||||
} else /* Returns with the tty_lock held for now */
|
||||
tty = tty_init_dev(driver, index);
|
||||
|
||||
mutex_unlock(&tty_mutex);
|
||||
if (driver)
|
||||
tty_driver_kref_put(driver);
|
||||
if (IS_ERR(tty)) {
|
||||
tty_unlock();
|
||||
retval = PTR_ERR(tty);
|
||||
goto err_file;
|
||||
}
|
||||
@@ -1977,7 +1989,7 @@ retry_open:
|
||||
printk(KERN_DEBUG "%s: error %d in opening %s...\n", __func__,
|
||||
retval, tty->name);
|
||||
#endif
|
||||
tty_unlock(); /* need to call tty_release without BTM */
|
||||
tty_unlock(tty); /* need to call tty_release without BTM */
|
||||
tty_release(inode, filp);
|
||||
if (retval != -ERESTARTSYS)
|
||||
return retval;
|
||||
@@ -1989,17 +2001,15 @@ retry_open:
|
||||
/*
|
||||
* Need to reset f_op in case a hangup happened.
|
||||
*/
|
||||
tty_lock();
|
||||
if (filp->f_op == &hung_up_tty_fops)
|
||||
filp->f_op = &tty_fops;
|
||||
tty_unlock();
|
||||
goto retry_open;
|
||||
}
|
||||
tty_unlock();
|
||||
tty_unlock(tty);
|
||||
|
||||
|
||||
mutex_lock(&tty_mutex);
|
||||
tty_lock();
|
||||
tty_lock(tty);
|
||||
spin_lock_irq(¤t->sighand->siglock);
|
||||
if (!noctty &&
|
||||
current->signal->leader &&
|
||||
@@ -2007,11 +2017,10 @@ retry_open:
|
||||
tty->session == NULL)
|
||||
__proc_set_tty(current, tty);
|
||||
spin_unlock_irq(¤t->sighand->siglock);
|
||||
tty_unlock();
|
||||
tty_unlock(tty);
|
||||
mutex_unlock(&tty_mutex);
|
||||
return 0;
|
||||
err_unlock:
|
||||
tty_unlock();
|
||||
mutex_unlock(&tty_mutex);
|
||||
/* after locks to avoid deadlock */
|
||||
if (!IS_ERR_OR_NULL(driver))
|
||||
@@ -2094,10 +2103,13 @@ out:
|
||||
|
||||
static int tty_fasync(int fd, struct file *filp, int on)
|
||||
{
|
||||
struct tty_struct *tty = file_tty(filp);
|
||||
int retval;
|
||||
tty_lock();
|
||||
|
||||
tty_lock(tty);
|
||||
retval = __tty_fasync(fd, filp, on);
|
||||
tty_unlock();
|
||||
tty_unlock(tty);
|
||||
|
||||
return retval;
|
||||
}
|
||||
|
||||
@@ -2934,6 +2946,7 @@ void initialize_tty_struct(struct tty_struct *tty,
|
||||
tty->pgrp = NULL;
|
||||
tty->overrun_time = jiffies;
|
||||
tty_buffer_init(tty);
|
||||
mutex_init(&tty->legacy_mutex);
|
||||
mutex_init(&tty->termios_mutex);
|
||||
mutex_init(&tty->ldisc_mutex);
|
||||
init_waitqueue_head(&tty->write_wait);
|
||||
|
Reference in New Issue
Block a user