| From a7479cb9ea0010f77493ba17c63fffc0dcaf0f89 Mon Sep 17 00:00:00 2001 |
| From: Dexuan Cui <decui@microsoft.com> |
| Date: Wed, 9 Jan 2019 20:56:06 +0000 |
| Subject: vmbus: fix subchannel removal |
| |
| [ Upstream commit b5679cebf780c6f1c2451a73bf1842a4409840e7 ] |
| |
| The changes to split ring allocation from open/close, broke |
| the cleanup of subchannels. This resulted in problems using |
| uio on network devices because the subchannel was left behind |
| when the network device was unbound. |
| |
| The cause was in the disconnect logic which used list splice |
| to move the subchannel list into a local variable. This won't |
| work because the subchannel list is needed later during the |
| process of the rescind messages (relid2channel). |
| |
| The fix is to just leave the subchannel list in place |
| which is what the original code did. The list is cleaned |
| up later when the host rescind is processed. |
| |
| Without the fix, we have a lot of "hang" issues in netvsc when we |
| try to change the NIC's MTU, set the number of channels, etc. |
| |
| Fixes: ae6935ed7d42 ("vmbus: split ring buffer allocation from open") |
| Cc: stable@vger.kernel.org |
| Signed-off-by: Stephen Hemminger <sthemmin@microsoft.com> |
| Signed-off-by: Dexuan Cui <decui@microsoft.com> |
| Signed-off-by: Sasha Levin <sashal@kernel.org> |
| --- |
| drivers/hv/channel.c | 9 +-------- |
| 1 file changed, 1 insertion(+), 8 deletions(-) |
| |
| diff --git a/drivers/hv/channel.c b/drivers/hv/channel.c |
| index ce0ba2062723..bea4c9850247 100644 |
| --- a/drivers/hv/channel.c |
| +++ b/drivers/hv/channel.c |
| @@ -701,19 +701,12 @@ static int vmbus_close_internal(struct vmbus_channel *channel) |
| int vmbus_disconnect_ring(struct vmbus_channel *channel) |
| { |
| struct vmbus_channel *cur_channel, *tmp; |
| - unsigned long flags; |
| - LIST_HEAD(list); |
| int ret; |
| |
| if (channel->primary_channel != NULL) |
| return -EINVAL; |
| |
| - /* Snapshot the list of subchannels */ |
| - spin_lock_irqsave(&channel->lock, flags); |
| - list_splice_init(&channel->sc_list, &list); |
| - spin_unlock_irqrestore(&channel->lock, flags); |
| - |
| - list_for_each_entry_safe(cur_channel, tmp, &list, sc_list) { |
| + list_for_each_entry_safe(cur_channel, tmp, &channel->sc_list, sc_list) { |
| if (cur_channel->rescind) |
| wait_for_completion(&cur_channel->rescind_event); |
| |
| -- |
| 2.19.1 |
| |