From c32a9d66fb497d507a3d1699d61553aca24ed9a8 Mon Sep 17 00:00:00 2001 From: Hans Petter Selasky Date: Mon, 15 Oct 2018 10:29:29 +0000 Subject: [PATCH] Fix deadlock when destroying VLANs. Synchronizing the epoch before freeing the multicast addresses while holding the VLAN_XLOCK() might lead to a deadlock. Use deferred freeing of the VLAN multicast addresses to resolve deadlock. Backtrace: Thread1: epoch_block_handler_preempt() ck_epoch_synchronize_wait() epoch_wait_preempt() vlan_setmulti() vlan_ioctl() in6m_release_task() gtaskqueue_run_locked() gtaskqueue_thread_loop() fork_exit() fork_trampoline() Thread2: sleepq_switch() sleepq_wait() _sx_xlock_hard() _sx_xlock() in6_leavegroup() in6_purgeaddr() if_purgeaddrs() if_detach_internal() if_detach() vlan_clone_destroy() if_clone_destroyif() if_clone_destroy() ifioctl() kern_ioctl() sys_ioctl() amd64_syscall() fast_syscall_common() syscall() Differential revision: https://reviews.freebsd.org/D17496 Reviewed by: slavash, mmacy Approved by: re (kib) Sponsored by: Mellanox Technologies --- sys/net/if_vlan.c | 14 ++++++++++---- 1 file changed, 10 insertions(+), 4 deletions(-) diff --git a/sys/net/if_vlan.c b/sys/net/if_vlan.c index 5170ee6ae35..b75a62c16b3 100644 --- a/sys/net/if_vlan.c +++ b/sys/net/if_vlan.c @@ -153,6 +153,7 @@ struct ifvlantrunk { struct vlan_mc_entry { struct sockaddr_dl mc_addr; CK_SLIST_ENTRY(vlan_mc_entry) mc_entries; + struct epoch_context mc_epoch_ctx; }; struct ifvlan { @@ -316,6 +317,13 @@ VNET_DEFINE_STATIC(struct if_clone *, vlan_cloner); #ifndef VLAN_ARRAY #define HASH(n, m) ((((n) >> 8) ^ ((n) >> 4) ^ (n)) & (m)) +static void +vlan_mc_free(struct epoch_context *ctx) +{ + struct vlan_mc_entry *mc = __containerof(ctx, struct vlan_mc_entry, mc_epoch_ctx); + free(mc, M_VLAN); +} + static void vlan_inithash(struct ifvlantrunk *trunk) { @@ -572,8 +580,7 @@ vlan_setmulti(struct ifnet *ifp) while ((mc = CK_SLIST_FIRST(&sc->vlan_mc_listhead)) != NULL) { CK_SLIST_REMOVE_HEAD(&sc->vlan_mc_listhead, mc_entries); (void)if_delmulti(ifp_p, (struct sockaddr *)&mc->mc_addr); - NET_EPOCH_WAIT(); - free(mc, M_VLAN); + epoch_call(net_epoch_preempt, &mc->mc_epoch_ctx, vlan_mc_free); } /* Now program new ones. */ @@ -1485,8 +1492,7 @@ vlan_unconfig_locked(struct ifnet *ifp, int departing) error); } CK_SLIST_REMOVE_HEAD(&ifv->vlan_mc_listhead, mc_entries); - NET_EPOCH_WAIT(); - free(mc, M_VLAN); + epoch_call(net_epoch_preempt, &mc->mc_epoch_ctx, vlan_mc_free); } vlan_setflags(ifp, 0); /* clear special flags on parent */