Skip to content

Commit 1469099

Browse files
liyanguoCoriginedavem330
authored andcommitted
nfp: flower: avoid rmmod nfp crash issues
When there are CT table entries, and you rmmod nfp, the following events can happen: task1: nfp_net_pci_remove ↓ nfp_flower_stop->(asynchronous)tcf_ct_flow_table_cleanup_work(3) ↓ nfp_zone_table_entry_destroy(1) task2: nfp_fl_ct_handle_nft_flow(2) When the execution order is (1)->(2)->(3), it will crash. Therefore, in the function nfp_fl_ct_del_flow, nf_flow_table_offload_del_cb needs to be executed synchronously. At the same time, in order to solve the deadlock problem and the problem of rtnl_lock sometimes failing, replace rtnl_lock with the private nfp_fl_lock. Fixes: 7cc93d8 ("nfp: flower-ct: remove callback delete deadlock") Cc: stable@vger.kernel.org Signed-off-by: Yanguo Li <yanguo.li@corigine.com> Signed-off-by: Louis Peens <louis.peens@corigine.com> Signed-off-by: David S. Miller <davem@davemloft.net>
1 parent 8f8abb8 commit 1469099

6 files changed

Lines changed: 54 additions & 23 deletions

File tree

drivers/net/ethernet/netronome/nfp/flower/cmsg.c

Lines changed: 6 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -210,6 +210,7 @@ nfp_flower_cmsg_merge_hint_rx(struct nfp_app *app, struct sk_buff *skb)
210210
unsigned int msg_len = nfp_flower_cmsg_get_data_len(skb);
211211
struct nfp_flower_cmsg_merge_hint *msg;
212212
struct nfp_fl_payload *sub_flows[2];
213+
struct nfp_flower_priv *priv;
213214
int err, i, flow_cnt;
214215

215216
msg = nfp_flower_cmsg_get_data(skb);
@@ -228,14 +229,15 @@ nfp_flower_cmsg_merge_hint_rx(struct nfp_app *app, struct sk_buff *skb)
228229
return;
229230
}
230231

231-
rtnl_lock();
232+
priv = app->priv;
233+
mutex_lock(&priv->nfp_fl_lock);
232234
for (i = 0; i < flow_cnt; i++) {
233235
u32 ctx = be32_to_cpu(msg->flow[i].host_ctx);
234236

235237
sub_flows[i] = nfp_flower_get_fl_payload_from_ctx(app, ctx);
236238
if (!sub_flows[i]) {
237239
nfp_flower_cmsg_warn(app, "Invalid flow in merge hint\n");
238-
goto err_rtnl_unlock;
240+
goto err_mutex_unlock;
239241
}
240242
}
241243

@@ -244,8 +246,8 @@ nfp_flower_cmsg_merge_hint_rx(struct nfp_app *app, struct sk_buff *skb)
244246
if (err == -ENOMEM)
245247
nfp_flower_cmsg_warn(app, "Flow merge memory fail.\n");
246248

247-
err_rtnl_unlock:
248-
rtnl_unlock();
249+
err_mutex_unlock:
250+
mutex_unlock(&priv->nfp_fl_lock);
249251
}
250252

251253
static void

drivers/net/ethernet/netronome/nfp/flower/conntrack.c

