diff --git a/activate.c b/activate.c index 0c1e7a1..10ad57d 100644 --- a/activate.c +++ b/activate.c @@ -99,7 +99,6 @@ static void activate_mapping(struct irq_info *info, void *data __attribute__((un "Cannot change IRQ %i affinity: %s\n", info->irq, strerror(errsave)); switch (errsave) { - case ENOSPC: /* Specified CPU APIC is full. */ case EAGAIN: /* Interrupted by signal. */ case EBUSY: /* Affinity change already in progress. */ case EINVAL: /* IRQ would be bound to no CPU. */ @@ -107,6 +106,18 @@ static void activate_mapping(struct irq_info *info, void *data __attribute__((un case ENOMEM: /* Kernel cannot allocate CPU mask. */ /* Do not blacklist the IRQ on transient errors. */ break; + case ENOSPC: /* Specified CPU APIC is full. */ + if (info->assigned_obj->obj_type != OBJ_TYPE_CPU) + break; + + if (info->assigned_obj->slots_left > 0) + info->assigned_obj->slots_left = -1; + else + /* Negative slots to count how many we need to free */ + info->assigned_obj->slots_left--; + + force_rebalance_irq(info, NULL); + break; default: /* Any other error is considered permanent. */ info->level = BALANCE_NONE; diff --git a/classify.c b/classify.c index 08340db..69d72ac 100644 --- a/classify.c +++ b/classify.c @@ -883,6 +883,8 @@ static void remove_no_existing_irq(struct irq_info *info, void *data __attribute entry = g_list_find_custom(info->assigned_obj->interrupts, info, compare_ints); if (entry) { info->assigned_obj->interrupts = g_list_delete_link(info->assigned_obj->interrupts, entry); + /* Probe number of slots again, don't guess whether the IRQ left a free slot */ + info->assigned_obj->slots_left = INT_MAX; } } free_irq(info, NULL); diff --git a/cputree.c b/cputree.c index d66be55..6c7b3b4 100644 --- a/cputree.c +++ b/cputree.c @@ -595,3 +595,13 @@ int get_cpu_count(void) return g_list_length(cpus); } +static void clear_obj_slots(struct topo_obj *d, void *data __attribute__((unused))) +{ + d->slots_left = INT_MAX; + for_each_object(d->children, clear_obj_slots, NULL); +} + +void clear_slots(void) +{ + for_each_object(numa_nodes, clear_obj_slots, NULL); +} diff --git a/irqbalance.c b/irqbalance.c index 7efbc98..1490336 100644 --- a/irqbalance.c +++ b/irqbalance.c @@ -298,6 +298,7 @@ gboolean scan(gpointer data __attribute__((unused))) } while (need_rebuild); for_each_irq(NULL, force_rebalance_irq, NULL); + clear_slots(); parse_proc_interrupts(); parse_proc_stat(); return TRUE; @@ -695,6 +696,8 @@ int main(int argc, char** argv) parse_proc_interrupts(); parse_proc_stat(); + clear_slots(); + #ifdef HAVE_IRQBALANCEUI if (init_socket()) { ret = EXIT_FAILURE; diff --git a/irqbalance.h b/irqbalance.h index 76640dd..47e40cc 100644 --- a/irqbalance.h +++ b/irqbalance.h @@ -98,6 +98,7 @@ extern struct topo_obj *get_numa_node(int nodeid); #define cpu_numa_node(cpu) ((cpu)->parent->numa_nodes) extern struct topo_obj *find_cpu_core(int cpunr); extern int get_cpu_count(void); +extern void clear_slots(void); /* * irq db functions diff --git a/irqlist.c b/irqlist.c index 304b1c6..9483a11 100644 --- a/irqlist.c +++ b/irqlist.c @@ -211,8 +211,17 @@ void migrate_irq_obj(struct topo_obj *from, struct topo_obj *to, struct irq_info migrate_irq(from_list, to_list, info); - if (to) + if (from) { + if (from->slots_left != INT_MAX) + from->slots_left++; + } + + if (to) { + if (to->slots_left != INT_MAX) + to->slots_left--; + to->load += info->load + 1; + } info->assigned_obj = to; } diff --git a/placement.c b/placement.c index f156e0e..3276dea 100644 --- a/placement.c +++ b/placement.c @@ -59,6 +59,9 @@ static void find_best_object(struct topo_obj *d, void *data) if (d->powersave_mode) return; + if (d->slots_left <= 0) + return; + newload = d->load; if (newload < best->best_cost) { best->best = d; diff --git a/types.h b/types.h index ea1fae8..5c66bf9 100644 --- a/types.h +++ b/types.h @@ -56,6 +56,7 @@ struct topo_obj { GList *children; GList *numa_nodes; GList **obj_type_list; + int slots_left; }; struct irq_info {