Re: neigh_create/inetdev_destroy race?
From: "David S. Miller" <davem@davemloft.net>
Date: 2004-09-02 05:21:18
On Tue, 31 Aug 2004 20:41:39 +1000 Herbert Xu [off-list ref] wrote:
quoted
I think we can clear this by putting neigh_parms_release() into an RCU handler. It can't be in in_dev_rcu_put.Yes that should go a long way in resolving this problem.
So here's the first step. No rcu_read_lock()'s are needed since the tbl->lock needs to be held as a write when traversing these things anyways for other reasons. Can you work on the next bit you mentioned, making sure the corresponding idev is still alive when we add a neighbour with its neigh_parms to the hash table? Thanks. ===== include/net/neighbour.h 1.8 vs edited =====
--- 1.8/include/net/neighbour.h 2004-08-16 14:10:51 -07:00
+++ edited/include/net/neighbour.h 2004-09-01 21:57:37 -07:00@@ -46,6 +46,7 @@ #include <asm/atomic.h> #include <linux/skbuff.h> #include <linux/netdevice.h> +#include <linux/rcupdate.h> #include <linux/err.h> #include <linux/sysctl.h>
@@ -65,6 +66,8 @@ void *priv; void *sysctl_table; + + struct rcu_head rcu_head; int base_reachable_time; int retrans_time;
===== net/core/neighbour.c 1.28 vs edited =====
--- 1.28/net/core/neighbour.c 2004-04-29 16:26:35 -07:00
+++ edited/net/core/neighbour.c 2004-09-01 22:00:59 -07:00@@ -1120,6 +1120,7 @@ if (p) { memcpy(p, &tbl->parms, sizeof(*p)); p->tbl = tbl; + INIT_RCU_HEAD(&p->rcu_head); p->reachable_time = neigh_rand_reach_time(p->base_reachable_time); if (dev && dev->neigh_setup && dev->neigh_setup(dev, p)) {
@@ -1135,6 +1136,14 @@ 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) { struct neigh_parms **p;
@@ -1146,7 +1155,7 @@ if (*p == parms) { *p = parms->next; write_unlock_bh(&tbl->lock); - kfree(parms); + call_rcu(&parms->rcu_head, neigh_rcu_free_parms); return; } }
@@ -1159,6 +1168,7 @@ { unsigned long now = jiffies; + INIT_RCU_HEAD(&tbl->parms.rcu_head); tbl->parms.reachable_time = neigh_rand_reach_time(tbl->parms.base_reachable_time);