The current algorithm for picking an outgoing channel was not distributing
the load well. Implement a simple round-robin scheme to ensure good
distribution of the outgoing traffic.

Signed-off-by: K. Y. Srinivasan <k...@microsoft.com>
Reviewed-by: Long Li <lon...@microsoft.com>
---
 drivers/hv/channel_mgmt.c |   30 +++++++++++++++---------------
 include/linux/hyperv.h    |    3 +++
 2 files changed, 18 insertions(+), 15 deletions(-)

diff --git a/drivers/hv/channel_mgmt.c b/drivers/hv/channel_mgmt.c
index b1e5a5f..6117891 100644
--- a/drivers/hv/channel_mgmt.c
+++ b/drivers/hv/channel_mgmt.c
@@ -350,6 +350,7 @@ static void vmbus_process_offer(struct vmbus_channel 
*newchannel)
                        }
 
                        newchannel->state = CHANNEL_OPEN_STATE;
+                       channel->num_sc++;
                        if (channel->sc_creation_callback != NULL)
                                /*
                                 * We need to invoke the sub-channel creation
@@ -862,9 +863,8 @@ cleanup:
 
 /*
  * Retrieve the (sub) channel on which to send an outgoing request.
- * When a primary channel has multiple sub-channels, we choose a
- * channel whose VCPU binding is closest to the VCPU on which
- * this call is being made.
+ * When a primary channel has multiple sub-channels, we try to
+ * distribute the load equally amongst all available channels.
  */
 struct vmbus_channel *vmbus_get_outgoing_channel(struct vmbus_channel *primary)
 {
@@ -872,11 +872,19 @@ struct vmbus_channel *vmbus_get_outgoing_channel(struct 
vmbus_channel *primary)
        int cur_cpu;
        struct vmbus_channel *cur_channel;
        struct vmbus_channel *outgoing_channel = primary;
-       int cpu_distance, new_cpu_distance;
+       int next_channel;
+       int i = 1;
 
        if (list_empty(&primary->sc_list))
                return outgoing_channel;
 
+       next_channel = primary->next_oc++;
+
+       if (next_channel > (primary->num_sc)) {
+               primary->next_oc = 0;
+               return outgoing_channel;
+       }
+
        cur_cpu = hv_context.vp_index[get_cpu()];
        put_cpu();
        list_for_each_safe(cur, tmp, &primary->sc_list) {
@@ -887,18 +895,10 @@ struct vmbus_channel *vmbus_get_outgoing_channel(struct 
vmbus_channel *primary)
                if (cur_channel->target_vp == cur_cpu)
                        return cur_channel;
 
-               cpu_distance = ((outgoing_channel->target_vp > cur_cpu) ?
-                               (outgoing_channel->target_vp - cur_cpu) :
-                               (cur_cpu - outgoing_channel->target_vp));
-
-               new_cpu_distance = ((cur_channel->target_vp > cur_cpu) ?
-                               (cur_channel->target_vp - cur_cpu) :
-                               (cur_cpu - cur_channel->target_vp));
-
-               if (cpu_distance < new_cpu_distance)
-                       continue;
+               if (i == next_channel)
+                       return cur_channel;
 
-               outgoing_channel = cur_channel;
+               i++;
        }
 
        return outgoing_channel;
diff --git a/include/linux/hyperv.h b/include/linux/hyperv.h
index dd92a85..1ca5824 100644
--- a/include/linux/hyperv.h
+++ b/include/linux/hyperv.h
@@ -761,6 +761,9 @@ struct vmbus_channel {
         * link up channels based on their CPU affinity.
         */
        struct list_head percpu_list;
+
+       int num_sc;
+       int next_oc;
 };
 
 static inline void set_channel_read_state(struct vmbus_channel *c, bool state)
-- 
1.7.4.1

_______________________________________________
devel mailing list
de...@linuxdriverproject.org
http://driverdev.linuxdriverproject.org/mailman/listinfo/driverdev-devel

Reply via email to