Netdev List
 help / color / mirror / Atom feed
* [PATCH net-next 00/11] bridge: prepare lockless br_port_fill_attrs() (I)
@ 2026-05-21 13:19 Eric Dumazet
  2026-05-21 13:19 ` [PATCH net-next 01/11] bridge: add a READ_ONCE() in br_timer_value() Eric Dumazet
                   ` (11 more replies)
  0 siblings, 12 replies; 15+ messages in thread
From: Eric Dumazet @ 2026-05-21 13:19 UTC (permalink / raw)
  To: David S . Miller, Jakub Kicinski, Paolo Abeni
  Cc: Simon Horman, netdev, Ido Schimmel, Nikolay Aleksandrov,
	eric.dumazet, Eric Dumazet

medium-term goal is to allow "ip link show" dump commands to run without RTNL.

This round of patches adds/fixes some lockess accesses in bridge.

This is not complete, more patches will come later.

Ultimately all changes to p->flags should use set_bit()/clear_bit().

Eric Dumazet (11):
  bridge: add a READ_ONCE() in br_timer_value()
  bridge: add bridge_flags_bit enum
  bridge: use BR_PROMISC_BIT
  bridge: use BR_ADMIN_COST_BIT
  bridge: provide lockless access to p->path_cost
  bridge: provide lockless access to p->designated_cost
  bridge: provide lockless access to p->designated_port
  bridge: provide lockless access to p->priority
  bridge: provide lockless access to p->port_id
  bridge: provide lockless access to p->config_pending
  bridge: read p->flags once in br_port_fill_attrs()

 include/linux/if_bridge.h | 78 ++++++++++++++++++++++++++-------------
 net/bridge/br_if.c        |  8 ++--
 net/bridge/br_ioctl.c     | 10 ++---
 net/bridge/br_netlink.c   | 55 ++++++++++++++-------------
 net/bridge/br_private.h   |  2 +-
 net/bridge/br_stp.c       | 38 ++++++++++---------
 net/bridge/br_stp_if.c    | 16 ++++----
 net/bridge/br_stp_timer.c |  2 +-
 net/bridge/br_sysfs_if.c  | 12 +++---
 9 files changed, 128 insertions(+), 93 deletions(-)

-- 
2.54.0.669.g59709faab0-goog


^ permalink raw reply	[flat|nested] 15+ messages in thread

* [PATCH net-next 01/11] bridge: add a READ_ONCE() in br_timer_value()
  2026-05-21 13:19 [PATCH net-next 00/11] bridge: prepare lockless br_port_fill_attrs() (I) Eric Dumazet
@ 2026-05-21 13:19 ` Eric Dumazet
  2026-05-21 13:19 ` [PATCH net-next 02/11] bridge: add bridge_flags_bit enum Eric Dumazet
                   ` (10 subsequent siblings)
  11 siblings, 0 replies; 15+ messages in thread
From: Eric Dumazet @ 2026-05-21 13:19 UTC (permalink / raw)
  To: David S . Miller, Jakub Kicinski, Paolo Abeni
  Cc: Simon Horman, netdev, Ido Schimmel, Nikolay Aleksandrov,
	eric.dumazet, Eric Dumazet

br_timer_value() can be called locklessly, the expires field
could be changed concurrently.

Signed-off-by: Eric Dumazet <edumazet@google.com>
---
 net/bridge/br_stp_timer.c | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/net/bridge/br_stp_timer.c b/net/bridge/br_stp_timer.c
index e5d453305381baa34225a144ac99e98f2a62d810..83cc9c6a3943508eb94d20ddc1b7e737a58d7abb 100644
--- a/net/bridge/br_stp_timer.c
+++ b/net/bridge/br_stp_timer.c
@@ -160,5 +160,5 @@ void br_stp_port_timer_init(struct net_bridge_port *p)
 unsigned long br_timer_value(const struct timer_list *timer)
 {
 	return timer_pending(timer)
-		? jiffies_delta_to_clock_t(timer->expires - jiffies) : 0;
+		? jiffies_delta_to_clock_t(READ_ONCE(timer->expires) - jiffies) : 0;
 }
-- 
2.54.0.669.g59709faab0-goog


^ permalink raw reply related	[flat|nested] 15+ messages in thread

* [PATCH net-next 02/11] bridge: add bridge_flags_bit enum
  2026-05-21 13:19 [PATCH net-next 00/11] bridge: prepare lockless br_port_fill_attrs() (I) Eric Dumazet
  2026-05-21 13:19 ` [PATCH net-next 01/11] bridge: add a READ_ONCE() in br_timer_value() Eric Dumazet
@ 2026-05-21 13:19 ` Eric Dumazet
  2026-05-21 13:19 ` [PATCH net-next 03/11] bridge: use BR_PROMISC_BIT Eric Dumazet
                   ` (9 subsequent siblings)
  11 siblings, 0 replies; 15+ messages in thread
From: Eric Dumazet @ 2026-05-21 13:19 UTC (permalink / raw)
  To: David S . Miller, Jakub Kicinski, Paolo Abeni
  Cc: Simon Horman, netdev, Ido Schimmel, Nikolay Aleksandrov,
	eric.dumazet, Eric Dumazet

We want to use atomic operations for lockless p->flags changes
and reads.

Add definitions for bits in addition of masks so that we can use
test_bit(), clear_bit() and set_bit() in subsequent patches.

Signed-off-by: Eric Dumazet <edumazet@google.com>
---
 include/linux/if_bridge.h | 78 ++++++++++++++++++++++++++-------------
 1 file changed, 53 insertions(+), 25 deletions(-)

diff --git a/include/linux/if_bridge.h b/include/linux/if_bridge.h
index ec9ffea1e46ede3762f108f6e7085ebb1bf1d2e1..75673b8bffcb8ad6396e6a05b8af8150208fb6fe 100644
--- a/include/linux/if_bridge.h
+++ b/include/linux/if_bridge.h
@@ -36,32 +36,60 @@ struct br_ip_list {
 	struct br_ip addr;
 };
 
-#define BR_HAIRPIN_MODE		BIT(0)
-#define BR_BPDU_GUARD		BIT(1)
-#define BR_ROOT_BLOCK		BIT(2)
-#define BR_MULTICAST_FAST_LEAVE	BIT(3)
-#define BR_ADMIN_COST		BIT(4)
-#define BR_LEARNING		BIT(5)
-#define BR_FLOOD		BIT(6)
+enum bridge_flags_bit {
+	BR_HAIRPIN_MODE_BIT,
+	BR_BPDU_GUARD_BIT,
+	BR_ROOT_BLOCK_BIT,
+	BR_MULTICAST_FAST_LEAVE_BIT,
+	BR_ADMIN_COST_BIT,
+	BR_LEARNING_BIT,
+	BR_FLOOD_BIT,
+	BR_PROMISC_BIT,
+	BR_PROXYARP_BIT,
+	BR_LEARNING_SYNC_BIT,
+	BR_PROXYARP_WIFI_BIT,
+	BR_MCAST_FLOOD_BIT,
+	BR_MULTICAST_TO_UNICAST_BIT,
+	BR_VLAN_TUNNEL_BIT,
+	BR_BCAST_FLOOD_BIT,
+	BR_NEIGH_SUPPRESS_BIT,
+	BR_ISOLATED_BIT,
+	BR_MRP_AWARE_BIT,
+	BR_MRP_LOST_CONT_BIT,
+	BR_MRP_LOST_IN_CONT_BIT,
+	BR_TX_FWD_OFFLOAD_BIT,
+	BR_PORT_LOCKED_BIT,
+	BR_PORT_MAB_BIT,
+	BR_NEIGH_VLAN_SUPPRESS_BIT,
+	BR_NEIGH_FORWARD_GRAT_BIT,
+};
+
+#define BR_HAIRPIN_MODE		BIT(BR_HAIRPIN_MODE_BIT)
+#define BR_BPDU_GUARD		BIT(BR_BPDU_GUARD_BIT)
+#define BR_ROOT_BLOCK		BIT(BR_ROOT_BLOCK_BIT)
+#define BR_MULTICAST_FAST_LEAVE	BIT(BR_MULTICAST_FAST_LEAVE_BIT)
+#define BR_ADMIN_COST		BIT(BR_ADMIN_COST_BIT)
+#define BR_LEARNING		BIT(BR_LEARNING_BIT)
+#define BR_FLOOD		BIT(BR_FLOOD_BIT)
 #define BR_AUTO_MASK		(BR_FLOOD | BR_LEARNING)
-#define BR_PROMISC		BIT(7)
-#define BR_PROXYARP		BIT(8)
-#define BR_LEARNING_SYNC	BIT(9)
-#define BR_PROXYARP_WIFI	BIT(10)
-#define BR_MCAST_FLOOD		BIT(11)
-#define BR_MULTICAST_TO_UNICAST	BIT(12)
-#define BR_VLAN_TUNNEL		BIT(13)
-#define BR_BCAST_FLOOD		BIT(14)
-#define BR_NEIGH_SUPPRESS	BIT(15)
-#define BR_ISOLATED		BIT(16)
-#define BR_MRP_AWARE		BIT(17)
-#define BR_MRP_LOST_CONT	BIT(18)
-#define BR_MRP_LOST_IN_CONT	BIT(19)
-#define BR_TX_FWD_OFFLOAD	BIT(20)
-#define BR_PORT_LOCKED		BIT(21)
-#define BR_PORT_MAB		BIT(22)
-#define BR_NEIGH_VLAN_SUPPRESS	BIT(23)
-#define BR_NEIGH_FORWARD_GRAT	BIT(24)
+#define BR_PROMISC		BIT(BR_PROMISC_BIT)
+#define BR_PROXYARP		BIT(BR_PROXYARP_BIT)
+#define BR_LEARNING_SYNC	BIT(BR_LEARNING_SYNC_BIT)
+#define BR_PROXYARP_WIFI	BIT(BR_PROXYARP_WIFI_BIT)
+#define BR_MCAST_FLOOD		BIT(BR_MCAST_FLOOD_BIT)
+#define BR_MULTICAST_TO_UNICAST	BIT(BR_MULTICAST_TO_UNICAST_BIT)
+#define BR_VLAN_TUNNEL		BIT(BR_VLAN_TUNNEL_BIT)
+#define BR_BCAST_FLOOD		BIT(BR_BCAST_FLOOD_BIT)
+#define BR_NEIGH_SUPPRESS	BIT(BR_NEIGH_SUPPRESS_BIT)
+#define BR_ISOLATED		BIT(BR_ISOLATED_BIT)
+#define BR_MRP_AWARE		BIT(BR_MRP_AWARE_BIT)
+#define BR_MRP_LOST_CONT	BIT(BR_MRP_LOST_CONT_BIT)
+#define BR_MRP_LOST_IN_CONT	BIT(BR_MRP_LOST_IN_CONT_BIT)
+#define BR_TX_FWD_OFFLOAD	BIT(BR_TX_FWD_OFFLOAD_BIT)
+#define BR_PORT_LOCKED		BIT(BR_PORT_LOCKED_BIT)
+#define BR_PORT_MAB		BIT(BR_PORT_MAB_BIT)
+#define BR_NEIGH_VLAN_SUPPRESS	BIT(BR_NEIGH_VLAN_SUPPRESS_BIT)
+#define BR_NEIGH_FORWARD_GRAT	BIT(BR_NEIGH_FORWARD_GRAT_BIT)
 
 #define BR_DEFAULT_AGEING_TIME	(300 * HZ)
 
-- 
2.54.0.669.g59709faab0-goog


^ permalink raw reply related	[flat|nested] 15+ messages in thread

* [PATCH net-next 03/11] bridge: use BR_PROMISC_BIT
  2026-05-21 13:19 [PATCH net-next 00/11] bridge: prepare lockless br_port_fill_attrs() (I) Eric Dumazet
  2026-05-21 13:19 ` [PATCH net-next 01/11] bridge: add a READ_ONCE() in br_timer_value() Eric Dumazet
  2026-05-21 13:19 ` [PATCH net-next 02/11] bridge: add bridge_flags_bit enum Eric Dumazet
@ 2026-05-21 13:19 ` Eric Dumazet
  2026-05-21 13:19 ` [PATCH net-next 04/11] bridge: use BR_ADMIN_COST_BIT Eric Dumazet
                   ` (8 subsequent siblings)
  11 siblings, 0 replies; 15+ messages in thread
