linux-kernel.vger.kernel.org archive mirror
 help / color / mirror / Atom feed
* [PATCH net-next v2 0/3] ipv6: per netns FIB6 walkers and garbage collector
@ 2016-03-08 13:44 Michal Kubecek
  2016-03-08 13:44 ` [PATCH net-next v2 1/3] ipv6: replace global gc_args with local variable Michal Kubecek
                   ` (3 more replies)
  0 siblings, 4 replies; 8+ messages in thread
From: Michal Kubecek @ 2016-03-08 13:44 UTC (permalink / raw)
  To: David S. Miller
  Cc: netdev, linux-kernel, Alexey Kuznetsov, James Morris,
	Hideaki YOSHIFUJI, Patrick McHardy, Hannes Frederic Sowa,
	Martin KaFai Lau, Cong Wang

Commit 2ac3ac8f86f2 ("ipv6: prevent fib6_run_gc() contention") reduced
the risk of contention on FIB6 garbage collector lock on systems with
many CPUs. However, one of our customers can still observe heavy
contention on fib6_gc_lock which can even trigger the soft lockup
detector.

This is caused by garbage collector running in forced mode from a timer.
While there is one timer per network namespace, the instances of
fib6_run_gc() running from them are protected by one global spinlock so
that only one garbage collector can run at any moment and other
namespaces have to wait. As most relevant data structures are separated
per netns, there is little reason for garbage collectors blocking each
other.

Similar problem exists for walkers: changes in one tree do not need to
adjust (and block) walkers traversing FIB trees in other namespaces.

This series separates both the walkers infrastructure and garbage
collector so that they work independently in network namespaces.

v2: get rid of ifdef in ipv6_route_seq_setup_walk(), pass net from
callers instead

Michal Kubecek (3):
  ipv6: replace global gc_args with local variable
  ipv6: per netns fib6 walkers
  ipv6: per netns FIB garbage collection

 include/net/netns/ipv6.h |  3 ++
 net/ipv6/ip6_fib.c       | 91 +++++++++++++++++++++++++-----------------------
 2 files changed, 51 insertions(+), 43 deletions(-)

-- 
2.7.2

^ permalink raw reply	[flat|nested] 8+ messages in thread

* [PATCH net-next v2 1/3] ipv6: replace global gc_args with local variable
  2016-03-08 13:44 [PATCH net-next v2 0/3] ipv6: per netns FIB6 walkers and garbage collector Michal Kubecek
@ 2016-03-08 13:44 ` Michal Kubecek
  2016-03-08 18:25   ` Cong Wang
  2016-03-08 13:44 ` [PATCH net-next v2 2/3] ipv6: per netns fib6 walkers Michal Kubecek
                   ` (2 subsequent siblings)
  3 siblings, 1 reply; 8+ messages in thread
From: Michal Kubecek @ 2016-03-08 13:44 UTC (permalink / raw)
  To: David S. Miller
  Cc: netdev, linux-kernel, Alexey Kuznetsov, James Morris,
	Hideaki YOSHIFUJI, Patrick McHardy, Hannes Frederic Sowa,
	Martin KaFai Lau, Cong Wang

Global variable gc_args is only used in fib6_run_gc() and functions
called from it. As fib6_run_gc() makes sure there is at most one
instance of fib6_clean_all() running at any moment, we can replace
gc_args with a local variable which will be needed once multiple
instances (per netns) of garbage collector are allowed.

Signed-off-by: Michal Kubecek <mkubecek@suse.cz>
---
 net/ipv6/ip6_fib.c | 14 ++++++++------
 1 file changed, 8 insertions(+), 6 deletions(-)

diff --git a/net/ipv6/ip6_fib.c b/net/ipv6/ip6_fib.c
index 0c7e276c230e..d7c715accac9 100644
--- a/net/ipv6/ip6_fib.c
+++ b/net/ipv6/ip6_fib.c
@@ -1725,14 +1725,15 @@ static void fib6_flush_trees(struct net *net)
  *	Garbage collection
  */
 
-static struct fib6_gc_args
+struct fib6_gc_args
 {
 	int			timeout;
 	int			more;
-} gc_args;
+};
 
 static int fib6_age(struct rt6_info *rt, void *arg)
 {
+	struct fib6_gc_args *gc_args = arg;
 	unsigned long now = jiffies;
 
 	/*
@@ -1748,10 +1749,10 @@ static int fib6_age(struct rt6_info *rt, void *arg)
 			RT6_TRACE("expiring %p\n", rt);
 			return -1;
 		}
-		gc_args.more++;
+		gc_args->more++;
 	} else if (rt->rt6i_flags & RTF_CACHE) {
 		if (atomic_read(&rt->dst.__refcnt) == 0 &&
-		    time_after_eq(now, rt->dst.lastuse + gc_args.timeout)) {
+		    time_after_eq(now, rt->dst.lastuse + gc_args->timeout)) {
 			RT6_TRACE("aging clone %p\n", rt);
 			return -1;
 		} else if (rt->rt6i_flags & RTF_GATEWAY) {
@@ -1769,7 +1770,7 @@ static int fib6_age(struct rt6_info *rt, void *arg)
 				return -1;
 			}
 		}
-		gc_args.more++;
+		gc_args->more++;
 	}
 
 	return 0;
@@ -1779,6 +1780,7 @@ static DEFINE_SPINLOCK(fib6_gc_lock);
 
 void fib6_run_gc(unsigned long expires, struct net *net, bool force)
 {
+	struct fib6_gc_args gc_args;
 	unsigned long now;
 
 	if (force) {
@@ -1792,7 +1794,7 @@ void fib6_run_gc(unsigned long expires, struct net *net, bool force)
 
 	gc_args.more = icmp6_dst_gc();
 
-	fib6_clean_all(net, fib6_age, NULL);
+	fib6_clean_all(net, fib6_age, &gc_args);
 	now = jiffies;
 	net->ipv6.ip6_rt_last_gc = now;
 
-- 
2.7.2

^ permalink raw reply related	[flat|nested] 8+ messages in thread

* [PATCH net-next v2 2/3] ipv6: per netns fib6 walkers
  2016-03-08 13:44 [PATCH net-next v2 0/3] ipv6: per netns FIB6 walkers and garbage collector Michal Kubecek
  2016-03-08 13:44 ` [PATCH net-next v2 1/3] ipv6: replace global gc_args with local variable Michal Kubecek
@ 2016-03-08 13:44 ` Michal Kubecek
  2016-03-08 18:34   ` Cong Wang
  2016-03-08 13:44 ` [PATCH net-next v2 3/3] ipv6: per netns FIB garbage collection Michal Kubecek
  2016-03-08 20:17 ` [PATCH net-next v2 0/3] ipv6: per netns FIB6 walkers and garbage collector David Miller
  3 siblings, 1 reply; 8+ messages in thread
From: Michal Kubecek @ 2016-03-08 13:44 UTC (permalink / raw)
  To: David S. Miller
  Cc: netdev, linux-kernel, Alexey Kuznetsov, James Morris,
	Hideaki YOSHIFUJI, Patrick McHardy, Hannes Frederic Sowa,
	Martin KaFai Lau, Cong Wang

The IPv6 FIB data structures are separated per network namespace but
there is still only one global walkers list and one global walker list
lock. This means changes in one namespace unnecessarily interfere with
walkers in other namespaces.

Replace the global list with per-netns lists (and give each its own
lock).

Signed-off-by: Michal Kubecek <mkubecek@suse.cz>
---
v2: get rid of ifdef in ipv6_route_seq_setup_walk(), pass net from
callers instead
---
 include/net/netns/ipv6.h |  2 ++
 net/ipv6/ip6_fib.c       | 68 +++++++++++++++++++++++++-----------------------
 2 files changed, 38 insertions(+), 32 deletions(-)

diff --git a/include/net/netns/ipv6.h b/include/net/netns/ipv6.h
index c0368db6df54..f0109b973648 100644
--- a/include/net/netns/ipv6.h
+++ b/include/net/netns/ipv6.h
@@ -58,7 +58,9 @@ struct netns_ipv6 {
 	struct timer_list       ip6_fib_timer;
 	struct hlist_head       *fib_table_hash;
 	struct fib6_table       *fib6_main_tbl;
+	struct list_head	fib6_walkers;
 	struct dst_ops		ip6_dst_ops;
+	rwlock_t		fib6_walker_lock;
 	unsigned int		 ip6_rt_gc_expire;
 	unsigned long		 ip6_rt_last_gc;
 #ifdef CONFIG_IPV6_MULTIPLE_TABLES
diff --git a/net/ipv6/ip6_fib.c b/net/ipv6/ip6_fib.c
index d7c715accac9..883f2836beab 100644
--- a/net/ipv6/ip6_fib.c
+++ b/net/ipv6/ip6_fib.c
@@ -55,8 +55,6 @@ struct fib6_cleaner {
 	void *arg;
 };
 
-static DEFINE_RWLOCK(fib6_walker_lock);
-
 #ifdef CONFIG_IPV6_SUBTREES
 #define FWS_INIT FWS_S
 #else
@@ -66,7 +64,7 @@ static DEFINE_RWLOCK(fib6_walker_lock);
 static void fib6_prune_clones(struct net *net, struct fib6_node *fn);
 static struct rt6_info *fib6_find_prefix(struct net *net, struct fib6_node *fn);
 static struct fib6_node *fib6_repair_tree(struct net *net, struct fib6_node *fn);
-static int fib6_walk(struct fib6_walker *w);
+static int fib6_walk(struct net *net, struct fib6_walker *w);
 static int fib6_walk_continue(struct fib6_walker *w);
 
 /*
@@ -78,21 +76,21 @@ static int fib6_walk_continue(struct fib6_walker *w);
 
 static void fib6_gc_timer_cb(unsigned long arg);
 
-static LIST_HEAD(fib6_walkers);
-#define FOR_WALKERS(w) list_for_each_entry(w, &fib6_walkers, lh)
+#define FOR_WALKERS(net, w) \
+	list_for_each_entry(w, &(net)->ipv6.fib6_walkers, lh)
 
-static void fib6_walker_link(struct fib6_walker *w)
+static void fib6_walker_link(struct net *net, struct fib6_walker *w)
 {
-	write_lock_bh(&fib6_walker_lock);
-	list_add(&w->lh, &fib6_walkers);
-	write_unlock_bh(&fib6_walker_lock);
+	write_lock_bh(&net->ipv6.fib6_walker_lock);
+	list_add(&w->lh, &net->ipv6.fib6_walkers);
+	write_unlock_bh(&net->ipv6.fib6_walker_lock);
 }
 
-static void fib6_walker_unlink(struct fib6_walker *w)
+static void fib6_walker_unlink(struct net *net, struct fib6_walker *w)
 {
-	write_lock_bh(&fib6_walker_lock);
+	write_lock_bh(&net->ipv6.fib6_walker_lock);
 	list_del(&w->lh);
-	write_unlock_bh(&fib6_walker_lock);
+	write_unlock_bh(&net->ipv6.fib6_walker_lock);
 }
 
 static int fib6_new_sernum(struct net *net)
@@ -325,12 +323,13 @@ static int fib6_dump_node(struct fib6_walker *w)
 
 static void fib6_dump_end(struct netlink_callback *cb)
 {
+	struct net *net = sock_net(cb->skb->sk);
 	struct fib6_walker *w = (void *)cb->args[2];
 
 	if (w) {
 		if (cb->args[4]) {
 			cb->args[4] = 0;
-			fib6_walker_unlink(w);
+			fib6_walker_unlink(net, w);
 		}
 		cb->args[2] = 0;
 		kfree(w);
@@ -348,6 +347,7 @@ static int fib6_dump_done(struct netlink_callback *cb)
 static int fib6_dump_table(struct fib6_table *table, struct sk_buff *skb,
 			   struct netlink_callback *cb)
 {
+	struct net *net = sock_net(skb->sk);
 	struct fib6_walker *w;
 	int res;
 
@@ -359,7 +359,7 @@ static int fib6_dump_table(struct fib6_table *table, struct sk_buff *skb,
 		w->skip = 0;
 
 		read_lock_bh(&table->tb6_lock);
-		res = fib6_walk(w);
+		res = fib6_walk(net, w);
 		read_unlock_bh(&table->tb6_lock);
 		if (res > 0) {
 			cb->args[4] = 1;
@@ -379,7 +379,7 @@ static int fib6_dump_table(struct fib6_table *table, struct sk_buff *skb,
 		res = fib6_walk_continue(w);
 		read_unlock_bh(&table->tb6_lock);
 		if (res <= 0) {
-			fib6_walker_unlink(w);
+			fib6_walker_unlink(net, w);
 			cb->args[4] = 0;
 		}
 	}
@@ -1340,8 +1340,8 @@ static struct fib6_node *fib6_repair_tree(struct net *net,
 		}
 #endif
 
-		read_lock(&fib6_walker_lock);
-		FOR_WALKERS(w) {
+		read_lock(&net->ipv6.fib6_walker_lock);
+		FOR_WALKERS(net, w) {
 			if (!child) {
 				if (w->root == fn) {
 					w->root = w->node = NULL;
@@ -1368,7 +1368,7 @@ static struct fib6_node *fib6_repair_tree(struct net *net,
 				}
 			}
 		}
-		read_unlock(&fib6_walker_lock);
+		read_unlock(&net->ipv6.fib6_walker_lock);
 
 		node_free(fn);
 		if (pn->fn_flags & RTN_RTINFO || FIB6_SUBTREE(pn))
@@ -1411,8 +1411,8 @@ static void fib6_del_route(struct fib6_node *fn, struct rt6_info **rtp,
 	}
 
 	/* Adjust walkers */
-	read_lock(&fib6_walker_lock);
-	FOR_WALKERS(w) {
+	read_lock(&net->ipv6.fib6_walker_lock);
+	FOR_WALKERS(net, w) {
 		if (w->state == FWS_C && w->leaf == rt) {
 			RT6_TRACE("walker %p adjusted by delroute\n", w);
 			w->leaf = rt->dst.rt6_next;
@@ -1420,7 +1420,7 @@ static void fib6_del_route(struct fib6_node *fn, struct rt6_info **rtp,
 				w->state = FWS_U;
 		}
 	}
-	read_unlock(&fib6_walker_lock);
+	read_unlock(&net->ipv6.fib6_walker_lock);
 
 	rt->dst.rt6_next = NULL;
 
@@ -1588,17 +1588,17 @@ skip:
 	}
 }
 
-static int fib6_walk(struct fib6_walker *w)
+static int fib6_walk(struct net *net, struct fib6_walker *w)
 {
 	int res;
 
 	w->state = FWS_INIT;
 	w->node = w->root;
 
-	fib6_walker_link(w);
+	fib6_walker_link(net, w);
 	res = fib6_walk_continue(w);
 	if (res <= 0)
-		fib6_walker_unlink(w);
+		fib6_walker_unlink(net, w);
 	return res;
 }
 
@@ -1668,7 +1668,7 @@ static void fib6_clean_tree(struct net *net, struct fib6_node *root,
 	c.arg = arg;
 	c.net = net;
 
-	fib6_walk(&c.w);
+	fib6_walk(net, &c.w);
 }
 
 static void __fib6_clean_all(struct net *net,
@@ -1816,6 +1816,8 @@ static int __net_init fib6_net_init(struct net *net)
 {
 	size_t size = sizeof(struct hlist_head) * FIB6_TABLE_HASHSZ;
 
+	rwlock_init(&net->ipv6.fib6_walker_lock);
+	INIT_LIST_HEAD(&net->ipv6.fib6_walkers);
 	setup_timer(&net->ipv6.ip6_fib_timer, fib6_gc_timer_cb, (unsigned long)net);
 
 	net->ipv6.rt6_stats = kzalloc(sizeof(*net->ipv6.rt6_stats), GFP_KERNEL);
@@ -1976,7 +1978,8 @@ static int ipv6_route_yield(struct fib6_walker *w)
 	return 0;
 }
 
-static void ipv6_route_seq_setup_walk(struct ipv6_route_iter *iter)
+static void ipv6_route_seq_setup_walk(struct ipv6_route_iter *iter,
+				      struct net *net)
 {
 	memset(&iter->w, 0, sizeof(iter->w));
 	iter->w.func = ipv6_route_yield;
@@ -1986,7 +1989,7 @@ static void ipv6_route_seq_setup_walk(struct ipv6_route_iter *iter)
 	iter->w.args = iter;
 	iter->sernum = iter->w.root->fn_sernum;
 	INIT_LIST_HEAD(&iter->w.lh);
-	fib6_walker_link(&iter->w);
+	fib6_walker_link(net, &iter->w);
 }
 
 static struct fib6_table *ipv6_route_seq_next_table(struct fib6_table *tbl,
@@ -2047,16 +2050,16 @@ iter_table:
 			++*pos;
 		return iter->w.leaf;
 	} else if (r < 0) {
-		fib6_walker_unlink(&iter->w);
+		fib6_walker_unlink(net, &iter->w);
 		return NULL;
 	}
-	fib6_walker_unlink(&iter->w);
+	fib6_walker_unlink(net, &iter->w);
 
 	iter->tbl = ipv6_route_seq_next_table(iter->tbl, net);
 	if (!iter->tbl)
 		return NULL;
 
-	ipv6_route_seq_setup_walk(iter);
+	ipv6_route_seq_setup_walk(iter, net);
 	goto iter_table;
 }
 
@@ -2071,7 +2074,7 @@ static void *ipv6_route_seq_start(struct seq_file *seq, loff_t *pos)
 	iter->skip = *pos;
 
 	if (iter->tbl) {
-		ipv6_route_seq_setup_walk(iter);
+		ipv6_route_seq_setup_walk(iter, net);
 		return ipv6_route_seq_next(seq, NULL, pos);
 	} else {
 		return NULL;
@@ -2087,10 +2090,11 @@ static bool ipv6_route_iter_active(struct ipv6_route_iter *iter)
 static void ipv6_route_seq_stop(struct seq_file *seq, void *v)
 	__releases(RCU_BH)
 {
+	struct net *net = seq_file_net(seq);
 	struct ipv6_route_iter *iter = seq->private;
 
 	if (ipv6_route_iter_active(iter))
-		fib6_walker_unlink(&iter->w);
+		fib6_walker_unlink(net, &iter->w);
 
 	rcu_read_unlock_bh();
 }
-- 
2.7.2

^ permalink raw reply related	[flat|nested] 8+ messages in thread

* [PATCH net-next v2 3/3] ipv6: per netns FIB garbage collection
  2016-03-08 13:44 [PATCH net-next v2 0/3] ipv6: per netns FIB6 walkers and garbage collector Michal Kubecek
  2016-03-08 13:44 ` [PATCH net-next v2 1/3] ipv6: replace global gc_args with local variable Michal Kubecek
  2016-03-08 13:44 ` [PATCH net-next v2 2/3] ipv6: per netns fib6 walkers Michal Kubecek
@ 2016-03-08 13:44 ` Michal Kubecek
  2016-03-08 18:36   ` Cong Wang
  2016-03-08 20:17 ` [PATCH net-next v2 0/3] ipv6: per netns FIB6 walkers and garbage collector David Miller
  3 siblings, 1 reply; 8+ messages in thread
From: Michal Kubecek @ 2016-03-08 13:44 UTC (permalink / raw)
  To: David S. Miller
  Cc: netdev, linux-kernel, Alexey Kuznetsov, James Morris,
	Hideaki YOSHIFUJI, Patrick McHardy, Hannes Frederic Sowa,
	Martin KaFai Lau, Cong Wang

One of our customers observed issues with FIB6 garbage collectors
running in different network namespaces blocking each other, resulting
in soft lockups (fib6_run_gc() initiated from timer runs always in
forced mode).

Now that FIB6 walkers are separated per namespace, there is no more need
for instances of fib6_run_gc() in different namespaces blocking each
other. There is still a call to icmp6_dst_gc() which operates on shared
data but this function is protected by its own shared lock.

Signed-off-by: Michal Kubecek <mkubecek@suse.cz>
---
 include/net/netns/ipv6.h | 1 +
 net/ipv6/ip6_fib.c       | 9 ++++-----
 2 files changed, 5 insertions(+), 5 deletions(-)

diff --git a/include/net/netns/ipv6.h b/include/net/netns/ipv6.h
index f0109b973648..10d0848f5b8a 100644
--- a/include/net/netns/ipv6.h
+++ b/include/net/netns/ipv6.h
@@ -61,6 +61,7 @@ struct netns_ipv6 {
 	struct list_head	fib6_walkers;
 	struct dst_ops		ip6_dst_ops;
 	rwlock_t		fib6_walker_lock;
+	spinlock_t		fib6_gc_lock;
 	unsigned int		 ip6_rt_gc_expire;
 	unsigned long		 ip6_rt_last_gc;
 #ifdef CONFIG_IPV6_MULTIPLE_TABLES
diff --git a/net/ipv6/ip6_fib.c b/net/ipv6/ip6_fib.c
index 883f2836beab..ea071fad67a0 100644
--- a/net/ipv6/ip6_fib.c
+++ b/net/ipv6/ip6_fib.c
@@ -1776,16 +1776,14 @@ static int fib6_age(struct rt6_info *rt, void *arg)
 	return 0;
 }
 
-static DEFINE_SPINLOCK(fib6_gc_lock);
-
 void fib6_run_gc(unsigned long expires, struct net *net, bool force)
 {
 	struct fib6_gc_args gc_args;
 	unsigned long now;
 
 	if (force) {
-		spin_lock_bh(&fib6_gc_lock);
-	} else if (!spin_trylock_bh(&fib6_gc_lock)) {
+		spin_lock_bh(&net->ipv6.fib6_gc_lock);
+	} else if (!spin_trylock_bh(&net->ipv6.fib6_gc_lock)) {
 		mod_timer(&net->ipv6.ip6_fib_timer, jiffies + HZ);
 		return;
 	}
@@ -1804,7 +1802,7 @@ void fib6_run_gc(unsigned long expires, struct net *net, bool force)
 					+ net->ipv6.sysctl.ip6_rt_gc_interval));
 	else
 		del_timer(&net->ipv6.ip6_fib_timer);
-	spin_unlock_bh(&fib6_gc_lock);
+	spin_unlock_bh(&net->ipv6.fib6_gc_lock);
 }
 
 static void fib6_gc_timer_cb(unsigned long arg)
@@ -1816,6 +1814,7 @@ static int __net_init fib6_net_init(struct net *net)
 {
 	size_t size = sizeof(struct hlist_head) * FIB6_TABLE_HASHSZ;
 
+	spin_lock_init(&net->ipv6.fib6_gc_lock);
 	rwlock_init(&net->ipv6.fib6_walker_lock);
 	INIT_LIST_HEAD(&net->ipv6.fib6_walkers);
 	setup_timer(&net->ipv6.ip6_fib_timer, fib6_gc_timer_cb, (unsigned long)net);
-- 
2.7.2

^ permalink raw reply related	[flat|nested] 8+ messages in thread

* Re: [PATCH net-next v2 1/3] ipv6: replace global gc_args with local variable
  2016-03-08 13:44 ` [PATCH net-next v2 1/3] ipv6: replace global gc_args with local variable Michal Kubecek
@ 2016-03-08 18:25   ` Cong Wang
  0 siblings, 0 replies; 8+ messages in thread
From: Cong Wang @ 2016-03-08 18:25 UTC (permalink / raw)
  To: Michal Kubecek
  Cc: David S. Miller, Linux Kernel Network Developers, LKML,
	Alexey Kuznetsov, James Morris, Hideaki YOSHIFUJI,
	Patrick McHardy, Hannes Frederic Sowa, Martin KaFai Lau

On Tue, Mar 8, 2016 at 5:44 AM, Michal Kubecek <mkubecek@suse.cz> wrote:
> Global variable gc_args is only used in fib6_run_gc() and functions
> called from it. As fib6_run_gc() makes sure there is at most one
> instance of fib6_clean_all() running at any moment, we can replace
> gc_args with a local variable which will be needed once multiple
> instances (per netns) of garbage collector are allowed.
>
> Signed-off-by: Michal Kubecek <mkubecek@suse.cz>

Reviewed-by: Cong Wang <xiyou.wangcong@gmail.com>

Thanks.

^ permalink raw reply	[flat|nested] 8+ messages in thread

* Re: [PATCH net-next v2 2/3] ipv6: per netns fib6 walkers
  2016-03-08 13:44 ` [PATCH net-next v2 2/3] ipv6: per netns fib6 walkers Michal Kubecek
@ 2016-03-08 18:34   ` Cong Wang
  0 siblings, 0 replies; 8+ messages in thread
From: Cong Wang @ 2016-03-08 18:34 UTC (permalink / raw)
  To: Michal Kubecek
  Cc: David S. Miller, Linux Kernel Network Developers, LKML,
	Alexey Kuznetsov, James Morris, Hideaki YOSHIFUJI,
	Patrick McHardy, Hannes Frederic Sowa, Martin KaFai Lau

On Tue, Mar 8, 2016 at 5:44 AM, Michal Kubecek <mkubecek@suse.cz> wrote:
> The IPv6 FIB data structures are separated per network namespace but
> there is still only one global walkers list and one global walker list
> lock. This means changes in one namespace unnecessarily interfere with
> walkers in other namespaces.
>
> Replace the global list with per-netns lists (and give each its own
> lock).
>
> Signed-off-by: Michal Kubecek <mkubecek@suse.cz>
> ---
> v2: get rid of ifdef in ipv6_route_seq_setup_walk(), pass net from
> callers instead

Reviewed-by: Cong Wang <xiyou.wangcong@gmail.com>

^ permalink raw reply	[flat|nested] 8+ messages in thread

* Re: [PATCH net-next v2 3/3] ipv6: per netns FIB garbage collection
  2016-03-08 13:44 ` [PATCH net-next v2 3/3] ipv6: per netns FIB garbage collection Michal Kubecek
@ 2016-03-08 18:36   ` Cong Wang
  0 siblings, 0 replies; 8+ messages in thread
From: Cong Wang @ 2016-03-08 18:36 UTC (permalink / raw)
  To: Michal Kubecek
  Cc: David S. Miller, Linux Kernel Network Developers, LKML,
	Alexey Kuznetsov, James Morris, Hideaki YOSHIFUJI,
	Patrick McHardy, Hannes Frederic Sowa, Martin KaFai Lau

On Tue, Mar 8, 2016 at 5:44 AM, Michal Kubecek <mkubecek@suse.cz> wrote:
> One of our customers observed issues with FIB6 garbage collectors
> running in different network namespaces blocking each other, resulting
> in soft lockups (fib6_run_gc() initiated from timer runs always in
> forced mode).
>
> Now that FIB6 walkers are separated per namespace, there is no more need
> for instances of fib6_run_gc() in different namespaces blocking each
> other. There is still a call to icmp6_dst_gc() which operates on shared
> data but this function is protected by its own shared lock.
>
> Signed-off-by: Michal Kubecek <mkubecek@suse.cz>


Reviewed-by: Cong Wang <xiyou.wangcong@gmail.com>

^ permalink raw reply	[flat|nested] 8+ messages in thread

* Re: [PATCH net-next v2 0/3] ipv6: per netns FIB6 walkers and garbage collector
  2016-03-08 13:44 [PATCH net-next v2 0/3] ipv6: per netns FIB6 walkers and garbage collector Michal Kubecek
                   ` (2 preceding siblings ...)
  2016-03-08 13:44 ` [PATCH net-next v2 3/3] ipv6: per netns FIB garbage collection Michal Kubecek
@ 2016-03-08 20:17 ` David Miller
  3 siblings, 0 replies; 8+ messages in thread
From: David Miller @ 2016-03-08 20:17 UTC (permalink / raw)
  To: mkubecek
  Cc: netdev, linux-kernel, kuznet, jmorris, yoshfuji, kaber, hannes,
	kafai, xiyou.wangcong

From: Michal Kubecek <mkubecek@suse.cz>
Date: Tue,  8 Mar 2016 14:44:15 +0100 (CET)

> Commit 2ac3ac8f86f2 ("ipv6: prevent fib6_run_gc() contention") reduced
> the risk of contention on FIB6 garbage collector lock on systems with
> many CPUs. However, one of our customers can still observe heavy
> contention on fib6_gc_lock which can even trigger the soft lockup
> detector.
> 
> This is caused by garbage collector running in forced mode from a timer.
> While there is one timer per network namespace, the instances of
> fib6_run_gc() running from them are protected by one global spinlock so
> that only one garbage collector can run at any moment and other
> namespaces have to wait. As most relevant data structures are separated
> per netns, there is little reason for garbage collectors blocking each
> other.
> 
> Similar problem exists for walkers: changes in one tree do not need to
> adjust (and block) walkers traversing FIB trees in other namespaces.
> 
> This series separates both the walkers infrastructure and garbage
> collector so that they work independently in network namespaces.
> 
> v2: get rid of ifdef in ipv6_route_seq_setup_walk(), pass net from
> callers instead

Series applied, thanks.

^ permalink raw reply	[flat|nested] 8+ messages in thread

end of thread, other threads:[~2016-03-08 20:17 UTC | newest]

Thread overview: 8+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2016-03-08 13:44 [PATCH net-next v2 0/3] ipv6: per netns FIB6 walkers and garbage collector Michal Kubecek
2016-03-08 13:44 ` [PATCH net-next v2 1/3] ipv6: replace global gc_args with local variable Michal Kubecek
2016-03-08 18:25   ` Cong Wang
2016-03-08 13:44 ` [PATCH net-next v2 2/3] ipv6: per netns fib6 walkers Michal Kubecek
2016-03-08 18:34   ` Cong Wang
2016-03-08 13:44 ` [PATCH net-next v2 3/3] ipv6: per netns FIB garbage collection Michal Kubecek
2016-03-08 18:36   ` Cong Wang
2016-03-08 20:17 ` [PATCH net-next v2 0/3] ipv6: per netns FIB6 walkers and garbage collector David Miller

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).