Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

[NET]: Fix neighbour destructor handling.

->neigh_destructor() is killed (not used), replaced with
->neigh_cleanup(), which is called when neighbor entry goes to dead
state. At this point everything is still valid: neigh->dev,
neigh->parms etc.

The device should guarantee that dead neighbor entries (neigh->dead !=
0) do not get private part initialized, otherwise nobody will cleanup
it.

I think this is enough for ipoib which is the only user of this thing.
Initialization private part of neighbor entries happens in ipib
start_xmit routine, which is not reached when device is down. But it
would be better to add explicit test for neigh->dead in any case.

Signed-off-by: David S. Miller <davem@davemloft.net>

authored by

Alexey Kuznetsov and committed by
David S. Miller
ecbb4169 e1701c68

+14 -17
+3 -3
drivers/infiniband/ulp/ipoib/ipoib_main.c
··· 814 814 queue_work(ipoib_workqueue, &priv->restart_task); 815 815 } 816 816 817 - static void ipoib_neigh_destructor(struct neighbour *n) 817 + static void ipoib_neigh_cleanup(struct neighbour *n) 818 818 { 819 819 struct ipoib_neigh *neigh; 820 820 struct ipoib_dev_priv *priv = netdev_priv(n->dev); ··· 822 822 struct ipoib_ah *ah = NULL; 823 823 824 824 ipoib_dbg(priv, 825 - "neigh_destructor for %06x " IPOIB_GID_FMT "\n", 825 + "neigh_cleanup for %06x " IPOIB_GID_FMT "\n", 826 826 IPOIB_QPN(n->ha), 827 827 IPOIB_GID_RAW_ARG(n->ha + 4)); 828 828 ··· 874 874 875 875 static int ipoib_neigh_setup_dev(struct net_device *dev, struct neigh_parms *parms) 876 876 { 877 - parms->neigh_destructor = ipoib_neigh_destructor; 877 + parms->neigh_cleanup = ipoib_neigh_cleanup; 878 878 879 879 return 0; 880 880 }
+1 -1
include/net/neighbour.h
··· 36 36 struct net_device *dev; 37 37 struct neigh_parms *next; 38 38 int (*neigh_setup)(struct neighbour *); 39 - void (*neigh_destructor)(struct neighbour *); 39 + void (*neigh_cleanup)(struct neighbour *); 40 40 struct neigh_table *tbl; 41 41 42 42 void *sysctl_table;
-9
net/atm/clip.c
··· 261 261 spin_unlock_irqrestore(&PRIV(dev)->xoff_lock, flags); 262 262 } 263 263 264 - static void clip_neigh_destroy(struct neighbour *neigh) 265 - { 266 - DPRINTK("clip_neigh_destroy (neigh %p)\n", neigh); 267 - if (NEIGH2ENTRY(neigh)->vccs) 268 - printk(KERN_CRIT "clip_neigh_destroy: vccs != NULL !!!\n"); 269 - NEIGH2ENTRY(neigh)->vccs = (void *) NEIGHBOR_DEAD; 270 - } 271 - 272 264 static void clip_neigh_solicit(struct neighbour *neigh, struct sk_buff *skb) 273 265 { 274 266 DPRINTK("clip_neigh_solicit (neigh %p, skb %p)\n", neigh, skb); ··· 334 342 /* parameters are copied from ARP ... */ 335 343 .parms = { 336 344 .tbl = &clip_tbl, 337 - .neigh_destructor = clip_neigh_destroy, 338 345 .base_reachable_time = 30 * HZ, 339 346 .retrans_time = 1 * HZ, 340 347 .gc_staletime = 60 * HZ,
+10 -4
net/core/neighbour.c
··· 140 140 n->dead = 1; 141 141 shrunk = 1; 142 142 write_unlock(&n->lock); 143 + if (n->parms->neigh_cleanup) 144 + n->parms->neigh_cleanup(n); 143 145 neigh_release(n); 144 146 continue; 145 147 } ··· 213 211 NEIGH_PRINTK2("neigh %p is stray.\n", n); 214 212 } 215 213 write_unlock(&n->lock); 214 + if (n->parms->neigh_cleanup) 215 + n->parms->neigh_cleanup(n); 216 216 neigh_release(n); 217 217 } 218 218 } ··· 586 582 kfree(hh); 587 583 } 588 584 589 - if (neigh->parms->neigh_destructor) 590 - (neigh->parms->neigh_destructor)(neigh); 591 - 592 585 skb_queue_purge(&neigh->arp_queue); 593 586 594 587 dev_put(neigh->dev); ··· 676 675 *np = n->next; 677 676 n->dead = 1; 678 677 write_unlock(&n->lock); 678 + if (n->parms->neigh_cleanup) 679 + n->parms->neigh_cleanup(n); 679 680 neigh_release(n); 680 681 continue; 681 682 } ··· 2091 2088 } else 2092 2089 np = &n->next; 2093 2090 write_unlock(&n->lock); 2094 - if (release) 2091 + if (release) { 2092 + if (n->parms->neigh_cleanup) 2093 + n->parms->neigh_cleanup(n); 2095 2094 neigh_release(n); 2095 + } 2096 2096 } 2097 2097 } 2098 2098 }