Files
linuxkit/kernel/patches-4.13.x/0003-vmbus-dynamically-enqueue-dequeue-a-channel-on-vmbus.patch
Rolf Neugebauer d0e55af229 kernel: Add support for 4.13 kernels
The patches from 4.12 applied cleanly, except for 81304747d9
("Drivers: hv: vmbus: Fix rescind handling"), which was already
in upstream so has been dropped from the patch series.

The kernel config is from 4.12 run through defconfig/oldconfig to
pick up any new defaults.

Signed-off-by: Rolf Neugebauer <rolf.neugebauer@docker.com>
2017-10-02 16:20:02 +01:00

190 lines
5.8 KiB
Diff
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

From 038dde9e9da90707062ebf934ee837b450454f2c Mon Sep 17 00:00:00 2001
From: Dexuan Cui <decui@microsoft.com>
Date: Fri, 5 May 2017 16:57:23 -0600
Subject: [PATCH 03/17] vmbus: dynamically enqueue/dequeue a channel on
vmbus_open/close
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
A just-closed channel may have a pending interrupt, and later when a new
channel with the same channel ID is not being fully initialized, the
pending interrupt of the previous channel with the same channel ID can run
the channel callback on the new channel data structure, causing a crash
of NULL pointer dereferencing.
Normally its pretty hard to reproduce the race condition, but it can
indeed happen with specially-designed hv_sock stress test cases.
Signed-off-by: Dexuan Cui <decui@microsoft.com>
Reported-by: Rolf Neugebauer <rolf.neugebauer@docker.com>
Tested-by: Rolf Neugebauer <rolf.neugebauer@docker.com>
Cc: K. Y. Srinivasan <kys@microsoft.com>
Cc: Haiyang Zhang <haiyangz@microsoft.com>
Cc: Stephen Hemminger <sthemmin@microsoft.com>
Origin: git@github.com:dcui/linux.git
(cherry picked from commit fdd8e16c855a6c7238c654d7217dcf51c5533307)
---
drivers/hv/channel.c | 12 +++++++++---
drivers/hv/channel_mgmt.c | 50 +++++++++++++++++++++--------------------------
include/linux/hyperv.h | 3 +++
3 files changed, 34 insertions(+), 31 deletions(-)
diff --git a/drivers/hv/channel.c b/drivers/hv/channel.c
index 42498ecd0f02..d4243b5c39b7 100644
--- a/drivers/hv/channel.c
+++ b/drivers/hv/channel.c
@@ -177,6 +177,8 @@ int vmbus_open(struct vmbus_channel *newchannel, u32 send_ringbuffer_size,
&vmbus_connection.chn_msg_list);
spin_unlock_irqrestore(&vmbus_connection.channelmsg_lock, flags);
+ hv_percpu_channel_enq(newchannel);
+
ret = vmbus_post_msg(open_msg,
sizeof(struct vmbus_channel_open_channel), true);
@@ -189,23 +191,25 @@ int vmbus_open(struct vmbus_channel *newchannel, u32 send_ringbuffer_size,
if (ret != 0) {
err = ret;
- goto error_free_gpadl;
+ goto error_deq_channel;
}
if (newchannel->rescind) {
err = -ENODEV;
- goto error_free_gpadl;
+ goto error_deq_channel;
}
if (open_info->response.open_result.status) {
err = -EAGAIN;
- goto error_free_gpadl;
+ goto error_deq_channel;
}
newchannel->state = CHANNEL_OPENED_STATE;
kfree(open_info);
return 0;
+error_deq_channel:
+ hv_percpu_channel_deq(newchannel);
error_free_gpadl:
vmbus_teardown_gpadl(newchannel, newchannel->ringbuffer_gpadlhandle);
kfree(open_info);
@@ -551,6 +555,8 @@ static int vmbus_close_internal(struct vmbus_channel *channel)
goto out;
}
+ hv_percpu_channel_deq(channel);
+
channel->state = CHANNEL_OPEN_STATE;
channel->sc_creation_callback = NULL;
/* Stop callback and cancel the timer asap */
diff --git a/drivers/hv/channel_mgmt.c b/drivers/hv/channel_mgmt.c
index 4bbb8dea4727..1afa7a699dd2 100644
--- a/drivers/hv/channel_mgmt.c
+++ b/drivers/hv/channel_mgmt.c
@@ -362,6 +362,17 @@ static void percpu_channel_enq(void *arg)
list_add_tail_rcu(&channel->percpu_list, &hv_cpu->chan_list);
}
+void hv_percpu_channel_enq(struct vmbus_channel *channel)
+{
+ if (channel->target_cpu != get_cpu())
+ smp_call_function_single(channel->target_cpu,
+ percpu_channel_enq, channel, true);
+ else
+ percpu_channel_enq(channel);
+
+ put_cpu();
+}
+
static void percpu_channel_deq(void *arg)
{
struct vmbus_channel *channel = arg;
@@ -369,6 +380,17 @@ static void percpu_channel_deq(void *arg)
list_del_rcu(&channel->percpu_list);
}
+void hv_percpu_channel_deq(struct vmbus_channel *channel)
+{
+ if (channel->target_cpu != get_cpu())
+ smp_call_function_single(channel->target_cpu,
+ percpu_channel_deq, channel, true);
+ else
+ percpu_channel_deq(channel);
+
+ put_cpu();
+}
+
static void vmbus_release_relid(u32 relid)
{
@@ -389,15 +411,6 @@ void hv_process_channel_removal(struct vmbus_channel *channel, u32 relid)
BUG_ON(!channel->rescind);
BUG_ON(!mutex_is_locked(&vmbus_connection.channel_mutex));
- if (channel->target_cpu != get_cpu()) {
- put_cpu();
- smp_call_function_single(channel->target_cpu,
- percpu_channel_deq, channel, true);
- } else {
- percpu_channel_deq(channel);
- put_cpu();
- }
-
if (channel->primary_channel == NULL) {
list_del(&channel->listentry);
@@ -490,16 +503,6 @@ static void vmbus_process_offer(struct vmbus_channel *newchannel)
init_vp_index(newchannel, dev_type);
- if (newchannel->target_cpu != get_cpu()) {
- put_cpu();
- smp_call_function_single(newchannel->target_cpu,
- percpu_channel_enq,
- newchannel, true);
- } else {
- percpu_channel_enq(newchannel);
- put_cpu();
- }
-
/*
* This state is used to indicate a successful open
* so that when we do close the channel normally, we
@@ -549,15 +552,6 @@ static void vmbus_process_offer(struct vmbus_channel *newchannel)
list_del(&newchannel->listentry);
mutex_unlock(&vmbus_connection.channel_mutex);
- if (newchannel->target_cpu != get_cpu()) {
- put_cpu();
- smp_call_function_single(newchannel->target_cpu,
- percpu_channel_deq, newchannel, true);
- } else {
- percpu_channel_deq(newchannel);
- put_cpu();
- }
-
vmbus_release_relid(newchannel->offermsg.child_relid);
err_free_chan:
diff --git a/include/linux/hyperv.h b/include/linux/hyperv.h
index b7d7bbec74e0..f5d3e8c01401 100644
--- a/include/linux/hyperv.h
+++ b/include/linux/hyperv.h
@@ -1453,6 +1453,9 @@ 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_percpu_channel_enq(struct vmbus_channel *channel);
+void hv_percpu_channel_deq(struct vmbus_channel *channel);
+
void hv_process_channel_removal(struct vmbus_channel *channel, u32 relid);
void vmbus_setevent(struct vmbus_channel *channel);
--
2.14.1