From: Eric Dumazet @ 2026-05-21 13:19 UTC (permalink / raw)
  To: David S . Miller, Jakub Kicinski, Paolo Abeni
  Cc: Simon Horman, netdev, Ido Schimmel, Nikolay Aleksandrov,
	eric.dumazet, Eric Dumazet

Use BR_PROMISC_BIT and set_bit(), clear_bit() and test_bit() lockless
functions.

Signed-off-by: Eric Dumazet <edumazet@google.com>
---
 net/bridge/br_if.c      | 4 ++--
 net/bridge/br_private.h | 2 +-
 2 files changed, 3 insertions(+), 3 deletions(-)

diff --git a/net/bridge/br_if.c b/net/bridge/br_if.c
index d39571e13744431f5e4c67f34ee7de34eb8bb6b0..3169fab686a534cf2a6458ff228eee2b6fc7e7e4 100644
--- a/net/bridge/br_if.c
+++ b/net/bridge/br_if.c
@@ -110,7 +110,7 @@ static void br_port_set_promisc(struct net_bridge_port *p)
 		return;
 
 	br_fdb_unsync_static(p->br, p);
-	p->flags |= BR_PROMISC;
+	set_bit(BR_PROMISC_BIT, &p->flags);
 }
 
 static void br_port_clear_promisc(struct net_bridge_port *p)
@@ -133,7 +133,7 @@ static void br_port_clear_promisc(struct net_bridge_port *p)
 		return;
 
 	dev_set_promiscuity(p->dev, -1);
