git: 6b3b1d6d4f43 - main - hn: Serialize VF link events with datapath handoff

From: Kevin Bowling <kbowling_at_FreeBSD.org>
Date: Tue, 15 Sep 2026 02:01:54 UTC
The branch main has been updated by kbowling:

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

commit 6b3b1d6d4f43d1521e5e10b759e3542deaf23667
Author:     Kevin Bowling <kbowling@FreeBSD.org>
AuthorDate: 2026-09-15 00:22:13 +0000
Commit:     Kevin Bowling <kbowling@FreeBSD.org>
CommitDate: 2026-09-15 02:01:35 +0000

    hn: Serialize VF link events with datapath handoff
    
    Hold hn_vf_lock across the VF identity/state check and link publication.
    Otherwise an event can observe an enabled VF, pause during fallback, then
    overwrite the freshly reported synthetic carrier with stale VF state.
    Ignore events while switching or after the association generation changes.
    The link notification only queues further work, so the callback does not
    need the sleepable hn lock.
    
    Document that association serial numbers are currently diagnostic:
    hn_ismyvf() matches the VF by MAC, while notifications gate availability.
    
    MFC after:      2 weeks
    Sponsored by:   BBOX.io
---
 sys/dev/hyperv/netvsc/if_hn.c | 9 ++++++++-
 1 file changed, 8 insertions(+), 1 deletion(-)

diff --git a/sys/dev/hyperv/netvsc/if_hn.c b/sys/dev/hyperv/netvsc/if_hn.c
index a36656b89b76..e4774b285a15 100644
--- a/sys/dev/hyperv/netvsc/if_hn.c
+++ b/sys/dev/hyperv/netvsc/if_hn.c
@@ -2132,10 +2132,16 @@ static void
 hn_ifnet_lnkevent(void *xsc, if_t ifp, int link_state)
 {
 	struct hn_softc *sc = xsc;
+	struct rm_priotracker pt;
 
+	/* Publish before a concurrent handoff can restore synthetic carrier. */
+	rm_rlock(&sc->hn_vf_lock, &pt);
 	if (sc->hn_vf_ifp == ifp &&
-	    (sc->hn_xvf_flags & HN_XVFFLAG_ENABLED))
+	    (sc->hn_xvf_flags & (HN_XVFFLAG_ENABLED | HN_XVFFLAG_SWITCHING)) ==
+	    HN_XVFFLAG_ENABLED && sc->hn_vf_active_assoc ==
+	    atomic_load_acq_int(&sc->hn_vf_assoc))
 		if_link_state_change(sc->hn_ifp, link_state);
+	rm_runlock(&sc->hn_vf_lock, &pt);
 }
 
 static int
@@ -7527,6 +7533,7 @@ hn_nvs_handle_notify(struct hn_softc *sc, const struct vmbus_chanpkt_hdr *pkt)
 			if_printf(sc->hn_ifp, "invalid VF association notification\n");
 			return;
 		}
+		/* The serial is diagnostic; hn_ismyvf() matches the VF by MAC. */
 		/* Preserve withdrawals even when the worker coalesces notices. */
 		state = (atomic_load_int(&sc->hn_vf_assoc) + HN_VF_ASSOC_GENINC) &
 		    ~HN_VF_ASSOC_ALLOCATED;