Commit abe9a300 authored by Alex Elder's avatar Alex Elder Committed by Greg Kroah-Hartman

greybus: first operation error prevails

If an operation already has an error result recorded, don't
overwrite it with a new error code.

In order to ensure a request completes exactly once, return a
Boolean indicating whether setting the result was successful.  If
two threads are racing to complete an operation (for example if a
slow-but-normal response message arrives at the same time timeout
processing commences) only the one that sets the final result
will finish its activity.
Signed-off-by: default avatarAlex Elder <elder@linaro.org>
Signed-off-by: default avatarGreg Kroah-Hartman <greg@kroah.com>
parent ba986b5a
...@@ -66,9 +66,12 @@ struct gb_operation_msg_hdr { ...@@ -66,9 +66,12 @@ struct gb_operation_msg_hdr {
/* XXX Could be per-host device, per-module, or even per-connection */ /* XXX Could be per-host device, per-module, or even per-connection */
static DEFINE_SPINLOCK(gb_operations_lock); static DEFINE_SPINLOCK(gb_operations_lock);
static void gb_operation_result_set(struct gb_operation *operation, int result) static bool gb_operation_result_set(struct gb_operation *operation, int result)
{ {
if (operation->errno)
return false;
operation->errno = result; operation->errno = result;
return true;
} }
int gb_operation_result(struct gb_operation *operation) int gb_operation_result(struct gb_operation *operation)
...@@ -174,7 +177,7 @@ static void gb_operation_request_handle(struct gb_operation *operation) ...@@ -174,7 +177,7 @@ static void gb_operation_request_handle(struct gb_operation *operation)
gb_connection_err(operation->connection, gb_connection_err(operation->connection,
"unexpected incoming request type 0x%02hhx\n", header->type); "unexpected incoming request type 0x%02hhx\n", header->type);
gb_operation_result_set(operation, -EPROTONOSUPPORT); (void)gb_operation_result_set(operation, -EPROTONOSUPPORT);
} }
#endif #endif
...@@ -512,7 +515,7 @@ greybus_data_sent(struct greybus_host_device *hd, void *header, int status) ...@@ -512,7 +515,7 @@ greybus_data_sent(struct greybus_host_device *hd, void *header, int status)
/* XXX Right now we assume we're an outgoing request */ /* XXX Right now we assume we're an outgoing request */
message = gb_hd_message_find(hd, header); message = gb_hd_message_find(hd, header);
operation = message->operation; operation = message->operation;
gb_operation_result_set(operation, status); if (gb_operation_result_set(operation, status))
queue_work(gb_operation_workqueue, &operation->work); queue_work(gb_operation_workqueue, &operation->work);
} }
EXPORT_SYMBOL_GPL(greybus_data_sent); EXPORT_SYMBOL_GPL(greybus_data_sent);
...@@ -538,7 +541,7 @@ void gb_connection_recv_request(struct gb_connection *connection, ...@@ -538,7 +541,7 @@ void gb_connection_recv_request(struct gb_connection *connection,
memcpy(operation->request->header, data, size); memcpy(operation->request->header, data, size);
/* XXX Right now this will just complete the operation */ /* XXX Right now this will just complete the operation */
gb_operation_result_set(operation, -ENOSYS); if (gb_operation_result_set(operation, -ENOSYS))
queue_work(gb_operation_workqueue, &operation->work); queue_work(gb_operation_workqueue, &operation->work);
} }
...@@ -582,7 +585,7 @@ static void gb_connection_recv_response(struct gb_connection *connection, ...@@ -582,7 +585,7 @@ static void gb_connection_recv_response(struct gb_connection *connection,
memcpy(message->header, data, size); memcpy(message->header, data, size);
/* The rest will be handled in work queue context */ /* The rest will be handled in work queue context */
gb_operation_result_set(operation, result); if (gb_operation_result_set(operation, result))
queue_work(gb_operation_workqueue, &operation->work); queue_work(gb_operation_workqueue, &operation->work);
} }
...@@ -630,9 +633,10 @@ void gb_connection_recv(struct gb_connection *connection, ...@@ -630,9 +633,10 @@ void gb_connection_recv(struct gb_connection *connection,
*/ */
void gb_operation_cancel(struct gb_operation *operation, int errno) void gb_operation_cancel(struct gb_operation *operation, int errno)
{ {
gb_operation_result_set(operation, errno); if (gb_operation_result_set(operation, errno)) {
gb_message_cancel(operation->request); gb_message_cancel(operation->request);
gb_message_cancel(operation->response); gb_message_cancel(operation->response);
}
} }
/** /**
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment