git: fe1299f16c55 - stable/15 - lagg: Avoid dropping locks when starting the interface

From: Zhenlei Huang <zlei_at_FreeBSD.org>
Date: Mon, 16 Feb 2026 10:01:05 UTC
The branch stable/15 has been updated by zlei:

URL: https://cgit.FreeBSD.org/src/commit/?id=fe1299f16c55f09fa053e71bf1e1feee7f32527f

commit fe1299f16c55f09fa053e71bf1e1feee7f32527f
Author:     Zhenlei Huang <zlei@FreeBSD.org>
AuthorDate: 2026-02-11 18:15:41 +0000
Commit:     Zhenlei Huang <zlei@FreeBSD.org>
CommitDate: 2026-02-16 10:00:30 +0000

    lagg: Avoid dropping locks when starting the interface
    
    The init routine of a lagg(4) interface will not change during the whole
    lifecycle. So we can call lagg_init() directly instead of through the
    function pointer. Well, that requires a drop and pickup lock, which
    unnecessarily expose a small race window. Refactor lagg_init() into
    lagg_init_locked() and call the later one to avoid that.
    
    Meanwhile, delay updating the driver managed status until after the
    interface is really ready.
    
    Reviewed by:    markj
    MFC after:      5 days
    Differential Revision:  https://reviews.freebsd.org/D55198
    
    (cherry picked from commit c182cf646a4f995fa8506afd8afc9541c4d32905)
---
 sys/net/if_lagg.c | 36 +++++++++++++++++++-----------------
 1 file changed, 19 insertions(+), 17 deletions(-)

diff --git a/sys/net/if_lagg.c b/sys/net/if_lagg.c
index c30af5bfcc4e..23ad4f72d255 100644
--- a/sys/net/if_lagg.c
+++ b/sys/net/if_lagg.c
@@ -139,6 +139,7 @@ static int	lagg_port_checkstacking(struct lagg_softc *);
 static void	lagg_port2req(struct lagg_port *, struct lagg_reqport *);
 static void	lagg_if_updown(struct lagg_softc *, bool);
 static void	lagg_init(void *);
+static void	lagg_init_locked(struct lagg_softc *);
 static void	lagg_stop(struct lagg_softc *);
 static int	lagg_ioctl(struct ifnet *, u_long, caddr_t);
 #if defined(KERN_TLS) || defined(RATELIMIT)
@@ -1282,16 +1283,21 @@ static void
 lagg_init(void *xsc)
 {
 	struct lagg_softc *sc = (struct lagg_softc *)xsc;
+
+	LAGG_XLOCK(sc);
+	lagg_init_locked(sc);
+	LAGG_XUNLOCK(sc);
+}
+
+static void
+lagg_init_locked(struct lagg_softc *sc)
+{
 	struct ifnet *ifp = sc->sc_ifp;
 	struct lagg_port *lp;
 
-	LAGG_XLOCK(sc);
-	if (ifp->if_drv_flags & IFF_DRV_RUNNING) {
-		LAGG_XUNLOCK(sc);
+	LAGG_XLOCK_ASSERT(sc);
+	if ((ifp->if_drv_flags & IFF_DRV_RUNNING) != 0)
 		return;
-	}
-
-	ifp->if_drv_flags |= IFF_DRV_RUNNING;
 
 	/*
 	 * Update the port lladdrs if needed.
@@ -1313,8 +1319,7 @@ lagg_init(void *xsc)
 		lagg_watchdog_infiniband(sc);
 		mtx_unlock(&sc->sc_mtx);
 	}
-
-	LAGG_XUNLOCK(sc);
+	ifp->if_drv_flags |= IFF_DRV_RUNNING;
 }
 
 static void
@@ -1677,24 +1682,21 @@ lagg_ioctl(struct ifnet *ifp, u_long cmd, caddr_t data)
 			lagg_setflags(lp, 1);
 		}
 
-		if (!(ifp->if_flags & IFF_UP) &&
-		    (ifp->if_drv_flags & IFF_DRV_RUNNING)) {
+		if ((ifp->if_flags & IFF_UP) == 0 &&
+		    (ifp->if_drv_flags & IFF_DRV_RUNNING) != 0)
 			/*
 			 * If interface is marked down and it is running,
 			 * then stop and disable it.
 			 */
 			lagg_stop(sc);
-			LAGG_XUNLOCK(sc);
-		} else if ((ifp->if_flags & IFF_UP) &&
-		    !(ifp->if_drv_flags & IFF_DRV_RUNNING)) {
+		else if ((ifp->if_flags & IFF_UP) != 0 &&
+		    (ifp->if_drv_flags & IFF_DRV_RUNNING) == 0)
 			/*
 			 * If interface is marked up and it is stopped, then
 			 * start it.
 			 */
-			LAGG_XUNLOCK(sc);
-			(*ifp->if_init)(sc);
-		} else
-			LAGG_XUNLOCK(sc);
+			lagg_init_locked(sc);
+		LAGG_XUNLOCK(sc);
 		break;
 	case SIOCADDMULTI:
 	case SIOCDELMULTI: