From: Mat Martineau <mathewm@codeaurora.org>
To: Gustavo Padovan <padovan@profusion.mobi>
Cc: linux-bluetooth@vger.kernel.org
Subject: Re: [PATCH v2 2/3] Bluetooth: Use event-driven approach for handling ERTM receive buffer
Date: Thu, 7 Jul 2011 08:43:40 -0700 (PDT) [thread overview]
Message-ID: <alpine.DEB.2.02.1107070826520.564@mathewm-linux> (raw)
In-Reply-To: <20110706234351.GA14399@joana>
Hi Gustavo -
On Wed, 6 Jul 2011, Gustavo Padovan wrote:
> Hi Mat,
>
> * Mat Martineau <mathewm@codeaurora.org> [2011-07-06 16:01:43 -0700]:
>
>>
>> Hi Gustavo -
>>
>> On Wed, 6 Jul 2011, Gustavo Padovan wrote:
>>
>>> Hi Mat,
>>>
>>> * Mat Martineau <mathewm@codeaurora.org> [2011-07-06 14:54:31 -0700]:
>>>
>>>> This change moves most L2CAP ERTM receive buffer handling out of the
>>>> L2CAP core and in to the socket code. It's up to the higher layer
>>>> (the socket code, in this case) to tell the core when its buffer is
>>>> full or has space available. The recv op should always accept
>>>> incoming ERTM data or else the connection will go down.
>>>>
>>>> Within the socket layer, an skb that does not fit in the socket
>>>> receive buffer will be temporarily stored. When the socket is read
>>>> from, that skb will be placed in the receive buffer if possible. Once
>>>> adequate buffer space becomes available, the L2CAP core is informed
>>>> and the ERTM local busy state is cleared.
>>>>
>>>> Receive buffer management for non-ERTM modes is unchanged.
>>>>
>>>> Signed-off-by: Mat Martineau <mathewm@codeaurora.org>
>>>> ---
>>>> include/net/bluetooth/l2cap.h | 2 +
>>>> net/bluetooth/l2cap_core.c | 41 ++++++++++++++++---------
>>>> net/bluetooth/l2cap_sock.c | 66 ++++++++++++++++++++++++++++++++++++++--
>>>> 3 files changed, 90 insertions(+), 19 deletions(-)
>>>>
>>>> diff --git a/include/net/bluetooth/l2cap.h b/include/net/bluetooth/l2cap.h
>>>> index 9c18e55..66b8d96 100644
>>>> --- a/include/net/bluetooth/l2cap.h
>>>> +++ b/include/net/bluetooth/l2cap.h
>>>> @@ -422,6 +422,7 @@ struct l2cap_conn {
>>>> struct l2cap_pinfo {
>>>> struct bt_sock bt;
>>>> struct l2cap_chan *chan;
>>>> + struct sk_buff *rx_busy_skb;
>>>> };
>>>>
>>>> enum {
>>>> @@ -498,5 +499,6 @@ void l2cap_chan_close(struct l2cap_chan *chan, int reason);
>>>> void l2cap_chan_destroy(struct l2cap_chan *chan);
>>>> int l2cap_chan_connect(struct l2cap_chan *chan);
>>>> int l2cap_chan_send(struct l2cap_chan *chan, struct msghdr *msg, size_t len);
>>>> +void l2cap_chan_busy(struct l2cap_chan *chan, int busy);
>>>>
>>>> #endif /* __L2CAP_H */
>>>> diff --git a/net/bluetooth/l2cap_core.c b/net/bluetooth/l2cap_core.c
>>>> index f7ada4a..ea9c7d0 100644
>>>> --- a/net/bluetooth/l2cap_core.c
>>>> +++ b/net/bluetooth/l2cap_core.c
>>>> @@ -3350,21 +3350,21 @@ static int l2cap_push_rx_skb(struct l2cap_chan *chan, struct sk_buff *skb, u16 c
>>>> }
>>>>
>>>> err = l2cap_ertm_reassembly_sdu(chan, skb, control);
>>>> - if (err >= 0) {
>>>> - chan->buffer_seq = (chan->buffer_seq + 1) % 64;
>>>> - return err;
>>>> - }
>>>> -
>>>> - l2cap_ertm_enter_local_busy(chan);
>>>> -
>>>> - bt_cb(skb)->sar = control >> L2CAP_CTRL_SAR_SHIFT;
>>>> - __skb_queue_tail(&chan->busy_q, skb);
>>>> -
>>>> - queue_work(_busy_wq, &chan->busy_work);
>>>> + chan->buffer_seq = (chan->buffer_seq + 1) % 64;
>>>>
>>>> return err;
>>>> }
>>>>
>>>> +void l2cap_chan_busy(struct l2cap_chan *chan, int busy)
>>>> +{
>>>> + if (chan->mode == L2CAP_MODE_ERTM) {
>>>> + if (busy)
>>>> + l2cap_ertm_enter_local_busy(chan);
>>>> + else
>>>> + l2cap_ertm_exit_local_busy(chan);
>>>> + }
>>>> +}
>>>> +
>>>> static int l2cap_streaming_reassembly_sdu(struct l2cap_chan *chan, struct sk_buff *skb, u16 control)
>>>> {
>>>> struct sk_buff *_skb;
>>>> @@ -3463,13 +3463,22 @@ static void l2cap_check_srej_gap(struct l2cap_chan *chan, u8 tx_seq)
>>>> struct sk_buff *skb;
>>>> u16 control;
>>>>
>>>> - while ((skb = skb_peek(&chan->srej_q))) {
>>>> + while ((skb = skb_peek(&chan->srej_q)) &&
>>>> + !test_bit(CONN_LOCAL_BUSY, &chan->conn_state)) {
>>>> + int err;
>>>> +
>>>> if (bt_cb(skb)->tx_seq != tx_seq)
>>>> break;
>>>>
>>>> skb = skb_dequeue(&chan->srej_q);
>>>> control = bt_cb(skb)->sar << L2CAP_CTRL_SAR_SHIFT;
>>>> - l2cap_ertm_reassembly_sdu(chan, skb, control);
>>>> + err = l2cap_ertm_reassembly_sdu(chan, skb, control);
>>>> +
>>>> + if (err < 0) {
>>>> + l2cap_send_disconn_req(chan->conn, chan, ECONNRESET);
>>>> + break;
>>>> + }
>>>> +
>>>> chan->buffer_seq_srej =
>>>> (chan->buffer_seq_srej + 1) % 64;
>>>> tx_seq = (tx_seq + 1) % 64;
>>>> @@ -3625,8 +3634,10 @@ expected:
>>>> }
>>>>
>>>> err = l2cap_push_rx_skb(chan, skb, rx_control);
>>>> - if (err < 0)
>>>> - return 0;
>>>> + if (err < 0) {
>>>> + l2cap_send_disconn_req(chan->conn, chan, ECONNRESET);
>>>> + return err;
>>>> + }
>>>>
>>>> if (rx_control & L2CAP_CTRL_FINAL) {
>>>> if (!test_and_clear_bit(CONN_REJ_ACT, &chan->conn_state))
>>>> diff --git a/net/bluetooth/l2cap_sock.c b/net/bluetooth/l2cap_sock.c
>>>> index 39082d4..9bf7313 100644
>>>> --- a/net/bluetooth/l2cap_sock.c
>>>> +++ b/net/bluetooth/l2cap_sock.c
>>>> @@ -711,13 +711,15 @@ static int l2cap_sock_sendmsg(struct kiocb *iocb, struct socket *sock, struct ms
>>>> static int l2cap_sock_recvmsg(struct kiocb *iocb, struct socket *sock, struct msghdr *msg, size_t len, int flags)
>>>> {
>>>> struct sock *sk = sock->sk;
>>>> + struct l2cap_pinfo *pi = l2cap_pi(sk);
>>>> + int err;
>>>>
>>>> lock_sock(sk);
>>>>
>>>> if (sk->sk_state == BT_CONNECT2 && bt_sk(sk)->defer_setup) {
>>>> sk->sk_state = BT_CONFIG;
>>>>
>>>> - __l2cap_connect_rsp_defer(l2cap_pi(sk)->chan);
>>>> + __l2cap_connect_rsp_defer(pi->chan);
>>>> release_sock(sk);
>>>> return 0;
>>>> }
>>>> @@ -725,9 +727,38 @@ static int l2cap_sock_recvmsg(struct kiocb *iocb, struct socket *sock, struct ms
>>>> release_sock(sk);
>>>>
>>>> if (sock->type == SOCK_STREAM)
>>>> - return bt_sock_stream_recvmsg(iocb, sock, msg, len, flags);
>>>> + err = bt_sock_stream_recvmsg(iocb, sock, msg, len, flags);
>>>> + else
>>>> + err = bt_sock_recvmsg(iocb, sock, msg, len, flags);
>>>> +
>>>> + if (pi->chan->mode == L2CAP_MODE_ERTM) {
>>>
>>> if (pi->chan->mode != L2CAP_MODE_ERTM) {
>>> return err;
>>>
>>> lock_sock()...
>>
>> Ok.
>>
>>>> + int threshold;
>>>> +
>>>> + /* Attempt to put pending rx data in the socket buffer */
>>>> +
>>>> + lock_sock(sk);
>>>> + if (pi->rx_busy_skb) {
>>>> + int queue_err;
>>>> + queue_err = sock_queue_rcv_skb(sk, pi->rx_busy_skb);
>>>> +
>>>> + if (!queue_err)
>>>> + pi->rx_busy_skb = NULL;
>>>
>>> if (!sock_queue_rcv_skb())
>>> pi->rx_busy_skb = NULL;
>>> else
>>> return err;
>>>
>>> What I understood is that if sock_queue_rcv_skb() fails there is no need to
>>> check if there is available space in the buffer, then we just return. The
>>> locks also needs to be released.
>>
>> You're right - it's better to make sure we don't exit local busy in
>> this case.
>>
>>>> + }
>>>> +
>>>> + /* Restore data flow when half of the receive buffer is
>>>> + * available. This avoids resending large numbers of
>>>> + * frames.
>>>> + */
>>>> + threshold = sk->sk_rcvbuf >> 1;
>>>> + if (test_bit(CONN_LOCAL_BUSY, &pi->chan->conn_state) &&
>>>> + !pi->rx_busy_skb &&
>>>> + atomic_read(&sk->sk_rmem_alloc) <= threshold)
>>>> + l2cap_chan_busy(pi->chan, 0);
>>>
>>> Then this if can be just
>>>
>>> if (atomic_read(sk_rmem_alloc) <= sk_rcvbuf >> 1)
>>> l2cap_chan_busy(pi->chan, 0);
>>>
>>
>> It's still important to see if the channel is currently LOCAL_BUSY,
>> this code path will be executed every time an ERTM socket is read
>> from (busy or not).
>
> what about this in beginning?
>
> if (pi->chan->mode != L2CAP_MODE_ERTM || !LOCAL_BUSY) {
>
> Then we avoid all the rest of the code if we are in Local Busy.
The lock needs to be held to check the local busy bit. I can check
LOCAL_BUSY after the lock, and release/return early if not busy.
--
Mat Martineau
Employee of Qualcomm Innovation Center, Inc.
Qualcomm Innovation Center, Inc. is a member of Code Aurora Forum
next prev parent reply other threads:[~2011-07-07 15:43 UTC|newest]
Thread overview: 8+ messages / expand[flat|nested] mbox.gz Atom feed top
2011-07-06 21:54 [PATCH v2 0/3] ERTM local busy enhancement Mat Martineau
2011-07-06 21:54 ` [PATCH v2 1/3] Bluetooth: Move code for ERTM local busy state to separate functions Mat Martineau
2011-07-06 21:54 ` [PATCH v2 2/3] Bluetooth: Use event-driven approach for handling ERTM receive buffer Mat Martineau
2011-07-06 22:36 ` Gustavo Padovan
2011-07-06 23:01 ` Mat Martineau
2011-07-06 23:43 ` Gustavo Padovan
2011-07-07 15:43 ` Mat Martineau [this message]
2011-07-06 21:54 ` [PATCH v2 3/3] Bluetooth: Remove L2CAP busy queue Mat Martineau
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=alpine.DEB.2.02.1107070826520.564@mathewm-linux \
--to=mathewm@codeaurora.org \
--cc=linux-bluetooth@vger.kernel.org \
--cc=padovan@profusion.mobi \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).