Skip site navigation (1)Skip section navigation (2)
Date:      Fri, 30 Nov 2018 10:36:14 +0000 (UTC)
From:      "Andrey V. Elsukov" <ae@FreeBSD.org>
To:        src-committers@freebsd.org, svn-src-all@freebsd.org, svn-src-head@freebsd.org
Subject:   svn commit: r341334 - head/sys/net
Message-ID:  <201811301036.wAUAaE9c094059@repo.freebsd.org>

next in thread | raw e-mail | index | archive | help
Author: ae
Date: Fri Nov 30 10:36:14 2018
New Revision: 341334
URL: https://svnweb.freebsd.org/changeset/base/341334

Log:
  Adapt the fix in r341008 to correctly work with EBR.
  
  IFNET_RLOCK_NOSLEEP() is epoch_enter_preempt() in FreeBSD 12+. Holding
  it in sysctl_rtsock() doesn't protect us from ifnet unlinking, because
  unlinking occurs with IFNET_WLOCK(), that is rw_wlock+sx_xlock, and it
  doesn check that concurrent code is running in epoch section. But while
  we are in epoch section, we should be able to do access to ifnet's
  fields, even it was unlinked. Thus do not change if_addr and if_hw_addr
  fields in ifnet_detach_internal() to NULL, since rtsock code can do
  access to these fields and this is allowed while it is running in epoch
  section.
  
  This should fix the race, when ifnet_detach_internal() unlinks ifnet
  after we checked it for IFF_DYING in sysctl_dumpentry.
  
  Move free(ifp->if_hw_addr) into ifnet_free_internal(). Also remove the
  NULL check for ifp->if_description, since free(9) can correctly handle
  NULL pointer.
  
  MFC after:	1 week

Modified:
  head/sys/net/if.c

Modified: head/sys/net/if.c
==============================================================================
--- head/sys/net/if.c	Fri Nov 30 10:31:30 2018	(r341333)
+++ head/sys/net/if.c	Fri Nov 30 10:36:14 2018	(r341334)
@@ -597,8 +597,6 @@ if_free_internal(struct ifnet *ifp)
 #ifdef MAC
 	mac_ifnet_destroy(ifp);
 #endif /* MAC */
-	if (ifp->if_description != NULL)
-		free(ifp->if_description, M_IFDESCR);
 	IF_AFDATA_DESTROY(ifp);
 	IF_ADDR_LOCK_DESTROY(ifp);
 	ifq_delete(&ifp->if_snd);
@@ -606,6 +604,8 @@ if_free_internal(struct ifnet *ifp)
 	for (int i = 0; i < IFCOUNTERS; i++)
 		counter_u64_free(ifp->if_counters[i]);
 
+	free(ifp->if_description, M_IFDESCR);
+	free(ifp->if_hw_addr, M_IFADDR);
 	free(ifp, M_IFNET);
 }
 
@@ -1184,14 +1184,8 @@ if_detach_internal(struct ifnet *ifp, int vmove, struc
 		if_dead(ifp);
 
 		/*
-		 * Remove link ifaddr pointer and maybe decrement if_index.
 		 * Clean up all addresses.
 		 */
-		free(ifp->if_hw_addr, M_IFADDR);
-		ifp->if_hw_addr = NULL;
-		ifp->if_addr = NULL;
-
-		/* We can now free link ifaddr. */
 		IF_ADDR_WLOCK(ifp);
 		if (!CK_STAILQ_EMPTY(&ifp->if_addrhead)) {
 			ifa = CK_STAILQ_FIRST(&ifp->if_addrhead);



Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?201811301036.wAUAaE9c094059>