mirror of
https://github.com/FEX-Emu/linux.git
synced 2024-12-23 18:07:03 +00:00
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>
This commit is contained in:
parent
bc9ad166e3
commit
75fbfd3323
@ -69,7 +69,7 @@ struct neigh_parms {
|
|||||||
struct net *net;
|
struct net *net;
|
||||||
#endif
|
#endif
|
||||||
struct net_device *dev;
|
struct net_device *dev;
|
||||||
struct neigh_parms *next;
|
struct list_head list;
|
||||||
int (*neigh_setup)(struct neighbour *);
|
int (*neigh_setup)(struct neighbour *);
|
||||||
void (*neigh_cleanup)(struct neighbour *);
|
void (*neigh_cleanup)(struct neighbour *);
|
||||||
struct neigh_table *tbl;
|
struct neigh_table *tbl;
|
||||||
@ -203,6 +203,7 @@ struct neigh_table {
|
|||||||
void (*proxy_redo)(struct sk_buff *skb);
|
void (*proxy_redo)(struct sk_buff *skb);
|
||||||
char *id;
|
char *id;
|
||||||
struct neigh_parms parms;
|
struct neigh_parms parms;
|
||||||
|
struct list_head parms_list;
|
||||||
int gc_interval;
|
int gc_interval;
|
||||||
int gc_thresh1;
|
int gc_thresh1;
|
||||||
int gc_thresh2;
|
int gc_thresh2;
|
||||||
|
@ -773,7 +773,7 @@ static void neigh_periodic_work(struct work_struct *work)
|
|||||||
if (time_after(jiffies, tbl->last_rand + 300 * HZ)) {
|
if (time_after(jiffies, tbl->last_rand + 300 * HZ)) {
|
||||||
struct neigh_parms *p;
|
struct neigh_parms *p;
|
||||||
tbl->last_rand = jiffies;
|
tbl->last_rand = jiffies;
|
||||||
for (p = &tbl->parms; p; p = p->next)
|
list_for_each_entry(p, &tbl->parms_list, list)
|
||||||
p->reachable_time =
|
p->reachable_time =
|
||||||
neigh_rand_reach_time(NEIGH_VAR(p, BASE_REACHABLE_TIME));
|
neigh_rand_reach_time(NEIGH_VAR(p, BASE_REACHABLE_TIME));
|
||||||
}
|
}
|
||||||
@ -1446,7 +1446,7 @@ static inline struct neigh_parms *lookup_neigh_parms(struct neigh_table *tbl,
|
|||||||
{
|
{
|
||||||
struct neigh_parms *p;
|
struct neigh_parms *p;
|
||||||
|
|
||||||
for (p = &tbl->parms; p; p = p->next) {
|
list_for_each_entry(p, &tbl->parms_list, list) {
|
||||||
if ((p->dev && p->dev->ifindex == ifindex && net_eq(neigh_parms_net(p), net)) ||
|
if ((p->dev && p->dev->ifindex == ifindex && net_eq(neigh_parms_net(p), net)) ||
|
||||||
(!p->dev && !ifindex && net_eq(net, &init_net)))
|
(!p->dev && !ifindex && net_eq(net, &init_net)))
|
||||||
return p;
|
return p;
|
||||||
@ -1481,8 +1481,7 @@ struct neigh_parms *neigh_parms_alloc(struct net_device *dev,
|
|||||||
}
|
}
|
||||||
|
|
||||||
write_lock_bh(&tbl->lock);
|
write_lock_bh(&tbl->lock);
|
||||||
p->next = tbl->parms.next;
|
list_add(&p->list, &tbl->parms.list);
|
||||||
tbl->parms.next = p;
|
|
||||||
write_unlock_bh(&tbl->lock);
|
write_unlock_bh(&tbl->lock);
|
||||||
|
|
||||||
neigh_parms_data_state_cleanall(p);
|
neigh_parms_data_state_cleanall(p);
|
||||||
@ -1501,24 +1500,15 @@ static void neigh_rcu_free_parms(struct rcu_head *head)
|
|||||||
|
|
||||||
void neigh_parms_release(struct neigh_table *tbl, struct neigh_parms *parms)
|
void neigh_parms_release(struct neigh_table *tbl, struct neigh_parms *parms)
|
||||||
{
|
{
|
||||||
struct neigh_parms **p;
|
|
||||||
|
|
||||||
if (!parms || parms == &tbl->parms)
|
if (!parms || parms == &tbl->parms)
|
||||||
return;
|
return;
|
||||||
write_lock_bh(&tbl->lock);
|
write_lock_bh(&tbl->lock);
|
||||||
for (p = &tbl->parms.next; *p; p = &(*p)->next) {
|
list_del(&parms->list);
|
||||||
if (*p == parms) {
|
parms->dead = 1;
|
||||||
*p = parms->next;
|
|
||||||
parms->dead = 1;
|
|
||||||
write_unlock_bh(&tbl->lock);
|
|
||||||
if (parms->dev)
|
|
||||||
dev_put(parms->dev);
|
|
||||||
call_rcu(&parms->rcu_head, neigh_rcu_free_parms);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
write_unlock_bh(&tbl->lock);
|
write_unlock_bh(&tbl->lock);
|
||||||
neigh_dbg(1, "%s: not found\n", __func__);
|
if (parms->dev)
|
||||||
|
dev_put(parms->dev);
|
||||||
|
call_rcu(&parms->rcu_head, neigh_rcu_free_parms);
|
||||||
}
|
}
|
||||||
EXPORT_SYMBOL(neigh_parms_release);
|
EXPORT_SYMBOL(neigh_parms_release);
|
||||||
|
|
||||||
@ -1535,6 +1525,8 @@ static void neigh_table_init_no_netlink(struct neigh_table *tbl)
|
|||||||
unsigned long now = jiffies;
|
unsigned long now = jiffies;
|
||||||
unsigned long phsize;
|
unsigned long phsize;
|
||||||
|
|
||||||
|
INIT_LIST_HEAD(&tbl->parms_list);
|
||||||
|
list_add(&tbl->parms.list, &tbl->parms_list);
|
||||||
write_pnet(&tbl->parms.net, &init_net);
|
write_pnet(&tbl->parms.net, &init_net);
|
||||||
atomic_set(&tbl->parms.refcnt, 1);
|
atomic_set(&tbl->parms.refcnt, 1);
|
||||||
tbl->parms.reachable_time =
|
tbl->parms.reachable_time =
|
||||||
@ -2154,7 +2146,9 @@ static int neightbl_dump_info(struct sk_buff *skb, struct netlink_callback *cb)
|
|||||||
NLM_F_MULTI) <= 0)
|
NLM_F_MULTI) <= 0)
|
||||||
break;
|
break;
|
||||||
|
|
||||||
for (nidx = 0, p = tbl->parms.next; p; p = p->next) {
|
nidx = 0;
|
||||||
|
p = list_next_entry(&tbl->parms, list);
|
||||||
|
list_for_each_entry_from(p, &tbl->parms_list, list) {
|
||||||
if (!net_eq(neigh_parms_net(p), net))
|
if (!net_eq(neigh_parms_net(p), net))
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user