Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit ada6eb11 authored by Stephen Hemminger's avatar Stephen Hemminger Committed by Greg Kroah-Hartman
Browse files

vmbus: only reschedule tasklet if time limit exceeded



The change to reschedule tasklet if more data arrives in ring buffer
can cause performance regression if host timing is such that the
next response happens in small window.

Go back to a modified version of the original looping behavior.
If the race occurs in a small time, then loop. But if the tasklet
has been running for a long interval due to flood, then reschedule
the tasklet to allow migration to ksoftirqd.

Signed-off-by: default avatarStephen Hemminger <sthemmin@microsoft.com>
Signed-off-by: default avatarK. Y. Srinivasan <kys@microsoft.com>
Signed-off-by: default avatarGreg Kroah-Hartman <gregkh@linuxfoundation.org>
parent c37235cc
Loading
Loading
Loading
Loading
+34 −31
Original line number Original line Diff line number Diff line
@@ -296,19 +296,29 @@ struct vmbus_channel *relid2channel(u32 relid)


/*
/*
 * vmbus_on_event - Process a channel event notification
 * vmbus_on_event - Process a channel event notification
 *
 * For batched channels (default) optimize host to guest signaling
 * by ensuring:
 * 1. While reading the channel, we disable interrupts from host.
 * 2. Ensure that we process all posted messages from the host
 *    before returning from this callback.
 * 3. Once we return, enable signaling from the host. Once this
 *    state is set we check to see if additional packets are
 *    available to read. In this case we repeat the process.
 *    If this tasklet has been running for a long time
 *    then reschedule ourselves.
 */
 */
void vmbus_on_event(unsigned long data)
void vmbus_on_event(unsigned long data)
{
{
	struct vmbus_channel *channel = (void *) data;
	struct vmbus_channel *channel = (void *) data;
	unsigned long time_limit = jiffies + 2;

	do {
		void (*callback_fn)(void *);
		void (*callback_fn)(void *);


	/*
		/* A channel once created is persistent even when
	 * A channel once created is persistent even when there
		 * there is no driver handling the device. An
	 * is no driver handling the device. An unloading driver
		 * unloading driver sets the onchannel_callback to NULL.
	 * sets the onchannel_callback to NULL on the same CPU
	 * as where this interrupt is handled (in an interrupt context).
	 * Thus, checking and invoking the driver specific callback takes
	 * care of orderly unloading of the driver.
		 */
		 */
		callback_fn = READ_ONCE(channel->onchannel_callback);
		callback_fn = READ_ONCE(channel->onchannel_callback);
		if (unlikely(callback_fn == NULL))
		if (unlikely(callback_fn == NULL))
@@ -316,25 +326,18 @@ void vmbus_on_event(unsigned long data)


		(*callback_fn)(channel->channel_callback_context);
		(*callback_fn)(channel->channel_callback_context);


	if (channel->callback_mode == HV_CALL_BATCHED) {
		if (channel->callback_mode != HV_CALL_BATCHED)
		/*
			return;
		 * This callback reads the messages sent by the host.

		 * We can optimize host to guest signaling by ensuring:
		if (likely(hv_end_read(&channel->inbound) == 0))
		 * 1. While reading the channel, we disable interrupts from
			return;
		 *    host.

		 * 2. Ensure that we process all posted messages from the host
		 *    before returning from this callback.
		 * 3. Once we return, enable signaling from the host. Once this
		 *    state is set we check to see if additional packets are
		 *    available to read. In this case we repeat the process.
		 */
		if (hv_end_read(&channel->inbound) != 0) {
		hv_begin_read(&channel->inbound);
		hv_begin_read(&channel->inbound);
	} while (likely(time_before(jiffies, time_limit)));


	/* The time limit (2 jiffies) has been reached */
	tasklet_schedule(&channel->callback_event);
	tasklet_schedule(&channel->callback_event);
}
}
	}
}


/*
/*
 * vmbus_post_msg - Send a msg on the vmbus's message connection
 * vmbus_post_msg - Send a msg on the vmbus's message connection