mirror of
https://github.com/hardkernel/linux.git
synced 2026-06-10 21:07:02 +09:00
Drivers: hv: vmbus: Fix a rescind handling bug
am: 728fe696fd
Change-Id: Ia857acfde097ec325f449a948b564ff562ccfbef
This commit is contained in:
@@ -157,6 +157,7 @@ int vmbus_open(struct vmbus_channel *newchannel, u32 send_ringbuffer_size,
|
||||
}
|
||||
|
||||
init_completion(&open_info->waitevent);
|
||||
open_info->waiting_channel = newchannel;
|
||||
|
||||
open_msg = (struct vmbus_channel_open_channel *)open_info->msg;
|
||||
open_msg->header.msgtype = CHANNELMSG_OPENCHANNEL;
|
||||
@@ -194,6 +195,11 @@ int vmbus_open(struct vmbus_channel *newchannel, u32 send_ringbuffer_size,
|
||||
list_del(&open_info->msglistentry);
|
||||
spin_unlock_irqrestore(&vmbus_connection.channelmsg_lock, flags);
|
||||
|
||||
if (newchannel->rescind) {
|
||||
err = -ENODEV;
|
||||
goto error_free_gpadl;
|
||||
}
|
||||
|
||||
if (open_info->response.open_result.status) {
|
||||
err = -EAGAIN;
|
||||
goto error_free_gpadl;
|
||||
@@ -405,6 +411,7 @@ int vmbus_establish_gpadl(struct vmbus_channel *channel, void *kbuffer,
|
||||
return ret;
|
||||
|
||||
init_completion(&msginfo->waitevent);
|
||||
msginfo->waiting_channel = channel;
|
||||
|
||||
gpadlmsg = (struct vmbus_channel_gpadl_header *)msginfo->msg;
|
||||
gpadlmsg->header.msgtype = CHANNELMSG_GPADL_HEADER;
|
||||
@@ -441,6 +448,11 @@ int vmbus_establish_gpadl(struct vmbus_channel *channel, void *kbuffer,
|
||||
}
|
||||
wait_for_completion(&msginfo->waitevent);
|
||||
|
||||
if (channel->rescind) {
|
||||
ret = -ENODEV;
|
||||
goto cleanup;
|
||||
}
|
||||
|
||||
/* At this point, we received the gpadl created msg */
|
||||
*gpadl_handle = gpadlmsg->gpadl;
|
||||
|
||||
@@ -474,6 +486,7 @@ int vmbus_teardown_gpadl(struct vmbus_channel *channel, u32 gpadl_handle)
|
||||
return -ENOMEM;
|
||||
|
||||
init_completion(&info->waitevent);
|
||||
info->waiting_channel = channel;
|
||||
|
||||
msg = (struct vmbus_channel_gpadl_teardown *)info->msg;
|
||||
|
||||
@@ -493,6 +506,11 @@ int vmbus_teardown_gpadl(struct vmbus_channel *channel, u32 gpadl_handle)
|
||||
|
||||
wait_for_completion(&info->waitevent);
|
||||
|
||||
if (channel->rescind) {
|
||||
ret = -ENODEV;
|
||||
goto post_msg_err;
|
||||
}
|
||||
|
||||
post_msg_err:
|
||||
spin_lock_irqsave(&vmbus_connection.channelmsg_lock, flags);
|
||||
list_del(&info->msglistentry);
|
||||
|
||||
@@ -147,6 +147,29 @@ static const struct {
|
||||
{ HV_RDV_GUID },
|
||||
};
|
||||
|
||||
/*
|
||||
* The rescinded channel may be blocked waiting for a response from the host;
|
||||
* take care of that.
|
||||
*/
|
||||
static void vmbus_rescind_cleanup(struct vmbus_channel *channel)
|
||||
{
|
||||
struct vmbus_channel_msginfo *msginfo;
|
||||
unsigned long flags;
|
||||
|
||||
|
||||
spin_lock_irqsave(&vmbus_connection.channelmsg_lock, flags);
|
||||
|
||||
list_for_each_entry(msginfo, &vmbus_connection.chn_msg_list,
|
||||
msglistentry) {
|
||||
|
||||
if (msginfo->waiting_channel == channel) {
|
||||
complete(&msginfo->waitevent);
|
||||
break;
|
||||
}
|
||||
}
|
||||
spin_unlock_irqrestore(&vmbus_connection.channelmsg_lock, flags);
|
||||
}
|
||||
|
||||
static bool is_unsupported_vmbus_devs(const uuid_le *guid)
|
||||
{
|
||||
int i;
|
||||
@@ -825,6 +848,8 @@ static void vmbus_onoffer_rescind(struct vmbus_channel_message_header *hdr)
|
||||
channel->rescind = true;
|
||||
spin_unlock_irqrestore(&channel->lock, flags);
|
||||
|
||||
vmbus_rescind_cleanup(channel);
|
||||
|
||||
if (channel->device_obj) {
|
||||
if (channel->chn_rescind_callback) {
|
||||
channel->chn_rescind_callback(channel);
|
||||
|
||||
@@ -641,6 +641,7 @@ struct vmbus_channel_msginfo {
|
||||
|
||||
/* Synchronize the request/response if needed */
|
||||
struct completion waitevent;
|
||||
struct vmbus_channel *waiting_channel;
|
||||
union {
|
||||
struct vmbus_channel_version_supported version_supported;
|
||||
struct vmbus_channel_open_result open_result;
|
||||
|
||||
Reference in New Issue
Block a user