> From: gregkh@xxxxxxxxxxxxxxxxxxx [mailto:gregkh@xxxxxxxxxxxxxxxxxxx] > Sent: Sunday, October 15, 2017 6:28 AM > To: KY Srinivasan <kys@xxxxxxxxxxxxx>; Dexuan Cui <decui@xxxxxxxxxxxxx>; > gregkh@xxxxxxxxxxxxxxxxxxx > Cc: stable@xxxxxxxxxxxxxxx > Subject: FAILED: patch "[PATCH] Drivers: hv: vmbus: Fix bugs in rescind > handling" failed to apply to 4.13-stable tree > > The patch below does not apply to the 4.13-stable tree. > If someone wants it applied there, or to any other stable or longterm > tree, then please email the backport, including the original git commit > id to <stable@xxxxxxxxxxxxxxx>. > > thanks, > > greg k-h Hi Greg, Before applying this patch (192b2d7872), please cherry-pick the prerequisite patch (6f3d791f30) in Linus's tree. As I tested just now, the 2 patches applied cleanly on linux-4.13.y, which Means v4.13.7 today. Thanks, -- Dexuan commit 6f3d791f300618caf82a2be0c27456edd76d5164 Author: K. Y. Srinivasan <kys@xxxxxxxxxxxxx> Date: Fri Aug 11 10:03:59 2017 -0700 Drivers: hv: vmbus: Fix rescind handling issues This patch handles the following issues that were observed when we are handling racing channel offer message and rescind message for the same offer: 1. Since the host does not respond to messages on a rescinded channel, in the current code, we could be indefinitely blocked on the vmbus_open() call. 2. When a rescinded channel is being closed, if there is a pending interrupt on the channel, we could end up freeing the channel that the interrupt handler would run on. Signed-off-by: K. Y. Srinivasan <kys@xxxxxxxxxxxxx> Reviewed-by: Dexuan Cui <decui@xxxxxxxxxxxxx> Tested-by: Dexuan Cui <decui@xxxxxxxxxxxxx> Signed-off-by: Greg Kroah-Hartman <gregkh@xxxxxxxxxxxxxxxxxxx> > ------------------ original commit in Linus's tree ------------------ > > From 192b2d78722ffea188e5ec6ae5d55010dce05a4b Mon Sep 17 00:00:00 > 2001 > From: "K. Y. Srinivasan" <kys@xxxxxxxxxxxxx> > Date: Fri, 29 Sep 2017 21:09:36 -0700 > Subject: [PATCH] Drivers: hv: vmbus: Fix bugs in rescind handling > > This patch addresses the following bugs in the current rescind handling code: > > 1. Fixes a race condition where we may be invoking > hv_process_channel_removal() > on an already freed channel. > > 2. Prevents indefinite wait when rescinding sub-channels by correctly setting > the probe_complete state. > > I would like to thank Dexuan for patiently reviewing earlier versions of this > patch and identifying many of the issues fixed here. > > Greg, please apply this to 4.14-final. > > Fixes: '54a66265d675 ("Drivers: hv: vmbus: Fix rescind handling")' > > Signed-off-by: K. Y. Srinivasan <kys@xxxxxxxxxxxxx> > Reviewed-by: Dexuan Cui <decui@xxxxxxxxxxxxx> > Cc: stable@xxxxxxxxxxxxxxx # (4.13 and above) > Signed-off-by: Greg Kroah-Hartman <gregkh@xxxxxxxxxxxxxxxxxxx> > > diff --git a/drivers/hv/channel.c b/drivers/hv/channel.c > index efd5db743319..894b67ac2cae 100644 > --- a/drivers/hv/channel.c > +++ b/drivers/hv/channel.c > @@ -640,6 +640,7 @@ void vmbus_close(struct vmbus_channel *channel) > */ > return; > } > + mutex_lock(&vmbus_connection.channel_mutex); > /* > * Close all the sub-channels first and then close the > * primary channel. > @@ -648,16 +649,15 @@ void vmbus_close(struct vmbus_channel *channel) > cur_channel = list_entry(cur, struct vmbus_channel, sc_list); > vmbus_close_internal(cur_channel); > if (cur_channel->rescind) { > - mutex_lock(&vmbus_connection.channel_mutex); > - hv_process_channel_removal(cur_channel, > + hv_process_channel_removal( > cur_channel->offermsg.child_relid); > - mutex_unlock(&vmbus_connection.channel_mutex); > } > } > /* > * Now close the primary. > */ > vmbus_close_internal(channel); > + mutex_unlock(&vmbus_connection.channel_mutex); > } > EXPORT_SYMBOL_GPL(vmbus_close); > > diff --git a/drivers/hv/channel_mgmt.c b/drivers/hv/channel_mgmt.c > index bcbb031f7263..018d2e0f8ec5 100644 > --- a/drivers/hv/channel_mgmt.c > +++ b/drivers/hv/channel_mgmt.c > @@ -159,7 +159,7 @@ static void vmbus_rescind_cleanup(struct > vmbus_channel *channel) > > > spin_lock_irqsave(&vmbus_connection.channelmsg_lock, flags); > - > + channel->rescind = true; > list_for_each_entry(msginfo, &vmbus_connection.chn_msg_list, > msglistentry) { > > @@ -381,14 +381,21 @@ static void vmbus_release_relid(u32 relid) > true); > } > > -void hv_process_channel_removal(struct vmbus_channel *channel, u32 relid) > +void hv_process_channel_removal(u32 relid) > { > unsigned long flags; > - struct vmbus_channel *primary_channel; > + struct vmbus_channel *primary_channel, *channel; > > - BUG_ON(!channel->rescind); > BUG_ON(!mutex_is_locked(&vmbus_connection.channel_mutex)); > > + /* > + * Make sure channel is valid as we may have raced. > + */ > + channel = relid2channel(relid); > + if (!channel) > + return; > + > + BUG_ON(!channel->rescind); > if (channel->target_cpu != get_cpu()) { > put_cpu(); > smp_call_function_single(channel->target_cpu, > @@ -515,6 +522,7 @@ static void vmbus_process_offer(struct vmbus_channel > *newchannel) > if (!fnew) { > if (channel->sc_creation_callback != NULL) > channel->sc_creation_callback(newchannel); > + newchannel->probe_done = true; > return; > } > > @@ -834,7 +842,6 @@ static void vmbus_onoffer_rescind(struct > vmbus_channel_message_header *hdr) > { > struct vmbus_channel_rescind_offer *rescind; > struct vmbus_channel *channel; > - unsigned long flags; > struct device *dev; > > rescind = (struct vmbus_channel_rescind_offer *)hdr; > @@ -873,16 +880,6 @@ static void vmbus_onoffer_rescind(struct > vmbus_channel_message_header *hdr) > return; > } > > - spin_lock_irqsave(&channel->lock, flags); > - channel->rescind = true; > - spin_unlock_irqrestore(&channel->lock, flags); > - > - /* > - * Now that we have posted the rescind state, perform > - * rescind related cleanup. > - */ > - vmbus_rescind_cleanup(channel); > - > /* > * Now wait for offer handling to complete. > */ > @@ -901,6 +898,7 @@ static void vmbus_onoffer_rescind(struct > vmbus_channel_message_header *hdr) > if (channel->device_obj) { > if (channel->chn_rescind_callback) { > channel->chn_rescind_callback(channel); > + vmbus_rescind_cleanup(channel); > return; > } > /* > @@ -909,6 +907,7 @@ static void vmbus_onoffer_rescind(struct > vmbus_channel_message_header *hdr) > */ > dev = get_device(&channel->device_obj->device); > if (dev) { > + vmbus_rescind_cleanup(channel); > vmbus_device_unregister(channel->device_obj); > put_device(dev); > } > @@ -921,16 +920,16 @@ static void vmbus_onoffer_rescind(struct > vmbus_channel_message_header *hdr) > * 1. Close all sub-channels first > * 2. Then close the primary channel. > */ > + mutex_lock(&vmbus_connection.channel_mutex); > + vmbus_rescind_cleanup(channel); > if (channel->state == CHANNEL_OPEN_STATE) { > /* > * The channel is currently not open; > * it is safe for us to cleanup the channel. > */ > - mutex_lock(&vmbus_connection.channel_mutex); > - hv_process_channel_removal(channel, > - channel->offermsg.child_relid); > - mutex_unlock(&vmbus_connection.channel_mutex); > + hv_process_channel_removal(rescind->child_relid); > } > + mutex_unlock(&vmbus_connection.channel_mutex); > } > } > > diff --git a/drivers/hv/vmbus_drv.c b/drivers/hv/vmbus_drv.c > index a9d49f6f6501..937801ac2fe0 100644 > --- a/drivers/hv/vmbus_drv.c > +++ b/drivers/hv/vmbus_drv.c > @@ -768,8 +768,7 @@ static void vmbus_device_release(struct device *device) > struct vmbus_channel *channel = hv_dev->channel; > > mutex_lock(&vmbus_connection.channel_mutex); > - hv_process_channel_removal(channel, > - channel->offermsg.child_relid); > + hv_process_channel_removal(channel->offermsg.child_relid); > mutex_unlock(&vmbus_connection.channel_mutex); > kfree(hv_dev); > > diff --git a/include/linux/hyperv.h b/include/linux/hyperv.h > index c458d7b7ad19..6431087816ba 100644 > --- a/include/linux/hyperv.h > +++ b/include/linux/hyperv.h > @@ -1403,7 +1403,7 @@ extern bool vmbus_prep_negotiate_resp(struct > icmsg_hdr *icmsghdrp, u8 *buf, > const int *srv_version, int srv_vercnt, > int *nego_fw_version, int *nego_srv_version); > > -void hv_process_channel_removal(struct vmbus_channel *channel, u32 relid); > +void hv_process_channel_removal(u32 relid); > > void vmbus_setevent(struct vmbus_channel *channel); > /*