]> git.karo-electronics.de Git - karo-tx-linux.git/commitdiff
greybus: connection: add connection-state locking
authorJohan Hovold <johan@hovoldconsulting.com>
Tue, 14 Jul 2015 13:43:30 +0000 (15:43 +0200)
committerGreg Kroah-Hartman <gregkh@google.com>
Wed, 15 Jul 2015 19:39:13 +0000 (12:39 -0700)
Add locking, and the implied barriers, to connection-state updates.

This will be used to fix a number of races in the operations and
connection-tear-down implementations.

Signed-off-by: Johan Hovold <johan@hovoldconsulting.com>
Signed-off-by: Greg Kroah-Hartman <gregkh@google.com>
drivers/staging/greybus/connection.c
drivers/staging/greybus/connection.h

index b9f9b11b1b65f2f335e2fbb14599ce038e8b0c83..abc1f861ea28afeb25eaa182c07263afff9c068c 100644 (file)
@@ -65,8 +65,13 @@ static ssize_t state_show(struct device *dev, struct device_attribute *attr,
                          char *buf)
 {
        struct gb_connection *connection = to_gb_connection(dev);
+       enum gb_connection_state state;
 
-       return sprintf(buf, "%d\n", connection->state);
+       spin_lock_irq(&connection->lock);
+       state = connection->state;
+       spin_unlock_irq(&connection->lock);
+
+       return sprintf(buf, "%d\n", state);
 }
 static DEVICE_ATTR_RO(state);
 
@@ -204,6 +209,7 @@ struct gb_connection *gb_connection_create(struct gb_bundle *bundle,
        spin_unlock_irq(&gb_connections_lock);
 
        atomic_set(&connection->op_cycle, 0);
+       spin_lock_init(&connection->lock);
        INIT_LIST_HEAD(&connection->operations);
 
        /* XXX Will have to establish connections to get version */
@@ -274,10 +280,16 @@ int gb_connection_init(struct gb_connection *connection)
        }
 
        /* Need to enable the connection to initialize it */
+       spin_lock_irq(&connection->lock);
        connection->state = GB_CONNECTION_STATE_ENABLED;
+       spin_unlock_irq(&connection->lock);
+
        ret = connection->protocol->connection_init(connection);
-       if (ret)
+       if (ret) {
+               spin_lock_irq(&connection->lock);
                connection->state = GB_CONNECTION_STATE_ERROR;
+               spin_unlock_irq(&connection->lock);
+       }
 
        return ret;
 }
@@ -291,10 +303,14 @@ void gb_connection_exit(struct gb_connection *connection)
                return;
        }
 
-       if (connection->state != GB_CONNECTION_STATE_ENABLED)
+       spin_lock_irq(&connection->lock);
+       if (connection->state != GB_CONNECTION_STATE_ENABLED) {
+               spin_unlock_irq(&connection->lock);
                return;
-
+       }
        connection->state = GB_CONNECTION_STATE_DESTROYING;
+       spin_unlock_irq(&connection->lock);
+
        connection->protocol->connection_exit(connection);
 
        /*
index ad699db0dfd8ce81d340f116e7dc1b55dd5743b9..c2b71fe7f39767c0699bc224b1b0817c94ac3c2e 100644 (file)
@@ -35,6 +35,7 @@ struct gb_connection {
        u8                              major;
        u8                              minor;
 
+       spinlock_t                      lock;
        enum gb_connection_state        state;
 
        atomic_t                        op_cycle;