aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorAlan Cox <alan@linux.intel.com>2009-06-11 07:48:02 -0400
committerLinus Torvalds <torvalds@linux-foundation.org>2009-06-11 11:51:01 -0400
commite8b70e7d3e86319a8b2aaabde3866833d92cd80f (patch)
treedac8e7b42f553ee3a9a0920e20b5a39da197b13a
parent5f0878acba7db24323f5ba4055ec9a96895bb150 (diff)
tty: Extract various bits of ldisc code
Before trying to tackle the ldisc bugs the code needs to be a good deal more readable, so do the simple extractions of routines first. Signed-off-by: Alan Cox <alan@linux.intel.com> Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
-rw-r--r--drivers/char/tty_io.c24
-rw-r--r--drivers/char/tty_ldisc.c97
-rw-r--r--include/linux/tty.h3
3 files changed, 88 insertions, 36 deletions
diff --git a/drivers/char/tty_io.c b/drivers/char/tty_io.c
index 6c817398232e..be49d0730bb9 100644
--- a/drivers/char/tty_io.c
+++ b/drivers/char/tty_io.c
@@ -2481,6 +2481,24 @@ static int tty_tiocmset(struct tty_struct *tty, struct file *file, unsigned int
2481 return tty->ops->tiocmset(tty, file, set, clear); 2481 return tty->ops->tiocmset(tty, file, set, clear);
2482} 2482}
2483 2483
2484struct tty_struct *tty_pair_get_tty(struct tty_struct *tty)
2485{
2486 if (tty->driver->type == TTY_DRIVER_TYPE_PTY &&
2487 tty->driver->subtype == PTY_TYPE_MASTER)
2488 tty = tty->link;
2489 return tty;
2490}
2491EXPORT_SYMBOL(tty_pair_get_tty);
2492
2493struct tty_struct *tty_pair_get_pty(struct tty_struct *tty)
2494{
2495 if (tty->driver->type == TTY_DRIVER_TYPE_PTY &&
2496 tty->driver->subtype == PTY_TYPE_MASTER)
2497 return tty;
2498 return tty->link;
2499}
2500EXPORT_SYMBOL(tty_pair_get_pty);
2501
2484/* 2502/*
2485 * Split this up, as gcc can choke on it otherwise.. 2503 * Split this up, as gcc can choke on it otherwise..
2486 */ 2504 */
@@ -2496,11 +2514,7 @@ long tty_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
2496 if (tty_paranoia_check(tty, inode, "tty_ioctl")) 2514 if (tty_paranoia_check(tty, inode, "tty_ioctl"))
2497 return -EINVAL; 2515 return -EINVAL;
2498 2516
2499 real_tty = tty; 2517 real_tty = tty_pair_get_tty(tty);
2500 if (tty->driver->type == TTY_DRIVER_TYPE_PTY &&
2501 tty->driver->subtype == PTY_TYPE_MASTER)
2502 real_tty = tty->link;
2503
2504 2518
2505 /* 2519 /*
2506 * Factor out some common prep work 2520 * Factor out some common prep work
diff --git a/drivers/char/tty_ldisc.c b/drivers/char/tty_ldisc.c
index f78f5b0127a8..e3c6416aa86d 100644
--- a/drivers/char/tty_ldisc.c
+++ b/drivers/char/tty_ldisc.c
@@ -444,6 +444,50 @@ static void tty_ldisc_restore(struct tty_struct *tty, struct tty_ldisc *old)
444} 444}
445 445
446/** 446/**
447 * tty_ldisc_halt - shutdown the line discipline
448 * @tty: tty device
449 *
450 * Shut down the line discipline and work queue for this tty device.
451 * The TTY_LDISC flag being cleared ensures no further references can
452 * be obtained while the delayed work queue halt ensures that no more
453 * data is fed to the ldisc.
454 *
455 * In order to wait for any existing references to complete see
456 * tty_ldisc_wait_idle.
457 */
458
459static void tty_ldisc_halt(struct tty_struct *tty)
460{
461 clear_bit(TTY_LDISC, &tty->flags);
462 cancel_delayed_work(&tty->buf.work);
463 /*
464 * Wait for ->hangup_work and ->buf.work handlers to terminate
465 */
466 flush_scheduled_work();
467}
468
469/**
470 * tty_ldisc_wait_idle - wait for the ldisc to become idle
471 * @tty: tty to wait for
472 *
473 * Wait for the line discipline to become idle. The discipline must
474 * have been halted for this to guarantee it remains idle.
475 *
476 */
477
478static void tty_ldisc_wait_idle(struct tty_struct *tty)
479{
480 unsigned long flags;
481 spin_lock_irqsave(&tty_ldisc_lock, flags);
482 while (tty->ldisc.refcount) {
483 spin_unlock_irqrestore(&tty_ldisc_lock, flags);
484 wait_event(tty_ldisc_wait, tty->ldisc.refcount == 0);
485 spin_lock_irqsave(&tty_ldisc_lock, flags);
486 }
487 spin_unlock_irqrestore(&tty_ldisc_lock, flags);
488}
489
490/**
447 * tty_set_ldisc - set line discipline 491 * tty_set_ldisc - set line discipline
448 * @tty: the terminal to set 492 * @tty: the terminal to set
449 * @ldisc: the line discipline 493 * @ldisc: the line discipline
@@ -636,6 +680,21 @@ int tty_ldisc_setup(struct tty_struct *tty, struct tty_struct *o_tty)
636 return 0; 680 return 0;
637} 681}
638 682
683static void tty_ldisc_reinit(struct tty_struct *tty)
684{
685 struct tty_ldisc ld;
686
687 if (tty->ldisc.ops->close)
688 (tty->ldisc.ops->close)(tty);
689 tty_ldisc_put(tty->ldisc.ops);
690 /*
691 * Switch the line discipline back
692 */
693 WARN_ON(tty_ldisc_get(N_TTY, &ld));
694 tty_ldisc_assign(tty, &ld);
695 tty_set_termios_ldisc(tty, N_TTY);
696}
697
639/** 698/**
640 * tty_ldisc_release - release line discipline 699 * tty_ldisc_release - release line discipline
641 * @tty: tty being shut down 700 * @tty: tty being shut down
@@ -647,58 +706,34 @@ int tty_ldisc_setup(struct tty_struct *tty, struct tty_struct *o_tty)
647 706
648void tty_ldisc_release(struct tty_struct *tty, struct tty_struct *o_tty) 707void tty_ldisc_release(struct tty_struct *tty, struct tty_struct *o_tty)
649{ 708{
650 unsigned long flags; 709
651 struct tty_ldisc ld;
652 /* 710 /*
653 * Prevent flush_to_ldisc() from rescheduling the work for later. Then 711 * Prevent flush_to_ldisc() from rescheduling the work for later. Then
654 * kill any delayed work. As this is the final close it does not 712 * kill any delayed work. As this is the final close it does not
655 * race with the set_ldisc code path. 713 * race with the set_ldisc code path.
656 */ 714 */
657 clear_bit(TTY_LDISC, &tty->flags);
658 cancel_delayed_work(&tty->buf.work);
659 715
660 /* 716 tty_ldisc_halt(tty);
661 * Wait for ->hangup_work and ->buf.work handlers to terminate
662 */
663
664 flush_scheduled_work();
665 717
666 /* 718 /*
667 * Wait for any short term users (we know they are just driver 719 * Wait for any short term users (we know they are just driver
668 * side waiters as the file is closing so user count on the file 720 * side waiters as the file is closing so user count on the file
669 * side is zero. 721 * side is zero.
670 */ 722 */
671 spin_lock_irqsave(&tty_ldisc_lock, flags); 723
672 while (tty->ldisc.refcount) { 724 tty_ldisc_wait_idle(tty);
673 spin_unlock_irqrestore(&tty_ldisc_lock, flags); 725
674 wait_event(tty_ldisc_wait, tty->ldisc.refcount == 0);
675 spin_lock_irqsave(&tty_ldisc_lock, flags);
676 }
677 spin_unlock_irqrestore(&tty_ldisc_lock, flags);
678 /* 726 /*
679 * Shutdown the current line discipline, and reset it to N_TTY. 727 * Shutdown the current line discipline, and reset it to N_TTY.
680 * 728 *
681 * FIXME: this MUST get fixed for the new reflocking 729 * FIXME: this MUST get fixed for the new reflocking
682 */ 730 */
683 if (tty->ldisc.ops->close)
684 (tty->ldisc.ops->close)(tty);
685 tty_ldisc_put(tty->ldisc.ops);
686 731
687 /* 732 tty_ldisc_reinit(tty);
688 * Switch the line discipline back
689 */
690 WARN_ON(tty_ldisc_get(N_TTY, &ld));
691 tty_ldisc_assign(tty, &ld);
692 tty_set_termios_ldisc(tty, N_TTY);
693 if (o_tty) { 733 if (o_tty) {
694 /* FIXME: could o_tty be in setldisc here ? */ 734 /* FIXME: could o_tty be in setldisc here ? */
695 clear_bit(TTY_LDISC, &o_tty->flags); 735 clear_bit(TTY_LDISC, &o_tty->flags);
696 if (o_tty->ldisc.ops->close) 736 tty_ldisc_reinit(o_tty);
697 (o_tty->ldisc.ops->close)(o_tty);
698 tty_ldisc_put(o_tty->ldisc.ops);
699 WARN_ON(tty_ldisc_get(N_TTY, &ld));
700 tty_ldisc_assign(o_tty, &ld);
701 tty_set_termios_ldisc(o_tty, N_TTY);
702 } 737 }
703} 738}
704 739
diff --git a/include/linux/tty.h b/include/linux/tty.h
index bed5a3d40307..f9c13c83790c 100644
--- a/include/linux/tty.h
+++ b/include/linux/tty.h
@@ -428,6 +428,9 @@ extern struct tty_struct *tty_init_dev(struct tty_driver *driver, int idx,
428extern void tty_release_dev(struct file *filp); 428extern void tty_release_dev(struct file *filp);
429extern int tty_init_termios(struct tty_struct *tty); 429extern int tty_init_termios(struct tty_struct *tty);
430 430
431extern struct tty_struct *tty_pair_get_tty(struct tty_struct *tty);
432extern struct tty_struct *tty_pair_get_pty(struct tty_struct *tty);
433
431extern struct mutex tty_mutex; 434extern struct mutex tty_mutex;
432 435
433extern void tty_write_unlock(struct tty_struct *tty); 436extern void tty_write_unlock(struct tty_struct *tty);