Commit a73102d5 authored by Philippe Gerum via Xenomai's avatar Philippe Gerum via Xenomai Committed by Jan Kiszka

cobalt/intr: fix interrupt stat iterator

The implementation does not iterate fully over all CPU slots for every
handler, leaving some of them uncollected. In addition, if maxcpus= is
used to restrict the number of available CPUs to a subset of the
present ones, with the highest numbered CPU marked offline, the
iterator rescans the first valid IRQ slot indefinitely, eventually
leading to memory corruption due to out-of-bound writes.

Rewrite the iterator in order to implement the following loop as
expected:

for_each_irq(irq)
    for_each_handler_of_irq(handler, irq)
    	for_each_online_cpu(cpu)
	    collect_stats(irq, handler, cpu);
Signed-off-by: Jan Kiszka's avatarJan Kiszka <jan.kiszka@siemens.com>
parent 44065a10
......@@ -1015,7 +1015,6 @@ void xnintr_put_query_lock(void)
int xnintr_query_init(struct xnintr_iterator *iterator)
{
iterator->cpu = -1;
iterator->prev = NULL;
/* The order is important here: first xnintr_list_rev then
......@@ -1039,43 +1038,38 @@ int xnintr_query_next(int irq, struct xnintr_iterator *iterator,
int cpu, nr_cpus = num_present_cpus();
struct xnintr *intr;
for (cpu = iterator->cpu + 1; cpu < nr_cpus; ++cpu) {
if (cpu_online(cpu))
break;
}
if (cpu == nr_cpus)
cpu = 0;
iterator->cpu = cpu;
if (iterator->list_rev != xnintr_list_rev)
return -EAGAIN;
if (!iterator->prev) {
intr = iterator->prev;
if (intr == NULL) {
if (xnintr_is_timer_irq(irq))
intr = &nktimer;
else
intr = xnintr_vec_first(irq);
} else
intr = xnintr_vec_next(iterator->prev);
if (intr == NULL) {
cpu = -1;
iterator->prev = NULL;
return -ENODEV;
if (intr == NULL)
return -ENODEV;
iterator->prev = intr;
iterator->cpu = -1;
}
ksformat(name_buf, XNOBJECT_NAME_LEN, "IRQ%d: %s", irq, intr->name);
for (;;) {
for (cpu = iterator->cpu + 1; cpu < nr_cpus; ++cpu) {
if (cpu_online(cpu)) {
ksformat(name_buf, XNOBJECT_NAME_LEN, "IRQ%d: %s",
irq, intr->name);
query_irqstats(intr, cpu, iterator);
iterator->cpu = cpu;
return 0;
}
}
query_irqstats(intr, cpu, iterator);
iterator->prev = xnintr_vec_next(intr);
if (iterator->prev == NULL)
return -ENODEV;
/*
* Proceed to next entry in shared IRQ chain when all CPUs
* have been visited for this one.
*/
if (cpu + 1 == nr_cpus)
iterator->prev = intr;
return 0;
iterator->cpu = -1;
}
}
#endif /* CONFIG_XENO_OPT_STATS */
......
......@@ -1265,7 +1265,7 @@ static int vfile_schedstat_rewind(struct xnvfile_snapshot_iterator *it)
*/
priv->curr = list_first_entry(&nkthreadq, struct xnthread, glink);
priv->irq = 0;
irqnr = xnintr_query_init(&priv->intr_it) * NR_CPUS;
irqnr = xnintr_query_init(&priv->intr_it) * num_online_cpus();
return irqnr + cobalt_nrthreads;
}
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment