Module Name: src Committed By: ozaki-r Date: Wed May 15 02:56:48 UTC 2019
Modified Files: src/sys/dev/ic: dwc_gmac.c src/sys/dev/pci: if_wm.c src/sys/dev/pci/ixgbe: ixgbe.c src/sys/net: if.c if_ether.h if_ethersubr.c Log Message: Store IFF_ALLMULTI in ec_flags instead of if_flags to avoid data races IFF_ALLMULTI is set/unset to if_flags via if_mcast_op. To avoid data races on if_flags, IFNET_LOCK was added for if_mcast_op. Unfortunately it produces a deadlock so we want to remove added IFNET_LOCK by avoiding the data races by another approach. This fix introduces ec_flags to struct ethercom and stores IFF_ALLMULTI to it. ec_flags is protected by ETHER_LOCK and thus IFNET_LOCK is no longer necessary for if_mcast_op. Note that the fix is applied only to MP-safe drivers that the data races matter. In the kernel, IFF_ALLMULTI is set by a driver and used by the driver itself. So changing the storing place doesn't break anything. One exception is ioctl(SIOCGIFFLAGS); we have to include IFF_ALLMULTI in a result if needed to export the flag as well as before. A upcoming commit will remove IFNET_LOCK. PR kern/54189 To generate a diff of this commit: cvs rdiff -u -r1.59 -r1.60 src/sys/dev/ic/dwc_gmac.c cvs rdiff -u -r1.635 -r1.636 src/sys/dev/pci/if_wm.c cvs rdiff -u -r1.182 -r1.183 src/sys/dev/pci/ixgbe/ixgbe.c cvs rdiff -u -r1.451 -r1.452 src/sys/net/if.c cvs rdiff -u -r1.77 -r1.78 src/sys/net/if_ether.h cvs rdiff -u -r1.273 -r1.274 src/sys/net/if_ethersubr.c Please note that diffs are not public domain; they are subject to the copyright notices on the relevant files.
Modified files: Index: src/sys/dev/ic/dwc_gmac.c diff -u src/sys/dev/ic/dwc_gmac.c:1.59 src/sys/dev/ic/dwc_gmac.c:1.60 --- src/sys/dev/ic/dwc_gmac.c:1.59 Mon Apr 15 06:00:04 2019 +++ src/sys/dev/ic/dwc_gmac.c Wed May 15 02:56:47 2019 @@ -1,4 +1,4 @@ -/* $NetBSD: dwc_gmac.c,v 1.59 2019/04/15 06:00:04 ozaki-r Exp $ */ +/* $NetBSD: dwc_gmac.c,v 1.60 2019/05/15 02:56:47 ozaki-r Exp $ */ /*- * Copyright (c) 2013, 2014 The NetBSD Foundation, Inc. @@ -41,7 +41,7 @@ #include <sys/cdefs.h> -__KERNEL_RCSID(1, "$NetBSD: dwc_gmac.c,v 1.59 2019/04/15 06:00:04 ozaki-r Exp $"); +__KERNEL_RCSID(1, "$NetBSD: dwc_gmac.c,v 1.60 2019/05/15 02:56:47 ozaki-r Exp $"); /* #define DWC_GMAC_DEBUG 1 */ @@ -1357,21 +1357,21 @@ dwc_gmac_setmulti(struct dwc_gmac_softc goto special_filter; } - ifp->if_flags &= ~IFF_ALLMULTI; ffilt &= ~(AWIN_GMAC_MAC_FFILT_PM|AWIN_GMAC_MAC_FFILT_PR); bus_space_write_4(sc->sc_bst, sc->sc_bsh, AWIN_GMAC_MAC_HTLOW, 0); bus_space_write_4(sc->sc_bst, sc->sc_bsh, AWIN_GMAC_MAC_HTHIGH, 0); ETHER_LOCK(ec); + ec->ec_flags &= ~ETHER_F_ALLMULTI; ETHER_FIRST_MULTI(step, ec, enm); mcnt = 0; while (enm != NULL) { if (memcmp(enm->enm_addrlo, enm->enm_addrhi, ETHER_ADDR_LEN) != 0) { - ETHER_UNLOCK(ec); ffilt |= AWIN_GMAC_MAC_FFILT_PM; - ifp->if_flags |= IFF_ALLMULTI; + ec->ec_flags |= ETHER_F_ALLMULTI; + ETHER_UNLOCK(ec); goto special_filter; } @@ -1395,7 +1395,7 @@ dwc_gmac_setmulti(struct dwc_gmac_softc hashes[0]); bus_space_write_4(sc->sc_bst, sc->sc_bsh, AWIN_GMAC_MAC_HTHIGH, hashes[1]); - sc->sc_if_flags = sc->sc_ec.ec_if.if_flags; + sc->sc_if_flags = ifp->if_flags; #ifdef DWC_GMAC_DEBUG dwc_gmac_dump_ffilt(sc, ffilt); Index: src/sys/dev/pci/if_wm.c diff -u src/sys/dev/pci/if_wm.c:1.635 src/sys/dev/pci/if_wm.c:1.636 --- src/sys/dev/pci/if_wm.c:1.635 Tue May 14 09:43:55 2019 +++ src/sys/dev/pci/if_wm.c Wed May 15 02:56:47 2019 @@ -1,4 +1,4 @@ -/* $NetBSD: if_wm.c,v 1.635 2019/05/14 09:43:55 ozaki-r Exp $ */ +/* $NetBSD: if_wm.c,v 1.636 2019/05/15 02:56:47 ozaki-r Exp $ */ /* * Copyright (c) 2001, 2002, 2003, 2004 Wasabi Systems, Inc. @@ -82,7 +82,7 @@ */ #include <sys/cdefs.h> -__KERNEL_RCSID(0, "$NetBSD: if_wm.c,v 1.635 2019/05/14 09:43:55 ozaki-r Exp $"); +__KERNEL_RCSID(0, "$NetBSD: if_wm.c,v 1.636 2019/05/15 02:56:47 ozaki-r Exp $"); #ifdef _KERNEL_OPT #include "opt_net_mpsafe.h" @@ -3707,6 +3707,9 @@ wm_set_filter(struct wm_softc *sc) sc->sc_rctl |= RCTL_BAM; if (ifp->if_flags & IFF_PROMISC) { sc->sc_rctl |= RCTL_UPE; + ETHER_LOCK(ec); + ec->ec_flags |= ETHER_F_ALLMULTI; + ETHER_UNLOCK(ec); goto allmulti; } @@ -3757,6 +3760,7 @@ wm_set_filter(struct wm_softc *sc) ETHER_FIRST_MULTI(step, ec, enm); while (enm != NULL) { if (memcmp(enm->enm_addrlo, enm->enm_addrhi, ETHER_ADDR_LEN)) { + ec->ec_flags |= ETHER_F_ALLMULTI; ETHER_UNLOCK(ec); /* * We must listen to a range of multicast addresses. @@ -3804,13 +3808,12 @@ wm_set_filter(struct wm_softc *sc) ETHER_NEXT_MULTI(step, enm); } + ec->ec_flags &= ~ETHER_F_ALLMULTI; ETHER_UNLOCK(ec); - ifp->if_flags &= ~IFF_ALLMULTI; goto setit; allmulti: - ifp->if_flags |= IFF_ALLMULTI; sc->sc_rctl |= RCTL_MPE; setit: Index: src/sys/dev/pci/ixgbe/ixgbe.c diff -u src/sys/dev/pci/ixgbe/ixgbe.c:1.182 src/sys/dev/pci/ixgbe/ixgbe.c:1.183 --- src/sys/dev/pci/ixgbe/ixgbe.c:1.182 Tue May 14 09:43:55 2019 +++ src/sys/dev/pci/ixgbe/ixgbe.c Wed May 15 02:56:47 2019 @@ -1,4 +1,4 @@ -/* $NetBSD: ixgbe.c,v 1.182 2019/05/14 09:43:55 ozaki-r Exp $ */ +/* $NetBSD: ixgbe.c,v 1.183 2019/05/15 02:56:47 ozaki-r Exp $ */ /****************************************************************************** @@ -3017,10 +3017,10 @@ ixgbe_set_promisc(struct adapter *adapte KASSERT(mutex_owned(&adapter->core_mtx)); rctl = IXGBE_READ_REG(&adapter->hw, IXGBE_FCTRL); rctl &= (~IXGBE_FCTRL_UPE); - if (ifp->if_flags & IFF_ALLMULTI) + ETHER_LOCK(ec); + if (ec->ec_flags & ETHER_F_ALLMULTI) mcnt = MAX_NUM_MULTICAST_ADDRESSES; else { - ETHER_LOCK(ec); ETHER_FIRST_MULTI(step, ec, enm); while (enm != NULL) { if (mcnt == MAX_NUM_MULTICAST_ADDRESSES) @@ -3028,7 +3028,6 @@ ixgbe_set_promisc(struct adapter *adapte mcnt++; ETHER_NEXT_MULTI(step, enm); } - ETHER_UNLOCK(ec); } if (mcnt < MAX_NUM_MULTICAST_ADDRESSES) rctl &= (~IXGBE_FCTRL_MPE); @@ -3037,11 +3036,12 @@ ixgbe_set_promisc(struct adapter *adapte if (ifp->if_flags & IFF_PROMISC) { rctl |= (IXGBE_FCTRL_UPE | IXGBE_FCTRL_MPE); IXGBE_WRITE_REG(&adapter->hw, IXGBE_FCTRL, rctl); - } else if (ifp->if_flags & IFF_ALLMULTI) { + } else if (ec->ec_flags & ETHER_F_ALLMULTI) { rctl |= IXGBE_FCTRL_MPE; rctl &= ~IXGBE_FCTRL_UPE; IXGBE_WRITE_REG(&adapter->hw, IXGBE_FCTRL, rctl); } + ETHER_UNLOCK(ec); } /* ixgbe_set_promisc */ /************************************************************************ @@ -4354,14 +4354,14 @@ ixgbe_set_multi(struct adapter *adapter) mta = adapter->mta; bzero(mta, sizeof(*mta) * MAX_NUM_MULTICAST_ADDRESSES); - ifp->if_flags &= ~IFF_ALLMULTI; ETHER_LOCK(ec); + ec->ec_flags &= ~ETHER_F_ALLMULTI; ETHER_FIRST_MULTI(step, ec, enm); while (enm != NULL) { if ((mcnt == MAX_NUM_MULTICAST_ADDRESSES) || (memcmp(enm->enm_addrlo, enm->enm_addrhi, ETHER_ADDR_LEN) != 0)) { - ifp->if_flags |= IFF_ALLMULTI; + ec->ec_flags |= ETHER_F_ALLMULTI; break; } bcopy(enm->enm_addrlo, @@ -4370,15 +4370,15 @@ ixgbe_set_multi(struct adapter *adapter) mcnt++; ETHER_NEXT_MULTI(step, enm); } - ETHER_UNLOCK(ec); fctrl = IXGBE_READ_REG(&adapter->hw, IXGBE_FCTRL); fctrl &= ~(IXGBE_FCTRL_UPE | IXGBE_FCTRL_MPE); if (ifp->if_flags & IFF_PROMISC) fctrl |= (IXGBE_FCTRL_UPE | IXGBE_FCTRL_MPE); - else if (ifp->if_flags & IFF_ALLMULTI) { + else if (ec->ec_flags & ETHER_F_ALLMULTI) { fctrl |= IXGBE_FCTRL_MPE; } + ETHER_UNLOCK(ec); IXGBE_WRITE_REG(&adapter->hw, IXGBE_FCTRL, fctrl); Index: src/sys/net/if.c diff -u src/sys/net/if.c:1.451 src/sys/net/if.c:1.452 --- src/sys/net/if.c:1.451 Sat Apr 20 22:16:47 2019 +++ src/sys/net/if.c Wed May 15 02:56:48 2019 @@ -1,4 +1,4 @@ -/* $NetBSD: if.c,v 1.451 2019/04/20 22:16:47 pgoyette Exp $ */ +/* $NetBSD: if.c,v 1.452 2019/05/15 02:56:48 ozaki-r Exp $ */ /*- * Copyright (c) 1999, 2000, 2001, 2008 The NetBSD Foundation, Inc. @@ -90,7 +90,7 @@ */ #include <sys/cdefs.h> -__KERNEL_RCSID(0, "$NetBSD: if.c,v 1.451 2019/04/20 22:16:47 pgoyette Exp $"); +__KERNEL_RCSID(0, "$NetBSD: if.c,v 1.452 2019/05/15 02:56:48 ozaki-r Exp $"); #if defined(_KERNEL_OPT) #include "opt_inet.h" @@ -3625,13 +3625,6 @@ if_mcast_op(ifnet_t *ifp, const unsigned int rc; struct ifreq ifr; - /* There remain some paths that don't hold IFNET_LOCK yet */ -#ifdef NET_MPSAFE - /* CARP and MROUTING still don't deal with the lock yet */ -#if (!defined(NCARP) || (NCARP == 0)) && !defined(MROUTING) - KASSERT(IFNET_LOCKED(ifp)); -#endif -#endif if (ifp->if_mcastop != NULL) rc = (*ifp->if_mcastop)(ifp, cmd, sa); else { Index: src/sys/net/if_ether.h diff -u src/sys/net/if_ether.h:1.77 src/sys/net/if_ether.h:1.78 --- src/sys/net/if_ether.h:1.77 Tue Mar 5 08:25:03 2019 +++ src/sys/net/if_ether.h Wed May 15 02:56:48 2019 @@ -1,4 +1,4 @@ -/* $NetBSD: if_ether.h,v 1.77 2019/03/05 08:25:03 msaitoh Exp $ */ +/* $NetBSD: if_ether.h,v 1.78 2019/05/15 02:56:48 ozaki-r Exp $ */ /* * Copyright (c) 1982, 1986, 1993 @@ -189,6 +189,8 @@ struct ethercom { */ ether_cb_t ec_ifflags_cb; kmutex_t *ec_lock; + /* Flags used only by the kernel */ + int ec_flags; #ifdef MBUFTRACE struct mowner ec_rx_mowner; /* mbufs received */ struct mowner ec_tx_mowner; /* mbufs transmitted */ @@ -225,6 +227,12 @@ struct ether_multi_sysctl { }; #ifdef _KERNEL +/* + * Flags for ec_flags + */ +/* Store IFF_ALLMULTI in ec_flags instead of if_flags to avoid data races. */ +#define ETHER_F_ALLMULTI __BIT(0) + extern const uint8_t etherbroadcastaddr[ETHER_ADDR_LEN]; extern const uint8_t ethermulticastaddr_slowprotocols[ETHER_ADDR_LEN]; extern const uint8_t ether_ipmulticast_min[ETHER_ADDR_LEN]; Index: src/sys/net/if_ethersubr.c diff -u src/sys/net/if_ethersubr.c:1.273 src/sys/net/if_ethersubr.c:1.274 --- src/sys/net/if_ethersubr.c:1.273 Mon Feb 4 10:11:34 2019 +++ src/sys/net/if_ethersubr.c Wed May 15 02:56:48 2019 @@ -1,4 +1,4 @@ -/* $NetBSD: if_ethersubr.c,v 1.273 2019/02/04 10:11:34 mrg Exp $ */ +/* $NetBSD: if_ethersubr.c,v 1.274 2019/05/15 02:56:48 ozaki-r Exp $ */ /* * Copyright (C) 1995, 1996, 1997, and 1998 WIDE Project. @@ -61,7 +61,7 @@ */ #include <sys/cdefs.h> -__KERNEL_RCSID(0, "$NetBSD: if_ethersubr.c,v 1.273 2019/02/04 10:11:34 mrg Exp $"); +__KERNEL_RCSID(0, "$NetBSD: if_ethersubr.c,v 1.274 2019/05/15 02:56:48 ozaki-r Exp $"); #ifdef _KERNEL_OPT #include "opt_inet.h" @@ -997,6 +997,7 @@ ether_ifattach(struct ifnet *ifp, const LIST_INIT(&ec->ec_multiaddrs); ec->ec_lock = mutex_obj_alloc(MUTEX_DEFAULT, IPL_NET); + ec->ec_flags = 0; ifp->if_broadcastaddr = etherbroadcastaddr; bpf_attach(ifp, DLT_EN10MB, sizeof(struct ether_header)); #ifdef MBUFTRACE @@ -1470,6 +1471,14 @@ ether_ioctl(struct ifnet *ifp, u_long cm if ((error = ifioctl_common(ifp, cmd, data)) != 0) return error; return ether_ioctl_reinit(ec); + case SIOCGIFFLAGS: + error = ifioctl_common(ifp, cmd, data); + if (error == 0) { + /* Set IFF_ALLMULTI for backcompat */ + ifr->ifr_flags |= (ec->ec_flags & ETHER_F_ALLMULTI) ? + IFF_ALLMULTI : 0; + } + return error; case SIOCGETHERCAP: eccr = (struct eccapreq *)data; eccr->eccr_capabilities = ec->ec_capabilities;