greybus: gb_operation: replace timeout workqueue
If an operation is issued and the response never comes back, gb_operation_timeout() cancels the operation but never wakes up the waiter in gb_operation_request_send(). This patch removes the timeout workqueue and changes the request wait to wait_for_completion_interruptible_timeout(), with timeout set to OPERATION_TIMEOUT_DEFAULT. Signed-off-by: Perry Hung <perry@leaflabs.com> Reviewed-by: Alex Elder <elder@linaro.org> Signed-off-by: Greg Kroah-Hartman <greg@kroah.com>
This commit is contained in:
parent
76590b1e88
commit
7bad4e85b8
|
@ -248,16 +248,6 @@ static void gb_operation_work(struct work_struct *work)
|
||||||
gb_operation_put(operation);
|
gb_operation_put(operation);
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
|
||||||
* Timeout call for the operation.
|
|
||||||
*/
|
|
||||||
static void gb_operation_timeout(struct work_struct *work)
|
|
||||||
{
|
|
||||||
struct gb_operation *operation;
|
|
||||||
|
|
||||||
operation = container_of(work, struct gb_operation, timeout_work.work);
|
|
||||||
gb_operation_cancel(operation, -ETIMEDOUT);
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Given a pointer to the header in a message sent on a given host
|
* Given a pointer to the header in a message sent on a given host
|
||||||
|
@ -533,7 +523,6 @@ gb_operation_create_common(struct gb_connection *connection, u8 type,
|
||||||
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, gb_operation_timeout);
|
|
||||||
kref_init(&operation->kref);
|
kref_init(&operation->kref);
|
||||||
|
|
||||||
spin_lock_irq(&gb_operations_lock);
|
spin_lock_irq(&gb_operations_lock);
|
||||||
|
@ -652,7 +641,6 @@ int gb_operation_request_send(struct gb_operation *operation,
|
||||||
{
|
{
|
||||||
struct gb_connection *connection = operation->connection;
|
struct gb_connection *connection = operation->connection;
|
||||||
struct gb_operation_msg_hdr *header;
|
struct gb_operation_msg_hdr *header;
|
||||||
unsigned long timeout;
|
|
||||||
unsigned int cycle;
|
unsigned int cycle;
|
||||||
|
|
||||||
if (connection->state != GB_CONNECTION_STATE_ENABLED)
|
if (connection->state != GB_CONNECTION_STATE_ENABLED)
|
||||||
|
@ -680,14 +668,6 @@ int gb_operation_request_send(struct gb_operation *operation,
|
||||||
header = operation->request->header;
|
header = operation->request->header;
|
||||||
header->operation_id = cpu_to_le16(operation->id);
|
header->operation_id = cpu_to_le16(operation->id);
|
||||||
|
|
||||||
/*
|
|
||||||
* We impose a time limit for requests to complete. We need
|
|
||||||
* to set the timer before we send the request though, so we
|
|
||||||
* don't lose a race with the receipt of the resposne.
|
|
||||||
*/
|
|
||||||
timeout = msecs_to_jiffies(OPERATION_TIMEOUT_DEFAULT);
|
|
||||||
schedule_delayed_work(&operation->timeout_work, timeout);
|
|
||||||
|
|
||||||
/* All set, send the request */
|
/* All set, send the request */
|
||||||
gb_operation_result_set(operation, -EINPROGRESS);
|
gb_operation_result_set(operation, -EINPROGRESS);
|
||||||
|
|
||||||
|
@ -703,15 +683,21 @@ int gb_operation_request_send(struct gb_operation *operation,
|
||||||
int gb_operation_request_send_sync(struct gb_operation *operation)
|
int gb_operation_request_send_sync(struct gb_operation *operation)
|
||||||
{
|
{
|
||||||
int ret;
|
int ret;
|
||||||
|
unsigned long timeout;
|
||||||
|
|
||||||
ret = gb_operation_request_send(operation, gb_operation_sync_callback);
|
ret = gb_operation_request_send(operation, gb_operation_sync_callback);
|
||||||
if (ret)
|
if (ret)
|
||||||
return ret;
|
return ret;
|
||||||
|
|
||||||
/* Cancel the operation if interrupted */
|
timeout = msecs_to_jiffies(OPERATION_TIMEOUT_DEFAULT);
|
||||||
ret = wait_for_completion_interruptible(&operation->completion);
|
ret = wait_for_completion_interruptible_timeout(&operation->completion, timeout);
|
||||||
if (ret < 0)
|
if (ret < 0) {
|
||||||
|
/* Cancel the operation if interrupted */
|
||||||
gb_operation_cancel(operation, -ECANCELED);
|
gb_operation_cancel(operation, -ECANCELED);
|
||||||
|
} else if (ret == 0) {
|
||||||
|
/* Cancel the operation if op timed out */
|
||||||
|
gb_operation_cancel(operation, -ETIMEDOUT);
|
||||||
|
}
|
||||||
|
|
||||||
return gb_operation_result(operation);
|
return gb_operation_result(operation);
|
||||||
}
|
}
|
||||||
|
@ -843,8 +829,6 @@ static void gb_connection_recv_response(struct gb_connection *connection,
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
cancel_delayed_work(&operation->timeout_work);
|
|
||||||
|
|
||||||
message = operation->response;
|
message = operation->response;
|
||||||
message_size = sizeof(*message->header) + message->payload_size;
|
message_size = sizeof(*message->header) + message->payload_size;
|
||||||
if (!errno && size != message_size) {
|
if (!errno && size != message_size) {
|
||||||
|
|
|
@ -88,7 +88,6 @@ struct gb_operation {
|
||||||
struct work_struct work;
|
struct work_struct work;
|
||||||
gb_operation_callback callback; /* If asynchronous */
|
gb_operation_callback callback; /* If asynchronous */
|
||||||
struct completion completion; /* Used if no callback */
|
struct completion completion; /* Used if no callback */
|
||||||
struct delayed_work timeout_work;
|
|
||||||
|
|
||||||
struct kref kref;
|
struct kref kref;
|
||||||
struct list_head links; /* connection->operations */
|
struct list_head links; /* connection->operations */
|
||||||
|
|
Loading…
Reference in New Issue