Skip to content

Commit 8c21ab1

Browse files
edumazetPaolo Abeni
authored andcommitted
net/sched: fq_pie: avoid stalls in fq_pie_timer()
When setting a high number of flows (limit being 65536), fq_pie_timer() is currently using too much time as syzbot reported. Add logic to yield the cpu every 2048 flows (less than 150 usec on debug kernels). It should also help by not blocking qdisc fast paths for too long. Worst case (65536 flows) would need 31 jiffies for a complete scan. Relevant extract from syzbot report: rcu: INFO: rcu_preempt detected expedited stalls on CPUs/tasks: { 0-.... } 2663 jiffies s: 873 root: 0x1/. rcu: blocking rcu_node structures (internal RCU debug): Sending NMI from CPU 1 to CPUs 0: NMI backtrace for cpu 0 CPU: 0 PID: 5177 Comm: syz-executor273 Not tainted 6.5.0-syzkaller-00453-g727dbda16b83 #0 Hardware name: Google Google Compute Engine/Google Compute Engine, BIOS Google 07/26/2023 RIP: 0010:check_kcov_mode kernel/kcov.c:173 [inline] RIP: 0010:write_comp_data+0x21/0x90 kernel/kcov.c:236 Code: 2e 0f 1f 84 00 00 00 00 00 65 8b 05 01 b2 7d 7e 49 89 f1 89 c6 49 89 d2 81 e6 00 01 00 00 49 89 f8 65 48 8b 14 25 80 b9 03 00 <a9> 00 01 ff 00 74 0e 85 f6 74 59 8b 82 04 16 00 00 85 c0 74 4f 8b RSP: 0018:ffffc90000007bb8 EFLAGS: 00000206 RAX: 0000000000000101 RBX: ffffc9000dc0d140 RCX: ffffffff885893b0 RDX: ffff88807c075940 RSI: 0000000000000100 RDI: 0000000000000001 RBP: 0000000000000000 R08: 0000000000000001 R09: 0000000000000000 R10: 0000000000000000 R11: 0000000000000000 R12: ffffc9000dc0d178 R13: 0000000000000000 R14: 0000000000000000 R15: 0000000000000000 FS: 0000555555d54380(0000) GS:ffff8880b9800000(0000) knlGS:0000000000000000 CS: 0010 DS: 0000 ES: 0000 CR0: 0000000080050033 CR2: 00007f6b442f6130 CR3: 000000006fe1c000 CR4: 00000000003506f0 DR0: 0000000000000000 DR1: 0000000000000000 DR2: 0000000000000000 DR3: 0000000000000000 DR6: 00000000fffe0ff0 DR7: 0000000000000400 Call Trace: <NMI> </NMI> <IRQ> pie_calculate_probability+0x480/0x850 net/sched/sch_pie.c:415 fq_pie_timer+0x1da/0x4f0 net/sched/sch_fq_pie.c:387 call_timer_fn+0x1a0/0x580 kernel/time/timer.c:1700 Fixes: ec97ecf ("net: sched: add Flow Queue PIE packet scheduler") Link: https://lore.kernel.org/lkml/[email protected]/ Reported-by: [email protected] Signed-off-by: Eric Dumazet <[email protected]> Reviewed-by: Michal Kubiak <[email protected]> Reviewed-by: Jamal Hadi Salim <[email protected]> Link: https://lore.kernel.org/r/[email protected] Signed-off-by: Paolo Abeni <[email protected]>
1 parent 4e60de1 commit 8c21ab1

File tree

1 file changed

+19
-8
lines changed

1 file changed

+19
-8
lines changed

net/sched/sch_fq_pie.c

Lines changed: 19 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -61,6 +61,7 @@ struct fq_pie_sched_data {
6161
struct pie_params p_params;
6262
u32 ecn_prob;
6363
u32 flows_cnt;
64+
u32 flows_cursor;
6465
u32 quantum;
6566
u32 memory_limit;
6667
u32 new_flow_count;
@@ -375,22 +376,32 @@ static int fq_pie_change(struct Qdisc *sch, struct nlattr *opt,
375376
static void fq_pie_timer(struct timer_list *t)
376377
{
377378
struct fq_pie_sched_data *q = from_timer(q, t, adapt_timer);
379+
unsigned long next, tupdate;
378380
struct Qdisc *sch = q->sch;
379381
spinlock_t *root_lock; /* to lock qdisc for probability calculations */
380-
u32 idx;
382+
int max_cnt, i;
381383

382384
rcu_read_lock();
383385
root_lock = qdisc_lock(qdisc_root_sleeping(sch));
384386
spin_lock(root_lock);
385387

386-
for (idx = 0; idx < q->flows_cnt; idx++)
387-
pie_calculate_probability(&q->p_params, &q->flows[idx].vars,
388-
q->flows[idx].backlog);
389-
390-
/* reset the timer to fire after 'tupdate' jiffies. */
391-
if (q->p_params.tupdate)
392-
mod_timer(&q->adapt_timer, jiffies + q->p_params.tupdate);
388+
/* Limit this expensive loop to 2048 flows per round. */
389+
max_cnt = min_t(int, q->flows_cnt - q->flows_cursor, 2048);
390+
for (i = 0; i < max_cnt; i++) {
391+
pie_calculate_probability(&q->p_params,
392+
&q->flows[q->flows_cursor].vars,
393+
q->flows[q->flows_cursor].backlog);
394+
q->flows_cursor++;
395+
}
393396

397+
tupdate = q->p_params.tupdate;
398+
next = 0;
399+
if (q->flows_cursor >= q->flows_cnt) {
400+
q->flows_cursor = 0;
401+
next = tupdate;
402+
}
403+
if (tupdate)
404+
mod_timer(&q->adapt_timer, jiffies + next);
394405
spin_unlock(root_lock);
395406
rcu_read_unlock();
396407
}

0 commit comments

Comments
 (0)