diff options
author | Andrea Parri (Microsoft) <parri.andrea@gmail.com> | 2020-04-06 02:15:09 +0200 |
---|---|---|
committer | Wei Liu <wei.liu@kernel.org> | 2020-04-23 13:17:12 +0000 |
commit | 9403b66e6161130ebae7e55a97491c84c1ad6f9f (patch) | |
tree | e52dfc4d433c7af48e347d1b794bebb018679eea /include/linux/hyperv.h | |
parent | 238d2ed8f7d1b1ca0c13334bb8197a42654af946 (diff) | |
download | lwn-9403b66e6161130ebae7e55a97491c84c1ad6f9f.tar.gz lwn-9403b66e6161130ebae7e55a97491c84c1ad6f9f.zip |
Drivers: hv: vmbus: Use a spin lock for synchronizing channel scheduling vs. channel removal
Since vmbus_chan_sched() dereferences the ring buffer pointer, we have
to make sure that the ring buffer data structures don't get freed while
such dereferencing is happening. Current code does this by sending an
IPI to the CPU that is allowed to access that ring buffer from interrupt
level, cf., vmbus_reset_channel_cb(). But with the new functionality
to allow changing the CPU that a channel will interrupt, we can't be
sure what CPU will be running the vmbus_chan_sched() function for a
particular channel, so the current IPI mechanism is infeasible.
Instead synchronize vmbus_chan_sched() and vmbus_reset_channel_cb() by
using the (newly introduced) per-channel spin lock "sched_lock". Move
the test for onchannel_callback being NULL before the "switch" control
statement in vmbus_chan_sched(), in order to not access the ring buffer
if the vmbus_reset_channel_cb() has been completed on the channel.
Suggested-by: Michael Kelley <mikelley@microsoft.com>
Signed-off-by: Andrea Parri (Microsoft) <parri.andrea@gmail.com>
Link: https://lore.kernel.org/r/20200406001514.19876-7-parri.andrea@gmail.com
Reviewed-by: Michael Kelley <mikelley@microsoft.com>
Signed-off-by: Wei Liu <wei.liu@kernel.org>
Diffstat (limited to 'include/linux/hyperv.h')
-rw-r--r-- | include/linux/hyperv.h | 6 |
1 files changed, 6 insertions, 0 deletions
diff --git a/include/linux/hyperv.h b/include/linux/hyperv.h index f5b3f008c55a..62b2c11d0875 100644 --- a/include/linux/hyperv.h +++ b/include/linux/hyperv.h @@ -772,6 +772,12 @@ struct vmbus_channel { void *channel_callback_context; /* + * Synchronize channel scheduling and channel removal; see the inline + * comments in vmbus_chan_sched() and vmbus_reset_channel_cb(). + */ + spinlock_t sched_lock; + + /* * A channel can be marked for one of three modes of reading: * BATCHED - callback called from taslket and should read * channel until empty. Interrupts from the host |