From nobody Mon Apr 6 18:55:09 2026 Received: from mail-dy1-f175.google.com (mail-dy1-f175.google.com [74.125.82.175]) (using TLSv1.2 with cipher ECDHE-RSA-AES128-GCM-SHA256 (128/128 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id 2C53C3E123D for ; Wed, 18 Mar 2026 15:03:15 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=74.125.82.175 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1773846199; cv=none; b=hteCBTkMrSKFxU8M20I8xgtqEDSPBQVAp5gtys9R2Ym2d3EpOiXXK+coElVjO7gBBxAWiDnjd+efACaS2RNNjdgk6SNgE/Pfgr/gKSNLyonotoMuCEKHWUFSJxSAOAsi5OjQlH0aCWQIiY5kWGUG2QHM3Lnwohc82zuVP7zUCGk= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1773846199; c=relaxed/simple; bh=4NH5F9UrZZRv67H096Ecg+wmusilA5EZ4o5TxZuzEHw=; h=From:To:Cc:Subject:Date:Message-ID:In-Reply-To:References: MIME-Version; b=a0wWyH9LVNxu5VTECU89AQ1pOjDRQZqtCS12ziIJ6UNqIVh7apSq2sCzSZO+Nctp7QXO5YM5jbEX38Cy9ev3lCGFjbwogV/0+SNM2MjxdchEhNTATr8IVhNnHFW4n9mohWZJ1QXr5xAt+Gfu3q5IzUhltNcwF0kks/K7n7veUyc= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dmarc=none (p=none dis=none) header.from=fomichev.me; spf=pass smtp.mailfrom=gmail.com; arc=none smtp.client-ip=74.125.82.175 Authentication-Results: smtp.subspace.kernel.org; dmarc=none (p=none dis=none) header.from=fomichev.me Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=gmail.com Received: by mail-dy1-f175.google.com with SMTP id 5a478bee46e88-2c0bb213b16so12101eec.0 for ; Wed, 18 Mar 2026 08:03:14 -0700 (PDT) X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20251104; t=1773846194; x=1774450994; h=content-transfer-encoding:mime-version:references:in-reply-to :message-id:date:subject:cc:to:from:x-gm-gg:x-gm-message-state:from :to:cc:subject:date:message-id:reply-to; bh=N5GGovMWPDFF8AAhYqWq6WCuZYPSvbfMRDbyACSGUuM=; b=f9Vk/G1k9iZ4KuXqai4cAdZH/Q8N9tIOWJKeO6nEK0PSau5clajLKA2/0GdTGOsdYF g8ePtKm/ETW1qXFBfdaaqoqZXVT7oU6hUCc3SvwUBJ71pNf5dvLBvVItYiMKUvwHnDf9 gkC21f5KdsqsEm+Eq6aj8VEWkmaYYcbbjpAuEFaFYNykXP9YEVOHYR9OH+VshnoIQ+mn yJHNrvikUgHSxVRwD5/1pBRKZd+/okL8Ia+SZWU2Jjyxuxv4h4nKD3aO91WzxCY/LbTk wUsLK9FBuuU5c3HgnrEzUUa/MR1cEFQ64KY0GW/XxcH11E63sU3kIZnYYyKzUeCeW9u3 Q54A== X-Forwarded-Encrypted: i=1; AJvYcCWgIrobYV926RsVhRQEBhhiELOg91HN+FjaFQ2nGxpbjZK1+cS+ewFvyoujIIDrN2gdhj6Wdd8SbFWiax0=@vger.kernel.org X-Gm-Message-State: AOJu0YxwSqwwbTW9TVDWqZRpZHUAD//AHoQLf4VN8klRfjGNBdDF0K9+ Vrr+OX5c/UCjzFeTLVyqZCabDanaePBuUBWwNjwh3M8C3qtTX3WPzMU= X-Gm-Gg: ATEYQzz1lUuka6wpH+Xh5U/4RoxVl3wUFoG2T9m52WAv8Abd+ZnTdMrqRSqhPLhqoBG MQrOPP8JbcV1vdMUwPXup4ZgV/21RllThrz4NR6zCVSyg+tzqrIiG5Q0++djAa1Er5aAR6puUQx JgsMJYS+t6bcjBCSRkFQRPX56dAACpHUpjuoZsjeN1NZIGhOSlIC1lUqu+e3LkvfMIdzlGNnXup yuypBxdSjUsQ9T38/4FZrKfbjAhilXUJPPlmezUmOI9BhKb33IsMNK7T/JEW6PCZEPJbwyAQFWA crq6StLeaBJVa9qhFOIW0RUCW3f7EEsjXJ7xo1UMM+sM66bCMxT10ykcbGh2rwdxqgNvMIFPwCK ZNdaYDqz4iM5x1JJYNK4IWobBNJsG1zUT1eWmFVVLXao8xkIVjm5tmr0OHV15hB4tk2z9ECGCcQ IEd3BXXLIYXh1MbaE+7ghOfcCba+QUNoZ8x9ocY0CFyNWx8D3hWZzvIAMWuqM9FQY2CszcJ3P5A c6Xp4RAPH6HtmN1NkI7OnzYMJ5f X-Received: by 2002:a05:7301:1691:b0:2bd:d3f3:b0be with SMTP id 5a478bee46e88-2c0e503eb7bmr2177414eec.20.1773846193273; Wed, 18 Mar 2026 08:03:13 -0700 (PDT) Received: from localhost (c-76-102-12-149.hsd1.ca.comcast.net. [76.102.12.149]) by smtp.gmail.com with ESMTPSA id 5a478bee46e88-2c0e5582dd5sm4001338eec.15.2026.03.18.08.03.12 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Wed, 18 Mar 2026 08:03:12 -0700 (PDT) From: Stanislav Fomichev To: netdev@vger.kernel.org Cc: davem@davemloft.net, edumazet@google.com, kuba@kernel.org, pabeni@redhat.com, horms@kernel.org, corbet@lwn.net, skhan@linuxfoundation.org, andrew+netdev@lunn.ch, michael.chan@broadcom.com, pavan.chebbi@broadcom.com, anthony.l.nguyen@intel.com, przemyslaw.kitszel@intel.com, saeedm@nvidia.com, tariqt@nvidia.com, mbloch@nvidia.com, alexanderduyck@fb.com, kernel-team@meta.com, johannes@sipsolutions.net, sd@queasysnail.net, jianbol@nvidia.com, dtatulea@nvidia.com, sdf@fomichev.me, mohsin.bashr@gmail.com, jacob.e.keller@intel.com, willemb@google.com, skhawaja@google.com, bestswngs@gmail.com, linux-doc@vger.kernel.org, linux-kernel@vger.kernel.org, intel-wired-lan@lists.osuosl.org, linux-rdma@vger.kernel.org, linux-wireless@vger.kernel.org, linux-kselftest@vger.kernel.org, leon@kernel.org Subject: [PATCH net-next v2 04/13] net: move promiscuity handling into dev_rx_mode_work Date: Wed, 18 Mar 2026 08:02:56 -0700 Message-ID: <20260318150305.123900-5-sdf@fomichev.me> X-Mailer: git-send-email 2.53.0 In-Reply-To: <20260318150305.123900-1-sdf@fomichev.me> References: <20260318150305.123900-1-sdf@fomichev.me> Precedence: bulk X-Mailing-List: linux-kernel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Content-Transfer-Encoding: quoted-printable Content-Type: text/plain; charset="utf-8" Move unicast promiscuity tracking into dev_rx_mode_work so it runs under netdev_ops_lock instead of under the addr_lock spinlock. This is required because __dev_set_promiscuity calls dev_change_rx_flags and __dev_notify_flags, both of which may need to sleep. Change ASSERT_RTNL() to netdev_ops_assert_locked() in __dev_set_promiscuity, netif_set_allmulti and __dev_change_flags since these are now called from the work queue under the ops lock. Signed-off-by: Stanislav Fomichev Reviewed-by: Aleksandr Loktionov --- Documentation/networking/netdevices.rst | 4 ++ net/core/dev.c | 79 +++++++++++++++++-------- 2 files changed, 57 insertions(+), 26 deletions(-) diff --git a/Documentation/networking/netdevices.rst b/Documentation/networ= king/netdevices.rst index dc83d78d3b27..5cdaa1a3dcc8 100644 --- a/Documentation/networking/netdevices.rst +++ b/Documentation/networking/netdevices.rst @@ -298,6 +298,10 @@ struct net_device synchronization rules Notes: Sleepable version of ndo_set_rx_mode. Receives snapshots of the unicast and multicast address lists. =20 +ndo_change_rx_flags: + Synchronization: rtnl_lock() semaphore. In addition, netdev instance + lock if the driver implements queue management or shaper API. + ndo_setup_tc: ``TC_SETUP_BLOCK`` and ``TC_SETUP_FT`` are running under NFT locks (i.e. no ``rtnl_lock`` and no device instance lock). The rest of diff --git a/net/core/dev.c b/net/core/dev.c index 77fdbe836754..d50d6dc6ac1f 100644 --- a/net/core/dev.c +++ b/net/core/dev.c @@ -9574,7 +9574,7 @@ static int __dev_set_promiscuity(struct net_device *d= ev, int inc, bool notify) kuid_t uid; kgid_t gid; =20 - ASSERT_RTNL(); + netdev_ops_assert_locked(dev); =20 promiscuity =3D dev->promiscuity + inc; if (promiscuity =3D=3D 0) { @@ -9610,16 +9610,8 @@ static int __dev_set_promiscuity(struct net_device *= dev, int inc, bool notify) =20 dev_change_rx_flags(dev, IFF_PROMISC); } - if (notify) { - /* The ops lock is only required to ensure consistent locking - * for `NETDEV_CHANGE` notifiers. This function is sometimes - * called without the lock, even for devices that are ops - * locked, such as in `dev_uc_sync_multiple` when using - * bonding or teaming. - */ - netdev_ops_assert_locked(dev); + if (notify) __dev_notify_flags(dev, old_flags, IFF_PROMISC, 0, NULL); - } return 0; } =20 @@ -9641,7 +9633,7 @@ int netif_set_allmulti(struct net_device *dev, int in= c, bool notify) unsigned int old_flags =3D dev->flags, old_gflags =3D dev->gflags; unsigned int allmulti, flags; =20 - ASSERT_RTNL(); + netdev_ops_assert_locked(dev); =20 allmulti =3D dev->allmulti + inc; if (allmulti =3D=3D 0) { @@ -9671,12 +9663,36 @@ int netif_set_allmulti(struct net_device *dev, int = inc, bool notify) return 0; } =20 +/** + * dev_uc_promisc_update() - evaluate whether uc_promisc should be toggled. + * @dev: device + * + * Must be called under netif_addr_lock_bh. + * Return: +1 to enter promisc, -1 to leave, 0 for no change. + */ +static int dev_uc_promisc_update(struct net_device *dev) +{ + if (dev->priv_flags & IFF_UNICAST_FLT) + return 0; + + if (!netdev_uc_empty(dev) && !dev->uc_promisc) { + dev->uc_promisc =3D true; + return 1; + } + if (netdev_uc_empty(dev) && dev->uc_promisc) { + dev->uc_promisc =3D false; + return -1; + } + return 0; +} + static void dev_rx_mode_work(struct work_struct *work) { struct net_device *dev =3D container_of(work, struct net_device, rx_mode_work); struct netdev_hw_addr_list uc_snap, mc_snap, uc_ref, mc_ref; const struct net_device_ops *ops =3D dev->netdev_ops; + int promisc_inc; int err; =20 __hw_addr_init(&uc_snap); @@ -9704,15 +9720,28 @@ static void dev_rx_mode_work(struct work_struct *wo= rk) if (!err) err =3D __hw_addr_list_snapshot(&mc_ref, &dev->mc, dev->addr_len); - netif_addr_unlock_bh(dev); =20 if (err) { __hw_addr_flush(&uc_snap); __hw_addr_flush(&uc_ref); __hw_addr_flush(&mc_snap); + netif_addr_unlock_bh(dev); goto out; } =20 + promisc_inc =3D dev_uc_promisc_update(dev); + + netif_addr_unlock_bh(dev); + } else { + netif_addr_lock_bh(dev); + promisc_inc =3D dev_uc_promisc_update(dev); + netif_addr_unlock_bh(dev); + } + + if (promisc_inc) + __dev_set_promiscuity(dev, promisc_inc, false); + + if (ops->ndo_set_rx_mode_async) { ops->ndo_set_rx_mode_async(dev, &uc_snap, &mc_snap); =20 netif_addr_lock_bh(dev); @@ -9721,6 +9750,10 @@ static void dev_rx_mode_work(struct work_struct *wor= k) __hw_addr_list_reconcile(&dev->mc, &mc_snap, &mc_ref, dev->addr_len); netif_addr_unlock_bh(dev); + } else if (ops->ndo_set_rx_mode) { + netif_addr_lock_bh(dev); + ops->ndo_set_rx_mode(dev); + netif_addr_unlock_bh(dev); } =20 out: @@ -9739,28 +9772,22 @@ static void dev_rx_mode_work(struct work_struct *wo= rk) void __dev_set_rx_mode(struct net_device *dev) { const struct net_device_ops *ops =3D dev->netdev_ops; + int promisc_inc; =20 /* dev_open will call this function so the list will stay sane. */ if (!netif_up_and_present(dev)) return; =20 - if (ops->ndo_set_rx_mode_async) { + if (ops->ndo_set_rx_mode_async || ops->ndo_change_rx_flags) { queue_work(rx_mode_wq, &dev->rx_mode_work); return; } =20 - if (!(dev->priv_flags & IFF_UNICAST_FLT)) { - /* Unicast addresses changes may only happen under the rtnl, - * therefore calling __dev_set_promiscuity here is safe. - */ - if (!netdev_uc_empty(dev) && !dev->uc_promisc) { - __dev_set_promiscuity(dev, 1, false); - dev->uc_promisc =3D true; - } else if (netdev_uc_empty(dev) && dev->uc_promisc) { - __dev_set_promiscuity(dev, -1, false); - dev->uc_promisc =3D false; - } - } + /* Legacy path for non-ops locked HW devices. */ + + promisc_inc =3D dev_uc_promisc_update(dev); + if (promisc_inc) + __dev_set_promiscuity(dev, promisc_inc, false); =20 if (ops->ndo_set_rx_mode) ops->ndo_set_rx_mode(dev); @@ -9810,7 +9837,7 @@ int __dev_change_flags(struct net_device *dev, unsign= ed int flags, unsigned int old_flags =3D dev->flags; int ret; =20 - ASSERT_RTNL(); + netdev_ops_assert_locked(dev); =20 /* * Set the flags on our device. --=20 2.53.0