Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 8192edef authored by Gustavo Padovan's avatar Gustavo Padovan
Browse files

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: default avatarMarcel Holtmann <marcel@holtmann.org>
Signed-off-by: default avatarGustavo F. Padovan <padovan@profusion.mobi>
parent d01b2ff4
Loading
Loading
Loading
Loading
+6 −8
Original line number Original line Diff line number Diff line
@@ -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);
}
}
+10 −2
Original line number Original line Diff line number Diff line
@@ -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;
	}
	}