Re: [PATCH net 0/2] net/sched: taprio: fix RCU stall from replayed schedule entries

From: Jakub Kicinski

Date: Thu Oct 08 2026 - 12:17:56 EST


On Tue, 6 Oct 2026 13:33:33 +0200 Krystian Kaniewski wrote:
> syzbot reported an RCU stall with a software taprio schedule made of a
> single 127 ns entry. When advance_sched() falls behind, it replays every
> missed entry inside the timer interrupt and the backlog only grows.
> Patch 2 makes it continue from the entry in progress instead.
>
> Patch 2 then checks for an admin schedule handover once after catching
> up. That requires the cycle_time_extension comparison to be monotonic,
> so the sum now saturates instead of wrapping. As a result a large
> extension can hand over to an admin schedule whose start time leaves no
> room for the timestamps derived from it. Initializing such a schedule
> already overflows today, and a carefully chosen extension can already
> reach it. Patch 1 rejects these schedules at configuration time and
> comes first, so the series never hands over to one.

The coccicheck CI job flags a new warning introduced by this patch:

net/sched/sch_taprio.c:972:8-13: ERROR: invalid reference to the index
variable of the iterator on line 959

This points at the new taprio_entry_at() helper:

list_for_each_entry(entry, &sched->entries, list) {
entry_end = min_t(s64, elapsed + entry->interval,
sched->cycle_time);
if (offset < entry_end ||
list_is_last(&entry->list, &sched->entries))
break;
elapsed = entry_end;
}
...
return entry;

`entry` is read/returned after the loop. Even though every code path here
actually breaks out of the loop on a real list element (the
list_is_last() check guarantees this), Coccinelle's generic
use-after-iterator check cannot verify that and treats any post-loop use
of the loop variable as a potential bug, since on a normal (non-break)
loop exit `entry` would point at the list head sentinel rather than a
valid `struct sched_entry`.

Could you restructure the helper to avoid reading `entry` after the loop,
e.g. by tracking the last matched entry in a separate local variable set
inside the loop body before the break, or by adding an explicit
"not found" fallback assignment after the loop? That should keep the
logic identical while satisfying the checker.