Files
linuxkit/alpine/kernel/patches/0002-Drivers-hv-vmbus-fix-the-race-when-querying-updating.patch
Ian Campbell 605163eb1d Fixup kernel patch whitepace
Some of git's whitespace fixup option corrupts the patches by (at least)
stripping trailing spaces (which are present for empty lines in context) and
changing leading <space><tab> into just <tab>. `patch(1)` used by the build
here seems to tolerate this, but `git am` and/or `git apply` do not.

Fix this up by running git am and at each failure point (i.e. every patch)
applying the relevant patch using `patch(1)` (which works because `git am` was
unable to even partially apply the patches) before regenerating the whole lot
with `git format-patch`.

Signed-off-by: Ian Campbell <ian.campbell@docker.com>
2016-11-21 11:43:48 +00:00

134 lines
4.1 KiB
Diff

From 457218c0979bb7272eca5e3a6039161890d7dcb5 Mon Sep 17 00:00:00 2001
From: Dexuan Cui <decui@microsoft.com>
Date: Sat, 21 May 2016 16:55:50 +0800
Subject: [PATCH 2/5] Drivers: hv: vmbus: fix the race when querying & updating
the percpu list
There is a rare race when we remove an entry from the global list
hv_context.percpu_list[cpu] in hv_process_channel_removal() ->
percpu_channel_deq() -> list_del(): at this time, if vmbus_on_event() ->
process_chn_event() -> pcpu_relid2channel() is trying to query the list,
we can get the general protection fault:
general protection fault: 0000 [#1] SMP
...
RIP: 0010:[<ffffffff81461b6b>] [<ffffffff81461b6b>] vmbus_on_event+0xc4/0x149
Similarly, we also have the issue in the code path: vmbus_process_offer() ->
percpu_channel_enq().
We can resolve the issue by disabling the tasklet when updating the list.
Reported-by: Rolf Neugebauer <rolf.neugebauer@docker.com>
Signed-off-by: Dexuan Cui <decui@microsoft.com>
Origin: https://github.com/dcui/linux/commit/fbcca73228b9b90911ab30fdf75f532b2b7c07e5
---
drivers/hv/channel.c | 1 +
drivers/hv/channel_mgmt.c | 18 ++++++++++++++++--
2 files changed, 17 insertions(+), 2 deletions(-)
diff --git a/drivers/hv/channel.c b/drivers/hv/channel.c
index 56dd261..75343e0 100644
--- a/drivers/hv/channel.c
+++ b/drivers/hv/channel.c
@@ -592,6 +592,7 @@ static int vmbus_close_internal(struct vmbus_channel *channel)
out:
tasklet_enable(tasklet);
+ tasklet_schedule(tasklet);
return ret;
}
diff --git a/drivers/hv/channel_mgmt.c b/drivers/hv/channel_mgmt.c
index b6c1211..8f4e6070 100644
--- a/drivers/hv/channel_mgmt.c
+++ b/drivers/hv/channel_mgmt.c
@@ -21,6 +21,7 @@
#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
#include <linux/kernel.h>
+#include <linux/interrupt.h>
#include <linux/sched.h>
#include <linux/wait.h>
#include <linux/mm.h>
@@ -307,12 +308,13 @@ void hv_process_channel_removal(struct vmbus_channel *channel, u32 relid)
{
unsigned long flags;
struct vmbus_channel *primary_channel;
-
- vmbus_release_relid(relid);
+ struct tasklet_struct *tasklet;
BUG_ON(!channel->rescind);
BUG_ON(!mutex_is_locked(&vmbus_connection.channel_mutex));
+ tasklet = hv_context.event_dpc[channel->target_cpu];
+ tasklet_disable(tasklet);
if (channel->target_cpu != get_cpu()) {
put_cpu();
smp_call_function_single(channel->target_cpu,
@@ -321,6 +323,8 @@ void hv_process_channel_removal(struct vmbus_channel *channel, u32 relid)
percpu_channel_deq(channel);
put_cpu();
}
+ tasklet_enable(tasklet);
+ tasklet_schedule(tasklet);
if (channel->primary_channel == NULL) {
list_del(&channel->listentry);
@@ -342,6 +346,8 @@ void hv_process_channel_removal(struct vmbus_channel *channel, u32 relid)
&primary_channel->alloced_cpus_in_node);
free_channel(channel);
+
+ vmbus_release_relid(relid);
}
void vmbus_free_channels(void)
@@ -363,6 +369,7 @@ void vmbus_free_channels(void)
*/
static void vmbus_process_offer(struct vmbus_channel *newchannel)
{
+ struct tasklet_struct *tasklet;
struct vmbus_channel *channel;
bool fnew = true;
unsigned long flags;
@@ -409,6 +416,8 @@ static void vmbus_process_offer(struct vmbus_channel *newchannel)
init_vp_index(newchannel, dev_type);
+ tasklet = hv_context.event_dpc[newchannel->target_cpu];
+ tasklet_disable(tasklet);
if (newchannel->target_cpu != get_cpu()) {
put_cpu();
smp_call_function_single(newchannel->target_cpu,
@@ -418,6 +427,8 @@ static void vmbus_process_offer(struct vmbus_channel *newchannel)
percpu_channel_enq(newchannel);
put_cpu();
}
+ tasklet_enable(tasklet);
+ tasklet_schedule(tasklet);
/*
* This state is used to indicate a successful open
@@ -469,6 +480,7 @@ err_deq_chan:
list_del(&newchannel->listentry);
mutex_unlock(&vmbus_connection.channel_mutex);
+ tasklet_disable(tasklet);
if (newchannel->target_cpu != get_cpu()) {
put_cpu();
smp_call_function_single(newchannel->target_cpu,
@@ -477,6 +489,8 @@ err_deq_chan:
percpu_channel_deq(newchannel);
put_cpu();
}
+ tasklet_enable(tasklet);
+ tasklet_schedule(tasklet);
err_free_chan:
free_channel(newchannel);
--
2.10.2