From e793dcf082c847bd2b742c781252c20cbec37986 Mon Sep 17 00:00:00 2001 From: Johan Hedberg Date: Mon, 16 Sep 2013 13:05:19 +0300 Subject: Bluetooth: Fix waiting for clearing of BT_SK_SUSPEND flag In the case of blocking sockets we should not proceed with sendmsg() if the socket has the BT_SK_SUSPEND flag set. So far the code was only ensuring that POLLOUT doesn't get set for non-blocking sockets using poll() but there was no code in place to ensure that blocking sockets do the right thing when writing to them. This patch adds a new bt_sock_wait_ready helper function to sleep in the sendmsg call if the BT_SK_SUSPEND flag is set, and wake up as soon as it is unset. It also updates the L2CAP and RFCOMM sendmsg callbacks to take advantage of this new helper function. Signed-off-by: Johan Hedberg Acked-by: Marcel Holtmann Signed-off-by: Gustavo Padovan --- net/bluetooth/af_bluetooth.c | 40 ++++++++++++++++++++++++++++++++++++++++ 1 file changed, 40 insertions(+) (limited to 'net/bluetooth/af_bluetooth.c') diff --git a/net/bluetooth/af_bluetooth.c b/net/bluetooth/af_bluetooth.c index 9096137c889c..c600631cd19e 100644 --- a/net/bluetooth/af_bluetooth.c +++ b/net/bluetooth/af_bluetooth.c @@ -525,6 +525,46 @@ int bt_sock_wait_state(struct sock *sk, int state, unsigned long timeo) } EXPORT_SYMBOL(bt_sock_wait_state); +/* This function expects the sk lock to be held when called */ +int bt_sock_wait_ready(struct sock *sk, unsigned long flags) +{ + DECLARE_WAITQUEUE(wait, current); + unsigned long timeo; + int err = 0; + + BT_DBG("sk %p", sk); + + timeo = sock_sndtimeo(sk, flags & O_NONBLOCK); + + add_wait_queue(sk_sleep(sk), &wait); + set_current_state(TASK_INTERRUPTIBLE); + while (test_bit(BT_SK_SUSPEND, &bt_sk(sk)->flags)) { + if (!timeo) { + err = -EAGAIN; + break; + } + + if (signal_pending(current)) { + err = sock_intr_errno(timeo); + break; + } + + release_sock(sk); + timeo = schedule_timeout(timeo); + lock_sock(sk); + set_current_state(TASK_INTERRUPTIBLE); + + err = sock_error(sk); + if (err) + break; + } + __set_current_state(TASK_RUNNING); + remove_wait_queue(sk_sleep(sk), &wait); + + return err; +} +EXPORT_SYMBOL(bt_sock_wait_ready); + #ifdef CONFIG_PROC_FS struct bt_seq_state { struct bt_sock_list *l; -- cgit