From 210b508e45f00fd81c1ba35c979836d8ffea3980 Mon Sep 17 00:00:00 2001 From: Johan Hovold Date: Tue, 19 Jan 2016 12:51:26 +0100 Subject: [PATCH] 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 Signed-off-by: Johan Hovold Signed-off-by: Greg Kroah-Hartman --- drivers/staging/greybus/connection.c | 17 ++++++++++++++++- 1 file changed, 16 insertions(+), 1 deletion(-) 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); }