-	p->flags &= ~BR_PROMISC;
+	clear_bit(BR_PROMISC_BIT, &p->flags);
 }
 
 /* When a port is added or removed or when certain port flags
diff --git a/net/bridge/br_private.h b/net/bridge/br_private.h
index 02671e648dac7ab6fd59b80e044f62b00a8e4a8a..d55ea9516e3e369bb9e0045fca5b8d034ef5a45f 100644
--- a/net/bridge/br_private.h
+++ b/net/bridge/br_private.h
@@ -452,7 +452,7 @@ struct net_bridge_port {
 #define kobj_to_brport(obj)	container_of(obj, struct net_bridge_port, kobj)
 
 #define br_auto_port(p) ((p)->flags & BR_AUTO_MASK)
-#define br_promisc_port(p) ((p)->flags & BR_PROMISC)
+#define br_promisc_port(p) test_bit(BR_PROMISC_BIT, &(p)->flags)
 
 static inline struct net_bridge_port *br_port_get_rcu(const struct net_device *dev)
 {
-- 
2.54.0.669.g59709faab0-goog


^ permalink raw reply related	[flat|nested] 15+ messages in thread

* [PATCH net-next 04/11] bridge: use BR_ADMIN_COST_BIT
  2026-05-21 13:19 [PATCH net-next 00/11] bridge: prepare lockless br_port_fill_attrs() (I) Eric Dumazet
                   ` (2 preceding siblings ...)
  2026-05-21 13:19 ` [PATCH net-next 03/11] bridge: use BR_PROMISC_BIT Eric Dumazet
@ 2026-05-21 13:19 ` Eric Dumazet
  2026-05-21 13:19 ` [PATCH net-next 05/11] bridge: provide lockless access to p->path_cost Eric Dumazet
                   ` (7 subsequent siblings)
  11 siblings, 0 replies; 15+ messages in thread
From: Eric Dumazet @ 2026-05-21 13:19 UTC (permalink / raw)
  To: David S . Miller, Jakub Kicinski, Paolo Abeni
  Cc: Simon Horman, netdev, Ido Schimmel, Nikolay Aleksandrov,
	eric.dumazet, Eric Dumazet

Use set_bit() and test_bit() lockless functions.

Signed-off-by: Eric Dumazet <edumazet@google.com>
---
 net/bridge/br_if.c     | 2 +-
 net/bridge/br_stp_if.c | 2 +-
 2 files changed, 2 insertions(+), 2 deletions(-)

diff --git a/net/bridge/br_if.c b/net/bridge/br_if.c
index 3169fab686a534cf2a6458ff228eee2b6fc7e7e4..0bd5cf925fa321b785e3578d6e99d8d7003fa89f 100644
--- a/net/bridge/br_if.c
+++ b/net/bridge/br_if.c
@@ -75,7 +75,7 @@ void br_port_carrier_check(struct net_bridge_port *p, bool *notified)
 	struct net_device *dev = p->dev;
 	struct net_bridge *br = p->br;
 
-	if (!(p->flags & BR_ADMIN_COST) &&
+	if (!test_bit(BR_ADMIN_COST_BIT, &p->flags) &&
 	    netif_running(dev) && netif_oper_up(dev))
 		p->path_cost = port_cost(dev);
 
diff --git a/net/bridge/br_stp_if.c b/net/bridge/br_stp_if.c
index 28c1d3f7e22f6e0a0edd8b3b3f501ea7acc31394..b29dc97b9ad8a5b5c56517d34fe426abd00e2ad6 100644
--- a/net/bridge/br_stp_if.c
+++ b/net/bridge/br_stp_if.c
@@ -340,7 +340,7 @@ int br_stp_set_path_cost(struct net_bridge_port *p, unsigned long path_cost)
 	    path_cost > BR_MAX_PATH_COST)
 		return -ERANGE;
 
-	p->flags |= BR_ADMIN_COST;
+	set_bit(BR_ADMIN_COST_BIT, &p->flags);
 	p->path_cost = path_cost;
 	br_configuration_update(p->br);
 	br_port_state_selection(p->br);
-- 
2.54.0.669.g59709faab0-goog


^ permalink raw reply related	[flat|nested] 15+ messages in thread

* [PATCH net-next 05/11] bridge: provide lockless access to p->path_cost
  2026-05-21 13:19 [PATCH net-next 00/11] bridge: prepare lockless br_port_fill_attrs() (I) Eric Dumazet
                   ` (3 preceding siblings ...)
  2026-05-21 13:19 ` [PATCH net-next 04/11] bridge: use BR_ADMIN_COST_BIT Eric Dumazet
@ 2026-05-21 13:19 ` Eric Dumazet
  2026-05-21 13:19 ` [PATCH net-next 06/11] bridge: provide lockless access to p->designated_cost Eric Dumazet
                   ` (6 subsequent siblings)
  11 siblings, 0 replies; 15+ messages in thread
From: Eric Dumazet @ 2026-05-21 13:19 UTC (permalink / raw)
  To: David S . Miller, Jakub Kicinski, Paolo Abeni
  Cc: Simon Horman, netdev, Ido Schimmel, Nikolay Aleksandrov,
	eric.dumazet, Eric Dumazet

Add READ_ONCE()/WRITE_ONCE() annotations around p->path_cost.

This is needed at least for sysfs show_path_cost(), BRCTL_GET_PORT_INFO
and upcoming RTNL avoidance in "ip link" dumps (cf br_port_fill_attrs()).

Signed-off-by: Eric Dumazet <edumazet@google.com>
---
 net/bridge/br_if.c       |  2 +-
 net/bridge/br_ioctl.c    |  2 +-
 net/bridge/br_netlink.c  |  2 +-
 net/bridge/br_stp.c      | 12 +++++++-----
 net/bridge/br_stp_if.c   |  2 +-
 net/bridge/br_sysfs_if.c |  2 +-
 6 files changed, 12 insertions(+), 10 deletions(-)

diff --git a/net/bridge/br_if.c b/net/bridge/br_if.c
index 0bd5cf925fa321b785e3578d6e99d8d7003fa89f..ab012e4762998fe8a133dd551e7f4f0efc6718c6 100644
--- a/net/bridge/br_if.c
+++ b/net/bridge/br_if.c
@@ -77,7 +77,7 @@ void br_port_carrier_check(struct net_bridge_port *p, bool *notified)
 
 	if (!test_bit(BR_ADMIN_COST_BIT, &p->flags) &&
 	    netif_running(dev) && netif_oper_up(dev))
-		p->path_cost = port_cost(dev);
+		WRITE_ONCE(p->path_cost, port_cost(dev));
 
 	*notified = false;
 	if (!netif_running(br->dev))
diff --git a/net/bridge/br_ioctl.c b/net/bridge/br_ioctl.c
index 766c43b327af830a80fba11c940ba34eb03c50c9..07cfcb821e27ebcb72901a365a3f06491f8b0bc3 100644
--- a/net/bridge/br_ioctl.c
+++ b/net/bridge/br_ioctl.c
@@ -259,7 +259,7 @@ int br_dev_siocdevprivate(struct net_device *dev, struct ifreq *rq,
 		memcpy(&p.designated_bridge, &pt->designated_bridge, 8);
 		p.port_id = pt->port_id;
 		p.designated_port = pt->designated_port;
-		p.path_cost = pt->path_cost;
+		p.path_cost = READ_ONCE(pt->path_cost);
 		p.designated_cost = pt->designated_cost;
 		p.state = pt->state;
 		p.top_change_ack = pt->topology_change_ack;
diff --git a/net/bridge/br_netlink.c b/net/bridge/br_netlink.c
index 898326c201ef99a1dafda820bfbfe3d428ae2bd3..1b2fbb3a8f9b18ef6479bd3a0c63fe1e761df9a7 100644
--- a/net/bridge/br_netlink.c
+++ b/net/bridge/br_netlink.c
@@ -240,7 +240,7 @@ static int br_port_fill_attrs(struct sk_buff *skb,
 
 	if (nla_put_u8(skb, IFLA_BRPORT_STATE, p->state) ||
 	    nla_put_u16(skb, IFLA_BRPORT_PRIORITY, p->priority) ||
-	    nla_put_u32(skb, IFLA_BRPORT_COST, p->path_cost) ||
+	    nla_put_u32(skb, IFLA_BRPORT_COST, READ_ONCE(p->path_cost)) ||
 	    nla_put_u8(skb, IFLA_BRPORT_MODE, mode) ||
 	    nla_put_u8(skb, IFLA_BRPORT_GUARD, !!(p->flags & BR_BPDU_GUARD)) ||
 	    nla_put_u8(skb, IFLA_BRPORT_PROTECT,
diff --git a/net/bridge/br_stp.c b/net/bridge/br_stp.c
index 024210f95468308066827ac2ae71f68f99fa77f5..1367cd3ac4dd6a587d4a6471184453a14af6879c 100644
--- a/net/bridge/br_stp.c
+++ b/net/bridge/br_stp.c
@@ -125,11 +125,12 @@ static int br_should_become_root_port(const struct net_bridge_port *p,
 	else if (t > 0)
 		return 0;
 
-	if (p->designated_cost + p->path_cost <
-	    rp->designated_cost + rp->path_cost)
+	t = p->designated_cost + READ_ONCE(p->path_cost) -
+	    (rp->designated_cost + READ_ONCE(rp->path_cost));
+
+	if (t < 0)
 		return 1;
-	else if (p->designated_cost + p->path_cost >
-		 rp->designated_cost + rp->path_cost)
+	else if (t > 0)
 		return 0;
 
 	t = memcmp(&p->designated_bridge, &rp->designated_bridge, 8);
@@ -187,7 +188,8 @@ static void br_root_selection(struct net_bridge *br)
 	} else {
 		p = br_get_port(br, root_port);
 		br->designated_root = p->designated_root;
-		br->root_path_cost = p->designated_cost + p->path_cost;
+		br->root_path_cost = p->designated_cost +
+				     READ_ONCE(p->path_cost);
 	}
 }
 
diff --git a/net/bridge/br_stp_if.c b/net/bridge/br_stp_if.c
index b29dc97b9ad8a5b5c56517d34fe426abd00e2ad6..e5d43492d2dcf0615ee984bc190d7ce2264aaab0 100644
--- a/net/bridge/br_stp_if.c
+++ b/net/bridge/br_stp_if.c
@@ -341,7 +341,7 @@ int br_stp_set_path_cost(struct net_bridge_port *p, unsigned long path_cost)
 		return -ERANGE;
 
 	set_bit(BR_ADMIN_COST_BIT, &p->flags);
-	p->path_cost = path_cost;
+	WRITE_ONCE(p->path_cost, path_cost);
 	br_configuration_update(p->br);
 	br_port_state_selection(p->br);
 	return 0;
diff --git a/net/bridge/br_sysfs_if.c b/net/bridge/br_sysfs_if.c
index 1f57c36a7fc097d69cbb8bd7a9348c31be6611aa..0616036a3ce45d45ba817555362f1613f5f9d6cf 100644
--- a/net/bridge/br_sysfs_if.c
+++ b/net/bridge/br_sysfs_if.c
@@ -83,7 +83,7 @@ static int store_flag(struct net_bridge_port *p, unsigned long v,
 
 static ssize_t show_path_cost(struct net_bridge_port *p, char *buf)
 {
-	return sysfs_emit(buf, "%d\n", p->path_cost);
+	return sysfs_emit(buf, "%d\n", READ_ONCE(p->path_cost));
 }
 
 static BRPORT_ATTR(path_cost, 0644,
-- 
2.54.0.669.g59709faab0-goog


^ permalink raw reply related	[flat|nested] 15+ messages in thread

* [PATCH net-next 06/11] bridge: provide lockless access to p->designated_cost
  2026-05-21 13:19 [PATCH net-next 00/11] bridge: prepare lockless br_port_fill_attrs() (I) Eric Dumazet
                   ` (4 preceding siblings ...)
  2026-05-21 13:19 ` [PATCH net-next 05/11] bridge: provide lockless access to p->path_cost Eric Dumazet
@ 2026-05-21 13:19 ` Eric Dumazet
  2026-05-21 13:19 ` [PATCH net-next 07/11] bridge: provide lockless access to p->designated_port Eric Dumazet
                   ` (5 subsequent siblings)
  11 siblings, 0 replies; 15+ messages in thread
From: Eric Dumazet @ 2026-05-21 13:19 UTC (permalink / raw)
  To: David S . Miller, Jakub Kicinski, Paolo Abeni
  Cc: Simon Horman, netdev, Ido Schimmel, Nikolay Aleksandrov,
	eric.dumazet, Eric Dumazet

Add READ_ONCE()/WRITE_ONCE() annotations around p->designated_cost

This is needed at least for sysfs show_designated_cost(), BRCTL_GET_PORT_INFO
and upcoming RTNL avoidance in "ip link" dumps (cf br_port_fill_attrs()).

Signed-off-by: Eric Dumazet <edumazet@google.com>
---
 net/bridge/br_ioctl.c    |  2 +-
 net/bridge/br_netlink.c  |  3 ++-
 net/bridge/br_stp.c      | 20 +++++++++++---------
 net/bridge/br_sysfs_if.c |  2 +-
 4 files changed, 15 insertions(+), 12 deletions(-)

diff --git a/net/bridge/br_ioctl.c b/net/bridge/br_ioctl.c
index 07cfcb821e27ebcb72901a365a3f06491f8b0bc3..a507c7b369ac49803019cdca7836c7fb9ef4459e 100644
--- a/net/bridge/br_ioctl.c
+++ b/net/bridge/br_ioctl.c
@@ -260,7 +260,7 @@ int br_dev_siocdevprivate(struct net_device *dev, struct ifreq *rq,
 		p.port_id = pt->port_id;
 		p.designated_port = pt->designated_port;
 		p.path_cost = READ_ONCE(pt->path_cost);
-		p.designated_cost = pt->designated_cost;
+		p.designated_cost = READ_ONCE(pt->designated_cost);
 		p.state = pt->state;
 		p.top_change_ack = pt->topology_change_ack;
 		p.config_pending = pt->config_pending;
diff --git a/net/bridge/br_netlink.c b/net/bridge/br_netlink.c
index 1b2fbb3a8f9b18ef6479bd3a0c63fe1e761df9a7..153e1cb0fbb6ea9f65933d884b9a78f5446d0de6 100644
--- a/net/bridge/br_netlink.c
+++ b/net/bridge/br_netlink.c
@@ -264,7 +264,8 @@ static int br_port_fill_attrs(struct sk_buff *skb,
 	    nla_put(skb, IFLA_BRPORT_BRIDGE_ID, sizeof(struct ifla_bridge_id),
 		    &p->designated_bridge) ||
 	    nla_put_u16(skb, IFLA_BRPORT_DESIGNATED_PORT, p->designated_port) ||
-	    nla_put_u16(skb, IFLA_BRPORT_DESIGNATED_COST, p->designated_cost) ||
+	    nla_put_u16(skb, IFLA_BRPORT_DESIGNATED_COST,
+			READ_ONCE(p->designated_cost)) ||
 	    nla_put_u16(skb, IFLA_BRPORT_ID, p->port_id) ||
 	    nla_put_u16(skb, IFLA_BRPORT_NO, p->port_no) ||
 	    nla_put_u8(skb, IFLA_BRPORT_TOPOLOGY_CHANGE_ACK,
diff --git a/net/bridge/br_stp.c b/net/bridge/br_stp.c
index 1367cd3ac4dd6a587d4a6471184453a14af6879c..62dcac1a181c829e2736d7ab8679c870ee676a71 100644
--- a/net/bridge/br_stp.c
+++ b/net/bridge/br_stp.c
@@ -125,8 +125,8 @@ static int br_should_become_root_port(const struct net_bridge_port *p,
 	else if (t > 0)
 		return 0;
 
-	t = p->designated_cost + READ_ONCE(p->path_cost) -
-	    (rp->designated_cost + READ_ONCE(rp->path_cost));
+	t = READ_ONCE(p->designated_cost) + READ_ONCE(p->path_cost) -
+	    (READ_ONCE(rp->designated_cost) + READ_ONCE(rp->path_cost));
 
 	if (t < 0)
 		return 1;
@@ -188,7 +188,7 @@ static void br_root_selection(struct net_bridge *br)
 	} else {
 		p = br_get_port(br, root_port);
 		br->designated_root = p->designated_root;
-		br->root_path_cost = p->designated_cost +
+		br->root_path_cost = READ_ONCE(p->designated_cost) +
 				     READ_ONCE(p->path_cost);
 	}
 }
@@ -254,7 +254,7 @@ static void br_record_config_information(struct net_bridge_port *p,
 					 const struct br_config_bpdu *bpdu)
 {
 	p->designated_root = bpdu->root;
-	p->designated_cost = bpdu->root_path_cost;
+	WRITE_ONCE(p->designated_cost, bpdu->root_path_cost);
 	p->designated_bridge = bpdu->bridge_id;
 	p->designated_port = bpdu->port_id;
 	p->designated_age = jiffies - bpdu->message_age;
@@ -299,9 +299,10 @@ static int br_should_become_designated_port(const struct net_bridge_port *p)
 	if (memcmp(&p->designated_root, &br->designated_root, 8))
 		return 1;
 
-	if (br->root_path_cost < p->designated_cost)
+	t = br->root_path_cost - READ_ONCE(p->designated_cost);
+	if (t < 0)
 		return 1;
-	else if (br->root_path_cost > p->designated_cost)
+	else if (t > 0)
 		return 0;
 
 	t = memcmp(&br->bridge_id, &p->designated_bridge, 8);
@@ -341,9 +342,10 @@ static int br_supersedes_port_info(const struct net_bridge_port *p,
 	else if (t > 0)
 		return 0;
 
-	if (bpdu->root_path_cost < p->designated_cost)
+	t = bpdu->root_path_cost < READ_ONCE(p->designated_cost);
+	if (t < 0)
 		return 1;
-	else if (bpdu->root_path_cost > p->designated_cost)
+	else if (t > 0)
 		return 0;
 
 	t = memcmp(&bpdu->bridge_id, &p->designated_bridge, 8);
@@ -423,7 +425,7 @@ void br_become_designated_port(struct net_bridge_port *p)
 
 	br = p->br;
 	p->designated_root = br->designated_root;
-	p->designated_cost = br->root_path_cost;
+	WRITE_ONCE(p->designated_cost, br->root_path_cost);
 	p->designated_bridge = br->bridge_id;
 	p->designated_port = p->port_id;
 }
diff --git a/net/bridge/br_sysfs_if.c b/net/bridge/br_sysfs_if.c
index 0616036a3ce45d45ba817555362f1613f5f9d6cf..9d560482e558aa1ef4d2f583373f15ae5db8a0f0 100644
--- a/net/bridge/br_sysfs_if.c
+++ b/net/bridge/br_sysfs_if.c
@@ -117,7 +117,7 @@ static BRPORT_ATTR(designated_port, 0444, show_designated_port, NULL);
 
 static ssize_t show_designated_cost(struct net_bridge_port *p, char *buf)
 {
-	return sysfs_emit(buf, "%d\n", p->designated_cost);
+	return sysfs_emit(buf, "%d\n", READ_ONCE(p->designated_cost));
 }
 static BRPORT_ATTR(designated_cost, 0444, show_designated_cost, NULL);
 
-- 
2.54.0.669.g59709faab0-goog


^ permalink raw reply related	[flat|nested] 15+ messages in thread

* [PATCH net-next 07/11] bridge: provide lockless access to p->designated_port
  2026-05-21 13:19 [PATCH net-next 00/11] bridge: prepare lockless br_port_fill_attrs() (I) Eric Dumazet
                   ` (5 preceding siblings ...)
  2026-05-21 13:19 ` [PATCH net-next 06/11] bridge: provide lockless access to p->designated_cost Eric Dumazet
@ 2026-05-21 13:19 ` Eric Dumazet
  2026-05-21 13:19 ` [PATCH net-next 08/11] bridge: provide lockless access to p->priority Eric Dumazet
                   ` (4 subsequent siblings)
  11 siblings, 0 replies; 15+ messages in thread
From: Eric Dumazet @ 2026-05-21 13:19 UTC (permalink / raw)
  To: David S . Miller, Jakub Kicinski, Paolo Abeni
  Cc: Simon Horman, netdev, Ido Schimmel, Nikolay Aleksandrov,
	eric.dumazet, Eric Dumazet

Add READ_ONCE()/WRITE_ONCE() annotations around p->designated_cost

This is needed at least for sysfs show_designated_port(), BRCTL_GET_PORT_INFO
and upcoming RTNL avoidance in "ip link" dumps (cf br_port_fill_attrs()).

Signed-off-by: Eric Dumazet <edumazet@google.com>
---
 net/bridge/br_ioctl.c    | 2 +-
 net/bridge/br_netlink.c  | 3 ++-
 net/bridge/br_stp.c      | 4 ++--
 net/bridge/br_stp_if.c   | 2 +-
 net/bridge/br_sysfs_if.c | 2 +-
 5 files changed, 7 insertions(+), 6 deletions(-)

diff --git a/net/bridge/br_ioctl.c b/net/bridge/br_ioctl.c
index a507c7b369ac49803019cdca7836c7fb9ef4459e..2be802991f70ab3ce48ade5da6d1488e072dbec6 100644
--- a/net/bridge/br_ioctl.c
+++ b/net/bridge/br_ioctl.c
@@ -258,7 +258,7 @@ int br_dev_siocdevprivate(struct net_device *dev, struct ifreq *rq,
 		memcpy(&p.designated_root, &pt->designated_root, 8);
 		memcpy(&p.designated_bridge, &pt->designated_bridge, 8);
 		p.port_id = pt->port_id;
-		p.designated_port = pt->designated_port;
+		p.designated_port = READ_ONCE(pt->designated_port);
 		p.path_cost = READ_ONCE(pt->path_cost);
 		p.designated_cost = READ_ONCE(pt->designated_cost);
 		p.state = pt->state;
diff --git a/net/bridge/br_netlink.c b/net/bridge/br_netlink.c
index 153e1cb0fbb6ea9f65933d884b9a78f5446d0de6..3c10125cfa6e703dec609a63940632b9b206d132 100644
--- a/net/bridge/br_netlink.c
+++ b/net/bridge/br_netlink.c
@@ -263,7 +263,8 @@ static int br_port_fill_attrs(struct sk_buff *skb,
 		    &p->designated_root) ||
 	    nla_put(skb, IFLA_BRPORT_BRIDGE_ID, sizeof(struct ifla_bridge_id),
 		    &p->designated_bridge) ||
-	    nla_put_u16(skb, IFLA_BRPORT_DESIGNATED_PORT, p->designated_port) ||
+	    nla_put_u16(skb, IFLA_BRPORT_DESIGNATED_PORT,
+			READ_ONCE(p->designated_port)) ||
 	    nla_put_u16(skb, IFLA_BRPORT_DESIGNATED_COST,
 			READ_ONCE(p->designated_cost)) ||
 	    nla_put_u16(skb, IFLA_BRPORT_ID, p->port_id) ||
diff --git a/net/bridge/br_stp.c b/net/bridge/br_stp.c
index 62dcac1a181c829e2736d7ab8679c870ee676a71..4c364a7f0f53f4f9360887b93bfbc592c738e311 100644
--- a/net/bridge/br_stp.c
+++ b/net/bridge/br_stp.c
@@ -256,7 +256,7 @@ static void br_record_config_information(struct net_bridge_port *p,
 	p->designated_root = bpdu->root;
 	WRITE_ONCE(p->designated_cost, bpdu->root_path_cost);
 	p->designated_bridge = bpdu->bridge_id;
-	p->designated_port = bpdu->port_id;
+	WRITE_ONCE(p->designated_port, bpdu->port_id);
 	p->designated_age = jiffies - bpdu->message_age;
 
 	mod_timer(&p->message_age_timer, jiffies
@@ -427,7 +427,7 @@ void br_become_designated_port(struct net_bridge_port *p)
 	p->designated_root = br->designated_root;
 	WRITE_ONCE(p->designated_cost, br->root_path_cost);
 	p->designated_bridge = br->bridge_id;
-	p->designated_port = p->port_id;
+	WRITE_ONCE(p->designated_port, p->port_id);
 }
 
 
diff --git a/net/bridge/br_stp_if.c b/net/bridge/br_stp_if.c
index e5d43492d2dcf0615ee984bc190d7ce2264aaab0..7b0d1a334785047905a00694fd65e3212b160e5d 100644
--- a/net/bridge/br_stp_if.c
+++ b/net/bridge/br_stp_if.c
@@ -320,7 +320,7 @@ int br_stp_set_port_priority(struct net_bridge_port *p, unsigned long newprio)
 
 	new_port_id = br_make_port_id(newprio, p->port_no);
 	if (br_is_designated_port(p))
-		p->designated_port = new_port_id;
+		WRITE_ONCE(p->designated_port, new_port_id);
 
 	p->port_id = new_port_id;
 	p->priority = newprio;
diff --git a/net/bridge/br_sysfs_if.c b/net/bridge/br_sysfs_if.c
index 9d560482e558aa1ef4d2f583373f15ae5db8a0f0..23ea003d72f413b1164496c3055832ab49197d4d 100644
--- a/net/bridge/br_sysfs_if.c
+++ b/net/bridge/br_sysfs_if.c
@@ -111,7 +111,7 @@ static BRPORT_ATTR(designated_bridge, 0444, show_designated_bridge, NULL);
 
 static ssize_t show_designated_port(struct net_bridge_port *p, char *buf)
 {
-	return sysfs_emit(buf, "%d\n", p->designated_port);
+	return sysfs_emit(buf, "%d\n", READ_ONCE(p->designated_port));
 }
 static BRPORT_ATTR(designated_port, 0444, show_designated_port, NULL);
 
-- 
2.54.0.669.g59709faab0-goog


^ permalink raw reply related	[flat|nested] 15+ messages in thread

* [PATCH net-next 08/11] bridge: provide lockless access to p->priority
  2026-05-21 13:19 [PATCH net-next 00/11] bridge: prepare lockless br_port_fill_attrs() (I) Eric Dumazet
                   ` (6 preceding siblings ...)
  2026-05-21 13:19 ` [PATCH net-next 07/11] bridge: provide lockless access to p->designated_port Eric Dumazet
@ 2026-05-21 13:19 ` Eric Dumazet
  2026-05-21 13:19 ` [PATCH net-next 09/11] bridge: provide lockless access to p->port_id Eric Dumazet
                   ` (3 subsequent siblings)
  11 siblings, 0 replies; 15+ messages in thread
From: Eric Dumazet @ 2026-05-21 13:19 UTC (permalink / raw)
  To: David S . Miller, Jakub Kicinski, Paolo Abeni
  Cc: Simon Horman, netdev, Ido Schimmel, Nikolay Aleksandrov,
	eric.dumazet, Eric Dumazet

sysfs show_priority() needs this.

Also br_port_fill_attrs() might in the future run without RTNL.

Signed-off-by: Eric Dumazet <edumazet@google.com>
---
 net/bridge/br_netlink.c  | 2 +-
 net/bridge/br_stp_if.c   | 2 +-
 net/bridge/br_sysfs_if.c | 2 +-
 3 files changed, 3 insertions(+), 3 deletions(-)

diff --git a/net/bridge/br_netlink.c b/net/bridge/br_netlink.c
index 3c10125cfa6e703dec609a63940632b9b206d132..30e253ca8d0b1ec9126e576629ade5211ab066ca 100644
--- a/net/bridge/br_netlink.c
+++ b/net/bridge/br_netlink.c
@@ -239,7 +239,7 @@ static int br_port_fill_attrs(struct sk_buff *skb,
 	u64 timerval;
 
 	if (nla_put_u8(skb, IFLA_BRPORT_STATE, p->state) ||
-	    nla_put_u16(skb, IFLA_BRPORT_PRIORITY, p->priority) ||
+	    nla_put_u16(skb, IFLA_BRPORT_PRIORITY, READ_ONCE(p->priority)) ||
 	    nla_put_u32(skb, IFLA_BRPORT_COST, READ_ONCE(p->path_cost)) ||
 	    nla_put_u8(skb, IFLA_BRPORT_MODE, mode) ||
 	    nla_put_u8(skb, IFLA_BRPORT_GUARD, !!(p->flags & BR_BPDU_GUARD)) ||
diff --git a/net/bridge/br_stp_if.c b/net/bridge/br_stp_if.c
index 7b0d1a334785047905a00694fd65e3212b160e5d..3524bb7e87f0586774a883720be9fa8eb60f0370 100644
--- a/net/bridge/br_stp_if.c
+++ b/net/bridge/br_stp_if.c
@@ -323,7 +323,7 @@ int br_stp_set_port_priority(struct net_bridge_port *p, unsigned long newprio)
 		WRITE_ONCE(p->designated_port, new_port_id);
 
 	p->port_id = new_port_id;
-	p->priority = newprio;
+	WRITE_ONCE(p->priority, newprio);
 	if (!memcmp(&p->br->bridge_id, &p->designated_bridge, 8) &&
 	    p->port_id < p->designated_port) {
 		br_become_designated_port(p);
diff --git a/net/bridge/br_sysfs_if.c b/net/bridge/br_sysfs_if.c
index 23ea003d72f413b1164496c3055832ab49197d4d..7c55f78237d9e421ac9c3e64d71cc021ca75d1c7 100644
--- a/net/bridge/br_sysfs_if.c
+++ b/net/bridge/br_sysfs_if.c
@@ -91,7 +91,7 @@ static BRPORT_ATTR(path_cost, 0644,
 
 static ssize_t show_priority(struct net_bridge_port *p, char *buf)
 {
-	return sysfs_emit(buf, "%d\n", p->priority);
+	return sysfs_emit(buf, "%d\n", READ_ONCE(p->priority));
 }
 
 static BRPORT_ATTR(priority, 0644,
-- 
2.54.0.669.g59709faab0-goog


^ permalink raw reply related	[flat|nested] 15+ messages in thread

* [PATCH net-next 09/11] bridge: provide lockless access to p->port_id
  2026-05-21 13:19 [PATCH net-next 00/11] bridge: prepare lockless br_port_fill_attrs() (I) Eric Dumazet
                   ` (7 preceding siblings ...)
  2026-05-21 13:19 ` [PATCH net-next 08/11] bridge: provide lockless access to p->priority Eric Dumazet
@ 2026-05-21 13:19 ` Eric Dumazet
  2026-05-21 13:19 ` [PATCH net-next 10/11] bridge: provide lockless access to p->config_pending Eric Dumazet
                   ` (2 subsequent siblings)
  11 siblings, 0 replies; 15+ messages in thread
From: Eric Dumazet @ 2026-05-21 13:19 UTC (permalink / raw)
  To: David S . Miller, Jakub Kicinski, Paolo Abeni
  Cc: Simon Horman, netdev, Ido Schimmel, Nikolay Aleksandrov,
	eric.dumazet, Eric Dumazet

sysfs show_port_id() and BRCTL_GET_PORT_INFO need this.

This will be needed for upcoming RTNL avoidance in "ip link"
dumps (cf br_port_fill_attrs()).

Signed-off-by: Eric Dumazet <edumazet@google.com>
---
 net/bridge/br_ioctl.c    | 2 +-
 net/bridge/br_netlink.c  | 2 +-
 net/bridge/br_stp_if.c   | 4 ++--
 net/bridge/br_sysfs_if.c | 2 +-
 4 files changed, 5 insertions(+), 5 deletions(-)

diff --git a/net/bridge/br_ioctl.c b/net/bridge/br_ioctl.c
index 2be802991f70ab3ce48ade5da6d1488e072dbec6..a017374c6e659498d98c6af3f8d8e46a8b93570e 100644
--- a/net/bridge/br_ioctl.c
+++ b/net/bridge/br_ioctl.c
@@ -257,7 +257,7 @@ int br_dev_siocdevprivate(struct net_device *dev, struct ifreq *rq,
 		memset(&p, 0, sizeof(struct __port_info));
 		memcpy(&p.designated_root, &pt->designated_root, 8);
 		memcpy(&p.designated_bridge, &pt->designated_bridge, 8);
-		p.port_id = pt->port_id;
+		p.port_id = READ_ONCE(pt->port_id);
 		p.designated_port = READ_ONCE(pt->designated_port);
 		p.path_cost = READ_ONCE(pt->path_cost);
 		p.designated_cost = READ_ONCE(pt->designated_cost);
diff --git a/net/bridge/br_netlink.c b/net/bridge/br_netlink.c
index 30e253ca8d0b1ec9126e576629ade5211ab066ca..7b039994d6a2df00a2fc8ca50e45e7db4f392fa7 100644
--- a/net/bridge/br_netlink.c
+++ b/net/bridge/br_netlink.c
@@ -267,7 +267,7 @@ static int br_port_fill_attrs(struct sk_buff *skb,
 			READ_ONCE(p->designated_port)) ||
 	    nla_put_u16(skb, IFLA_BRPORT_DESIGNATED_COST,
 			READ_ONCE(p->designated_cost)) ||
-	    nla_put_u16(skb, IFLA_BRPORT_ID, p->port_id) ||
+	    nla_put_u16(skb, IFLA_BRPORT_ID, READ_ONCE(p->port_id)) ||
 	    nla_put_u16(skb, IFLA_BRPORT_NO, p->port_no) ||
 	    nla_put_u8(skb, IFLA_BRPORT_TOPOLOGY_CHANGE_ACK,
 		       p->topology_change_ack) ||
diff --git a/net/bridge/br_stp_if.c b/net/bridge/br_stp_if.c
index 3524bb7e87f0586774a883720be9fa8eb60f0370..8a418f6af423ccba88fae57d2254e35e1ae4a1a0 100644
--- a/net/bridge/br_stp_if.c
+++ b/net/bridge/br_stp_if.c
@@ -34,7 +34,7 @@ void br_init_port(struct net_bridge_port *p)
 {
 	int err;
 
-	p->port_id = br_make_port_id(p->priority, p->port_no);
+	WRITE_ONCE(p->port_id, br_make_port_id(p->priority, p->port_no));
 	br_become_designated_port(p);
 	br_set_state(p, BR_STATE_BLOCKING);
 	p->topology_change_ack = 0;
@@ -322,7 +322,7 @@ int br_stp_set_port_priority(struct net_bridge_port *p, unsigned long newprio)
 	if (br_is_designated_port(p))
 		WRITE_ONCE(p->designated_port, new_port_id);
 
-	p->port_id = new_port_id;
+	WRITE_ONCE(p->port_id, new_port_id);
 	WRITE_ONCE(p->priority, newprio);
 	if (!memcmp(&p->br->bridge_id, &p->designated_bridge, 8) &&
 	    p->port_id < p->designated_port) {
diff --git a/net/bridge/br_sysfs_if.c b/net/bridge/br_sysfs_if.c
index 7c55f78237d9e421ac9c3e64d71cc021ca75d1c7..af17f62e95aaff320f8407aa7b50244573ecdc00 100644
--- a/net/bridge/br_sysfs_if.c
+++ b/net/bridge/br_sysfs_if.c
@@ -123,7 +123,7 @@ static BRPORT_ATTR(designated_cost, 0444, show_designated_cost, NULL);
 
 static ssize_t show_port_id(struct net_bridge_port *p, char *buf)
 {
-	return sysfs_emit(buf, "0x%x\n", p->port_id);
+	return sysfs_emit(buf, "0x%x\n", READ_ONCE(p->port_id));
 }
 static BRPORT_ATTR(port_id, 0444, show_port_id, NULL);
 
-- 
2.54.0.669.g59709faab0-goog


^ permalink raw reply related	[flat|nested] 15+ messages in thread

* [PATCH net-next 10/11] bridge: provide lockless access to p->config_pending
  2026-05-21 13:19 [PATCH net-next 00/11] bridge: prepare lockless br_port_fill_attrs() (I) Eric Dumazet
                   ` (8 preceding siblings ...)
  2026-05-21 13:19 ` [PATCH net-next 09/11] bridge: provide lockless access to p->port_id Eric Dumazet
@ 2026-05-21 13:19 ` Eric Dumazet
  2026-05-21 13:19 ` [PATCH net-next 11/11] bridge: read p->flags once in br_port_fill_attrs() Eric Dumazet
  2026-05-22  8:45 ` [PATCH net-next 00/11] bridge: prepare lockless br_port_fill_attrs() (I) Ido Schimmel
  11 siblings, 0 replies; 15+ messages in thread
From: Eric Dumazet @ 2026-05-21 13:19 UTC (permalink / raw)
  To: David S . Miller, Jakub Kicinski, Paolo Abeni
  Cc: Simon Horman, netdev, Ido Schimmel, Nikolay Aleksandrov,
	eric.dumazet, Eric Dumazet

Needed for sysfs show_config_pending(), BRCTL_GET_PORT_INFO
and upcoming RTNL avoidance in "ip link" dumps (cf br_port_fill_attrs()).

Signed-off-by: Eric Dumazet <edumazet@google.com>
---
 net/bridge/br_ioctl.c    | 2 +-
 net/bridge/br_netlink.c  | 2 +-
 net/bridge/br_stp.c      | 8 ++++----
 net/bridge/br_stp_if.c   | 4 ++--
 net/bridge/br_sysfs_if.c | 2 +-
 5 files changed, 9 insertions(+), 9 deletions(-)

diff --git a/net/bridge/br_ioctl.c b/net/bridge/br_ioctl.c
index a017374c6e659498d98c6af3f8d8e46a8b93570e..39f3ffcfa2d33f15cec6e61490100925eefc7e68 100644
--- a/net/bridge/br_ioctl.c
+++ b/net/bridge/br_ioctl.c
@@ -263,7 +263,7 @@ int br_dev_siocdevprivate(struct net_device *dev, struct ifreq *rq,
 		p.designated_cost = READ_ONCE(pt->designated_cost);
 		p.state = pt->state;
 		p.top_change_ack = pt->topology_change_ack;
-		p.config_pending = pt->config_pending;
+		p.config_pending = READ_ONCE(pt->config_pending);
 		p.message_age_timer_value = br_timer_value(&pt->message_age_timer);
 		p.forward_delay_timer_value = br_timer_value(&pt->forward_delay_timer);
 		p.hold_timer_value = br_timer_value(&pt->hold_timer);
diff --git a/net/bridge/br_netlink.c b/net/bridge/br_netlink.c
index 7b039994d6a2df00a2fc8ca50e45e7db4f392fa7..cc485b929d983ee4faf2541b661cad88896d39ed 100644
--- a/net/bridge/br_netlink.c
+++ b/net/bridge/br_netlink.c
@@ -271,7 +271,7 @@ static int br_port_fill_attrs(struct sk_buff *skb,
 	    nla_put_u16(skb, IFLA_BRPORT_NO, p->port_no) ||
 	    nla_put_u8(skb, IFLA_BRPORT_TOPOLOGY_CHANGE_ACK,
 		       p->topology_change_ack) ||
-	    nla_put_u8(skb, IFLA_BRPORT_CONFIG_PENDING, p->config_pending) ||
+	    nla_put_u8(skb, IFLA_BRPORT_CONFIG_PENDING, READ_ONCE(p->config_pending)) ||
 	    nla_put_u8(skb, IFLA_BRPORT_VLAN_TUNNEL, !!(p->flags &
 							BR_VLAN_TUNNEL)) ||
 	    nla_put_u16(skb, IFLA_BRPORT_GROUP_FWD_MASK, p->group_fwd_mask) ||
diff --git a/net/bridge/br_stp.c b/net/bridge/br_stp.c
index 4c364a7f0f53f4f9360887b93bfbc592c738e311..4db0b21b50ccd908b5fe8c70d77daa1afaee550d 100644
--- a/net/bridge/br_stp.c
+++ b/net/bridge/br_stp.c
@@ -215,7 +215,7 @@ void br_transmit_config(struct net_bridge_port *p)
 	struct net_bridge *br;
 
 	if (timer_pending(&p->hold_timer)) {
-		p->config_pending = 1;
+		WRITE_ONCE(p->config_pending, 1);
 		return;
 	}
 
@@ -242,7 +242,7 @@ void br_transmit_config(struct net_bridge_port *p)
 	if (bpdu.message_age < br->max_age) {
 		br_send_config_bpdu(p, &bpdu);
 		p->topology_change_ack = 0;
-		p->config_pending = 0;
+		WRITE_ONCE(p->config_pending, 0);
 		if (p->br->stp_enabled == BR_KERNEL_STP)
 			mod_timer(&p->hold_timer,
 				  round_jiffies(jiffies + BR_HOLD_TIME));
@@ -483,14 +483,14 @@ void br_port_state_selection(struct net_bridge *br)
 		/* Don't change port states if userspace is handling STP */
 		if (br->stp_enabled != BR_USER_STP) {
 			if (p->port_no == br->root_port) {
-				p->config_pending = 0;
+				WRITE_ONCE(p->config_pending, 0);
 				p->topology_change_ack = 0;
 				br_make_forwarding(p);
 			} else if (br_is_designated_port(p)) {
 				timer_delete(&p->message_age_timer);
 				br_make_forwarding(p);
 			} else {
-				p->config_pending = 0;
+				WRITE_ONCE(p->config_pending, 0);
 				p->topology_change_ack = 0;
 				br_make_blocking(p);
 			}
diff --git a/net/bridge/br_stp_if.c b/net/bridge/br_stp_if.c
index 8a418f6af423ccba88fae57d2254e35e1ae4a1a0..a7e5422eb5d140b501a7dcebf0238d5a77c5f4a1 100644
--- a/net/bridge/br_stp_if.c
+++ b/net/bridge/br_stp_if.c
@@ -38,7 +38,7 @@ void br_init_port(struct net_bridge_port *p)
 	br_become_designated_port(p);
 	br_set_state(p, BR_STATE_BLOCKING);
 	p->topology_change_ack = 0;
-	p->config_pending = 0;
+	WRITE_ONCE(p->config_pending, 0);
 
 	err = __set_ageing_time(p->dev, p->br->ageing_time);
 	if (err)
@@ -105,7 +105,7 @@ void br_stp_disable_port(struct net_bridge_port *p)
 	br_become_designated_port(p);
 	br_set_state(p, BR_STATE_DISABLED);
 	p->topology_change_ack = 0;
-	p->config_pending = 0;
+	WRITE_ONCE(p->config_pending, 0);
 
 	br_ifinfo_notify(RTM_NEWLINK, NULL, p);
 
diff --git a/net/bridge/br_sysfs_if.c b/net/bridge/br_sysfs_if.c
index af17f62e95aaff320f8407aa7b50244573ecdc00..58ba535da4e5f473be6c6eec21ce1c71f4bf97c9 100644
--- a/net/bridge/br_sysfs_if.c
+++ b/net/bridge/br_sysfs_if.c
@@ -142,7 +142,7 @@ static BRPORT_ATTR(change_ack, 0444, show_change_ack, NULL);
 
 static ssize_t show_config_pending(struct net_bridge_port *p, char *buf)
 {
-	return sysfs_emit(buf, "%d\n", p->config_pending);
+	return sysfs_emit(buf, "%d\n", READ_ONCE(p->config_pending));
 }
 static BRPORT_ATTR(config_pending, 0444, show_config_pending, NULL);
 
-- 
2.54.0.669.g59709faab0-goog


^ permalink raw reply related	[flat|nested] 15+ messages in thread

* [PATCH net-next 11/11] bridge: read p->flags once in br_port_fill_attrs()
  2026-05-21 13:19 [PATCH net-next 00/11] bridge: prepare lockless br_port_fill_attrs() (I) Eric Dumazet
                   ` (9 preceding siblings ...)
  2026-05-21 13:19 ` [PATCH net-next 10/11] bridge: provide lockless access to p->config_pending Eric Dumazet
@ 2026-05-21 13:19 ` Eric Dumazet
  2026-05-22  8:45 ` [PATCH net-next 00/11] bridge: prepare lockless br_port_fill_attrs() (I) Ido Schimmel
  11 siblings, 0 replies; 15+ messages in thread
From: Eric Dumazet @ 2026-05-21 13:19 UTC (permalink / raw)
  To: David S . Miller, Jakub Kicinski, Paolo Abeni
  Cc: Simon Horman, netdev, Ido Schimmel, Nikolay Aleksandrov,
	eric.dumazet, Eric Dumazet

We might run br_port_fill_attrs() locklessly in the future.

Signed-off-by: Eric Dumazet <edumazet@google.com>
---
 net/bridge/br_netlink.c | 41 +++++++++++++++++++++--------------------
 1 file changed, 21 insertions(+), 20 deletions(-)

diff --git a/net/bridge/br_netlink.c b/net/bridge/br_netlink.c
index cc485b929d983ee4faf2541b661cad88896d39ed..26d3adec2dcbe5d5492ddf961aa221382ded9125 100644
--- a/net/bridge/br_netlink.c
+++ b/net/bridge/br_netlink.c
@@ -234,7 +234,8 @@ static inline size_t br_nlmsg_size(struct net_device *dev, u32 filter_mask)
 static int br_port_fill_attrs(struct sk_buff *skb,
 			      const struct net_bridge_port *p)
 {
-	u8 mode = !!(p->flags & BR_HAIRPIN_MODE);
+	unsigned long flags = READ_ONCE(p->flags);
+	u8 mode = !!(flags & BR_HAIRPIN_MODE);
 	struct net_bridge_port *backup_p;
 	u64 timerval;
 
@@ -242,23 +243,23 @@ static int br_port_fill_attrs(struct sk_buff *skb,
 	    nla_put_u16(skb, IFLA_BRPORT_PRIORITY, READ_ONCE(p->priority)) ||
 	    nla_put_u32(skb, IFLA_BRPORT_COST, READ_ONCE(p->path_cost)) ||
 	    nla_put_u8(skb, IFLA_BRPORT_MODE, mode) ||
-	    nla_put_u8(skb, IFLA_BRPORT_GUARD, !!(p->flags & BR_BPDU_GUARD)) ||
+	    nla_put_u8(skb, IFLA_BRPORT_GUARD, !!(flags & BR_BPDU_GUARD)) ||
 	    nla_put_u8(skb, IFLA_BRPORT_PROTECT,
-		       !!(p->flags & BR_ROOT_BLOCK)) ||
+		       !!(flags & BR_ROOT_BLOCK)) ||
 	    nla_put_u8(skb, IFLA_BRPORT_FAST_LEAVE,
-		       !!(p->flags & BR_MULTICAST_FAST_LEAVE)) ||
+		       !!(flags & BR_MULTICAST_FAST_LEAVE)) ||
 	    nla_put_u8(skb, IFLA_BRPORT_MCAST_TO_UCAST,
-		       !!(p->flags & BR_MULTICAST_TO_UNICAST)) ||
-	    nla_put_u8(skb, IFLA_BRPORT_LEARNING, !!(p->flags & BR_LEARNING)) ||
+		       !!(flags & BR_MULTICAST_TO_UNICAST)) ||
+	    nla_put_u8(skb, IFLA_BRPORT_LEARNING, !!(flags & BR_LEARNING)) ||
 	    nla_put_u8(skb, IFLA_BRPORT_UNICAST_FLOOD,
-		       !!(p->flags & BR_FLOOD)) ||
+		       !!(flags & BR_FLOOD)) ||
 	    nla_put_u8(skb, IFLA_BRPORT_MCAST_FLOOD,
-		       !!(p->flags & BR_MCAST_FLOOD)) ||
+		       !!(flags & BR_MCAST_FLOOD)) ||
 	    nla_put_u8(skb, IFLA_BRPORT_BCAST_FLOOD,
-		       !!(p->flags & BR_BCAST_FLOOD)) ||
-	    nla_put_u8(skb, IFLA_BRPORT_PROXYARP, !!(p->flags & BR_PROXYARP)) ||
+		       !!(flags & BR_BCAST_FLOOD)) ||
+	    nla_put_u8(skb, IFLA_BRPORT_PROXYARP, !!(flags & BR_PROXYARP)) ||
 	    nla_put_u8(skb, IFLA_BRPORT_PROXYARP_WIFI,
-		       !!(p->flags & BR_PROXYARP_WIFI)) ||
+		       !!(flags & BR_PROXYARP_WIFI)) ||
 	    nla_put(skb, IFLA_BRPORT_ROOT_ID, sizeof(struct ifla_bridge_id),
 		    &p->designated_root) ||
 	    nla_put(skb, IFLA_BRPORT_BRIDGE_ID, sizeof(struct ifla_bridge_id),
@@ -272,22 +273,22 @@ static int br_port_fill_attrs(struct sk_buff *skb,
 	    nla_put_u8(skb, IFLA_BRPORT_TOPOLOGY_CHANGE_ACK,
 		       p->topology_change_ack) ||
 	    nla_put_u8(skb, IFLA_BRPORT_CONFIG_PENDING, READ_ONCE(p->config_pending)) ||
-	    nla_put_u8(skb, IFLA_BRPORT_VLAN_TUNNEL, !!(p->flags &
+	    nla_put_u8(skb, IFLA_BRPORT_VLAN_TUNNEL, !!(flags &
 							BR_VLAN_TUNNEL)) ||
 	    nla_put_u16(skb, IFLA_BRPORT_GROUP_FWD_MASK, p->group_fwd_mask) ||
 	    nla_put_u8(skb, IFLA_BRPORT_NEIGH_SUPPRESS,
-		       !!(p->flags & BR_NEIGH_SUPPRESS)) ||
-	    nla_put_u8(skb, IFLA_BRPORT_MRP_RING_OPEN, !!(p->flags &
+		       !!(flags & BR_NEIGH_SUPPRESS)) ||
+	    nla_put_u8(skb, IFLA_BRPORT_MRP_RING_OPEN, !!(flags &
 							  BR_MRP_LOST_CONT)) ||
 	    nla_put_u8(skb, IFLA_BRPORT_MRP_IN_OPEN,
-		       !!(p->flags & BR_MRP_LOST_IN_CONT)) ||
-	    nla_put_u8(skb, IFLA_BRPORT_ISOLATED, !!(p->flags & BR_ISOLATED)) ||
-	    nla_put_u8(skb, IFLA_BRPORT_LOCKED, !!(p->flags & BR_PORT_LOCKED)) ||
-	    nla_put_u8(skb, IFLA_BRPORT_MAB, !!(p->flags & BR_PORT_MAB)) ||
+		       !!(flags & BR_MRP_LOST_IN_CONT)) ||
+	    nla_put_u8(skb, IFLA_BRPORT_ISOLATED, !!(flags & BR_ISOLATED)) ||
+	    nla_put_u8(skb, IFLA_BRPORT_LOCKED, !!(flags & BR_PORT_LOCKED)) ||
+	    nla_put_u8(skb, IFLA_BRPORT_MAB, !!(flags & BR_PORT_MAB)) ||
 	    nla_put_u8(skb, IFLA_BRPORT_NEIGH_VLAN_SUPPRESS,
-		       !!(p->flags & BR_NEIGH_VLAN_SUPPRESS)) ||
+		       !!(flags & BR_NEIGH_VLAN_SUPPRESS)) ||
 	    nla_put_u8(skb, IFLA_BRPORT_NEIGH_FORWARD_GRAT,
-		       !!(p->flags & BR_NEIGH_FORWARD_GRAT)))
+		       !!(flags & BR_NEIGH_FORWARD_GRAT)))
 		return -EMSGSIZE;
 
 	timerval = br_timer_value(&p->message_age_timer);
