Commit 721c4181 authored by Gustavo F. Padovan's avatar Gustavo F. Padovan

Bluetooth: Move L2CAP timers to workqueue

L2CAP timers also need to run in process context. As the works in l2cap
are small we are using the system worqueue.
Acked-by: default avatarMarcel Holtmann <marcel@holtmann.org>
Signed-off-by: default avatarGustavo F. Padovan <padovan@profusion.mobi>
parent b9cc553f
...@@ -482,10 +482,11 @@ struct l2cap_chan { ...@@ -482,10 +482,11 @@ struct l2cap_chan {
__u32 remote_acc_lat; __u32 remote_acc_lat;
__u32 remote_flush_to; __u32 remote_flush_to;
struct timer_list chan_timer; struct delayed_work chan_timer;
struct timer_list retrans_timer; struct delayed_work retrans_timer;
struct timer_list monitor_timer; struct delayed_work monitor_timer;
struct timer_list ack_timer; struct delayed_work ack_timer;
struct sk_buff *tx_send_head; struct sk_buff *tx_send_head;
struct sk_buff_head tx_q; struct sk_buff_head tx_q;
struct sk_buff_head srej_q; struct sk_buff_head srej_q;
...@@ -595,16 +596,16 @@ enum { ...@@ -595,16 +596,16 @@ enum {
}; };
#define __set_chan_timer(c, t) l2cap_set_timer(c, &c->chan_timer, (t)) #define __set_chan_timer(c, t) l2cap_set_timer(c, &c->chan_timer, (t))
#define __clear_chan_timer(c) l2cap_clear_timer(c, &c->chan_timer) #define __clear_chan_timer(c) l2cap_clear_timer(&c->chan_timer)
#define __set_retrans_timer(c) l2cap_set_timer(c, &c->retrans_timer, \ #define __set_retrans_timer(c) l2cap_set_timer(c, &c->retrans_timer, \
L2CAP_DEFAULT_RETRANS_TO); L2CAP_DEFAULT_RETRANS_TO);
#define __clear_retrans_timer(c) l2cap_clear_timer(c, &c->retrans_timer) #define __clear_retrans_timer(c) l2cap_clear_timer(&c->retrans_timer)
#define __set_monitor_timer(c) l2cap_set_timer(c, &c->monitor_timer, \ #define __set_monitor_timer(c) l2cap_set_timer(c, &c->monitor_timer, \
L2CAP_DEFAULT_MONITOR_TO); L2CAP_DEFAULT_MONITOR_TO);
#define __clear_monitor_timer(c) l2cap_clear_timer(c, &c->monitor_timer) #define __clear_monitor_timer(c) l2cap_clear_timer(&c->monitor_timer)
#define __set_ack_timer(c) l2cap_set_timer(c, &chan->ack_timer, \ #define __set_ack_timer(c) l2cap_set_timer(c, &chan->ack_timer, \
L2CAP_DEFAULT_ACK_TO); L2CAP_DEFAULT_ACK_TO);
#define __clear_ack_timer(c) l2cap_clear_timer(c, &c->ack_timer) #define __clear_ack_timer(c) l2cap_clear_timer(&c->ack_timer)
static inline int __seq_offset(struct l2cap_chan *chan, __u16 seq1, __u16 seq2) static inline int __seq_offset(struct l2cap_chan *chan, __u16 seq1, __u16 seq2)
{ {
......
...@@ -213,20 +213,18 @@ static u16 l2cap_alloc_cid(struct l2cap_conn *conn) ...@@ -213,20 +213,18 @@ static u16 l2cap_alloc_cid(struct l2cap_conn *conn)
return 0; return 0;
} }
static void l2cap_set_timer(struct l2cap_chan *chan, struct timer_list *timer, long timeout) static void l2cap_set_timer(struct l2cap_chan *chan, struct delayed_work *work, long timeout)
{ {
BT_DBG("chan %p state %d timeout %ld", chan, chan->state, timeout); BT_DBG("chan %p state %d timeout %ld", chan, chan->state, timeout);
if (!mod_timer(timer, jiffies + msecs_to_jiffies(timeout))) cancel_delayed_work_sync(work);
chan_hold(chan);
schedule_delayed_work(work, timeout);
} }
static void l2cap_clear_timer(struct l2cap_chan *chan, struct timer_list *timer) static void l2cap_clear_timer(struct delayed_work *work)
{ {
BT_DBG("chan %p state %d", chan, chan->state); cancel_delayed_work_sync(work);
if (timer_pending(timer) && del_timer(timer))
chan_put(chan);
} }
static char *state_to_string(int state) static char *state_to_string(int state)
...@@ -264,23 +262,16 @@ static void l2cap_state_change(struct l2cap_chan *chan, int state) ...@@ -264,23 +262,16 @@ static void l2cap_state_change(struct l2cap_chan *chan, int state)
chan->ops->state_change(chan->data, state); chan->ops->state_change(chan->data, state);
} }
static void l2cap_chan_timeout(unsigned long arg) static void l2cap_chan_timeout(struct work_struct *work)
{ {
struct l2cap_chan *chan = (struct l2cap_chan *) arg; struct l2cap_chan *chan = container_of(work, struct l2cap_chan,
chan_timer.work);
struct sock *sk = chan->sk; struct sock *sk = chan->sk;
int reason; int reason;
BT_DBG("chan %p state %d", chan, chan->state); BT_DBG("chan %p state %d", chan, chan->state);
bh_lock_sock(sk); lock_sock(sk);
if (sock_owned_by_user(sk)) {
/* sk is owned by user. Try again later */
__set_chan_timer(chan, L2CAP_DISC_TIMEOUT);
bh_unlock_sock(sk);
chan_put(chan);
return;
}
if (chan->state == BT_CONNECTED || chan->state == BT_CONFIG) if (chan->state == BT_CONNECTED || chan->state == BT_CONFIG)
reason = ECONNREFUSED; reason = ECONNREFUSED;
...@@ -292,7 +283,7 @@ static void l2cap_chan_timeout(unsigned long arg) ...@@ -292,7 +283,7 @@ static void l2cap_chan_timeout(unsigned long arg)
l2cap_chan_close(chan, reason); l2cap_chan_close(chan, reason);
bh_unlock_sock(sk); release_sock(sk);
chan->ops->close(chan->data); chan->ops->close(chan->data);
chan_put(chan); chan_put(chan);
...@@ -312,7 +303,7 @@ struct l2cap_chan *l2cap_chan_create(struct sock *sk) ...@@ -312,7 +303,7 @@ struct l2cap_chan *l2cap_chan_create(struct sock *sk)
list_add(&chan->global_l, &chan_list); list_add(&chan->global_l, &chan_list);
write_unlock_bh(&chan_list_lock); write_unlock_bh(&chan_list_lock);
setup_timer(&chan->chan_timer, l2cap_chan_timeout, (unsigned long) chan); INIT_DELAYED_WORK(&chan->chan_timer, l2cap_chan_timeout);
chan->state = BT_OPEN; chan->state = BT_OPEN;
...@@ -1251,17 +1242,18 @@ int __l2cap_wait_ack(struct sock *sk) ...@@ -1251,17 +1242,18 @@ int __l2cap_wait_ack(struct sock *sk)
return err; return err;
} }
static void l2cap_monitor_timeout(unsigned long arg) static void l2cap_monitor_timeout(struct work_struct *work)
{ {
struct l2cap_chan *chan = (void *) arg; struct l2cap_chan *chan = container_of(work, struct l2cap_chan,
monitor_timer.work);
struct sock *sk = chan->sk; struct sock *sk = chan->sk;
BT_DBG("chan %p", chan); BT_DBG("chan %p", chan);
bh_lock_sock(sk); lock_sock(sk);
if (chan->retry_count >= chan->remote_max_tx) { if (chan->retry_count >= chan->remote_max_tx) {
l2cap_send_disconn_req(chan->conn, chan, ECONNABORTED); l2cap_send_disconn_req(chan->conn, chan, ECONNABORTED);
bh_unlock_sock(sk); release_sock(sk);
return; return;
} }
...@@ -1269,24 +1261,25 @@ static void l2cap_monitor_timeout(unsigned long arg) ...@@ -1269,24 +1261,25 @@ static void l2cap_monitor_timeout(unsigned long arg)
__set_monitor_timer(chan); __set_monitor_timer(chan);
l2cap_send_rr_or_rnr(chan, L2CAP_CTRL_POLL); l2cap_send_rr_or_rnr(chan, L2CAP_CTRL_POLL);
bh_unlock_sock(sk); release_sock(sk);
} }
static void l2cap_retrans_timeout(unsigned long arg) static void l2cap_retrans_timeout(struct work_struct *work)
{ {
struct l2cap_chan *chan = (void *) arg; struct l2cap_chan *chan = container_of(work, struct l2cap_chan,
retrans_timer.work);
struct sock *sk = chan->sk; struct sock *sk = chan->sk;
BT_DBG("chan %p", chan); BT_DBG("chan %p", chan);
bh_lock_sock(sk); lock_sock(sk);
chan->retry_count = 1; chan->retry_count = 1;
__set_monitor_timer(chan); __set_monitor_timer(chan);
set_bit(CONN_WAIT_F, &chan->conn_state); set_bit(CONN_WAIT_F, &chan->conn_state);
l2cap_send_rr_or_rnr(chan, L2CAP_CTRL_POLL); l2cap_send_rr_or_rnr(chan, L2CAP_CTRL_POLL);
bh_unlock_sock(sk); release_sock(sk);
} }
static void l2cap_drop_acked_frames(struct l2cap_chan *chan) static void l2cap_drop_acked_frames(struct l2cap_chan *chan)
...@@ -1955,13 +1948,14 @@ static void l2cap_add_opt_efs(void **ptr, struct l2cap_chan *chan) ...@@ -1955,13 +1948,14 @@ static void l2cap_add_opt_efs(void **ptr, struct l2cap_chan *chan)
(unsigned long) &efs); (unsigned long) &efs);
} }
static void l2cap_ack_timeout(unsigned long arg) static void l2cap_ack_timeout(struct work_struct *work)
{ {
struct l2cap_chan *chan = (void *) arg; struct l2cap_chan *chan = container_of(work, struct l2cap_chan,
ack_timer.work);
bh_lock_sock(chan->sk); lock_sock(chan->sk);
l2cap_send_ack(chan); l2cap_send_ack(chan);
bh_unlock_sock(chan->sk); release_sock(chan->sk);
} }
static inline void l2cap_ertm_init(struct l2cap_chan *chan) static inline void l2cap_ertm_init(struct l2cap_chan *chan)
...@@ -1974,11 +1968,9 @@ static inline void l2cap_ertm_init(struct l2cap_chan *chan) ...@@ -1974,11 +1968,9 @@ static inline void l2cap_ertm_init(struct l2cap_chan *chan)
chan->num_acked = 0; chan->num_acked = 0;
chan->frames_sent = 0; chan->frames_sent = 0;
setup_timer(&chan->retrans_timer, l2cap_retrans_timeout, INIT_DELAYED_WORK(&chan->retrans_timer, l2cap_retrans_timeout);
(unsigned long) chan); INIT_DELAYED_WORK(&chan->monitor_timer, l2cap_monitor_timeout);
setup_timer(&chan->monitor_timer, l2cap_monitor_timeout, INIT_DELAYED_WORK(&chan->ack_timer, l2cap_ack_timeout);
(unsigned long) chan);
setup_timer(&chan->ack_timer, l2cap_ack_timeout, (unsigned long) chan);
skb_queue_head_init(&chan->srej_q); skb_queue_head_init(&chan->srej_q);
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment