diff options
author | Johan Hovold | 2015-07-14 15:43:35 +0200 |
---|---|---|
committer | Greg Kroah-Hartman | 2015-07-15 21:39:13 +0200 |
commit | 5a3be769e92ea993f8a8c27b89571c276d874733 (patch) | |
tree | 72a61b98fa4272814d2cce4859abe9e30bf3220b /drivers/staging/greybus/operation.c | |
parent | greybus: operation: fix response-cancellation race (diff) | |
download | kernel-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.c | 50 |
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 |