diff options
Diffstat (limited to 'drivers/tty/tty_io.c')
-rw-r--r-- | drivers/tty/tty_io.c | 50 |
1 files changed, 38 insertions, 12 deletions
diff --git a/drivers/tty/tty_io.c b/drivers/tty/tty_io.c index 4f1fc81112e6..05085beb83db 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) | |||
194 | return ((struct tty_file_private *)file->private_data)->tty; | 194 | return ((struct tty_file_private *)file->private_data)->tty; |
195 | } | 195 | } |
196 | 196 | ||
197 | /* Associate a new file with the tty structure */ | 197 | int tty_alloc_file(struct file *file) |
198 | int tty_add_file(struct tty_struct *tty, struct file *file) | ||
199 | { | 198 | { |
200 | struct tty_file_private *priv; | 199 | struct tty_file_private *priv; |
201 | 200 | ||
@@ -203,15 +202,36 @@ int tty_add_file(struct tty_struct *tty, struct file *file) | |||
203 | if (!priv) | 202 | if (!priv) |
204 | return -ENOMEM; | 203 | return -ENOMEM; |
205 | 204 | ||
205 | file->private_data = priv; | ||
206 | |||
207 | return 0; | ||
208 | } | ||
209 | |||
210 | /* Associate a new file with the tty structure */ | ||
211 | void tty_add_file(struct tty_struct *tty, struct file *file) | ||
212 | { | ||
213 | struct tty_file_private *priv = file->private_data; | ||
214 | |||
206 | priv->tty = tty; | 215 | priv->tty = tty; |
207 | priv->file = file; | 216 | priv->file = file; |
208 | file->private_data = priv; | ||
209 | 217 | ||
210 | spin_lock(&tty_files_lock); | 218 | spin_lock(&tty_files_lock); |
211 | list_add(&priv->list, &tty->tty_files); | 219 | list_add(&priv->list, &tty->tty_files); |
212 | spin_unlock(&tty_files_lock); | 220 | spin_unlock(&tty_files_lock); |
221 | } | ||
213 | 222 | ||
214 | return 0; | 223 | /** |
224 | * tty_free_file - free file->private_data | ||
225 | * | ||
226 | * This shall be used only for fail path handling when tty_add_file was not | ||
227 | * called yet. | ||
228 | */ | ||
229 | void tty_free_file(struct file *file) | ||
230 | { | ||
231 | struct tty_file_private *priv = file->private_data; | ||
232 | |||
233 | file->private_data = NULL; | ||
234 | kfree(priv); | ||
215 | } | 235 | } |
216 | 236 | ||
217 | /* Delete file from its tty */ | 237 | /* Delete file from its tty */ |
@@ -222,8 +242,7 @@ void tty_del_file(struct file *file) | |||
222 | spin_lock(&tty_files_lock); | 242 | spin_lock(&tty_files_lock); |
223 | list_del(&priv->list); | 243 | list_del(&priv->list); |
224 | spin_unlock(&tty_files_lock); | 244 | spin_unlock(&tty_files_lock); |
225 | file->private_data = NULL; | 245 | tty_free_file(file); |
226 | kfree(priv); | ||
227 | } | 246 | } |
228 | 247 | ||
229 | 248 | ||
@@ -1811,6 +1830,10 @@ static int tty_open(struct inode *inode, struct file *filp) | |||
1811 | nonseekable_open(inode, filp); | 1830 | nonseekable_open(inode, filp); |
1812 | 1831 | ||
1813 | retry_open: | 1832 | retry_open: |
1833 | retval = tty_alloc_file(filp); | ||
1834 | if (retval) | ||
1835 | return -ENOMEM; | ||
1836 | |||
1814 | noctty = filp->f_flags & O_NOCTTY; | 1837 | noctty = filp->f_flags & O_NOCTTY; |
1815 | index = -1; | 1838 | index = -1; |
1816 | retval = 0; | 1839 | retval = 0; |
@@ -1823,6 +1846,7 @@ retry_open: | |||
1823 | if (!tty) { | 1846 | if (!tty) { |
1824 | tty_unlock(); | 1847 | tty_unlock(); |
1825 | mutex_unlock(&tty_mutex); | 1848 | mutex_unlock(&tty_mutex); |
1849 | tty_free_file(filp); | ||
1826 | return -ENXIO; | 1850 | return -ENXIO; |
1827 | } | 1851 | } |
1828 | driver = tty_driver_kref_get(tty->driver); | 1852 | driver = tty_driver_kref_get(tty->driver); |
@@ -1855,6 +1879,7 @@ retry_open: | |||
1855 | } | 1879 | } |
1856 | tty_unlock(); | 1880 | tty_unlock(); |
1857 | mutex_unlock(&tty_mutex); | 1881 | mutex_unlock(&tty_mutex); |
1882 | tty_free_file(filp); | ||
1858 | return -ENODEV; | 1883 | return -ENODEV; |
1859 | } | 1884 | } |
1860 | 1885 | ||
@@ -1862,6 +1887,7 @@ retry_open: | |||
1862 | if (!driver) { | 1887 | if (!driver) { |
1863 | tty_unlock(); | 1888 | tty_unlock(); |
1864 | mutex_unlock(&tty_mutex); | 1889 | mutex_unlock(&tty_mutex); |
1890 | tty_free_file(filp); | ||
1865 | return -ENODEV; | 1891 | return -ENODEV; |
1866 | } | 1892 | } |
1867 | got_driver: | 1893 | got_driver: |
@@ -1872,6 +1898,8 @@ got_driver: | |||
1872 | if (IS_ERR(tty)) { | 1898 | if (IS_ERR(tty)) { |
1873 | tty_unlock(); | 1899 | tty_unlock(); |
1874 | mutex_unlock(&tty_mutex); | 1900 | mutex_unlock(&tty_mutex); |
1901 | tty_driver_kref_put(driver); | ||
1902 | tty_free_file(filp); | ||
1875 | return PTR_ERR(tty); | 1903 | return PTR_ERR(tty); |
1876 | } | 1904 | } |
1877 | } | 1905 | } |
@@ -1887,15 +1915,11 @@ got_driver: | |||
1887 | tty_driver_kref_put(driver); | 1915 | tty_driver_kref_put(driver); |
1888 | if (IS_ERR(tty)) { | 1916 | if (IS_ERR(tty)) { |
1889 | tty_unlock(); | 1917 | tty_unlock(); |
1918 | tty_free_file(filp); | ||
1890 | return PTR_ERR(tty); | 1919 | return PTR_ERR(tty); |
1891 | } | 1920 | } |
1892 | 1921 | ||
1893 | retval = tty_add_file(tty, filp); | 1922 | tty_add_file(tty, filp); |
1894 | if (retval) { | ||
1895 | tty_unlock(); | ||
1896 | tty_release(inode, filp); | ||
1897 | return retval; | ||
1898 | } | ||
1899 | 1923 | ||
1900 | check_tty_count(tty, "tty_open"); | 1924 | check_tty_count(tty, "tty_open"); |
1901 | if (tty->driver->type == TTY_DRIVER_TYPE_PTY && | 1925 | if (tty->driver->type == TTY_DRIVER_TYPE_PTY && |
@@ -2716,6 +2740,8 @@ static long tty_compat_ioctl(struct file *file, unsigned int cmd, | |||
2716 | ld = tty_ldisc_ref_wait(tty); | 2740 | ld = tty_ldisc_ref_wait(tty); |
2717 | if (ld->ops->compat_ioctl) | 2741 | if (ld->ops->compat_ioctl) |
2718 | retval = ld->ops->compat_ioctl(tty, file, cmd, arg); | 2742 | retval = ld->ops->compat_ioctl(tty, file, cmd, arg); |
2743 | else | ||
2744 | retval = n_tty_compat_ioctl_helper(tty, file, cmd, arg); | ||
2719 | tty_ldisc_deref(ld); | 2745 | tty_ldisc_deref(ld); |
2720 | 2746 | ||
2721 | return retval; | 2747 | return retval; |