net: sched: lock action when translating it to flow_action infra
authorVlad Buslov <vladbu@mellanox.com>
Mon, 17 Feb 2020 10:12:09 +0000 (12:12 +0200)
committerDavid S. Miller <davem@davemloft.net>
Mon, 17 Feb 2020 22:17:02 +0000 (14:17 -0800)
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>
include/net/tc_act/tc_tunnel_key.h
net/sched/act_sample.c
net/sched/cls_api.c

index 0689d9b..2b3df07 100644 (file)
@@ -69,7 +69,7 @@ tcf_tunnel_info_copy(const struct tc_action *a)
        if (tun) {
                size_t tun_size = sizeof(*tun) + tun->options_len;
                struct ip_tunnel_info *tun_copy = kmemdup(tun, tun_size,
-                                                         GFP_KERNEL);
+                                                         GFP_ATOMIC);
 
                return tun_copy;
        }
index ce948c1..5e2df59 100644 (file)
@@ -267,14 +267,12 @@ tcf_sample_get_group(const struct tc_action *a,
        struct tcf_sample *s = to_sample(a);
        struct psample_group *group;
 
-       spin_lock_bh(&s->tcf_lock);
        group = rcu_dereference_protected(s->psample_group,
                                          lockdep_is_held(&s->tcf_lock));
        if (group) {
                psample_group_take(group);
                *destructor = tcf_psample_group_put;
        }
-       spin_unlock_bh(&s->tcf_lock);
 
        return group;
 }
index c2cdd0f..6105051 100644 (file)
@@ -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,
                         const struct tcf_exts *exts, bool rtnl_held)
 {
-       const struct tc_action *act;
+       struct tc_action *act;
        int i, j, k, err = 0;
 
        if (!exts)
@@ -3449,6 +3449,7 @@ int tc_setup_flow_action(struct flow_action *flow_action,
                struct flow_action_entry *entry;
 
                entry = &flow_action->entries[j];
+               spin_lock_bh(&act->tcfa_lock);
                if (is_tcf_gact_ok(act)) {
                        entry->id = FLOW_ACTION_ACCEPT;
                } else if (is_tcf_gact_shot(act)) {
@@ -3489,13 +3490,13 @@ int tc_setup_flow_action(struct flow_action *flow_action,
                                break;
                        default:
                                err = -EOPNOTSUPP;
-                               goto err_out;
+                               goto err_out_locked;
                        }
                } else if (is_tcf_tunnel_set(act)) {
                        entry->id = FLOW_ACTION_TUNNEL_ENCAP;
                        err = tcf_tunnel_encap_get_tunnel(entry, act);
                        if (err)
-                               goto err_out;
+                               goto err_out_locked;
                } else if (is_tcf_tunnel_release(act)) {
                        entry->id = FLOW_ACTION_TUNNEL_DECAP;
                } else if (is_tcf_pedit(act)) {
@@ -3509,7 +3510,7 @@ int tc_setup_flow_action(struct flow_action *flow_action,
                                        break;
                                default:
                                        err = -EOPNOTSUPP;
-                                       goto err_out;
+                                       goto err_out_locked;
                                }
                                entry->mangle.htype = tcf_pedit_htype(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);
                                break;
                        default:
-                               goto err_out;
+                               goto err_out_locked;
                        }
                } else if (is_tcf_skbedit_ptype(act)) {
                        entry->id = FLOW_ACTION_PTYPE;
                        entry->ptype = tcf_skbedit_ptype(act);
                } else {
                        err = -EOPNOTSUPP;
-                       goto err_out;
+                       goto err_out_locked;
                }
+               spin_unlock_bh(&act->tcfa_lock);
 
                if (!is_tcf_pedit(act))
                        j++;
@@ -3582,6 +3584,9 @@ err_out:
                tc_cleanup_flow_action(flow_action);
 
        return err;
+err_out_locked:
+       spin_unlock_bh(&act->tcfa_lock);
+       goto err_out;
 }
 EXPORT_SYMBOL(tc_setup_flow_action);