act_ife: move tcfa_lock down to where necessary
authorCong Wang <xiyou.wangcong@gmail.com>
Sun, 19 Aug 2018 19:22:12 +0000 (12:22 -0700)
committerGreg Kroah-Hartman <gregkh@linuxfoundation.org>
Sat, 15 Sep 2018 07:42:56 +0000 (09:42 +0200)
[ 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@mellanox.com>
Tested-by: Vlad Buslov <vladbu@mellanox.com>
Cc: Vlad Buslov <vladbu@mellanox.com>
Cc: Jamal Hadi Salim <jhs@mojatatu.com>
Signed-off-by: Cong Wang <xiyou.wangcong@gmail.com>
Signed-off-by: David S. Miller <davem@davemloft.net>
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
net/sched/act_ife.c

index df90ca9..dfcd4e8 100644 (file)
@@ -267,10 +267,8 @@ static int ife_validate_metatype(struct tcf_meta_ops *ops, void *val, int len)
 }
 
 /* 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;
@@ -278,13 +276,9 @@ static int load_metaops_and_vet(struct tcf_ife_info *ife, u32 metaid,
        if (!ops) {
                ret = -ENOENT;
 #ifdef CONFIG_MODULES
-               if (exists)
-                       spin_unlock_bh(&ife->tcf_lock);
                rtnl_unlock();
                request_module("ifemeta%u", metaid);
                rtnl_lock();
-               if (exists)
-                       spin_lock_bh(&ife->tcf_lock);
                ops = find_ife_oplist(metaid);
 #endif
        }
@@ -301,10 +295,9 @@ static int load_metaops_and_vet(struct tcf_ife_info *ife, u32 metaid,
 }
 
 /* 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);
@@ -331,12 +324,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);
+       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;
@@ -344,7 +341,7 @@ static int use_all_metadata(struct tcf_ife_info *ife)
 
        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;
        }
@@ -416,7 +413,6 @@ static void tcf_ife_cleanup(struct tc_action *a, int bind)
        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,
                             bool exists)
 {
@@ -430,11 +426,11 @@ static int populate_metalist(struct tcf_ife_info *ife, struct nlattr **tb,
                        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;
                }
@@ -510,6 +506,8 @@ static int tcf_ife_init(struct net *net, struct nlattr *nla,
        if (exists)
                spin_lock_bh(&ife->tcf_lock);
        ife->tcf_action = parm->action;
+       if (exists)
+               spin_unlock_bh(&ife->tcf_lock);
 
        if (parm->flags & IFE_ENCODE) {
                if (daddr)
@@ -537,9 +535,6 @@ metadata_parse_err:
                                tcf_hash_release(*a, bind);
                        if (ret == ACT_P_CREATED)
                                _tcf_ife_cleanup(*a, bind);
-
-                       if (exists)
-                               spin_unlock_bh(&ife->tcf_lock);
                        return err;
                }
 
@@ -553,20 +548,14 @@ 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_ife_cleanup(*a, bind);
-
-                       if (exists)
-                               spin_unlock_bh(&ife->tcf_lock);
                        return err;
                }
        }
 
-       if (exists)
-               spin_unlock_bh(&ife->tcf_lock);
-
        if (ret == ACT_P_CREATED)
                tcf_hash_insert(tn, *a);