diff options
author | Gustavo F. Padovan <padovan@profusion.mobi> | 2011-06-23 18:29:58 -0400 |
---|---|---|
committer | Gustavo F. Padovan <padovan@profusion.mobi> | 2011-12-18 14:07:55 -0500 |
commit | 721c41812daf7b38759942563773a7832e3c990d (patch) | |
tree | 8a0ab0aee4b619b91e9e68daca1a1369d29ab18d | |
parent | b9cc553f12d14b692d0fcb607d28db783da68139 (diff) |
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: Marcel Holtmann <marcel@holtmann.org>
Signed-off-by: Gustavo F. Padovan <padovan@profusion.mobi>
-rw-r--r-- | include/net/bluetooth/l2cap.h | 17 | ||||
-rw-r--r-- | net/bluetooth/l2cap_core.c | 70 |
2 files changed, 40 insertions, 47 deletions
diff --git a/include/net/bluetooth/l2cap.h b/include/net/bluetooth/l2cap.h index 30719eb2e77c..03be9111dc51 100644 --- a/include/net/bluetooth/l2cap.h +++ b/include/net/bluetooth/l2cap.h | |||
@@ -482,10 +482,11 @@ struct l2cap_chan { | |||
482 | __u32 remote_acc_lat; | 482 | __u32 remote_acc_lat; |
483 | __u32 remote_flush_to; | 483 | __u32 remote_flush_to; |
484 | 484 | ||
485 | struct timer_list chan_timer; | 485 | struct delayed_work chan_timer; |
486 | struct timer_list retrans_timer; | 486 | struct delayed_work retrans_timer; |
487 | struct timer_list monitor_timer; | 487 | struct delayed_work monitor_timer; |
488 | struct timer_list ack_timer; | 488 | struct delayed_work ack_timer; |
489 | |||
489 | struct sk_buff *tx_send_head; | 490 | struct sk_buff *tx_send_head; |
490 | struct sk_buff_head tx_q; | 491 | struct sk_buff_head tx_q; |
491 | struct sk_buff_head srej_q; | 492 | struct sk_buff_head srej_q; |
@@ -595,16 +596,16 @@ enum { | |||
595 | }; | 596 | }; |
596 | 597 | ||
597 | #define __set_chan_timer(c, t) l2cap_set_timer(c, &c->chan_timer, (t)) | 598 | #define __set_chan_timer(c, t) l2cap_set_timer(c, &c->chan_timer, (t)) |
598 | #define __clear_chan_timer(c) l2cap_clear_timer(c, &c->chan_timer) | 599 | #define __clear_chan_timer(c) l2cap_clear_timer(&c->chan_timer) |
599 | #define __set_retrans_timer(c) l2cap_set_timer(c, &c->retrans_timer, \ | 600 | #define __set_retrans_timer(c) l2cap_set_timer(c, &c->retrans_timer, \ |
600 | L2CAP_DEFAULT_RETRANS_TO); | 601 | L2CAP_DEFAULT_RETRANS_TO); |
601 | #define __clear_retrans_timer(c) l2cap_clear_timer(c, &c->retrans_timer) | 602 | #define __clear_retrans_timer(c) l2cap_clear_timer(&c->retrans_timer) |
602 | #define __set_monitor_timer(c) l2cap_set_timer(c, &c->monitor_timer, \ | 603 | #define __set_monitor_timer(c) l2cap_set_timer(c, &c->monitor_timer, \ |
603 | L2CAP_DEFAULT_MONITOR_TO); | 604 | L2CAP_DEFAULT_MONITOR_TO); |
604 | #define __clear_monitor_timer(c) l2cap_clear_timer(c, &c->monitor_timer) | 605 | #define __clear_monitor_timer(c) l2cap_clear_timer(&c->monitor_timer) |
605 | #define __set_ack_timer(c) l2cap_set_timer(c, &chan->ack_timer, \ | 606 | #define __set_ack_timer(c) l2cap_set_timer(c, &chan->ack_timer, \ |
606 | L2CAP_DEFAULT_ACK_TO); | 607 | L2CAP_DEFAULT_ACK_TO); |
607 | #define __clear_ack_timer(c) l2cap_clear_timer(c, &c->ack_timer) | 608 | #define __clear_ack_timer(c) l2cap_clear_timer(&c->ack_timer) |
608 | 609 | ||
609 | static inline int __seq_offset(struct l2cap_chan *chan, __u16 seq1, __u16 seq2) | 610 | static inline int __seq_offset(struct l2cap_chan *chan, __u16 seq1, __u16 seq2) |
610 | { | 611 | { |
diff --git a/net/bluetooth/l2cap_core.c b/net/bluetooth/l2cap_core.c index 0369a9bf60c6..89cda6d82d0c 100644 --- a/net/bluetooth/l2cap_core.c +++ b/net/bluetooth/l2cap_core.c | |||
@@ -213,20 +213,18 @@ static u16 l2cap_alloc_cid(struct l2cap_conn *conn) | |||
213 | return 0; | 213 | return 0; |
214 | } | 214 | } |
215 | 215 | ||
216 | static void l2cap_set_timer(struct l2cap_chan *chan, struct timer_list *timer, long timeout) | 216 | static void l2cap_set_timer(struct l2cap_chan *chan, struct delayed_work *work, long timeout) |
217 | { | 217 | { |
218 | BT_DBG("chan %p state %d timeout %ld", chan, chan->state, timeout); | 218 | BT_DBG("chan %p state %d timeout %ld", chan, chan->state, timeout); |
219 | 219 | ||
220 | if (!mod_timer(timer, jiffies + msecs_to_jiffies(timeout))) | 220 | cancel_delayed_work_sync(work); |
221 | chan_hold(chan); | 221 | |
222 | schedule_delayed_work(work, timeout); | ||
222 | } | 223 | } |
223 | 224 | ||
224 | static void l2cap_clear_timer(struct l2cap_chan *chan, struct timer_list *timer) | 225 | static void l2cap_clear_timer(struct delayed_work *work) |
225 | { | 226 | { |
226 | BT_DBG("chan %p state %d", chan, chan->state); | 227 | cancel_delayed_work_sync(work); |
227 | |||
228 | if (timer_pending(timer) && del_timer(timer)) | ||
229 | chan_put(chan); | ||
230 | } | 228 | } |
231 | 229 | ||
232 | static char *state_to_string(int state) | 230 | static char *state_to_string(int state) |
@@ -264,23 +262,16 @@ static void l2cap_state_change(struct l2cap_chan *chan, int state) | |||
264 | chan->ops->state_change(chan->data, state); | 262 | chan->ops->state_change(chan->data, state); |
265 | } | 263 | } |
266 | 264 | ||
267 | static void l2cap_chan_timeout(unsigned long arg) | 265 | static void l2cap_chan_timeout(struct work_struct *work) |
268 | { | 266 | { |
269 | struct l2cap_chan *chan = (struct l2cap_chan *) arg; | 267 | struct l2cap_chan *chan = container_of(work, struct l2cap_chan, |
268 | chan_timer.work); | ||
270 | struct sock *sk = chan->sk; | 269 | struct sock *sk = chan->sk; |
271 | int reason; | 270 | int reason; |
272 | 271 | ||
273 | BT_DBG("chan %p state %d", chan, chan->state); | 272 | BT_DBG("chan %p state %d", chan, chan->state); |
274 | 273 | ||
275 | bh_lock_sock(sk); | 274 | lock_sock(sk); |
276 | |||
277 | if (sock_owned_by_user(sk)) { | ||
278 | /* sk is owned by user. Try again later */ | ||
279 | __set_chan_timer(chan, L2CAP_DISC_TIMEOUT); | ||
280 | bh_unlock_sock(sk); | ||
281 | chan_put(chan); | ||
282 | return; | ||
283 | } | ||
284 | 275 | ||
285 | if (chan->state == BT_CONNECTED || chan->state == BT_CONFIG) | 276 | if (chan->state == BT_CONNECTED || chan->state == BT_CONFIG) |
286 | reason = ECONNREFUSED; | 277 | reason = ECONNREFUSED; |
@@ -292,7 +283,7 @@ static void l2cap_chan_timeout(unsigned long arg) | |||
292 | 283 | ||
293 | l2cap_chan_close(chan, reason); | 284 | l2cap_chan_close(chan, reason); |
294 | 285 | ||
295 | bh_unlock_sock(sk); | 286 | release_sock(sk); |
296 | 287 | ||
297 | chan->ops->close(chan->data); | 288 | chan->ops->close(chan->data); |
298 | chan_put(chan); | 289 | chan_put(chan); |
@@ -312,7 +303,7 @@ struct l2cap_chan *l2cap_chan_create(struct sock *sk) | |||
312 | list_add(&chan->global_l, &chan_list); | 303 | list_add(&chan->global_l, &chan_list); |
313 | write_unlock_bh(&chan_list_lock); | 304 | write_unlock_bh(&chan_list_lock); |
314 | 305 | ||
315 | setup_timer(&chan->chan_timer, l2cap_chan_timeout, (unsigned long) chan); | 306 | INIT_DELAYED_WORK(&chan->chan_timer, l2cap_chan_timeout); |
316 | 307 | ||
317 | chan->state = BT_OPEN; | 308 | chan->state = BT_OPEN; |
318 | 309 | ||
@@ -1251,17 +1242,18 @@ int __l2cap_wait_ack(struct sock *sk) | |||
1251 | return err; | 1242 | return err; |
1252 | } | 1243 | } |
1253 | 1244 | ||
1254 | static void l2cap_monitor_timeout(unsigned long arg) | 1245 | static void l2cap_monitor_timeout(struct work_struct *work) |
1255 | { | 1246 | { |
1256 | struct l2cap_chan *chan = (void *) arg; | 1247 | struct l2cap_chan *chan = container_of(work, struct l2cap_chan, |
1248 | monitor_timer.work); | ||
1257 | struct sock *sk = chan->sk; | 1249 | struct sock *sk = chan->sk; |
1258 | 1250 | ||
1259 | BT_DBG("chan %p", chan); | 1251 | BT_DBG("chan %p", chan); |
1260 | 1252 | ||
1261 | bh_lock_sock(sk); | 1253 | lock_sock(sk); |
1262 | if (chan->retry_count >= chan->remote_max_tx) { | 1254 | if (chan->retry_count >= chan->remote_max_tx) { |
1263 | l2cap_send_disconn_req(chan->conn, chan, ECONNABORTED); | 1255 | l2cap_send_disconn_req(chan->conn, chan, ECONNABORTED); |
1264 | bh_unlock_sock(sk); | 1256 | release_sock(sk); |
1265 | return; | 1257 | return; |
1266 | } | 1258 | } |
1267 | 1259 | ||
@@ -1269,24 +1261,25 @@ static void l2cap_monitor_timeout(unsigned long arg) | |||
1269 | __set_monitor_timer(chan); | 1261 | __set_monitor_timer(chan); |
1270 | 1262 | ||
1271 | l2cap_send_rr_or_rnr(chan, L2CAP_CTRL_POLL); | 1263 | l2cap_send_rr_or_rnr(chan, L2CAP_CTRL_POLL); |
1272 | bh_unlock_sock(sk); | 1264 | release_sock(sk); |
1273 | } | 1265 | } |
1274 | 1266 | ||
1275 | static void l2cap_retrans_timeout(unsigned long arg) | 1267 | static void l2cap_retrans_timeout(struct work_struct *work) |
1276 | { | 1268 | { |
1277 | struct l2cap_chan *chan = (void *) arg; | 1269 | struct l2cap_chan *chan = container_of(work, struct l2cap_chan, |
1270 | retrans_timer.work); | ||
1278 | struct sock *sk = chan->sk; | 1271 | struct sock *sk = chan->sk; |
1279 | 1272 | ||
1280 | BT_DBG("chan %p", chan); | 1273 | BT_DBG("chan %p", chan); |
1281 | 1274 | ||
1282 | bh_lock_sock(sk); | 1275 | lock_sock(sk); |
1283 | chan->retry_count = 1; | 1276 | chan->retry_count = 1; |
1284 | __set_monitor_timer(chan); | 1277 | __set_monitor_timer(chan); |
1285 | 1278 | ||
1286 | set_bit(CONN_WAIT_F, &chan->conn_state); | 1279 | set_bit(CONN_WAIT_F, &chan->conn_state); |
1287 | 1280 | ||
1288 | l2cap_send_rr_or_rnr(chan, L2CAP_CTRL_POLL); | 1281 | l2cap_send_rr_or_rnr(chan, L2CAP_CTRL_POLL); |
1289 | bh_unlock_sock(sk); | 1282 | release_sock(sk); |
1290 | } | 1283 | } |
1291 | 1284 | ||
1292 | static void l2cap_drop_acked_frames(struct l2cap_chan *chan) | 1285 | 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 | (unsigned long) &efs); | 1948 | (unsigned long) &efs); |
1956 | } | 1949 | } |
1957 | 1950 | ||
1958 | static void l2cap_ack_timeout(unsigned long arg) | 1951 | static void l2cap_ack_timeout(struct work_struct *work) |
1959 | { | 1952 | { |
1960 | struct l2cap_chan *chan = (void *) arg; | 1953 | struct l2cap_chan *chan = container_of(work, struct l2cap_chan, |
1954 | ack_timer.work); | ||
1961 | 1955 | ||
1962 | bh_lock_sock(chan->sk); | 1956 | lock_sock(chan->sk); |
1963 | l2cap_send_ack(chan); | 1957 | l2cap_send_ack(chan); |
1964 | bh_unlock_sock(chan->sk); | 1958 | release_sock(chan->sk); |
1965 | } | 1959 | } |
1966 | 1960 | ||
1967 | static inline void l2cap_ertm_init(struct l2cap_chan *chan) | 1961 | 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 | chan->num_acked = 0; | 1968 | chan->num_acked = 0; |
1975 | chan->frames_sent = 0; | 1969 | chan->frames_sent = 0; |
1976 | 1970 | ||
1977 | setup_timer(&chan->retrans_timer, l2cap_retrans_timeout, | 1971 | INIT_DELAYED_WORK(&chan->retrans_timer, l2cap_retrans_timeout); |
1978 | (unsigned long) chan); | 1972 | INIT_DELAYED_WORK(&chan->monitor_timer, l2cap_monitor_timeout); |
1979 | setup_timer(&chan->monitor_timer, l2cap_monitor_timeout, | 1973 | INIT_DELAYED_WORK(&chan->ack_timer, l2cap_ack_timeout); |
1980 | (unsigned long) chan); | ||
1981 | setup_timer(&chan->ack_timer, l2cap_ack_timeout, (unsigned long) chan); | ||
1982 | 1974 | ||
1983 | skb_queue_head_init(&chan->srej_q); | 1975 | skb_queue_head_init(&chan->srej_q); |
1984 | 1976 | ||