Commit 58b31cc9 authored by David S. Miller's avatar David S. Miller

[NET]: Free neigh_parms using RCU to fix neigh_create/inetdev_destroy race.

Signed-off-by: default avatarDavid S. Miller <davem@davemloft.net>
parent 5f9cf8d9
...@@ -46,6 +46,7 @@ ...@@ -46,6 +46,7 @@
#include <asm/atomic.h> #include <asm/atomic.h>
#include <linux/skbuff.h> #include <linux/skbuff.h>
#include <linux/netdevice.h> #include <linux/netdevice.h>
#include <linux/rcupdate.h>
#include <linux/err.h> #include <linux/err.h>
#include <linux/sysctl.h> #include <linux/sysctl.h>
...@@ -66,6 +67,8 @@ struct neigh_parms ...@@ -66,6 +67,8 @@ struct neigh_parms
void *sysctl_table; void *sysctl_table;
struct rcu_head rcu_head;
int base_reachable_time; int base_reachable_time;
int retrans_time; int retrans_time;
int gc_staletime; int gc_staletime;
......
...@@ -1120,6 +1120,7 @@ struct neigh_parms *neigh_parms_alloc(struct net_device *dev, ...@@ -1120,6 +1120,7 @@ struct neigh_parms *neigh_parms_alloc(struct net_device *dev,
if (p) { if (p) {
memcpy(p, &tbl->parms, sizeof(*p)); memcpy(p, &tbl->parms, sizeof(*p));
p->tbl = tbl; p->tbl = tbl;
INIT_RCU_HEAD(&p->rcu_head);
p->reachable_time = p->reachable_time =
neigh_rand_reach_time(p->base_reachable_time); neigh_rand_reach_time(p->base_reachable_time);
if (dev && dev->neigh_setup && dev->neigh_setup(dev, p)) { if (dev && dev->neigh_setup && dev->neigh_setup(dev, p)) {
...@@ -1135,6 +1136,14 @@ struct neigh_parms *neigh_parms_alloc(struct net_device *dev, ...@@ -1135,6 +1136,14 @@ struct neigh_parms *neigh_parms_alloc(struct net_device *dev,
return p; return p;
} }
static void neigh_rcu_free_parms(struct rcu_head *head)
{
struct neigh_parms *parms =
container_of(head, struct neigh_parms, rcu_head);
kfree(parms);
}
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; struct neigh_parms **p;
...@@ -1146,7 +1155,7 @@ void neigh_parms_release(struct neigh_table *tbl, struct neigh_parms *parms) ...@@ -1146,7 +1155,7 @@ void neigh_parms_release(struct neigh_table *tbl, struct neigh_parms *parms)
if (*p == parms) { if (*p == parms) {
*p = parms->next; *p = parms->next;
write_unlock_bh(&tbl->lock); write_unlock_bh(&tbl->lock);
kfree(parms); call_rcu(&parms->rcu_head, neigh_rcu_free_parms);
return; return;
} }
} }
...@@ -1159,6 +1168,7 @@ void neigh_table_init(struct neigh_table *tbl) ...@@ -1159,6 +1168,7 @@ void neigh_table_init(struct neigh_table *tbl)
{ {
unsigned long now = jiffies; unsigned long now = jiffies;
INIT_RCU_HEAD(&tbl->parms.rcu_head);
tbl->parms.reachable_time = tbl->parms.reachable_time =
neigh_rand_reach_time(tbl->parms.base_reachable_time); neigh_rand_reach_time(tbl->parms.base_reachable_time);
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment