diff options
author | Marcel Holtmann <marcel@holtmann.org> | 2006-07-12 17:00:07 -0400 |
---|---|---|
committer | David S. Miller <davem@sunset.davemloft.net> | 2006-07-12 18:34:35 -0400 |
commit | fd1278d720b48ad7576f64014b916cc77365cb3f (patch) | |
tree | 5d692235135cbdeac93f10b52084ec72009a8541 /net/bluetooth/l2cap.c | |
parent | 0263603a01e802f79e369ac489793e5320031560 (diff) |
[Bluetooth] Fix deadlock in the L2CAP layer
The Bluetooth L2CAP layer has 2 locks that are used in softirq context,
(one spinlock and one rwlock, where the softirq usage is readlock) but
where not all usages of the lock were _bh safe. The patch below corrects
this.
Signed-off-by: Arjan van de Ven <arjan@linux.intel.com>
Signed-off-by: Ingo Molnar <mingo@elte.hu>
Signed-off-by: Marcel Holtmann <marcel@holtmann.org>
Diffstat (limited to 'net/bluetooth/l2cap.c')
-rw-r--r-- | net/bluetooth/l2cap.c | 18 |
1 files changed, 9 insertions, 9 deletions
diff --git a/net/bluetooth/l2cap.c b/net/bluetooth/l2cap.c index eaaad658d11d..d56f60b392ac 100644 --- a/net/bluetooth/l2cap.c +++ b/net/bluetooth/l2cap.c | |||
@@ -185,7 +185,7 @@ static inline void l2cap_chan_unlink(struct l2cap_chan_list *l, struct sock *sk) | |||
185 | { | 185 | { |
186 | struct sock *next = l2cap_pi(sk)->next_c, *prev = l2cap_pi(sk)->prev_c; | 186 | struct sock *next = l2cap_pi(sk)->next_c, *prev = l2cap_pi(sk)->prev_c; |
187 | 187 | ||
188 | write_lock(&l->lock); | 188 | write_lock_bh(&l->lock); |
189 | if (sk == l->head) | 189 | if (sk == l->head) |
190 | l->head = next; | 190 | l->head = next; |
191 | 191 | ||
@@ -193,7 +193,7 @@ static inline void l2cap_chan_unlink(struct l2cap_chan_list *l, struct sock *sk) | |||
193 | l2cap_pi(next)->prev_c = prev; | 193 | l2cap_pi(next)->prev_c = prev; |
194 | if (prev) | 194 | if (prev) |
195 | l2cap_pi(prev)->next_c = next; | 195 | l2cap_pi(prev)->next_c = next; |
196 | write_unlock(&l->lock); | 196 | write_unlock_bh(&l->lock); |
197 | 197 | ||
198 | __sock_put(sk); | 198 | __sock_put(sk); |
199 | } | 199 | } |
@@ -313,9 +313,9 @@ static void l2cap_conn_del(struct hci_conn *hcon, int err) | |||
313 | static inline void l2cap_chan_add(struct l2cap_conn *conn, struct sock *sk, struct sock *parent) | 313 | static inline void l2cap_chan_add(struct l2cap_conn *conn, struct sock *sk, struct sock *parent) |
314 | { | 314 | { |
315 | struct l2cap_chan_list *l = &conn->chan_list; | 315 | struct l2cap_chan_list *l = &conn->chan_list; |
316 | write_lock(&l->lock); | 316 | write_lock_bh(&l->lock); |
317 | __l2cap_chan_add(conn, sk, parent); | 317 | __l2cap_chan_add(conn, sk, parent); |
318 | write_unlock(&l->lock); | 318 | write_unlock_bh(&l->lock); |
319 | } | 319 | } |
320 | 320 | ||
321 | static inline u8 l2cap_get_ident(struct l2cap_conn *conn) | 321 | static inline u8 l2cap_get_ident(struct l2cap_conn *conn) |
@@ -328,14 +328,14 @@ static inline u8 l2cap_get_ident(struct l2cap_conn *conn) | |||
328 | * 200 - 254 are used by utilities like l2ping, etc. | 328 | * 200 - 254 are used by utilities like l2ping, etc. |
329 | */ | 329 | */ |
330 | 330 | ||
331 | spin_lock(&conn->lock); | 331 | spin_lock_bh(&conn->lock); |
332 | 332 | ||
333 | if (++conn->tx_ident > 128) | 333 | if (++conn->tx_ident > 128) |
334 | conn->tx_ident = 1; | 334 | conn->tx_ident = 1; |
335 | 335 | ||
336 | id = conn->tx_ident; | 336 | id = conn->tx_ident; |
337 | 337 | ||
338 | spin_unlock(&conn->lock); | 338 | spin_unlock_bh(&conn->lock); |
339 | 339 | ||
340 | return id; | 340 | return id; |
341 | } | 341 | } |
@@ -1416,11 +1416,11 @@ static inline int l2cap_connect_req(struct l2cap_conn *conn, struct l2cap_cmd_hd | |||
1416 | if (!sk) | 1416 | if (!sk) |
1417 | goto response; | 1417 | goto response; |
1418 | 1418 | ||
1419 | write_lock(&list->lock); | 1419 | write_lock_bh(&list->lock); |
1420 | 1420 | ||
1421 | /* Check if we already have channel with that dcid */ | 1421 | /* Check if we already have channel with that dcid */ |
1422 | if (__l2cap_get_chan_by_dcid(list, scid)) { | 1422 | if (__l2cap_get_chan_by_dcid(list, scid)) { |
1423 | write_unlock(&list->lock); | 1423 | write_unlock_bh(&list->lock); |
1424 | sock_set_flag(sk, SOCK_ZAPPED); | 1424 | sock_set_flag(sk, SOCK_ZAPPED); |
1425 | l2cap_sock_kill(sk); | 1425 | l2cap_sock_kill(sk); |
1426 | goto response; | 1426 | goto response; |
@@ -1458,7 +1458,7 @@ static inline int l2cap_connect_req(struct l2cap_conn *conn, struct l2cap_cmd_hd | |||
1458 | result = status = 0; | 1458 | result = status = 0; |
1459 | 1459 | ||
1460 | done: | 1460 | done: |
1461 | write_unlock(&list->lock); | 1461 | write_unlock_bh(&list->lock); |
1462 | 1462 | ||
1463 | response: | 1463 | response: |
1464 | bh_unlock_sock(parent); | 1464 | bh_unlock_sock(parent); |