net: bridge: vlan: split unpublishing from deletion

Split removal of a VLAN from its lookup and flood structures from object
destruction. Pass the VLAN group explicitly to __vlan_del() and call both
operations consecutively for now. This prepares deletion paths to quiesce
readers after making an entry unreachable and before freeing it.

Reviewed-by: Ido Schimmel <idosch@nvidia.com>
Signed-off-by: Nikolay Aleksandrov <razor@blackwall.org>
Link: https://patch.msgid.link/20260930071411.2786201-8-razor@blackwall.org
Signed-off-by: Jakub Kicinski <kuba@kernel.org>
This commit is contained in:
Nikolay Aleksandrov 2026-09-30 10:14:06 +03:00 committed by Jakub Kicinski
parent f0a349b921
commit e5c71bf914

View File

@ -429,22 +429,34 @@ static int __vlan_add(struct net_bridge_vlan *v, u16 flags,
goto out;
}
static void __vlan_del(struct net_bridge_vlan *v)
static void __vlan_unpublish(struct net_bridge_vlan_group *vg,
struct net_bridge_vlan *v)
{
__vlan_delete_pvid(vg, v);
if (!br_vlan_is_master(v)) {
struct net_bridge_vlan *masterv = v->brvlan;
rhashtable_remove_fast(&vg->vlan_hash, &v->vnode,
br_vlan_rht_params);
__vlan_del_list(v);
/* -1 because br_vlan_put_master() is called later */
br_vlan_rebuild_port_array(masterv,
br_vlan_num_ports(masterv) - 1);
}
}
static void __vlan_del(struct net_bridge_vlan_group *vg,
struct net_bridge_vlan *v)
{
struct net_bridge_vlan *masterv = v;
struct net_bridge_vlan_group *vg;
struct net_bridge_port *p = NULL;
int err;
if (br_vlan_is_master(v)) {
vg = br_vlan_group(v->br);
} else {
if (!br_vlan_is_master(v)) {
p = v->port;
vg = nbp_vlan_group(v->port);
masterv = v->brvlan;
}
__vlan_delete_pvid(vg, v);
if (p) {
err = __vlan_vid_del(p->dev, p->br, v);
if (err)
@ -467,12 +479,6 @@ static void __vlan_del(struct net_bridge_vlan *v)
if (masterv != v) {
vlan_tunnel_info_del(vg, v);
rhashtable_remove_fast(&vg->vlan_hash, &v->vnode,
br_vlan_rht_params);
__vlan_del_list(v);
/* -1 because br_vlan_put_master() is called later */
br_vlan_rebuild_port_array(masterv,
br_vlan_num_ports(masterv) - 1);
nbp_vlan_set_vlan_dev_state(p, v->vid);
br_multicast_toggle_one_vlan(v, false);
br_multicast_port_ctx_deinit(&v->port_mcast_ctx);
@ -509,7 +515,8 @@ static void __vlan_flush(const struct net_bridge *br,
}
v_end = vlan->vid;
__vlan_del(vlan);
__vlan_unpublish(vg, vlan);
__vlan_del(vg, vlan);
}
/* notify about the last/whole vlan range */
@ -873,7 +880,8 @@ int br_vlan_delete(struct net_bridge *br, u16 vid)
br_fdb_cleanup_by_dst(br, br_port_to_dst(NULL), vid, 0);
vlan_tunnel_info_del(vg, v);
__vlan_del(v);
__vlan_unpublish(vg, v);
__vlan_del(vg, v);
return 0;
}
@ -1389,15 +1397,18 @@ int nbp_vlan_add(struct net_bridge_port *port, u16 vid, u16 flags,
*/
int nbp_vlan_delete(struct net_bridge_port *port, u16 vid)
{
struct net_bridge_vlan_group *vg;
struct net_bridge_vlan *v;
ASSERT_RTNL();
v = br_vlan_find(nbp_vlan_group(port), vid);
vg = nbp_vlan_group(port);
v = br_vlan_find(vg, vid);
if (!v)
return -ENOENT;
br_fdb_cleanup_by_dst(port->br, br_vlan_to_dst(v), vid, 0);
__vlan_del(v);
__vlan_unpublish(vg, v);
__vlan_del(vg, v);
return 0;
}