X-Git-Url: https://err.no/cgi-bin/gitweb.cgi?a=blobdiff_plain;f=net%2Fbluetooth%2Frfcomm%2Ftty.c;h=c9191871c1e0921cf9b096a3fdcad79c28f30309;hb=af5329cdf51cdd208a323e521faa46800a16d2ec;hp=e4c779bb8d76e6cf9dfab3b82a3ae33f7276dc68;hpb=4f4ae0d42680889c62db4e1f3e6b4aa7787a7257;p=linux-2.6 diff --git a/net/bluetooth/rfcomm/tty.c b/net/bluetooth/rfcomm/tty.c index e4c779bb8d..c9191871c1 100644 --- a/net/bluetooth/rfcomm/tty.c +++ b/net/bluetooth/rfcomm/tty.c @@ -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); }