]> err.no Git - linux-2.6/blobdiff - net/bluetooth/rfcomm/tty.c
Merge branch 'core/stacktrace' of git://git.kernel.org/pub/scm/linux/kernel/git/tip...
[linux-2.6] / net / bluetooth / rfcomm / tty.c
index e4c779bb8d76e6cf9dfab3b82a3ae33f7276dc68..c9191871c1e0921cf9b096a3fdcad79c28f30309 100644 (file)
@@ -566,14 +566,20 @@ static void rfcomm_dev_state_change(struct rfcomm_dlc *dlc, int err)
        if (dlc->state == BT_CLOSED) {
                if (!dev->tty) {
                        if (test_bit(RFCOMM_RELEASE_ONHUP, &dev->flags)) {
-                               if (rfcomm_dev_get(dev->id) == NULL)
+                               /* Drop DLC lock here to avoid deadlock
+                                * 1. rfcomm_dev_get will take rfcomm_dev_lock
+                                *    but in rfcomm_dev_add there's lock order:
+                                *    rfcomm_dev_lock -> dlc lock
+                                * 2. rfcomm_dev_put will deadlock if it's
+                                *    the last reference
+                                */
+                               rfcomm_dlc_unlock(dlc);
+                               if (rfcomm_dev_get(dev->id) == NULL) {
+                                       rfcomm_dlc_lock(dlc);
                                        return;
+                               }
 
                                rfcomm_dev_del(dev);
-                               /* We have to drop DLC lock here, otherwise
-                                  rfcomm_dev_put() will dead lock if it's
-                                  the last reference. */
-                               rfcomm_dlc_unlock(dlc);
                                rfcomm_dev_put(dev);
                                rfcomm_dlc_lock(dlc);
                        }