Bluetooth: Really fix registering hci with duplicate name

Commit fc50744 ("Bluetooth: Fix registering hci with duplicate name") didn't
fully fix the duplicate naming issue with devices, and duplicate device names
could still be created:

[  142.484097] device: 'hci1': device_add
[...]
[  150.545263] device: 'hci1': device_add
[  150.550128] kobject: 'hci1' (ffff880014cc4e58): kobject_add_internal: parent: 'bluetooth', set: 'devices'
[  150.558979] ------------[ cut here ]------------
[  150.561438] WARNING: at fs/sysfs/dir.c:529 sysfs_add_one+0xb0/0xd0()
[  150.572974] Hardware name: Bochs
[  150.580502] sysfs: cannot create duplicate filename '/devices/virtual/bluetooth/hci1'
[  150.584444] Pid: 7563, comm: trinity-child1 Tainted: G        W    3.4.0-next-20120524-sasha #296
[...]

Instead of the weird logic and the attempt at keeping the device list sorted,
just use an IDA.

Signed-off-by: Sasha Levin <levinsasha928@gmail.com>
Signed-off-by: Marcel Holtmann <marcel@holtmann.org>
This commit is contained in:
Sasha Levin 2012-05-27 22:36:56 +02:00 committed by Johan Hedberg
parent 6754e0df13
commit 3df92b31b2

View File

@ -26,6 +26,7 @@
/* Bluetooth HCI core. */ /* Bluetooth HCI core. */
#include <linux/export.h> #include <linux/export.h>
#include <linux/idr.h>
#include <linux/rfkill.h> #include <linux/rfkill.h>
@ -46,6 +47,9 @@ DEFINE_RWLOCK(hci_dev_list_lock);
LIST_HEAD(hci_cb_list); LIST_HEAD(hci_cb_list);
DEFINE_RWLOCK(hci_cb_list_lock); DEFINE_RWLOCK(hci_cb_list_lock);
/* HCI ID Numbering */
static DEFINE_IDA(hci_index_ida);
/* ---- HCI notifications ---- */ /* ---- HCI notifications ---- */
static void hci_notify(struct hci_dev *hdev, int event) static void hci_notify(struct hci_dev *hdev, int event)
@ -1689,37 +1693,35 @@ EXPORT_SYMBOL(hci_free_dev);
/* Register HCI device */ /* Register HCI device */
int hci_register_dev(struct hci_dev *hdev) int hci_register_dev(struct hci_dev *hdev)
{ {
struct list_head *head, *p;
int id, error; int id, error;
if (!hdev->open || !hdev->close) if (!hdev->open || !hdev->close)
return -EINVAL; return -EINVAL;
write_lock(&hci_dev_list_lock);
/* Do not allow HCI_AMP devices to register at index 0, /* Do not allow HCI_AMP devices to register at index 0,
* so the index can be used as the AMP controller ID. * so the index can be used as the AMP controller ID.
*/ */
id = (hdev->dev_type == HCI_BREDR) ? 0 : 1; switch (hdev->dev_type) {
head = &hci_dev_list; case HCI_BREDR:
id = ida_simple_get(&hci_index_ida, 0, 0, GFP_KERNEL);
/* Find first available device id */ break;
list_for_each(p, &hci_dev_list) { case HCI_AMP:
int nid = list_entry(p, struct hci_dev, list)->id; id = ida_simple_get(&hci_index_ida, 1, 0, GFP_KERNEL);
if (nid > id) break;
break; default:
if (nid == id) return -EINVAL;
id++;
head = p;
} }
if (id < 0)
return id;
sprintf(hdev->name, "hci%d", id); sprintf(hdev->name, "hci%d", id);
hdev->id = id; hdev->id = id;
BT_DBG("%p name %s bus %d", hdev, hdev->name, hdev->bus); BT_DBG("%p name %s bus %d", hdev, hdev->name, hdev->bus);
list_add(&hdev->list, head); write_lock(&hci_dev_list_lock);
list_add(&hdev->list, &hci_dev_list);
write_unlock(&hci_dev_list_lock); write_unlock(&hci_dev_list_lock);
hdev->workqueue = alloc_workqueue(hdev->name, WQ_HIGHPRI | WQ_UNBOUND | hdev->workqueue = alloc_workqueue(hdev->name, WQ_HIGHPRI | WQ_UNBOUND |
@ -1755,6 +1757,7 @@ int hci_register_dev(struct hci_dev *hdev)
err_wqueue: err_wqueue:
destroy_workqueue(hdev->workqueue); destroy_workqueue(hdev->workqueue);
err: err:
ida_simple_remove(&hci_index_ida, hdev->id);
write_lock(&hci_dev_list_lock); write_lock(&hci_dev_list_lock);
list_del(&hdev->list); list_del(&hdev->list);
write_unlock(&hci_dev_list_lock); write_unlock(&hci_dev_list_lock);
@ -1766,12 +1769,14 @@ EXPORT_SYMBOL(hci_register_dev);
/* Unregister HCI device */ /* Unregister HCI device */
void hci_unregister_dev(struct hci_dev *hdev) void hci_unregister_dev(struct hci_dev *hdev)
{ {
int i; int i, id;
BT_DBG("%p name %s bus %d", hdev, hdev->name, hdev->bus); BT_DBG("%p name %s bus %d", hdev, hdev->name, hdev->bus);
set_bit(HCI_UNREGISTER, &hdev->dev_flags); set_bit(HCI_UNREGISTER, &hdev->dev_flags);
id = hdev->id;
write_lock(&hci_dev_list_lock); write_lock(&hci_dev_list_lock);
list_del(&hdev->list); list_del(&hdev->list);
write_unlock(&hci_dev_list_lock); write_unlock(&hci_dev_list_lock);
@ -1812,6 +1817,8 @@ void hci_unregister_dev(struct hci_dev *hdev)
hci_dev_unlock(hdev); hci_dev_unlock(hdev);
hci_dev_put(hdev); hci_dev_put(hdev);
ida_simple_remove(&hci_index_ida, id);
} }
EXPORT_SYMBOL(hci_unregister_dev); EXPORT_SYMBOL(hci_unregister_dev);