-- 
2.54.0.669.g59709faab0-goog


^ permalink raw reply related	[flat|nested] 15+ messages in thread

* Re: [PATCH net-next 00/11] bridge: prepare lockless br_port_fill_attrs() (I)
  2026-05-21 13:19 [PATCH net-next 00/11] bridge: prepare lockless br_port_fill_attrs() (I) Eric Dumazet
                   ` (10 preceding siblings ...)
  2026-05-21 13:19 ` [PATCH net-next 11/11] bridge: read p->flags once in br_port_fill_attrs() Eric Dumazet
@ 2026-05-22  8:45 ` Ido Schimmel
  2026-05-22  9:31   ` Eric Dumazet
  2026-05-22  9:32   ` Nikolay Aleksandrov
  11 siblings, 2 replies; 15+ messages in thread
From: Ido Schimmel @ 2026-05-22  8:45 UTC (permalink / raw)
  To: Eric Dumazet
  Cc: David S . Miller, Jakub Kicinski, Paolo Abeni, Simon Horman,
	netdev, Nikolay Aleksandrov, eric.dumazet

On Thu, May 21, 2026 at 01:19:05PM +0000, Eric Dumazet wrote:
> medium-term goal is to allow "ip link show" dump commands to run without RTNL.
> 
> This round of patches adds/fixes some lockess accesses in bridge.
> 
> This is not complete, more patches will come later.
> 
> Ultimately all changes to p->flags should use set_bit()/clear_bit().

Thanks for the patches, Eric. I have two fixes [1][2] that I am planning
to submit next week where I mention some of these issues. There might be
a small conflict between both patchsets. I can review on Sunday unless
it's critical to merge the set before that.

[1] https://github.com/idosch/linux/commit/3350834468428df21c279acca1c37f67e68e1626.patch
[2] https://github.com/idosch/linux/commit/dd63fb916cdeec9e69685726ef65a40b57bd74fb.patch

^ permalink raw reply	[flat|nested] 15+ messages in thread

* Re: [PATCH net-next 00/11] bridge: prepare lockless br_port_fill_attrs() (I)
  2026-05-22  8:45 ` [PATCH net-next 00/11] bridge: prepare lockless br_port_fill_attrs() (I) Ido Schimmel
