Module Name: src Committed By: ozaki-r Date: Tue Oct 20 07:46:59 UTC 2015
Modified Files: src/sys/netinet: if_arp.c Log Message: Stop callout in arp_rtrequest(RTM_DELETE) This change fixes arptimer panic after removing an interface (say by drvctl -d), which is reported by Takahiro Hayashi. This change also fixes llentry's reference counting; we have to take into account rtentry#rt_llinfo as well as arptimer. To generate a diff of this commit: cvs rdiff -u -r1.190 -r1.191 src/sys/netinet/if_arp.c Please note that diffs are not public domain; they are subject to the copyright notices on the relevant files.
Modified files: Index: src/sys/netinet/if_arp.c diff -u src/sys/netinet/if_arp.c:1.190 src/sys/netinet/if_arp.c:1.191 --- src/sys/netinet/if_arp.c:1.190 Tue Oct 20 07:35:15 2015 +++ src/sys/netinet/if_arp.c Tue Oct 20 07:46:59 2015 @@ -1,4 +1,4 @@ -/* $NetBSD: if_arp.c,v 1.190 2015/10/20 07:35:15 ozaki-r Exp $ */ +/* $NetBSD: if_arp.c,v 1.191 2015/10/20 07:46:59 ozaki-r Exp $ */ /*- * Copyright (c) 1998, 2000, 2008 The NetBSD Foundation, Inc. @@ -68,7 +68,7 @@ */ #include <sys/cdefs.h> -__KERNEL_RCSID(0, "$NetBSD: if_arp.c,v 1.190 2015/10/20 07:35:15 ozaki-r Exp $"); +__KERNEL_RCSID(0, "$NetBSD: if_arp.c,v 1.191 2015/10/20 07:46:59 ozaki-r Exp $"); #ifdef _KERNEL_OPT #include "opt_ddb.h" @@ -635,6 +635,7 @@ arp_rtrequest(int req, struct rtentry *r break; } rt->rt_llinfo = la; + LLE_ADDREF(la); switch (ifp->if_type) { #if NTOKEN > 0 case IFT_ISO88025: @@ -662,17 +663,14 @@ arp_rtrequest(int req, struct rtentry *r rt->rt_llinfo = NULL; rt->rt_flags &= ~RTF_LLINFO; + /* Have to do before IF_AFDATA_WLOCK to avoid deadlock */ + callout_halt(&la->la_timer, &la->lle_lock); + /* XXX: LOR avoidance. We still have ref on lle. */ LLE_RUNLOCK(la); flags |= LLE_EXCLUSIVE; IF_AFDATA_WLOCK(ifp); - - la = lla_lookup(LLTABLE(ifp), flags, rt_getkey(rt)); - /* This shouldn't happen */ - if (la == NULL) { - IF_AFDATA_WUNLOCK(ifp); - break; - } + LLE_WLOCK(la); if (la->la_opaque != NULL) { switch (ifp->if_type) { @@ -695,10 +693,20 @@ arp_rtrequest(int req, struct rtentry *r la->la_rt->rt_refcnt--; la->la_rt = NULL; } - llentry_free(la); - IF_AFDATA_WUNLOCK(ifp); + /* Guard against race with other llentry_free(). */ + if (la->la_flags & LLE_LINKED) { + size_t pkts_dropped; + + LLE_REMREF(la); + pkts_dropped = llentry_free(la); + ARP_STATADD(ARP_STAT_DFRDROPPED, pkts_dropped); + } else { + LLE_FREE_LOCKED(la); + } la = NULL; + + IF_AFDATA_WUNLOCK(ifp); } if (la != NULL) {