Sophie

Sophie

distrib > Scientific%20Linux > 5x > x86_64 > by-pkgid > 27922b4260f65d317aabda37e42bbbff > files > 2341

kernel-2.6.18-238.el5.src.rpm

From: Jiri Pirko <jpirko@redhat.com>
Date: Mon, 22 Dec 2008 15:38:54 +0100
Subject: [net] add preemption point in qdisc_run
Message-id: 20081222153854.56c180d8@psychotron.englab.brq.redhat.com
O-Subject: [RHEL5.4 patch] BZ471398 net: add preemption point in qdisc_run
Bugzilla: 471398
RH-Acked-by: Michal Schmidt <mschmidt@redhat.com>
RH-Acked-by: Neil Horman <nhorman@redhat.com>
RH-Acked-by: Herbert Xu <herbert.xu@redhat.com>
CVE: CVE-2008-5713

BZ471398
https://bugzilla.redhat.com/show_bug.cgi?id=471398

Description:
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.

Upstream:
http://git.kernel.org/?p=linux/kernel/git/torvalds/linux-2.6.git;a=commit;h=2ba2506ca7ca62c56edaa334b0fe61eb5eab6ab0

Brew:
https://brewweb.devel.redhat.com/taskinfo?taskID=1624510

Test:
Booted and tested with reproducer on nec-em8.rhts.bos.redhat.com
(16cpu, x86_64). Used hp-ml370g4-01.rhts.bos.redhat.com as a
"netserver". With -92 kernel I was able to trigger the soft lookup
safely like this:
./np hp-ml370g4-01.rhts.bos.redhat.com 40

With patched kernel I was unable to trigger the soft lookup even after
few reproducer runs.

Jirka

diff --git a/net/sched/sch_generic.c b/net/sched/sch_generic.c
index 88c6a99..d0df5b5 100644
--- a/net/sched/sch_generic.c
+++ b/net/sched/sch_generic.c
@@ -183,11 +183,25 @@ requeue:
 
 void __qdisc_run(struct net_device *dev)
 {
+	unsigned long start_time = jiffies;
+
 	if (unlikely(dev->qdisc == &noop_qdisc))
 		goto out;
 
-	while (qdisc_restart(dev) < 0 && !netif_queue_stopped(dev))
-		/* NOTHING */;
+	while (qdisc_restart(dev) < 0) {
+		if (netif_queue_stopped(dev))
+			break;
+
+		/*
+		 * Postpone processing if
+		 * 1. another process needs the CPU;
+		 * 2. we've been doing it for too long.
+		 */
+		if (need_resched() || jiffies != start_time) {
+			netif_schedule(dev);
+			break;
+		}
+	}
 
 out:
 	clear_bit(__LINK_STATE_QDISC_RUNNING, &dev->state);