greybus: connection: add connection-state locking
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>
This commit is contained in:
parent
886c6069bc
commit
cad09a8f8c
|
@ -65,8 +65,13 @@ static ssize_t state_show(struct device *dev, struct device_attribute *attr,
|
||||||
char *buf)
|
char *buf)
|
||||||
{
|
{
|
||||||
struct gb_connection *connection = to_gb_connection(dev);
|
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);
|
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);
|
spin_unlock_irq(&gb_connections_lock);
|
||||||
|
|
||||||
atomic_set(&connection->op_cycle, 0);
|
atomic_set(&connection->op_cycle, 0);
|
||||||
|
spin_lock_init(&connection->lock);
|
||||||
INIT_LIST_HEAD(&connection->operations);
|
INIT_LIST_HEAD(&connection->operations);
|
||||||
|
|
||||||
/* XXX Will have to establish connections to get version */
|
/* 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 */
|
/* Need to enable the connection to initialize it */
|
||||||
|
spin_lock_irq(&connection->lock);
|
||||||
connection->state = GB_CONNECTION_STATE_ENABLED;
|
connection->state = GB_CONNECTION_STATE_ENABLED;
|
||||||
|
spin_unlock_irq(&connection->lock);
|
||||||
|
|
||||||
ret = connection->protocol->connection_init(connection);
|
ret = connection->protocol->connection_init(connection);
|
||||||
if (ret)
|
if (ret) {
|
||||||
|
spin_lock_irq(&connection->lock);
|
||||||
connection->state = GB_CONNECTION_STATE_ERROR;
|
connection->state = GB_CONNECTION_STATE_ERROR;
|
||||||
|
spin_unlock_irq(&connection->lock);
|
||||||
|
}
|
||||||
|
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
@ -291,10 +303,14 @@ void gb_connection_exit(struct gb_connection *connection)
|
||||||
return;
|
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;
|
return;
|
||||||
|
}
|
||||||
connection->state = GB_CONNECTION_STATE_DESTROYING;
|
connection->state = GB_CONNECTION_STATE_DESTROYING;
|
||||||
|
spin_unlock_irq(&connection->lock);
|
||||||
|
|
||||||
connection->protocol->connection_exit(connection);
|
connection->protocol->connection_exit(connection);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
|
|
@ -35,6 +35,7 @@ struct gb_connection {
|
||||||
u8 major;
|
u8 major;
|
||||||
u8 minor;
|
u8 minor;
|
||||||
|
|
||||||
|
spinlock_t lock;
|
||||||
enum gb_connection_state state;
|
enum gb_connection_state state;
|
||||||
|
|
||||||
atomic_t op_cycle;
|
atomic_t op_cycle;
|
||||||
|
|
Loading…
Reference in New Issue