diff options
author | Johan Hedberg <johan.hedberg@intel.com> | 2014-11-19 08:22:22 -0500 |
---|---|---|
committer | Marcel Holtmann <marcel@holtmann.org> | 2014-11-19 10:19:47 -0500 |
commit | 0378b59770130a994272b176a2a4346dc27361e9 (patch) | |
tree | 38615471a8b13d1e3b4d8d0ad5bfee0b75053249 | |
parent | cb6f3f7ace0e61285db22508a9efd8a5aeca0af5 (diff) |
Bluetooth: Convert link keys list to use RCU
This patch converts the hdev->link_keys list to be protected through
RCU, thereby eliminating the need to hold the hdev lock while accessing
the list.
Signed-off-by: Johan Hedberg <johan.hedberg@intel.com>
Signed-off-by: Marcel Holtmann <marcel@holtmann.org>
-rw-r--r-- | include/net/bluetooth/hci_core.h | 1 | ||||
-rw-r--r-- | net/bluetooth/hci_core.c | 37 | ||||
-rw-r--r-- | net/bluetooth/hci_event.c | 4 |
3 files changed, 21 insertions, 21 deletions
diff --git a/include/net/bluetooth/hci_core.h b/include/net/bluetooth/hci_core.h index a805b3d97c0b..396c09840fdf 100644 --- a/include/net/bluetooth/hci_core.h +++ b/include/net/bluetooth/hci_core.h | |||
@@ -130,6 +130,7 @@ struct smp_irk { | |||
130 | 130 | ||
131 | struct link_key { | 131 | struct link_key { |
132 | struct list_head list; | 132 | struct list_head list; |
133 | struct rcu_head rcu; | ||
133 | bdaddr_t bdaddr; | 134 | bdaddr_t bdaddr; |
134 | u8 type; | 135 | u8 type; |
135 | u8 val[HCI_LINK_KEY_SIZE]; | 136 | u8 val[HCI_LINK_KEY_SIZE]; |
diff --git a/net/bluetooth/hci_core.c b/net/bluetooth/hci_core.c index a67a4b8e4e1c..5c319a49a5a4 100644 --- a/net/bluetooth/hci_core.c +++ b/net/bluetooth/hci_core.c | |||
@@ -274,15 +274,13 @@ static const struct file_operations inquiry_cache_fops = { | |||
274 | static int link_keys_show(struct seq_file *f, void *ptr) | 274 | static int link_keys_show(struct seq_file *f, void *ptr) |
275 | { | 275 | { |
276 | struct hci_dev *hdev = f->private; | 276 | struct hci_dev *hdev = f->private; |
277 | struct list_head *p, *n; | 277 | struct link_key *key; |
278 | 278 | ||
279 | hci_dev_lock(hdev); | 279 | rcu_read_lock(); |
280 | list_for_each_safe(p, n, &hdev->link_keys) { | 280 | list_for_each_entry_rcu(key, &hdev->link_keys, list) |
281 | struct link_key *key = list_entry(p, struct link_key, list); | ||
282 | seq_printf(f, "%pMR %u %*phN %u\n", &key->bdaddr, key->type, | 281 | seq_printf(f, "%pMR %u %*phN %u\n", &key->bdaddr, key->type, |
283 | HCI_LINK_KEY_SIZE, key->val, key->pin_len); | 282 | HCI_LINK_KEY_SIZE, key->val, key->pin_len); |
284 | } | 283 | rcu_read_unlock(); |
285 | hci_dev_unlock(hdev); | ||
286 | 284 | ||
287 | return 0; | 285 | return 0; |
288 | } | 286 | } |
@@ -3101,15 +3099,11 @@ void hci_uuids_clear(struct hci_dev *hdev) | |||
3101 | 3099 | ||
3102 | void hci_link_keys_clear(struct hci_dev *hdev) | 3100 | void hci_link_keys_clear(struct hci_dev *hdev) |
3103 | { | 3101 | { |
3104 | struct list_head *p, *n; | 3102 | struct link_key *key; |
3105 | |||
3106 | list_for_each_safe(p, n, &hdev->link_keys) { | ||
3107 | struct link_key *key; | ||
3108 | |||
3109 | key = list_entry(p, struct link_key, list); | ||
3110 | 3103 | ||
3111 | list_del(p); | 3104 | list_for_each_entry_rcu(key, &hdev->link_keys, list) { |
3112 | kfree(key); | 3105 | list_del_rcu(&key->list); |
3106 | kfree_rcu(key, rcu); | ||
3113 | } | 3107 | } |
3114 | } | 3108 | } |
3115 | 3109 | ||
@@ -3137,9 +3131,14 @@ struct link_key *hci_find_link_key(struct hci_dev *hdev, bdaddr_t *bdaddr) | |||
3137 | { | 3131 | { |
3138 | struct link_key *k; | 3132 | struct link_key *k; |
3139 | 3133 | ||
3140 | list_for_each_entry(k, &hdev->link_keys, list) | 3134 | rcu_read_lock(); |
3141 | if (bacmp(bdaddr, &k->bdaddr) == 0) | 3135 | list_for_each_entry_rcu(k, &hdev->link_keys, list) { |
3136 | if (bacmp(bdaddr, &k->bdaddr) == 0) { | ||
3137 | rcu_read_unlock(); | ||
3142 | return k; | 3138 | return k; |
3139 | } | ||
3140 | } | ||
3141 | rcu_read_unlock(); | ||
3143 | 3142 | ||
3144 | return NULL; | 3143 | return NULL; |
3145 | } | 3144 | } |
@@ -3290,7 +3289,7 @@ struct link_key *hci_add_link_key(struct hci_dev *hdev, struct hci_conn *conn, | |||
3290 | key = kzalloc(sizeof(*key), GFP_KERNEL); | 3289 | key = kzalloc(sizeof(*key), GFP_KERNEL); |
3291 | if (!key) | 3290 | if (!key) |
3292 | return NULL; | 3291 | return NULL; |
3293 | list_add(&key->list, &hdev->link_keys); | 3292 | list_add_rcu(&key->list, &hdev->link_keys); |
3294 | } | 3293 | } |
3295 | 3294 | ||
3296 | BT_DBG("%s key for %pMR type %u", hdev->name, bdaddr, type); | 3295 | BT_DBG("%s key for %pMR type %u", hdev->name, bdaddr, type); |
@@ -3383,8 +3382,8 @@ int hci_remove_link_key(struct hci_dev *hdev, bdaddr_t *bdaddr) | |||
3383 | 3382 | ||
3384 | BT_DBG("%s removing %pMR", hdev->name, bdaddr); | 3383 | BT_DBG("%s removing %pMR", hdev->name, bdaddr); |
3385 | 3384 | ||
3386 | list_del(&key->list); | 3385 | list_del_rcu(&key->list); |
3387 | kfree(key); | 3386 | kfree_rcu(key, rcu); |
3388 | 3387 | ||
3389 | return 0; | 3388 | return 0; |
3390 | } | 3389 | } |
diff --git a/net/bluetooth/hci_event.c b/net/bluetooth/hci_event.c index 54680fd39608..bd0a80120665 100644 --- a/net/bluetooth/hci_event.c +++ b/net/bluetooth/hci_event.c | |||
@@ -3324,8 +3324,8 @@ static void hci_link_key_notify_evt(struct hci_dev *hdev, struct sk_buff *skb) | |||
3324 | */ | 3324 | */ |
3325 | if (key->type == HCI_LK_DEBUG_COMBINATION && | 3325 | if (key->type == HCI_LK_DEBUG_COMBINATION && |
3326 | !test_bit(HCI_KEEP_DEBUG_KEYS, &hdev->dev_flags)) { | 3326 | !test_bit(HCI_KEEP_DEBUG_KEYS, &hdev->dev_flags)) { |
3327 | list_del(&key->list); | 3327 | list_del_rcu(&key->list); |
3328 | kfree(key); | 3328 | kfree_rcu(key, rcu); |
3329 | } else if (conn) { | 3329 | } else if (conn) { |
3330 | if (persistent) | 3330 | if (persistent) |
3331 | clear_bit(HCI_CONN_FLUSH_KEY, &conn->flags); | 3331 | clear_bit(HCI_CONN_FLUSH_KEY, &conn->flags); |