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
333 esw_debug(esw->dev, "%s applying global %s policy\n", __func__, val ? "pop" : "none");333 esw_debug(esw->dev, "%s applying global %s policy\n", __func__, val ? "pop" : "none");
334 for (vf_vport = 1; vf_vport < esw->enabled_vports; vf_vport++) {334 for (vf_vport = 1; vf_vport < esw->enabled_vports; vf_vport++) {
335 rep = &esw->offloads.vport_reps[vf_vport];335 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)
337 continue;337 continue;
338 338
339 err = __mlx5_eswitch_set_vport_vlan(esw, rep->vport, 0, 0, val);339 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
1277 ether_addr_copy(rep->hw_id, hw_id);1277 ether_addr_copy(rep->hw_id, hw_id);
1278 1278
1279 for (rep_type = 0; rep_type < NUM_REP_TYPES; rep_type++)1279 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);
1281 }1282 }
1282 1283
1283 return 0;1284 return 0;
@@ -1286,11 +1287,9 @@ int esw_offloads_init_reps(struct mlx5_eswitch *esw) · 2 unmodified lines
1286static void __esw_offloads_unload_rep(struct mlx5_eswitch *esw,1287static void __esw_offloads_unload_rep(struct mlx5_eswitch *esw,
1287 struct mlx5_eswitch_rep *rep, u8 rep_type)1288 struct mlx5_eswitch_rep *rep, u8 rep_type)
1288{1289{
1289 if (rep->rep_if[rep_type].state != REP_LOADED)1290 if (atomic_cmpxchg(&rep->rep_if[rep_type].state,
1290 return;1291 REP_LOADED, REP_REGISTERED) == REP_LOADED)
1291 1292 rep->rep_if[rep_type].unload(rep);
1292 rep->rep_if[rep_type].unload(rep);
1293 rep->rep_if[rep_type].state = REP_REGISTERED;
1294}1293}
1295 1294
1296static void __unload_reps_special_vport(struct mlx5_eswitch *esw, u8 rep_type)1295static 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
1351{1350{
1352 int err = 0;1351 int err = 0;
1353 1352
1354 if (rep->rep_if[rep_type].state != REP_REGISTERED)1353 if (atomic_cmpxchg(&rep->rep_if[rep_type].state,
1355 return 0;1354 REP_REGISTERED, REP_LOADED) == REP_REGISTERED) {
1356 1355 err = rep->rep_if[rep_type].load(esw->dev, rep);
1357 err = rep->rep_if[rep_type].load(esw->dev, rep);1356 if (err)
1358 if (err)1357 atomic_set(&rep->rep_if[rep_type].state,
1359 return err;1358 REP_REGISTERED);
1360 1359 }
1361 rep->rep_if[rep_type].state = REP_LOADED;
1362 1360
1363 return 0;1361 return err;
1364}1362}
1365 1363
1366static int __load_reps_special_vport(struct mlx5_eswitch *esw, u8 rep_type)1364static 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
2217 rep_if->get_proto_dev = __rep_if->get_proto_dev;2215 rep_if->get_proto_dev = __rep_if->get_proto_dev;
2218 rep_if->priv = __rep_if->priv;2216 rep_if->priv = __rep_if->priv;
2219 2217
2220 rep_if->state = REP_REGISTERED;2218 atomic_set(&rep_if->state, REP_REGISTERED);
2221 }2219 }
2222}2220}
2223EXPORT_SYMBOL(mlx5_eswitch_register_vport_reps);2221EXPORT_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
2232 __unload_reps_all_vport(esw, max_vf, rep_type);2230 __unload_reps_all_vport(esw, max_vf, rep_type);
2233 2231
2234 mlx5_esw_for_all_reps(esw, i, rep)2232 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);
2236}2234}
2237EXPORT_SYMBOL(mlx5_eswitch_unregister_vport_reps);2235EXPORT_SYMBOL(mlx5_eswitch_unregister_vport_reps);
2238 2236
@@ -2252,7 +2250,7 @@ void *mlx5_eswitch_get_proto_dev(struct mlx5_eswitch *esw, · 13 unmodified lines
2252 2250
2253 rep = mlx5_eswitch_get_rep(esw, vport);2251 rep = mlx5_eswitch_get_rep(esw, vport);
2254 2252
2255 if (rep->rep_if[rep_type].state == REP_LOADED &&2253 if (atomic_read(&rep->rep_if[rep_type].state) == REP_LOADED &&
2256 rep->rep_if[rep_type].get_proto_dev)2254 rep->rep_if[rep_type].get_proto_dev)
2257 return rep->rep_if[rep_type].get_proto_dev(rep);2255 return rep->rep_if[rep_type].get_proto_dev(rep);
2258 return NULL;2256 return NULL;
include/linux/mlx5/eswitch.h+1−1
@@ -35,7 +35,7 @@ struct mlx5_eswitch_rep_if { · 34 unmodified lines
35 void (*unload)(struct mlx5_eswitch_rep *rep);35 void (*unload)(struct mlx5_eswitch_rep *rep);
36 void *(*get_proto_dev)(struct mlx5_eswitch_rep *rep);36 void *(*get_proto_dev)(struct mlx5_eswitch_rep *rep);
37 void *priv;37 void *priv;
38 u8 state;38 atomic_t state;
39};39};
40 40
41struct mlx5_eswitch_rep {41struct 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