Index: sys/net/if.c =================================================================== --- sys/net/if.c +++ sys/net/if.c @@ -472,11 +472,24 @@ { struct ifnet *ifp, *nifp; + /* + * We need to protect our access to the V_ifnet tailq. Ordinarily we'd + * enter NET_EPOCH, but that's not possible, because if_vmove() calls + * if_detach_internal(), which waits for NET_EPOCH callbacks to + * complete. We can't do that from within NET_EPOCH. + * + * However, we can also use the IFNET_xLOCK, which is the V_ifnet + * read/write lock. We take this lock from within if_vmove() as well, + * but it's a recursive lock, so that's safe. We do have to take the + * write lock, because we need the write lock in if_vmove(). + */ + IFNET_WLOCK(); /* Return all inherited interfaces to their parent vnets. */ CK_STAILQ_FOREACH_SAFE(ifp, &V_ifnet, if_link, nifp) { if (ifp->if_home_vnet != ifp->if_vnet) if_vmove(ifp, ifp->if_home_vnet); } + IFNET_WUNLOCK(); } VNET_SYSUNINIT(vnet_if_return, SI_SUB_VNET_DONE, SI_ORDER_ANY, vnet_if_return, NULL); Index: sys/net/if_var.h =================================================================== --- sys/net/if_var.h +++ sys/net/if_var.h @@ -595,23 +595,10 @@ extern struct sx ifnet_sxlock; -#define IFNET_WLOCK() do { \ - sx_xlock(&ifnet_sxlock); \ -} while (0) - -#define IFNET_WUNLOCK() do { \ - sx_xunlock(&ifnet_sxlock); \ -} while (0) - -/* - * To assert the ifnet lock, you must know not only whether it's for read or - * write, but also whether it was acquired with sleep support or not. - */ -#define IFNET_RLOCK_ASSERT() sx_assert(&ifnet_sxlock, SA_SLOCKED) -#define IFNET_WLOCK_ASSERT() do { \ - sx_assert(&ifnet_sxlock, SA_XLOCKED); \ -} while (0) - +#define IFNET_WLOCK() sx_xlock(&ifnet_sxlock) +#define IFNET_WUNLOCK() sx_xunlock(&ifnet_sxlock) +#define IFNET_RLOCK_ASSERT() sx_assert(&ifnet_sxlock, SA_SLOCKED) +#define IFNET_WLOCK_ASSERT() sx_assert(&ifnet_sxlock, SA_XLOCKED) #define IFNET_RLOCK() sx_slock(&ifnet_sxlock) #define IFNET_RUNLOCK() sx_sunlock(&ifnet_sxlock)