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 | |
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')
-rw-r--r-- | drivers/staging/greybus/connection.c | 6 | ||||
-rw-r--r-- | drivers/staging/greybus/operation.c | 50 | ||||
-rw-r--r-- | drivers/staging/greybus/operation.h | 1 |
3 files changed, 39 insertions, 18 deletions
diff --git a/drivers/staging/greybus/connection.c b/drivers/staging/greybus/connection.c index ac9b2d174805..81a5df0e3230 100644 --- a/drivers/staging/greybus/connection.c +++ b/drivers/staging/greybus/connection.c @@ -238,7 +238,11 @@ static void gb_connection_cancel_operations(struct gb_connection *connection, gb_operation_get(operation); spin_unlock_irq(&connection->lock); - gb_operation_cancel(operation, errno); + if (gb_operation_is_incoming(operation)) + gb_operation_cancel_incoming(operation, errno); + else + gb_operation_cancel(operation, errno); + gb_operation_put(operation); spin_lock_irq(&connection->lock); 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 diff --git a/drivers/staging/greybus/operation.h b/drivers/staging/greybus/operation.h index 26ecd66710a3..d7e59a3f4b47 100644 --- a/drivers/staging/greybus/operation.h +++ b/drivers/staging/greybus/operation.h @@ -171,6 +171,7 @@ int gb_operation_request_send(struct gb_operation *operation, int gb_operation_request_send_sync(struct gb_operation *operation); void gb_operation_cancel(struct gb_operation *operation, int errno); +void gb_operation_cancel_incoming(struct gb_operation *operation, int errno); void greybus_message_sent(struct greybus_host_device *hd, struct gb_message *message, int status); |