diff options
author | Gianluca Anzolin <gianluca@sottospazio.it> | 2013-08-27 12:28:46 -0400 |
---|---|---|
committer | Gustavo Padovan <gustavo.padovan@collabora.co.uk> | 2013-09-20 15:17:54 -0400 |
commit | 29cd718beba999bda4bdbbf59b5a4d25c07e1547 (patch) | |
tree | 7178b36b8086d21b09dd3d21b281eb5770753c63 /net/bluetooth | |
parent | bf5430360ebe4b2d0c51d91f782e649107b502eb (diff) |
Bluetooth: don't release the port in rfcomm_dev_state_change()
When the dlc is closed, rfcomm_dev_state_change() tries to release the
port in the case it cannot get a reference to the tty. However this is
racy and not even needed.
Infact as Peter Hurley points out:
1. Only consider dlcs that are 'stolen' from a connected socket, ie.
reused. Allocated dlcs cannot have been closed prior to port
activate and so for these dlcs a tty reference will always be avail
in rfcomm_dev_state_change() -- except for the conditions covered by
#2b below.
2. If a tty was at some point previously created for this rfcomm, then
either
(a) the tty reference is still avail, so rfcomm_dev_state_change()
will perform a hangup. So nothing to do, or,
(b) the tty reference is no longer avail, and the tty_port will be
destroyed by the last tty_port_put() in rfcomm_tty_cleanup.
Again, no action required.
3. Prior to obtaining the dlc lock in rfcomm_dev_add(),
rfcomm_dev_state_change() will not 'see' a rfcomm_dev so nothing to
do here.
4. After releasing the dlc lock in rfcomm_dev_add(),
rfcomm_dev_state_change() will 'see' an incomplete rfcomm_dev if a
tty reference could not be obtained. Again, the best thing to do here
is nothing. Any future attempted open() will block on
rfcomm_dev_carrier_raised(). The unconnected device will exist until
released by ioctl(RFCOMMRELEASEDEV).
The patch removes the aforementioned code and uses the
tty_port_tty_hangup() helper to hangup the tty.
Signed-off-by: Gianluca Anzolin <gianluca@sottospazio.it>
Reviewed-by: Peter Hurley <peter@hurleysoftware.com>
Signed-off-by: Gustavo Padovan <gustavo.padovan@collabora.co.uk>
Diffstat (limited to 'net/bluetooth')
-rw-r--r-- | net/bluetooth/rfcomm/tty.c | 35 |
1 files changed, 2 insertions, 33 deletions
diff --git a/net/bluetooth/rfcomm/tty.c b/net/bluetooth/rfcomm/tty.c index 6d126faf145f..84fcf9fff3ea 100644 --- a/net/bluetooth/rfcomm/tty.c +++ b/net/bluetooth/rfcomm/tty.c | |||
@@ -569,7 +569,6 @@ static void rfcomm_dev_data_ready(struct rfcomm_dlc *dlc, struct sk_buff *skb) | |||
569 | static void rfcomm_dev_state_change(struct rfcomm_dlc *dlc, int err) | 569 | static void rfcomm_dev_state_change(struct rfcomm_dlc *dlc, int err) |
570 | { | 570 | { |
571 | struct rfcomm_dev *dev = dlc->owner; | 571 | struct rfcomm_dev *dev = dlc->owner; |
572 | struct tty_struct *tty; | ||
573 | if (!dev) | 572 | if (!dev) |
574 | return; | 573 | return; |
575 | 574 | ||
@@ -581,38 +580,8 @@ static void rfcomm_dev_state_change(struct rfcomm_dlc *dlc, int err) | |||
581 | DPM_ORDER_DEV_AFTER_PARENT); | 580 | DPM_ORDER_DEV_AFTER_PARENT); |
582 | 581 | ||
583 | wake_up_interruptible(&dev->port.open_wait); | 582 | wake_up_interruptible(&dev->port.open_wait); |
584 | } else if (dlc->state == BT_CLOSED) { | 583 | } else if (dlc->state == BT_CLOSED) |
585 | tty = tty_port_tty_get(&dev->port); | 584 | tty_port_tty_hangup(&dev->port, false); |
586 | if (!tty) { | ||
587 | if (test_bit(RFCOMM_RELEASE_ONHUP, &dev->flags)) { | ||
588 | /* Drop DLC lock here to avoid deadlock | ||
589 | * 1. rfcomm_dev_get will take rfcomm_dev_lock | ||
590 | * but in rfcomm_dev_add there's lock order: | ||
591 | * rfcomm_dev_lock -> dlc lock | ||
592 | * 2. tty_port_put will deadlock if it's | ||
593 | * the last reference | ||
594 | * | ||
595 | * FIXME: when we release the lock anything | ||
596 | * could happen to dev, even its destruction | ||
597 | */ | ||
598 | rfcomm_dlc_unlock(dlc); | ||
599 | if (rfcomm_dev_get(dev->id) == NULL) { | ||
600 | rfcomm_dlc_lock(dlc); | ||
601 | return; | ||
602 | } | ||
603 | |||
604 | if (!test_and_set_bit(RFCOMM_TTY_RELEASED, | ||
605 | &dev->flags)) | ||
606 | tty_port_put(&dev->port); | ||
607 | |||
608 | tty_port_put(&dev->port); | ||
609 | rfcomm_dlc_lock(dlc); | ||
610 | } | ||
611 | } else { | ||
612 | tty_hangup(tty); | ||
613 | tty_kref_put(tty); | ||
614 | } | ||
615 | } | ||
616 | } | 585 | } |
617 | 586 | ||
618 | static void rfcomm_dev_modem_status(struct rfcomm_dlc *dlc, u8 v24_sig) | 587 | static void rfcomm_dev_modem_status(struct rfcomm_dlc *dlc, u8 v24_sig) |