From 87c4092b26050ed12fe67e9148d3c99e77e16b7e Mon Sep 17 00:00:00 2001 From: Rolf Neugebauer Date: Thu, 30 Mar 2017 10:54:05 +0100 Subject: [PATCH] kernel: Add patches to fix VMBus channel ID re-use On some hv_sock workloads which quickly open/close many connections occasionally, channel IDs would get re-used while still having work pending. This can cause a kernel crash on a NULL pointer exception. The three patches added to the 4.9.x and 4.10.x kernels fixes these bugs. The patches are being prepared to be upstreamed, but for now we cherry-picked them from the developers tree. Signed-off-by: Rolf Neugebauer --- ...01-hv_sock-introduce-Hyper-V-Sockets.patch | 2 +- ...-Use-all-supported-IC-versions-to-ne.patch | 2 +- ...rs-hv-Log-the-negotiated-IC-versions.patch | 2 +- ...vmbus-fix-missed-ring-events-on-boot.patch | 56 ++++++ ...to-error_clean_msglist-in-vmbus_open.patch | 59 ++++++ ...y-enqueue-dequeue-the-channel-on-vmb.patch | 177 ++++++++++++++++++ ...01-hv_sock-introduce-Hyper-V-Sockets.patch | 2 +- ...n-t-spam-the-logs-with-unknown-GUIDs.patch | 2 +- ...-Fix-the-mapping-between-host-versio.patch | 4 +- ...-Drivers-hv-vss-Improve-log-messages.patch | 2 +- ...peration-timeouts-should-match-host-.patch | 2 +- ...-Use-all-supported-IC-versions-to-ne.patch | 2 +- ...rs-hv-Log-the-negotiated-IC-versions.patch | 2 +- ...vmbus-fix-missed-ring-events-on-boot.patch | 56 ++++++ ...to-error_clean_msglist-in-vmbus_open.patch | 60 ++++++ ...y-enqueue-dequeue-the-channel-on-vmb.patch | 177 ++++++++++++++++++ 16 files changed, 596 insertions(+), 11 deletions(-) create mode 100644 kernel/patches-4.10/0004-vmbus-fix-missed-ring-events-on-boot.patch create mode 100644 kernel/patches-4.10/0005-vmbus-remove-goto-error_clean_msglist-in-vmbus_open.patch create mode 100644 kernel/patches-4.10/0006-vmbus-dynamically-enqueue-dequeue-the-channel-on-vmb.patch create mode 100644 kernel/patches-4.9/0008-vmbus-fix-missed-ring-events-on-boot.patch create mode 100644 kernel/patches-4.9/0009-vmbus-remove-goto-error_clean_msglist-in-vmbus_open.patch create mode 100644 kernel/patches-4.9/0010-vmbus-dynamically-enqueue-dequeue-the-channel-on-vmb.patch diff --git a/kernel/patches-4.10/0001-hv_sock-introduce-Hyper-V-Sockets.patch b/kernel/patches-4.10/0001-hv_sock-introduce-Hyper-V-Sockets.patch index 8da3a6cad..03995975a 100644 --- a/kernel/patches-4.10/0001-hv_sock-introduce-Hyper-V-Sockets.patch +++ b/kernel/patches-4.10/0001-hv_sock-introduce-Hyper-V-Sockets.patch @@ -1,7 +1,7 @@ From f8892ad868fdcd96ccf6edc93ed61d8a97af88e4 Mon Sep 17 00:00:00 2001 From: Dexuan Cui Date: Thu, 21 Jul 2016 16:04:38 -0600 -Subject: [PATCH 1/3] hv_sock: introduce Hyper-V Sockets +Subject: [PATCH 1/6] hv_sock: introduce Hyper-V Sockets Hyper-V Sockets (hv_sock) supplies a byte-stream based communication mechanism between the host and the guest. It's somewhat like TCP over diff --git a/kernel/patches-4.10/0002-Drivers-hv-vmbus-Use-all-supported-IC-versions-to-ne.patch b/kernel/patches-4.10/0002-Drivers-hv-vmbus-Use-all-supported-IC-versions-to-ne.patch index 750f8bfd3..174de85ff 100644 --- a/kernel/patches-4.10/0002-Drivers-hv-vmbus-Use-all-supported-IC-versions-to-ne.patch +++ b/kernel/patches-4.10/0002-Drivers-hv-vmbus-Use-all-supported-IC-versions-to-ne.patch @@ -1,7 +1,7 @@ From 268b402c42c140328224ff994d1d76053f3113f9 Mon Sep 17 00:00:00 2001 From: Alex Ng Date: Sat, 28 Jan 2017 12:37:17 -0700 -Subject: [PATCH 2/3] Drivers: hv: vmbus: Use all supported IC versions to +Subject: [PATCH 2/6] Drivers: hv: vmbus: Use all supported IC versions to negotiate Previously, we were assuming that each IC protocol version was tied to a diff --git a/kernel/patches-4.10/0003-Drivers-hv-Log-the-negotiated-IC-versions.patch b/kernel/patches-4.10/0003-Drivers-hv-Log-the-negotiated-IC-versions.patch index ea84c5465..f59b69323 100644 --- a/kernel/patches-4.10/0003-Drivers-hv-Log-the-negotiated-IC-versions.patch +++ b/kernel/patches-4.10/0003-Drivers-hv-Log-the-negotiated-IC-versions.patch @@ -1,7 +1,7 @@ From 1dc474194b72f224081c90311887317415f987dc Mon Sep 17 00:00:00 2001 From: Alex Ng Date: Sat, 28 Jan 2017 12:37:18 -0700 -Subject: [PATCH 3/3] Drivers: hv: Log the negotiated IC versions. +Subject: [PATCH 3/6] Drivers: hv: Log the negotiated IC versions. Log the negotiated IC versions. diff --git a/kernel/patches-4.10/0004-vmbus-fix-missed-ring-events-on-boot.patch b/kernel/patches-4.10/0004-vmbus-fix-missed-ring-events-on-boot.patch new file mode 100644 index 000000000..eb1dd7450 --- /dev/null +++ b/kernel/patches-4.10/0004-vmbus-fix-missed-ring-events-on-boot.patch @@ -0,0 +1,56 @@ +From 686f341e764920ada0163bedf354924250ed32d8 Mon Sep 17 00:00:00 2001 +From: Dexuan Cui +Date: Sun, 26 Mar 2017 16:42:20 +0800 +Subject: [PATCH 4/6] vmbus: fix missed ring events on boot + +During initialization, the channel initialization code schedules the +tasklet to scan the VMBUS receive event page (i.e. simulates an +interrupt). The problem was that it invokes the tasklet on a different +CPU from where it normally runs and therefore if an event is present, +it will clear the bit but not find the associated channel. + +This can lead to missed events, typically stuck tasks, during bootup +when sub channels are being initialized. Typically seen as stuck +boot with 8 or more CPU's. + +This patch is not necessary for upstream (4.11 and later) since +commit 631e63a9f346 ("vmbus: change to per channel tasklet"). +This changed vmbus code to get rid of common tasklet which +caused the problem. + +Cc: stable@vger.kernel.org +Fixes: 638fea33aee8 ("Drivers: hv: vmbus: fix the race when querying & updating the percpu list") +Signed-off-by: Stephen Hemminger +Origin: git@github.com:dcui/linux.git +(cherry picked from commit 5cf3a72a111cecc7da759542c56560ce509159d7) +--- + drivers/hv/channel_mgmt.c | 13 +++++++++++-- + 1 file changed, 11 insertions(+), 2 deletions(-) + +diff --git a/drivers/hv/channel_mgmt.c b/drivers/hv/channel_mgmt.c +index feca5d2e7b25..3fda63bf60ab 100644 +--- a/drivers/hv/channel_mgmt.c ++++ b/drivers/hv/channel_mgmt.c +@@ -389,8 +389,17 @@ void hv_event_tasklet_enable(struct vmbus_channel *channel) + tasklet = hv_context.event_dpc[channel->target_cpu]; + tasklet_enable(tasklet); + +- /* In case there is any pending event */ +- tasklet_schedule(tasklet); ++ /* ++ * In case there is any pending event schedule a rescan ++ * but must be on the correct CPU for the channel. ++ */ ++ if (channel->target_cpu == get_cpu()) ++ tasklet_schedule(tasklet); ++ else ++ smp_call_function_single(channel->target_cpu, ++ (smp_call_func_t)tasklet_schedule, ++ tasklet, false); ++ put_cpu(); + } + + void hv_process_channel_removal(struct vmbus_channel *channel, u32 relid) +-- +2.11.0 + diff --git a/kernel/patches-4.10/0005-vmbus-remove-goto-error_clean_msglist-in-vmbus_open.patch b/kernel/patches-4.10/0005-vmbus-remove-goto-error_clean_msglist-in-vmbus_open.patch new file mode 100644 index 000000000..857cf07b2 --- /dev/null +++ b/kernel/patches-4.10/0005-vmbus-remove-goto-error_clean_msglist-in-vmbus_open.patch @@ -0,0 +1,59 @@ +From e3de49b1a6a80b33f792caf62cc33048dcbaed91 Mon Sep 17 00:00:00 2001 +From: Dexuan Cui +Date: Wed, 29 Mar 2017 18:37:10 +0800 +Subject: [PATCH 5/6] vmbus: remove "goto error_clean_msglist" in vmbus_open() + +This is just a cleanup patch to simplify the code a little. +No semantic change. + +Signed-off-by: Dexuan Cui +Origin: git@github.com:dcui/linux.git +(cherry picked from commit 2c89f21cbdfd39299482cd6068094097a45f13b3) +--- + drivers/hv/channel.c | 18 +++++++----------- + 1 file changed, 7 insertions(+), 11 deletions(-) + +diff --git a/drivers/hv/channel.c b/drivers/hv/channel.c +index 1606e7f08f4b..1caed01954f6 100644 +--- a/drivers/hv/channel.c ++++ b/drivers/hv/channel.c +@@ -184,17 +184,18 @@ int vmbus_open(struct vmbus_channel *newchannel, u32 send_ringbuffer_size, + ret = vmbus_post_msg(open_msg, + sizeof(struct vmbus_channel_open_channel), true); + +- if (ret != 0) { +- err = ret; +- goto error_clean_msglist; +- } +- +- wait_for_completion(&open_info->waitevent); ++ if (ret == 0) ++ wait_for_completion(&open_info->waitevent); + + spin_lock_irqsave(&vmbus_connection.channelmsg_lock, flags); + list_del(&open_info->msglistentry); + spin_unlock_irqrestore(&vmbus_connection.channelmsg_lock, flags); + ++ if (ret != 0) { ++ err = ret; ++ goto error_free_gpadl; ++ } ++ + if (newchannel->rescind) { + err = -ENODEV; + goto error_free_gpadl; +@@ -209,11 +210,6 @@ int vmbus_open(struct vmbus_channel *newchannel, u32 send_ringbuffer_size, + kfree(open_info); + return 0; + +-error_clean_msglist: +- spin_lock_irqsave(&vmbus_connection.channelmsg_lock, flags); +- list_del(&open_info->msglistentry); +- spin_unlock_irqrestore(&vmbus_connection.channelmsg_lock, flags); +- + error_free_gpadl: + vmbus_teardown_gpadl(newchannel, newchannel->ringbuffer_gpadlhandle); + kfree(open_info); +-- +2.11.0 + diff --git a/kernel/patches-4.10/0006-vmbus-dynamically-enqueue-dequeue-the-channel-on-vmb.patch b/kernel/patches-4.10/0006-vmbus-dynamically-enqueue-dequeue-the-channel-on-vmb.patch new file mode 100644 index 000000000..c12dd851a --- /dev/null +++ b/kernel/patches-4.10/0006-vmbus-dynamically-enqueue-dequeue-the-channel-on-vmb.patch @@ -0,0 +1,177 @@ +From e609da809e493b72eb28c0ad215edea8ddf54fb5 Mon Sep 17 00:00:00 2001 +From: Dexuan Cui +Date: Fri, 24 Mar 2017 20:53:18 +0800 +Subject: [PATCH 6/6] vmbus: dynamically enqueue/dequeue the channel on + vmbus_open/close + +Signed-off-by: Dexuan Cui +Origin: git@github.com:dcui/linux.git +(cherry picked from commit bee4910daa4aed57ce60d2e2350e3cc120c383ca) +--- + drivers/hv/channel.c | 16 ++++++++++--- + drivers/hv/channel_mgmt.c | 58 ++++++++++++++++++++--------------------------- + include/linux/hyperv.h | 3 +++ + 3 files changed, 40 insertions(+), 37 deletions(-) + +diff --git a/drivers/hv/channel.c b/drivers/hv/channel.c +index 1caed01954f6..5bbcc964dbf7 100644 +--- a/drivers/hv/channel.c ++++ b/drivers/hv/channel.c +@@ -181,6 +181,10 @@ 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_event_tasklet_disable(newchannel); ++ hv_percpu_channel_enq(newchannel); ++ hv_event_tasklet_enable(newchannel); ++ + ret = vmbus_post_msg(open_msg, + sizeof(struct vmbus_channel_open_channel), true); + +@@ -193,23 +197,27 @@ 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_event_tasklet_disable(newchannel); ++ hv_percpu_channel_deq(newchannel); ++ hv_event_tasklet_enable(newchannel); + error_free_gpadl: + vmbus_teardown_gpadl(newchannel, newchannel->ringbuffer_gpadlhandle); + kfree(open_info); +@@ -555,6 +563,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 3fda63bf60ab..e2fbfa290f1c 100644 +--- a/drivers/hv/channel_mgmt.c ++++ b/drivers/hv/channel_mgmt.c +@@ -376,6 +376,30 @@ static void vmbus_release_relid(u32 relid) + true); + } + ++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(); ++ ++} ++ ++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(); ++ ++} ++ + void hv_event_tasklet_disable(struct vmbus_channel *channel) + { + struct tasklet_struct *tasklet; +@@ -410,17 +434,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)); + +- hv_event_tasklet_disable(channel); +- 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(); +- } +- hv_event_tasklet_enable(channel); +- + if (channel->primary_channel == NULL) { + list_del(&channel->listentry); + +@@ -513,18 +526,6 @@ static void vmbus_process_offer(struct vmbus_channel *newchannel) + + init_vp_index(newchannel, dev_type); + +- hv_event_tasklet_disable(newchannel); +- 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(); +- } +- hv_event_tasklet_enable(newchannel); +- + /* + * This state is used to indicate a successful open + * so that when we do close the channel normally, we +@@ -573,17 +574,6 @@ static void vmbus_process_offer(struct vmbus_channel *newchannel) + list_del(&newchannel->listentry); + mutex_unlock(&vmbus_connection.channel_mutex); + +- hv_event_tasklet_disable(newchannel); +- 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(); +- } +- hv_event_tasklet_enable(newchannel); +- + vmbus_release_relid(newchannel->offermsg.child_relid); + + err_free_chan: +diff --git a/include/linux/hyperv.h b/include/linux/hyperv.h +index 41e5ed87f833..0792d16f4b3e 100644 +--- a/include/linux/hyperv.h ++++ b/include/linux/hyperv.h +@@ -1467,6 +1467,9 @@ extern bool vmbus_prep_negotiate_resp(struct icmsg_hdr *icmsghdrp, u8 *buf, + void hv_event_tasklet_disable(struct vmbus_channel *channel); + void hv_event_tasklet_enable(struct vmbus_channel *channel); + ++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.11.0 + diff --git a/kernel/patches-4.9/0001-hv_sock-introduce-Hyper-V-Sockets.patch b/kernel/patches-4.9/0001-hv_sock-introduce-Hyper-V-Sockets.patch index ba3983b38..ab8e5693f 100644 --- a/kernel/patches-4.9/0001-hv_sock-introduce-Hyper-V-Sockets.patch +++ b/kernel/patches-4.9/0001-hv_sock-introduce-Hyper-V-Sockets.patch @@ -1,7 +1,7 @@ From 687435d249d10985e1c6d6d6cc143e8004e8b976 Mon Sep 17 00:00:00 2001 From: Dexuan Cui Date: Sat, 23 Jul 2016 01:35:51 +0000 -Subject: [PATCH 1/7] hv_sock: introduce Hyper-V Sockets +Subject: [PATCH 01/10] hv_sock: introduce Hyper-V Sockets Hyper-V Sockets (hv_sock) supplies a byte-stream based communication mechanism between the host and the guest. It's somewhat like TCP over diff --git a/kernel/patches-4.9/0002-vmbus-Don-t-spam-the-logs-with-unknown-GUIDs.patch b/kernel/patches-4.9/0002-vmbus-Don-t-spam-the-logs-with-unknown-GUIDs.patch index a21634ea1..72d7ddfc4 100644 --- a/kernel/patches-4.9/0002-vmbus-Don-t-spam-the-logs-with-unknown-GUIDs.patch +++ b/kernel/patches-4.9/0002-vmbus-Don-t-spam-the-logs-with-unknown-GUIDs.patch @@ -1,7 +1,7 @@ From 554ba8b0c4d9aa719d239b2f97eb59075c6c33d9 Mon Sep 17 00:00:00 2001 From: Rolf Neugebauer Date: Mon, 23 May 2016 18:55:45 +0100 -Subject: [PATCH 2/7] vmbus: Don't spam the logs with unknown GUIDs +Subject: [PATCH 02/10] vmbus: Don't spam the logs with unknown GUIDs With Hyper-V sockets device types are introduced on the fly. The pr_info() then prints a message on every connection, which is way too verbose. Since diff --git a/kernel/patches-4.9/0003-Drivers-hv-utils-Fix-the-mapping-between-host-versio.patch b/kernel/patches-4.9/0003-Drivers-hv-utils-Fix-the-mapping-between-host-versio.patch index 9a11ed82e..520397f7e 100644 --- a/kernel/patches-4.9/0003-Drivers-hv-utils-Fix-the-mapping-between-host-versio.patch +++ b/kernel/patches-4.9/0003-Drivers-hv-utils-Fix-the-mapping-between-host-versio.patch @@ -1,8 +1,8 @@ From a9c848779876b7b98a6c588494cd20010894fbf1 Mon Sep 17 00:00:00 2001 From: Alex Ng Date: Sun, 6 Nov 2016 13:14:07 -0800 -Subject: [PATCH 3/7] Drivers: hv: utils: Fix the mapping between host version - and protocol to use +Subject: [PATCH 03/10] Drivers: hv: utils: Fix the mapping between host + version and protocol to use We should intentionally declare the protocols to use for every known host and default to using the latest protocol if the host is unknown or new. diff --git a/kernel/patches-4.9/0004-Drivers-hv-vss-Improve-log-messages.patch b/kernel/patches-4.9/0004-Drivers-hv-vss-Improve-log-messages.patch index 37e9cd873..fc3b251da 100644 --- a/kernel/patches-4.9/0004-Drivers-hv-vss-Improve-log-messages.patch +++ b/kernel/patches-4.9/0004-Drivers-hv-vss-Improve-log-messages.patch @@ -1,7 +1,7 @@ From ccab2062a98a38bd5ff2d57e184229345ff057ff Mon Sep 17 00:00:00 2001 From: Alex Ng Date: Sun, 6 Nov 2016 13:14:10 -0800 -Subject: [PATCH 4/7] Drivers: hv: vss: Improve log messages. +Subject: [PATCH 04/10] Drivers: hv: vss: Improve log messages. Adding log messages to help troubleshoot error cases and transaction handling. diff --git a/kernel/patches-4.9/0005-Drivers-hv-vss-Operation-timeouts-should-match-host-.patch b/kernel/patches-4.9/0005-Drivers-hv-vss-Operation-timeouts-should-match-host-.patch index af697292a..b8bcd0c57 100644 --- a/kernel/patches-4.9/0005-Drivers-hv-vss-Operation-timeouts-should-match-host-.patch +++ b/kernel/patches-4.9/0005-Drivers-hv-vss-Operation-timeouts-should-match-host-.patch @@ -1,7 +1,7 @@ From d303deabd611b45b7574015c06ad2d7408235e77 Mon Sep 17 00:00:00 2001 From: Alex Ng Date: Sun, 6 Nov 2016 13:14:11 -0800 -Subject: [PATCH 5/7] Drivers: hv: vss: Operation timeouts should match host +Subject: [PATCH 05/10] Drivers: hv: vss: Operation timeouts should match host expectation Increase the timeout of backup operations. When system is under I/O load, diff --git a/kernel/patches-4.9/0006-Drivers-hv-vmbus-Use-all-supported-IC-versions-to-ne.patch b/kernel/patches-4.9/0006-Drivers-hv-vmbus-Use-all-supported-IC-versions-to-ne.patch index 433ecfad2..d07410ccb 100644 --- a/kernel/patches-4.9/0006-Drivers-hv-vmbus-Use-all-supported-IC-versions-to-ne.patch +++ b/kernel/patches-4.9/0006-Drivers-hv-vmbus-Use-all-supported-IC-versions-to-ne.patch @@ -1,7 +1,7 @@ From bd8b51edd59a3326bf6457fd939e5503ff3f8efb Mon Sep 17 00:00:00 2001 From: Alex Ng Date: Sat, 28 Jan 2017 12:37:17 -0700 -Subject: [PATCH 6/7] Drivers: hv: vmbus: Use all supported IC versions to +Subject: [PATCH 06/10] Drivers: hv: vmbus: Use all supported IC versions to negotiate Previously, we were assuming that each IC protocol version was tied to a diff --git a/kernel/patches-4.9/0007-Drivers-hv-Log-the-negotiated-IC-versions.patch b/kernel/patches-4.9/0007-Drivers-hv-Log-the-negotiated-IC-versions.patch index 28295c497..bb2b5dc5e 100644 --- a/kernel/patches-4.9/0007-Drivers-hv-Log-the-negotiated-IC-versions.patch +++ b/kernel/patches-4.9/0007-Drivers-hv-Log-the-negotiated-IC-versions.patch @@ -1,7 +1,7 @@ From d692ce39b600298e6c60481d46c284c3c1bf975f Mon Sep 17 00:00:00 2001 From: Alex Ng Date: Sat, 28 Jan 2017 12:37:18 -0700 -Subject: [PATCH 7/7] Drivers: hv: Log the negotiated IC versions. +Subject: [PATCH 07/10] Drivers: hv: Log the negotiated IC versions. Log the negotiated IC versions. diff --git a/kernel/patches-4.9/0008-vmbus-fix-missed-ring-events-on-boot.patch b/kernel/patches-4.9/0008-vmbus-fix-missed-ring-events-on-boot.patch new file mode 100644 index 000000000..228d31f70 --- /dev/null +++ b/kernel/patches-4.9/0008-vmbus-fix-missed-ring-events-on-boot.patch @@ -0,0 +1,56 @@ +From c68a516460f877753f6617d81455f42911d4bf66 Mon Sep 17 00:00:00 2001 +From: Dexuan Cui +Date: Sun, 26 Mar 2017 16:42:20 +0800 +Subject: [PATCH 08/10] vmbus: fix missed ring events on boot + +During initialization, the channel initialization code schedules the +tasklet to scan the VMBUS receive event page (i.e. simulates an +interrupt). The problem was that it invokes the tasklet on a different +CPU from where it normally runs and therefore if an event is present, +it will clear the bit but not find the associated channel. + +This can lead to missed events, typically stuck tasks, during bootup +when sub channels are being initialized. Typically seen as stuck +boot with 8 or more CPU's. + +This patch is not necessary for upstream (4.11 and later) since +commit 631e63a9f346 ("vmbus: change to per channel tasklet"). +This changed vmbus code to get rid of common tasklet which +caused the problem. + +Cc: stable@vger.kernel.org +Fixes: 638fea33aee8 ("Drivers: hv: vmbus: fix the race when querying & updating the percpu list") +Signed-off-by: Stephen Hemminger +Origin: git@github.com:dcui/linux.git +(cherry picked from commit 5cf3a72a111cecc7da759542c56560ce509159d7) +--- + drivers/hv/channel_mgmt.c | 13 +++++++++++-- + 1 file changed, 11 insertions(+), 2 deletions(-) + +diff --git a/drivers/hv/channel_mgmt.c b/drivers/hv/channel_mgmt.c +index e7949b64bfbc..2fe024e86209 100644 +--- a/drivers/hv/channel_mgmt.c ++++ b/drivers/hv/channel_mgmt.c +@@ -388,8 +388,17 @@ void hv_event_tasklet_enable(struct vmbus_channel *channel) + tasklet = hv_context.event_dpc[channel->target_cpu]; + tasklet_enable(tasklet); + +- /* In case there is any pending event */ +- tasklet_schedule(tasklet); ++ /* ++ * In case there is any pending event schedule a rescan ++ * but must be on the correct CPU for the channel. ++ */ ++ if (channel->target_cpu == get_cpu()) ++ tasklet_schedule(tasklet); ++ else ++ smp_call_function_single(channel->target_cpu, ++ (smp_call_func_t)tasklet_schedule, ++ tasklet, false); ++ put_cpu(); + } + + void hv_process_channel_removal(struct vmbus_channel *channel, u32 relid) +-- +2.11.0 + diff --git a/kernel/patches-4.9/0009-vmbus-remove-goto-error_clean_msglist-in-vmbus_open.patch b/kernel/patches-4.9/0009-vmbus-remove-goto-error_clean_msglist-in-vmbus_open.patch new file mode 100644 index 000000000..0fa196c48 --- /dev/null +++ b/kernel/patches-4.9/0009-vmbus-remove-goto-error_clean_msglist-in-vmbus_open.patch @@ -0,0 +1,60 @@ +From 55ddc3b37ec5d311e5fff71cacb224d5c87803f3 Mon Sep 17 00:00:00 2001 +From: Dexuan Cui +Date: Wed, 29 Mar 2017 18:37:10 +0800 +Subject: [PATCH 09/10] vmbus: remove "goto error_clean_msglist" in + vmbus_open() + +This is just a cleanup patch to simplify the code a little. +No semantic change. + +Signed-off-by: Dexuan Cui +Origin: git@github.com:dcui/linux.git +(cherry picked from commit 2c89f21cbdfd39299482cd6068094097a45f13b3) +--- + drivers/hv/channel.c | 18 +++++++----------- + 1 file changed, 7 insertions(+), 11 deletions(-) + +diff --git a/drivers/hv/channel.c b/drivers/hv/channel.c +index 1606e7f08f4b..1caed01954f6 100644 +--- a/drivers/hv/channel.c ++++ b/drivers/hv/channel.c +@@ -184,17 +184,18 @@ int vmbus_open(struct vmbus_channel *newchannel, u32 send_ringbuffer_size, + ret = vmbus_post_msg(open_msg, + sizeof(struct vmbus_channel_open_channel), true); + +- if (ret != 0) { +- err = ret; +- goto error_clean_msglist; +- } +- +- wait_for_completion(&open_info->waitevent); ++ if (ret == 0) ++ wait_for_completion(&open_info->waitevent); + + spin_lock_irqsave(&vmbus_connection.channelmsg_lock, flags); + list_del(&open_info->msglistentry); + spin_unlock_irqrestore(&vmbus_connection.channelmsg_lock, flags); + ++ if (ret != 0) { ++ err = ret; ++ goto error_free_gpadl; ++ } ++ + if (newchannel->rescind) { + err = -ENODEV; + goto error_free_gpadl; +@@ -209,11 +210,6 @@ int vmbus_open(struct vmbus_channel *newchannel, u32 send_ringbuffer_size, + kfree(open_info); + return 0; + +-error_clean_msglist: +- spin_lock_irqsave(&vmbus_connection.channelmsg_lock, flags); +- list_del(&open_info->msglistentry); +- spin_unlock_irqrestore(&vmbus_connection.channelmsg_lock, flags); +- + error_free_gpadl: + vmbus_teardown_gpadl(newchannel, newchannel->ringbuffer_gpadlhandle); + kfree(open_info); +-- +2.11.0 + diff --git a/kernel/patches-4.9/0010-vmbus-dynamically-enqueue-dequeue-the-channel-on-vmb.patch b/kernel/patches-4.9/0010-vmbus-dynamically-enqueue-dequeue-the-channel-on-vmb.patch new file mode 100644 index 000000000..9636f239d --- /dev/null +++ b/kernel/patches-4.9/0010-vmbus-dynamically-enqueue-dequeue-the-channel-on-vmb.patch @@ -0,0 +1,177 @@ +From 83ba0bff619dc73f2aa6385ed3e039bb7641550a Mon Sep 17 00:00:00 2001 +From: Dexuan Cui +Date: Fri, 24 Mar 2017 20:53:18 +0800 +Subject: [PATCH 10/10] vmbus: dynamically enqueue/dequeue the channel on + vmbus_open/close + +Signed-off-by: Dexuan Cui +Origin: git@github.com:dcui/linux.git +(cherry picked from commit bee4910daa4aed57ce60d2e2350e3cc120c383ca) +--- + drivers/hv/channel.c | 16 ++++++++++--- + drivers/hv/channel_mgmt.c | 58 ++++++++++++++++++++--------------------------- + include/linux/hyperv.h | 3 +++ + 3 files changed, 40 insertions(+), 37 deletions(-) + +diff --git a/drivers/hv/channel.c b/drivers/hv/channel.c +index 1caed01954f6..5bbcc964dbf7 100644 +--- a/drivers/hv/channel.c ++++ b/drivers/hv/channel.c +@@ -181,6 +181,10 @@ 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_event_tasklet_disable(newchannel); ++ hv_percpu_channel_enq(newchannel); ++ hv_event_tasklet_enable(newchannel); ++ + ret = vmbus_post_msg(open_msg, + sizeof(struct vmbus_channel_open_channel), true); + +@@ -193,23 +197,27 @@ 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_event_tasklet_disable(newchannel); ++ hv_percpu_channel_deq(newchannel); ++ hv_event_tasklet_enable(newchannel); + error_free_gpadl: + vmbus_teardown_gpadl(newchannel, newchannel->ringbuffer_gpadlhandle); + kfree(open_info); +@@ -555,6 +563,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 2fe024e86209..b2bdcfb49144 100644 +--- a/drivers/hv/channel_mgmt.c ++++ b/drivers/hv/channel_mgmt.c +@@ -375,6 +375,30 @@ static void vmbus_release_relid(u32 relid) + true); + } + ++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(); ++ ++} ++ ++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(); ++ ++} ++ + void hv_event_tasklet_disable(struct vmbus_channel *channel) + { + struct tasklet_struct *tasklet; +@@ -409,17 +433,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)); + +- hv_event_tasklet_disable(channel); +- 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(); +- } +- hv_event_tasklet_enable(channel); +- + if (channel->primary_channel == NULL) { + list_del(&channel->listentry); + +@@ -512,18 +525,6 @@ static void vmbus_process_offer(struct vmbus_channel *newchannel) + + init_vp_index(newchannel, dev_type); + +- hv_event_tasklet_disable(newchannel); +- 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(); +- } +- hv_event_tasklet_enable(newchannel); +- + /* + * This state is used to indicate a successful open + * so that when we do close the channel normally, we +@@ -572,17 +573,6 @@ static void vmbus_process_offer(struct vmbus_channel *newchannel) + list_del(&newchannel->listentry); + mutex_unlock(&vmbus_connection.channel_mutex); + +- hv_event_tasklet_disable(newchannel); +- 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(); +- } +- hv_event_tasklet_enable(newchannel); +- + vmbus_release_relid(newchannel->offermsg.child_relid); + + err_free_chan: +diff --git a/include/linux/hyperv.h b/include/linux/hyperv.h +index 956acfc93487..9ee292b28e41 100644 +--- a/include/linux/hyperv.h ++++ b/include/linux/hyperv.h +@@ -1461,6 +1461,9 @@ extern bool vmbus_prep_negotiate_resp(struct icmsg_hdr *icmsghdrp, u8 *buf, + void hv_event_tasklet_disable(struct vmbus_channel *channel); + void hv_event_tasklet_enable(struct vmbus_channel *channel); + ++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.11.0 +