|
@@ -1994,6 +1994,69 @@ static struct tty_driver *tty_lookup_driver(dev_t device, struct file *filp,
|
|
|
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
|
|
@@ -2022,8 +2085,6 @@ static int tty_open(struct inode *inode, struct file *filp)
|
|
|
{
|
|
|
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;
|
|
|
|
|
@@ -2034,53 +2095,15 @@ retry_open:
|
|
|
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;
|
|
|
}
|
|
@@ -2151,15 +2174,6 @@ 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;
|
|
|
}
|
|
|
|
|
|
|