mirror of
https://github.com/torvalds/linux.git
synced 2026-11-07 06:17:02 +01:00
Bluetooth: L2CAP: annotate locking for l2cap_chan_del()
Add context analysis annotations for chan->lock and chan->conn->lock involving l2cap_chan_del() usage. Add necessary annotations and related lockdep_assert_held to callers. Move struct l2cap_ops definition after struct l2cap_conn, so that the callbacks can be annotated. In l2cap_chan_close_unlocked() we consider chan->conn->lock as locked even if chan->conn == NULL, to avoid needing to define separate __l2cap_chan_close/del for this NULL case. Signed-off-by: Pauli Virtanen <pav@iki.fi> Signed-off-by: Luiz Augusto von Dentz <luiz.von.dentz@intel.com>
This commit is contained in:
parent
dc1ddc65f0
commit
0e4d951a2f
|
|
@ -614,31 +614,6 @@ struct l2cap_chan {
|
|||
struct mutex lock;
|
||||
};
|
||||
|
||||
struct l2cap_ops {
|
||||
char *name;
|
||||
|
||||
int (*new_connection)(struct l2cap_chan *chan,
|
||||
struct l2cap_chan *new_chan);
|
||||
int (*recv) (struct l2cap_chan * chan,
|
||||
struct sk_buff *skb);
|
||||
void (*teardown) (struct l2cap_chan *chan, int err);
|
||||
void (*close) (struct l2cap_chan *chan);
|
||||
void (*state_change) (struct l2cap_chan *chan,
|
||||
int state, int err);
|
||||
void (*ready) (struct l2cap_chan *chan);
|
||||
void (*defer) (struct l2cap_chan *chan);
|
||||
void (*resume) (struct l2cap_chan *chan);
|
||||
void (*suspend) (struct l2cap_chan *chan);
|
||||
void (*set_shutdown) (struct l2cap_chan *chan);
|
||||
long (*get_sndtimeo) (struct l2cap_chan *chan);
|
||||
struct pid *(*get_peer_pid) (struct l2cap_chan *chan);
|
||||
struct sk_buff *(*alloc_skb) (struct l2cap_chan *chan,
|
||||
unsigned long hdr_len,
|
||||
unsigned long len, int nb);
|
||||
int (*filter) (struct l2cap_chan * chan,
|
||||
struct sk_buff *skb);
|
||||
};
|
||||
|
||||
struct l2cap_conn {
|
||||
struct hci_conn *hcon;
|
||||
struct hci_chan *hchan;
|
||||
|
|
@ -674,6 +649,34 @@ struct l2cap_conn {
|
|||
struct list_head users;
|
||||
};
|
||||
|
||||
struct l2cap_ops {
|
||||
char *name;
|
||||
|
||||
int (*new_connection)(struct l2cap_chan *chan,
|
||||
struct l2cap_chan *new_chan);
|
||||
int (*recv) (struct l2cap_chan * chan,
|
||||
struct sk_buff *skb);
|
||||
void (*teardown) (struct l2cap_chan *chan, int err)
|
||||
__must_hold(&chan->lock);
|
||||
void (*close) (struct l2cap_chan *chan);
|
||||
void (*state_change) (struct l2cap_chan *chan,
|
||||
int state, int err);
|
||||
void (*ready) (struct l2cap_chan *chan)
|
||||
__must_hold(&chan->lock)
|
||||
__must_hold(&chan->conn->lock);
|
||||
void (*defer) (struct l2cap_chan *chan);
|
||||
void (*resume) (struct l2cap_chan *chan);
|
||||
void (*suspend) (struct l2cap_chan *chan);
|
||||
void (*set_shutdown) (struct l2cap_chan *chan);
|
||||
long (*get_sndtimeo) (struct l2cap_chan *chan);
|
||||
struct pid *(*get_peer_pid) (struct l2cap_chan *chan);
|
||||
struct sk_buff *(*alloc_skb) (struct l2cap_chan *chan,
|
||||
unsigned long hdr_len,
|
||||
unsigned long len, int nb);
|
||||
int (*filter) (struct l2cap_chan * chan,
|
||||
struct sk_buff *skb);
|
||||
};
|
||||
|
||||
struct l2cap_user {
|
||||
struct list_head list;
|
||||
int (*probe) (struct l2cap_conn *conn, struct l2cap_user *user);
|
||||
|
|
@ -983,7 +986,8 @@ void __l2cap_chan_add(struct l2cap_conn *conn, struct l2cap_chan *chan)
|
|||
typedef void (*l2cap_chan_func_t)(struct l2cap_chan *chan, void *data);
|
||||
void l2cap_chan_list(struct l2cap_conn *conn, l2cap_chan_func_t func,
|
||||
void *data);
|
||||
void l2cap_chan_del(struct l2cap_chan *chan, int err);
|
||||
void l2cap_chan_del(struct l2cap_chan *chan, int err)
|
||||
__must_hold(&chan->lock) __must_hold(&chan->conn->lock);
|
||||
void l2cap_send_conn_req(struct l2cap_chan *chan);
|
||||
|
||||
struct l2cap_conn *l2cap_conn_get(struct l2cap_conn *conn);
|
||||
|
|
|
|||
|
|
@ -722,6 +722,8 @@ static int setup_netdev(struct l2cap_chan *chan, struct lowpan_btle_dev **dev)
|
|||
}
|
||||
|
||||
static inline void chan_ready_cb(struct l2cap_chan *chan)
|
||||
__must_hold(&chan->lock)
|
||||
__must_hold(&chan->conn->lock)
|
||||
{
|
||||
struct lowpan_btle_dev *dev;
|
||||
bool new_netdev = false;
|
||||
|
|
|
|||
|
|
@ -59,7 +59,8 @@ static void l2cap_tx(struct l2cap_chan *chan, struct l2cap_ctrl *control,
|
|||
static void l2cap_retrans_timeout(struct work_struct *work);
|
||||
static void l2cap_monitor_timeout(struct work_struct *work);
|
||||
static void l2cap_ack_timeout(struct work_struct *work);
|
||||
static void __l2cap_chan_close(struct l2cap_chan *chan, int reason);
|
||||
static void __l2cap_chan_close(struct l2cap_chan *chan, int reason)
|
||||
__must_hold(&chan->lock) __must_hold(&chan->conn->lock);
|
||||
|
||||
static inline u8 bdaddr_type(u8 link_type, u8 bdaddr_type)
|
||||
{
|
||||
|
|
@ -681,6 +682,8 @@ void l2cap_chan_add(struct l2cap_conn *conn, struct l2cap_chan *chan)
|
|||
|
||||
void l2cap_chan_del(struct l2cap_chan *chan, int err)
|
||||
{
|
||||
lockdep_assert(!chan->conn || lockdep_is_held(&chan->conn->lock));
|
||||
|
||||
__clear_chan_timer(chan);
|
||||
|
||||
BT_DBG("chan %p, err %d, state %s", chan, err,
|
||||
|
|
@ -812,12 +815,11 @@ static void l2cap_chan_le_connect_reject(struct l2cap_chan *chan)
|
|||
}
|
||||
|
||||
static void l2cap_chan_ecred_connect_reject(struct l2cap_chan *chan)
|
||||
__must_hold(&chan->lock)
|
||||
__must_hold(&chan->conn->lock)
|
||||
{
|
||||
l2cap_state_change(chan, BT_DISCONN);
|
||||
|
||||
lockdep_assert_held(&chan->lock);
|
||||
lockdep_assert_held(&chan->conn->lock);
|
||||
|
||||
__l2cap_ecred_conn_rsp_defer(chan);
|
||||
}
|
||||
|
||||
|
|
@ -848,8 +850,6 @@ static void __l2cap_chan_close(struct l2cap_chan *chan, int reason)
|
|||
|
||||
BT_DBG("chan %p state %s", chan, state_to_string(chan->state));
|
||||
|
||||
lockdep_assert_held(&chan->lock);
|
||||
|
||||
switch (chan->state) {
|
||||
case BT_LISTEN:
|
||||
chan->ops->teardown(chan, 0);
|
||||
|
|
@ -934,7 +934,10 @@ void l2cap_chan_close_unlocked(struct l2cap_chan *chan, int reason)
|
|||
bool have_conn;
|
||||
|
||||
have_conn = l2cap_chan_lock_conn(chan);
|
||||
__l2cap_chan_close(chan, reason);
|
||||
|
||||
/* Context analysis: consider chan->conn->lock held also if conn NULL */
|
||||
context_unsafe(__l2cap_chan_close(chan, reason));
|
||||
|
||||
l2cap_chan_unlock_conn(chan, have_conn);
|
||||
}
|
||||
EXPORT_SYMBOL(l2cap_chan_close_unlocked);
|
||||
|
|
@ -1336,6 +1339,8 @@ void l2cap_send_conn_req(struct l2cap_chan *chan)
|
|||
}
|
||||
|
||||
static void l2cap_chan_ready(struct l2cap_chan *chan)
|
||||
__must_hold(&chan->lock)
|
||||
__must_hold(&chan->conn->lock)
|
||||
{
|
||||
/* The channel may have already been flagged as connected in
|
||||
* case of receiving data before the L2CAP info req/rsp
|
||||
|
|
@ -1471,6 +1476,7 @@ static void l2cap_ecred_connect(struct l2cap_chan *chan)
|
|||
}
|
||||
|
||||
static void l2cap_le_start(struct l2cap_chan *chan)
|
||||
__must_hold(&chan->lock)
|
||||
__must_hold(&chan->conn->lock)
|
||||
{
|
||||
struct l2cap_conn *conn = chan->conn;
|
||||
|
|
@ -1492,6 +1498,7 @@ static void l2cap_le_start(struct l2cap_chan *chan)
|
|||
}
|
||||
|
||||
static void l2cap_start_connection(struct l2cap_chan *chan)
|
||||
__must_hold(&chan->lock)
|
||||
__must_hold(&chan->conn->lock)
|
||||
{
|
||||
if (chan->conn->hcon->type == LE_LINK) {
|
||||
|
|
@ -1542,6 +1549,7 @@ static bool l2cap_check_enc_key_size(struct hci_conn *hcon,
|
|||
}
|
||||
|
||||
static void l2cap_do_start(struct l2cap_chan *chan)
|
||||
__must_hold(&chan->lock)
|
||||
__must_hold(&chan->conn->lock)
|
||||
{
|
||||
struct l2cap_conn *conn = chan->conn;
|
||||
|
|
@ -1893,6 +1901,8 @@ static void l2cap_conn_del(struct hci_conn *hcon, int err)
|
|||
l2cap_chan_hold(chan);
|
||||
l2cap_chan_lock(chan);
|
||||
|
||||
lockdep_assert_held(&chan->conn->lock);
|
||||
|
||||
l2cap_chan_del(chan, err);
|
||||
|
||||
chan->ops->close(chan);
|
||||
|
|
@ -4218,6 +4228,8 @@ static struct l2cap_chan *l2cap_new_connection(struct l2cap_conn *conn,
|
|||
|
||||
__l2cap_chan_add(conn, chan);
|
||||
|
||||
lockdep_assert_held(&chan->conn->lock);
|
||||
|
||||
if (pchan->ops->new_connection &&
|
||||
pchan->ops->new_connection(pchan, chan) < 0) {
|
||||
l2cap_chan_del(chan, 0);
|
||||
|
|
@ -4419,6 +4431,8 @@ static int l2cap_connect_create_rsp(struct l2cap_conn *conn,
|
|||
|
||||
l2cap_chan_lock(chan);
|
||||
|
||||
lockdep_assert_held(&chan->conn->lock);
|
||||
|
||||
switch (result) {
|
||||
case L2CAP_CR_SUCCESS:
|
||||
if (__l2cap_get_chan_by_dcid(conn, dcid)) {
|
||||
|
|
@ -4520,6 +4534,8 @@ static inline int l2cap_config_req(struct l2cap_conn *conn,
|
|||
|
||||
l2cap_chan_lock(chan);
|
||||
|
||||
lockdep_assert_held(&chan->conn->lock);
|
||||
|
||||
if (chan->state != BT_CONFIG && chan->state != BT_CONNECT2 &&
|
||||
chan->state != BT_CONNECTED) {
|
||||
cmd_reject_invalid_cid(conn, cmd->ident, chan->scid,
|
||||
|
|
@ -4634,6 +4650,8 @@ static inline int l2cap_config_rsp(struct l2cap_conn *conn,
|
|||
|
||||
l2cap_chan_lock(chan);
|
||||
|
||||
lockdep_assert_held(&chan->conn->lock);
|
||||
|
||||
switch (result) {
|
||||
case L2CAP_CONF_SUCCESS:
|
||||
l2cap_conf_rfc_get(chan, rsp->data, len);
|
||||
|
|
@ -4743,6 +4761,8 @@ static inline int l2cap_disconnect_req(struct l2cap_conn *conn,
|
|||
|
||||
l2cap_chan_lock(chan);
|
||||
|
||||
lockdep_assert_held(&chan->conn->lock);
|
||||
|
||||
rsp.dcid = cpu_to_le16(chan->scid);
|
||||
rsp.scid = cpu_to_le16(chan->dcid);
|
||||
l2cap_send_cmd(conn, cmd->ident, L2CAP_DISCONN_RSP, sizeof(rsp), &rsp);
|
||||
|
|
@ -4783,6 +4803,8 @@ static inline int l2cap_disconnect_rsp(struct l2cap_conn *conn,
|
|||
|
||||
l2cap_chan_lock(chan);
|
||||
|
||||
lockdep_assert_held(&chan->conn->lock);
|
||||
|
||||
if (chan->state != BT_DISCONN) {
|
||||
l2cap_chan_unlock(chan);
|
||||
l2cap_chan_put(chan);
|
||||
|
|
@ -4995,6 +5017,8 @@ static int l2cap_le_connect_rsp(struct l2cap_conn *conn,
|
|||
|
||||
l2cap_chan_lock(chan);
|
||||
|
||||
lockdep_assert_held(&chan->conn->lock);
|
||||
|
||||
switch (result) {
|
||||
case L2CAP_CR_LE_SUCCESS:
|
||||
if (__l2cap_get_chan_by_dcid(conn, dcid)) {
|
||||
|
|
@ -5213,6 +5237,8 @@ static int l2cap_le_connect_req(struct l2cap_conn *conn,
|
|||
|
||||
l2cap_chan_lock(chan);
|
||||
|
||||
lockdep_assert_held(&chan->conn->lock);
|
||||
|
||||
bacpy(&chan->src, &conn->hcon->src);
|
||||
bacpy(&chan->dst, &conn->hcon->dst);
|
||||
chan->src_type = bdaddr_src_type(conn->hcon);
|
||||
|
|
@ -5444,6 +5470,8 @@ static inline int l2cap_ecred_conn_req(struct l2cap_conn *conn,
|
|||
|
||||
l2cap_chan_lock(chan);
|
||||
|
||||
lockdep_assert_held(&chan->conn->lock);
|
||||
|
||||
bacpy(&chan->src, &conn->hcon->src);
|
||||
bacpy(&chan->dst, &conn->hcon->dst);
|
||||
chan->src_type = bdaddr_src_type(conn->hcon);
|
||||
|
|
@ -5533,6 +5561,8 @@ static inline int l2cap_ecred_conn_rsp(struct l2cap_conn *conn,
|
|||
l2cap_chan_hold(chan);
|
||||
l2cap_chan_lock(chan);
|
||||
|
||||
lockdep_assert_held(&chan->conn->lock);
|
||||
|
||||
/* Check that there is a dcid for each pending channel */
|
||||
if (cmd_len < sizeof(dcid)) {
|
||||
l2cap_chan_del(chan, ECONNREFUSED);
|
||||
|
|
@ -5760,6 +5790,8 @@ static inline int l2cap_ecred_reconf_rsp(struct l2cap_conn *conn,
|
|||
continue;
|
||||
l2cap_chan_lock(chan);
|
||||
|
||||
lockdep_assert_held(&chan->conn->lock);
|
||||
|
||||
l2cap_chan_del(chan, ECONNRESET);
|
||||
|
||||
l2cap_chan_unlock(chan);
|
||||
|
|
@ -5789,6 +5821,7 @@ static inline int l2cap_le_command_rej(struct l2cap_conn *conn,
|
|||
goto done;
|
||||
|
||||
l2cap_chan_lock(chan);
|
||||
lockdep_assert_held(&chan->conn->lock);
|
||||
l2cap_chan_del(chan, ECONNREFUSED);
|
||||
l2cap_chan_unlock(chan);
|
||||
l2cap_chan_put(chan);
|
||||
|
|
@ -7184,6 +7217,8 @@ static void l2cap_data_channel(struct l2cap_conn *conn, u16 cid,
|
|||
|
||||
l2cap_chan_lock(chan);
|
||||
|
||||
lockdep_assert_held(&chan->conn->lock);
|
||||
|
||||
BT_DBG("chan %p, len %d", chan, skb->len);
|
||||
|
||||
/* If we receive data on a fixed channel before the info req/rsp
|
||||
|
|
|
|||
Loading…
Reference in New Issue
Block a user