--- linux-2.6/net/core/dst.c.orig 2005-04-07 20:48:25.000000000 +1000 +++ linux-2.6/net/core/dst.c 2005-04-07 20:57:33.000000000 +1000 @@ -169,9 +169,9 @@ struct neighbour *neigh; struct hh_cache *hh; +again: smp_rmb(); -again: neigh = dst->neighbour; hh = dst->hh; child = dst->child; @@ -197,19 +197,19 @@ kmem_cache_free(dst->ops->kmem_cachep, dst); dst = child; - if (dst) { + if (unlikely(dst)) { int nohash = dst->flags & DST_NOHASH; - if (atomic_dec_and_test(&dst->__refcnt)) { + atomic_dec(&dst->__refcnt); + + if (nohash) { /* We were real parent of this dst, so kill child. */ - if (nohash) + if (!atomic_read(&dst->__refcnt)) goto again; - } else { /* Child is still referenced, return it for freeing. */ - if (nohash) - return dst; - /* Child is still in his hash table */ + return dst; } + /* Child is still in his hash table or on the GC list. */ } return NULL; }