* [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