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>