@ 2026-05-22  9:31   ` Eric Dumazet
  2026-05-22  9:32   ` Nikolay Aleksandrov
  1 sibling, 0 replies; 15+ messages in thread
From: Eric Dumazet @ 2026-05-22  9:31 UTC (permalink / raw)
  To: Ido Schimmel
  Cc: David S . Miller, Jakub Kicinski, Paolo Abeni, Simon Horman,
	netdev, Nikolay Aleksandrov, eric.dumazet

On Fri, May 22, 2026 at 1:45 AM Ido Schimmel <idosch@nvidia.com> wrote:
>
> On Thu, May 21, 2026 at 01:19:05PM +0000, Eric Dumazet wrote:
> > medium-term goal is to allow "ip link show" dump commands to run without RTNL.
> >
> > This round of patches adds/fixes some lockess accesses in bridge.
> >
> > This is not complete, more patches will come later.
> >
> > Ultimately all changes to p->flags should use set_bit()/clear_bit().
>
> Thanks for the patches, Eric. I have two fixes [1][2] that I am planning
> to submit next week where I mention some of these issues. There might be
> a small conflict between both patchsets. I can review on Sunday unless
> it's critical to merge the set before that.
>
> [1] https://github.com/idosch/linux/commit/3350834468428df21c279acca1c37f67e68e1626.patch
> [2] https://github.com/idosch/linux/commit/dd63fb916cdeec9e69685726ef65a40b57bd74fb.patch

