diff options
author | Alan Cox <alan@lxorguk.ukuu.org.uk> | 2008-04-30 03:53:29 -0400 |
---|---|---|
committer | Linus Torvalds <torvalds@linux-foundation.org> | 2008-04-30 11:29:40 -0400 |
commit | 04f378b198da233ca0aca341b113dc6579d46123 (patch) | |
tree | 696e7bd401125cee71ecaa2047c4273f38732554 /drivers/char/tty_io.c | |
parent | e52384426064bca0669a954736206adca7595d48 (diff) |
tty: BKL pushdown
- Push the BKL down into the line disciplines
- Switch the tty layer to unlocked_ioctl
- Introduce a new ctrl_lock spin lock for the control bits
- Eliminate much of the lock_kernel use in n_tty
- Prepare to (but don't yet) call the drivers with the lock dropped
on the paths that historically held the lock
BKL now primarily protects open/close/ldisc change in the tty layer
[jirislaby@gmail.com: a couple of fixes]
Signed-off-by: Alan Cox <alan@redhat.com>
Signed-off-by: Jiri Slaby <jirislaby@gmail.com>
Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
Diffstat (limited to 'drivers/char/tty_io.c')
-rw-r--r-- | drivers/char/tty_io.c | 107 |
1 files changed, 74 insertions, 33 deletions
diff --git a/drivers/char/tty_io.c b/drivers/char/tty_io.c index 2fa6856706ab..0b0354bc28d6 100644 --- a/drivers/char/tty_io.c +++ b/drivers/char/tty_io.c | |||
@@ -152,8 +152,7 @@ ssize_t redirected_tty_write(struct file *, const char __user *, | |||
152 | static unsigned int tty_poll(struct file *, poll_table *); | 152 | static unsigned int tty_poll(struct file *, poll_table *); |
153 | static int tty_open(struct inode *, struct file *); | 153 | static int tty_open(struct inode *, struct file *); |
154 | static int tty_release(struct inode *, struct file *); | 154 | static int tty_release(struct inode *, struct file *); |
155 | int tty_ioctl(struct inode *inode, struct file *file, | 155 | long tty_ioctl(struct file *file, unsigned int cmd, unsigned long arg); |
156 | unsigned int cmd, unsigned long arg); | ||
157 | #ifdef CONFIG_COMPAT | 156 | #ifdef CONFIG_COMPAT |
158 | static long tty_compat_ioctl(struct file *file, unsigned int cmd, | 157 | static long tty_compat_ioctl(struct file *file, unsigned int cmd, |
159 | unsigned long arg); | 158 | unsigned long arg); |
@@ -1205,7 +1204,7 @@ EXPORT_SYMBOL_GPL(tty_find_polling_driver); | |||
1205 | * not in the foreground, send a SIGTTOU. If the signal is blocked or | 1204 | * not in the foreground, send a SIGTTOU. If the signal is blocked or |
1206 | * ignored, go ahead and perform the operation. (POSIX 7.2) | 1205 | * ignored, go ahead and perform the operation. (POSIX 7.2) |
1207 | * | 1206 | * |
1208 | * Locking: none | 1207 | * Locking: none - FIXME: review this |
1209 | */ | 1208 | */ |
1210 | 1209 | ||
1211 | int tty_check_change(struct tty_struct *tty) | 1210 | int tty_check_change(struct tty_struct *tty) |
@@ -1247,8 +1246,8 @@ static unsigned int hung_up_tty_poll(struct file *filp, poll_table *wait) | |||
1247 | return POLLIN | POLLOUT | POLLERR | POLLHUP | POLLRDNORM | POLLWRNORM; | 1246 | return POLLIN | POLLOUT | POLLERR | POLLHUP | POLLRDNORM | POLLWRNORM; |
1248 | } | 1247 | } |
1249 | 1248 | ||
1250 | static int hung_up_tty_ioctl(struct inode *inode, struct file *file, | 1249 | static long hung_up_tty_ioctl(struct file *file, unsigned int cmd, |
1251 | unsigned int cmd, unsigned long arg) | 1250 | unsigned long arg) |
1252 | { | 1251 | { |
1253 | return cmd == TIOCSPGRP ? -ENOTTY : -EIO; | 1252 | return cmd == TIOCSPGRP ? -ENOTTY : -EIO; |
1254 | } | 1253 | } |
@@ -1264,7 +1263,7 @@ static const struct file_operations tty_fops = { | |||
1264 | .read = tty_read, | 1263 | .read = tty_read, |
1265 | .write = tty_write, | 1264 | .write = tty_write, |
1266 | .poll = tty_poll, | 1265 | .poll = tty_poll, |
1267 | .ioctl = tty_ioctl, | 1266 | .unlocked_ioctl = tty_ioctl, |
1268 | .compat_ioctl = tty_compat_ioctl, | 1267 | .compat_ioctl = tty_compat_ioctl, |
1269 | .open = tty_open, | 1268 | .open = tty_open, |
1270 | .release = tty_release, | 1269 | .release = tty_release, |
@@ -1277,7 +1276,7 @@ static const struct file_operations ptmx_fops = { | |||
1277 | .read = tty_read, | 1276 | .read = tty_read, |
1278 | .write = tty_write, | 1277 | .write = tty_write, |
1279 | .poll = tty_poll, | 1278 | .poll = tty_poll, |
1280 | .ioctl = tty_ioctl, | 1279 | .unlocked_ioctl = tty_ioctl, |
1281 | .compat_ioctl = tty_compat_ioctl, | 1280 | .compat_ioctl = tty_compat_ioctl, |
1282 | .open = ptmx_open, | 1281 | .open = ptmx_open, |
1283 | .release = tty_release, | 1282 | .release = tty_release, |
@@ -1290,7 +1289,7 @@ static const struct file_operations console_fops = { | |||
1290 | .read = tty_read, | 1289 | .read = tty_read, |
1291 | .write = redirected_tty_write, | 1290 | .write = redirected_tty_write, |
1292 | .poll = tty_poll, | 1291 | .poll = tty_poll, |
1293 | .ioctl = tty_ioctl, | 1292 | .unlocked_ioctl = tty_ioctl, |
1294 | .compat_ioctl = tty_compat_ioctl, | 1293 | .compat_ioctl = tty_compat_ioctl, |
1295 | .open = tty_open, | 1294 | .open = tty_open, |
1296 | .release = tty_release, | 1295 | .release = tty_release, |
@@ -1302,7 +1301,7 @@ static const struct file_operations hung_up_tty_fops = { | |||
1302 | .read = hung_up_tty_read, | 1301 | .read = hung_up_tty_read, |
1303 | .write = hung_up_tty_write, | 1302 | .write = hung_up_tty_write, |
1304 | .poll = hung_up_tty_poll, | 1303 | .poll = hung_up_tty_poll, |
1305 | .ioctl = hung_up_tty_ioctl, | 1304 | .unlocked_ioctl = hung_up_tty_ioctl, |
1306 | .compat_ioctl = hung_up_tty_compat_ioctl, | 1305 | .compat_ioctl = hung_up_tty_compat_ioctl, |
1307 | .release = tty_release, | 1306 | .release = tty_release, |
1308 | }; | 1307 | }; |
@@ -1626,16 +1625,17 @@ void disassociate_ctty(int on_exit) | |||
1626 | struct tty_struct *tty; | 1625 | struct tty_struct *tty; |
1627 | struct pid *tty_pgrp = NULL; | 1626 | struct pid *tty_pgrp = NULL; |
1628 | 1627 | ||
1629 | lock_kernel(); | ||
1630 | 1628 | ||
1631 | mutex_lock(&tty_mutex); | 1629 | mutex_lock(&tty_mutex); |
1632 | tty = get_current_tty(); | 1630 | tty = get_current_tty(); |
1633 | if (tty) { | 1631 | if (tty) { |
1634 | tty_pgrp = get_pid(tty->pgrp); | 1632 | tty_pgrp = get_pid(tty->pgrp); |
1635 | mutex_unlock(&tty_mutex); | 1633 | mutex_unlock(&tty_mutex); |
1634 | lock_kernel(); | ||
1636 | /* XXX: here we race, there is nothing protecting tty */ | 1635 | /* XXX: here we race, there is nothing protecting tty */ |
1637 | if (on_exit && tty->driver->type != TTY_DRIVER_TYPE_PTY) | 1636 | if (on_exit && tty->driver->type != TTY_DRIVER_TYPE_PTY) |
1638 | tty_vhangup(tty); | 1637 | tty_vhangup(tty); |
1638 | unlock_kernel(); | ||
1639 | } else if (on_exit) { | 1639 | } else if (on_exit) { |
1640 | struct pid *old_pgrp; | 1640 | struct pid *old_pgrp; |
1641 | spin_lock_irq(¤t->sighand->siglock); | 1641 | spin_lock_irq(¤t->sighand->siglock); |
@@ -1648,7 +1648,6 @@ void disassociate_ctty(int on_exit) | |||
1648 | put_pid(old_pgrp); | 1648 | put_pid(old_pgrp); |
1649 | } | 1649 | } |
1650 | mutex_unlock(&tty_mutex); | 1650 | mutex_unlock(&tty_mutex); |
1651 | unlock_kernel(); | ||
1652 | return; | 1651 | return; |
1653 | } | 1652 | } |
1654 | if (tty_pgrp) { | 1653 | if (tty_pgrp) { |
@@ -1683,7 +1682,6 @@ void disassociate_ctty(int on_exit) | |||
1683 | read_lock(&tasklist_lock); | 1682 | read_lock(&tasklist_lock); |
1684 | session_clear_tty(task_session(current)); | 1683 | session_clear_tty(task_session(current)); |
1685 | read_unlock(&tasklist_lock); | 1684 | read_unlock(&tasklist_lock); |
1686 | unlock_kernel(); | ||
1687 | } | 1685 | } |
1688 | 1686 | ||
1689 | /** | 1687 | /** |
@@ -1693,8 +1691,10 @@ void disassociate_ctty(int on_exit) | |||
1693 | void no_tty(void) | 1691 | void no_tty(void) |
1694 | { | 1692 | { |
1695 | struct task_struct *tsk = current; | 1693 | struct task_struct *tsk = current; |
1694 | lock_kernel(); | ||
1696 | if (tsk->signal->leader) | 1695 | if (tsk->signal->leader) |
1697 | disassociate_ctty(0); | 1696 | disassociate_ctty(0); |
1697 | unlock_kernel(); | ||
1698 | proc_clear_tty(tsk); | 1698 | proc_clear_tty(tsk); |
1699 | } | 1699 | } |
1700 | 1700 | ||
@@ -1714,19 +1714,24 @@ void no_tty(void) | |||
1714 | * but not always. | 1714 | * but not always. |
1715 | * | 1715 | * |
1716 | * Locking: | 1716 | * Locking: |
1717 | * Broken. Relies on BKL which is unsafe here. | 1717 | * Uses the tty control lock internally |
1718 | */ | 1718 | */ |
1719 | 1719 | ||
1720 | void stop_tty(struct tty_struct *tty) | 1720 | void stop_tty(struct tty_struct *tty) |
1721 | { | 1721 | { |
1722 | if (tty->stopped) | 1722 | unsigned long flags; |
1723 | spin_lock_irqsave(&tty->ctrl_lock, flags); | ||
1724 | if (tty->stopped) { | ||
1725 | spin_unlock_irqrestore(&tty->ctrl_lock, flags); | ||
1723 | return; | 1726 | return; |
1727 | } | ||
1724 | tty->stopped = 1; | 1728 | tty->stopped = 1; |
1725 | if (tty->link && tty->link->packet) { | 1729 | if (tty->link && tty->link->packet) { |
1726 | tty->ctrl_status &= ~TIOCPKT_START; | 1730 | tty->ctrl_status &= ~TIOCPKT_START; |
1727 | tty->ctrl_status |= TIOCPKT_STOP; | 1731 | tty->ctrl_status |= TIOCPKT_STOP; |
1728 | wake_up_interruptible(&tty->link->read_wait); | 1732 | wake_up_interruptible(&tty->link->read_wait); |
1729 | } | 1733 | } |
1734 | spin_unlock_irqrestore(&tty->ctrl_lock, flags); | ||
1730 | if (tty->driver->stop) | 1735 | if (tty->driver->stop) |
1731 | (tty->driver->stop)(tty); | 1736 | (tty->driver->stop)(tty); |
1732 | } | 1737 | } |
@@ -1743,19 +1748,24 @@ EXPORT_SYMBOL(stop_tty); | |||
1743 | * driver start method is invoked and the line discipline woken. | 1748 | * driver start method is invoked and the line discipline woken. |
1744 | * | 1749 | * |
1745 | * Locking: | 1750 | * Locking: |
1746 | * Broken. Relies on BKL which is unsafe here. | 1751 | * ctrl_lock |
1747 | */ | 1752 | */ |
1748 | 1753 | ||
1749 | void start_tty(struct tty_struct *tty) | 1754 | void start_tty(struct tty_struct *tty) |
1750 | { | 1755 | { |
1751 | if (!tty->stopped || tty->flow_stopped) | 1756 | unsigned long flags; |
1757 | spin_lock_irqsave(&tty->ctrl_lock, flags); | ||
1758 | if (!tty->stopped || tty->flow_stopped) { | ||
1759 | spin_unlock_irqrestore(&tty->ctrl_lock, flags); | ||
1752 | return; | 1760 | return; |
1761 | } | ||
1753 | tty->stopped = 0; | 1762 | tty->stopped = 0; |
1754 | if (tty->link && tty->link->packet) { | 1763 | if (tty->link && tty->link->packet) { |
1755 | tty->ctrl_status &= ~TIOCPKT_STOP; | 1764 | tty->ctrl_status &= ~TIOCPKT_STOP; |
1756 | tty->ctrl_status |= TIOCPKT_START; | 1765 | tty->ctrl_status |= TIOCPKT_START; |
1757 | wake_up_interruptible(&tty->link->read_wait); | 1766 | wake_up_interruptible(&tty->link->read_wait); |
1758 | } | 1767 | } |
1768 | spin_unlock_irqrestore(&tty->ctrl_lock, flags); | ||
1759 | if (tty->driver->start) | 1769 | if (tty->driver->start) |
1760 | (tty->driver->start)(tty); | 1770 | (tty->driver->start)(tty); |
1761 | /* If we have a running line discipline it may need kicking */ | 1771 | /* If we have a running line discipline it may need kicking */ |
@@ -1799,13 +1809,11 @@ static ssize_t tty_read(struct file *file, char __user *buf, size_t count, | |||
1799 | /* We want to wait for the line discipline to sort out in this | 1809 | /* We want to wait for the line discipline to sort out in this |
1800 | situation */ | 1810 | situation */ |
1801 | ld = tty_ldisc_ref_wait(tty); | 1811 | ld = tty_ldisc_ref_wait(tty); |
1802 | lock_kernel(); | ||
1803 | if (ld->read) | 1812 | if (ld->read) |
1804 | i = (ld->read)(tty, file, buf, count); | 1813 | i = (ld->read)(tty, file, buf, count); |
1805 | else | 1814 | else |
1806 | i = -EIO; | 1815 | i = -EIO; |
1807 | tty_ldisc_deref(ld); | 1816 | tty_ldisc_deref(ld); |
1808 | unlock_kernel(); | ||
1809 | if (i > 0) | 1817 | if (i > 0) |
1810 | inode->i_atime = current_fs_time(inode->i_sb); | 1818 | inode->i_atime = current_fs_time(inode->i_sb); |
1811 | return i; | 1819 | return i; |
@@ -1893,9 +1901,7 @@ static inline ssize_t do_tty_write( | |||
1893 | ret = -EFAULT; | 1901 | ret = -EFAULT; |
1894 | if (copy_from_user(tty->write_buf, buf, size)) | 1902 | if (copy_from_user(tty->write_buf, buf, size)) |
1895 | break; | 1903 | break; |
1896 | lock_kernel(); | ||
1897 | ret = write(tty, file, tty->write_buf, size); | 1904 | ret = write(tty, file, tty->write_buf, size); |
1898 | unlock_kernel(); | ||
1899 | if (ret <= 0) | 1905 | if (ret <= 0) |
1900 | break; | 1906 | break; |
1901 | written += ret; | 1907 | written += ret; |
@@ -3070,10 +3076,13 @@ static int fionbio(struct file *file, int __user *p) | |||
3070 | if (get_user(nonblock, p)) | 3076 | if (get_user(nonblock, p)) |
3071 | return -EFAULT; | 3077 | return -EFAULT; |
3072 | 3078 | ||
3079 | /* file->f_flags is still BKL protected in the fs layer - vomit */ | ||
3080 | lock_kernel(); | ||
3073 | if (nonblock) | 3081 | if (nonblock) |
3074 | file->f_flags |= O_NONBLOCK; | 3082 | file->f_flags |= O_NONBLOCK; |
3075 | else | 3083 | else |
3076 | file->f_flags &= ~O_NONBLOCK; | 3084 | file->f_flags &= ~O_NONBLOCK; |
3085 | unlock_kernel(); | ||
3077 | return 0; | 3086 | return 0; |
3078 | } | 3087 | } |
3079 | 3088 | ||
@@ -3162,7 +3171,7 @@ static int tiocgpgrp(struct tty_struct *tty, struct tty_struct *real_tty, pid_t | |||
3162 | * Set the process group of the tty to the session passed. Only | 3171 | * Set the process group of the tty to the session passed. Only |
3163 | * permitted where the tty session is our session. | 3172 | * permitted where the tty session is our session. |
3164 | * | 3173 | * |
3165 | * Locking: None | 3174 | * Locking: RCU |
3166 | */ | 3175 | */ |
3167 | 3176 | ||
3168 | static int tiocspgrp(struct tty_struct *tty, struct tty_struct *real_tty, pid_t __user *p) | 3177 | static int tiocspgrp(struct tty_struct *tty, struct tty_struct *real_tty, pid_t __user *p) |
@@ -3237,10 +3246,16 @@ static int tiocgsid(struct tty_struct *tty, struct tty_struct *real_tty, pid_t _ | |||
3237 | static int tiocsetd(struct tty_struct *tty, int __user *p) | 3246 | static int tiocsetd(struct tty_struct *tty, int __user *p) |
3238 | { | 3247 | { |
3239 | int ldisc; | 3248 | int ldisc; |
3249 | int ret; | ||
3240 | 3250 | ||
3241 | if (get_user(ldisc, p)) | 3251 | if (get_user(ldisc, p)) |
3242 | return -EFAULT; | 3252 | return -EFAULT; |
3243 | return tty_set_ldisc(tty, ldisc); | 3253 | |
3254 | lock_kernel(); | ||
3255 | ret = tty_set_ldisc(tty, ldisc); | ||
3256 | unlock_kernel(); | ||
3257 | |||
3258 | return ret; | ||
3244 | } | 3259 | } |
3245 | 3260 | ||
3246 | /** | 3261 | /** |
@@ -3258,16 +3273,21 @@ static int tiocsetd(struct tty_struct *tty, int __user *p) | |||
3258 | 3273 | ||
3259 | static int send_break(struct tty_struct *tty, unsigned int duration) | 3274 | static int send_break(struct tty_struct *tty, unsigned int duration) |
3260 | { | 3275 | { |
3276 | int retval = -EINTR; | ||
3277 | |||
3278 | lock_kernel(); | ||
3261 | if (tty_write_lock(tty, 0) < 0) | 3279 | if (tty_write_lock(tty, 0) < 0) |
3262 | return -EINTR; | 3280 | goto out; |
3263 | tty->driver->break_ctl(tty, -1); | 3281 | tty->driver->break_ctl(tty, -1); |
3264 | if (!signal_pending(current)) | 3282 | if (!signal_pending(current)) |
3265 | msleep_interruptible(duration); | 3283 | msleep_interruptible(duration); |
3266 | tty->driver->break_ctl(tty, 0); | 3284 | tty->driver->break_ctl(tty, 0); |
3267 | tty_write_unlock(tty); | 3285 | tty_write_unlock(tty); |
3268 | if (signal_pending(current)) | 3286 | if (!signal_pending(current)) |
3269 | return -EINTR; | 3287 | retval = 0; |
3270 | return 0; | 3288 | out: |
3289 | unlock_kernel(); | ||
3290 | return retval; | ||
3271 | } | 3291 | } |
3272 | 3292 | ||
3273 | /** | 3293 | /** |
@@ -3287,7 +3307,9 @@ static int tty_tiocmget(struct tty_struct *tty, struct file *file, int __user *p | |||
3287 | int retval = -EINVAL; | 3307 | int retval = -EINVAL; |
3288 | 3308 | ||
3289 | if (tty->driver->tiocmget) { | 3309 | if (tty->driver->tiocmget) { |
3310 | lock_kernel(); | ||
3290 | retval = tty->driver->tiocmget(tty, file); | 3311 | retval = tty->driver->tiocmget(tty, file); |
3312 | unlock_kernel(); | ||
3291 | 3313 | ||
3292 | if (retval >= 0) | 3314 | if (retval >= 0) |
3293 | retval = put_user(retval, p); | 3315 | retval = put_user(retval, p); |
@@ -3337,7 +3359,9 @@ static int tty_tiocmset(struct tty_struct *tty, struct file *file, unsigned int | |||
3337 | set &= TIOCM_DTR|TIOCM_RTS|TIOCM_OUT1|TIOCM_OUT2|TIOCM_LOOP; | 3359 | set &= TIOCM_DTR|TIOCM_RTS|TIOCM_OUT1|TIOCM_OUT2|TIOCM_LOOP; |
3338 | clear &= TIOCM_DTR|TIOCM_RTS|TIOCM_OUT1|TIOCM_OUT2|TIOCM_LOOP; | 3360 | clear &= TIOCM_DTR|TIOCM_RTS|TIOCM_OUT1|TIOCM_OUT2|TIOCM_LOOP; |
3339 | 3361 | ||
3362 | lock_kernel(); | ||
3340 | retval = tty->driver->tiocmset(tty, file, set, clear); | 3363 | retval = tty->driver->tiocmset(tty, file, set, clear); |
3364 | unlock_kernel(); | ||
3341 | } | 3365 | } |
3342 | return retval; | 3366 | return retval; |
3343 | } | 3367 | } |
@@ -3345,20 +3369,18 @@ static int tty_tiocmset(struct tty_struct *tty, struct file *file, unsigned int | |||
3345 | /* | 3369 | /* |
3346 | * Split this up, as gcc can choke on it otherwise.. | 3370 | * Split this up, as gcc can choke on it otherwise.. |
3347 | */ | 3371 | */ |
3348 | int tty_ioctl(struct inode *inode, struct file *file, | 3372 | long tty_ioctl(struct file *file, unsigned int cmd, unsigned long arg) |
3349 | unsigned int cmd, unsigned long arg) | ||
3350 | { | 3373 | { |
3351 | struct tty_struct *tty, *real_tty; | 3374 | struct tty_struct *tty, *real_tty; |
3352 | void __user *p = (void __user *)arg; | 3375 | void __user *p = (void __user *)arg; |
3353 | int retval; | 3376 | int retval; |
3354 | struct tty_ldisc *ld; | 3377 | struct tty_ldisc *ld; |
3378 | struct inode *inode = file->f_dentry->d_inode; | ||
3355 | 3379 | ||
3356 | tty = (struct tty_struct *)file->private_data; | 3380 | tty = (struct tty_struct *)file->private_data; |
3357 | if (tty_paranoia_check(tty, inode, "tty_ioctl")) | 3381 | if (tty_paranoia_check(tty, inode, "tty_ioctl")) |
3358 | return -EINVAL; | 3382 | return -EINVAL; |
3359 | 3383 | ||
3360 | /* CHECKME: is this safe as one end closes ? */ | ||
3361 | |||
3362 | real_tty = tty; | 3384 | real_tty = tty; |
3363 | if (tty->driver->type == TTY_DRIVER_TYPE_PTY && | 3385 | if (tty->driver->type == TTY_DRIVER_TYPE_PTY && |
3364 | tty->driver->subtype == PTY_TYPE_MASTER) | 3386 | tty->driver->subtype == PTY_TYPE_MASTER) |
@@ -3367,13 +3389,19 @@ int tty_ioctl(struct inode *inode, struct file *file, | |||
3367 | /* | 3389 | /* |
3368 | * Break handling by driver | 3390 | * Break handling by driver |
3369 | */ | 3391 | */ |
3392 | |||
3393 | retval = -EINVAL; | ||
3394 | |||
3370 | if (!tty->driver->break_ctl) { | 3395 | if (!tty->driver->break_ctl) { |
3371 | switch (cmd) { | 3396 | switch (cmd) { |
3372 | case TIOCSBRK: | 3397 | case TIOCSBRK: |
3373 | case TIOCCBRK: | 3398 | case TIOCCBRK: |
3374 | if (tty->driver->ioctl) | 3399 | if (tty->driver->ioctl) { |
3375 | return tty->driver->ioctl(tty, file, cmd, arg); | 3400 | lock_kernel(); |
3376 | return -EINVAL; | 3401 | retval = tty->driver->ioctl(tty, file, cmd, arg); |
3402 | unlock_kernel(); | ||
3403 | } | ||
3404 | return retval; | ||
3377 | 3405 | ||
3378 | /* These two ioctl's always return success; even if */ | 3406 | /* These two ioctl's always return success; even if */ |
3379 | /* the driver doesn't support them. */ | 3407 | /* the driver doesn't support them. */ |
@@ -3381,7 +3409,9 @@ int tty_ioctl(struct inode *inode, struct file *file, | |||
3381 | case TCSBRKP: | 3409 | case TCSBRKP: |
3382 | if (!tty->driver->ioctl) | 3410 | if (!tty->driver->ioctl) |
3383 | return 0; | 3411 | return 0; |
3412 | lock_kernel(); | ||
3384 | retval = tty->driver->ioctl(tty, file, cmd, arg); | 3413 | retval = tty->driver->ioctl(tty, file, cmd, arg); |
3414 | unlock_kernel(); | ||
3385 | if (retval == -ENOIOCTLCMD) | 3415 | if (retval == -ENOIOCTLCMD) |
3386 | retval = 0; | 3416 | retval = 0; |
3387 | return retval; | 3417 | return retval; |
@@ -3401,7 +3431,9 @@ int tty_ioctl(struct inode *inode, struct file *file, | |||
3401 | if (retval) | 3431 | if (retval) |
3402 | return retval; | 3432 | return retval; |
3403 | if (cmd != TIOCCBRK) { | 3433 | if (cmd != TIOCCBRK) { |
3434 | lock_kernel(); | ||
3404 | tty_wait_until_sent(tty, 0); | 3435 | tty_wait_until_sent(tty, 0); |
3436 | unlock_kernel(); | ||
3405 | if (signal_pending(current)) | 3437 | if (signal_pending(current)) |
3406 | return -EINTR; | 3438 | return -EINTR; |
3407 | } | 3439 | } |
@@ -3451,11 +3483,15 @@ int tty_ioctl(struct inode *inode, struct file *file, | |||
3451 | * Break handling | 3483 | * Break handling |
3452 | */ | 3484 | */ |
3453 | case TIOCSBRK: /* Turn break on, unconditionally */ | 3485 | case TIOCSBRK: /* Turn break on, unconditionally */ |
3486 | lock_kernel(); | ||
3454 | tty->driver->break_ctl(tty, -1); | 3487 | tty->driver->break_ctl(tty, -1); |
3488 | unlock_kernel(); | ||
3455 | return 0; | 3489 | return 0; |
3456 | 3490 | ||
3457 | case TIOCCBRK: /* Turn break off, unconditionally */ | 3491 | case TIOCCBRK: /* Turn break off, unconditionally */ |
3492 | lock_kernel(); | ||
3458 | tty->driver->break_ctl(tty, 0); | 3493 | tty->driver->break_ctl(tty, 0); |
3494 | unlock_kernel(); | ||
3459 | return 0; | 3495 | return 0; |
3460 | case TCSBRK: /* SVID version: non-zero arg --> no break */ | 3496 | case TCSBRK: /* SVID version: non-zero arg --> no break */ |
3461 | /* non-zero arg means wait for all output data | 3497 | /* non-zero arg means wait for all output data |
@@ -3485,14 +3521,18 @@ int tty_ioctl(struct inode *inode, struct file *file, | |||
3485 | break; | 3521 | break; |
3486 | } | 3522 | } |
3487 | if (tty->driver->ioctl) { | 3523 | if (tty->driver->ioctl) { |
3524 | lock_kernel(); | ||
3488 | retval = (tty->driver->ioctl)(tty, file, cmd, arg); | 3525 | retval = (tty->driver->ioctl)(tty, file, cmd, arg); |
3526 | unlock_kernel(); | ||
3489 | if (retval != -ENOIOCTLCMD) | 3527 | if (retval != -ENOIOCTLCMD) |
3490 | return retval; | 3528 | return retval; |
3491 | } | 3529 | } |
3492 | ld = tty_ldisc_ref_wait(tty); | 3530 | ld = tty_ldisc_ref_wait(tty); |
3493 | retval = -EINVAL; | 3531 | retval = -EINVAL; |
3494 | if (ld->ioctl) { | 3532 | if (ld->ioctl) { |
3533 | lock_kernel(); | ||
3495 | retval = ld->ioctl(tty, file, cmd, arg); | 3534 | retval = ld->ioctl(tty, file, cmd, arg); |
3535 | unlock_kernel(); | ||
3496 | if (retval == -ENOIOCTLCMD) | 3536 | if (retval == -ENOIOCTLCMD) |
3497 | retval = -EINVAL; | 3537 | retval = -EINVAL; |
3498 | } | 3538 | } |
@@ -3770,6 +3810,7 @@ static void initialize_tty_struct(struct tty_struct *tty) | |||
3770 | mutex_init(&tty->atomic_read_lock); | 3810 | mutex_init(&tty->atomic_read_lock); |
3771 | mutex_init(&tty->atomic_write_lock); | 3811 | mutex_init(&tty->atomic_write_lock); |
3772 | spin_lock_init(&tty->read_lock); | 3812 | spin_lock_init(&tty->read_lock); |
3813 | spin_lock_init(&tty->ctrl_lock); | ||
3773 | INIT_LIST_HEAD(&tty->tty_files); | 3814 | INIT_LIST_HEAD(&tty->tty_files); |
3774 | INIT_WORK(&tty->SAK_work, do_SAK_work); | 3815 | INIT_WORK(&tty->SAK_work, do_SAK_work); |
3775 | } | 3816 | } |