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) {

Reply via email to