Skip to content

Commit ece3150

Browse files
funnydogGustavo Padovan
authored andcommitted
Bluetooth: Fix the reference counting of tty_port
The tty_port can be released in two cases: when we get a HUP in the functions rfcomm_tty_hangup() and rfcomm_dev_state_change(). Or when the user releases the device in rfcomm_release_dev(). In these cases we set the flag RFCOMM_TTY_RELEASED so that no other function can get a reference to the tty_port. The use of !test_and_set_bit(RFCOMM_TTY_RELEASED) ensures that the 'initial' tty_port reference is only dropped once. The rfcomm_dev_del function is removed becase it isn't used anymore. Signed-off-by: Gianluca Anzolin <[email protected]> Reviewed-by: Peter Hurley <[email protected]> Signed-off-by: Gustavo Padovan <[email protected]>
1 parent cad348a commit ece3150

File tree

1 file changed

+12
-34
lines changed
  • net/bluetooth/rfcomm

1 file changed

+12
-34
lines changed

net/bluetooth/rfcomm/tty.c

Lines changed: 12 additions & 34 deletions
Original file line numberDiff line numberDiff line change
@@ -324,23 +324,6 @@ static int rfcomm_dev_add(struct rfcomm_dev_req *req, struct rfcomm_dlc *dlc)
324324
return err;
325325
}
326326

327-
static void rfcomm_dev_del(struct rfcomm_dev *dev)
328-
{
329-
unsigned long flags;
330-
BT_DBG("dev %p", dev);
331-
332-
BUG_ON(test_and_set_bit(RFCOMM_TTY_RELEASED, &dev->flags));
333-
334-
spin_lock_irqsave(&dev->port.lock, flags);
335-
if (dev->port.count > 0) {
336-
spin_unlock_irqrestore(&dev->port.lock, flags);
337-
return;
338-
}
339-
spin_unlock_irqrestore(&dev->port.lock, flags);
340-
341-
tty_port_put(&dev->port);
342-
}
343-
344327
/* ---- Send buffer ---- */
345328
static inline unsigned int rfcomm_room(struct rfcomm_dlc *dlc)
346329
{
@@ -454,8 +437,9 @@ static int rfcomm_release_dev(void __user *arg)
454437
tty_kref_put(tty);
455438
}
456439

457-
if (!test_bit(RFCOMM_RELEASE_ONHUP, &dev->flags))
458-
rfcomm_dev_del(dev);
440+
if (!test_and_set_bit(RFCOMM_TTY_RELEASED, &dev->flags))
441+
tty_port_put(&dev->port);
442+
459443
tty_port_put(&dev->port);
460444
return 0;
461445
}
@@ -607,14 +591,20 @@ static void rfcomm_dev_state_change(struct rfcomm_dlc *dlc, int err)
607591
* rfcomm_dev_lock -> dlc lock
608592
* 2. tty_port_put will deadlock if it's
609593
* the last reference
594+
*
595+
* FIXME: when we release the lock anything
596+
* could happen to dev, even its destruction
610597
*/
611598
rfcomm_dlc_unlock(dlc);
612599
if (rfcomm_dev_get(dev->id) == NULL) {
613600
rfcomm_dlc_lock(dlc);
614601
return;
615602
}
616603

617-
rfcomm_dev_del(dev);
604+
if (!test_and_set_bit(RFCOMM_TTY_RELEASED,
605+
&dev->flags))
606+
tty_port_put(&dev->port);
607+
618608
tty_port_put(&dev->port);
619609
rfcomm_dlc_lock(dlc);
620610
}
@@ -741,16 +731,10 @@ static void rfcomm_tty_close(struct tty_struct *tty, struct file *filp)
741731
{
742732
struct rfcomm_dev *dev = (struct rfcomm_dev *) tty->driver_data;
743733

744-
if (!dev)
745-
return;
746-
747734
BT_DBG("tty %p dev %p dlc %p opened %d", tty, dev, dev->dlc,
748735
dev->port.count);
749736

750737
tty_port_close(&dev->port, tty, filp);
751-
752-
if (test_bit(RFCOMM_TTY_RELEASED, &dev->flags))
753-
tty_port_put(&dev->port);
754738
}
755739

756740
static int rfcomm_tty_write(struct tty_struct *tty, const unsigned char *buf, int count)
@@ -1050,17 +1034,11 @@ static void rfcomm_tty_hangup(struct tty_struct *tty)
10501034

10511035
BT_DBG("tty %p dev %p", tty, dev);
10521036

1053-
if (!dev)
1054-
return;
1055-
10561037
tty_port_hangup(&dev->port);
10571038

1058-
if (test_bit(RFCOMM_RELEASE_ONHUP, &dev->flags)) {
1059-
if (rfcomm_dev_get(dev->id) == NULL)
1060-
return;
1061-
rfcomm_dev_del(dev);
1039+
if (test_bit(RFCOMM_RELEASE_ONHUP, &dev->flags) &&
1040+
!test_and_set_bit(RFCOMM_TTY_RELEASED, &dev->flags))
10621041
tty_port_put(&dev->port);
1063-
}
10641042
}
10651043

10661044
static int rfcomm_tty_tiocmget(struct tty_struct *tty)

0 commit comments

Comments
 (0)