Bluetooth: Use RCU to manipulate chan_list
authorGustavo F. Padovan <padovan@profusion.mobi>
Wed, 14 Dec 2011 17:08:48 +0000 (15:08 -0200)
committerGustavo F. Padovan <padovan@profusion.mobi>
Sun, 18 Dec 2011 19:07:56 +0000 (17:07 -0200)
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>

net/bluetooth/hci_conn.c
net/bluetooth/hci_core.c

index e6d8a22..b044676 100644 (file)
@@ -960,9 +960,7 @@ struct hci_chan *hci_chan_create(struct hci_conn *conn)
        chan->conn = conn;
        skb_queue_head_init(&chan->data_q);
 
-       tasklet_disable(&hdev->tx_task);
-       list_add(&conn->chan_list, &chan->list);
-       tasklet_enable(&hdev->tx_task);
+       list_add_rcu(&chan->list, &conn->chan_list);
 
        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);
 
-       tasklet_disable(&hdev->tx_task);
-       list_del(&chan->list);
-       tasklet_enable(&hdev->tx_task);
+       list_del_rcu(&chan->list);
+
+       synchronize_rcu();
 
        skb_queue_purge(&chan->data_q);
        kfree(chan);
@@ -986,10 +984,10 @@ int hci_chan_del(struct hci_chan *chan)
 
 void hci_chan_list_flush(struct hci_conn *conn)
 {
-       struct hci_chan *chan, *tmp;
+       struct hci_chan *chan;
 
        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);
 }
index 36763aa..2c4f32f 100644 (file)
@@ -2135,7 +2135,9 @@ static inline struct hci_chan *hci_chan_sent(struct hci_dev *hdev, __u8 type,
 
                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;
 
                        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)
                        break;
        }
@@ -2207,7 +2211,9 @@ static void hci_prio_recalculate(struct hci_dev *hdev, __u8 type)
 
                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;
 
                        if (chan->sent) {
@@ -2228,6 +2234,8 @@ static void hci_prio_recalculate(struct hci_dev *hdev, __u8 type)
                                                                skb->priority);
                }
 
+               rcu_read_unlock();
+
                if (hci_conn_num(hdev, type) == num)
                        break;
        }