aboutsummaryrefslogtreecommitdiff
path: root/drivers/staging/greybus/connection.c
diff options
context:
space:
mode:
authorGravatar Johan Hovold <johan@hovoldconsulting.com> 2016-01-19 12:51:26 +0100
committerGravatar Greg Kroah-Hartman <gregkh@google.com> 2016-01-19 12:17:13 -0800
commit210b508e45f00fd81c1ba35c979836d8ffea3980 (patch)
tree9004b7b0563bfcf6106eed50ceb43d70bc72d6a6 /drivers/staging/greybus/connection.c
parentgreybus: connection: fix lookup race (diff)
downloadlinux-210b508e45f00fd81c1ba35c979836d8ffea3980.tar.gz
linux-210b508e45f00fd81c1ba35c979836d8ffea3980.tar.bz2
linux-210b508e45f00fd81c1ba35c979836d8ffea3980.zip
greybus: connection: serialise connection creation
Serialise connection creation against concurrent creation and destruction using a global mutex. This is needed to prevent two drivers from attempting to create a connection to the same interface CPort and to cope with a racing connection destroy when moving to driver managed connections. Note that the locking can not (easily) be made more fine-grained as not all connections have an interface, but these are not hot paths anyway. Reviewed-by: Viresh Kumar <viresh.kumar@linaro.org> Signed-off-by: Johan Hovold <johan@hovoldconsulting.com> Signed-off-by: Greg Kroah-Hartman <gregkh@google.com>
Diffstat (limited to 'drivers/staging/greybus/connection.c')
-rw-r--r--drivers/staging/greybus/connection.c17
1 files changed, 16 insertions, 1 deletions
diff --git a/drivers/staging/greybus/connection.c b/drivers/staging/greybus/connection.c
index d215c5c6331b..de44775b0bc5 100644
--- a/drivers/staging/greybus/connection.c
+++ b/drivers/staging/greybus/connection.c
@@ -16,6 +16,8 @@ static void gb_connection_kref_release(struct kref *kref);
static DEFINE_SPINLOCK(gb_connections_lock);
+static DEFINE_MUTEX(gb_connection_mutex);
+
/* This is only used at initialization time; no locking is required. */
static struct gb_connection *
@@ -125,6 +127,9 @@ static void gb_connection_init_name(struct gb_connection *connection)
* A connection also maintains the state of operations sent over the
* connection.
*
+ * Serialised against concurrent create and destroy using the
+ * gb_connection_mutex.
+ *
* Return: A pointer to the new connection if successful, or NULL otherwise.
*/
static struct gb_connection *
@@ -159,9 +164,11 @@ gb_connection_create(struct gb_host_device *hd, int hd_cport_id,
return NULL;
}
+ mutex_lock(&gb_connection_mutex);
+
hd_cport_id = ida_simple_get(id_map, ida_start, ida_end, GFP_KERNEL);
if (hd_cport_id < 0)
- return NULL;
+ goto err_unlock;
connection = kzalloc(sizeof(*connection), GFP_KERNEL);
if (!connection)
@@ -201,12 +208,16 @@ gb_connection_create(struct gb_host_device *hd, int hd_cport_id,
spin_unlock_irq(&gb_connections_lock);
+ mutex_unlock(&gb_connection_mutex);
+
return connection;
err_free_connection:
kfree(connection);
err_remove_ida:
ida_simple_remove(id_map, hd_cport_id);
+err_unlock:
+ mutex_unlock(&gb_connection_mutex);
return NULL;
}
@@ -524,6 +535,8 @@ void gb_connection_destroy(struct gb_connection *connection)
if (!connection)
return;
+ mutex_lock(&gb_connection_mutex);
+
spin_lock_irq(&gb_connections_lock);
list_del(&connection->bundle_links);
list_del(&connection->hd_links);
@@ -535,6 +548,8 @@ void gb_connection_destroy(struct gb_connection *connection)
ida_simple_remove(id_map, connection->hd_cport_id);
connection->hd_cport_id = CPORT_ID_BAD;
+ mutex_unlock(&gb_connection_mutex);
+
gb_connection_put(connection);
}