Commit b6c06321 authored by Dave Young's avatar Dave Young Committed by David S. Miller

[BLUETOOTH]: Add conn add/del workqueues to avoid connection fail.

The bluetooth hci_conn sysfs add/del executed in the default
workqueue.  If the del_conn is executed after the new add_conn with
same target, add_conn will failed with warning of "same kobject name".

Here add btaddconn & btdelconn workqueues, flush the btdelconn
workqueue in the add_conn function to avoid the issue.
Signed-off-by: default avatarDave Young <hidave.darkstar@gmail.com>
Signed-off-by: default avatarDavid S. Miller <davem@davemloft.net>
parent 2614fa59
...@@ -12,6 +12,8 @@ ...@@ -12,6 +12,8 @@
#undef BT_DBG #undef BT_DBG
#define BT_DBG(D...) #define BT_DBG(D...)
#endif #endif
static struct workqueue_struct *btaddconn;
static struct workqueue_struct *btdelconn;
static inline char *typetostr(int type) static inline char *typetostr(int type)
{ {
...@@ -279,6 +281,7 @@ static void add_conn(struct work_struct *work) ...@@ -279,6 +281,7 @@ static void add_conn(struct work_struct *work)
struct hci_conn *conn = container_of(work, struct hci_conn, work); struct hci_conn *conn = container_of(work, struct hci_conn, work);
int i; int i;
flush_workqueue(btdelconn);
if (device_add(&conn->dev) < 0) { if (device_add(&conn->dev) < 0) {
BT_ERR("Failed to register connection device"); BT_ERR("Failed to register connection device");
return; return;
...@@ -313,6 +316,7 @@ void hci_conn_add_sysfs(struct hci_conn *conn) ...@@ -313,6 +316,7 @@ void hci_conn_add_sysfs(struct hci_conn *conn)
INIT_WORK(&conn->work, add_conn); INIT_WORK(&conn->work, add_conn);
queue_work(btaddconn, &conn->work);
schedule_work(&conn->work); schedule_work(&conn->work);
} }
...@@ -349,6 +353,7 @@ void hci_conn_del_sysfs(struct hci_conn *conn) ...@@ -349,6 +353,7 @@ void hci_conn_del_sysfs(struct hci_conn *conn)
INIT_WORK(&conn->work, del_conn); INIT_WORK(&conn->work, del_conn);
queue_work(btdelconn, &conn->work);
schedule_work(&conn->work); schedule_work(&conn->work);
} }
...@@ -398,31 +403,52 @@ int __init bt_sysfs_init(void) ...@@ -398,31 +403,52 @@ int __init bt_sysfs_init(void)
{ {
int err; int err;
btaddconn = create_singlethread_workqueue("btaddconn");
if (!btaddconn) {
err = -ENOMEM;
goto out;
}
btdelconn = create_singlethread_workqueue("btdelconn");
if (!btdelconn) {
err = -ENOMEM;
goto out_del;
}
bt_platform = platform_device_register_simple("bluetooth", -1, NULL, 0); bt_platform = platform_device_register_simple("bluetooth", -1, NULL, 0);
if (IS_ERR(bt_platform)) if (IS_ERR(bt_platform)) {
return PTR_ERR(bt_platform); err = PTR_ERR(bt_platform);
goto out_platform;
}
err = bus_register(&bt_bus); err = bus_register(&bt_bus);
if (err < 0) { if (err < 0)
platform_device_unregister(bt_platform); goto out_bus;
return err;
}
bt_class = class_create(THIS_MODULE, "bluetooth"); bt_class = class_create(THIS_MODULE, "bluetooth");
if (IS_ERR(bt_class)) { if (IS_ERR(bt_class)) {
bus_unregister(&bt_bus); err = PTR_ERR(bt_class);
platform_device_unregister(bt_platform); goto out_class;
return PTR_ERR(bt_class);
} }
return 0; return 0;
out_class:
bus_unregister(&bt_bus);
out_bus:
platform_device_unregister(bt_platform);
out_platform:
destroy_workqueue(btdelconn);
out_del:
destroy_workqueue(btaddconn);
out:
return err;
} }
void bt_sysfs_cleanup(void) void bt_sysfs_cleanup(void)
{ {
destroy_workqueue(btaddconn);
destroy_workqueue(btdelconn);
class_destroy(bt_class); class_destroy(bt_class);
bus_unregister(&bt_bus); bus_unregister(&bt_bus);
platform_device_unregister(bt_platform); platform_device_unregister(bt_platform);
} }
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment