mirror of
https://git.kernel.org/pub/scm/linux/kernel/git/stable/linux.git
synced 2024-09-12 05:48:40 +00:00
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
1 changed files with 21 additions and 7 deletions
|
@ -82,18 +82,32 @@ static DEFINE_SPINLOCK(gb_operations_lock);
|
|||
*/
|
||||
static bool gb_operation_result_set(struct gb_operation *operation, int result)
|
||||
{
|
||||
int prev;
|
||||
|
||||
/* Nobody should be setting -EBADR */
|
||||
if (WARN_ON(result == -EBADR))
|
||||
return false;
|
||||
|
||||
/* Are we sending the request message? */
|
||||
if (result == -EINPROGRESS) {
|
||||
if (WARN_ON(operation->errno != -EBADR))
|
||||
return false;
|
||||
} else if (operation->errno != -EINPROGRESS) {
|
||||
return false;
|
||||
}
|
||||
operation->errno = result;
|
||||
/* Yes, but verify the result has not already been set */
|
||||
spin_lock_irq(&gb_operations_lock);
|
||||
prev = operation->errno;
|
||||
if (prev == -EBADR)
|
||||
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)
|
||||
|
|
Loading…
Reference in a new issue