summaryrefslogtreecommitdiffstats
path: root/drivers
diff options
context:
space:
mode:
authorJohan Hovold2015-07-14 15:43:34 +0200
committerGreg Kroah-Hartman2015-07-15 21:39:13 +0200
commit0eb8c1159839dcb6c97fba82e5a8698d9c30f815 (patch)
tree65fca89e07364dfc52bbc93a3b0fedb858289774 /drivers
parentgreybus: operation: fix operation look-up race (diff)
downloadkernel-qcow2-linux-0eb8c1159839dcb6c97fba82e5a8698d9c30f815.tar.gz
kernel-qcow2-linux-0eb8c1159839dcb6c97fba82e5a8698d9c30f815.tar.xz
kernel-qcow2-linux-0eb8c1159839dcb6c97fba82e5a8698d9c30f815.zip
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')
-rw-r--r--drivers/staging/greybus/operation.c12
1 files changed, 8 insertions, 4 deletions
diff --git a/drivers/staging/greybus/operation.c b/drivers/staging/greybus/operation.c
index f7b0aa970bbc..0576f197f58e 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)) {