Otherwise `if_snd' could still contain packets. If any of them has
associated data with bumped reference counter, the corresponding
refcnt_finalize() will sleep forever. I don't think we need to
transmit these packets when interface became running again.
I don't like this unlocked if_flags check we have in ifq_start_task().
Guess READ_ONCE() is much better to load value.
The problem reported in the "wg destroy hangs" [1] thread is the kind of
described above. Also, current ifq_start_task() implementation denies to
introduce reference counters for wg_peer and remove this
wg_peer_destroy() hack:
NET_LOCK();
while (!ifq_empty(&sc->sc_if.if_snd)) {
NET_UNLOCK();
tsleep_nsec(sc, PWAIT, "wg_ifq", 1000);
NET_LOCK();
}
NET_UNLOCK();
1. https://marc.info/?t=169642396300001&r=1&w=2
ok?
Index: sys/net/ifq.c
===================================================================
RCS file: /cvs/src/sys/net/ifq.c,v
retrieving revision 1.51
diff -u -p -r1.51 ifq.c
--- sys/net/ifq.c 5 Oct 2023 11:08:56 -0000 1.51
+++ sys/net/ifq.c 5 Oct 2023 11:49:40 -0000
@@ -140,8 +140,11 @@ ifq_start_task(void *p)
struct ifqueue *ifq = p;
struct ifnet *ifp = ifq->ifq_if;
- if (!ISSET(ifp->if_flags, IFF_RUNNING) ||
- ifq_empty(ifq) || ifq_is_oactive(ifq))
+ if (!ISSET(READ_ONCE(ifp->if_flags), IFF_RUNNING)){
+ ifq_purge(ifq);
+ return;
+ }
+ if (ifq_empty(ifq) || ifq_is_oactive(ifq))
return;
ifp->if_qstart(ifq);