Lines changed: 13 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -2131,8 +2131,6 @@ nfp_fl_ct_offload_nft_flow(struct nfp_fl_ct_zone_entry *zt, struct flow_cls_offl
21312131
struct nfp_fl_ct_flow_entry *ct_entry;
21322132
struct netlink_ext_ack *extack = NULL;
21332133

2134-
ASSERT_RTNL();
2135-
21362134
extack = flow->common.extack;
21372135
switch (flow->command) {
21382136
case FLOW_CLS_REPLACE:
@@ -2178,9 +2176,13 @@ int nfp_fl_ct_handle_nft_flow(enum tc_setup_type type, void *type_data, void *cb
21782176

21792177
switch (type) {
21802178
case TC_SETUP_CLSFLOWER:
2181-
rtnl_lock();
2179+
while (!mutex_trylock(&zt->priv->nfp_fl_lock)) {
2180+
if (!zt->nft) /* avoid deadlock */
2181+
return err;
2182+
msleep(20);
2183+
}
21822184
err = nfp_fl_ct_offload_nft_flow(zt, flow);
2183-
rtnl_unlock();
2185+
mutex_unlock(&zt->priv->nfp_fl_lock);
21842186
break;
21852187
default:
21862188
return -EOPNOTSUPP;
@@ -2208,6 +2210,7 @@ int nfp_fl_ct_del_flow(struct nfp_fl_ct_map_entry *ct_map_ent)
22082210
struct nfp_fl_ct_flow_entry *ct_entry;
22092211
struct nfp_fl_ct_zone_entry *zt;
22102212
struct rhashtable *m_table;
2213+
struct nf_flowtable *nft;
22112214

22122215
if (!ct_map_ent)
22132216
return -ENOENT;
@@ -2226,8 +2229,12 @@ int nfp_fl_ct_del_flow(struct nfp_fl_ct_map_entry *ct_map_ent)
22262229
if (ct_map_ent->cookie > 0)
22272230
kfree(ct_map_ent);
22282231

2229-
if (!zt->pre_ct_count) {
2230-
zt->nft = NULL;
2232+
if (!zt->pre_ct_count && zt->nft) {
2233+
nft = zt->nft;
2234+
zt->nft = NULL; /* avoid deadlock */
2235+
nf_flow_table_offload_del_cb(nft,
2236+
nfp_fl_ct_handle_nft_flow,
2237+
zt);
22312238
nfp_fl_ct_clean_nft_entries(zt);
22322239
}
22332240
break;

drivers/net/ethernet/netronome/nfp/flower/main.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -297,6 +297,7 @@ struct nfp_fl_internal_ports {
297297
* @predt_list: List to keep track of decap pretun flows
298298
* @neigh_table: Table to keep track of neighbor entries
299299
* @predt_lock: Lock to serialise predt/neigh table updates
300+
* @nfp_fl_lock: Lock to protect the flow offload operation
300301
*/
301302
struct nfp_flower_priv {
302303
struct nfp_app *app;
@@ -339,6 +340,7 @@ struct nfp_flower_priv {
339340
struct list_head predt_list;
340341
struct rhashtable neigh_table;
341342
spinlock_t predt_lock; /* Lock to serialise predt/neigh table updates */
343+
struct mutex nfp_fl_lock; /* Protect the flow operation */
342344
};
343345

344346
/**

drivers/net/ethernet/netronome/nfp/flower/metadata.c

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -528,6 +528,8 @@ int nfp_flower_metadata_init(struct nfp_app *app, u64 host_ctx_count,
528528
if (err)
529529
goto err_free_stats_ctx_table;
530530

531+
mutex_init(&priv->nfp_fl_lock);
532+
531533
err = rhashtable_init(&priv->ct_zone_table, &nfp_zone_table_params);
532534
if (err)
533535
goto err_free_merge_table;

drivers/net/ethernet/netronome/nfp/flower/offload.c

Lines changed: 18 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1009,8 +1009,6 @@ int nfp_flower_merge_offloaded_flows(struct nfp_app *app,
10091009
u64 parent_ctx = 0;
10101010
int err;
10111011

1012-
ASSERT_RTNL();
1013-
10141012
if (sub_flow1 == sub_flow2 ||
10151013
nfp_flower_is_merge_flow(sub_flow1) ||
10161014
nfp_flower_is_merge_flow(sub_flow2))
@@ -1727,19 +1725,30 @@ static int
17271725
nfp_flower_repr_offload(struct nfp_app *app, struct net_device *netdev,
17281726
struct flow_cls_offload *flower)
17291727
{
1728+
struct nfp_flower_priv *priv = app->priv;
1729+
int ret;
1730+
17301731
if (!eth_proto_is_802_3(flower->common.protocol))
17311732
return -EOPNOTSUPP;
17321733

1734+
mutex_lock(&priv->nfp_fl_lock);
17331735
switch (flower->command) {
17341736
case FLOW_CLS_REPLACE:
1735-
return nfp_flower_add_offload(app, netdev, flower);
1737+
ret = nfp_flower_add_offload(app, netdev, flower);
1738+
break;
17361739
case FLOW_CLS_DESTROY:
1737-
return nfp_flower_del_offload(app, netdev, flower);
1740+
ret = nfp_flower_del_offload(app, netdev, flower);
1741+
break;
17381742
case FLOW_CLS_STATS:
1739-
return nfp_flower_get_stats(app, netdev, flower);
1743+
ret = nfp_flower_get_stats(app, netdev, flower);
1744+
break;
17401745
default:
1741-
return -EOPNOTSUPP;
1746+
ret = -EOPNOTSUPP;
1747+
break;
17421748
}
1749+
mutex_unlock(&priv->nfp_fl_lock);
1750+
1751+
return ret;
17431752
}
17441753

17451754
static int nfp_flower_setup_tc_block_cb(enum tc_setup_type type,
@@ -1778,6 +1787,7 @@ static int nfp_flower_setup_tc_block(struct net_device *netdev,
17781787
repr_priv = repr->app_priv;
17791788
repr_priv->block_shared = f->block_shared;
17801789
f->driver_block_list = &nfp_block_cb_list;
1790+
f->unlocked_driver_cb = true;
17811791

17821792
switch (f->command) {
17831793
case FLOW_BLOCK_BIND:
@@ -1876,6 +1886,8 @@ nfp_flower_setup_indr_tc_block(struct net_device *netdev, struct Qdisc *sch, str
18761886
nfp_flower_internal_port_can_offload(app, netdev)))
18771887
return -EOPNOTSUPP;
18781888

1889+
f->unlocked_driver_cb = true;
1890+
18791891
switch (f->command) {
18801892
case FLOW_BLOCK_BIND:
18811893
cb_priv = nfp_flower_indr_block_cb_priv_lookup(app, netdev);

drivers/net/ethernet/netronome/nfp/flower/qos_conf.c

Lines changed: 13 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -523,25 +523,31 @@ int nfp_flower_setup_qos_offload(struct nfp_app *app, struct net_device *netdev,
523523
{
524524
struct netlink_ext_ack *extack = flow->common.extack;
525525
struct nfp_flower_priv *fl_priv = app->priv;
526+
int ret;
526527

527528
if (!(fl_priv->flower_ext_feats & NFP_FL_FEATS_VF_RLIM)) {
528529
NL_SET_ERR_MSG_MOD(extack, "unsupported offload: loaded firmware does not support qos rate limit offload");
529530
return -EOPNOTSUPP;
530531
}
531532

533+
mutex_lock(&fl_priv->nfp_fl_lock);
532534
switch (flow->command) {
533535
case TC_CLSMATCHALL_REPLACE:
534-
return nfp_flower_install_rate_limiter(app, netdev, flow,
535-
extack);
536+
ret = nfp_flower_install_rate_limiter(app, netdev, flow, extack);
537+
break;
536538
case TC_CLSMATCHALL_DESTROY:
537-
return nfp_flower_remove_rate_limiter(app, netdev, flow,
538-
extack);
539+
ret = nfp_flower_remove_rate_limiter(app, netdev, flow, extack);
540+
break;
539541
case TC_CLSMATCHALL_STATS:
540-
return nfp_flower_stats_rate_limiter(app, netdev, flow,
541-
extack);
542+
ret = nfp_flower_stats_rate_limiter(app, netdev, flow, extack);
543+
break;
542544
default:
543-
return -EOPNOTSUPP;
545+
ret = -EOPNOTSUPP;
546+
break;
544547
}
548+
mutex_unlock(&fl_priv->nfp_fl_lock);
549+
550+
return ret;
545551
}
546552

547553
/* Offload tc action, currently only for tc police */

0 commit comments

Comments
 (0)