diff options
author | Gianluca Anzolin <gianluca@sottospazio.it> | 2014-01-06 15:23:50 -0500 |
---|---|---|
committer | Marcel Holtmann <marcel@holtmann.org> | 2014-01-06 16:51:45 -0500 |
commit | 5b899241874dcc1a2b932a668731c80a3a869575 (patch) | |
tree | a138c1ce7fb63a0a966fc64e86a26d80b3f80f6d /net/bluetooth/rfcomm | |
parent | cb6ca8e1ed922082bacc6e5e5ee040491a443ea2 (diff) |
Bluetooth: Release RFCOMM port when the last user closes the TTY
This patch fixes a userspace regression introduced by the commit
29cd718b.
If the rfcomm device was created with the flag RFCOMM_RELEASE_ONHUP the
user space expects that the tty_port is released as soon as the last
process closes the tty.
The current code attempts to release the port in the function
rfcomm_dev_state_change(). However it won't get a reference to the
relevant tty to send a HUP: at that point the tty is already destroyed
and therefore NULL.
This patch fixes the regression by taking over the tty refcount in the
tty install method(). This way the tty_port is automatically released as
soon as the tty is destroyed.
As a consequence the check for RFCOMM_RELEASE_ONHUP flag in the hangup()
method is now redundant. Instead we have to be careful with the reference
counting in the rfcomm_release_dev() function.
Signed-off-by: Gianluca Anzolin <gianluca@sottospazio.it>
Reported-by: Alexander Holler <holler@ahsoftware.de>
Signed-off-by: Marcel Holtmann <marcel@holtmann.org>
Diffstat (limited to 'net/bluetooth/rfcomm')
-rw-r--r-- | net/bluetooth/rfcomm/tty.c | 21 |
1 files changed, 14 insertions, 7 deletions
diff --git a/net/bluetooth/rfcomm/tty.c b/net/bluetooth/rfcomm/tty.c index 84fcf9fff3ea..a535ef148ef6 100644 --- a/net/bluetooth/rfcomm/tty.c +++ b/net/bluetooth/rfcomm/tty.c | |||
@@ -437,7 +437,8 @@ static int rfcomm_release_dev(void __user *arg) | |||
437 | tty_kref_put(tty); | 437 | tty_kref_put(tty); |
438 | } | 438 | } |
439 | 439 | ||
440 | if (!test_and_set_bit(RFCOMM_TTY_RELEASED, &dev->flags)) | 440 | if (!test_bit(RFCOMM_RELEASE_ONHUP, &dev->flags) && |
441 | !test_and_set_bit(RFCOMM_TTY_RELEASED, &dev->flags)) | ||
441 | tty_port_put(&dev->port); | 442 | tty_port_put(&dev->port); |
442 | 443 | ||
443 | tty_port_put(&dev->port); | 444 | tty_port_put(&dev->port); |
@@ -670,10 +671,20 @@ static int rfcomm_tty_install(struct tty_driver *driver, struct tty_struct *tty) | |||
670 | 671 | ||
671 | /* install the tty_port */ | 672 | /* install the tty_port */ |
672 | err = tty_port_install(&dev->port, driver, tty); | 673 | err = tty_port_install(&dev->port, driver, tty); |
673 | if (err) | 674 | if (err) { |
674 | rfcomm_tty_cleanup(tty); | 675 | rfcomm_tty_cleanup(tty); |
676 | return err; | ||
677 | } | ||
675 | 678 | ||
676 | return err; | 679 | /* take over the tty_port reference if the port was created with the |
680 | * flag RFCOMM_RELEASE_ONHUP. This will force the release of the port | ||
681 | * when the last process closes the tty. The behaviour is expected by | ||
682 | * userspace. | ||
683 | */ | ||
684 | if (test_bit(RFCOMM_RELEASE_ONHUP, &dev->flags)) | ||
685 | tty_port_put(&dev->port); | ||
686 | |||
687 | return 0; | ||
677 | } | 688 | } |
678 | 689 | ||
679 | static int rfcomm_tty_open(struct tty_struct *tty, struct file *filp) | 690 | static int rfcomm_tty_open(struct tty_struct *tty, struct file *filp) |
@@ -1010,10 +1021,6 @@ static void rfcomm_tty_hangup(struct tty_struct *tty) | |||
1010 | BT_DBG("tty %p dev %p", tty, dev); | 1021 | BT_DBG("tty %p dev %p", tty, dev); |
1011 | 1022 | ||
1012 | tty_port_hangup(&dev->port); | 1023 | tty_port_hangup(&dev->port); |
1013 | |||
1014 | if (test_bit(RFCOMM_RELEASE_ONHUP, &dev->flags) && | ||
1015 | !test_and_set_bit(RFCOMM_TTY_RELEASED, &dev->flags)) | ||
1016 | tty_port_put(&dev->port); | ||
1017 | } | 1024 | } |
1018 | 1025 | ||
1019 | static int rfcomm_tty_tiocmget(struct tty_struct *tty) | 1026 | static int rfcomm_tty_tiocmget(struct tty_struct *tty) |