diff options
-rw-r--r-- | sys/netinet/if_ether.c | 22 | ||||
-rw-r--r-- | sys/netinet/in.c | 3 | ||||
-rw-r--r-- | sys/netinet6/in6.c | 3 | ||||
-rw-r--r-- | sys/netinet6/nd6.c | 23 |
4 files changed, 43 insertions, 8 deletions
diff --git a/sys/netinet/if_ether.c b/sys/netinet/if_ether.c index f838919..03d894f 100644 --- a/sys/netinet/if_ether.c +++ b/sys/netinet/if_ether.c @@ -170,10 +170,28 @@ arptimer(void *arg) struct ifnet *ifp; if (lle->la_flags & LLE_STATIC) { - LLE_WUNLOCK(lle); return; } - + LLE_WLOCK(lle); + if (callout_pending(&lle->la_timer)) { + /* + * Here we are a bit odd here in the treatment of + * active/pending. If the pending bit is set, it got + * rescheduled before I ran. The active + * bit we ignore, since if it was stopped + * in ll_tablefree() and was currently running + * it would have return 0 so the code would + * not have deleted it since the callout could + * not be stopped so we want to go through + * with the delete here now. If the callout + * was restarted, the pending bit will be back on and + * we just want to bail since the callout_reset would + * return 1 and our reference would have been removed + * by arpresolve() below. + */ + LLE_WUNLOCK(lle); + return; + } ifp = lle->lle_tbl->llt_ifp; CURVNET_SET(ifp->if_vnet); diff --git a/sys/netinet/in.c b/sys/netinet/in.c index be26ecd..b61b4b6 100644 --- a/sys/netinet/in.c +++ b/sys/netinet/in.c @@ -1263,8 +1263,7 @@ in_lltable_new(const struct sockaddr *l3addr, u_int flags) lle->base.lle_refcnt = 1; lle->base.lle_free = in_lltable_free; LLE_LOCK_INIT(&lle->base); - callout_init_rw(&lle->base.la_timer, &lle->base.lle_lock, - CALLOUT_RETURNUNLOCKED); + callout_init(&lle->base.la_timer, 1); return (&lle->base); } diff --git a/sys/netinet6/in6.c b/sys/netinet6/in6.c index 714e33f..6a8a155 100644 --- a/sys/netinet6/in6.c +++ b/sys/netinet6/in6.c @@ -2519,8 +2519,7 @@ in6_lltable_new(const struct sockaddr *l3addr, u_int flags) lle->base.lle_refcnt = 1; lle->base.lle_free = in6_lltable_free; LLE_LOCK_INIT(&lle->base); - callout_init_rw(&lle->base.ln_timer_ch, &lle->base.lle_lock, - CALLOUT_RETURNUNLOCKED); + callout_init(&lle->base.ln_timer_ch, 1); return (&lle->base); } diff --git a/sys/netinet6/nd6.c b/sys/netinet6/nd6.c index 53087f4..fb3c995 100644 --- a/sys/netinet6/nd6.c +++ b/sys/netinet6/nd6.c @@ -466,9 +466,28 @@ nd6_llinfo_timer(void *arg) KASSERT(arg != NULL, ("%s: arg NULL", __func__)); ln = (struct llentry *)arg; - LLE_WLOCK_ASSERT(ln); + LLE_WLOCK(ln); + if (callout_pending(&ln->la_timer)) { + /* + * Here we are a bit odd here in the treatment of + * active/pending. If the pending bit is set, it got + * rescheduled before I ran. The active + * bit we ignore, since if it was stopped + * in ll_tablefree() and was currently running + * it would have return 0 so the code would + * not have deleted it since the callout could + * not be stopped so we want to go through + * with the delete here now. If the callout + * was restarted, the pending bit will be back on and + * we just want to bail since the callout_reset would + * return 1 and our reference would have been removed + * by nd6_llinfo_settimer_locked above since canceled + * would have been 1. + */ + LLE_WUNLOCK(ln); + return; + } ifp = ln->lle_tbl->llt_ifp; - CURVNET_SET(ifp->if_vnet); if (ln->ln_ntick > 0) { |