diff options
author | Mat Martineau <mathewm@codeaurora.org> | 2011-07-07 12:39:03 -0400 |
---|---|---|
committer | Gustavo F. Padovan <padovan@profusion.mobi> | 2011-07-07 14:29:06 -0400 |
commit | fadd192e81b0a8d8086531b8c11bd88b311b68c2 (patch) | |
tree | fc1cf6a8183382801e49a48f0440c589cfb16645 /net | |
parent | e328140fdacbba43292a59a22fb55d9185288318 (diff) |
Bluetooth: Remove L2CAP busy queue
The ERTM receive buffer is now handled in a way that does not require
the busy queue and the associated polling code.
Signed-off-by: Mat Martineau <mathewm@codeaurora.org>
Signed-off-by: Gustavo F. Padovan <padovan@profusion.mobi>
Diffstat (limited to 'net')
-rw-r--r-- | net/bluetooth/l2cap_core.c | 125 |
1 files changed, 8 insertions, 117 deletions
diff --git a/net/bluetooth/l2cap_core.c b/net/bluetooth/l2cap_core.c index ea9c7d061046..2c5d335bde87 100644 --- a/net/bluetooth/l2cap_core.c +++ b/net/bluetooth/l2cap_core.c | |||
@@ -61,13 +61,9 @@ int disable_ertm; | |||
61 | static u32 l2cap_feat_mask = L2CAP_FEAT_FIXED_CHAN; | 61 | static u32 l2cap_feat_mask = L2CAP_FEAT_FIXED_CHAN; |
62 | static u8 l2cap_fixed_chan[8] = { 0x02, }; | 62 | static u8 l2cap_fixed_chan[8] = { 0x02, }; |
63 | 63 | ||
64 | static struct workqueue_struct *_busy_wq; | ||
65 | |||
66 | static LIST_HEAD(chan_list); | 64 | static LIST_HEAD(chan_list); |
67 | static DEFINE_RWLOCK(chan_list_lock); | 65 | static DEFINE_RWLOCK(chan_list_lock); |
68 | 66 | ||
69 | static void l2cap_busy_work(struct work_struct *work); | ||
70 | |||
71 | static struct sk_buff *l2cap_build_cmd(struct l2cap_conn *conn, | 67 | static struct sk_buff *l2cap_build_cmd(struct l2cap_conn *conn, |
72 | u8 code, u8 ident, u16 dlen, void *data); | 68 | u8 code, u8 ident, u16 dlen, void *data); |
73 | static void l2cap_send_cmd(struct l2cap_conn *conn, u8 ident, u8 code, u16 len, | 69 | static void l2cap_send_cmd(struct l2cap_conn *conn, u8 ident, u8 code, u16 len, |
@@ -395,7 +391,6 @@ static void l2cap_chan_del(struct l2cap_chan *chan, int err) | |||
395 | __clear_ack_timer(chan); | 391 | __clear_ack_timer(chan); |
396 | 392 | ||
397 | skb_queue_purge(&chan->srej_q); | 393 | skb_queue_purge(&chan->srej_q); |
398 | skb_queue_purge(&chan->busy_q); | ||
399 | 394 | ||
400 | list_for_each_entry_safe(l, tmp, &chan->srej_l, list) { | 395 | list_for_each_entry_safe(l, tmp, &chan->srej_l, list) { |
401 | list_del(&l->list); | 396 | list_del(&l->list); |
@@ -1873,11 +1868,9 @@ static inline void l2cap_ertm_init(struct l2cap_chan *chan) | |||
1873 | setup_timer(&chan->ack_timer, l2cap_ack_timeout, (unsigned long) chan); | 1868 | setup_timer(&chan->ack_timer, l2cap_ack_timeout, (unsigned long) chan); |
1874 | 1869 | ||
1875 | skb_queue_head_init(&chan->srej_q); | 1870 | skb_queue_head_init(&chan->srej_q); |
1876 | skb_queue_head_init(&chan->busy_q); | ||
1877 | 1871 | ||
1878 | INIT_LIST_HEAD(&chan->srej_l); | 1872 | INIT_LIST_HEAD(&chan->srej_l); |
1879 | 1873 | ||
1880 | INIT_WORK(&chan->busy_work, l2cap_busy_work); | ||
1881 | 1874 | ||
1882 | sk->sk_backlog_rcv = l2cap_ertm_data_rcv; | 1875 | sk->sk_backlog_rcv = l2cap_ertm_data_rcv; |
1883 | } | 1876 | } |
@@ -3182,32 +3175,27 @@ static int l2cap_ertm_reassembly_sdu(struct l2cap_chan *chan, struct sk_buff *sk | |||
3182 | if (!chan->sdu) | 3175 | if (!chan->sdu) |
3183 | goto disconnect; | 3176 | goto disconnect; |
3184 | 3177 | ||
3185 | if (!test_bit(CONN_SAR_RETRY, &chan->conn_state)) { | 3178 | chan->partial_sdu_len += skb->len; |
3186 | chan->partial_sdu_len += skb->len; | ||
3187 | 3179 | ||
3188 | if (chan->partial_sdu_len > chan->imtu) | 3180 | if (chan->partial_sdu_len > chan->imtu) |
3189 | goto drop; | 3181 | goto drop; |
3190 | 3182 | ||
3191 | if (chan->partial_sdu_len != chan->sdu_len) | 3183 | if (chan->partial_sdu_len != chan->sdu_len) |
3192 | goto drop; | 3184 | goto drop; |
3193 | 3185 | ||
3194 | memcpy(skb_put(chan->sdu, skb->len), skb->data, skb->len); | 3186 | memcpy(skb_put(chan->sdu, skb->len), skb->data, skb->len); |
3195 | } | ||
3196 | 3187 | ||
3197 | _skb = skb_clone(chan->sdu, GFP_ATOMIC); | 3188 | _skb = skb_clone(chan->sdu, GFP_ATOMIC); |
3198 | if (!_skb) { | 3189 | if (!_skb) { |
3199 | set_bit(CONN_SAR_RETRY, &chan->conn_state); | ||
3200 | return -ENOMEM; | 3190 | return -ENOMEM; |
3201 | } | 3191 | } |
3202 | 3192 | ||
3203 | err = chan->ops->recv(chan->data, _skb); | 3193 | err = chan->ops->recv(chan->data, _skb); |
3204 | if (err < 0) { | 3194 | if (err < 0) { |
3205 | kfree_skb(_skb); | 3195 | kfree_skb(_skb); |
3206 | set_bit(CONN_SAR_RETRY, &chan->conn_state); | ||
3207 | return err; | 3196 | return err; |
3208 | } | 3197 | } |
3209 | 3198 | ||
3210 | clear_bit(CONN_SAR_RETRY, &chan->conn_state); | ||
3211 | clear_bit(CONN_SAR_SDU, &chan->conn_state); | 3199 | clear_bit(CONN_SAR_SDU, &chan->conn_state); |
3212 | 3200 | ||
3213 | kfree_skb(chan->sdu); | 3201 | kfree_skb(chan->sdu); |
@@ -3268,93 +3256,6 @@ done: | |||
3268 | BT_DBG("chan %p, Exit local busy", chan); | 3256 | BT_DBG("chan %p, Exit local busy", chan); |
3269 | } | 3257 | } |
3270 | 3258 | ||
3271 | static int l2cap_try_push_rx_skb(struct l2cap_chan *chan) | ||
3272 | { | ||
3273 | struct sk_buff *skb; | ||
3274 | u16 control; | ||
3275 | int err; | ||
3276 | |||
3277 | while ((skb = skb_dequeue(&chan->busy_q))) { | ||
3278 | control = bt_cb(skb)->sar << L2CAP_CTRL_SAR_SHIFT; | ||
3279 | err = l2cap_ertm_reassembly_sdu(chan, skb, control); | ||
3280 | if (err < 0) { | ||
3281 | skb_queue_head(&chan->busy_q, skb); | ||
3282 | return -EBUSY; | ||
3283 | } | ||
3284 | |||
3285 | chan->buffer_seq = (chan->buffer_seq + 1) % 64; | ||
3286 | } | ||
3287 | |||
3288 | l2cap_ertm_exit_local_busy(chan); | ||
3289 | |||
3290 | return 0; | ||
3291 | } | ||
3292 | |||
3293 | static void l2cap_busy_work(struct work_struct *work) | ||
3294 | { | ||
3295 | DECLARE_WAITQUEUE(wait, current); | ||
3296 | struct l2cap_chan *chan = | ||
3297 | container_of(work, struct l2cap_chan, busy_work); | ||
3298 | struct sock *sk = chan->sk; | ||
3299 | int n_tries = 0, timeo = HZ/5, err; | ||
3300 | struct sk_buff *skb; | ||
3301 | |||
3302 | lock_sock(sk); | ||
3303 | |||
3304 | add_wait_queue(sk_sleep(sk), &wait); | ||
3305 | while ((skb = skb_peek(&chan->busy_q))) { | ||
3306 | set_current_state(TASK_INTERRUPTIBLE); | ||
3307 | |||
3308 | if (n_tries++ > L2CAP_LOCAL_BUSY_TRIES) { | ||
3309 | err = -EBUSY; | ||
3310 | l2cap_send_disconn_req(chan->conn, chan, EBUSY); | ||
3311 | break; | ||
3312 | } | ||
3313 | |||
3314 | if (!timeo) | ||
3315 | timeo = HZ/5; | ||
3316 | |||
3317 | if (signal_pending(current)) { | ||
3318 | err = sock_intr_errno(timeo); | ||
3319 | break; | ||
3320 | } | ||
3321 | |||
3322 | release_sock(sk); | ||
3323 | timeo = schedule_timeout(timeo); | ||
3324 | lock_sock(sk); | ||
3325 | |||
3326 | err = sock_error(sk); | ||
3327 | if (err) | ||
3328 | break; | ||
3329 | |||
3330 | if (l2cap_try_push_rx_skb(chan) == 0) | ||
3331 | break; | ||
3332 | } | ||
3333 | |||
3334 | set_current_state(TASK_RUNNING); | ||
3335 | remove_wait_queue(sk_sleep(sk), &wait); | ||
3336 | |||
3337 | release_sock(sk); | ||
3338 | } | ||
3339 | |||
3340 | static int l2cap_push_rx_skb(struct l2cap_chan *chan, struct sk_buff *skb, u16 control) | ||
3341 | { | ||
3342 | int err; | ||
3343 | |||
3344 | if (test_bit(CONN_LOCAL_BUSY, &chan->conn_state)) { | ||
3345 | bt_cb(skb)->sar = control >> L2CAP_CTRL_SAR_SHIFT; | ||
3346 | __skb_queue_tail(&chan->busy_q, skb); | ||
3347 | return l2cap_try_push_rx_skb(chan); | ||
3348 | |||
3349 | |||
3350 | } | ||
3351 | |||
3352 | err = l2cap_ertm_reassembly_sdu(chan, skb, control); | ||
3353 | chan->buffer_seq = (chan->buffer_seq + 1) % 64; | ||
3354 | |||
3355 | return err; | ||
3356 | } | ||
3357 | |||
3358 | void l2cap_chan_busy(struct l2cap_chan *chan, int busy) | 3259 | void l2cap_chan_busy(struct l2cap_chan *chan, int busy) |
3359 | { | 3260 | { |
3360 | if (chan->mode == L2CAP_MODE_ERTM) { | 3261 | if (chan->mode == L2CAP_MODE_ERTM) { |
@@ -3612,7 +3513,6 @@ static inline int l2cap_data_channel_iframe(struct l2cap_chan *chan, u16 rx_cont | |||
3612 | chan->buffer_seq_srej = chan->buffer_seq; | 3513 | chan->buffer_seq_srej = chan->buffer_seq; |
3613 | 3514 | ||
3614 | __skb_queue_head_init(&chan->srej_q); | 3515 | __skb_queue_head_init(&chan->srej_q); |
3615 | __skb_queue_head_init(&chan->busy_q); | ||
3616 | l2cap_add_to_srej_queue(chan, skb, tx_seq, sar); | 3516 | l2cap_add_to_srej_queue(chan, skb, tx_seq, sar); |
3617 | 3517 | ||
3618 | set_bit(CONN_SEND_PBIT, &chan->conn_state); | 3518 | set_bit(CONN_SEND_PBIT, &chan->conn_state); |
@@ -3633,7 +3533,8 @@ expected: | |||
3633 | return 0; | 3533 | return 0; |
3634 | } | 3534 | } |
3635 | 3535 | ||
3636 | err = l2cap_push_rx_skb(chan, skb, rx_control); | 3536 | err = l2cap_ertm_reassembly_sdu(chan, skb, rx_control); |
3537 | chan->buffer_seq = (chan->buffer_seq + 1) % 64; | ||
3637 | if (err < 0) { | 3538 | if (err < 0) { |
3638 | l2cap_send_disconn_req(chan->conn, chan, ECONNRESET); | 3539 | l2cap_send_disconn_req(chan->conn, chan, ECONNRESET); |
3639 | return err; | 3540 | return err; |
@@ -4439,12 +4340,6 @@ int __init l2cap_init(void) | |||
4439 | if (err < 0) | 4340 | if (err < 0) |
4440 | return err; | 4341 | return err; |
4441 | 4342 | ||
4442 | _busy_wq = create_singlethread_workqueue("l2cap"); | ||
4443 | if (!_busy_wq) { | ||
4444 | err = -ENOMEM; | ||
4445 | goto error; | ||
4446 | } | ||
4447 | |||
4448 | err = hci_register_proto(&l2cap_hci_proto); | 4343 | err = hci_register_proto(&l2cap_hci_proto); |
4449 | if (err < 0) { | 4344 | if (err < 0) { |
4450 | BT_ERR("L2CAP protocol registration failed"); | 4345 | BT_ERR("L2CAP protocol registration failed"); |
@@ -4462,7 +4357,6 @@ int __init l2cap_init(void) | |||
4462 | return 0; | 4357 | return 0; |
4463 | 4358 | ||
4464 | error: | 4359 | error: |
4465 | destroy_workqueue(_busy_wq); | ||
4466 | l2cap_cleanup_sockets(); | 4360 | l2cap_cleanup_sockets(); |
4467 | return err; | 4361 | return err; |
4468 | } | 4362 | } |
@@ -4471,9 +4365,6 @@ void l2cap_exit(void) | |||
4471 | { | 4365 | { |
4472 | debugfs_remove(l2cap_debugfs); | 4366 | debugfs_remove(l2cap_debugfs); |
4473 | 4367 | ||
4474 | flush_workqueue(_busy_wq); | ||
4475 | destroy_workqueue(_busy_wq); | ||
4476 | |||
4477 | if (hci_unregister_proto(&l2cap_hci_proto) < 0) | 4368 | if (hci_unregister_proto(&l2cap_hci_proto) < 0) |
4478 | BT_ERR("L2CAP protocol unregistration failed"); | 4369 | BT_ERR("L2CAP protocol unregistration failed"); |
4479 | 4370 | ||