This is a note to let you know that I've just added the patch titled Drivers: hv: vmbus: Fix a rescind handling bug to the 4.9-stable tree which can be found at: http://www.kernel.org/git/?p=linux/kernel/git/stable/stable-queue.git;a=summary The filename of the patch is: drivers-hv-vmbus-fix-a-rescind-handling-bug.patch and it can be found in the queue-4.9 subdirectory. If you, or anyone else, feels it should not be added to the stable tree, please let <stable@xxxxxxxxxxxxxxx> know about it. >From ccb61f8a99e6c29df4fb96a65dad4fad740d5be9 Mon Sep 17 00:00:00 2001 From: "K. Y. Srinivasan" <kys@xxxxxxxxxxxxx> Date: Thu, 22 Dec 2016 16:54:00 -0800 Subject: Drivers: hv: vmbus: Fix a rescind handling bug From: K. Y. Srinivasan <kys@xxxxxxxxxxxxx> commit ccb61f8a99e6c29df4fb96a65dad4fad740d5be9 upstream. The host can rescind a channel that has been offered to the guest and once the channel is rescinded, the host does not respond to any requests on that channel. Deal with the case where the guest may be blocked waiting for a response from the host. Signed-off-by: K. Y. Srinivasan <kys@xxxxxxxxxxxxx> Signed-off-by: Greg Kroah-Hartman <gregkh@xxxxxxxxxxxxxxxxxxx> --- drivers/hv/channel.c | 18 ++++++++++++++++++ drivers/hv/channel_mgmt.c | 25 +++++++++++++++++++++++++ include/linux/hyperv.h | 1 + 3 files changed, 44 insertions(+) --- a/drivers/hv/channel.c +++ b/drivers/hv/channel.c @@ -157,6 +157,7 @@ int vmbus_open(struct vmbus_channel *new } 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 *new 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_c 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_c } 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_ch 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_ch 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); --- a/drivers/hv/channel_mgmt.c +++ b/drivers/hv/channel_mgmt.c @@ -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 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); --- a/include/linux/hyperv.h +++ b/include/linux/hyperv.h @@ -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; Patches currently in stable-queue which might be from kys@xxxxxxxxxxxxx are queue-4.9/hv-init-percpu_list-in-hv_synic_alloc.patch queue-4.9/drivers-hv-vmbus-prevent-sending-data-on-a-rescinded-channel.patch queue-4.9/drivers-hv-util-backup-fix-a-rescind-processing-issue.patch queue-4.9/drivers-hv-util-fcopy-fix-a-rescind-processing-issue.patch queue-4.9/pci-hv-fix-wslot_to_devfn-to-fix-warnings-on-device-removal.patch queue-4.9/scsi-storvsc-use-tagged-srb-requests-if-supported-by-the-device.patch queue-4.9/drivers-hv-vmbus-raise-retry-wait-limits-in-vmbus_post_msg.patch queue-4.9/drivers-hv-util-kvp-fix-a-rescind-processing-issue.patch queue-4.9/hv-allocate-synic-pages-for-all-present-cpus.patch queue-4.9/hv-don-t-reset-hv_context.tsc_page-on-crash.patch queue-4.9/scsi-storvsc-properly-set-residual-data-length-on-errors.patch queue-4.9/scsi-storvsc-properly-handle-srb_error-when-sense-message-is-present.patch queue-4.9/drivers-hv-vmbus-fix-a-rescind-handling-bug.patch