From owner-svn-src-all@FreeBSD.ORG Sun Apr 11 16:04:08 2010 Return-Path: Delivered-To: svn-src-all@freebsd.org Received: from mx1.freebsd.org (mx1.freebsd.org [IPv6:2001:4f8:fff6::34]) by hub.freebsd.org (Postfix) with ESMTP id EBE4A106564A; Sun, 11 Apr 2010 16:04:08 +0000 (UTC) (envelope-from bz@FreeBSD.org) Received: from svn.freebsd.org (svn.freebsd.org [IPv6:2001:4f8:fff6::2c]) by mx1.freebsd.org (Postfix) with ESMTP id DB90D8FC08; Sun, 11 Apr 2010 16:04:08 +0000 (UTC) Received: from svn.freebsd.org (localhost [127.0.0.1]) by svn.freebsd.org (8.14.3/8.14.3) with ESMTP id o3BG48Hx044437; Sun, 11 Apr 2010 16:04:08 GMT (envelope-from bz@svn.freebsd.org) Received: (from bz@localhost) by svn.freebsd.org (8.14.3/8.14.3/Submit) id o3BG48rI044430; Sun, 11 Apr 2010 16:04:08 GMT (envelope-from bz@svn.freebsd.org) Message-Id: <201004111604.o3BG48rI044430@svn.freebsd.org> From: "Bjoern A. Zeeb" Date: Sun, 11 Apr 2010 16:04:08 +0000 (UTC) To: src-committers@freebsd.org, svn-src-all@freebsd.org, svn-src-head@freebsd.org X-SVN-Group: head MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Cc: Subject: svn commit: r206481 - in head/sys: net netinet netinet6 X-BeenThere: svn-src-all@freebsd.org X-Mailman-Version: 2.1.5 Precedence: list List-Id: "SVN commit messages for the entire src tree \(except for " user" and " projects" \)" List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , X-List-Received-Date: Sun, 11 Apr 2010 16:04:09 -0000 Author: bz Date: Sun Apr 11 16:04:08 2010 New Revision: 206481 URL: http://svn.freebsd.org/changeset/base/206481 Log: Plug reference leaks in the link-layer code ("new-arp") that previously prevented the link-layer entry from being freed. In both in.c and in6.c (though that code path seems to be basically dead) plug a reference leak in case of a pending callout being drained. In if_ether.c consistently add a reference before resetting the callout and in case we canceled a pending one remove the reference for that. In the final case in arptimer, before freeing the expired entry, remove the reference again and explicitly call callout_stop() to clear the active flag. In nd6.c:nd6_free() we are only ever called from the callout function and thus need to remove the reference there as well before calling into llentry_free(). In if_llatbl.c when freeing entire tables make sure that in case we cancel a pending callout to remove the reference as well. Reviewed by: qingli (earlier version) MFC after: 10 days Problem observed, patch tested by: simon on ipv6gw.f.o, Christian Kratzer (ck cksoft.de), Evgenii Davidov (dado korolev-net.ru) PR: kern/144564 Configurations still affected: with options FLOWTABLE Modified: head/sys/net/if_llatbl.c head/sys/netinet/if_ether.c head/sys/netinet/in.c head/sys/netinet6/in6.c head/sys/netinet6/nd6.c Modified: head/sys/net/if_llatbl.c ============================================================================== --- head/sys/net/if_llatbl.c Sun Apr 11 15:35:17 2010 (r206480) +++ head/sys/net/if_llatbl.c Sun Apr 11 16:04:08 2010 (r206481) @@ -170,9 +170,12 @@ lltable_free(struct lltable *llt) for (i=0; i < LLTBL_HASHTBL_SIZE; i++) { LIST_FOREACH_SAFE(lle, &llt->lle_head[i], lle_next, next) { + int canceled; - callout_drain(&lle->la_timer); + canceled = callout_drain(&lle->la_timer); LLE_WLOCK(lle); + if (canceled) + LLE_REMREF(lle); llentry_free(lle); } } Modified: head/sys/netinet/if_ether.c ============================================================================== --- head/sys/netinet/if_ether.c Sun Apr 11 15:35:17 2010 (r206480) +++ head/sys/netinet/if_ether.c Sun Apr 11 16:04:08 2010 (r206481) @@ -180,6 +180,8 @@ arptimer(void *arg) else { if (!callout_pending(&lle->la_timer) && callout_active(&lle->la_timer)) { + callout_stop(&lle->la_timer); + LLE_REMREF(lle); (void) llentry_free(lle); ARPSTAT_INC(timeouts); } @@ -382,9 +384,14 @@ retry: EHOSTUNREACH : EHOSTDOWN; if (renew) { + int canceled; + LLE_ADDREF(la); la->la_expire = time_second + V_arpt_down; - callout_reset(&la->la_timer, hz * V_arpt_down, arptimer, la); + canceled = callout_reset(&la->la_timer, hz * V_arpt_down, + arptimer, la); + if (canceled) + LLE_REMREF(la); la->la_asked++; LLE_WUNLOCK(la); arprequest(ifp, NULL, &SIN(dst)->sin_addr, @@ -696,9 +703,14 @@ match: EVENTHANDLER_INVOKE(arp_update_event, la); if (!(la->la_flags & LLE_STATIC)) { + int canceled; + + LLE_ADDREF(la); la->la_expire = time_second + V_arpt_keep; - callout_reset(&la->la_timer, hz * V_arpt_keep, - arptimer, la); + canceled = callout_reset(&la->la_timer, + hz * V_arpt_keep, arptimer, la); + if (canceled) + LLE_REMREF(la); } la->la_asked = 0; la->la_preempt = V_arp_maxtries; Modified: head/sys/netinet/in.c ============================================================================== --- head/sys/netinet/in.c Sun Apr 11 15:35:17 2010 (r206480) +++ head/sys/netinet/in.c Sun Apr 11 16:04:08 2010 (r206481) @@ -1357,8 +1357,12 @@ in_lltable_prefix_free(struct lltable *l if (IN_ARE_MASKED_ADDR_EQUAL((struct sockaddr_in *)L3_ADDR(lle), pfx, msk)) { - callout_drain(&lle->la_timer); + int canceled; + + canceled = callout_drain(&lle->la_timer); LLE_WLOCK(lle); + if (canceled) + LLE_REMREF(lle); llentry_free(lle); } } Modified: head/sys/netinet6/in6.c ============================================================================== --- head/sys/netinet6/in6.c Sun Apr 11 15:35:17 2010 (r206480) +++ head/sys/netinet6/in6.c Sun Apr 11 16:04:08 2010 (r206481) @@ -2344,8 +2344,12 @@ in6_lltable_prefix_free(struct lltable * &((struct sockaddr_in6 *)L3_ADDR(lle))->sin6_addr, &pfx->sin6_addr, &msk->sin6_addr)) { - callout_drain(&lle->la_timer); + int canceled; + + canceled = callout_drain(&lle->la_timer); LLE_WLOCK(lle); + if (canceled) + LLE_REMREF(lle); llentry_free(lle); } } Modified: head/sys/netinet6/nd6.c ============================================================================== --- head/sys/netinet6/nd6.c Sun Apr 11 15:35:17 2010 (r206480) +++ head/sys/netinet6/nd6.c Sun Apr 11 16:04:08 2010 (r206481) @@ -1125,6 +1125,7 @@ nd6_free(struct llentry *ln, int gc) ifp = ln->lle_tbl->llt_ifp; IF_AFDATA_LOCK(ifp); LLE_WLOCK(ln); + LLE_REMREF(ln); llentry_free(ln); IF_AFDATA_UNLOCK(ifp);