Bluetooth: Introduce dedicated TX fragment pool

There's a risk of a deadlock if we use the same pool for ACL fragments
as we use for general ACL TX buffers: all TX buffers are queued up,
and we try to segment one of them, a segment buffer will never become
available. To work around this risk, introduce a dedicated fragment
pool.

Signed-off-by: Johan Hedberg <johan.hedberg@intel.com>
This commit is contained in:
Johan Hedberg 2018-02-09 21:44:01 +02:00 committed by Johan Hedberg
commit abc20e7eae
2 changed files with 35 additions and 0 deletions

View file

@ -168,6 +168,18 @@ config BT_L2CAP_TX_BUF_COUNT
help
Number of buffers available for outgoing L2CAP packets.
config BT_L2CAP_TX_FRAG_COUNT
int "Number of L2CAP TX fragment buffers"
default 2
range 0 255
help
Number of buffers available for fragments of TX buffers. Warning:
setting this to 0 means that the application must ensure that
queued TX buffers never need to be fragmented, i.e. that the
controller's buffer size is large enough. If this is not ensured,
and there are no dedicated fragment buffers, a deadlock may occur.
In most cases the default value of 2 is a safe bet.
config BT_L2CAP_TX_MTU
int "Maximum supported L2CAP MTU for L2CAP TX buffers"
default 23

View file

@ -37,6 +37,25 @@ NET_BUF_POOL_DEFINE(acl_tx_pool, CONFIG_BT_L2CAP_TX_BUF_COUNT,
BT_L2CAP_BUF_SIZE(CONFIG_BT_L2CAP_TX_MTU),
BT_BUF_USER_DATA_MIN, NULL);
#if CONFIG_BT_L2CAP_TX_FRAG_COUNT > 0
#if defined(BT_CTLR_TX_BUFFER_SIZE)
#define FRAG_SIZE BT_L2CAP_BUF_SIZE(BT_CTLR_TX_BUFFER_SIZE - 4)
#else
#define FRAG_SIZE BT_L2CAP_BUF_SIZE(CONFIG_BT_L2CAP_TX_MTU)
#endif
/* Dedicated pool for fragment buffers in case queued up TX buffers don't
* fit the controllers buffer size. We can't use the acl_tx_pool for the
* fragmentation, since it's possible that pool is empty and all buffers
* are queued up in the TX queue. In such a situation, trying to allocate
* another buffer from the acl_tx_pool would result in a deadlock.
*/
NET_BUF_POOL_FIXED_DEFINE(frag_pool, CONFIG_BT_L2CAP_TX_FRAG_COUNT, FRAG_SIZE,
NULL);
#endif /* CONFIG_BT_L2CAP_TX_FRAG_COUNT > 0 */
/* How long until we cancel HCI_LE_Create_Connection */
#define CONN_TIMEOUT K_SECONDS(3)
@ -1198,7 +1217,11 @@ static struct net_buf *create_frag(struct bt_conn *conn, struct net_buf *buf)
struct net_buf *frag;
u16_t frag_len;
#if CONFIG_BT_L2CAP_TX_FRAG_COUNT > 0
frag = bt_conn_create_pdu(&frag_pool, 0);
#else
frag = bt_conn_create_pdu(NULL, 0);
#endif
if (conn->state != BT_CONN_CONNECTED) {
net_buf_unref(frag);