Skip site navigation (1)Skip section navigation (2)
Date:      Thu, 13 Dec 2012 11:11:15 +0000 (UTC)
From:      Gleb Smirnoff <glebius@FreeBSD.org>
To:        src-committers@freebsd.org, svn-src-all@freebsd.org, svn-src-head@freebsd.org
Subject:   svn commit: r244183 - in head/sys: net netinet netinet6
Message-ID:  <201212131111.qBDBBFrk017294@svn.freebsd.org>

next in thread | raw e-mail | index | archive | help
Author: glebius
Date: Thu Dec 13 11:11:15 2012
New Revision: 244183
URL: http://svnweb.freebsd.org/changeset/base/244183

Log:
    Fix problem in r238990. The LLE_LINKED flag should be tested prior to
  entering llentry_free(), and in case if we lose the race, we should simply
  perform LLE_FREE_LOCKED(). Otherwise, if the race is lost by the thread
  performing arptimer(), it will remove two references from the lle instead
  of one.
  
  Reported by:	Ian FREISLICH <ianf clue.co.za>

Modified:
  head/sys/net/if_llatbl.c
  head/sys/netinet/if_ether.c
  head/sys/netinet6/nd6.c

Modified: head/sys/net/if_llatbl.c
==============================================================================
--- head/sys/net/if_llatbl.c	Thu Dec 13 09:55:26 2012	(r244182)
+++ head/sys/net/if_llatbl.c	Thu Dec 13 11:11:15 2012	(r244183)
@@ -109,12 +109,6 @@ llentry_free(struct llentry *lle)
 	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);
 

Modified: head/sys/netinet/if_ether.c
==============================================================================
--- head/sys/netinet/if_ether.c	Thu Dec 13 09:55:26 2012	(r244182)
+++ head/sys/netinet/if_ether.c	Thu Dec 13 11:11:15 2012	(r244183)
@@ -165,7 +165,6 @@ arptimer(void *arg)
 {
 	struct llentry *lle = (struct llentry *)arg;
 	struct ifnet *ifp;
-	size_t pkts_dropped;
 
 	if (lle->la_flags & LLE_STATIC) {
 		LLE_WUNLOCK(lle);
@@ -192,11 +191,20 @@ arptimer(void *arg)
 	IF_AFDATA_LOCK(ifp);
 	LLE_WLOCK(lle);
 
-	LLE_REMREF(lle);
-	pkts_dropped = llentry_free(lle);
+	/* Guard against race with other llentry_free(). */
+	if (lle->la_flags & LLE_LINKED) {
+		size_t pkts_dropped;
+
+		LLE_REMREF(lle);
+		pkts_dropped = llentry_free(lle);
+		ARPSTAT_ADD(dropped, pkts_dropped);
+	} else
+		LLE_FREE_LOCKED(lle);
+
 	IF_AFDATA_UNLOCK(ifp);
-	ARPSTAT_ADD(dropped, pkts_dropped);
+
 	ARPSTAT_INC(timeouts);
+
 	CURVNET_RESTORE();
 }
 

Modified: head/sys/netinet6/nd6.c
==============================================================================
--- head/sys/netinet6/nd6.c	Thu Dec 13 09:55:26 2012	(r244182)
+++ head/sys/netinet6/nd6.c	Thu Dec 13 11:11:15 2012	(r244183)
@@ -1108,8 +1108,14 @@ nd6_free(struct llentry *ln, int gc)
 	LLE_WUNLOCK(ln);
 	IF_AFDATA_LOCK(ifp);
 	LLE_WLOCK(ln);
-	LLE_REMREF(ln);
-	llentry_free(ln);
+
+	/* Guard against race with other llentry_free(). */
+	if (ln->la_flags & LLE_LINKED) {
+		LLE_REMREF(ln);
+		llentry_free(ln);
+	} else
+		LLE_FREE_LOCKED(ln);
+
 	IF_AFDATA_UNLOCK(ifp);
 
 	return (next);



Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?201212131111.qBDBBFrk017294>