Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

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>

authored by

Vlad Buslov and committed by
David S. Miller
5a6ff4b1 9838b20a

+36
+2
include/net/pkt_cls.h
··· 505 505 506 506 int tc_setup_flow_action(struct flow_action *flow_action, 507 507 const struct tcf_exts *exts, bool rtnl_held); 508 + void tc_cleanup_flow_action(struct flow_action *flow_action); 509 + 508 510 int tc_setup_cb_call(struct tcf_block *block, enum tc_setup_type type, 509 511 void *type_data, bool err_stop, bool rtnl_held); 510 512 int tc_setup_cb_add(struct tcf_block *block, struct tcf_proto *tp,
+32
net/sched/cls_api.c
··· 3265 3265 } 3266 3266 EXPORT_SYMBOL(tc_setup_cb_reoffload); 3267 3267 3268 + void 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 + } 3287 + EXPORT_SYMBOL(tc_cleanup_flow_action); 3288 + 3268 3289 int tc_setup_flow_action(struct flow_action *flow_action, 3269 3290 const struct tcf_exts *exts, bool rtnl_held) 3270 3291 { ··· 3315 3294 } else if (is_tcf_mirred_egress_redirect(act)) { 3316 3295 entry->id = FLOW_ACTION_REDIRECT; 3317 3296 entry->dev = tcf_mirred_dev(act); 3297 + if (entry->dev) 3298 + dev_hold(entry->dev); 3318 3299 } else if (is_tcf_mirred_egress_mirror(act)) { 3319 3300 entry->id = FLOW_ACTION_MIRRED; 3320 3301 entry->dev = tcf_mirred_dev(act); 3302 + if (entry->dev) 3303 + dev_hold(entry->dev); 3321 3304 } else if (is_tcf_mirred_ingress_redirect(act)) { 3322 3305 entry->id = FLOW_ACTION_REDIRECT_INGRESS; 3323 3306 entry->dev = tcf_mirred_dev(act); 3307 + if (entry->dev) 3308 + dev_hold(entry->dev); 3324 3309 } else if (is_tcf_mirred_ingress_mirror(act)) { 3325 3310 entry->id = FLOW_ACTION_MIRRED_INGRESS; 3326 3311 entry->dev = tcf_mirred_dev(act); 3312 + if (entry->dev) 3313 + dev_hold(entry->dev); 3327 3314 } else if (is_tcf_vlan(act)) { 3328 3315 switch (tcf_vlan_action(act)) { 3329 3316 case TCA_VLAN_ACT_PUSH: ··· 3438 3409 err_out: 3439 3410 if (!rtnl_held) 3440 3411 rtnl_unlock(); 3412 + 3413 + if (err) 3414 + tc_cleanup_flow_action(flow_action); 3441 3415 3442 3416 return err; 3443 3417 }
+2
net/sched/cls_flower.c
··· 465 465 466 466 err = tc_setup_cb_add(block, tp, TC_SETUP_CLSFLOWER, &cls_flower, 467 467 skip_sw, &f->flags, &f->in_hw_count, true); 468 + tc_cleanup_flow_action(&cls_flower.rule->action); 468 469 kfree(cls_flower.rule); 469 470 470 471 if (err) { ··· 1839 1838 TC_SETUP_CLSFLOWER, &cls_flower, 1840 1839 cb_priv, &f->flags, 1841 1840 &f->in_hw_count); 1841 + tc_cleanup_flow_action(&cls_flower.rule->action); 1842 1842 kfree(cls_flower.rule); 1843 1843 1844 1844 if (err) {