Bluetooth: Remove the device from the list in the destructor
authorGianluca Anzolin <gianluca@sottospazio.it>
Mon, 29 Jul 2013 15:08:09 +0000 (17:08 +0200)
committerGustavo Padovan <gustavo.padovan@collabora.co.uk>
Wed, 21 Aug 2013 14:47:06 +0000 (16:47 +0200)
The current code removes the device from the device list in several
places. Do it only in the destructor instead and in the error path of
rfcomm_add_dev() if the device couldn't be initialized.

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>
net/bluetooth/rfcomm/tty.c

index cd7ff370be3877cfc17425d6b290bf18dc832a1d..9c0e142041bdc5ef7de97d572d1af70ef5b21d36 100644 (file)
@@ -76,13 +76,6 @@ static void rfcomm_dev_modem_status(struct rfcomm_dlc *dlc, u8 v24_sig);
 
 /* ---- Device functions ---- */
 
-/*
- * The reason this isn't actually a race, as you no doubt have a little voice
- * screaming at you in your head, is that the refcount should never actually
- * reach zero unless the device has already been taken off the list, in
- * rfcomm_dev_del(). And if that's not true, we'll hit the BUG() in
- * rfcomm_dev_destruct() anyway.
- */
 static void rfcomm_dev_destruct(struct tty_port *port)
 {
        struct rfcomm_dev *dev = container_of(port, struct rfcomm_dev, port);
@@ -90,10 +83,9 @@ static void rfcomm_dev_destruct(struct tty_port *port)
 
        BT_DBG("dev %p dlc %p", dev, dlc);
 
-       /* Refcount should only hit zero when called from rfcomm_dev_del()
-          which will have taken us off the list. Everything else are
-          refcounting bugs. */
-       BUG_ON(!list_empty(&dev->list));
+       spin_lock(&rfcomm_dev_lock);
+       list_del(&dev->list);
+       spin_unlock(&rfcomm_dev_lock);
 
        rfcomm_dlc_lock(dlc);
        /* Detach DLC if it's owned by this dev */
@@ -282,7 +274,9 @@ out:
                        dev->id, NULL);
        if (IS_ERR(dev->tty_dev)) {
                err = PTR_ERR(dev->tty_dev);
+               spin_lock(&rfcomm_dev_lock);
                list_del(&dev->list);
+               spin_unlock(&rfcomm_dev_lock);
                goto free;
        }
 
@@ -315,10 +309,6 @@ static void rfcomm_dev_del(struct rfcomm_dev *dev)
        }
        spin_unlock_irqrestore(&dev->port.lock, flags);
 
-       spin_lock(&rfcomm_dev_lock);
-       list_del_init(&dev->list);
-       spin_unlock(&rfcomm_dev_lock);
-
        tty_port_put(&dev->port);
 }
 
@@ -750,13 +740,8 @@ static void rfcomm_tty_close(struct tty_struct *tty, struct file *filp)
                dev->port.tty = NULL;
                rfcomm_dlc_unlock(dev->dlc);
 
-               if (test_bit(RFCOMM_TTY_RELEASED, &dev->flags)) {
-                       spin_lock(&rfcomm_dev_lock);
-                       list_del_init(&dev->list);
-                       spin_unlock(&rfcomm_dev_lock);
-
+               if (test_bit(RFCOMM_TTY_RELEASED, &dev->flags))
                        tty_port_put(&dev->port);
-               }
        } else
                spin_unlock_irqrestore(&dev->port.lock, flags);