[kernel] r19616 - in dists/squeeze/linux-2.6/debian: . patches/bugfix/all patches/series

Ben Hutchings benh at alioth.debian.org
Mon Dec 17 00:17:34 UTC 2012


Author: benh
Date: Mon Dec 17 00:17:34 2012
New Revision: 19616

Log:
net: fix route cache rebuilds (Closes: #646063)

Added:
   dists/squeeze/linux-2.6/debian/patches/bugfix/all/net-fix-route-cache-rebuilds.patch
Modified:
   dists/squeeze/linux-2.6/debian/changelog
   dists/squeeze/linux-2.6/debian/patches/series/47

Modified: dists/squeeze/linux-2.6/debian/changelog
==============================================================================
--- dists/squeeze/linux-2.6/debian/changelog	Sun Dec 16 23:23:22 2012	(r19615)
+++ dists/squeeze/linux-2.6/debian/changelog	Mon Dec 17 00:17:34 2012	(r19616)
@@ -7,6 +7,7 @@
   * header: fix broken headers for user space (Closes: #692133)
   * nfsv4: Fix kernel panic when mounting NFSv4 (Closes: #695872)
   * hpsa: Backport changes up to Linux 3.2.35 (Closes: #690100)
+  * net: fix route cache rebuilds (Closes: #646063)
 
   [ Jonathan Nieder ]
   * megaraid_sas: Backport changes up to Linux 3.0.56 (Closes: #666108)

Added: dists/squeeze/linux-2.6/debian/patches/bugfix/all/net-fix-route-cache-rebuilds.patch
==============================================================================
--- /dev/null	00:00:00 1970	(empty, because file is newly added)
+++ dists/squeeze/linux-2.6/debian/patches/bugfix/all/net-fix-route-cache-rebuilds.patch	Mon Dec 17 00:17:34 2012	(r19616)
@@ -0,0 +1,145 @@
+From: Eric Dumazet <eric.dumazet at gmail.com>
+Date: Mon, 8 Mar 2010 03:20:00 +0000
+Subject: net: fix route cache rebuilds
+MIME-Version: 1.0
+Content-Type: text/plain; charset=UTF-8
+Content-Transfer-Encoding: 8bit
+
+commit 9837638727488922727b0cfd438039fa73364183 upstream.
+
+We added an automatic route cache rebuilding in commit 1080d709fb9d8cd43
+but had to correct few bugs. One of the assumption of original patch,
+was that entries where kept sorted in a given way.
+
+This assumption is known to be wrong (commit 1ddbcb005c395518 gave an
+explanation of this and corrected a leak) and expensive to respect.
+
+Paweł Staszewski reported to me one of his machine got its routing cache
+disabled after few messages like :
+
+[ 2677.850065] Route hash chain too long!
+[ 2677.850080] Adjust your secret_interval!
+[82839.662993] Route hash chain too long!
+[82839.662996] Adjust your secret_interval!
+[155843.731650] Route hash chain too long!
+[155843.731664] Adjust your secret_interval!
+[155843.811881] Route hash chain too long!
+[155843.811891] Adjust your secret_interval!
+[155843.858209] vlan0811: 5 rebuilds is over limit, route caching
+disabled
+[155843.858212] Route hash chain too long!
+[155843.858213] Adjust your secret_interval!
+
+This is because rt_intern_hash() might be fooled when computing a chain
+length, because multiple entries with same keys can differ because of
+TOS (or mark/oif) bits.
+
+In the rare case the fast algorithm see a too long chain, and before
+taking expensive path, we call a helper function in order to not count
+duplicates of same routes, that only differ with tos/mark/oif bits. This
+helper works with data already in cpu cache and is not be very
+expensive, despite its O(N^2) implementation.
+
+Paweł Staszewski sucessfully tested this patch on his loaded router.
+
+Reported-and-tested-by: Paweł Staszewski <pstaszewski at itcare.pl>
+Signed-off-by: Eric Dumazet <eric.dumazet at gmail.com>
+Acked-by: Neil Horman <nhorman at tuxdriver.com>
+Signed-off-by: David S. Miller <davem at davemloft.net>
+---
+ net/ipv4/route.c |   50 ++++++++++++++++++++++++++++++++++++++------------
+ 1 file changed, 38 insertions(+), 12 deletions(-)
+
+diff --git a/net/ipv4/route.c b/net/ipv4/route.c
+index b2ba558..d9b4024 100644
+--- a/net/ipv4/route.c
++++ b/net/ipv4/route.c
+@@ -146,7 +146,6 @@ static struct dst_entry *ipv4_negative_advice(struct dst_entry *dst);
+ static void		 ipv4_link_failure(struct sk_buff *skb);
+ static void		 ip_rt_update_pmtu(struct dst_entry *dst, u32 mtu);
+ static int rt_garbage_collect(struct dst_ops *ops);
+-static void rt_emergency_hash_rebuild(struct net *net);
+ 
+ 
+ static struct dst_ops ipv4_dst_ops = {
+@@ -780,11 +779,30 @@ static void rt_do_flush(int process_context)
+ #define FRACT_BITS 3
+ #define ONE (1UL << FRACT_BITS)
+ 
++/*
++ * Given a hash chain and an item in this hash chain,
++ * find if a previous entry has the same hash_inputs
++ * (but differs on tos, mark or oif)
++ * Returns 0 if an alias is found.
++ * Returns ONE if rth has no alias before itself.
++ */
++static int has_noalias(const struct rtable *head, const struct rtable *rth)
++{
++	const struct rtable *aux = head;
++
++	while (aux != rth) {
++		if (compare_hash_inputs(&aux->fl, &rth->fl))
++			return 0;
++		aux = aux->u.dst.rt_next;
++	}
++	return ONE;
++}
++
+ static void rt_check_expire(void)
+ {
+ 	static unsigned int rover;
+ 	unsigned int i = rover, goal;
+-	struct rtable *rth, *aux, **rthp;
++	struct rtable *rth, **rthp;
+ 	unsigned long samples = 0;
+ 	unsigned long sum = 0, sum2 = 0;
+ 	unsigned long delta;
+@@ -835,15 +853,7 @@ nofree:
+ 					 * attributes don't unfairly skew
+ 					 * the length computation
+ 					 */
+-					for (aux = rt_hash_table[i].chain;;) {
+-						if (aux == rth) {
+-							length += ONE;
+-							break;
+-						}
+-						if (compare_hash_inputs(&aux->fl, &rth->fl))
+-							break;
+-						aux = aux->u.dst.rt_next;
+-					}
++					length += has_noalias(rt_hash_table[i].chain, rth);
+ 					continue;
+ 				}
+ 			} else if (!rt_may_expire(rth, tmo, ip_rt_gc_timeout))
+@@ -1073,6 +1083,21 @@ work_done:
+ out:	return 0;
+ }
+ 
++/*
++ * Returns number of entries in a hash chain that have different hash_inputs
++ */
++static int slow_chain_length(const struct rtable *head)
++{
++	int length = 0;
++	const struct rtable *rth = head;
++
++	while (rth) {
++		length += has_noalias(head, rth);
++		rth = rth->u.dst.rt_next;
++	}
++	return length >> FRACT_BITS;
++}
++
+ static int rt_intern_hash(unsigned hash, struct rtable *rt,
+ 			  struct rtable **rp, struct sk_buff *skb)
+ {
+@@ -1185,7 +1210,8 @@ restart:
+ 			rt_free(cand);
+ 		}
+ 	} else {
+-		if (chain_length > rt_chain_length_max) {
++		if (chain_length > rt_chain_length_max &&
++		    slow_chain_length(rt_hash_table[hash].chain) > rt_chain_length_max) {
+ 			struct net *net = dev_net(rt->u.dst.dev);
+ 			int num = ++net->ipv4.current_rt_cache_rebuild_count;
+ 			if (!rt_caching(dev_net(rt->u.dst.dev))) {

Modified: dists/squeeze/linux-2.6/debian/patches/series/47
==============================================================================
--- dists/squeeze/linux-2.6/debian/patches/series/47	Sun Dec 16 23:23:22 2012	(r19615)
+++ dists/squeeze/linux-2.6/debian/patches/series/47	Mon Dec 17 00:17:34 2012	(r19616)
@@ -118,3 +118,5 @@
 + features/all/megaraid_sas/0052-megaraid_sas-version-and-changelog-update.patch
 + features/all/megaraid_sas/0053-megaraid_sas-move-poll_aen_lock-initializer.patch
 + features/all/megaraid_sas/0054-megaraid_sas-cosmetic-changes.patch
+
++ bugfix/all/net-fix-route-cache-rebuilds.patch



More information about the Kernel-svn-changes mailing list