[PATCH 4.18 011/197] act_ife: move tcfa_lock down to where necessary

From: Greg Kroah-Hartman
Date: Thu Sep 13 2018 - 09:50:28 EST


4.18-stable review patch. If anyone has any objections, please let me know.

------------------

From: Cong Wang <xiyou.wangcong@xxxxxxxxx>

[ Upstream commit 4e407ff5cd67ec76eeeea1deec227b7982dc7f66 ]

The only time we need to take tcfa_lock is when adding
a new metainfo to an existing ife->metalist. We don't need
to take tcfa_lock so early and so broadly in tcf_ife_init().

This means we can always take ife_mod_lock first, avoid the
reverse locking ordering warning as reported by Vlad.

Reported-by: Vlad Buslov <vladbu@xxxxxxxxxxxx>
Tested-by: Vlad Buslov <vladbu@xxxxxxxxxxxx>
Cc: Vlad Buslov <vladbu@xxxxxxxxxxxx>
Cc: Jamal Hadi Salim <jhs@xxxxxxxxxxxx>
Signed-off-by: Cong Wang <xiyou.wangcong@xxxxxxxxx>
Signed-off-by: David S. Miller <davem@xxxxxxxxxxxxx>
Signed-off-by: Greg Kroah-Hartman <gregkh@xxxxxxxxxxxxxxxxxxx>
---
net/sched/act_ife.c | 36 +++++++++++++-----------------------
1 file changed, 13 insertions(+), 23 deletions(-)

--- a/net/sched/act_ife.c
+++ b/net/sched/act_ife.c
@@ -265,10 +265,8 @@ static const char *ife_meta_id2name(u32
#endif

/* called when adding new meta information
- * under ife->tcf_lock for existing action
*/
-static int load_metaops_and_vet(struct tcf_ife_info *ife, u32 metaid,
- void *val, int len, bool exists)
+static int load_metaops_and_vet(u32 metaid, void *val, int len)
{
struct tcf_meta_ops *ops = find_ife_oplist(metaid);
int ret = 0;
@@ -276,13 +274,9 @@ static int load_metaops_and_vet(struct t
if (!ops) {
ret = -ENOENT;
#ifdef CONFIG_MODULES
- if (exists)
- spin_unlock_bh(&ife->tcf_lock);
rtnl_unlock();
request_module("ife-meta-%s", ife_meta_id2name(metaid));
rtnl_lock();
- if (exists)
- spin_lock_bh(&ife->tcf_lock);
ops = find_ife_oplist(metaid);
#endif
}
@@ -299,10 +293,9 @@ static int load_metaops_and_vet(struct t
}

/* called when adding new meta information
- * under ife->tcf_lock for existing action
*/
static int add_metainfo(struct tcf_ife_info *ife, u32 metaid, void *metaval,
- int len, bool atomic)
+ int len, bool atomic, bool exists)
{
struct tcf_meta_info *mi = NULL;
struct tcf_meta_ops *ops = find_ife_oplist(metaid);
@@ -329,12 +322,16 @@ static int add_metainfo(struct tcf_ife_i
}
}

+ if (exists)
+ spin_lock_bh(&ife->tcf_lock);
list_add_tail(&mi->metalist, &ife->metalist);
+ if (exists)
+ spin_unlock_bh(&ife->tcf_lock);

return ret;
}

-static int use_all_metadata(struct tcf_ife_info *ife)
+static int use_all_metadata(struct tcf_ife_info *ife, bool exists)
{
struct tcf_meta_ops *o;
int rc = 0;
@@ -342,7 +339,7 @@ static int use_all_metadata(struct tcf_i

read_lock(&ife_mod_lock);
list_for_each_entry(o, &ifeoplist, list) {
- rc = add_metainfo(ife, o->metaid, NULL, 0, true);
+ rc = add_metainfo(ife, o->metaid, NULL, 0, true, exists);
if (rc == 0)
installed += 1;
}
@@ -419,7 +416,6 @@ static void tcf_ife_cleanup(struct tc_ac
kfree_rcu(p, rcu);
}

-/* under ife->tcf_lock for existing action */
static int populate_metalist(struct tcf_ife_info *ife, struct nlattr **tb,
bool exists)
{
@@ -433,11 +429,11 @@ static int populate_metalist(struct tcf_
val = nla_data(tb[i]);
len = nla_len(tb[i]);

- rc = load_metaops_and_vet(ife, i, val, len, exists);
+ rc = load_metaops_and_vet(i, val, len);
if (rc != 0)
return rc;

- rc = add_metainfo(ife, i, val, len, exists);
+ rc = add_metainfo(ife, i, val, len, false, exists);
if (rc)
return rc;
}
@@ -531,8 +527,6 @@ static int tcf_ife_init(struct net *net,
p->eth_type = ife_type;
}

- if (exists)
- spin_lock_bh(&ife->tcf_lock);

if (ret == ACT_P_CREATED)
INIT_LIST_HEAD(&ife->metalist);
@@ -544,9 +538,6 @@ static int tcf_ife_init(struct net *net,
metadata_parse_err:
if (ret == ACT_P_CREATED)
tcf_idr_release(*a, bind);
-
- if (exists)
- spin_unlock_bh(&ife->tcf_lock);
kfree(p);
return err;
}
@@ -561,18 +552,17 @@ metadata_parse_err:
* as we can. You better have at least one else we are
* going to bail out
*/
- err = use_all_metadata(ife);
+ err = use_all_metadata(ife, exists);
if (err) {
if (ret == ACT_P_CREATED)
tcf_idr_release(*a, bind);
-
- if (exists)
- spin_unlock_bh(&ife->tcf_lock);
kfree(p);
return err;
}
}

+ if (exists)
+ spin_lock_bh(&ife->tcf_lock);
ife->tcf_action = parm->action;
if (exists)
spin_unlock_bh(&ife->tcf_lock);