diff options
author | Johan Hovold <johan@hovoldconsulting.com> | 2015-07-14 13:43:34 (GMT) |
---|---|---|
committer | Greg Kroah-Hartman <gregkh@google.com> | 2015-07-15 19:39:13 (GMT) |
commit | 0eb8c1159839dcb6c97fba82e5a8698d9c30f815 (patch) | |
tree | 65fca89e07364dfc52bbc93a3b0fedb858289774 /drivers/staging/greybus/operation.c | |
parent | 3325a4ad7122acdbfae5360cafc7152b32eefd57 (diff) | |
download | linux-0eb8c1159839dcb6c97fba82e5a8698d9c30f815.tar.xz |
greybus: operation: fix response-cancellation race
Make sure the request handler has submitted the response before
cancelling it during operation cancellation.
This prevents cancelling not-yet-submitted messages. It currently also
avoids us ending up with an active message on a stalled connection (e.g.
due to E2EFC).
Note that the call to gb_operation_result_set() is now redundant but is
kept as a precaution to guarantee that a response has indeed been
allocated as part of response submission.
Signed-off-by: Johan Hovold <johan@hovoldconsulting.com>
Signed-off-by: Greg Kroah-Hartman <gregkh@google.com>
Diffstat (limited to 'drivers/staging/greybus/operation.c')
-rw-r--r-- | drivers/staging/greybus/operation.c | 12 |
1 files changed, 8 insertions, 4 deletions
diff --git a/drivers/staging/greybus/operation.c b/drivers/staging/greybus/operation.c index f7b0aa9..0576f19 100644 --- a/drivers/staging/greybus/operation.c +++ b/drivers/staging/greybus/operation.c @@ -928,10 +928,14 @@ void gb_connection_recv(struct gb_connection *connection, void gb_operation_cancel(struct gb_operation *operation, int errno) { if (gb_operation_is_incoming(operation)) { - /* Cancel response if it has been allocated */ - if (!gb_operation_result_set(operation, errno) && - !gb_operation_is_unidirectional(operation)) { - gb_message_cancel(operation->response); + if (!gb_operation_is_unidirectional(operation)) { + /* + * Make sure the request handler has submitted the + * response before cancelling it. + */ + flush_work(&operation->work); + if (!gb_operation_result_set(operation, errno)) + gb_message_cancel(operation->response); } } else { if (gb_operation_result_set(operation, errno)) { |