Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

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>

authored by

Alan Cox and committed by
Linus Torvalds
e8b70e7d 5f0878ac

+88 -36
+19 -5
drivers/char/tty_io.c
··· 2481 2481 return tty->ops->tiocmset(tty, file, set, clear); 2482 2482 } 2483 2483 2484 + struct 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 + } 2491 + EXPORT_SYMBOL(tty_pair_get_tty); 2492 + 2493 + struct 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 + } 2500 + EXPORT_SYMBOL(tty_pair_get_pty); 2501 + 2484 2502 /* 2485 2503 * Split this up, as gcc can choke on it otherwise.. 2486 2504 */ ··· 2514 2496 if (tty_paranoia_check(tty, inode, "tty_ioctl")) 2515 2497 return -EINVAL; 2516 2498 2517 - real_tty = tty; 2518 - if (tty->driver->type == TTY_DRIVER_TYPE_PTY && 2519 - tty->driver->subtype == PTY_TYPE_MASTER) 2520 - real_tty = tty->link; 2521 - 2499 + real_tty = tty_pair_get_tty(tty); 2522 2500 2523 2501 /* 2524 2502 * Factor out some common prep work
+66 -31
drivers/char/tty_ldisc.c
··· 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 + 459 + static 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 + 478 + static 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 491 * tty_set_ldisc - set line discipline 448 492 * @tty: the terminal to set 449 493 * @ldisc: the line discipline ··· 680 636 return 0; 681 637 } 682 638 639 + static void tty_ldisc_reinit(struct tty_struct *tty) 640 + { 641 + struct tty_ldisc ld; 642 + 643 + if (tty->ldisc.ops->close) 644 + (tty->ldisc.ops->close)(tty); 645 + tty_ldisc_put(tty->ldisc.ops); 646 + /* 647 + * Switch the line discipline back 648 + */ 649 + WARN_ON(tty_ldisc_get(N_TTY, &ld)); 650 + tty_ldisc_assign(tty, &ld); 651 + tty_set_termios_ldisc(tty, N_TTY); 652 + } 653 + 683 654 /** 684 655 * tty_ldisc_release - release line discipline 685 656 * @tty: tty being shut down ··· 706 647 707 648 void tty_ldisc_release(struct tty_struct *tty, struct tty_struct *o_tty) 708 649 { 709 - unsigned long flags; 710 - struct tty_ldisc ld; 650 + 711 651 /* 712 652 * Prevent flush_to_ldisc() from rescheduling the work for later. Then 713 653 * kill any delayed work. As this is the final close it does not 714 654 * race with the set_ldisc code path. 715 655 */ 716 - clear_bit(TTY_LDISC, &tty->flags); 717 - cancel_delayed_work(&tty->buf.work); 718 656 719 - /* 720 - * Wait for ->hangup_work and ->buf.work handlers to terminate 721 - */ 722 - 723 - flush_scheduled_work(); 657 + tty_ldisc_halt(tty); 724 658 725 659 /* 726 660 * Wait for any short term users (we know they are just driver 727 661 * side waiters as the file is closing so user count on the file 728 662 * side is zero. 729 663 */ 730 - spin_lock_irqsave(&tty_ldisc_lock, flags); 731 - while (tty->ldisc.refcount) { 732 - spin_unlock_irqrestore(&tty_ldisc_lock, flags); 733 - wait_event(tty_ldisc_wait, tty->ldisc.refcount == 0); 734 - spin_lock_irqsave(&tty_ldisc_lock, flags); 735 - } 736 - spin_unlock_irqrestore(&tty_ldisc_lock, flags); 664 + 665 + tty_ldisc_wait_idle(tty); 666 + 737 667 /* 738 668 * Shutdown the current line discipline, and reset it to N_TTY. 739 669 * 740 670 * FIXME: this MUST get fixed for the new reflocking 741 671 */ 742 - if (tty->ldisc.ops->close) 743 - (tty->ldisc.ops->close)(tty); 744 - tty_ldisc_put(tty->ldisc.ops); 745 672 746 - /* 747 - * Switch the line discipline back 748 - */ 749 - WARN_ON(tty_ldisc_get(N_TTY, &ld)); 750 - tty_ldisc_assign(tty, &ld); 751 - tty_set_termios_ldisc(tty, N_TTY); 673 + tty_ldisc_reinit(tty); 752 674 if (o_tty) { 753 675 /* FIXME: could o_tty be in setldisc here ? */ 754 676 clear_bit(TTY_LDISC, &o_tty->flags); 755 - if (o_tty->ldisc.ops->close) 756 - (o_tty->ldisc.ops->close)(o_tty); 757 - tty_ldisc_put(o_tty->ldisc.ops); 758 - WARN_ON(tty_ldisc_get(N_TTY, &ld)); 759 - tty_ldisc_assign(o_tty, &ld); 760 - tty_set_termios_ldisc(o_tty, N_TTY); 677 + tty_ldisc_reinit(o_tty); 761 678 } 762 679 } 763 680
+3
include/linux/tty.h
··· 428 428 extern void tty_release_dev(struct file *filp); 429 429 extern int tty_init_termios(struct tty_struct *tty); 430 430 431 + extern struct tty_struct *tty_pair_get_tty(struct tty_struct *tty); 432 + extern struct tty_struct *tty_pair_get_pty(struct tty_struct *tty); 433 + 431 434 extern struct mutex tty_mutex; 432 435 433 436 extern void tty_write_unlock(struct tty_struct *tty);