summaryrefslogtreecommitdiffstats
path: root/drivers/tty/tty_io.c
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/tty/tty_io.c')
-rw-r--r--drivers/tty/tty_io.c50
1 files changed, 38 insertions, 12 deletions
diff --git a/drivers/tty/tty_io.c b/drivers/tty/tty_io.c
index 4f1fc81112e..05085beb83d 100644
--- a/drivers/tty/tty_io.c
+++ b/drivers/tty/tty_io.c
@@ -194,8 +194,7 @@ static inline struct tty_struct *file_tty(struct file *file)
return ((struct tty_file_private *)file->private_data)->tty;
}
-/* Associate a new file with the tty structure */
-int tty_add_file(struct tty_struct *tty, struct file *file)
+int tty_alloc_file(struct file *file)
{
struct tty_file_private *priv;
@@ -203,15 +202,36 @@ int tty_add_file(struct tty_struct *tty, struct file *file)
if (!priv)
return -ENOMEM;
+ file->private_data = priv;
+
+ return 0;
+}
+
+/* Associate a new file with the tty structure */
+void tty_add_file(struct tty_struct *tty, struct file *file)
+{
+ struct tty_file_private *priv = file->private_data;
+
priv->tty = tty;
priv->file = file;
- file->private_data = priv;
spin_lock(&tty_files_lock);
list_add(&priv->list, &tty->tty_files);
spin_unlock(&tty_files_lock);
+}
- return 0;
+/**
+ * tty_free_file - free file->private_data
+ *
+ * This shall be used only for fail path handling when tty_add_file was not
+ * called yet.
+ */
+void tty_free_file(struct file *file)
+{
+ struct tty_file_private *priv = file->private_data;
+
+ file->private_data = NULL;
+ kfree(priv);
}
/* Delete file from its tty */
@@ -222,8 +242,7 @@ void tty_del_file(struct file *file)
spin_lock(&tty_files_lock);
list_del(&priv->list);
spin_unlock(&tty_files_lock);
- file->private_data = NULL;
- kfree(priv);
+ tty_free_file(file);
}
@@ -1811,6 +1830,10 @@ static int tty_open(struct inode *inode, struct file *filp)
nonseekable_open(inode, filp);
retry_open:
+ retval = tty_alloc_file(filp);
+ if (retval)
+ return -ENOMEM;
+
noctty = filp->f_flags & O_NOCTTY;
index = -1;
retval = 0;
@@ -1823,6 +1846,7 @@ retry_open:
if (!tty) {
tty_unlock();
mutex_unlock(&tty_mutex);
+ tty_free_file(filp);
return -ENXIO;
}
driver = tty_driver_kref_get(tty->driver);
@@ -1855,6 +1879,7 @@ retry_open:
}
tty_unlock();
mutex_unlock(&tty_mutex);
+ tty_free_file(filp);
return -ENODEV;
}
@@ -1862,6 +1887,7 @@ retry_open:
if (!driver) {
tty_unlock();
mutex_unlock(&tty_mutex);
+ tty_free_file(filp);
return -ENODEV;
}
got_driver:
@@ -1872,6 +1898,8 @@ got_driver:
if (IS_ERR(tty)) {
tty_unlock();
mutex_unlock(&tty_mutex);
+ tty_driver_kref_put(driver);
+ tty_free_file(filp);
return PTR_ERR(tty);
}
}
@@ -1887,15 +1915,11 @@ got_driver:
tty_driver_kref_put(driver);
if (IS_ERR(tty)) {
tty_unlock();
+ tty_free_file(filp);
return PTR_ERR(tty);
}
- retval = tty_add_file(tty, filp);
- if (retval) {
- tty_unlock();
- tty_release(inode, filp);
- return retval;
- }
+ tty_add_file(tty, filp);
check_tty_count(tty, "tty_open");
if (tty->driver->type == TTY_DRIVER_TYPE_PTY &&
@@ -2716,6 +2740,8 @@ static long tty_compat_ioctl(struct file *file, unsigned int cmd,
ld = tty_ldisc_ref_wait(tty);
if (ld->ops->compat_ioctl)
retval = ld->ops->compat_ioctl(tty, file, cmd, arg);
+ else
+ retval = n_tty_compat_ioctl_helper(tty, file, cmd, arg);
tty_ldisc_deref(ld);
return retval;