On Thu, May 20, 2010 at 5:13 PM, Andrei Emeltchenko <andrei.emeltchenko.news@xxxxxxxxx> wrote: > Hi All, > > I have done second experimental version of the patch. > > Main difference is that when sk is owned by user I do not run > "l2cap_chan_del" example below: > > + /* don't delete l2cap channel if sk is owned by user */ > + if (sock_owned_by_user(sk)) { > + sk->sk_state = BT_DISCONN; > + l2cap_sock_clear_timer(sk); > + l2cap_sock_set_timer(sk, HZ); > + bh_unlock_sock(sk); > + return 0; > + } > > I start timer which will run this function. I do also the same check > in timer context. > > + if (sock_owned_by_user(sk)) { > + /* sk is owned by user. Try again later */ > + l2cap_sock_set_timer(sk, HZ * 2); > + bh_unlock_sock(sk); > + sock_put(sk); > + return; > + } Little modification to the second patch attached. -- Regards, Andrei
From 99f3c96b432c2732dce8d84155a8be346e633a56 Mon Sep 17 00:00:00 2001 From: Andrei Emeltchenko <andrei.emeltchenko@xxxxxxxxx> Date: Thu, 20 May 2010 16:52:19 +0300 Subject: [PATCHv2 2/2] Bluetooth: timer check sk is not owned before freeing In timer context we might delete l2cap channel used by krfcommd. The check makes sure that sk is not owned. Signed-off-by: Andrei Emeltchenko <andrei.emeltchenko@xxxxxxxxx> --- net/bluetooth/l2cap.c | 32 ++++++++++++++++++++------------ 1 files changed, 20 insertions(+), 12 deletions(-) diff --git a/net/bluetooth/l2cap.c b/net/bluetooth/l2cap.c index 11060d6..1a6c5bb 100644 --- a/net/bluetooth/l2cap.c +++ b/net/bluetooth/l2cap.c @@ -84,6 +84,18 @@ static struct sk_buff *l2cap_build_cmd(struct l2cap_conn *conn, u8 code, u8 ident, u16 dlen, void *data); /* ---- L2CAP timers ---- */ +static void l2cap_sock_set_timer(struct sock *sk, long timeout) +{ + BT_DBG("sk %p state %d timeout %ld", sk, sk->sk_state, timeout); + sk_reset_timer(sk, &sk->sk_timer, jiffies + timeout); +} + +static void l2cap_sock_clear_timer(struct sock *sk) +{ + BT_DBG("sock %p state %d", sk, sk->sk_state); + sk_stop_timer(sk, &sk->sk_timer); +} + static void l2cap_sock_timeout(unsigned long arg) { struct sock *sk = (struct sock *) arg; @@ -93,6 +105,14 @@ static void l2cap_sock_timeout(unsigned long arg) bh_lock_sock(sk); + if (sock_owned_by_user(sk)) { + /* sk is owned by user. Try again later */ + l2cap_sock_set_timer(sk, HZ * 2); + bh_unlock_sock(sk); + sock_put(sk); + return; + } + if (sk->sk_state == BT_CONNECTED || sk->sk_state == BT_CONFIG) reason = ECONNREFUSED; else if (sk->sk_state == BT_CONNECT && @@ -109,18 +129,6 @@ static void l2cap_sock_timeout(unsigned long arg) sock_put(sk); } -static void l2cap_sock_set_timer(struct sock *sk, long timeout) -{ - BT_DBG("sk %p state %d timeout %ld", sk, sk->sk_state, timeout); - sk_reset_timer(sk, &sk->sk_timer, jiffies + timeout); -} - -static void l2cap_sock_clear_timer(struct sock *sk) -{ - BT_DBG("sock %p state %d", sk, sk->sk_state); - sk_stop_timer(sk, &sk->sk_timer); -} - /* ---- L2CAP channels ---- */ static struct sock *__l2cap_get_chan_by_dcid(struct l2cap_chan_list *l, u16 cid) { -- 1.7.0.4