* [PATCH net v4 1/2] net: hsr: serialize seq_blocks merge across nodes
2026-04-01 9:22 [PATCH net v4 0/2] net: hsr: fixes for PRP duplication and VLAN unwind luka.gejak
@ 2026-04-01 9:22 ` luka.gejak
2026-04-01 9:22 ` [PATCH net v4 2/2] net: hsr: fix VLAN add unwind on slave errors luka.gejak
2026-04-02 15:40 ` [PATCH net v4 0/2] net: hsr: fixes for PRP duplication and VLAN unwind patchwork-bot+netdevbpf
2 siblings, 0 replies; 4+ messages in thread
From: luka.gejak @ 2026-04-01 9:22 UTC (permalink / raw)
To: davem, edumazet, kuba, pabeni
Cc: netdev, fmaurer, horms, bigeasy, m-karicheri2, luka.gejak
From: Luka Gejak <luka.gejak@linux.dev>
During node merging, hsr_handle_sup_frame() walks node_curr->seq_blocks
to update node_real without holding node_curr->seq_out_lock. This
allows concurrent mutations from duplicate registration paths, risking
inconsistent state or XArray/bitmap corruption.
Fix this by locking both nodes' seq_out_lock during the merge.
To prevent ABBA deadlocks, locks are acquired in order of memory
address.
Reviewed-by: Felix Maurer <fmaurer@redhat.com>
Fixes: 415e6367512b ("hsr: Implement more robust duplicate discard for PRP")
Signed-off-by: Luka Gejak <luka.gejak@linux.dev>
---
net/hsr/hsr_framereg.c | 38 ++++++++++++++++++++++++++++++++++++--
1 file changed, 36 insertions(+), 2 deletions(-)
diff --git a/net/hsr/hsr_framereg.c b/net/hsr/hsr_framereg.c
index 577fb588bc2f..d09875b33588 100644
--- a/net/hsr/hsr_framereg.c
+++ b/net/hsr/hsr_framereg.c
@@ -123,6 +123,40 @@ static void hsr_free_node_rcu(struct rcu_head *rn)
hsr_free_node(node);
}
+static void hsr_lock_seq_out_pair(struct hsr_node *node_a,
+ struct hsr_node *node_b)
+{
+ if (node_a == node_b) {
+ spin_lock_bh(&node_a->seq_out_lock);
+ return;
+ }
+
+ if (node_a < node_b) {
+ spin_lock_bh(&node_a->seq_out_lock);
+ spin_lock_nested(&node_b->seq_out_lock, SINGLE_DEPTH_NESTING);
+ } else {
+ spin_lock_bh(&node_b->seq_out_lock);
+ spin_lock_nested(&node_a->seq_out_lock, SINGLE_DEPTH_NESTING);
+ }
+}
+
+static void hsr_unlock_seq_out_pair(struct hsr_node *node_a,
+ struct hsr_node *node_b)
+{
+ if (node_a == node_b) {
+ spin_unlock_bh(&node_a->seq_out_lock);
+ return;
+ }
+
+ if (node_a < node_b) {
+ spin_unlock(&node_b->seq_out_lock);
+ spin_unlock_bh(&node_a->seq_out_lock);
+ } else {
+ spin_unlock(&node_a->seq_out_lock);
+ spin_unlock_bh(&node_b->seq_out_lock);
+ }
+}
+
void hsr_del_nodes(struct list_head *node_db)
{
struct hsr_node *node;
@@ -432,7 +466,7 @@ void hsr_handle_sup_frame(struct hsr_frame_info *frame)
}
ether_addr_copy(node_real->macaddress_B, ethhdr->h_source);
- spin_lock_bh(&node_real->seq_out_lock);
+ hsr_lock_seq_out_pair(node_real, node_curr);
for (i = 0; i < HSR_PT_PORTS; i++) {
if (!node_curr->time_in_stale[i] &&
time_after(node_curr->time_in[i], node_real->time_in[i])) {
@@ -455,7 +489,7 @@ void hsr_handle_sup_frame(struct hsr_frame_info *frame)
src_blk->seq_nrs[i], HSR_SEQ_BLOCK_SIZE);
}
}
- spin_unlock_bh(&node_real->seq_out_lock);
+ hsr_unlock_seq_out_pair(node_real, node_curr);
node_real->addr_B_port = port_rcv->type;
spin_lock_bh(&hsr->list_lock);
--
2.53.0
^ permalink raw reply related [flat|nested] 4+ messages in thread* [PATCH net v4 2/2] net: hsr: fix VLAN add unwind on slave errors
2026-04-01 9:22 [PATCH net v4 0/2] net: hsr: fixes for PRP duplication and VLAN unwind luka.gejak
2026-04-01 9:22 ` [PATCH net v4 1/2] net: hsr: serialize seq_blocks merge across nodes luka.gejak
@ 2026-04-01 9:22 ` luka.gejak
2026-04-02 15:40 ` [PATCH net v4 0/2] net: hsr: fixes for PRP duplication and VLAN unwind patchwork-bot+netdevbpf
2 siblings, 0 replies; 4+ messages in thread
From: luka.gejak @ 2026-04-01 9:22 UTC (permalink / raw)
To: davem, edumazet, kuba, pabeni
Cc: netdev, fmaurer, horms, bigeasy, m-karicheri2, luka.gejak
From: Luka Gejak <luka.gejak@linux.dev>
When vlan_vid_add() fails for a secondary slave, the error path calls
vlan_vid_del() on the failing port instead of the peer slave that had
already succeeded. This results in asymmetric VLAN state across the HSR
pair.
Fix this by switching to a centralized unwind path that removes the VID
from any slave device that was already programmed.
Fixes: 1a8a63a5305e ("net: hsr: Add VLAN CTAG filter support")
Signed-off-by: Luka Gejak <luka.gejak@linux.dev>
---
net/hsr/hsr_device.c | 32 +++++++++++++++++---------------
1 file changed, 17 insertions(+), 15 deletions(-)
diff --git a/net/hsr/hsr_device.c b/net/hsr/hsr_device.c
index 90236028817d..5555b71ab19b 100644
--- a/net/hsr/hsr_device.c
+++ b/net/hsr/hsr_device.c
@@ -532,8 +532,8 @@ static void hsr_change_rx_flags(struct net_device *dev, int change)
static int hsr_ndo_vlan_rx_add_vid(struct net_device *dev,
__be16 proto, u16 vid)
{
- bool is_slave_a_added = false;
- bool is_slave_b_added = false;
+ struct net_device *slave_a_dev = NULL;
+ struct net_device *slave_b_dev = NULL;
struct hsr_port *port;
struct hsr_priv *hsr;
int ret = 0;
@@ -549,33 +549,35 @@ static int hsr_ndo_vlan_rx_add_vid(struct net_device *dev,
switch (port->type) {
case HSR_PT_SLAVE_A:
if (ret) {
- /* clean up Slave-B */
netdev_err(dev, "add vid failed for Slave-A\n");
- if (is_slave_b_added)
- vlan_vid_del(port->dev, proto, vid);
- return ret;
+ goto unwind;
}
-
- is_slave_a_added = true;
+ slave_a_dev = port->dev;
break;
-
case HSR_PT_SLAVE_B:
if (ret) {
- /* clean up Slave-A */
netdev_err(dev, "add vid failed for Slave-B\n");
- if (is_slave_a_added)
- vlan_vid_del(port->dev, proto, vid);
- return ret;
+ goto unwind;
}
-
- is_slave_b_added = true;
+ slave_b_dev = port->dev;
break;
default:
+ if (ret)
+ goto unwind;
break;
}
}
return 0;
+
+unwind:
+ if (slave_a_dev)
+ vlan_vid_del(slave_a_dev, proto, vid);
+
+ if (slave_b_dev)
+ vlan_vid_del(slave_b_dev, proto, vid);
+
+ return ret;
}
static int hsr_ndo_vlan_rx_kill_vid(struct net_device *dev,
--
2.53.0
^ permalink raw reply related [flat|nested] 4+ messages in thread* Re: [PATCH net v4 0/2] net: hsr: fixes for PRP duplication and VLAN unwind
2026-04-01 9:22 [PATCH net v4 0/2] net: hsr: fixes for PRP duplication and VLAN unwind luka.gejak
2026-04-01 9:22 ` [PATCH net v4 1/2] net: hsr: serialize seq_blocks merge across nodes luka.gejak
2026-04-01 9:22 ` [PATCH net v4 2/2] net: hsr: fix VLAN add unwind on slave errors luka.gejak
@ 2026-04-02 15:40 ` patchwork-bot+netdevbpf
2 siblings, 0 replies; 4+ messages in thread
From: patchwork-bot+netdevbpf @ 2026-04-02 15:40 UTC (permalink / raw)
To: Luka Gejak
Cc: davem, edumazet, kuba, pabeni, netdev, fmaurer, horms, bigeasy,
m-karicheri2
Hello:
This series was applied to netdev/net.git (main)
by Jakub Kicinski <kuba@kernel.org>:
On Wed, 1 Apr 2026 11:22:41 +0200 you wrote:
> From: Luka Gejak <luka.gejak@linux.dev>
>
> This series addresses two logic bugs in the HSR/PRP implementation
> identified during a protocol audit. These are targeted for the 'net'
> tree as they fix potential memory corruption and state inconsistency.
>
> The primary change resolves a race condition in the node merging path by
> implementing address-based lock ordering. This ensures that concurrent
> mutations of sequence blocks do not lead to state corruption or
> deadlocks.
>
> [...]
Here is the summary with links:
- [net,v4,1/2] net: hsr: serialize seq_blocks merge across nodes
https://git.kernel.org/netdev/net/c/f5df2990c364
- [net,v4,2/2] net: hsr: fix VLAN add unwind on slave errors
https://git.kernel.org/netdev/net/c/2e3514e63bfb
You are awesome, thank you!
--
Deet-doot-dot, I am a bot.
https://korg.docs.kernel.org/patchwork/pwbot.html
^ permalink raw reply [flat|nested] 4+ messages in thread