Patch "Drivers: hv: vmbus: Fix bugs in rescind handling" has been added to the 4.13-stable tree
Subsystems (2)
This is a note to let you know that I've just added the patch titled
Drivers: hv: vmbus: Fix bugs in rescind handling
to the 4.13-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-bugs-in-rescind-handling.patch
and it can be found in the queue-4.13 subdirectory.
If you, or anyone else, feels it should not be added to the stable tree, please let <[email protected]> know about it.
Quoted 1 line
From
192b2d78722ffea188e5ec6ae5d55010dce05a4bMon Sep 17 00:00:00 2001
From: "K. Y. Srinivasan" <[email protected]>
Date: Fri, 29 Sep 2017 21:09:36 -0700
Subject: Drivers: hv: vmbus: Fix bugs in rescind handling
From: K. Y. Srinivasan <[email protected]>
commit 192b2d78722ffea188e5ec6ae5d55010dce05a4b upstream.
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.
--- drivers/hv/channel.c | 6 +++--- drivers/hv/channel_mgmt.c | 37 ++++++++++++++++++------------------- drivers/hv/vmbus_drv.c | 3 +-- include/linux/hyperv.h | 2 +- 4 files changed, 23 insertions(+), 25 deletions(-)
drivers/hv/channel.c +3 -3
@@ -640,6 +640,7 @@ void vmbus_close(struct vmbus_channel *c*/ 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 *c 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);
drivers/hv/channel_mgmt.c +18 -19
@@ -159,7 +159,7 @@ static void vmbus_rescind_cleanup(structspin_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 reli 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 vif (!fnew) {if (channel->sc_creation_callback !=NULL ) channel->sc_creation_callback (newchannel); + newchannel->probe_done = true;return ; }
@@ -843,7 +851,6 @@ static void vmbus_onoffer_rescind(struct {struct vmbus_channel_rescind_offer *rescind;struct vmbus_channel *channel; -unsigned long flags;struct device *dev; rescind = (struct vmbus_channel_rescind_offer *)hdr;
@@ -882,16 +889,6 @@ static void vmbus_onoffer_rescind(structreturn ; } -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. */
@@ -910,6 +907,7 @@ static void vmbus_onoffer_rescind(structif (channel->device_obj) {if (channel->chn_rescind_callback) { channel->chn_rescind_callback (channel); +vmbus_rescind_cleanup (channel);return ; }/*
@@ -918,6 +916,7 @@ static void vmbus_onoffer_rescind(struct*/ dev =get_device (&channel->device_obj->device);if (dev) { +vmbus_rescind_cleanup (channel);vmbus_device_unregister (channel->device_obj);put_device (dev); }
@@ -930,16 +929,16 @@ static void vmbus_onoffer_rescind(struct* 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); } }
drivers/hv/vmbus_drv.c +1 -2
@@ -768,8 +768,7 @@ static void vmbus_device_release(structstruct 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);
include/linux/hyperv.h +1 -1
@@ -1455,7 +1455,7 @@ extern bool vmbus_prep_negotiate_resp(st 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);/*
Patches currently in stable-queue which might be from [email protected] are
queue-4.13/drivers-hv-vmbus-fix-bugs-in-rescind-handling.patch queue-4.13/drivers-hv-vmbus-fix-rescind-handling-issues.patch