aboutsummaryrefslogtreecommitdiffstats
path: root/net/bluetooth/hci_core.c
diff options
context:
space:
mode:
authorJohan Hedberg <johan.hedberg@intel.com>2014-11-19 08:22:22 -0500
committerMarcel Holtmann <marcel@holtmann.org>2014-11-19 10:19:47 -0500
commit0378b59770130a994272b176a2a4346dc27361e9 (patch)
tree38615471a8b13d1e3b4d8d0ad5bfee0b75053249 /net/bluetooth/hci_core.c
parentcb6f3f7ace0e61285db22508a9efd8a5aeca0af5 (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>
Diffstat (limited to 'net/bluetooth/hci_core.c')
-rw-r--r--net/bluetooth/hci_core.c37
1 files changed, 18 insertions, 19 deletions
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 = {
274static int link_keys_show(struct seq_file *f, void *ptr) 274static 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
3102void hci_link_keys_clear(struct hci_dev *hdev) 3100void 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}