|
@@ -566,11 +566,22 @@ 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);
|
|
|
rfcomm_dev_put(dev);
|
|
|
+ rfcomm_dlc_lock(dlc);
|
|
|
}
|
|
|
} else
|
|
|
tty_hangup(dev->tty);
|