aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorNicolas Dichtel <nicolas.dichtel@6wind.com>2014-10-29 14:29:31 -0400
committerDavid S. Miller <davem@davemloft.net>2014-10-29 16:11:50 -0400
commit75fbfd33234a71556bec34b099d98f970190905d (patch)
tree1a5b40b1e9d8035336c8e8ac581cb10165951cc2
parentbc9ad166e38ae1cdcb5323a8aa45dff834d68bfa (diff)
neigh: optimize neigh_parms_release()
In neigh_parms_release() we loop over all entries to find the entry given in argument and being able to remove it from the list. By using a double linked list, we can avoid this loop. Here are some numbers with 30 000 dummy interfaces configured: Before the patch: $ time rmmod dummy real 2m0.118s user 0m0.000s sys 1m50.048s After the patch: $ time rmmod dummy real 1m9.970s user 0m0.000s sys 0m47.976s Suggested-by: Thierry Herbelot <thierry.herbelot@6wind.com> Signed-off-by: Nicolas Dichtel <nicolas.dichtel@6wind.com> Acked-by: Eric Dumazet <edumazet@google.com> Signed-off-by: David S. Miller <davem@davemloft.net>
-rw-r--r--include/net/neighbour.h3
-rw-r--r--net/core/neighbour.c32
2 files changed, 15 insertions, 20 deletions
diff --git a/include/net/neighbour.h b/include/net/neighbour.h
index f60558d0254c..dedfb188b1a7 100644
--- a/include/net/neighbour.h
+++ b/include/net/neighbour.h
@@ -69,7 +69,7 @@ struct neigh_parms {
69 struct net *net; 69 struct net *net;
70#endif 70#endif
71 struct net_device *dev; 71 struct net_device *dev;
72 struct neigh_parms *next; 72 struct list_head list;
73 int (*neigh_setup)(struct neighbour *); 73 int (*neigh_setup)(struct neighbour *);
74 void (*neigh_cleanup)(struct neighbour *); 74 void (*neigh_cleanup)(struct neighbour *);
75 struct neigh_table *tbl; 75 struct neigh_table *tbl;
@@ -203,6 +203,7 @@ struct neigh_table {
203 void (*proxy_redo)(struct sk_buff *skb); 203 void (*proxy_redo)(struct sk_buff *skb);
204 char *id; 204 char *id;
205 struct neigh_parms parms; 205 struct neigh_parms parms;
206 struct list_head parms_list;
206 int gc_interval; 207 int gc_interval;
207 int gc_thresh1; 208 int gc_thresh1;
208 int gc_thresh2; 209 int gc_thresh2;
diff --git a/net/core/neighbour.c b/net/core/neighbour.c
index ef31fef25e5a..edd04116ecb7 100644
--- a/net/core/neighbour.c
+++ b/net/core/neighbour.c
@@ -773,7 +773,7 @@ static void neigh_periodic_work(struct work_struct *work)
773 if (time_after(jiffies, tbl->last_rand + 300 * HZ)) { 773 if (time_after(jiffies, tbl->last_rand + 300 * HZ)) {
774 struct neigh_parms *p; 774 struct neigh_parms *p;
775 tbl->last_rand = jiffies; 775 tbl->last_rand = jiffies;
776 for (p = &tbl->parms; p; p = p->next) 776 list_for_each_entry(p, &tbl->parms_list, list)
777 p->reachable_time = 777 p->reachable_time =
778 neigh_rand_reach_time(NEIGH_VAR(p, BASE_REACHABLE_TIME)); 778 neigh_rand_reach_time(NEIGH_VAR(p, BASE_REACHABLE_TIME));
779 } 779 }
@@ -1446,7 +1446,7 @@ static inline struct neigh_parms *lookup_neigh_parms(struct neigh_table *tbl,
1446{ 1446{
1447 struct neigh_parms *p; 1447 struct neigh_parms *p;
1448 1448
1449 for (p = &tbl->parms; p; p = p->next) { 1449 list_for_each_entry(p, &tbl->parms_list, list) {
1450 if ((p->dev && p->dev->ifindex == ifindex && net_eq(neigh_parms_net(p), net)) || 1450 if ((p->dev && p->dev->ifindex == ifindex && net_eq(neigh_parms_net(p), net)) ||
1451 (!p->dev && !ifindex && net_eq(net, &init_net))) 1451 (!p->dev && !ifindex && net_eq(net, &init_net)))
1452 return p; 1452 return p;
@@ -1481,8 +1481,7 @@ struct neigh_parms *neigh_parms_alloc(struct net_device *dev,
1481 } 1481 }
1482 1482
1483 write_lock_bh(&tbl->lock); 1483 write_lock_bh(&tbl->lock);
1484 p->next = tbl->parms.next; 1484 list_add(&p->list, &tbl->parms.list);
1485 tbl->parms.next = p;
1486 write_unlock_bh(&tbl->lock); 1485 write_unlock_bh(&tbl->lock);
1487 1486
1488 neigh_parms_data_state_cleanall(p); 1487 neigh_parms_data_state_cleanall(p);
@@ -1501,24 +1500,15 @@ static void neigh_rcu_free_parms(struct rcu_head *head)
1501 1500
1502void neigh_parms_release(struct neigh_table *tbl, struct neigh_parms *parms) 1501void neigh_parms_release(struct neigh_table *tbl, struct neigh_parms *parms)
1503{ 1502{
1504 struct neigh_parms **p;
1505
1506 if (!parms || parms == &tbl->parms) 1503 if (!parms || parms == &tbl->parms)
1507 return; 1504 return;
1508 write_lock_bh(&tbl->lock); 1505 write_lock_bh(&tbl->lock);
1509 for (p = &tbl->parms.next; *p; p = &(*p)->next) { 1506 list_del(&parms->list);
1510 if (*p == parms) { 1507 parms->dead = 1;
1511 *p = parms->next;
1512 parms->dead = 1;
1513 write_unlock_bh(&tbl->lock);
1514 if (parms->dev)
1515 dev_put(parms->dev);
1516 call_rcu(&parms->rcu_head, neigh_rcu_free_parms);
1517 return;
1518 }
1519 }
1520 write_unlock_bh(&tbl->lock); 1508 write_unlock_bh(&tbl->lock);
1521 neigh_dbg(1, "%s: not found\n", __func__); 1509 if (parms->dev)
1510 dev_put(parms->dev);
1511 call_rcu(&parms->rcu_head, neigh_rcu_free_parms);
1522} 1512}
1523EXPORT_SYMBOL(neigh_parms_release); 1513EXPORT_SYMBOL(neigh_parms_release);
1524 1514
@@ -1535,6 +1525,8 @@ static void neigh_table_init_no_netlink(struct neigh_table *tbl)
1535 unsigned long now = jiffies; 1525 unsigned long now = jiffies;
1536 unsigned long phsize; 1526 unsigned long phsize;
1537 1527
1528 INIT_LIST_HEAD(&tbl->parms_list);
1529 list_add(&tbl->parms.list, &tbl->parms_list);
1538 write_pnet(&tbl->parms.net, &init_net); 1530 write_pnet(&tbl->parms.net, &init_net);
1539 atomic_set(&tbl->parms.refcnt, 1); 1531 atomic_set(&tbl->parms.refcnt, 1);
1540 tbl->parms.reachable_time = 1532 tbl->parms.reachable_time =
@@ -2154,7 +2146,9 @@ static int neightbl_dump_info(struct sk_buff *skb, struct netlink_callback *cb)
2154 NLM_F_MULTI) <= 0) 2146 NLM_F_MULTI) <= 0)
2155 break; 2147 break;
2156 2148
2157 for (nidx = 0, p = tbl->parms.next; p; p = p->next) { 2149 nidx = 0;
2150 p = list_next_entry(&tbl->parms, list);
2151 list_for_each_entry_from(p, &tbl->parms_list, list) {
2158 if (!net_eq(neigh_parms_net(p), net)) 2152 if (!net_eq(neigh_parms_net(p), net))
2159 continue; 2153 continue;
2160 2154