summaryrefslogtreecommitdiffstats
path: root/sys/net/if_llatbl.c
diff options
context:
space:
mode:
authorglebius <glebius@FreeBSD.org>2012-08-02 13:57:49 +0000
committerglebius <glebius@FreeBSD.org>2012-08-02 13:57:49 +0000
commitabf245020a075c487a1ac4e60c7069e2d8c9c7c3 (patch)
treebc9d35350ff3e80778a0341908f6905a862f4004 /sys/net/if_llatbl.c
parent34fe3f296a23dcd2b2315ab9b7cbe217a7e36c17 (diff)
downloadFreeBSD-src-abf245020a075c487a1ac4e60c7069e2d8c9c7c3.zip
FreeBSD-src-abf245020a075c487a1ac4e60c7069e2d8c9c7c3.tar.gz
Fix races between in_lltable_prefix_free(), lla_lookup(),
llentry_free() and arptimer(): o Use callout_init_rw() for lle timeout, this allows us safely disestablish them. - This allows us to simplify the arptimer() and make it race safe. o Consistently use ifp->if_afdata_lock to lock access to linked lists in the lle hashes. o Introduce new lle flag LLE_LINKED, which marks an entry that is attached to the hash. - Use LLE_LINKED to avoid double unlinking via consequent calls to llentry_free(). - Mark lle with LLE_DELETED via |= operation istead of =, so that other flags won't be lost. o Make LLE_ADDREF(), LLE_REMREF() and LLE_FREE_LOCKED() more consistent and provide more informative KASSERTs. The patch is a collaborative work of all submitters and myself. PR: kern/165863 Submitted by: Andrey Zonov <andrey zonov.org> Submitted by: Ryan Stone <rysto32 gmail.com> Submitted by: Eric van Gyzen <eric_van_gyzen dell.com>
Diffstat (limited to 'sys/net/if_llatbl.c')
-rw-r--r--sys/net/if_llatbl.c19
1 files changed, 13 insertions, 6 deletions
diff --git a/sys/net/if_llatbl.c b/sys/net/if_llatbl.c
index 2fc75ef..bb49fdd 100644
--- a/sys/net/if_llatbl.c
+++ b/sys/net/if_llatbl.c
@@ -106,10 +106,19 @@ llentry_free(struct llentry *lle)
size_t pkts_dropped;
struct mbuf *next;
- pkts_dropped = 0;
+ IF_AFDATA_WLOCK_ASSERT(lle->lle_tbl->llt_ifp);
LLE_WLOCK_ASSERT(lle);
+
+ /* XXX: guard against race with other llentry_free(). */
+ if (!(lle->la_flags & LLE_LINKED)) {
+ LLE_FREE_LOCKED(lle);
+ return (0);
+ }
+
LIST_REMOVE(lle, lle_next);
+ lle->la_flags &= ~(LLE_VALID | LLE_LINKED);
+ pkts_dropped = 0;
while ((lle->la_numheld > 0) && (lle->la_hold != NULL)) {
next = lle->la_hold->m_nextpkt;
m_freem(lle->la_hold);
@@ -122,7 +131,6 @@ llentry_free(struct llentry *lle)
("%s: la_numheld %d > 0, pkts_droped %zd", __func__,
lle->la_numheld, pkts_dropped));
- lle->la_flags &= ~LLE_VALID;
LLE_FREE_LOCKED(lle);
return (pkts_dropped);
@@ -173,17 +181,16 @@ lltable_free(struct lltable *llt)
SLIST_REMOVE(&V_lltables, llt, lltable, llt_link);
LLTABLE_WUNLOCK();
+ IF_AFDATA_WLOCK(llt->llt_ifp);
for (i = 0; i < LLTBL_HASHTBL_SIZE; i++) {
LIST_FOREACH_SAFE(lle, &llt->lle_head[i], lle_next, next) {
- int canceled;
-
- canceled = callout_drain(&lle->la_timer);
LLE_WLOCK(lle);
- if (canceled)
+ if (callout_stop(&lle->la_timer))
LLE_REMREF(lle);
llentry_free(lle);
}
}
+ IF_AFDATA_WUNLOCK(llt->llt_ifp);
free(llt, M_LLTABLE);
}
OpenPOWER on IntegriCloud