Bluetooth: Use RCU to manipulate chan_list
Instead of using tasklet_disable() to prevent acess to the channel use, we can use RCU and improve the performance of our code. Acked-by: Marcel Holtmann <marcel@holtmann.org> Signed-off-by: Gustavo F. Padovan <padovan@profusion.mobi>
This commit is contained in:
parent
d01b2ff4e6
commit
8192edef03
|
@ -960,9 +960,7 @@ struct hci_chan *hci_chan_create(struct hci_conn *conn)
|
||||||
chan->conn = conn;
|
chan->conn = conn;
|
||||||
skb_queue_head_init(&chan->data_q);
|
skb_queue_head_init(&chan->data_q);
|
||||||
|
|
||||||
tasklet_disable(&hdev->tx_task);
|
list_add_rcu(&chan->list, &conn->chan_list);
|
||||||
list_add(&conn->chan_list, &chan->list);
|
|
||||||
tasklet_enable(&hdev->tx_task);
|
|
||||||
|
|
||||||
return chan;
|
return chan;
|
||||||
}
|
}
|
||||||
|
@ -974,9 +972,9 @@ int hci_chan_del(struct hci_chan *chan)
|
||||||
|
|
||||||
BT_DBG("%s conn %p chan %p", hdev->name, conn, chan);
|
BT_DBG("%s conn %p chan %p", hdev->name, conn, chan);
|
||||||
|
|
||||||
tasklet_disable(&hdev->tx_task);
|
list_del_rcu(&chan->list);
|
||||||
list_del(&chan->list);
|
|
||||||
tasklet_enable(&hdev->tx_task);
|
synchronize_rcu();
|
||||||
|
|
||||||
skb_queue_purge(&chan->data_q);
|
skb_queue_purge(&chan->data_q);
|
||||||
kfree(chan);
|
kfree(chan);
|
||||||
|
@ -986,10 +984,10 @@ int hci_chan_del(struct hci_chan *chan)
|
||||||
|
|
||||||
void hci_chan_list_flush(struct hci_conn *conn)
|
void hci_chan_list_flush(struct hci_conn *conn)
|
||||||
{
|
{
|
||||||
struct hci_chan *chan, *tmp;
|
struct hci_chan *chan;
|
||||||
|
|
||||||
BT_DBG("conn %p", conn);
|
BT_DBG("conn %p", conn);
|
||||||
|
|
||||||
list_for_each_entry_safe(chan, tmp, &conn->chan_list, list)
|
list_for_each_entry_rcu(chan, &conn->chan_list, list)
|
||||||
hci_chan_del(chan);
|
hci_chan_del(chan);
|
||||||
}
|
}
|
||||||
|
|
|
@ -2135,7 +2135,9 @@ static inline struct hci_chan *hci_chan_sent(struct hci_dev *hdev, __u8 type,
|
||||||
|
|
||||||
conn_num++;
|
conn_num++;
|
||||||
|
|
||||||
list_for_each_entry(tmp, &conn->chan_list, list) {
|
rcu_read_lock();
|
||||||
|
|
||||||
|
list_for_each_entry_rcu(tmp, &conn->chan_list, list) {
|
||||||
struct sk_buff *skb;
|
struct sk_buff *skb;
|
||||||
|
|
||||||
if (skb_queue_empty(&tmp->data_q))
|
if (skb_queue_empty(&tmp->data_q))
|
||||||
|
@ -2159,6 +2161,8 @@ static inline struct hci_chan *hci_chan_sent(struct hci_dev *hdev, __u8 type,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
rcu_read_unlock();
|
||||||
|
|
||||||
if (hci_conn_num(hdev, type) == conn_num)
|
if (hci_conn_num(hdev, type) == conn_num)
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
@ -2207,7 +2211,9 @@ static void hci_prio_recalculate(struct hci_dev *hdev, __u8 type)
|
||||||
|
|
||||||
num++;
|
num++;
|
||||||
|
|
||||||
list_for_each_entry(chan, &conn->chan_list, list) {
|
rcu_read_lock();
|
||||||
|
|
||||||
|
list_for_each_entry_rcu(chan, &conn->chan_list, list) {
|
||||||
struct sk_buff *skb;
|
struct sk_buff *skb;
|
||||||
|
|
||||||
if (chan->sent) {
|
if (chan->sent) {
|
||||||
|
@ -2228,6 +2234,8 @@ static void hci_prio_recalculate(struct hci_dev *hdev, __u8 type)
|
||||||
skb->priority);
|
skb->priority);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
rcu_read_unlock();
|
||||||
|
|
||||||
if (hci_conn_num(hdev, type) == num)
|
if (hci_conn_num(hdev, type) == num)
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue