diff options
Diffstat (limited to 'net/bluetooth/rfcomm/tty.c')
-rw-r--r-- | net/bluetooth/rfcomm/tty.c | 30 |
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); |