]> git.ipfire.org Git - thirdparty/kernel/stable-queue.git/blob - releases/2.6.25.7/bluetooth-rfcomm_dev_state_change-deadlock-fix.patch
4.14-stable patches
[thirdparty/kernel/stable-queue.git] / releases / 2.6.25.7 / bluetooth-rfcomm_dev_state_change-deadlock-fix.patch
1 From 537d59af73d894750cff14f90fe2b6d77fbab15b Mon Sep 17 00:00:00 2001
2 From: Dave Young <hidave.darkstar@gmail.com>
3 Date: Sun, 1 Jun 2008 23:50:52 -0700
4 Subject: [PATCH] bluetooth: rfcomm_dev_state_change deadlock fix
5
6 From: Dave Young <hidave.darkstar@gmail.com>
7
8 commit 537d59af73d894750cff14f90fe2b6d77fbab15b in mainline
9
10 There's logic in __rfcomm_dlc_close:
11 rfcomm_dlc_lock(d);
12 d->state = BT_CLOSED;
13 d->state_changed(d, err);
14 rfcomm_dlc_unlock(d);
15
16 In rfcomm_dev_state_change, it's possible that rfcomm_dev_put try to
17 take the dlc lock, then we will deadlock.
18
19 Here fixed it by unlock dlc before rfcomm_dev_get in
20 rfcomm_dev_state_change.
21
22 why not unlock just before rfcomm_dev_put? it's because there's
23 another problem. rfcomm_dev_get/rfcomm_dev_del will take
24 rfcomm_dev_lock, but in rfcomm_dev_add the lock order is :
25 rfcomm_dev_lock --> dlc lock
26
27 so I unlock dlc before the taken of rfcomm_dev_lock.
28
29 Actually it's a regression caused by commit
30 1905f6c736cb618e07eca0c96e60e3c024023428 ("bluetooth :
31 __rfcomm_dlc_close lock fix"), the dlc state_change could be two
32 callbacks : rfcomm_sk_state_change and rfcomm_dev_state_change. I
33 missed the rfcomm_sk_state_change that time.
34
35 Thanks Arjan van de Ven <arjan@linux.intel.com> for the effort in
36 commit 4c8411f8c115def968820a4df6658ccfd55d7f1a ("bluetooth: fix
37 locking bug in the rfcomm socket cleanup handling") but he missed the
38 rfcomm_dev_state_change lock issue.
39
40 Signed-off-by: Dave Young <hidave.darkstar@gmail.com>
41 Acked-by: Marcel Holtmann <marcel@holtmann.org>
42 Signed-off-by: David S. Miller <davem@davemloft.net>
43 Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
44
45 ---
46 net/bluetooth/rfcomm/tty.c | 13 ++++++++++++-
47 1 file changed, 12 insertions(+), 1 deletion(-)
48
49 --- a/net/bluetooth/rfcomm/tty.c
50 +++ b/net/bluetooth/rfcomm/tty.c
51 @@ -566,11 +566,22 @@ static void rfcomm_dev_state_change(stru
52 if (dlc->state == BT_CLOSED) {
53 if (!dev->tty) {
54 if (test_bit(RFCOMM_RELEASE_ONHUP, &dev->flags)) {
55 - if (rfcomm_dev_get(dev->id) == NULL)
56 + /* Drop DLC lock here to avoid deadlock
57 + * 1. rfcomm_dev_get will take rfcomm_dev_lock
58 + * but in rfcomm_dev_add there's lock order:
59 + * rfcomm_dev_lock -> dlc lock
60 + * 2. rfcomm_dev_put will deadlock if it's
61 + * the last reference
62 + */
63 + rfcomm_dlc_unlock(dlc);
64 + if (rfcomm_dev_get(dev->id) == NULL) {
65 + rfcomm_dlc_lock(dlc);
66 return;
67 + }
68
69 rfcomm_dev_del(dev);
70 rfcomm_dev_put(dev);
71 + rfcomm_dlc_lock(dlc);
72 }
73 } else
74 tty_hangup(dev->tty);