diff options
author | Dexuan Cui <decui@microsoft.com> | 2016-06-10 04:47:24 +0300 |
---|---|---|
committer | Greg Kroah-Hartman <gregkh@linuxfoundation.org> | 2016-08-31 14:05:41 +0300 |
commit | 638fea33aee858cc665297a76f0039e95a28ce0c (patch) | |
tree | b7d64f0d5feea234364b488021b729c1ef3434c0 /drivers/hv/channel.c | |
parent | e0fa3e5e7df61eb2c339c9f0067c202c0cdeec2c (diff) | |
download | linux-638fea33aee858cc665297a76f0039e95a28ce0c.tar.xz |
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 kernel fault.
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.
The patch also moves vmbus_release_relid() to a later place where
the channel has been removed from the per-cpu and the global lists.
Reported-by: Rolf Neugebauer <rolf.neugebauer@docker.com>
Signed-off-by: Dexuan Cui <decui@microsoft.com>
Signed-off-by: K. Y. Srinivasan <kys@microsoft.com>
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
Diffstat (limited to 'drivers/hv/channel.c')
-rw-r--r-- | drivers/hv/channel.c | 6 |
1 files changed, 2 insertions, 4 deletions
diff --git a/drivers/hv/channel.c b/drivers/hv/channel.c index 9a88c63f6e0d..e47d37d21d56 100644 --- a/drivers/hv/channel.c +++ b/drivers/hv/channel.c @@ -505,7 +505,6 @@ static void reset_channel_cb(void *arg) static int vmbus_close_internal(struct vmbus_channel *channel) { struct vmbus_channel_close_channel *msg; - struct tasklet_struct *tasklet; int ret; /* @@ -517,8 +516,7 @@ static int vmbus_close_internal(struct vmbus_channel *channel) * To resolve the race, we can serialize them by disabling the * tasklet when the latter is running here. */ - tasklet = hv_context.event_dpc[channel->target_cpu]; - tasklet_disable(tasklet); + hv_event_tasklet_disable(channel); /* * In case a device driver's probe() fails (e.g., @@ -584,7 +582,7 @@ static int vmbus_close_internal(struct vmbus_channel *channel) get_order(channel->ringbuffer_pagecount * PAGE_SIZE)); out: - tasklet_enable(tasklet); + hv_event_tasklet_enable(channel); return ret; } |