diff options
author | Nicolas Dichtel <nicolas.dichtel@6wind.com> | 2014-10-29 14:29:31 -0400 |
---|---|---|
committer | David S. Miller <davem@davemloft.net> | 2014-10-29 16:11:50 -0400 |
commit | 75fbfd33234a71556bec34b099d98f970190905d (patch) | |
tree | 1a5b40b1e9d8035336c8e8ac581cb10165951cc2 | |
parent | bc9ad166e38ae1cdcb5323a8aa45dff834d68bfa (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.h | 3 | ||||
-rw-r--r-- | net/core/neighbour.c | 32 |
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 | ||
1502 | void neigh_parms_release(struct neigh_table *tbl, struct neigh_parms *parms) | 1501 | void 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 | } |
1523 | EXPORT_SYMBOL(neigh_parms_release); | 1513 | EXPORT_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 | ||