net: sched: lock action when translating it to flow_action infra
In order to remove dependency on rtnl lock, take action's tcfa_lock when constructing its representation as flow_action_entry structure. Refactor tcf_sample_get_group() to assume that caller holds tcf_lock and don't take it manually. This callback is only called from flow_action infra representation translator which now calls it with tcf_lock held, so this refactoring is necessary to prevent deadlock. Allocate memory with GFP_ATOMIC flag for ip_tunnel_info copy because tcf_tunnel_info_copy() is only called from flow_action representation infra code with tcf_lock spinlock taken. Signed-off-by: Vlad Buslov <vladbu@mellanox.com> Acked-by: Jiri Pirko <jiri@mellanox.com> Signed-off-by: David S. Miller <davem@davemloft.net>
This commit is contained in:
parent
92df9f8a74
commit
7a47281439
|
@ -69,7 +69,7 @@ tcf_tunnel_info_copy(const struct tc_action *a)
|
||||||
if (tun) {
|
if (tun) {
|
||||||
size_t tun_size = sizeof(*tun) + tun->options_len;
|
size_t tun_size = sizeof(*tun) + tun->options_len;
|
||||||
struct ip_tunnel_info *tun_copy = kmemdup(tun, tun_size,
|
struct ip_tunnel_info *tun_copy = kmemdup(tun, tun_size,
|
||||||
GFP_KERNEL);
|
GFP_ATOMIC);
|
||||||
|
|
||||||
return tun_copy;
|
return tun_copy;
|
||||||
}
|
}
|
||||||
|
|
|
@ -267,14 +267,12 @@ tcf_sample_get_group(const struct tc_action *a,
|
||||||
struct tcf_sample *s = to_sample(a);
|
struct tcf_sample *s = to_sample(a);
|
||||||
struct psample_group *group;
|
struct psample_group *group;
|
||||||
|
|
||||||
spin_lock_bh(&s->tcf_lock);
|
|
||||||
group = rcu_dereference_protected(s->psample_group,
|
group = rcu_dereference_protected(s->psample_group,
|
||||||
lockdep_is_held(&s->tcf_lock));
|
lockdep_is_held(&s->tcf_lock));
|
||||||
if (group) {
|
if (group) {
|
||||||
psample_group_take(group);
|
psample_group_take(group);
|
||||||
*destructor = tcf_psample_group_put;
|
*destructor = tcf_psample_group_put;
|
||||||
}
|
}
|
||||||
spin_unlock_bh(&s->tcf_lock);
|
|
||||||
|
|
||||||
return group;
|
return group;
|
||||||
}
|
}
|
||||||
|
|
|
@ -3435,7 +3435,7 @@ static void tcf_sample_get_group(struct flow_action_entry *entry,
|
||||||
int tc_setup_flow_action(struct flow_action *flow_action,
|
int tc_setup_flow_action(struct flow_action *flow_action,
|
||||||
const struct tcf_exts *exts, bool rtnl_held)
|
const struct tcf_exts *exts, bool rtnl_held)
|
||||||
{
|
{
|
||||||
const struct tc_action *act;
|
struct tc_action *act;
|
||||||
int i, j, k, err = 0;
|
int i, j, k, err = 0;
|
||||||
|
|
||||||
if (!exts)
|
if (!exts)
|
||||||
|
@ -3449,6 +3449,7 @@ int tc_setup_flow_action(struct flow_action *flow_action,
|
||||||
struct flow_action_entry *entry;
|
struct flow_action_entry *entry;
|
||||||
|
|
||||||
entry = &flow_action->entries[j];
|
entry = &flow_action->entries[j];
|
||||||
|
spin_lock_bh(&act->tcfa_lock);
|
||||||
if (is_tcf_gact_ok(act)) {
|
if (is_tcf_gact_ok(act)) {
|
||||||
entry->id = FLOW_ACTION_ACCEPT;
|
entry->id = FLOW_ACTION_ACCEPT;
|
||||||
} else if (is_tcf_gact_shot(act)) {
|
} else if (is_tcf_gact_shot(act)) {
|
||||||
|
@ -3489,13 +3490,13 @@ int tc_setup_flow_action(struct flow_action *flow_action,
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
err = -EOPNOTSUPP;
|
err = -EOPNOTSUPP;
|
||||||
goto err_out;
|
goto err_out_locked;
|
||||||
}
|
}
|
||||||
} else if (is_tcf_tunnel_set(act)) {
|
} else if (is_tcf_tunnel_set(act)) {
|
||||||
entry->id = FLOW_ACTION_TUNNEL_ENCAP;
|
entry->id = FLOW_ACTION_TUNNEL_ENCAP;
|
||||||
err = tcf_tunnel_encap_get_tunnel(entry, act);
|
err = tcf_tunnel_encap_get_tunnel(entry, act);
|
||||||
if (err)
|
if (err)
|
||||||
goto err_out;
|
goto err_out_locked;
|
||||||
} else if (is_tcf_tunnel_release(act)) {
|
} else if (is_tcf_tunnel_release(act)) {
|
||||||
entry->id = FLOW_ACTION_TUNNEL_DECAP;
|
entry->id = FLOW_ACTION_TUNNEL_DECAP;
|
||||||
} else if (is_tcf_pedit(act)) {
|
} else if (is_tcf_pedit(act)) {
|
||||||
|
@ -3509,7 +3510,7 @@ int tc_setup_flow_action(struct flow_action *flow_action,
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
err = -EOPNOTSUPP;
|
err = -EOPNOTSUPP;
|
||||||
goto err_out;
|
goto err_out_locked;
|
||||||
}
|
}
|
||||||
entry->mangle.htype = tcf_pedit_htype(act, k);
|
entry->mangle.htype = tcf_pedit_htype(act, k);
|
||||||
entry->mangle.mask = tcf_pedit_mask(act, k);
|
entry->mangle.mask = tcf_pedit_mask(act, k);
|
||||||
|
@ -3560,15 +3561,16 @@ int tc_setup_flow_action(struct flow_action *flow_action,
|
||||||
entry->mpls_mangle.ttl = tcf_mpls_ttl(act);
|
entry->mpls_mangle.ttl = tcf_mpls_ttl(act);
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
goto err_out;
|
goto err_out_locked;
|
||||||
}
|
}
|
||||||
} else if (is_tcf_skbedit_ptype(act)) {
|
} else if (is_tcf_skbedit_ptype(act)) {
|
||||||
entry->id = FLOW_ACTION_PTYPE;
|
entry->id = FLOW_ACTION_PTYPE;
|
||||||
entry->ptype = tcf_skbedit_ptype(act);
|
entry->ptype = tcf_skbedit_ptype(act);
|
||||||
} else {
|
} else {
|
||||||
err = -EOPNOTSUPP;
|
err = -EOPNOTSUPP;
|
||||||
goto err_out;
|
goto err_out_locked;
|
||||||
}
|
}
|
||||||
|
spin_unlock_bh(&act->tcfa_lock);
|
||||||
|
|
||||||
if (!is_tcf_pedit(act))
|
if (!is_tcf_pedit(act))
|
||||||
j++;
|
j++;
|
||||||
|
@ -3582,6 +3584,9 @@ err_out:
|
||||||
tc_cleanup_flow_action(flow_action);
|
tc_cleanup_flow_action(flow_action);
|
||||||
|
|
||||||
return err;
|
return err;
|
||||||
|
err_out_locked:
|
||||||
|
spin_unlock_bh(&act->tcfa_lock);
|
||||||
|
goto err_out;
|
||||||
}
|
}
|
||||||
EXPORT_SYMBOL(tc_setup_flow_action);
|
EXPORT_SYMBOL(tc_setup_flow_action);
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue