Module Name:    src
Committed By:   yamaguchi
Date:           Thu Sep 30 04:20:14 UTC 2021

Modified Files:
        src/sys/net/lagg: if_lagg.c

Log Message:
Fix to acquire LAGG_LOCK without psref
to remove possibility of deadlock

the deadlock maybe happened between lagg_ifdetach()
and lagg_delport()

1. lagg_ifdetach calls psref_target_acquire()
2. lagg_delport calls LAGG_LOCK()
3. lagg_ifdetach calls LAGG_LOCK()
   - wait for lagg_delport
4. lagg_delport calls psref_target_destroy()
   - wait for lagg_ifdetach


To generate a diff of this commit:
cvs rdiff -u -r1.7 -r1.8 src/sys/net/lagg/if_lagg.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/net/lagg/if_lagg.c
diff -u src/sys/net/lagg/if_lagg.c:1.7 src/sys/net/lagg/if_lagg.c:1.8
--- src/sys/net/lagg/if_lagg.c:1.7	Thu Sep 30 03:39:39 2021
+++ src/sys/net/lagg/if_lagg.c	Thu Sep 30 04:20:14 2021
@@ -1,4 +1,4 @@
-/*	$NetBSD: if_lagg.c,v 1.7 2021/09/30 03:39:39 yamaguchi Exp $	*/
+/*	$NetBSD: if_lagg.c,v 1.8 2021/09/30 04:20:14 yamaguchi Exp $	*/
 
 /*
  * Copyright (c) 2005, 2006 Reyk Floeter <r...@openbsd.org>
@@ -20,7 +20,7 @@
  */
 
 #include <sys/cdefs.h>
-__KERNEL_RCSID(0, "$NetBSD: if_lagg.c,v 1.7 2021/09/30 03:39:39 yamaguchi Exp $");
+__KERNEL_RCSID(0, "$NetBSD: if_lagg.c,v 1.8 2021/09/30 04:20:14 yamaguchi Exp $");
 
 #ifdef _KERNEL_OPT
 #include "opt_inet.h"
@@ -2051,15 +2051,19 @@ lagg_addport(struct lagg_softc *sc, stru
 }
 
 static void
-lagg_delport_locked(struct lagg_softc *sc, struct lagg_port *lp)
+lagg_delport_locked(struct lagg_softc *sc, struct lagg_port *lp,
+    bool is_ifdetach)
 {
 	struct ifnet *ifp_port;
 	struct ifreq ifr;
 	u_long if_type;
-	bool stopped, detaching;
+	bool stopped;
 
 	KASSERT(LAGG_LOCKED(sc));
 
+	if (lp == NULL)
+		return;
+
 	ifp_port = lp->lp_ifp;
 	stopped = false;
 
@@ -2093,7 +2097,6 @@ lagg_delport_locked(struct lagg_softc *s
 	lagg_port_purgemulti(sc, lp);
 	lagg_port_purgevlan(sc, lp);
 
-	detaching = lp->lp_detaching;
 	IFNET_LOCK(ifp_port);
 	if_type = ifp_port->if_type;
 	ifp_port->if_type = lp->lp_iftype;
@@ -2111,7 +2114,7 @@ lagg_delport_locked(struct lagg_softc *s
 		ifp_port->if_init(ifp_port);
 	}
 
-	if (!detaching) {
+	if (is_ifdetach == false) {
 		IFNET_LOCK(ifp_port);
 		lagg_in6_ifattach(ifp_port);
 		IFNET_UNLOCK(ifp_port);
@@ -2125,7 +2128,7 @@ lagg_delport_all(struct lagg_softc *sc)
 
 	LAGG_LOCK(sc);
 	LAGG_PORTS_FOREACH_SAFE(sc, lp, lp0) {
-		lagg_delport_locked(sc, lp);
+		lagg_delport_locked(sc, lp, false);
 	}
 	LAGG_UNLOCK(sc);
 }
@@ -2142,7 +2145,7 @@ lagg_delport(struct lagg_softc *sc, stru
 		return ENOENT;
 
 	LAGG_LOCK(sc);
-	lagg_delport_locked(sc, lp);
+	lagg_delport_locked(sc, lp, false);
 	LAGG_UNLOCK(sc);
 
 	return 0;
@@ -2315,7 +2318,6 @@ lagg_ifdetach(struct ifnet *ifp_port)
 {
 	struct lagg_port *lp;
 	struct lagg_softc *sc;
-	struct psref psref;
 	int s;
 
 	IFNET_ASSERT_UNLOCKED(ifp_port);
@@ -2326,21 +2328,22 @@ lagg_ifdetach(struct ifnet *ifp_port)
 		pserialize_read_exit(s);
 		return;
 	}
-	lagg_port_getref(lp, &psref);
-	pserialize_read_exit(s);
 
 	sc = lp->lp_softc;
-	if (sc != NULL) {
-		IFNET_LOCK(&sc->sc_if);
-		LAGG_LOCK(sc);
-		lagg_port_putref(lp, &psref);
-	} else {
-		lagg_port_putref(lp, &psref);
+	if (sc == NULL) {
+		pserialize_read_exit(s);
 		return;
 	}
+	pserialize_read_exit(s);
 
-	lp->lp_detaching = true;
-	lagg_delport_locked(sc, lp);
+	IFNET_LOCK(&sc->sc_if);
+	LAGG_LOCK(sc);
+	/*
+	 * reload if_lagg because it may write
+	 * after pserialize_read_exit.
+	 */
+	lp = ifp_port->if_lagg;
+	lagg_delport_locked(sc, lp, true);
 	LAGG_UNLOCK(sc);
 	IFNET_UNLOCK(&sc->sc_if);
 }

Reply via email to