History

net/mlx5: E-Switch, Use atomic rep state to serialize state change

When the state of rep was introduced, it was also designed to prevent duplicate unloading of the same rep. Considering the following two flows when an eswitch manager is at switchdev mode with n VF reps loaded. +--------------------------------------+--------------------------------+ | cpu-0 | cpu-1 | | -------- | -------- | | mlx5_ib_remove | mlx5_eswitch_disable_sriov | | mlx5_ib_unregister_vport_reps | esw_offloads_cleanup | | mlx5_eswitch_unregister_vport_reps | esw_offloads_unload_all_reps | | __unload_reps_all_vport | __unload_reps_all_vport | +--------------------------------------+--------------------------------+ These two flows will try to unload the same rep. Per original design, once one flow unloads the rep, the state moves to REGISTERED. The 2nd flow will no longer needs to do the unload and bails out. However, as read and write of the state is not atomic, when 1st flow is doing the unload, the state is still LOADED, 2nd flow is able to do the same unload action. Kernel crash will happen. To solve this, driver should do atomic test-and-set for the state. So that only one flow can change the rep state from LOADED to REGISTERED, and proceed to do the actual unloading. Since the state is changing to atomic type, all other read/write should be atomic action as well.

Bodong Wang committed 7 years ago

Commit 6f4e0211 parent 5d9986a2 files · +18 −20Browse files

Unified · Split

2 files
  1. drivers/net/ethernet/mellanox/mlx5/core/eswitch_offloads.c +17 −19
  2. include/linux/mlx5/eswitch.h +1 −1
drivers/net/ethernet/mellanox/mlx5/core/eswitch_offloads.c+17−19
@@ -333,7 +333,7 @@ static int esw_set_global_vlan_pop(struct mlx5_eswitch *esw, u8 val) · 332 unmodified lines
333333 esw_debug(esw->dev, "%s applying global %s policy\n", __func__, val ? "pop" : "none");
334334 for (vf_vport = 1; vf_vport < esw->enabled_vports; vf_vport++) {
335335 rep = &esw->offloads.vport_reps[vf_vport];
336− if (rep->rep_if[REP_ETH].state != REP_LOADED)
336+ if (atomic_read(&rep->rep_if[REP_ETH].state) != REP_LOADED)
337337 continue;
338338
339339 err = __mlx5_eswitch_set_vport_vlan(esw, rep->vport, 0, 0, val);
@@ -1277,7 +1277,8 @@ int esw_offloads_init_reps(struct mlx5_eswitch *esw) · 937 unmodified lines
12771277 ether_addr_copy(rep->hw_id, hw_id);
12781278
12791279 for (rep_type = 0; rep_type < NUM_REP_TYPES; rep_type++)
1280− rep->rep_if[rep_type].state = REP_UNREGISTERED;
1280+ atomic_set(&rep->rep_if[rep_type].state,
1281+ REP_UNREGISTERED);
12811282 }
12821283
12831284 return 0;
@@ -1286,11 +1287,9 @@ int esw_offloads_init_reps(struct mlx5_eswitch *esw) · 2 unmodified lines
12861287 static void __esw_offloads_unload_rep(struct mlx5_eswitch *esw,
12871288 struct mlx5_eswitch_rep *rep, u8 rep_type)
12881289 {
1289− if (rep->rep_if[rep_type].state != REP_LOADED)
1290− return;
1291−
1292− rep->rep_if[rep_type].unload(rep);
1293− rep->rep_if[rep_type].state = REP_REGISTERED;
1290+ if (atomic_cmpxchg(&rep->rep_if[rep_type].state,
1291+ REP_LOADED, REP_REGISTERED) == REP_LOADED)
1292+ rep->rep_if[rep_type].unload(rep);
12941293 }
12951294
12961295 static void __unload_reps_special_vport(struct mlx5_eswitch *esw, u8 rep_type)
@@ -1351,16 +1350,15 @@ static int __esw_offloads_load_rep(struct mlx5_eswitch *esw, · 54 unmodified lines
13511350 {
13521351 int err = 0;
13531352
1354− if (rep->rep_if[rep_type].state != REP_REGISTERED)
1355− return 0;
1356−
1357− err = rep->rep_if[rep_type].load(esw->dev, rep);
1358− if (err)
1359− return err;
1360−
1361− rep->rep_if[rep_type].state = REP_LOADED;
1353+ if (atomic_cmpxchg(&rep->rep_if[rep_type].state,
1354+ REP_REGISTERED, REP_LOADED) == REP_REGISTERED) {
1355+ err = rep->rep_if[rep_type].load(esw->dev, rep);
1356+ if (err)
1357+ atomic_set(&rep->rep_if[rep_type].state,
1358+ REP_REGISTERED);
1359+ }
13621360
1363− return 0;
1361+ return err;
13641362 }
13651363
13661364 static int __load_reps_special_vport(struct mlx5_eswitch *esw, u8 rep_type)
@@ -2217,7 +2215,7 @@ void mlx5_eswitch_register_vport_reps(struct mlx5_eswitch *esw, · 850 unmodified lines
22172215 rep_if->get_proto_dev = __rep_if->get_proto_dev;
22182216 rep_if->priv = __rep_if->priv;
22192217
2220− rep_if->state = REP_REGISTERED;
2218+ atomic_set(&rep_if->state, REP_REGISTERED);
22212219 }
22222220 }
22232221 EXPORT_SYMBOL(mlx5_eswitch_register_vport_reps);
@@ -2232,7 +2230,7 @@ void mlx5_eswitch_unregister_vport_reps(struct mlx5_eswitch *esw, u8 rep_type) · 8 unmodified lines
22322230 __unload_reps_all_vport(esw, max_vf, rep_type);
22332231
22342232 mlx5_esw_for_all_reps(esw, i, rep)
2235− rep->rep_if[rep_type].state = REP_UNREGISTERED;
2233+ atomic_set(&rep->rep_if[rep_type].state, REP_UNREGISTERED);
22362234 }
22372235 EXPORT_SYMBOL(mlx5_eswitch_unregister_vport_reps);
22382236
@@ -2252,7 +2250,7 @@ void *mlx5_eswitch_get_proto_dev(struct mlx5_eswitch *esw, · 13 unmodified lines
22522250
22532251 rep = mlx5_eswitch_get_rep(esw, vport);
22542252
2255− if (rep->rep_if[rep_type].state == REP_LOADED &&
2253+ if (atomic_read(&rep->rep_if[rep_type].state) == REP_LOADED &&
22562254 rep->rep_if[rep_type].get_proto_dev)
22572255 return rep->rep_if[rep_type].get_proto_dev(rep);
22582256 return NULL;
include/linux/mlx5/eswitch.h+1−1
@@ -35,7 +35,7 @@ struct mlx5_eswitch_rep_if { · 34 unmodified lines
3535 void (*unload)(struct mlx5_eswitch_rep *rep);
3636 void *(*get_proto_dev)(struct mlx5_eswitch_rep *rep);
3737 void *priv;
38− u8 state;
38+ atomic_t state;
3939 };
4040
4141 struct mlx5_eswitch_rep {

Keyboard shortcuts

General

Show keyboard shortcuts
?
Focus the current search
/

Issues and pull requests

Open filters
f

Issues, pull requests and Inbox

Select next item
j↓
Select previous item
k↑
Open selected item
Enter
Dismiss filters or clear selection
Esc

Repository code

Go to file
t