Commit cd7330c0 authored by Cong Wang's avatar Cong Wang Committed by Greg Kroah-Hartman

act_ife: move tcfa_lock down to where necessary

[ Upstream commit 4e407ff5 ]

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: default avatarVlad Buslov <vladbu@mellanox.com>
Tested-by: default avatarVlad Buslov <vladbu@mellanox.com>
Cc: Vlad Buslov <vladbu@mellanox.com>
Cc: Jamal Hadi Salim <jhs@mojatatu.com>
Signed-off-by: default avatarCong Wang <xiyou.wangcong@gmail.com>
Signed-off-by: default avatarDavid S. Miller <davem@davemloft.net>
Signed-off-by: default avatarGreg Kroah-Hartman <gregkh@linuxfoundation.org>
parent 8aa07625
...@@ -249,10 +249,8 @@ static int ife_validate_metatype(struct tcf_meta_ops *ops, void *val, int len) ...@@ -249,10 +249,8 @@ static int ife_validate_metatype(struct tcf_meta_ops *ops, void *val, int len)
} }
/* called when adding new meta information /* 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, static int load_metaops_and_vet(u32 metaid, void *val, int len)
void *val, int len, bool exists)
{ {
struct tcf_meta_ops *ops = find_ife_oplist(metaid); struct tcf_meta_ops *ops = find_ife_oplist(metaid);
int ret = 0; int ret = 0;
...@@ -260,13 +258,9 @@ static int load_metaops_and_vet(struct tcf_ife_info *ife, u32 metaid, ...@@ -260,13 +258,9 @@ static int load_metaops_and_vet(struct tcf_ife_info *ife, u32 metaid,
if (!ops) { if (!ops) {
ret = -ENOENT; ret = -ENOENT;
#ifdef CONFIG_MODULES #ifdef CONFIG_MODULES
if (exists)
spin_unlock_bh(&ife->tcf_lock);
rtnl_unlock(); rtnl_unlock();
request_module("ifemeta%u", metaid); request_module("ifemeta%u", metaid);
rtnl_lock(); rtnl_lock();
if (exists)
spin_lock_bh(&ife->tcf_lock);
ops = find_ife_oplist(metaid); ops = find_ife_oplist(metaid);
#endif #endif
} }
...@@ -283,10 +277,9 @@ static int load_metaops_and_vet(struct tcf_ife_info *ife, u32 metaid, ...@@ -283,10 +277,9 @@ static int load_metaops_and_vet(struct tcf_ife_info *ife, u32 metaid,
} }
/* called when adding new meta information /* 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, 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_info *mi = NULL;
struct tcf_meta_ops *ops = find_ife_oplist(metaid); struct tcf_meta_ops *ops = find_ife_oplist(metaid);
...@@ -313,12 +306,16 @@ static int add_metainfo(struct tcf_ife_info *ife, u32 metaid, void *metaval, ...@@ -313,12 +306,16 @@ static int add_metainfo(struct tcf_ife_info *ife, u32 metaid, void *metaval,
} }
} }
if (exists)
spin_lock_bh(&ife->tcf_lock);
list_add_tail(&mi->metalist, &ife->metalist); list_add_tail(&mi->metalist, &ife->metalist);
if (exists)
spin_unlock_bh(&ife->tcf_lock);
return ret; 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; struct tcf_meta_ops *o;
int rc = 0; int rc = 0;
...@@ -326,7 +323,7 @@ static int use_all_metadata(struct tcf_ife_info *ife) ...@@ -326,7 +323,7 @@ static int use_all_metadata(struct tcf_ife_info *ife)
read_lock(&ife_mod_lock); read_lock(&ife_mod_lock);
list_for_each_entry(o, &ifeoplist, list) { 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) if (rc == 0)
installed += 1; installed += 1;
} }
...@@ -398,7 +395,6 @@ static void tcf_ife_cleanup(struct tc_action *a, int bind) ...@@ -398,7 +395,6 @@ static void tcf_ife_cleanup(struct tc_action *a, int bind)
spin_unlock_bh(&ife->tcf_lock); spin_unlock_bh(&ife->tcf_lock);
} }
/* under ife->tcf_lock for existing action */
static int populate_metalist(struct tcf_ife_info *ife, struct nlattr **tb, static int populate_metalist(struct tcf_ife_info *ife, struct nlattr **tb,
bool exists) bool exists)
{ {
...@@ -412,11 +408,11 @@ static int populate_metalist(struct tcf_ife_info *ife, struct nlattr **tb, ...@@ -412,11 +408,11 @@ static int populate_metalist(struct tcf_ife_info *ife, struct nlattr **tb,
val = nla_data(tb[i]); val = nla_data(tb[i]);
len = nla_len(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) if (rc != 0)
return rc; return rc;
rc = add_metainfo(ife, i, val, len, exists); rc = add_metainfo(ife, i, val, len, false, exists);
if (rc) if (rc)
return rc; return rc;
} }
...@@ -481,6 +477,8 @@ static int tcf_ife_init(struct net *net, struct nlattr *nla, ...@@ -481,6 +477,8 @@ static int tcf_ife_init(struct net *net, struct nlattr *nla,
if (exists) if (exists)
spin_lock_bh(&ife->tcf_lock); spin_lock_bh(&ife->tcf_lock);
ife->tcf_action = parm->action; ife->tcf_action = parm->action;
if (exists)
spin_unlock_bh(&ife->tcf_lock);
if (parm->flags & IFE_ENCODE) { if (parm->flags & IFE_ENCODE) {
if (daddr) if (daddr)
...@@ -508,9 +506,6 @@ static int tcf_ife_init(struct net *net, struct nlattr *nla, ...@@ -508,9 +506,6 @@ static int tcf_ife_init(struct net *net, struct nlattr *nla,
tcf_idr_release(*a, bind); tcf_idr_release(*a, bind);
if (ret == ACT_P_CREATED) if (ret == ACT_P_CREATED)
_tcf_ife_cleanup(*a, bind); _tcf_ife_cleanup(*a, bind);
if (exists)
spin_unlock_bh(&ife->tcf_lock);
return err; return err;
} }
...@@ -524,20 +519,14 @@ static int tcf_ife_init(struct net *net, struct nlattr *nla, ...@@ -524,20 +519,14 @@ static int tcf_ife_init(struct net *net, struct nlattr *nla,
* as we can. You better have at least one else we are * as we can. You better have at least one else we are
* going to bail out * going to bail out
*/ */
err = use_all_metadata(ife); err = use_all_metadata(ife, exists);
if (err) { if (err) {
if (ret == ACT_P_CREATED) if (ret == ACT_P_CREATED)
_tcf_ife_cleanup(*a, bind); _tcf_ife_cleanup(*a, bind);
if (exists)
spin_unlock_bh(&ife->tcf_lock);
return err; return err;
} }
} }
if (exists)
spin_unlock_bh(&ife->tcf_lock);
if (ret == ACT_P_CREATED) if (ret == ACT_P_CREATED)
tcf_idr_insert(tn, *a); tcf_idr_insert(tn, *a);
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment