diff options
Diffstat (limited to 'net/ipv6/ip6_fib.c')
-rw-r--r-- | net/ipv6/ip6_fib.c | 53 |
1 files changed, 35 insertions, 18 deletions
diff --git a/net/ipv6/ip6_fib.c b/net/ipv6/ip6_fib.c index 0e93ca56eb69..6b82e02158c6 100644 --- a/net/ipv6/ip6_fib.c +++ b/net/ipv6/ip6_fib.c | |||
@@ -26,6 +26,7 @@ | |||
26 | #include <linux/in6.h> | 26 | #include <linux/in6.h> |
27 | #include <linux/init.h> | 27 | #include <linux/init.h> |
28 | #include <linux/list.h> | 28 | #include <linux/list.h> |
29 | #include <linux/slab.h> | ||
29 | 30 | ||
30 | #ifdef CONFIG_PROC_FS | 31 | #ifdef CONFIG_PROC_FS |
31 | #include <linux/proc_fs.h> | 32 | #include <linux/proc_fs.h> |
@@ -93,29 +94,20 @@ static __u32 rt_sernum; | |||
93 | 94 | ||
94 | static void fib6_gc_timer_cb(unsigned long arg); | 95 | static void fib6_gc_timer_cb(unsigned long arg); |
95 | 96 | ||
96 | static struct fib6_walker_t fib6_walker_list = { | 97 | static LIST_HEAD(fib6_walkers); |
97 | .prev = &fib6_walker_list, | 98 | #define FOR_WALKERS(w) list_for_each_entry(w, &fib6_walkers, lh) |
98 | .next = &fib6_walker_list, | ||
99 | }; | ||
100 | |||
101 | #define FOR_WALKERS(w) for ((w)=fib6_walker_list.next; (w) != &fib6_walker_list; (w)=(w)->next) | ||
102 | 99 | ||
103 | static inline void fib6_walker_link(struct fib6_walker_t *w) | 100 | static inline void fib6_walker_link(struct fib6_walker_t *w) |
104 | { | 101 | { |
105 | write_lock_bh(&fib6_walker_lock); | 102 | write_lock_bh(&fib6_walker_lock); |
106 | w->next = fib6_walker_list.next; | 103 | list_add(&w->lh, &fib6_walkers); |
107 | w->prev = &fib6_walker_list; | ||
108 | w->next->prev = w; | ||
109 | w->prev->next = w; | ||
110 | write_unlock_bh(&fib6_walker_lock); | 104 | write_unlock_bh(&fib6_walker_lock); |
111 | } | 105 | } |
112 | 106 | ||
113 | static inline void fib6_walker_unlink(struct fib6_walker_t *w) | 107 | static inline void fib6_walker_unlink(struct fib6_walker_t *w) |
114 | { | 108 | { |
115 | write_lock_bh(&fib6_walker_lock); | 109 | write_lock_bh(&fib6_walker_lock); |
116 | w->next->prev = w->prev; | 110 | list_del(&w->lh); |
117 | w->prev->next = w->next; | ||
118 | w->prev = w->next = w; | ||
119 | write_unlock_bh(&fib6_walker_lock); | 111 | write_unlock_bh(&fib6_walker_lock); |
120 | } | 112 | } |
121 | static __inline__ u32 fib6_new_sernum(void) | 113 | static __inline__ u32 fib6_new_sernum(void) |
@@ -239,7 +231,7 @@ struct fib6_table *fib6_get_table(struct net *net, u32 id) | |||
239 | return NULL; | 231 | return NULL; |
240 | } | 232 | } |
241 | 233 | ||
242 | static void fib6_tables_init(struct net *net) | 234 | static void __net_init fib6_tables_init(struct net *net) |
243 | { | 235 | { |
244 | fib6_link_table(net, net->ipv6.fib6_main_tbl); | 236 | fib6_link_table(net, net->ipv6.fib6_main_tbl); |
245 | fib6_link_table(net, net->ipv6.fib6_local_tbl); | 237 | fib6_link_table(net, net->ipv6.fib6_local_tbl); |
@@ -262,7 +254,7 @@ struct dst_entry *fib6_rule_lookup(struct net *net, struct flowi *fl, | |||
262 | return (struct dst_entry *) lookup(net, net->ipv6.fib6_main_tbl, fl, flags); | 254 | return (struct dst_entry *) lookup(net, net->ipv6.fib6_main_tbl, fl, flags); |
263 | } | 255 | } |
264 | 256 | ||
265 | static void fib6_tables_init(struct net *net) | 257 | static void __net_init fib6_tables_init(struct net *net) |
266 | { | 258 | { |
267 | fib6_link_table(net, net->ipv6.fib6_main_tbl); | 259 | fib6_link_table(net, net->ipv6.fib6_main_tbl); |
268 | } | 260 | } |
@@ -319,12 +311,26 @@ static int fib6_dump_table(struct fib6_table *table, struct sk_buff *skb, | |||
319 | w->root = &table->tb6_root; | 311 | w->root = &table->tb6_root; |
320 | 312 | ||
321 | if (cb->args[4] == 0) { | 313 | if (cb->args[4] == 0) { |
314 | w->count = 0; | ||
315 | w->skip = 0; | ||
316 | |||
322 | read_lock_bh(&table->tb6_lock); | 317 | read_lock_bh(&table->tb6_lock); |
323 | res = fib6_walk(w); | 318 | res = fib6_walk(w); |
324 | read_unlock_bh(&table->tb6_lock); | 319 | read_unlock_bh(&table->tb6_lock); |
325 | if (res > 0) | 320 | if (res > 0) { |
326 | cb->args[4] = 1; | 321 | cb->args[4] = 1; |
322 | cb->args[5] = w->root->fn_sernum; | ||
323 | } | ||
327 | } else { | 324 | } else { |
325 | if (cb->args[5] != w->root->fn_sernum) { | ||
326 | /* Begin at the root if the tree changed */ | ||
327 | cb->args[5] = w->root->fn_sernum; | ||
328 | w->state = FWS_INIT; | ||
329 | w->node = w->root; | ||
330 | w->skip = w->count; | ||
331 | } else | ||
332 | w->skip = 0; | ||
333 | |||
328 | read_lock_bh(&table->tb6_lock); | 334 | read_lock_bh(&table->tb6_lock); |
329 | res = fib6_walk_continue(w); | 335 | res = fib6_walk_continue(w); |
330 | read_unlock_bh(&table->tb6_lock); | 336 | read_unlock_bh(&table->tb6_lock); |
@@ -1250,9 +1256,18 @@ static int fib6_walk_continue(struct fib6_walker_t *w) | |||
1250 | w->leaf = fn->leaf; | 1256 | w->leaf = fn->leaf; |
1251 | case FWS_C: | 1257 | case FWS_C: |
1252 | if (w->leaf && fn->fn_flags&RTN_RTINFO) { | 1258 | if (w->leaf && fn->fn_flags&RTN_RTINFO) { |
1253 | int err = w->func(w); | 1259 | int err; |
1260 | |||
1261 | if (w->count < w->skip) { | ||
1262 | w->count++; | ||
1263 | continue; | ||
1264 | } | ||
1265 | |||
1266 | err = w->func(w); | ||
1254 | if (err) | 1267 | if (err) |
1255 | return err; | 1268 | return err; |
1269 | |||
1270 | w->count++; | ||
1256 | continue; | 1271 | continue; |
1257 | } | 1272 | } |
1258 | w->state = FWS_U; | 1273 | w->state = FWS_U; |
@@ -1346,6 +1361,8 @@ static void fib6_clean_tree(struct net *net, struct fib6_node *root, | |||
1346 | c.w.root = root; | 1361 | c.w.root = root; |
1347 | c.w.func = fib6_clean_node; | 1362 | c.w.func = fib6_clean_node; |
1348 | c.w.prune = prune; | 1363 | c.w.prune = prune; |
1364 | c.w.count = 0; | ||
1365 | c.w.skip = 0; | ||
1349 | c.func = func; | 1366 | c.func = func; |
1350 | c.arg = arg; | 1367 | c.arg = arg; |
1351 | c.net = net; | 1368 | c.net = net; |
@@ -1469,7 +1486,7 @@ static void fib6_gc_timer_cb(unsigned long arg) | |||
1469 | fib6_run_gc(0, (struct net *)arg); | 1486 | fib6_run_gc(0, (struct net *)arg); |
1470 | } | 1487 | } |
1471 | 1488 | ||
1472 | static int fib6_net_init(struct net *net) | 1489 | static int __net_init fib6_net_init(struct net *net) |
1473 | { | 1490 | { |
1474 | setup_timer(&net->ipv6.ip6_fib_timer, fib6_gc_timer_cb, (unsigned long)net); | 1491 | setup_timer(&net->ipv6.ip6_fib_timer, fib6_gc_timer_cb, (unsigned long)net); |
1475 | 1492 | ||