diff options
Diffstat (limited to 'drivers/tty/pty.c')
-rw-r--r-- | drivers/tty/pty.c | 40 |
1 files changed, 28 insertions, 12 deletions
diff --git a/drivers/tty/pty.c b/drivers/tty/pty.c index eeae7fafe9a7..59af3945ea85 100644 --- a/drivers/tty/pty.c +++ b/drivers/tty/pty.c | |||
@@ -26,11 +26,13 @@ | |||
26 | #include <linux/bitops.h> | 26 | #include <linux/bitops.h> |
27 | #include <linux/devpts_fs.h> | 27 | #include <linux/devpts_fs.h> |
28 | #include <linux/slab.h> | 28 | #include <linux/slab.h> |
29 | #include <linux/mutex.h> | ||
29 | 30 | ||
30 | 31 | ||
31 | #ifdef CONFIG_UNIX98_PTYS | 32 | #ifdef CONFIG_UNIX98_PTYS |
32 | static struct tty_driver *ptm_driver; | 33 | static struct tty_driver *ptm_driver; |
33 | static struct tty_driver *pts_driver; | 34 | static struct tty_driver *pts_driver; |
35 | static DEFINE_MUTEX(devpts_mutex); | ||
34 | #endif | 36 | #endif |
35 | 37 | ||
36 | static void pty_close(struct tty_struct *tty, struct file *filp) | 38 | static void pty_close(struct tty_struct *tty, struct file *filp) |
@@ -45,6 +47,7 @@ static void pty_close(struct tty_struct *tty, struct file *filp) | |||
45 | wake_up_interruptible(&tty->read_wait); | 47 | wake_up_interruptible(&tty->read_wait); |
46 | wake_up_interruptible(&tty->write_wait); | 48 | wake_up_interruptible(&tty->write_wait); |
47 | tty->packet = 0; | 49 | tty->packet = 0; |
50 | /* Review - krefs on tty_link ?? */ | ||
48 | if (!tty->link) | 51 | if (!tty->link) |
49 | return; | 52 | return; |
50 | tty->link->packet = 0; | 53 | tty->link->packet = 0; |
@@ -54,12 +57,15 @@ static void pty_close(struct tty_struct *tty, struct file *filp) | |||
54 | if (tty->driver->subtype == PTY_TYPE_MASTER) { | 57 | if (tty->driver->subtype == PTY_TYPE_MASTER) { |
55 | set_bit(TTY_OTHER_CLOSED, &tty->flags); | 58 | set_bit(TTY_OTHER_CLOSED, &tty->flags); |
56 | #ifdef CONFIG_UNIX98_PTYS | 59 | #ifdef CONFIG_UNIX98_PTYS |
57 | if (tty->driver == ptm_driver) | 60 | if (tty->driver == ptm_driver) { |
61 | mutex_lock(&devpts_mutex); | ||
58 | devpts_pty_kill(tty->link); | 62 | devpts_pty_kill(tty->link); |
63 | mutex_unlock(&devpts_mutex); | ||
64 | } | ||
59 | #endif | 65 | #endif |
60 | tty_unlock(); | 66 | tty_unlock(tty); |
61 | tty_vhangup(tty->link); | 67 | tty_vhangup(tty->link); |
62 | tty_lock(); | 68 | tty_lock(tty); |
63 | } | 69 | } |
64 | } | 70 | } |
65 | 71 | ||
@@ -475,13 +481,17 @@ static struct tty_struct *ptm_unix98_lookup(struct tty_driver *driver, | |||
475 | * @idx: tty index | 481 | * @idx: tty index |
476 | * | 482 | * |
477 | * Look up a pty master device. Called under the tty_mutex for now. | 483 | * Look up a pty master device. Called under the tty_mutex for now. |
478 | * This provides our locking. | 484 | * This provides our locking for the tty pointer. |
479 | */ | 485 | */ |
480 | 486 | ||
481 | static struct tty_struct *pts_unix98_lookup(struct tty_driver *driver, | 487 | static struct tty_struct *pts_unix98_lookup(struct tty_driver *driver, |
482 | struct inode *pts_inode, int idx) | 488 | struct inode *pts_inode, int idx) |
483 | { | 489 | { |
484 | struct tty_struct *tty = devpts_get_tty(pts_inode, idx); | 490 | struct tty_struct *tty; |
491 | |||
492 | mutex_lock(&devpts_mutex); | ||
493 | tty = devpts_get_tty(pts_inode, idx); | ||
494 | mutex_unlock(&devpts_mutex); | ||
485 | /* Master must be open before slave */ | 495 | /* Master must be open before slave */ |
486 | if (!tty) | 496 | if (!tty) |
487 | return ERR_PTR(-EIO); | 497 | return ERR_PTR(-EIO); |
@@ -613,24 +623,29 @@ static int ptmx_open(struct inode *inode, struct file *filp) | |||
613 | return retval; | 623 | return retval; |
614 | 624 | ||
615 | /* find a device that is not in use. */ | 625 | /* find a device that is not in use. */ |
616 | tty_lock(); | 626 | mutex_lock(&devpts_mutex); |
617 | index = devpts_new_index(inode); | 627 | index = devpts_new_index(inode); |
618 | tty_unlock(); | ||
619 | if (index < 0) { | 628 | if (index < 0) { |
620 | retval = index; | 629 | retval = index; |
621 | goto err_file; | 630 | goto err_file; |
622 | } | 631 | } |
623 | 632 | ||
633 | mutex_unlock(&devpts_mutex); | ||
634 | |||
624 | mutex_lock(&tty_mutex); | 635 | mutex_lock(&tty_mutex); |
625 | tty_lock(); | 636 | mutex_lock(&devpts_mutex); |
626 | tty = tty_init_dev(ptm_driver, index); | 637 | tty = tty_init_dev(ptm_driver, index); |
627 | mutex_unlock(&tty_mutex); | ||
628 | 638 | ||
629 | if (IS_ERR(tty)) { | 639 | if (IS_ERR(tty)) { |
630 | retval = PTR_ERR(tty); | 640 | retval = PTR_ERR(tty); |
631 | goto out; | 641 | goto out; |
632 | } | 642 | } |
633 | 643 | ||
644 | /* The tty returned here is locked so we can safely | ||
645 | drop the mutex */ | ||
646 | mutex_unlock(&devpts_mutex); | ||
647 | mutex_unlock(&tty_mutex); | ||
648 | |||
634 | set_bit(TTY_PTY_LOCK, &tty->flags); /* LOCK THE SLAVE */ | 649 | set_bit(TTY_PTY_LOCK, &tty->flags); /* LOCK THE SLAVE */ |
635 | 650 | ||
636 | tty_add_file(tty, filp); | 651 | tty_add_file(tty, filp); |
@@ -643,16 +658,17 @@ static int ptmx_open(struct inode *inode, struct file *filp) | |||
643 | if (retval) | 658 | if (retval) |
644 | goto err_release; | 659 | goto err_release; |
645 | 660 | ||
646 | tty_unlock(); | 661 | tty_unlock(tty); |
647 | return 0; | 662 | return 0; |
648 | err_release: | 663 | err_release: |
649 | tty_unlock(); | 664 | tty_unlock(tty); |
650 | tty_release(inode, filp); | 665 | tty_release(inode, filp); |
651 | return retval; | 666 | return retval; |
652 | out: | 667 | out: |
668 | mutex_unlock(&tty_mutex); | ||
653 | devpts_kill_index(inode, index); | 669 | devpts_kill_index(inode, index); |
654 | tty_unlock(); | ||
655 | err_file: | 670 | err_file: |
671 | mutex_unlock(&devpts_mutex); | ||
656 | tty_free_file(filp); | 672 | tty_free_file(filp); |
657 | return retval; | 673 | return retval; |
658 | } | 674 | } |