Page Menu
Home
FreeBSD
Search
Configure Global Search
Log In
Files
F143588888
D4605.id18333.diff
No One
Temporary
Actions
View File
Edit File
Delete File
View Transforms
Subscribe
Mute Notifications
Flag For Later
Award Token
Size
8 KB
Referenced Files
None
Subscribers
None
D4605.id18333.diff
View Options
Index: sys/net/if_llatbl.h
===================================================================
--- sys/net/if_llatbl.h
+++ sys/net/if_llatbl.h
@@ -104,6 +104,9 @@
#define LLE_REQ_LOCK(lle) mtx_lock(&(lle)->req_mtx)
#define LLE_REQ_UNLOCK(lle) mtx_unlock(&(lle)->req_mtx)
+#define LLE_TIMER_INIT(lle) callout_init_rw(&(lle)->lle_timer, \
+ &(lle)->lle_lock, CALLOUT_RETURNUNLOCKED)
+
#define LLE_IS_VALID(lle) (((lle) != NULL) && ((lle) != (void *)-1))
#define LLE_ADDREF(lle) do { \
@@ -216,6 +219,9 @@
#endif
int lltable_sysctl_dumparp(int, struct sysctl_req *);
+void llentry_timer_start(struct llentry *, int, void (*)(void *));
+void llentry_timer_stop(struct llentry *);
+void llentry_timer_uninit(struct llentry *);
size_t llentry_free(struct llentry *);
struct llentry *llentry_alloc(struct ifnet *, struct lltable *,
struct sockaddr_storage *);
Index: sys/net/if_llatbl.c
===================================================================
--- sys/net/if_llatbl.c
+++ sys/net/if_llatbl.c
@@ -494,6 +494,43 @@
return (0);
}
+void
+llentry_timer_start(struct llentry *lle, int timeout, void (*func)(void *))
+{
+
+ if (callout_reset(&lle->lle_timer, timeout, func, lle) <= 0)
+ LLE_ADDREF(lle);
+}
+
+void
+llentry_timer_stop(struct llentry *lle)
+{
+
+ if (callout_stop(&lle->lle_timer) > 0)
+ LLE_REMREF(lle);
+}
+
+static void
+llentry_timer_drain_callback(void *arg)
+{
+ struct llentry *lle = arg;
+
+ LLE_FREE(lle);
+}
+
+void
+llentry_timer_uninit(struct llentry *lle)
+{
+ int cancelled;
+
+ cancelled = callout_async_drain(&lle->lle_timer,
+ &llentry_timer_drain_callback);
+ if (cancelled > 0)
+ LLE_REMREF(lle); /* was stopped */
+ else if (cancelled == 0)
+ LLE_ADDREF(lle); /* needs drain */
+}
+
/*
* Free all entries from given table and free itself.
*/
@@ -515,8 +552,7 @@
IF_AFDATA_WUNLOCK(llt->llt_ifp);
LIST_FOREACH_SAFE(lle, &dchain, lle_chain, next) {
- if (callout_stop(&lle->lle_timer) > 0)
- LLE_REMREF(lle);
+ llentry_timer_uninit(lle);
llentry_free(lle);
}
Index: sys/netinet/if_ether.c
===================================================================
--- sys/netinet/if_ether.c
+++ sys/netinet/if_ether.c
@@ -174,28 +174,10 @@
int r_skip_req;
if (lle->la_flags & LLE_STATIC) {
+ LLE_WUNLOCK(lle);
return;
}
- LLE_WLOCK(lle);
- if (callout_pending(&lle->lle_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);
@@ -258,7 +240,7 @@
EVENTHANDLER_INVOKE(lle_event, lle, evt);
}
- callout_stop(&lle->lle_timer);
+ llentry_timer_stop(lle);
/* XXX: LOR avoidance. We still have ref on lle. */
LLE_WUNLOCK(lle);
@@ -267,6 +249,7 @@
/* Guard against race with other llentry_free(). */
if (lle->la_flags & LLE_LINKED) {
+ /* Remove our reference */
LLE_REMREF(lle);
lltable_unlink_entry(lle->lle_tbl, lle);
}
@@ -531,14 +514,8 @@
error = is_gw != 0 ? EHOSTUNREACH : EHOSTDOWN;
if (renew) {
- int canceled;
-
- LLE_ADDREF(la);
la->la_expire = time_uptime;
- canceled = callout_reset(&la->lle_timer, hz * V_arpt_down,
- arptimer, la);
- if (canceled)
- LLE_REMREF(la);
+ llentry_timer_start(la, hz * V_arpt_down, arptimer);
la->la_asked++;
LLE_WUNLOCK(la);
arprequest(ifp, NULL, &SIN(dst)->sin_addr, NULL);
@@ -1219,7 +1196,7 @@
static void
arp_mark_lle_reachable(struct llentry *la)
{
- int canceled, wtime;
+ int wtime;
LLE_WLOCK_ASSERT(la);
@@ -1227,15 +1204,11 @@
EVENTHANDLER_INVOKE(lle_event, la, LLENTRY_RESOLVED);
if (!(la->la_flags & LLE_STATIC)) {
- LLE_ADDREF(la);
la->la_expire = time_uptime + V_arpt_keep;
wtime = V_arpt_keep - V_arp_maxtries * V_arpt_rexmit;
if (wtime < 0)
wtime = V_arpt_keep;
- canceled = callout_reset(&la->lle_timer,
- hz * wtime, arptimer, la);
- if (canceled)
- LLE_REMREF(la);
+ llentry_timer_start(la, hz * wtime, arptimer);
}
la->la_asked = 0;
la->la_preempt = V_arp_maxtries;
Index: sys/netinet/in.c
===================================================================
--- sys/netinet/in.c
+++ sys/netinet/in.c
@@ -1078,7 +1078,7 @@
lle->base.lle_free = in_lltable_destroy_lle;
LLE_LOCK_INIT(&lle->base);
LLE_REQ_INIT(&lle->base);
- callout_init(&lle->base.lle_timer, 1);
+ LLE_TIMER_INIT(&lle->base);
return (&lle->base);
}
@@ -1136,9 +1136,8 @@
lltable_unlink_entry(llt, lle);
}
- /* cancel timer */
- if (callout_stop(&lle->lle_timer) > 0)
- LLE_REMREF(lle);
+ /* Cancel timer */
+ llentry_timer_uninit(lle);
/* Drop hold queue */
pkts_dropped = llentry_free(lle);
@@ -1283,6 +1282,8 @@
#ifdef DIAGNOSTIC
log(LOG_INFO, "ifaddr cache = %p is deleted\n", lle);
#endif
+ /* Cancel timer */
+ llentry_timer_uninit(lle);
llentry_free(lle);
}
Index: sys/netinet6/in6.c
===================================================================
--- sys/netinet6/in6.c
+++ sys/netinet6/in6.c
@@ -2039,7 +2039,7 @@
lle->base.lle_free = in6_lltable_destroy_lle;
LLE_LOCK_INIT(&lle->base);
LLE_REQ_INIT(&lle->base);
- callout_init(&lle->base.lle_timer, 1);
+ LLE_TIMER_INIT(&lle->base);
return (&lle->base);
}
@@ -2093,9 +2093,8 @@
lltable_unlink_entry(llt, lle);
}
- if (callout_stop(&lle->lle_timer) > 0)
- LLE_REMREF(lle);
-
+ /* Cancel timer */
+ llentry_timer_uninit(lle);
llentry_free(lle);
}
@@ -2191,6 +2190,8 @@
#ifdef DIAGNOSTIC
log(LOG_INFO, "ifaddr cache = %p is deleted\n", lle);
#endif
+ /* Cancel timer */
+ llentry_timer_uninit(lle);
llentry_free(lle);
}
Index: sys/netinet6/nd6.c
===================================================================
--- sys/netinet6/nd6.c
+++ sys/netinet6/nd6.c
@@ -520,29 +520,22 @@
static void
nd6_llinfo_settimer_locked(struct llentry *ln, long tick)
{
- int canceled;
-
LLE_WLOCK_ASSERT(ln);
if (tick < 0) {
ln->la_expire = 0;
ln->ln_ntick = 0;
- canceled = callout_stop(&ln->lle_timer);
+ llentry_timer_stop(ln);
} else {
ln->la_expire = time_uptime + tick / hz;
- LLE_ADDREF(ln);
if (tick > INT_MAX) {
ln->ln_ntick = tick - INT_MAX;
- canceled = callout_reset(&ln->lle_timer, INT_MAX,
- nd6_llinfo_timer, ln);
+ llentry_timer_start(ln, INT_MAX, nd6_llinfo_timer);
} else {
ln->ln_ntick = 0;
- canceled = callout_reset(&ln->lle_timer, tick,
- nd6_llinfo_timer, ln);
+ llentry_timer_start(ln, tick, nd6_llinfo_timer);
}
}
- if (canceled > 0)
- LLE_REMREF(ln);
}
/*
@@ -746,29 +739,23 @@
KASSERT(arg != NULL, ("%s: arg NULL", __func__));
ln = (struct llentry *)arg;
+ LLE_WLOCK_ASSERT(ln);
ifp = lltable_get_ifp(ln->lle_tbl);
CURVNET_SET(ifp->if_vnet);
+ /* XXX swap locks */
+ LLE_WUNLOCK(ln);
ND6_RLOCK();
LLE_WLOCK(ln);
+
if (callout_pending(&ln->lle_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.
+ * Because this callout is protected by a lock
+ * callout_reset() won't return 1 when we get into
+ * this function and we need to drop our reference if
+ * there was callout reset in between.
*/
- LLE_WUNLOCK(ln);
+ LLE_FREE_LOCKED(ln);
ND6_RUNLOCK();
CURVNET_RESTORE();
return;
@@ -1414,6 +1401,7 @@
nd6_llinfo_settimer_locked(ln,
(long)V_nd6_gctimer * hz);
+ /* Drop reference so that timeout frees "ln" */
LLE_REMREF(ln);
LLE_WUNLOCK(ln);
defrouter_rele(dr);
@@ -1490,12 +1478,14 @@
LLE_WLOCK(ln);
/* Guard against race with other llentry_free(). */
if (ln->la_flags & LLE_LINKED) {
- /* Remove callout reference */
+ /* Remove our reference */
LLE_REMREF(ln);
lltable_unlink_entry(ln->lle_tbl, ln);
}
IF_AFDATA_UNLOCK(ifp);
+ /* Cancel timer */
+ llentry_timer_uninit(ln);
llentry_free(ln);
if (dr != NULL)
defrouter_rele(dr);
File Metadata
Details
Attached
Mime Type
text/plain
Expires
Sun, Feb 1, 12:14 AM (11 h, 5 m)
Storage Engine
blob
Storage Format
Raw Data
Storage Handle
28225110
Default Alt Text
D4605.id18333.diff (8 KB)
Attached To
Mode
D4605: Properly stop timer before freeing link level entries for IPv4 and IPv6
Attached
Detach File
Event Timeline
Log In to Comment