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 | |
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')
-rw-r--r-- | drivers/char/n_hdlc.c | 24 | ||||
-rw-r--r-- | drivers/char/n_r3964.c | 16 | ||||
-rw-r--r-- | drivers/char/n_tty.c | 32 | ||||
-rw-r--r-- | drivers/char/pty.c | 3 | ||||
-rw-r--r-- | drivers/char/tty_io.c | 107 | ||||
-rw-r--r-- | drivers/char/tty_ioctl.c | 6 | ||||
-rw-r--r-- | drivers/char/vt.c | 8 |
7 files changed, 146 insertions, 50 deletions
diff --git a/drivers/char/n_hdlc.c b/drivers/char/n_hdlc.c index 06803ed5568c..a07c0af4819e 100644 --- a/drivers/char/n_hdlc.c +++ b/drivers/char/n_hdlc.c | |||
@@ -578,26 +578,36 @@ static ssize_t n_hdlc_tty_read(struct tty_struct *tty, struct file *file, | |||
578 | return -EFAULT; | 578 | return -EFAULT; |
579 | } | 579 | } |
580 | 580 | ||
581 | lock_kernel(); | ||
582 | |||
581 | for (;;) { | 583 | for (;;) { |
582 | if (test_bit(TTY_OTHER_CLOSED, &tty->flags)) | 584 | if (test_bit(TTY_OTHER_CLOSED, &tty->flags)) { |
585 | unlock_kernel(); | ||
583 | return -EIO; | 586 | return -EIO; |
587 | } | ||
584 | 588 | ||
585 | n_hdlc = tty2n_hdlc (tty); | 589 | n_hdlc = tty2n_hdlc (tty); |
586 | if (!n_hdlc || n_hdlc->magic != HDLC_MAGIC || | 590 | if (!n_hdlc || n_hdlc->magic != HDLC_MAGIC || |
587 | tty != n_hdlc->tty) | 591 | tty != n_hdlc->tty) { |
592 | unlock_kernel(); | ||
588 | return 0; | 593 | return 0; |
594 | } | ||
589 | 595 | ||
590 | rbuf = n_hdlc_buf_get(&n_hdlc->rx_buf_list); | 596 | rbuf = n_hdlc_buf_get(&n_hdlc->rx_buf_list); |
591 | if (rbuf) | 597 | if (rbuf) |
592 | break; | 598 | break; |
593 | 599 | ||
594 | /* no data */ | 600 | /* no data */ |
595 | if (file->f_flags & O_NONBLOCK) | 601 | if (file->f_flags & O_NONBLOCK) { |
602 | unlock_kernel(); | ||
596 | return -EAGAIN; | 603 | return -EAGAIN; |
604 | } | ||
597 | 605 | ||
598 | interruptible_sleep_on (&tty->read_wait); | 606 | interruptible_sleep_on (&tty->read_wait); |
599 | if (signal_pending(current)) | 607 | if (signal_pending(current)) { |
608 | unlock_kernel(); | ||
600 | return -EINTR; | 609 | return -EINTR; |
610 | } | ||
601 | } | 611 | } |
602 | 612 | ||
603 | if (rbuf->count > nr) | 613 | if (rbuf->count > nr) |
@@ -618,7 +628,7 @@ static ssize_t n_hdlc_tty_read(struct tty_struct *tty, struct file *file, | |||
618 | kfree(rbuf); | 628 | kfree(rbuf); |
619 | else | 629 | else |
620 | n_hdlc_buf_put(&n_hdlc->rx_free_buf_list,rbuf); | 630 | n_hdlc_buf_put(&n_hdlc->rx_free_buf_list,rbuf); |
621 | 631 | unlock_kernel(); | |
622 | return ret; | 632 | return ret; |
623 | 633 | ||
624 | } /* end of n_hdlc_tty_read() */ | 634 | } /* end of n_hdlc_tty_read() */ |
@@ -661,6 +671,8 @@ static ssize_t n_hdlc_tty_write(struct tty_struct *tty, struct file *file, | |||
661 | count = maxframe; | 671 | count = maxframe; |
662 | } | 672 | } |
663 | 673 | ||
674 | lock_kernel(); | ||
675 | |||
664 | add_wait_queue(&tty->write_wait, &wait); | 676 | add_wait_queue(&tty->write_wait, &wait); |
665 | set_current_state(TASK_INTERRUPTIBLE); | 677 | set_current_state(TASK_INTERRUPTIBLE); |
666 | 678 | ||
@@ -695,7 +707,7 @@ static ssize_t n_hdlc_tty_write(struct tty_struct *tty, struct file *file, | |||
695 | n_hdlc_buf_put(&n_hdlc->tx_buf_list,tbuf); | 707 | n_hdlc_buf_put(&n_hdlc->tx_buf_list,tbuf); |
696 | n_hdlc_send_frames(n_hdlc,tty); | 708 | n_hdlc_send_frames(n_hdlc,tty); |
697 | } | 709 | } |
698 | 710 | unlock_kernel(); | |
699 | return error; | 711 | return error; |
700 | 712 | ||
701 | } /* end of n_hdlc_tty_write() */ | 713 | } /* end of n_hdlc_tty_write() */ |
diff --git a/drivers/char/n_r3964.c b/drivers/char/n_r3964.c index 6b918b80f73e..3f6486e9f1ec 100644 --- a/drivers/char/n_r3964.c +++ b/drivers/char/n_r3964.c | |||
@@ -1075,12 +1075,15 @@ static ssize_t r3964_read(struct tty_struct *tty, struct file *file, | |||
1075 | 1075 | ||
1076 | TRACE_L("read()"); | 1076 | TRACE_L("read()"); |
1077 | 1077 | ||
1078 | lock_kernel(); | ||
1079 | |||
1078 | pClient = findClient(pInfo, task_pid(current)); | 1080 | pClient = findClient(pInfo, task_pid(current)); |
1079 | if (pClient) { | 1081 | if (pClient) { |
1080 | pMsg = remove_msg(pInfo, pClient); | 1082 | pMsg = remove_msg(pInfo, pClient); |
1081 | if (pMsg == NULL) { | 1083 | if (pMsg == NULL) { |
1082 | /* no messages available. */ | 1084 | /* no messages available. */ |
1083 | if (file->f_flags & O_NONBLOCK) { | 1085 | if (file->f_flags & O_NONBLOCK) { |
1086 | unlock_kernel(); | ||
1084 | return -EAGAIN; | 1087 | return -EAGAIN; |
1085 | } | 1088 | } |
1086 | /* block until there is a message: */ | 1089 | /* block until there is a message: */ |
@@ -1090,8 +1093,10 @@ static ssize_t r3964_read(struct tty_struct *tty, struct file *file, | |||
1090 | 1093 | ||
1091 | /* If we still haven't got a message, we must have been signalled */ | 1094 | /* If we still haven't got a message, we must have been signalled */ |
1092 | 1095 | ||
1093 | if (!pMsg) | 1096 | if (!pMsg) { |
1097 | unlock_kernel(); | ||
1094 | return -EINTR; | 1098 | return -EINTR; |
1099 | } | ||
1095 | 1100 | ||
1096 | /* deliver msg to client process: */ | 1101 | /* deliver msg to client process: */ |
1097 | theMsg.msg_id = pMsg->msg_id; | 1102 | theMsg.msg_id = pMsg->msg_id; |
@@ -1102,12 +1107,15 @@ static ssize_t r3964_read(struct tty_struct *tty, struct file *file, | |||
1102 | kfree(pMsg); | 1107 | kfree(pMsg); |
1103 | TRACE_M("r3964_read - msg kfree %p", pMsg); | 1108 | TRACE_M("r3964_read - msg kfree %p", pMsg); |
1104 | 1109 | ||
1105 | if (copy_to_user(buf, &theMsg, count)) | 1110 | if (copy_to_user(buf, &theMsg, count)) { |
1111 | unlock_kernel(); | ||
1106 | return -EFAULT; | 1112 | return -EFAULT; |
1113 | } | ||
1107 | 1114 | ||
1108 | TRACE_PS("read - return %d", count); | 1115 | TRACE_PS("read - return %d", count); |
1109 | return count; | 1116 | return count; |
1110 | } | 1117 | } |
1118 | unlock_kernel(); | ||
1111 | return -EPERM; | 1119 | return -EPERM; |
1112 | } | 1120 | } |
1113 | 1121 | ||
@@ -1156,6 +1164,8 @@ static ssize_t r3964_write(struct tty_struct *tty, struct file *file, | |||
1156 | pHeader->locks = 0; | 1164 | pHeader->locks = 0; |
1157 | pHeader->owner = NULL; | 1165 | pHeader->owner = NULL; |
1158 | 1166 | ||
1167 | lock_kernel(); | ||
1168 | |||
1159 | pClient = findClient(pInfo, task_pid(current)); | 1169 | pClient = findClient(pInfo, task_pid(current)); |
1160 | if (pClient) { | 1170 | if (pClient) { |
1161 | pHeader->owner = pClient; | 1171 | pHeader->owner = pClient; |
@@ -1173,6 +1183,8 @@ static ssize_t r3964_write(struct tty_struct *tty, struct file *file, | |||
1173 | add_tx_queue(pInfo, pHeader); | 1183 | add_tx_queue(pInfo, pHeader); |
1174 | trigger_transmit(pInfo); | 1184 | trigger_transmit(pInfo); |
1175 | 1185 | ||
1186 | unlock_kernel(); | ||
1187 | |||
1176 | return 0; | 1188 | return 0; |
1177 | } | 1189 | } |
1178 | 1190 | ||
diff --git a/drivers/char/n_tty.c b/drivers/char/n_tty.c index 0c09409fa45d..001d9d875387 100644 --- a/drivers/char/n_tty.c +++ b/drivers/char/n_tty.c | |||
@@ -183,22 +183,24 @@ static void reset_buffer_flags(struct tty_struct *tty) | |||
183 | * at hangup) or when the N_TTY line discipline internally has to | 183 | * at hangup) or when the N_TTY line discipline internally has to |
184 | * clean the pending queue (for example some signals). | 184 | * clean the pending queue (for example some signals). |
185 | * | 185 | * |
186 | * FIXME: tty->ctrl_status is not spinlocked and relies on | 186 | * Locking: ctrl_lock |
187 | * lock_kernel() still. | ||
188 | */ | 187 | */ |
189 | 188 | ||
190 | static void n_tty_flush_buffer(struct tty_struct *tty) | 189 | static void n_tty_flush_buffer(struct tty_struct *tty) |
191 | { | 190 | { |
191 | unsigned long flags; | ||
192 | /* clear everything and unthrottle the driver */ | 192 | /* clear everything and unthrottle the driver */ |
193 | reset_buffer_flags(tty); | 193 | reset_buffer_flags(tty); |
194 | 194 | ||
195 | if (!tty->link) | 195 | if (!tty->link) |
196 | return; | 196 | return; |
197 | 197 | ||
198 | spin_lock_irqsave(&tty->ctrl_lock, flags); | ||
198 | if (tty->link->packet) { | 199 | if (tty->link->packet) { |
199 | tty->ctrl_status |= TIOCPKT_FLUSHREAD; | 200 | tty->ctrl_status |= TIOCPKT_FLUSHREAD; |
200 | wake_up_interruptible(&tty->link->read_wait); | 201 | wake_up_interruptible(&tty->link->read_wait); |
201 | } | 202 | } |
203 | spin_unlock_irqrestore(&tty->ctrl_lock, flags); | ||
202 | } | 204 | } |
203 | 205 | ||
204 | /** | 206 | /** |
@@ -264,7 +266,7 @@ static inline int is_continuation(unsigned char c, struct tty_struct *tty) | |||
264 | * relevant in the world today. If you ever need them, add them here. | 266 | * relevant in the world today. If you ever need them, add them here. |
265 | * | 267 | * |
266 | * Called from both the receive and transmit sides and can be called | 268 | * Called from both the receive and transmit sides and can be called |
267 | * re-entrantly. Relies on lock_kernel() still. | 269 | * re-entrantly. Relies on lock_kernel() for tty->column state. |
268 | */ | 270 | */ |
269 | 271 | ||
270 | static int opost(unsigned char c, struct tty_struct *tty) | 272 | static int opost(unsigned char c, struct tty_struct *tty) |
@@ -275,6 +277,7 @@ static int opost(unsigned char c, struct tty_struct *tty) | |||
275 | if (!space) | 277 | if (!space) |
276 | return -1; | 278 | return -1; |
277 | 279 | ||
280 | lock_kernel(); | ||
278 | if (O_OPOST(tty)) { | 281 | if (O_OPOST(tty)) { |
279 | switch (c) { | 282 | switch (c) { |
280 | case '\n': | 283 | case '\n': |
@@ -323,6 +326,7 @@ static int opost(unsigned char c, struct tty_struct *tty) | |||
323 | } | 326 | } |
324 | } | 327 | } |
325 | tty->driver->put_char(tty, c); | 328 | tty->driver->put_char(tty, c); |
329 | unlock_kernel(); | ||
326 | return 0; | 330 | return 0; |
327 | } | 331 | } |
328 | 332 | ||
@@ -337,7 +341,8 @@ static int opost(unsigned char c, struct tty_struct *tty) | |||
337 | * the simple cases normally found and helps to generate blocks of | 341 | * the simple cases normally found and helps to generate blocks of |
338 | * symbols for the console driver and thus improve performance. | 342 | * symbols for the console driver and thus improve performance. |
339 | * | 343 | * |
340 | * Called from write_chan under the tty layer write lock. | 344 | * Called from write_chan under the tty layer write lock. Relies |
345 | * on lock_kernel for the tty->column state. | ||
341 | */ | 346 | */ |
342 | 347 | ||
343 | static ssize_t opost_block(struct tty_struct *tty, | 348 | static ssize_t opost_block(struct tty_struct *tty, |
@@ -353,6 +358,7 @@ static ssize_t opost_block(struct tty_struct *tty, | |||
353 | if (nr > space) | 358 | if (nr > space) |
354 | nr = space; | 359 | nr = space; |
355 | 360 | ||
361 | lock_kernel(); | ||
356 | for (i = 0, cp = buf; i < nr; i++, cp++) { | 362 | for (i = 0, cp = buf; i < nr; i++, cp++) { |
357 | switch (*cp) { | 363 | switch (*cp) { |
358 | case '\n': | 364 | case '\n': |
@@ -387,6 +393,7 @@ break_out: | |||
387 | if (tty->driver->flush_chars) | 393 | if (tty->driver->flush_chars) |
388 | tty->driver->flush_chars(tty); | 394 | tty->driver->flush_chars(tty); |
389 | i = tty->driver->write(tty, buf, i); | 395 | i = tty->driver->write(tty, buf, i); |
396 | unlock_kernel(); | ||
390 | return i; | 397 | return i; |
391 | } | 398 | } |
392 | 399 | ||
@@ -1194,6 +1201,11 @@ extern ssize_t redirected_tty_write(struct file *, const char __user *, | |||
1194 | * Perform job control management checks on this file/tty descriptor | 1201 | * Perform job control management checks on this file/tty descriptor |
1195 | * and if appropriate send any needed signals and return a negative | 1202 | * and if appropriate send any needed signals and return a negative |
1196 | * error code if action should be taken. | 1203 | * error code if action should be taken. |
1204 | * | ||
1205 | * FIXME: | ||
1206 | * Locking: None - redirected write test is safe, testing | ||
1207 | * current->signal should possibly lock current->sighand | ||
1208 | * pgrp locking ? | ||
1197 | */ | 1209 | */ |
1198 | 1210 | ||
1199 | static int job_control(struct tty_struct *tty, struct file *file) | 1211 | static int job_control(struct tty_struct *tty, struct file *file) |
@@ -1246,6 +1258,7 @@ static ssize_t read_chan(struct tty_struct *tty, struct file *file, | |||
1246 | ssize_t size; | 1258 | ssize_t size; |
1247 | long timeout; | 1259 | long timeout; |
1248 | unsigned long flags; | 1260 | unsigned long flags; |
1261 | int packet; | ||
1249 | 1262 | ||
1250 | do_it_again: | 1263 | do_it_again: |
1251 | 1264 | ||
@@ -1289,16 +1302,19 @@ do_it_again: | |||
1289 | if (mutex_lock_interruptible(&tty->atomic_read_lock)) | 1302 | if (mutex_lock_interruptible(&tty->atomic_read_lock)) |
1290 | return -ERESTARTSYS; | 1303 | return -ERESTARTSYS; |
1291 | } | 1304 | } |
1305 | packet = tty->packet; | ||
1292 | 1306 | ||
1293 | add_wait_queue(&tty->read_wait, &wait); | 1307 | add_wait_queue(&tty->read_wait, &wait); |
1294 | while (nr) { | 1308 | while (nr) { |
1295 | /* First test for status change. */ | 1309 | /* First test for status change. */ |
1296 | if (tty->packet && tty->link->ctrl_status) { | 1310 | if (packet && tty->link->ctrl_status) { |
1297 | unsigned char cs; | 1311 | unsigned char cs; |
1298 | if (b != buf) | 1312 | if (b != buf) |
1299 | break; | 1313 | break; |
1314 | spin_lock_irqsave(&tty->link->ctrl_lock, flags); | ||
1300 | cs = tty->link->ctrl_status; | 1315 | cs = tty->link->ctrl_status; |
1301 | tty->link->ctrl_status = 0; | 1316 | tty->link->ctrl_status = 0; |
1317 | spin_unlock_irqrestore(&tty->link->ctrl_lock, flags); | ||
1302 | if (tty_put_user(tty, cs, b++)) { | 1318 | if (tty_put_user(tty, cs, b++)) { |
1303 | retval = -EFAULT; | 1319 | retval = -EFAULT; |
1304 | b--; | 1320 | b--; |
@@ -1333,6 +1349,7 @@ do_it_again: | |||
1333 | retval = -ERESTARTSYS; | 1349 | retval = -ERESTARTSYS; |
1334 | break; | 1350 | break; |
1335 | } | 1351 | } |
1352 | /* FIXME: does n_tty_set_room need locking ? */ | ||
1336 | n_tty_set_room(tty); | 1353 | n_tty_set_room(tty); |
1337 | timeout = schedule_timeout(timeout); | 1354 | timeout = schedule_timeout(timeout); |
1338 | continue; | 1355 | continue; |
@@ -1340,7 +1357,7 @@ do_it_again: | |||
1340 | __set_current_state(TASK_RUNNING); | 1357 | __set_current_state(TASK_RUNNING); |
1341 | 1358 | ||
1342 | /* Deal with packet mode. */ | 1359 | /* Deal with packet mode. */ |
1343 | if (tty->packet && b == buf) { | 1360 | if (packet && b == buf) { |
1344 | if (tty_put_user(tty, TIOCPKT_DATA, b++)) { | 1361 | if (tty_put_user(tty, TIOCPKT_DATA, b++)) { |
1345 | retval = -EFAULT; | 1362 | retval = -EFAULT; |
1346 | b--; | 1363 | b--; |
@@ -1388,6 +1405,8 @@ do_it_again: | |||
1388 | break; | 1405 | break; |
1389 | } else { | 1406 | } else { |
1390 | int uncopied; | 1407 | int uncopied; |
1408 | /* The copy function takes the read lock and handles | ||
1409 | locking internally for this case */ | ||
1391 | uncopied = copy_from_read_buf(tty, &b, &nr); | 1410 | uncopied = copy_from_read_buf(tty, &b, &nr); |
1392 | uncopied += copy_from_read_buf(tty, &b, &nr); | 1411 | uncopied += copy_from_read_buf(tty, &b, &nr); |
1393 | if (uncopied) { | 1412 | if (uncopied) { |
@@ -1429,7 +1448,6 @@ do_it_again: | |||
1429 | goto do_it_again; | 1448 | goto do_it_again; |
1430 | 1449 | ||
1431 | n_tty_set_room(tty); | 1450 | n_tty_set_room(tty); |
1432 | |||
1433 | return retval; | 1451 | return retval; |
1434 | } | 1452 | } |
1435 | 1453 | ||
diff --git a/drivers/char/pty.c b/drivers/char/pty.c index 706ff34728f1..6288356b769d 100644 --- a/drivers/char/pty.c +++ b/drivers/char/pty.c | |||
@@ -181,6 +181,7 @@ static int pty_set_lock(struct tty_struct *tty, int __user * arg) | |||
181 | static void pty_flush_buffer(struct tty_struct *tty) | 181 | static void pty_flush_buffer(struct tty_struct *tty) |
182 | { | 182 | { |
183 | struct tty_struct *to = tty->link; | 183 | struct tty_struct *to = tty->link; |
184 | unsigned long flags; | ||
184 | 185 | ||
185 | if (!to) | 186 | if (!to) |
186 | return; | 187 | return; |
@@ -189,8 +190,10 @@ static void pty_flush_buffer(struct tty_struct *tty) | |||
189 | to->ldisc.flush_buffer(to); | 190 | to->ldisc.flush_buffer(to); |
190 | 191 | ||
191 | if (to->packet) { | 192 | if (to->packet) { |
193 | spin_lock_irqsave(&tty->ctrl_lock, flags); | ||
192 | tty->ctrl_status |= TIOCPKT_FLUSHWRITE; | 194 | tty->ctrl_status |= TIOCPKT_FLUSHWRITE; |
193 | wake_up_interruptible(&to->read_wait); | 195 | wake_up_interruptible(&to->read_wait); |
196 | spin_unlock_irqrestore(&tty->ctrl_lock, flags); | ||
194 | } | 197 | } |
195 | } | 198 | } |
196 | 199 | ||
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 | } |
diff --git a/drivers/char/tty_ioctl.c b/drivers/char/tty_ioctl.c index f95a80b2265f..d6353d89b451 100644 --- a/drivers/char/tty_ioctl.c +++ b/drivers/char/tty_ioctl.c | |||
@@ -395,6 +395,7 @@ static void change_termios(struct tty_struct *tty, struct ktermios *new_termios) | |||
395 | int canon_change; | 395 | int canon_change; |
396 | struct ktermios old_termios = *tty->termios; | 396 | struct ktermios old_termios = *tty->termios; |
397 | struct tty_ldisc *ld; | 397 | struct tty_ldisc *ld; |
398 | unsigned long flags; | ||
398 | 399 | ||
399 | /* | 400 | /* |
400 | * Perform the actual termios internal changes under lock. | 401 | * Perform the actual termios internal changes under lock. |
@@ -429,11 +430,13 @@ static void change_termios(struct tty_struct *tty, struct ktermios *new_termios) | |||
429 | STOP_CHAR(tty) == '\023' && | 430 | STOP_CHAR(tty) == '\023' && |
430 | START_CHAR(tty) == '\021'); | 431 | START_CHAR(tty) == '\021'); |
431 | if (old_flow != new_flow) { | 432 | if (old_flow != new_flow) { |
433 | spin_lock_irqsave(&tty->ctrl_lock, flags); | ||
432 | tty->ctrl_status &= ~(TIOCPKT_DOSTOP | TIOCPKT_NOSTOP); | 434 | tty->ctrl_status &= ~(TIOCPKT_DOSTOP | TIOCPKT_NOSTOP); |
433 | if (new_flow) | 435 | if (new_flow) |
434 | tty->ctrl_status |= TIOCPKT_DOSTOP; | 436 | tty->ctrl_status |= TIOCPKT_DOSTOP; |
435 | else | 437 | else |
436 | tty->ctrl_status |= TIOCPKT_NOSTOP; | 438 | tty->ctrl_status |= TIOCPKT_NOSTOP; |
439 | spin_unlock_irqrestore(&tty->ctrl_lock, flags); | ||
437 | wake_up_interruptible(&tty->link->read_wait); | 440 | wake_up_interruptible(&tty->link->read_wait); |
438 | } | 441 | } |
439 | } | 442 | } |
@@ -905,6 +908,7 @@ int n_tty_ioctl(struct tty_struct *tty, struct file *file, | |||
905 | unsigned int cmd, unsigned long arg) | 908 | unsigned int cmd, unsigned long arg) |
906 | { | 909 | { |
907 | struct tty_struct *real_tty; | 910 | struct tty_struct *real_tty; |
911 | unsigned long flags; | ||
908 | int retval; | 912 | int retval; |
909 | 913 | ||
910 | if (tty->driver->type == TTY_DRIVER_TYPE_PTY && | 914 | if (tty->driver->type == TTY_DRIVER_TYPE_PTY && |
@@ -963,6 +967,7 @@ int n_tty_ioctl(struct tty_struct *tty, struct file *file, | |||
963 | return -ENOTTY; | 967 | return -ENOTTY; |
964 | if (get_user(pktmode, (int __user *) arg)) | 968 | if (get_user(pktmode, (int __user *) arg)) |
965 | return -EFAULT; | 969 | return -EFAULT; |
970 | spin_lock_irqsave(&tty->ctrl_lock, flags); | ||
966 | if (pktmode) { | 971 | if (pktmode) { |
967 | if (!tty->packet) { | 972 | if (!tty->packet) { |
968 | tty->packet = 1; | 973 | tty->packet = 1; |
@@ -970,6 +975,7 @@ int n_tty_ioctl(struct tty_struct *tty, struct file *file, | |||
970 | } | 975 | } |
971 | } else | 976 | } else |
972 | tty->packet = 0; | 977 | tty->packet = 0; |
978 | spin_unlock_irqrestore(&tty->ctrl_lock, flags); | ||
973 | return 0; | 979 | return 0; |
974 | } | 980 | } |
975 | default: | 981 | default: |
diff --git a/drivers/char/vt.c b/drivers/char/vt.c index 1c2660477135..e64f0bf3624e 100644 --- a/drivers/char/vt.c +++ b/drivers/char/vt.c | |||
@@ -2541,6 +2541,9 @@ int tioclinux(struct tty_struct *tty, unsigned long arg) | |||
2541 | if (get_user(type, p)) | 2541 | if (get_user(type, p)) |
2542 | return -EFAULT; | 2542 | return -EFAULT; |
2543 | ret = 0; | 2543 | ret = 0; |
2544 | |||
2545 | lock_kernel(); | ||
2546 | |||
2544 | switch (type) | 2547 | switch (type) |
2545 | { | 2548 | { |
2546 | case TIOCL_SETSEL: | 2549 | case TIOCL_SETSEL: |
@@ -2560,7 +2563,7 @@ int tioclinux(struct tty_struct *tty, unsigned long arg) | |||
2560 | ret = sel_loadlut(p); | 2563 | ret = sel_loadlut(p); |
2561 | break; | 2564 | break; |
2562 | case TIOCL_GETSHIFTSTATE: | 2565 | case TIOCL_GETSHIFTSTATE: |
2563 | 2566 | ||
2564 | /* | 2567 | /* |
2565 | * Make it possible to react to Shift+Mousebutton. | 2568 | * Make it possible to react to Shift+Mousebutton. |
2566 | * Note that 'shift_state' is an undocumented | 2569 | * Note that 'shift_state' is an undocumented |
@@ -2615,6 +2618,7 @@ int tioclinux(struct tty_struct *tty, unsigned long arg) | |||
2615 | ret = -EINVAL; | 2618 | ret = -EINVAL; |
2616 | break; | 2619 | break; |
2617 | } | 2620 | } |
2621 | unlock_kernel(); | ||
2618 | return ret; | 2622 | return ret; |
2619 | } | 2623 | } |
2620 | 2624 | ||
@@ -3829,7 +3833,7 @@ static int con_font_get(struct vc_data *vc, struct console_font_op *op) | |||
3829 | goto out; | 3833 | goto out; |
3830 | 3834 | ||
3831 | c = (font.width+7)/8 * 32 * font.charcount; | 3835 | c = (font.width+7)/8 * 32 * font.charcount; |
3832 | 3836 | ||
3833 | if (op->data && font.charcount > op->charcount) | 3837 | if (op->data && font.charcount > op->charcount) |
3834 | rc = -ENOSPC; | 3838 | rc = -ENOSPC; |
3835 | if (!(op->flags & KD_FONT_FLAG_OLD)) { | 3839 | if (!(op->flags & KD_FONT_FLAG_OLD)) { |