greybus: cancel operation on timeout

If an operation times out, we need to cancel whatever message it
has in-flight.  Do that instead of completing the operation, in the
timeout handler.  When the in-flight request message is canceled its
completion function will lead to the proper completion of the
operation.

Change gb_operation_cancel() so it takes the errno that it's
supposed to assign as the result of the operation.

Note that we want to preserve the original -ETIMEDOUT error, so
don't overwrite the operation result value if it has already been
set.

Signed-off-by: Alex Elder <elder@linaro.org>
Signed-off-by: Greg Kroah-Hartman <greg@kroah.com>
This commit is contained in:
Alex Elder 2014-11-21 19:29:17 -06:00 committed by Greg Kroah-Hartman
parent 0e3d0e8fad
commit f68c05c021
3 changed files with 8 additions and 16 deletions

View File

@ -212,7 +212,7 @@ void gb_connection_destroy(struct gb_connection *connection)
if (WARN_ON(!list_empty(&connection->operations))) { if (WARN_ON(!list_empty(&connection->operations))) {
list_for_each_entry_safe(operation, next, list_for_each_entry_safe(operation, next,
&connection->operations, links) &connection->operations, links)
gb_operation_cancel(operation); gb_operation_cancel(operation, -ESHUTDOWN);
} }
spin_lock_irq(&gb_connections_lock); spin_lock_irq(&gb_connections_lock);
list_del(&connection->interface_links); list_del(&connection->interface_links);

View File

@ -215,20 +215,13 @@ static void gb_operation_work(struct work_struct *work)
/* /*
* Timeout call for the operation. * Timeout call for the operation.
*
* If this fires, something went wrong, so mark the result as timed out, and
* run the completion handler, which (hopefully) should clean up the operation
* properly.
*/ */
static void operation_timeout(struct work_struct *work) static void gb_operation_timeout(struct work_struct *work)
{ {
struct gb_operation *operation; struct gb_operation *operation;
operation = container_of(work, struct gb_operation, timeout_work.work); operation = container_of(work, struct gb_operation, timeout_work.work);
pr_debug("%s: timeout!\n", __func__); gb_operation_cancel(operation, -ETIMEDOUT);
operation->errno = -ETIMEDOUT;
gb_operation_complete(operation);
} }
/* /*
@ -376,7 +369,7 @@ gb_operation_create_common(struct gb_connection *connection, bool outgoing,
INIT_WORK(&operation->work, gb_operation_work); INIT_WORK(&operation->work, gb_operation_work);
operation->callback = NULL; /* set at submit time */ operation->callback = NULL; /* set at submit time */
init_completion(&operation->completion); init_completion(&operation->completion);
INIT_DELAYED_WORK(&operation->timeout_work, operation_timeout); INIT_DELAYED_WORK(&operation->timeout_work, gb_operation_timeout);
kref_init(&operation->kref); kref_init(&operation->kref);
spin_lock_irq(&gb_operations_lock); spin_lock_irq(&gb_operations_lock);
@ -633,11 +626,11 @@ void gb_connection_recv(struct gb_connection *connection,
} }
/* /*
* Cancel an operation. * Cancel an operation, and record the given error to indicate why.
*/ */
void gb_operation_cancel(struct gb_operation *operation) void gb_operation_cancel(struct gb_operation *operation, int errno)
{ {
operation->canceled = true; operation->errno = errno;
gb_message_cancel(operation->request); gb_message_cancel(operation->request);
gb_message_cancel(operation->response); gb_message_cancel(operation->response);
} }

View File

@ -69,7 +69,6 @@ struct gb_operation {
struct gb_message *request; struct gb_message *request;
struct gb_message *response; struct gb_message *response;
u16 id; u16 id;
bool canceled;
int errno; /* Operation result */ int errno; /* Operation result */
@ -99,7 +98,7 @@ int gb_operation_request_send(struct gb_operation *operation,
gb_operation_callback callback); gb_operation_callback callback);
int gb_operation_response_send(struct gb_operation *operation); int gb_operation_response_send(struct gb_operation *operation);
void gb_operation_cancel(struct gb_operation *operation); void gb_operation_cancel(struct gb_operation *operation, int errno);
int gb_operation_wait(struct gb_operation *operation); int gb_operation_wait(struct gb_operation *operation);
int gb_operation_status_map(u8 status); int gb_operation_status_map(u8 status);