find_best_object() has a problem that three or more topo_obj, which have the same ->load value, are involved. The comparison of the ->interrupts length are always held with the one, which is registered in best->best. Think about the following case: topo_obj A, the length of ->interrupts is 3. B, 1. C, 2. and find_best_object() eats them in the order of A, B, and C. Here, find_best_object() wrongly chooses C, instead of B, because the length of -> interrupts of B is not compared with that of C. To fix this, remember only the best one and compare it with the next one. Signed-off-by: Seiichi Ikarashi <s.ikarashi at jp.fujitsu.com> --- placement.c | 17 ++++++----------- 1 files changed, 6 insertions(+), 11 deletions(-) diff --git a/placement.c b/placement.c index cc0d273..f476e02 100644 --- a/placement.c +++ b/placement.c @@ -33,7 +33,6 @@ GList *rebalance_irq_list; struct obj_placement { struct topo_obj *best; - struct topo_obj *least_irqs; uint64_t best_cost; struct irq_info *info; }; @@ -78,12 +77,10 @@ static void find_best_object(struct topo_obj *d, void *data) if (newload < best->best_cost) { best->best = d; best->best_cost = newload; - best->least_irqs = NULL; - } - - if (newload == best->best_cost) { - if (g_list_length(d->interrupts) < g_list_length(best->best->interrupts)) - best->least_irqs = d; + } else if (newload == best->best_cost) { + if (g_list_length(d->interrupts) < g_list_length(best->best->interrupts)) { + best->best = d; + } } } @@ -120,12 +117,11 @@ static void find_best_object_for_irq(struct irq_info *info, void *data) place.info = info; place.best = NULL; - place.least_irqs = NULL; place.best_cost = ULLONG_MAX; for_each_object(d->children, find_best_object, &place); - asign = place.least_irqs ? place.least_irqs : place.best; + asign = place.best; if (asign) { migrate_irq(&d->interrupts, &asign->interrupts, info); @@ -168,12 +164,11 @@ static void place_irq_in_node(struct irq_info *info, void *data __attribute__((u find_placement: place.best_cost = ULLONG_MAX; place.best = NULL; - place.least_irqs = NULL; place.info = info; for_each_object(numa_nodes, find_best_object, &place); - asign = place.least_irqs ? place.least_irqs : place.best; + asign = place.best; if (asign) { migrate_irq(&rebalance_irq_list, &asign->interrupts, info);