diff options
author | Gustavo F. Padovan <padovan@profusion.mobi> | 2011-12-14 19:54:12 -0500 |
---|---|---|
committer | Gustavo F. Padovan <padovan@profusion.mobi> | 2011-12-18 14:07:56 -0500 |
commit | bf4c63252490ba78fb833cc7acf1a5b1900c970f (patch) | |
tree | 628e5d6a2b0214a8d6d4c85ce61177a9fd59cbc5 | |
parent | 8192edef03f9b47f1cc1120724db525e63e218f3 (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.h | 45 | ||||
-rw-r--r-- | net/bluetooth/hci_conn.c | 19 | ||||
-rw-r--r-- | net/bluetooth/hci_core.c | 34 |
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) | |||
392 | static inline void hci_conn_hash_add(struct hci_dev *hdev, struct hci_conn *c) | 392 | static 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) | |||
410 | static inline void hci_conn_hash_del(struct hci_dev *hdev, struct hci_conn *c) | 410 | static 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 | ||
2116 | static inline struct hci_chan *hci_chan_sent(struct hci_dev *hdev, __u8 type, | 2125 | static 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 | ||
2244 | static inline void hci_sched_acl(struct hci_dev *hdev) | 2254 | static inline void hci_sched_acl(struct hci_dev *hdev) |