summaryrefslogtreecommitdiffstats
path: root/drivers/staging/greybus/operation.c
diff options
context:
space:
mode:
authorJohan Hovold2015-07-14 15:43:35 +0200
committerGreg Kroah-Hartman2015-07-15 21:39:13 +0200
commit5a3be769e92ea993f8a8c27b89571c276d874733 (patch)
tree72a61b98fa4272814d2cce4859abe9e30bf3220b /drivers/staging/greybus/operation.c
parentgreybus: operation: fix response-cancellation race (diff)
downloadkernel-qcow2-linux-5a3be769e92ea993f8a8c27b89571c276d874733.tar.gz
kernel-qcow2-linux-5a3be769e92ea993f8a8c27b89571c276d874733.tar.xz
kernel-qcow2-linux-5a3be769e92ea993f8a8c27b89571c276d874733.zip
greybus: operation: split incoming and outgoing cancellation
Split incoming and outgoing operation-cancellation helpers. Incoming operations are only cancelled as part of connection tear down and is specifically not needed in the driver API. 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.c50
1 files changed, 33 insertions, 17 deletions
diff --git a/drivers/staging/greybus/operation.c b/drivers/staging/greybus/operation.c
index 0576f197f58e..17b07fb24006 100644
--- a/drivers/staging/greybus/operation.c
+++ b/drivers/staging/greybus/operation.c
@@ -922,26 +922,17 @@ void gb_connection_recv(struct gb_connection *connection,
}
/*
- * Cancel an operation synchronously, and record the given error to indicate
- * why.
+ * Cancel an outgoing operation synchronously, and record the given error to
+ * indicate why.
*/
void gb_operation_cancel(struct gb_operation *operation, int errno)
{
- if (gb_operation_is_incoming(operation)) {
- 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)) {
- gb_message_cancel(operation->request);
- queue_work(gb_operation_workqueue, &operation->work);
- }
+ if (WARN_ON(gb_operation_is_incoming(operation)))
+ return;
+
+ if (gb_operation_result_set(operation, errno)) {
+ gb_message_cancel(operation->request);
+ queue_work(gb_operation_workqueue, &operation->work);
}
atomic_inc(&operation->waiters);
@@ -951,6 +942,31 @@ void gb_operation_cancel(struct gb_operation *operation, int errno)
}
EXPORT_SYMBOL_GPL(gb_operation_cancel);
+/*
+ * Cancel an incoming operation synchronously. Called during connection tear
+ * down.
+ */
+void gb_operation_cancel_incoming(struct gb_operation *operation, int errno)
+{
+ if (WARN_ON(!gb_operation_is_incoming(operation)))
+ return;
+
+ 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);
+ }
+
+ atomic_inc(&operation->waiters);
+ wait_event(gb_operation_cancellation_queue,
+ !gb_operation_is_active(operation));
+ atomic_dec(&operation->waiters);
+}
+
/**
* gb_operation_sync: implement a "simple" synchronous gb operation.
* @connection: the Greybus connection to send this to