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: Alex Elder <elder@linaro.org> Signed-off-by: Greg Kroah-Hartman <greg@kroah.com>
This commit is contained in:
parent
ba986b5ab9
commit
abe9a3006f
@ -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)
|
|||||||
|
|
||||||
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,8 +515,8 @@ 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,8 +541,8 @@ 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,8 +585,8 @@ 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,
|
|||||||
*/
|
*/
|
||||||
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);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
Loading…
Reference in New Issue
Block a user