No problem my series can wait!

^ permalink raw reply	[flat|nested] 15+ messages in thread

* Re: [PATCH net-next 00/11] bridge: prepare lockless br_port_fill_attrs() (I)
  2026-05-22  8:45 ` [PATCH net-next 00/11] bridge: prepare lockless br_port_fill_attrs() (I) Ido Schimmel
  2026-05-22  9:31   ` Eric Dumazet
@ 2026-05-22  9:32   ` Nikolay Aleksandrov
  1 sibling, 0 replies; 15+ messages in thread
From: Nikolay Aleksandrov @ 2026-05-22  9:32 UTC (permalink / raw)
  To: Ido Schimmel
  Cc: Eric Dumazet, David S . Miller, Jakub Kicinski, Paolo Abeni,
	Simon Horman, netdev, eric.dumazet

On Fri, May 22, 2026 at 11:45:38AM +0300, Ido Schimmel wrote:
> On Thu, May 21, 2026 at 01:19:05PM +0000, Eric Dumazet wrote:
> > medium-term goal is to allow "ip link show" dump commands to run without RTNL.
> > 
> > This round of patches adds/fixes some lockess accesses in bridge.
> > 
> > This is not complete, more patches will come later.
> > 
> > Ultimately all changes to p->flags should use set_bit()/clear_bit().
> 
> Thanks for the patches, Eric. I have two fixes [1][2] that I am planning
> to submit next week where I mention some of these issues. There might be
> a small conflict between both patchsets. I can review on Sunday unless
> it's critical to merge the set before that.
> 
> [1] https://github.com/idosch/linux/commit/3350834468428df21c279acca1c37f67e68e1626.patch
> [2] https://github.com/idosch/linux/commit/dd63fb916cdeec9e69685726ef65a40b57bd74fb.patch

+1
I'm on the road next two days and will be able to review them properly
on Sunday at the earliest.

Cheers,
 Nik

^ permalink raw reply	[flat|nested] 15+ messages in thread

end of thread, other threads:[~2026-05-22  9:32 UTC | newest]

Thread overview: 15+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2026-05-21 13:19 [PATCH net-next 00/11] bridge: prepare lockless br_port_fill_attrs() (I) Eric Dumazet
2026-05-21 13:19 ` [PATCH net-next 01/11] bridge: add a READ_ONCE() in br_timer_value() Eric Dumazet
2026-05-21 13:19 ` [PATCH net-next 02/11] bridge: add bridge_flags_bit enum Eric Dumazet
2026-05-21 13:19 ` [PATCH net-next 03/11] bridge: use BR_PROMISC_BIT Eric Dumazet
2026-05-21 13:19 ` [PATCH net-next 04/11] bridge: use BR_ADMIN_COST_BIT Eric Dumazet
2026-05-21 13:19 ` [PATCH net-next 05/11] bridge: provide lockless access to p->path_cost Eric Dumazet
2026-05-21 13:19 ` [PATCH net-next 06/11] bridge: provide lockless access to p->designated_cost Eric Dumazet
2026-05-21 13:19 ` [PATCH net-next 07/11] bridge: provide lockless access to p->designated_port Eric Dumazet
2026-05-21 13:19 ` [PATCH net-next 08/11] bridge: provide lockless access to p->priority Eric Dumazet
2026-05-21 13:19 ` [PATCH net-next 09/11] bridge: provide lockless access to p->port_id Eric Dumazet
2026-05-21 13:19 ` [PATCH net-next 10/11] bridge: provide lockless access to p->config_pending Eric Dumazet
2026-05-21 13:19 ` [PATCH net-next 11/11] bridge: read p->flags once in br_port_fill_attrs() Eric Dumazet
2026-05-22  8:45 ` [PATCH net-next 00/11] bridge: prepare lockless br_port_fill_attrs() (I) Ido Schimmel
2026-05-22  9:31   ` Eric Dumazet
2026-05-22  9:32   ` Nikolay Aleksandrov

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox