Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

[NET]: Add preemption point in qdisc_run

The qdisc_run loop is currently unbounded and runs entirely in a
softirq. This is bad as it may create an unbounded softirq run.

This patch fixes this by calling need_resched and breaking out if
necessary.

It also adds a break out if the jiffies value changes since that would
indicate we've been transmitting for too long which starves other
softirqs.

Signed-off-by: Herbert Xu <herbert@gondor.apana.org.au>
Signed-off-by: David S. Miller <davem@davemloft.net>

authored by

Herbert Xu and committed by
David S. Miller
2ba2506c 32aced75

+15 -3
+15 -3
net/sched/sch_generic.c
··· 184 184 185 185 void __qdisc_run(struct net_device *dev) 186 186 { 187 - do { 188 - if (!qdisc_restart(dev)) 187 + unsigned long start_time = jiffies; 188 + 189 + while (qdisc_restart(dev)) { 190 + if (netif_queue_stopped(dev)) 189 191 break; 190 - } while (!netif_queue_stopped(dev)); 192 + 193 + /* 194 + * Postpone processing if 195 + * 1. another process needs the CPU; 196 + * 2. we've been doing it for too long. 197 + */ 198 + if (need_resched() || jiffies != start_time) { 199 + netif_schedule(dev); 200 + break; 201 + } 202 + } 191 203 192 204 clear_bit(__LINK_STATE_QDISC_RUNNING, &dev->state); 193 205 }