aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/char
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/char')
-rw-r--r--drivers/char/pty.c5
-rw-r--r--drivers/char/tty_io.c79
2 files changed, 56 insertions, 28 deletions
diff --git a/drivers/char/pty.c b/drivers/char/pty.c
index da32889d22c0..49f3997fd251 100644
--- a/drivers/char/pty.c
+++ b/drivers/char/pty.c
@@ -149,15 +149,14 @@ static int pty_write_room(struct tty_struct *tty)
149static int pty_chars_in_buffer(struct tty_struct *tty) 149static int pty_chars_in_buffer(struct tty_struct *tty)
150{ 150{
151 struct tty_struct *to = tty->link; 151 struct tty_struct *to = tty->link;
152 ssize_t (*chars_in_buffer)(struct tty_struct *);
153 int count; 152 int count;
154 153
155 /* We should get the line discipline lock for "tty->link" */ 154 /* We should get the line discipline lock for "tty->link" */
156 if (!to || !(chars_in_buffer = to->ldisc.chars_in_buffer)) 155 if (!to || !to->ldisc.chars_in_buffer)
157 return 0; 156 return 0;
158 157
159 /* The ldisc must report 0 if no characters available to be read */ 158 /* The ldisc must report 0 if no characters available to be read */
160 count = chars_in_buffer(to); 159 count = to->ldisc.chars_in_buffer(to);
161 160
162 if (tty->driver->subtype == PTY_TYPE_SLAVE) return count; 161 if (tty->driver->subtype == PTY_TYPE_SLAVE) return count;
163 162
diff --git a/drivers/char/tty_io.c b/drivers/char/tty_io.c
index 9d657127f313..6a56ae4f7725 100644
--- a/drivers/char/tty_io.c
+++ b/drivers/char/tty_io.c
@@ -469,21 +469,19 @@ static void tty_ldisc_enable(struct tty_struct *tty)
469 469
470static int tty_set_ldisc(struct tty_struct *tty, int ldisc) 470static int tty_set_ldisc(struct tty_struct *tty, int ldisc)
471{ 471{
472 int retval = 0; 472 int retval = 0;
473 struct tty_ldisc o_ldisc; 473 struct tty_ldisc o_ldisc;
474 char buf[64]; 474 char buf[64];
475 int work; 475 int work;
476 unsigned long flags; 476 unsigned long flags;
477 struct tty_ldisc *ld; 477 struct tty_ldisc *ld;
478 struct tty_struct *o_tty;
478 479
479 if ((ldisc < N_TTY) || (ldisc >= NR_LDISCS)) 480 if ((ldisc < N_TTY) || (ldisc >= NR_LDISCS))
480 return -EINVAL; 481 return -EINVAL;
481 482
482restart: 483restart:
483 484
484 if (tty->ldisc.num == ldisc)
485 return 0; /* We are already in the desired discipline */
486
487 ld = tty_ldisc_get(ldisc); 485 ld = tty_ldisc_get(ldisc);
488 /* Eduardo Blanco <ejbs@cs.cs.com.uy> */ 486 /* Eduardo Blanco <ejbs@cs.cs.com.uy> */
489 /* Cyrus Durgin <cider@speakeasy.org> */ 487 /* Cyrus Durgin <cider@speakeasy.org> */
@@ -494,45 +492,74 @@ restart:
494 if (ld == NULL) 492 if (ld == NULL)
495 return -EINVAL; 493 return -EINVAL;
496 494
497 o_ldisc = tty->ldisc;
498
499 tty_wait_until_sent(tty, 0); 495 tty_wait_until_sent(tty, 0);
500 496
497 if (tty->ldisc.num == ldisc) {
498 tty_ldisc_put(ldisc);
499 return 0;
500 }
501
502 o_ldisc = tty->ldisc;
503 o_tty = tty->link;
504
501 /* 505 /*
502 * Make sure we don't change while someone holds a 506 * Make sure we don't change while someone holds a
503 * reference to the line discipline. The TTY_LDISC bit 507 * reference to the line discipline. The TTY_LDISC bit
504 * prevents anyone taking a reference once it is clear. 508 * prevents anyone taking a reference once it is clear.
505 * We need the lock to avoid racing reference takers. 509 * We need the lock to avoid racing reference takers.
506 */ 510 */
507 511
508 spin_lock_irqsave(&tty_ldisc_lock, flags); 512 spin_lock_irqsave(&tty_ldisc_lock, flags);
509 if(tty->ldisc.refcount) 513 if (tty->ldisc.refcount || (o_tty && o_tty->ldisc.refcount)) {
510 { 514 if(tty->ldisc.refcount) {
511 /* Free the new ldisc we grabbed. Must drop the lock 515 /* Free the new ldisc we grabbed. Must drop the lock
512 first. */ 516 first. */
517 spin_unlock_irqrestore(&tty_ldisc_lock, flags);
518 tty_ldisc_put(ldisc);
519 /*
520 * There are several reasons we may be busy, including
521 * random momentary I/O traffic. We must therefore
522 * retry. We could distinguish between blocking ops
523 * and retries if we made tty_ldisc_wait() smarter. That
524 * is up for discussion.
525 */
526 if (wait_event_interruptible(tty_ldisc_wait, tty->ldisc.refcount == 0) < 0)
527 return -ERESTARTSYS;
528 goto restart;
529 }
530 if(o_tty && o_tty->ldisc.refcount) {
531 spin_unlock_irqrestore(&tty_ldisc_lock, flags);
532 tty_ldisc_put(ldisc);
533 if (wait_event_interruptible(tty_ldisc_wait, o_tty->ldisc.refcount == 0) < 0)
534 return -ERESTARTSYS;
535 goto restart;
536 }
537 }
538
539 /* if the TTY_LDISC bit is set, then we are racing against another ldisc change */
540
541 if (!test_bit(TTY_LDISC, &tty->flags)) {
513 spin_unlock_irqrestore(&tty_ldisc_lock, flags); 542 spin_unlock_irqrestore(&tty_ldisc_lock, flags);
514 tty_ldisc_put(ldisc); 543 tty_ldisc_put(ldisc);
515 /* 544 ld = tty_ldisc_ref_wait(tty);
516 * There are several reasons we may be busy, including 545 tty_ldisc_deref(ld);
517 * random momentary I/O traffic. We must therefore
518 * retry. We could distinguish between blocking ops
519 * and retries if we made tty_ldisc_wait() smarter. That
520 * is up for discussion.
521 */
522 if(wait_event_interruptible(tty_ldisc_wait, tty->ldisc.refcount == 0) < 0)
523 return -ERESTARTSYS;
524 goto restart; 546 goto restart;
525 } 547 }
526 clear_bit(TTY_LDISC, &tty->flags); 548
549 clear_bit(TTY_LDISC, &tty->flags);
527 clear_bit(TTY_DONT_FLIP, &tty->flags); 550 clear_bit(TTY_DONT_FLIP, &tty->flags);
551 if (o_tty) {
552 clear_bit(TTY_LDISC, &o_tty->flags);
553 clear_bit(TTY_DONT_FLIP, &o_tty->flags);
554 }
528 spin_unlock_irqrestore(&tty_ldisc_lock, flags); 555 spin_unlock_irqrestore(&tty_ldisc_lock, flags);
529 556
530 /* 557 /*
531 * From this point on we know nobody has an ldisc 558 * From this point on we know nobody has an ldisc
532 * usage reference, nor can they obtain one until 559 * usage reference, nor can they obtain one until
533 * we say so later on. 560 * we say so later on.
534 */ 561 */
535 562
536 work = cancel_delayed_work(&tty->flip.work); 563 work = cancel_delayed_work(&tty->flip.work);
537 /* 564 /*
538 * Wait for ->hangup_work and ->flip.work handlers to terminate 565 * Wait for ->hangup_work and ->flip.work handlers to terminate
@@ -583,10 +610,12 @@ restart:
583 */ 610 */
584 611
585 tty_ldisc_enable(tty); 612 tty_ldisc_enable(tty);
613 if (o_tty)
614 tty_ldisc_enable(o_tty);
586 615
587 /* Restart it in case no characters kick it off. Safe if 616 /* Restart it in case no characters kick it off. Safe if
588 already running */ 617 already running */
589 if(work) 618 if (work)
590 schedule_delayed_work(&tty->flip.work, 1); 619 schedule_delayed_work(&tty->flip.work, 1);
591 return retval; 620 return retval;
592} 621}