| From stable-bounces@linux.kernel.org Wed Jun 6 23:02:20 2007 |
| Date: Wed, 06 Jun 2007 23:02:16 -0700 (PDT) |
| Message-Id: <20070606.230216.42775266.davem@davemloft.net> |
| To: stable@kernel.org |
| From: David Miller <davem@davemloft.net> |
| Cc: bunk@stusta.de |
| Subject: BLUETOOTH: Fix locking in hci_sock_dev_event(). |
| |
| From: Satyam Sharma <ssatyam@cse.iitk.ac.in> |
| |
| We presently use lock_sock() to acquire a lock on a socket in |
| hci_sock_dev_event(), but this goes BUG because lock_sock() |
| can sleep and we're already holding a read-write spinlock at |
| that point. So, we must use the non-sleeping BH version, |
| bh_lock_sock(). |
| |
| However, hci_sock_dev_event() is called from user context and |
| hence using simply bh_lock_sock() will deadlock against a |
| concurrent softirq that tries to acquire a lock on the same |
| socket. Hence, disabling BH's before acquiring the socket lock |
| and enable them afterwards, is the proper solution to fix |
| socket locking in hci_sock_dev_event(). |
| |
| Signed-off-by: Satyam Sharma <ssatyam@cse.iitk.ac.in> |
| Signed-off-by: Marcel Holtmann <marcel@holtmann.org> |
| Signed-off-by: Jiri Kosina <jkosina@suse.cz> |
| Signed-off-by: David S. Miller <davem@davemloft.net> |
| Signed-off-by: Chris Wright <chrisw@sous-sol.org> |
| Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de> |
| --- |
| net/bluetooth/hci_sock.c | 6 ++++-- |
| 1 file changed, 4 insertions(+), 2 deletions(-) |
| |
| --- linux-2.6.21.4.orig/net/bluetooth/hci_sock.c |
| +++ linux-2.6.21.4/net/bluetooth/hci_sock.c |
| @@ -656,7 +656,8 @@ static int hci_sock_dev_event(struct not |
| /* Detach sockets from device */ |
| read_lock(&hci_sk_list.lock); |
| sk_for_each(sk, node, &hci_sk_list.head) { |
| - lock_sock(sk); |
| + local_bh_disable(); |
| + bh_lock_sock_nested(sk); |
| if (hci_pi(sk)->hdev == hdev) { |
| hci_pi(sk)->hdev = NULL; |
| sk->sk_err = EPIPE; |
| @@ -665,7 +666,8 @@ static int hci_sock_dev_event(struct not |
| |
| hci_dev_put(hdev); |
| } |
| - release_sock(sk); |
| + bh_unlock_sock(sk); |
| + local_bh_enable(); |
| } |
| read_unlock(&hci_sk_list.lock); |
| } |