aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorVlad Buslov <vladbu@mellanox.com>2019-08-26 09:45:04 -0400
committerDavid S. Miller <davem@davemloft.net>2019-08-26 17:17:43 -0400
commit5a6ff4b13d598573fc954f672cd2a267b76a01ec (patch)
tree5d0222c2eb4a232f49a9b4f33dddd57ccf982586
parent9838b20a7fb28c69fa66ac8e68d967ffe1d0ecad (diff)
net: sched: take reference to action dev before calling offloads
In order to remove dependency on rtnl lock when calling hardware offload API, take reference to action mirred dev when initializing flow_action structure in tc_setup_flow_action(). Implement function tc_cleanup_flow_action(), use it to release the device after hardware offload API is done using it. Signed-off-by: Vlad Buslov <vladbu@mellanox.com> Acked-by: Jiri Pirko <jiri@mellanox.com> Signed-off-by: David S. Miller <davem@davemloft.net>
-rw-r--r--include/net/pkt_cls.h2
-rw-r--r--net/sched/cls_api.c32
-rw-r--r--net/sched/cls_flower.c2
3 files changed, 36 insertions, 0 deletions
diff --git a/include/net/pkt_cls.h b/include/net/pkt_cls.h
index a48824bc1489..e553fc80eb23 100644
--- a/include/net/pkt_cls.h
+++ b/include/net/pkt_cls.h
@@ -505,6 +505,8 @@ tcf_match_indev(struct sk_buff *skb, int ifindex)
505 505
506int tc_setup_flow_action(struct flow_action *flow_action, 506int tc_setup_flow_action(struct flow_action *flow_action,
507 const struct tcf_exts *exts, bool rtnl_held); 507 const struct tcf_exts *exts, bool rtnl_held);
508void tc_cleanup_flow_action(struct flow_action *flow_action);
509
508int tc_setup_cb_call(struct tcf_block *block, enum tc_setup_type type, 510int tc_setup_cb_call(struct tcf_block *block, enum tc_setup_type type,
509 void *type_data, bool err_stop, bool rtnl_held); 511 void *type_data, bool err_stop, bool rtnl_held);
510int tc_setup_cb_add(struct tcf_block *block, struct tcf_proto *tp, 512int tc_setup_cb_add(struct tcf_block *block, struct tcf_proto *tp,
diff --git a/net/sched/cls_api.c b/net/sched/cls_api.c
index 8751bb8a682f..d988737693e4 100644
--- a/net/sched/cls_api.c
+++ b/net/sched/cls_api.c
@@ -3265,6 +3265,27 @@ int tc_setup_cb_reoffload(struct tcf_block *block, struct tcf_proto *tp,
3265} 3265}
3266EXPORT_SYMBOL(tc_setup_cb_reoffload); 3266EXPORT_SYMBOL(tc_setup_cb_reoffload);
3267 3267
3268void tc_cleanup_flow_action(struct flow_action *flow_action)
3269{
3270 struct flow_action_entry *entry;
3271 int i;
3272
3273 flow_action_for_each(i, entry, flow_action) {
3274 switch (entry->id) {
3275 case FLOW_ACTION_REDIRECT:
3276 case FLOW_ACTION_MIRRED:
3277 case FLOW_ACTION_REDIRECT_INGRESS:
3278 case FLOW_ACTION_MIRRED_INGRESS:
3279 if (entry->dev)
3280 dev_put(entry->dev);
3281 break;
3282 default:
3283 break;
3284 }
3285 }
3286}
3287EXPORT_SYMBOL(tc_cleanup_flow_action);
3288
3268int tc_setup_flow_action(struct flow_action *flow_action, 3289int tc_setup_flow_action(struct flow_action *flow_action,
3269 const struct tcf_exts *exts, bool rtnl_held) 3290 const struct tcf_exts *exts, bool rtnl_held)
3270{ 3291{
@@ -3294,15 +3315,23 @@ int tc_setup_flow_action(struct flow_action *flow_action,
3294 } else if (is_tcf_mirred_egress_redirect(act)) { 3315 } else if (is_tcf_mirred_egress_redirect(act)) {
3295 entry->id = FLOW_ACTION_REDIRECT; 3316 entry->id = FLOW_ACTION_REDIRECT;
3296 entry->dev = tcf_mirred_dev(act); 3317 entry->dev = tcf_mirred_dev(act);
3318 if (entry->dev)
3319 dev_hold(entry->dev);
3297 } else if (is_tcf_mirred_egress_mirror(act)) { 3320 } else if (is_tcf_mirred_egress_mirror(act)) {
3298 entry->id = FLOW_ACTION_MIRRED; 3321 entry->id = FLOW_ACTION_MIRRED;
3299 entry->dev = tcf_mirred_dev(act); 3322 entry->dev = tcf_mirred_dev(act);
3323 if (entry->dev)
3324 dev_hold(entry->dev);
3300 } else if (is_tcf_mirred_ingress_redirect(act)) { 3325 } else if (is_tcf_mirred_ingress_redirect(act)) {
3301 entry->id = FLOW_ACTION_REDIRECT_INGRESS; 3326 entry->id = FLOW_ACTION_REDIRECT_INGRESS;
3302 entry->dev = tcf_mirred_dev(act); 3327 entry->dev = tcf_mirred_dev(act);
3328 if (entry->dev)
3329 dev_hold(entry->dev);
3303 } else if (is_tcf_mirred_ingress_mirror(act)) { 3330 } else if (is_tcf_mirred_ingress_mirror(act)) {
3304 entry->id = FLOW_ACTION_MIRRED_INGRESS; 3331 entry->id = FLOW_ACTION_MIRRED_INGRESS;
3305 entry->dev = tcf_mirred_dev(act); 3332 entry->dev = tcf_mirred_dev(act);
3333 if (entry->dev)
3334 dev_hold(entry->dev);
3306 } else if (is_tcf_vlan(act)) { 3335 } else if (is_tcf_vlan(act)) {
3307 switch (tcf_vlan_action(act)) { 3336 switch (tcf_vlan_action(act)) {
3308 case TCA_VLAN_ACT_PUSH: 3337 case TCA_VLAN_ACT_PUSH:
@@ -3410,6 +3439,9 @@ err_out:
3410 if (!rtnl_held) 3439 if (!rtnl_held)
3411 rtnl_unlock(); 3440 rtnl_unlock();
3412 3441
3442 if (err)
3443 tc_cleanup_flow_action(flow_action);
3444
3413 return err; 3445 return err;
3414} 3446}
3415EXPORT_SYMBOL(tc_setup_flow_action); 3447EXPORT_SYMBOL(tc_setup_flow_action);
diff --git a/net/sched/cls_flower.c b/net/sched/cls_flower.c
index fb305bd45d93..2852fe6f50d2 100644
--- a/net/sched/cls_flower.c
+++ b/net/sched/cls_flower.c
@@ -465,6 +465,7 @@ static int fl_hw_replace_filter(struct tcf_proto *tp,
465 465
466 err = tc_setup_cb_add(block, tp, TC_SETUP_CLSFLOWER, &cls_flower, 466 err = tc_setup_cb_add(block, tp, TC_SETUP_CLSFLOWER, &cls_flower,
467 skip_sw, &f->flags, &f->in_hw_count, true); 467 skip_sw, &f->flags, &f->in_hw_count, true);
468 tc_cleanup_flow_action(&cls_flower.rule->action);
468 kfree(cls_flower.rule); 469 kfree(cls_flower.rule);
469 470
470 if (err) { 471 if (err) {
@@ -1838,6 +1839,7 @@ static int fl_reoffload(struct tcf_proto *tp, bool add, flow_setup_cb_t *cb,
1838 TC_SETUP_CLSFLOWER, &cls_flower, 1839 TC_SETUP_CLSFLOWER, &cls_flower,
1839 cb_priv, &f->flags, 1840 cb_priv, &f->flags,
1840 &f->in_hw_count); 1841 &f->in_hw_count);
1842 tc_cleanup_flow_action(&cls_flower.rule->action);
1841 kfree(cls_flower.rule); 1843 kfree(cls_flower.rule);
1842 1844
1843 if (err) { 1845 if (err) {