hv_utils: Always execute the fcopy and vss callbacks in a tasklet
authorAndrea Parri (Microsoft) <parri.andrea@gmail.com>
Mon, 6 Apr 2020 00:15:08 +0000 (02:15 +0200)
committerWei Liu <wei.liu@kernel.org>
Thu, 23 Apr 2020 13:17:11 +0000 (13:17 +0000)
The fcopy and vss callback functions could be running in a tasklet
at the same time they are called in hv_poll_channel().  Current code
serializes the invocations of these functions, and their accesses to
the channel ring buffer, by sending an IPI to the CPU that is allowed
to access the ring buffer, cf. hv_poll_channel().  This IPI mechanism
becomes infeasible if we allow changing the CPU that a channel will
interrupt.  Instead modify the callback wrappers to always execute
the fcopy and vss callbacks in a tasklet, thus mirroring the solution
for the kvp callback functions adopted since commit a3ade8cc474d8
("HV: properly delay KVP packets when negotiation is in progress").
This will ensure that the callback function can't run on two CPUs at
the same time.

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-6-parri.andrea@gmail.com
Reviewed-by: Michael Kelley <mikelley@microsoft.com>
Signed-off-by: Wei Liu <wei.liu@kernel.org>
drivers/hv/hv_fcopy.c
drivers/hv/hv_snapshot.c
drivers/hv/hyperv_vmbus.h

index bb9ba3f7c794926bc6b79514816e9b4a14bf9099..5040d7e0cd9e983559dfb09d0df8d103eeb8f652 100644 (file)
@@ -71,7 +71,7 @@ static void fcopy_poll_wrapper(void *channel)
 {
        /* Transaction is finished, reset the state here to avoid races. */
        fcopy_transaction.state = HVUTIL_READY;
-       hv_fcopy_onchannelcallback(channel);
+       tasklet_schedule(&((struct vmbus_channel *)channel)->callback_event);
 }
 
 static void fcopy_timeout_func(struct work_struct *dummy)
index 1c75b38f0d6da5ae6328c7b650f8e4bdddc3dd88..783779e4cc1a5c7dd41037591b6412e75a5e9eb8 100644 (file)
@@ -80,7 +80,7 @@ static void vss_poll_wrapper(void *channel)
 {
        /* Transaction is finished, reset the state here to avoid races. */
        vss_transaction.state = HVUTIL_READY;
-       hv_vss_onchannelcallback(channel);
+       tasklet_schedule(&((struct vmbus_channel *)channel)->callback_event);
 }
 
 /*
index 3edf993b0fd9b0240ee10dc5f1c173d9e65fe154..5e5cebe5d048fe9917b4a0e29bddf7411673af56 100644 (file)
@@ -378,12 +378,7 @@ static inline void hv_poll_channel(struct vmbus_channel *channel,
 {
        if (!channel)
                return;
-
-       if (in_interrupt() && (channel->target_cpu == smp_processor_id())) {
-               cb(channel);
-               return;
-       }
-       smp_call_function_single(channel->target_cpu, cb, channel, true);
+       cb(channel);
 }
 
 enum hvutil_device_state {