Commit 3e48acac authored by Johan Hovold's avatar Johan Hovold Committed by Greg Kroah-Hartman

greybus: svc: fix racy hotplug handling

Fix racy hotplug handling by serialising all processing of hot-plug and
unplug requests using a single-threaded dedicated workqueue.

This fixes a reported crash during enumeration when processing multiple
events.

The current svc implementation does not handle concurrency at all (e.g.
no interface list lock or refcounting) so we need to use the big hammer
for now.

Note that we will eventually want to process events for different
interfaces in parallel, but that we'd still need a workqueue in order
not to starve other svc requests (e.g. for timesync).
Reported-by: default avatarVaibhav Hiremath <vaibhav.hiremath@linaro.org>
Signed-off-by: default avatarJohan Hovold <johan@hovoldconsulting.com>
Signed-off-by: default avatarGreg Kroah-Hartman <gregkh@google.com>
parent 57ccd4b0
...@@ -511,6 +511,7 @@ static void gb_svc_process_deferred_request(struct work_struct *work) ...@@ -511,6 +511,7 @@ static void gb_svc_process_deferred_request(struct work_struct *work)
static int gb_svc_queue_deferred_request(struct gb_operation *operation) static int gb_svc_queue_deferred_request(struct gb_operation *operation)
{ {
struct gb_svc *svc = operation->connection->private;
struct gb_svc_deferred_request *dr; struct gb_svc_deferred_request *dr;
dr = kmalloc(sizeof(*dr), GFP_KERNEL); dr = kmalloc(sizeof(*dr), GFP_KERNEL);
...@@ -522,7 +523,7 @@ static int gb_svc_queue_deferred_request(struct gb_operation *operation) ...@@ -522,7 +523,7 @@ static int gb_svc_queue_deferred_request(struct gb_operation *operation)
dr->operation = operation; dr->operation = operation;
INIT_WORK(&dr->work, gb_svc_process_deferred_request); INIT_WORK(&dr->work, gb_svc_process_deferred_request);
queue_work(system_unbound_wq, &dr->work); queue_work(svc->wq, &dr->work);
return 0; return 0;
} }
...@@ -532,7 +533,7 @@ static int gb_svc_queue_deferred_request(struct gb_operation *operation) ...@@ -532,7 +533,7 @@ static int gb_svc_queue_deferred_request(struct gb_operation *operation)
* initialization on the module side. Over that, we may also need to download * initialization on the module side. Over that, we may also need to download
* the firmware first and flash that on the module. * the firmware first and flash that on the module.
* *
* In order to make other hotplug events to not wait for all this to finish, * In order not to make other svc events wait for all this to finish,
* handle most of module hotplug stuff outside of the hotplug callback, with * handle most of module hotplug stuff outside of the hotplug callback, with
* help of a workqueue. * help of a workqueue.
*/ */
...@@ -658,6 +659,7 @@ static void gb_svc_release(struct device *dev) ...@@ -658,6 +659,7 @@ static void gb_svc_release(struct device *dev)
struct gb_svc *svc = to_gb_svc(dev); struct gb_svc *svc = to_gb_svc(dev);
ida_destroy(&svc->device_id_map); ida_destroy(&svc->device_id_map);
destroy_workqueue(svc->wq);
kfree(svc); kfree(svc);
} }
...@@ -675,6 +677,12 @@ static int gb_svc_connection_init(struct gb_connection *connection) ...@@ -675,6 +677,12 @@ static int gb_svc_connection_init(struct gb_connection *connection)
if (!svc) if (!svc)
return -ENOMEM; return -ENOMEM;
svc->wq = alloc_workqueue("%s:svc", WQ_UNBOUND, 1, dev_name(&hd->dev));
if (!svc->wq) {
kfree(svc);
return -ENOMEM;
}
svc->dev.parent = &hd->dev; svc->dev.parent = &hd->dev;
svc->dev.bus = &greybus_bus_type; svc->dev.bus = &greybus_bus_type;
svc->dev.type = &greybus_svc_type; svc->dev.type = &greybus_svc_type;
......
...@@ -22,6 +22,7 @@ struct gb_svc { ...@@ -22,6 +22,7 @@ struct gb_svc {
struct gb_connection *connection; struct gb_connection *connection;
enum gb_svc_state state; enum gb_svc_state state;
struct ida device_id_map; struct ida device_id_map;
struct workqueue_struct *wq;
u16 endo_id; u16 endo_id;
u8 ap_intf_id; u8 ap_intf_id;
......
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