diff options
author | Arnd Bergmann <arnd@arndb.de> | 2010-06-01 16:53:02 -0400 |
---|---|---|
committer | Greg Kroah-Hartman <gregkh@suse.de> | 2010-08-10 16:47:43 -0400 |
commit | 64ba3dc3143d94bbe935722aa17fa516b232bc83 (patch) | |
tree | 9649ffd431eb8dc97fbad83d47feaed96980cb7e /drivers/char | |
parent | ec79d6056de58511d8e46d9ae59d3878f958dc3e (diff) |
tty: never hold BTM while getting tty_mutex
tty_mutex is never taken with the BTM held, except for
two corner cases that are worked around here.
We give up the BTM before calling tty_release() in the
error path of tty_open().
Similarly, we reorder the locking in ptmx_open()
to get tty_mutex before the BTM.
Signed-off-by: Arnd Bergmann <arnd@arndb.de>
Cc: Alan Cox <alan@lxorguk.ukuu.org.uk>
Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
Diffstat (limited to 'drivers/char')
-rw-r--r-- | drivers/char/pty.c | 24 | ||||
-rw-r--r-- | drivers/char/tty_io.c | 12 |
2 files changed, 17 insertions, 19 deletions
diff --git a/drivers/char/pty.c b/drivers/char/pty.c index 622e21ca9a5..de22ea95283 100644 --- a/drivers/char/pty.c +++ b/drivers/char/pty.c | |||
@@ -647,7 +647,7 @@ static const struct tty_operations pty_unix98_ops = { | |||
647 | * allocated_ptys_lock handles the list of free pty numbers | 647 | * allocated_ptys_lock handles the list of free pty numbers |
648 | */ | 648 | */ |
649 | 649 | ||
650 | static int __ptmx_open(struct inode *inode, struct file *filp) | 650 | static int ptmx_open(struct inode *inode, struct file *filp) |
651 | { | 651 | { |
652 | struct tty_struct *tty; | 652 | struct tty_struct *tty; |
653 | int retval; | 653 | int retval; |
@@ -656,11 +656,14 @@ static int __ptmx_open(struct inode *inode, struct file *filp) | |||
656 | nonseekable_open(inode, filp); | 656 | nonseekable_open(inode, filp); |
657 | 657 | ||
658 | /* find a device that is not in use. */ | 658 | /* find a device that is not in use. */ |
659 | tty_lock(); | ||
659 | index = devpts_new_index(inode); | 660 | index = devpts_new_index(inode); |
661 | tty_unlock(); | ||
660 | if (index < 0) | 662 | if (index < 0) |
661 | return index; | 663 | return index; |
662 | 664 | ||
663 | mutex_lock(&tty_mutex); | 665 | mutex_lock(&tty_mutex); |
666 | tty_lock(); | ||
664 | tty = tty_init_dev(ptm_driver, index, 1); | 667 | tty = tty_init_dev(ptm_driver, index, 1); |
665 | mutex_unlock(&tty_mutex); | 668 | mutex_unlock(&tty_mutex); |
666 | 669 | ||
@@ -678,24 +681,19 @@ static int __ptmx_open(struct inode *inode, struct file *filp) | |||
678 | goto out1; | 681 | goto out1; |
679 | 682 | ||
680 | retval = ptm_driver->ops->open(tty, filp); | 683 | retval = ptm_driver->ops->open(tty, filp); |
681 | if (!retval) | 684 | if (retval) |
682 | return 0; | 685 | goto out2; |
683 | out1: | 686 | out1: |
687 | tty_unlock(); | ||
688 | return retval; | ||
689 | out2: | ||
690 | tty_unlock(); | ||
684 | tty_release(inode, filp); | 691 | tty_release(inode, filp); |
685 | return retval; | 692 | return retval; |
686 | out: | 693 | out: |
687 | devpts_kill_index(inode, index); | 694 | devpts_kill_index(inode, index); |
688 | return retval; | ||
689 | } | ||
690 | |||
691 | static int ptmx_open(struct inode *inode, struct file *filp) | ||
692 | { | ||
693 | int ret; | ||
694 | |||
695 | tty_lock(); | ||
696 | ret = __ptmx_open(inode, filp); | ||
697 | tty_unlock(); | 695 | tty_unlock(); |
698 | return ret; | 696 | return retval; |
699 | } | 697 | } |
700 | 698 | ||
701 | static struct file_operations ptmx_fops; | 699 | static struct file_operations ptmx_fops; |
diff --git a/drivers/char/tty_io.c b/drivers/char/tty_io.c index 5ee9081a560..bb22cf49543 100644 --- a/drivers/char/tty_io.c +++ b/drivers/char/tty_io.c | |||
@@ -1866,19 +1866,19 @@ got_driver: | |||
1866 | printk(KERN_DEBUG "error %d in opening %s...", retval, | 1866 | printk(KERN_DEBUG "error %d in opening %s...", retval, |
1867 | tty->name); | 1867 | tty->name); |
1868 | #endif | 1868 | #endif |
1869 | tty_unlock(); /* need to call tty_release without BTM */ | ||
1869 | tty_release(inode, filp); | 1870 | tty_release(inode, filp); |
1870 | if (retval != -ERESTARTSYS) { | 1871 | if (retval != -ERESTARTSYS) |
1871 | tty_unlock(); | ||
1872 | return retval; | 1872 | return retval; |
1873 | } | 1873 | |
1874 | if (signal_pending(current)) { | 1874 | if (signal_pending(current)) |
1875 | tty_unlock(); | ||
1876 | return retval; | 1875 | return retval; |
1877 | } | 1876 | |
1878 | schedule(); | 1877 | schedule(); |
1879 | /* | 1878 | /* |
1880 | * Need to reset f_op in case a hangup happened. | 1879 | * Need to reset f_op in case a hangup happened. |
1881 | */ | 1880 | */ |
1881 | tty_lock(); | ||
1882 | if (filp->f_op == &hung_up_tty_fops) | 1882 | if (filp->f_op == &hung_up_tty_fops) |
1883 | filp->f_op = &tty_fops; | 1883 | filp->f_op = &tty_fops; |
1884 | tty_unlock(); | 1884 | tty_unlock(); |