aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorGustavo F. Padovan <padovan@profusion.mobi>2011-12-14 19:54:12 -0500
committerGustavo F. Padovan <padovan@profusion.mobi>2011-12-18 14:07:56 -0500
commitbf4c63252490ba78fb833cc7acf1a5b1900c970f (patch)
tree628e5d6a2b0214a8d6d4c85ce61177a9fd59cbc5
parent8192edef03f9b47f1cc1120724db525e63e218f3 (diff)
Bluetooth: convert conn hash to RCU
Handling hci_conn_hash with RCU make us avoid some locking and disable tasklets. Acked-by: Marcel Holtmann <marcel@holtmann.org> Signed-off-by: Gustavo F. Padovan <padovan@profusion.mobi>
-rw-r--r--include/net/bluetooth/hci_core.h45
-rw-r--r--net/bluetooth/hci_conn.c19
-rw-r--r--net/bluetooth/hci_core.c34
3 files changed, 62 insertions, 36 deletions
diff --git a/include/net/bluetooth/hci_core.h b/include/net/bluetooth/hci_core.h
index 14b200b08d84..e83243318924 100644
--- a/include/net/bluetooth/hci_core.h
+++ b/include/net/bluetooth/hci_core.h
@@ -392,7 +392,7 @@ static inline void hci_conn_hash_init(struct hci_dev *hdev)
392static inline void hci_conn_hash_add(struct hci_dev *hdev, struct hci_conn *c) 392static inline void hci_conn_hash_add(struct hci_dev *hdev, struct hci_conn *c)
393{ 393{
394 struct hci_conn_hash *h = &hdev->conn_hash; 394 struct hci_conn_hash *h = &hdev->conn_hash;
395 list_add(&c->list, &h->list); 395 list_add_rcu(&c->list, &h->list);
396 switch (c->type) { 396 switch (c->type) {
397 case ACL_LINK: 397 case ACL_LINK:
398 h->acl_num++; 398 h->acl_num++;
@@ -410,7 +410,10 @@ static inline void hci_conn_hash_add(struct hci_dev *hdev, struct hci_conn *c)
410static inline void hci_conn_hash_del(struct hci_dev *hdev, struct hci_conn *c) 410static inline void hci_conn_hash_del(struct hci_dev *hdev, struct hci_conn *c)
411{ 411{
412 struct hci_conn_hash *h = &hdev->conn_hash; 412 struct hci_conn_hash *h = &hdev->conn_hash;
413 list_del(&c->list); 413
414 list_del_rcu(&c->list);
415 synchronize_rcu();
416
414 switch (c->type) { 417 switch (c->type) {
415 case ACL_LINK: 418 case ACL_LINK:
416 h->acl_num--; 419 h->acl_num--;
@@ -445,14 +448,18 @@ static inline struct hci_conn *hci_conn_hash_lookup_handle(struct hci_dev *hdev,
445 __u16 handle) 448 __u16 handle)
446{ 449{
447 struct hci_conn_hash *h = &hdev->conn_hash; 450 struct hci_conn_hash *h = &hdev->conn_hash;
448 struct list_head *p;
449 struct hci_conn *c; 451 struct hci_conn *c;
450 452
451 list_for_each(p, &h->list) { 453 rcu_read_lock();
452 c = list_entry(p, struct hci_conn, list); 454
453 if (c->handle == handle) 455 list_for_each_entry_rcu(c, &h->list, list) {
456 if (c->handle == handle) {
457 rcu_read_unlock();
454 return c; 458 return c;
459 }
455 } 460 }
461 rcu_read_unlock();
462
456 return NULL; 463 return NULL;
457} 464}
458 465
@@ -460,14 +467,19 @@ static inline struct hci_conn *hci_conn_hash_lookup_ba(struct hci_dev *hdev,
460 __u8 type, bdaddr_t *ba) 467 __u8 type, bdaddr_t *ba)
461{ 468{
462 struct hci_conn_hash *h = &hdev->conn_hash; 469 struct hci_conn_hash *h = &hdev->conn_hash;
463 struct list_head *p;
464 struct hci_conn *c; 470 struct hci_conn *c;
465 471
466 list_for_each(p, &h->list) { 472 rcu_read_lock();
467 c = list_entry(p, struct hci_conn, list); 473
468 if (c->type == type && !bacmp(&c->dst, ba)) 474 list_for_each_entry_rcu(c, &h->list, list) {
475 if (c->type == type && !bacmp(&c->dst, ba)) {
476 rcu_read_unlock();
469 return c; 477 return c;
478 }
470 } 479 }
480
481 rcu_read_unlock();
482
471 return NULL; 483 return NULL;
472} 484}
473 485
@@ -475,14 +487,19 @@ static inline struct hci_conn *hci_conn_hash_lookup_state(struct hci_dev *hdev,
475 __u8 type, __u16 state) 487 __u8 type, __u16 state)
476{ 488{
477 struct hci_conn_hash *h = &hdev->conn_hash; 489 struct hci_conn_hash *h = &hdev->conn_hash;
478 struct list_head *p;
479 struct hci_conn *c; 490 struct hci_conn *c;
480 491
481 list_for_each(p, &h->list) { 492 rcu_read_lock();
482 c = list_entry(p, struct hci_conn, list); 493
483 if (c->type == type && c->state == state) 494 list_for_each_entry_rcu(c, &h->list, list) {
495 if (c->type == type && c->state == state) {
496 rcu_read_unlock();
484 return c; 497 return c;
498 }
485 } 499 }
500
501 rcu_read_unlock();
502
486 return NULL; 503 return NULL;
487} 504}
488 505
diff --git a/net/bluetooth/hci_conn.c b/net/bluetooth/hci_conn.c
index b04467674a13..5e9e193ac71e 100644
--- a/net/bluetooth/hci_conn.c
+++ b/net/bluetooth/hci_conn.c
@@ -418,18 +418,17 @@ struct hci_conn *hci_conn_add(struct hci_dev *hdev, int type, bdaddr_t *dst)
418 418
419 hci_dev_hold(hdev); 419 hci_dev_hold(hdev);
420 420
421 tasklet_disable(&hdev->tx_task);
422
423 hci_conn_hash_add(hdev, conn); 421 hci_conn_hash_add(hdev, conn);
424 if (hdev->notify) 422 if (hdev->notify) {
423 tasklet_disable(&hdev->tx_task);
425 hdev->notify(hdev, HCI_NOTIFY_CONN_ADD); 424 hdev->notify(hdev, HCI_NOTIFY_CONN_ADD);
425 tasklet_enable(&hdev->tx_task);
426 }
426 427
427 atomic_set(&conn->devref, 0); 428 atomic_set(&conn->devref, 0);
428 429
429 hci_conn_init_sysfs(conn); 430 hci_conn_init_sysfs(conn);
430 431
431 tasklet_enable(&hdev->tx_task);
432
433 return conn; 432 return conn;
434} 433}
435 434
@@ -465,15 +464,15 @@ int hci_conn_del(struct hci_conn *conn)
465 } 464 }
466 } 465 }
467 466
468 tasklet_disable(&hdev->tx_task);
469 467
470 hci_chan_list_flush(conn); 468 hci_chan_list_flush(conn);
471 469
472 hci_conn_hash_del(hdev, conn); 470 hci_conn_hash_del(hdev, conn);
473 if (hdev->notify) 471 if (hdev->notify) {
472 tasklet_disable(&hdev->tx_task);
474 hdev->notify(hdev, HCI_NOTIFY_CONN_DEL); 473 hdev->notify(hdev, HCI_NOTIFY_CONN_DEL);
475 474 tasklet_enable(&hdev->tx_task);
476 tasklet_enable(&hdev->tx_task); 475 }
477 476
478 skb_queue_purge(&conn->data_q); 477 skb_queue_purge(&conn->data_q);
479 478
@@ -808,7 +807,7 @@ void hci_conn_hash_flush(struct hci_dev *hdev)
808 807
809 BT_DBG("hdev %s", hdev->name); 808 BT_DBG("hdev %s", hdev->name);
810 809
811 list_for_each_entry(c, &h->list, list) { 810 list_for_each_entry_rcu(c, &h->list, list) {
812 c->state = BT_CLOSED; 811 c->state = BT_CLOSED;
813 812
814 hci_proto_disconn_cfm(c, HCI_ERROR_LOCAL_HOST_TERM); 813 hci_proto_disconn_cfm(c, HCI_ERROR_LOCAL_HOST_TERM);
diff --git a/net/bluetooth/hci_core.c b/net/bluetooth/hci_core.c
index 2c4f32f44569..de923ee60093 100644
--- a/net/bluetooth/hci_core.c
+++ b/net/bluetooth/hci_core.c
@@ -2050,7 +2050,10 @@ static inline struct hci_conn *hci_low_sent(struct hci_dev *hdev, __u8 type, int
2050 2050
2051 /* We don't have to lock device here. Connections are always 2051 /* We don't have to lock device here. Connections are always
2052 * added and removed with TX task disabled. */ 2052 * added and removed with TX task disabled. */
2053 list_for_each_entry(c, &h->list, list) { 2053
2054 rcu_read_lock();
2055
2056 list_for_each_entry_rcu(c, &h->list, list) {
2054 if (c->type != type || skb_queue_empty(&c->data_q)) 2057 if (c->type != type || skb_queue_empty(&c->data_q))
2055 continue; 2058 continue;
2056 2059
@@ -2068,6 +2071,8 @@ static inline struct hci_conn *hci_low_sent(struct hci_dev *hdev, __u8 type, int
2068 break; 2071 break;
2069 } 2072 }
2070 2073
2074 rcu_read_unlock();
2075
2071 if (conn) { 2076 if (conn) {
2072 int cnt, q; 2077 int cnt, q;
2073 2078
@@ -2103,14 +2108,18 @@ static inline void hci_link_tx_to(struct hci_dev *hdev, __u8 type)
2103 2108
2104 BT_ERR("%s link tx timeout", hdev->name); 2109 BT_ERR("%s link tx timeout", hdev->name);
2105 2110
2111 rcu_read_lock();
2112
2106 /* Kill stalled connections */ 2113 /* Kill stalled connections */
2107 list_for_each_entry(c, &h->list, list) { 2114 list_for_each_entry_rcu(c, &h->list, list) {
2108 if (c->type == type && c->sent) { 2115 if (c->type == type && c->sent) {
2109 BT_ERR("%s killing stalled connection %s", 2116 BT_ERR("%s killing stalled connection %s",
2110 hdev->name, batostr(&c->dst)); 2117 hdev->name, batostr(&c->dst));
2111 hci_acl_disconn(c, 0x13); 2118 hci_acl_disconn(c, 0x13);
2112 } 2119 }
2113 } 2120 }
2121
2122 rcu_read_unlock();
2114} 2123}
2115 2124
2116static inline struct hci_chan *hci_chan_sent(struct hci_dev *hdev, __u8 type, 2125static inline struct hci_chan *hci_chan_sent(struct hci_dev *hdev, __u8 type,
@@ -2124,7 +2133,9 @@ static inline struct hci_chan *hci_chan_sent(struct hci_dev *hdev, __u8 type,
2124 2133
2125 BT_DBG("%s", hdev->name); 2134 BT_DBG("%s", hdev->name);
2126 2135
2127 list_for_each_entry(conn, &h->list, list) { 2136 rcu_read_lock();
2137
2138 list_for_each_entry_rcu(conn, &h->list, list) {
2128 struct hci_chan *tmp; 2139 struct hci_chan *tmp;
2129 2140
2130 if (conn->type != type) 2141 if (conn->type != type)
@@ -2135,8 +2146,6 @@ static inline struct hci_chan *hci_chan_sent(struct hci_dev *hdev, __u8 type,
2135 2146
2136 conn_num++; 2147 conn_num++;
2137 2148
2138 rcu_read_lock();
2139
2140 list_for_each_entry_rcu(tmp, &conn->chan_list, list) { 2149 list_for_each_entry_rcu(tmp, &conn->chan_list, list) {
2141 struct sk_buff *skb; 2150 struct sk_buff *skb;
2142 2151
@@ -2161,12 +2170,12 @@ static inline struct hci_chan *hci_chan_sent(struct hci_dev *hdev, __u8 type,
2161 } 2170 }
2162 } 2171 }
2163 2172
2164 rcu_read_unlock();
2165
2166 if (hci_conn_num(hdev, type) == conn_num) 2173 if (hci_conn_num(hdev, type) == conn_num)
2167 break; 2174 break;
2168 } 2175 }
2169 2176
2177 rcu_read_unlock();
2178
2170 if (!chan) 2179 if (!chan)
2171 return NULL; 2180 return NULL;
2172 2181
@@ -2200,7 +2209,9 @@ static void hci_prio_recalculate(struct hci_dev *hdev, __u8 type)
2200 2209
2201 BT_DBG("%s", hdev->name); 2210 BT_DBG("%s", hdev->name);
2202 2211
2203 list_for_each_entry(conn, &h->list, list) { 2212 rcu_read_lock();
2213
2214 list_for_each_entry_rcu(conn, &h->list, list) {
2204 struct hci_chan *chan; 2215 struct hci_chan *chan;
2205 2216
2206 if (conn->type != type) 2217 if (conn->type != type)
@@ -2211,8 +2222,6 @@ static void hci_prio_recalculate(struct hci_dev *hdev, __u8 type)
2211 2222
2212 num++; 2223 num++;
2213 2224
2214 rcu_read_lock();
2215
2216 list_for_each_entry_rcu(chan, &conn->chan_list, list) { 2225 list_for_each_entry_rcu(chan, &conn->chan_list, list) {
2217 struct sk_buff *skb; 2226 struct sk_buff *skb;
2218 2227
@@ -2234,11 +2243,12 @@ static void hci_prio_recalculate(struct hci_dev *hdev, __u8 type)
2234 skb->priority); 2243 skb->priority);
2235 } 2244 }
2236 2245
2237 rcu_read_unlock();
2238
2239 if (hci_conn_num(hdev, type) == num) 2246 if (hci_conn_num(hdev, type) == num)
2240 break; 2247 break;
2241 } 2248 }
2249
2250 rcu_read_unlock();
2251
2242} 2252}
2243 2253
2244static inline void hci_sched_acl(struct hci_dev *hdev) 2254static inline void hci_sched_acl(struct hci_dev *hdev)