greybus: update operation result atomically
An operation result can be set both in and out of interrupt context. For example, a response message could be arriving at the same time a timeout of the operation is getting processed. We therefore need to ensure the result is accessed atomically. Protect updates to the errno field using the operations spinlock. Signed-off-by: Alex Elder <elder@linaro.org> Signed-off-by: Greg Kroah-Hartman <greg@kroah.com>
This commit is contained in:
parent
aa3a4d1209
commit
894cbc3136
|
@ -82,18 +82,32 @@ static DEFINE_SPINLOCK(gb_operations_lock);
|
||||||
*/
|
*/
|
||||||
static bool gb_operation_result_set(struct gb_operation *operation, int result)
|
static bool gb_operation_result_set(struct gb_operation *operation, int result)
|
||||||
{
|
{
|
||||||
|
int prev;
|
||||||
|
|
||||||
|
/* Nobody should be setting -EBADR */
|
||||||
if (WARN_ON(result == -EBADR))
|
if (WARN_ON(result == -EBADR))
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
|
/* Are we sending the request message? */
|
||||||
if (result == -EINPROGRESS) {
|
if (result == -EINPROGRESS) {
|
||||||
if (WARN_ON(operation->errno != -EBADR))
|
/* Yes, but verify the result has not already been set */
|
||||||
return false;
|
spin_lock_irq(&gb_operations_lock);
|
||||||
} else if (operation->errno != -EINPROGRESS) {
|
prev = operation->errno;
|
||||||
return false;
|
if (prev == -EBADR)
|
||||||
}
|
operation->errno = result;
|
||||||
operation->errno = result;
|
spin_unlock_irq(&gb_operations_lock);
|
||||||
|
|
||||||
return true;
|
return !WARN_ON(prev != -EBADR);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Trying to set final status; only the first one succeeds */
|
||||||
|
spin_lock_irq(&gb_operations_lock);
|
||||||
|
prev = operation->errno;
|
||||||
|
if (prev == -EINPROGRESS)
|
||||||
|
operation->errno = result;
|
||||||
|
spin_unlock_irq(&gb_operations_lock);
|
||||||
|
|
||||||
|
return prev == -EINPROGRESS;
|
||||||
}
|
}
|
||||||
|
|
||||||
int gb_operation_result(struct gb_operation *operation)
|
int gb_operation_result(struct gb_operation *operation)
|
||||||
|
|
Loading…
Reference in New Issue