vmbus_get_outgoing_channel() implements the following algorithm for selecting an outgoing channel (despite the comment before the function saying it distributes the load equally): 1) If we have no subchannels return the primary channel; 2) If primary->next_oc is grater than primary->num_sc reset the primary->next_oc to 0 and return the primary channel; 3) Aim for the primary->next_oc subchannel, increment primary->next_oc; 4) Loop through all opened subchannels. If we see a channel which has target_cpu == current_cpu return it. If we reached the primary->next_oc'th open subchannel return it; 5) Return the primary channel. The implementation also skips the subchannel No. 0 unless it matches the current cpu as we assign i to 1 in the initialization. This is not a fair round robin as subchannels in the beginning of the list are more likely to be returned and checking for current cpu aslo creates additional complexity. Simplify the vmbus_get_outgoing_channel() function, make it do what the comment before it says. Signed-off-by: Vitaly Kuznetsov <vkuznets@xxxxxxxxxx> --- drivers/hv/channel_mgmt.c | 27 +++++++++------------------ 1 file changed, 9 insertions(+), 18 deletions(-) diff --git a/drivers/hv/channel_mgmt.c b/drivers/hv/channel_mgmt.c index daa6417..df82442 100644 --- a/drivers/hv/channel_mgmt.c +++ b/drivers/hv/channel_mgmt.c @@ -827,39 +827,30 @@ cleanup: struct vmbus_channel *vmbus_get_outgoing_channel(struct vmbus_channel *primary) { struct list_head *cur, *tmp; - int cur_cpu; struct vmbus_channel *cur_channel; - struct vmbus_channel *outgoing_channel = primary; - int next_channel; - int i = 1; + int i = 0; if (list_empty(&primary->sc_list)) - return outgoing_channel; + return primary; - next_channel = primary->next_oc++; - - if (next_channel > (primary->num_sc)) { + if (primary->next_oc > primary->num_sc) { primary->next_oc = 0; - return outgoing_channel; + return primary; } - cur_cpu = hv_context.vp_index[get_cpu()]; - put_cpu(); list_for_each_safe(cur, tmp, &primary->sc_list) { + i++; cur_channel = list_entry(cur, struct vmbus_channel, sc_list); if (cur_channel->state != CHANNEL_OPENED_STATE) continue; - if (cur_channel->target_vp == cur_cpu) - return cur_channel; - - if (i == next_channel) + if (i > primary->next_oc) { + primary->next_oc = i; return cur_channel; - - i++; + } } - return outgoing_channel; + return primary; } EXPORT_SYMBOL_GPL(vmbus_get_outgoing_channel); -- 1.9.3 _______________________________________________ devel mailing list devel@xxxxxxxxxxxxxxxxxxxxxx http://driverdev.linuxdriverproject.org/mailman/listinfo/driverdev-devel