aboutsummaryrefslogtreecommitdiffstats
path: root/net/bluetooth/rfcomm/tty.c
diff options
context:
space:
mode:
Diffstat (limited to 'net/bluetooth/rfcomm/tty.c')
-rw-r--r--net/bluetooth/rfcomm/tty.c30
1 files changed, 21 insertions, 9 deletions
diff --git a/net/bluetooth/rfcomm/tty.c b/net/bluetooth/rfcomm/tty.c
index 1e4100bb0b65..111c6c858247 100644
--- a/net/bluetooth/rfcomm/tty.c
+++ b/net/bluetooth/rfcomm/tty.c
@@ -53,7 +53,7 @@ struct rfcomm_dev {
53 char name[12]; 53 char name[12];
54 int id; 54 int id;
55 unsigned long flags; 55 unsigned long flags;
56 int opened; 56 atomic_t opened;
57 int err; 57 int err;
58 58
59 bdaddr_t src; 59 bdaddr_t src;
@@ -256,6 +256,8 @@ static int rfcomm_dev_add(struct rfcomm_dev_req *req, struct rfcomm_dlc *dlc)
256 dev->flags = req->flags & 256 dev->flags = req->flags &
257 ((1 << RFCOMM_RELEASE_ONHUP) | (1 << RFCOMM_REUSE_DLC)); 257 ((1 << RFCOMM_RELEASE_ONHUP) | (1 << RFCOMM_REUSE_DLC));
258 258
259 atomic_set(&dev->opened, 0);
260
259 init_waitqueue_head(&dev->wait); 261 init_waitqueue_head(&dev->wait);
260 tasklet_init(&dev->wakeup_task, rfcomm_tty_wakeup, (unsigned long) dev); 262 tasklet_init(&dev->wakeup_task, rfcomm_tty_wakeup, (unsigned long) dev);
261 263
@@ -325,10 +327,10 @@ static void rfcomm_dev_del(struct rfcomm_dev *dev)
325{ 327{
326 BT_DBG("dev %p", dev); 328 BT_DBG("dev %p", dev);
327 329
328 if (test_bit(RFCOMM_TTY_RELEASED, &dev->flags)) 330 BUG_ON(test_and_set_bit(RFCOMM_TTY_RELEASED, &dev->flags));
329 BUG_ON(1); 331
330 else 332 if (atomic_read(&dev->opened) > 0)
331 set_bit(RFCOMM_TTY_RELEASED, &dev->flags); 333 return;
332 334
333 write_lock_bh(&rfcomm_dev_lock); 335 write_lock_bh(&rfcomm_dev_lock);
334 list_del_init(&dev->list); 336 list_del_init(&dev->list);
@@ -684,9 +686,10 @@ static int rfcomm_tty_open(struct tty_struct *tty, struct file *filp)
684 if (!dev) 686 if (!dev)
685 return -ENODEV; 687 return -ENODEV;
686 688
687 BT_DBG("dev %p dst %s channel %d opened %d", dev, batostr(&dev->dst), dev->channel, dev->opened); 689 BT_DBG("dev %p dst %s channel %d opened %d", dev, batostr(&dev->dst),
690 dev->channel, atomic_read(&dev->opened));
688 691
689 if (dev->opened++ != 0) 692 if (atomic_inc_return(&dev->opened) > 1)
690 return 0; 693 return 0;
691 694
692 dlc = dev->dlc; 695 dlc = dev->dlc;
@@ -742,9 +745,10 @@ static void rfcomm_tty_close(struct tty_struct *tty, struct file *filp)
742 if (!dev) 745 if (!dev)
743 return; 746 return;
744 747
745 BT_DBG("tty %p dev %p dlc %p opened %d", tty, dev, dev->dlc, dev->opened); 748 BT_DBG("tty %p dev %p dlc %p opened %d", tty, dev, dev->dlc,
749 atomic_read(&dev->opened));
746 750
747 if (--dev->opened == 0) { 751 if (atomic_dec_and_test(&dev->opened)) {
748 if (dev->tty_dev->parent) 752 if (dev->tty_dev->parent)
749 device_move(dev->tty_dev, NULL); 753 device_move(dev->tty_dev, NULL);
750 754
@@ -758,6 +762,14 @@ static void rfcomm_tty_close(struct tty_struct *tty, struct file *filp)
758 tty->driver_data = NULL; 762 tty->driver_data = NULL;
759 dev->tty = NULL; 763 dev->tty = NULL;
760 rfcomm_dlc_unlock(dev->dlc); 764 rfcomm_dlc_unlock(dev->dlc);
765
766 if (test_bit(RFCOMM_TTY_RELEASED, &dev->flags)) {
767 write_lock_bh(&rfcomm_dev_lock);
768 list_del_init(&dev->list);
769 write_unlock_bh(&rfcomm_dev_lock);
770
771 rfcomm_dev_put(dev);
772 }
761 } 773 }
762 774
763 rfcomm_dev_put(dev); 775 rfcomm_dev_put(dev);