net: sched: extend proto ops to support unlocked classifiers
authorVlad Buslov <vladbu@mellanox.com>
Mon, 11 Feb 2019 08:55:45 +0000 (10:55 +0200)
committerDavid S. Miller <davem@davemloft.net>
Tue, 12 Feb 2019 18:41:33 +0000 (13:41 -0500)
Add 'rtnl_held' flag to tcf proto change, delete, destroy, dump, walk
functions to track rtnl lock status. Extend users of these function in cls
API to propagate rtnl lock status to them. This allows classifiers to
obtain rtnl lock when necessary and to pass rtnl lock status to extensions
and driver offload callbacks.

Add flags field to tcf proto ops. Add flag value to indicate that
classifier doesn't require rtnl lock.

Signed-off-by: Vlad Buslov <vladbu@mellanox.com>
Acked-by: Jiri Pirko <jiri@mellanox.com>
Signed-off-by: David S. Miller <davem@davemloft.net>
15 files changed:
include/net/pkt_cls.h
include/net/sch_generic.h
net/sched/cls_api.c
net/sched/cls_basic.c
net/sched/cls_bpf.c
net/sched/cls_cgroup.c
net/sched/cls_flow.c
net/sched/cls_flower.c
net/sched/cls_fw.c
net/sched/cls_matchall.c
net/sched/cls_route.c
net/sched/cls_rsvp.h
net/sched/cls_tcindex.c
net/sched/cls_u32.c
net/sched/sch_api.c

index 0e3b6101693144c95f5e70f31cd12cd44c313c5a..6a530bef92538d8c9d96579925106bce3994d73b 100644 (file)
@@ -47,7 +47,7 @@ void tcf_chain_put_by_act(struct tcf_chain *chain);
 struct tcf_chain *tcf_get_next_chain(struct tcf_block *block,
                                     struct tcf_chain *chain);
 struct tcf_proto *tcf_get_next_proto(struct tcf_chain *chain,
-                                    struct tcf_proto *tp);
+                                    struct tcf_proto *tp, bool rtnl_held);
 void tcf_block_netif_keep_dst(struct tcf_block *block);
 int tcf_block_get(struct tcf_block **p_block,
                  struct tcf_proto __rcu **p_filter_chain, struct Qdisc *q,
index 410dda80ca620cbaba624001216e559d1a4f5307..365801c2a4f5cd62e7247dde5938ce32608230a3 100644 (file)
@@ -273,7 +273,7 @@ struct tcf_proto_ops {
                                            const struct tcf_proto *,
                                            struct tcf_result *);
        int                     (*init)(struct tcf_proto*);
-       void                    (*destroy)(struct tcf_proto *tp,
+       void                    (*destroy)(struct tcf_proto *tp, bool rtnl_held,
                                           struct netlink_ext_ack *extack);
 
        void*                   (*get)(struct tcf_proto*, u32 handle);
@@ -281,12 +281,13 @@ struct tcf_proto_ops {
        int                     (*change)(struct net *net, struct sk_buff *,
                                        struct tcf_proto*, unsigned long,
                                        u32 handle, struct nlattr **,
-                                       void **, bool,
+                                       void **, bool, bool,
                                        struct netlink_ext_ack *);
        int                     (*delete)(struct tcf_proto *tp, void *arg,
-                                         bool *last,
+                                         bool *last, bool rtnl_held,
                                          struct netlink_ext_ack *);
-       void                    (*walk)(struct tcf_proto*, struct tcf_walker *arg);
+       void                    (*walk)(struct tcf_proto *tp,
+                                       struct tcf_walker *arg, bool rtnl_held);
        int                     (*reoffload)(struct tcf_proto *tp, bool add,
                                             tc_setup_cb_t *cb, void *cb_priv,
                                             struct netlink_ext_ack *extack);
@@ -299,12 +300,18 @@ struct tcf_proto_ops {
 
        /* rtnetlink specific */
        int                     (*dump)(struct net*, struct tcf_proto*, void *,
-                                       struct sk_buff *skb, struct tcmsg*);
+                                       struct sk_buff *skb, struct tcmsg*,
+                                       bool);
        int                     (*tmplt_dump)(struct sk_buff *skb,
                                              struct net *net,
                                              void *tmplt_priv);
 
        struct module           *owner;
+       int                     flags;
+};
+
+enum tcf_proto_ops_flags {
+       TCF_PROTO_OPS_DOIT_UNLOCKED = 1,
 };
 
 struct tcf_proto {
index 8fe38aa180cfb8ae938708ad83761f72fd30e969..e8ed461e94af5a3bae84621a5b0583d7856df252 100644 (file)
@@ -69,7 +69,8 @@ static const struct tcf_proto_ops *__tcf_proto_lookup_ops(const char *kind)
 }
 
 static const struct tcf_proto_ops *
-tcf_proto_lookup_ops(const char *kind, struct netlink_ext_ack *extack)
+tcf_proto_lookup_ops(const char *kind, bool rtnl_held,
+                    struct netlink_ext_ack *extack)
 {
        const struct tcf_proto_ops *ops;
 
@@ -77,9 +78,11 @@ tcf_proto_lookup_ops(const char *kind, struct netlink_ext_ack *extack)
        if (ops)
                return ops;
 #ifdef CONFIG_MODULES
-       rtnl_unlock();
+       if (rtnl_held)
+               rtnl_unlock();
        request_module("cls_%s", kind);
-       rtnl_lock();
+       if (rtnl_held)
+               rtnl_lock();
        ops = __tcf_proto_lookup_ops(kind);
        /* We dropped the RTNL semaphore in order to perform
         * the module load. So, even if we succeeded in loading
@@ -162,6 +165,7 @@ static inline u32 tcf_auto_prio(struct tcf_proto *tp)
 
 static struct tcf_proto *tcf_proto_create(const char *kind, u32 protocol,
                                          u32 prio, struct tcf_chain *chain,
+                                         bool rtnl_held,
                                          struct netlink_ext_ack *extack)
 {
        struct tcf_proto *tp;
@@ -171,7 +175,7 @@ static struct tcf_proto *tcf_proto_create(const char *kind, u32 protocol,
        if (!tp)
                return ERR_PTR(-ENOBUFS);
 
-       tp->ops = tcf_proto_lookup_ops(kind, extack);
+       tp->ops = tcf_proto_lookup_ops(kind, rtnl_held, extack);
        if (IS_ERR(tp->ops)) {
                err = PTR_ERR(tp->ops);
                goto errout;
@@ -202,20 +206,20 @@ static void tcf_proto_get(struct tcf_proto *tp)
 
 static void tcf_chain_put(struct tcf_chain *chain);
 
-static void tcf_proto_destroy(struct tcf_proto *tp,
+static void tcf_proto_destroy(struct tcf_proto *tp, bool rtnl_held,
                              struct netlink_ext_ack *extack)
 {
-       tp->ops->destroy(tp, extack);
+       tp->ops->destroy(tp, rtnl_held, extack);
        tcf_chain_put(tp->chain);
        module_put(tp->ops->owner);
        kfree_rcu(tp, rcu);
 }
 
-static void tcf_proto_put(struct tcf_proto *tp,
+static void tcf_proto_put(struct tcf_proto *tp, bool rtnl_held,
                          struct netlink_ext_ack *extack)
 {
        if (refcount_dec_and_test(&tp->refcnt))
-               tcf_proto_destroy(tp, extack);
+               tcf_proto_destroy(tp, rtnl_held, extack);
 }
 
 static int walker_noop(struct tcf_proto *tp, void *d, struct tcf_walker *arg)
@@ -223,21 +227,21 @@ static int walker_noop(struct tcf_proto *tp, void *d, struct tcf_walker *arg)
        return -1;
 }
 
-static bool tcf_proto_is_empty(struct tcf_proto *tp)
+static bool tcf_proto_is_empty(struct tcf_proto *tp, bool rtnl_held)
 {
        struct tcf_walker walker = { .fn = walker_noop, };
 
        if (tp->ops->walk) {
-               tp->ops->walk(tp, &walker);
+               tp->ops->walk(tp, &walker, rtnl_held);
                return !walker.stop;
        }
        return true;
 }
 
-static bool tcf_proto_check_delete(struct tcf_proto *tp)
+static bool tcf_proto_check_delete(struct tcf_proto *tp, bool rtnl_held)
 {
        spin_lock(&tp->lock);
-       if (tcf_proto_is_empty(tp))
+       if (tcf_proto_is_empty(tp, rtnl_held))
                tp->deleting = true;
        spin_unlock(&tp->lock);
        return tp->deleting;
@@ -506,7 +510,7 @@ static void tcf_chain_put_explicitly_created(struct tcf_chain *chain)
        __tcf_chain_put(chain, false, true);
 }
 
-static void tcf_chain_flush(struct tcf_chain *chain)
+static void tcf_chain_flush(struct tcf_chain *chain, bool rtnl_held)
 {
        struct tcf_proto *tp, *tp_next;
 
@@ -519,7 +523,7 @@ static void tcf_chain_flush(struct tcf_chain *chain)
 
        while (tp) {
                tp_next = rcu_dereference_protected(tp->next, 1);
-               tcf_proto_put(tp, NULL);
+               tcf_proto_put(tp, rtnl_held, NULL);
                tp = tp_next;
        }
 }
@@ -1070,18 +1074,19 @@ __tcf_get_next_proto(struct tcf_chain *chain, struct tcf_proto *tp)
  */
 
 struct tcf_proto *
-tcf_get_next_proto(struct tcf_chain *chain, struct tcf_proto *tp)
+tcf_get_next_proto(struct tcf_chain *chain, struct tcf_proto *tp,
+                  bool rtnl_held)
 {
        struct tcf_proto *tp_next = __tcf_get_next_proto(chain, tp);
 
        if (tp)
-               tcf_proto_put(tp, NULL);
+               tcf_proto_put(tp, rtnl_held, NULL);
 
        return tp_next;
 }
 EXPORT_SYMBOL(tcf_get_next_proto);
 
-static void tcf_block_flush_all_chains(struct tcf_block *block)
+static void tcf_block_flush_all_chains(struct tcf_block *block, bool rtnl_held)
 {
        struct tcf_chain *chain;
 
@@ -1092,12 +1097,12 @@ static void tcf_block_flush_all_chains(struct tcf_block *block)
             chain;
             chain = tcf_get_next_chain(block, chain)) {
                tcf_chain_put_explicitly_created(chain);
-               tcf_chain_flush(chain);
+               tcf_chain_flush(chain, rtnl_held);
        }
 }
 
 static void __tcf_block_put(struct tcf_block *block, struct Qdisc *q,
-                           struct tcf_block_ext_info *ei)
+                           struct tcf_block_ext_info *ei, bool rtnl_held)
 {
        if (refcount_dec_and_mutex_lock(&block->refcnt, &block->lock)) {
                /* Flushing/putting all chains will cause the block to be
@@ -1118,15 +1123,15 @@ static void __tcf_block_put(struct tcf_block *block, struct Qdisc *q,
                if (free_block)
                        tcf_block_destroy(block);
                else
-                       tcf_block_flush_all_chains(block);
+                       tcf_block_flush_all_chains(block, rtnl_held);
        } else if (q) {
                tcf_block_offload_unbind(block, q, ei);
        }
 }
 
-static void tcf_block_refcnt_put(struct tcf_block *block)
+static void tcf_block_refcnt_put(struct tcf_block *block, bool rtnl_held)
 {
-       __tcf_block_put(block, NULL, NULL);
+       __tcf_block_put(block, NULL, NULL, rtnl_held);
 }
 
 /* Find tcf block.
@@ -1244,10 +1249,11 @@ errout_qdisc:
        return ERR_PTR(err);
 }
 
-static void tcf_block_release(struct Qdisc *q, struct tcf_block *block)
+static void tcf_block_release(struct Qdisc *q, struct tcf_block *block,
+                             bool rtnl_held)
 {
        if (!IS_ERR_OR_NULL(block))
-               tcf_block_refcnt_put(block);
+               tcf_block_refcnt_put(block, rtnl_held);
 
        if (q)
                qdisc_put(q);
@@ -1358,7 +1364,7 @@ err_chain0_head_change_cb_add:
        tcf_block_owner_del(block, q, ei->binder_type);
 err_block_owner_add:
 err_block_insert:
-       tcf_block_refcnt_put(block);
+       tcf_block_refcnt_put(block, true);
        return err;
 }
 EXPORT_SYMBOL(tcf_block_get_ext);
@@ -1395,7 +1401,7 @@ void tcf_block_put_ext(struct tcf_block *block, struct Qdisc *q,
        tcf_chain0_head_change_cb_del(block, ei);
        tcf_block_owner_del(block, q, ei->binder_type);
 
-       __tcf_block_put(block, q, ei);
+       __tcf_block_put(block, q, ei, true);
 }
 EXPORT_SYMBOL(tcf_block_put_ext);
 
@@ -1464,7 +1470,7 @@ tcf_block_playback_offloads(struct tcf_block *block, tc_setup_cb_t *cb,
                for (tp = __tcf_get_next_proto(chain, NULL); tp;
                     tp_prev = tp,
                             tp = __tcf_get_next_proto(chain, tp),
-                            tcf_proto_put(tp_prev, NULL)) {
+                            tcf_proto_put(tp_prev, true, NULL)) {
                        if (tp->ops->reoffload) {
                                err = tp->ops->reoffload(tp, add, cb, cb_priv,
                                                         extack);
@@ -1481,7 +1487,7 @@ tcf_block_playback_offloads(struct tcf_block *block, tc_setup_cb_t *cb,
        return 0;
 
 err_playback_remove:
-       tcf_proto_put(tp, NULL);
+       tcf_proto_put(tp, true, NULL);
        tcf_chain_put(chain);
        tcf_block_playback_offloads(block, cb, cb_priv, false, offload_in_use,
                                    extack);
@@ -1654,7 +1660,8 @@ static struct tcf_proto *tcf_chain_tp_find(struct tcf_chain *chain,
 
 static struct tcf_proto *tcf_chain_tp_insert_unique(struct tcf_chain *chain,
                                                    struct tcf_proto *tp_new,
-                                                   u32 protocol, u32 prio)
+                                                   u32 protocol, u32 prio,
+                                                   bool rtnl_held)
 {
        struct tcf_chain_info chain_info;
        struct tcf_proto *tp;
@@ -1669,10 +1676,10 @@ static struct tcf_proto *tcf_chain_tp_insert_unique(struct tcf_chain *chain,
        mutex_unlock(&chain->filter_chain_lock);
 
        if (tp) {
-               tcf_proto_destroy(tp_new, NULL);
+               tcf_proto_destroy(tp_new, rtnl_held, NULL);
                tp_new = tp;
        } else if (err) {
-               tcf_proto_destroy(tp_new, NULL);
+               tcf_proto_destroy(tp_new, rtnl_held, NULL);
                tp_new = ERR_PTR(err);
        }
 
@@ -1680,7 +1687,7 @@ static struct tcf_proto *tcf_chain_tp_insert_unique(struct tcf_chain *chain,
 }
 
 static void tcf_chain_tp_delete_empty(struct tcf_chain *chain,
-                                     struct tcf_proto *tp,
+                                     struct tcf_proto *tp, bool rtnl_held,
                                      struct netlink_ext_ack *extack)
 {
        struct tcf_chain_info chain_info;
@@ -1705,7 +1712,7 @@ static void tcf_chain_tp_delete_empty(struct tcf_chain *chain,
         * concurrently.
         * Mark tp for deletion if it is empty.
         */
-       if (!tp_iter || !tcf_proto_check_delete(tp)) {
+       if (!tp_iter || !tcf_proto_check_delete(tp, rtnl_held)) {
                mutex_unlock(&chain->filter_chain_lock);
                return;
        }
@@ -1716,7 +1723,7 @@ static void tcf_chain_tp_delete_empty(struct tcf_chain *chain,
        RCU_INIT_POINTER(*chain_info.pprev, next);
        mutex_unlock(&chain->filter_chain_lock);
 
-       tcf_proto_put(tp, extack);
+       tcf_proto_put(tp, rtnl_held, extack);
 }
 
 static struct tcf_proto *tcf_chain_tp_find(struct tcf_chain *chain,
@@ -1755,7 +1762,8 @@ static struct tcf_proto *tcf_chain_tp_find(struct tcf_chain *chain,
 static int tcf_fill_node(struct net *net, struct sk_buff *skb,
                         struct tcf_proto *tp, struct tcf_block *block,
                         struct Qdisc *q, u32 parent, void *fh,
-                        u32 portid, u32 seq, u16 flags, int event)
+                        u32 portid, u32 seq, u16 flags, int event,
+                        bool rtnl_held)
 {
        struct tcmsg *tcm;
        struct nlmsghdr  *nlh;
@@ -1783,7 +1791,8 @@ static int tcf_fill_node(struct net *net, struct sk_buff *skb,
        if (!fh) {
                tcm->tcm_handle = 0;
        } else {
-               if (tp->ops->dump && tp->ops->dump(net, tp, fh, skb, tcm) < 0)
+               if (tp->ops->dump &&
+                   tp->ops->dump(net, tp, fh, skb, tcm, rtnl_held) < 0)
                        goto nla_put_failure;
        }
        nlh->nlmsg_len = skb_tail_pointer(skb) - b;
@@ -1798,7 +1807,8 @@ nla_put_failure:
 static int tfilter_notify(struct net *net, struct sk_buff *oskb,
                          struct nlmsghdr *n, struct tcf_proto *tp,
                          struct tcf_block *block, struct Qdisc *q,
-                         u32 parent, void *fh, int event, bool unicast)
+                         u32 parent, void *fh, int event, bool unicast,
+                         bool rtnl_held)
 {
        struct sk_buff *skb;
        u32 portid = oskb ? NETLINK_CB(oskb).portid : 0;
@@ -1808,7 +1818,8 @@ static int tfilter_notify(struct net *net, struct sk_buff *oskb,
                return -ENOBUFS;
 
        if (tcf_fill_node(net, skb, tp, block, q, parent, fh, portid,
-                         n->nlmsg_seq, n->nlmsg_flags, event) <= 0) {
+                         n->nlmsg_seq, n->nlmsg_flags, event,
+                         rtnl_held) <= 0) {
                kfree_skb(skb);
                return -EINVAL;
        }
@@ -1824,7 +1835,7 @@ static int tfilter_del_notify(struct net *net, struct sk_buff *oskb,
                              struct nlmsghdr *n, struct tcf_proto *tp,
                              struct tcf_block *block, struct Qdisc *q,
                              u32 parent, void *fh, bool unicast, bool *last,
-                             struct netlink_ext_ack *extack)
+                             bool rtnl_held, struct netlink_ext_ack *extack)
 {
        struct sk_buff *skb;
        u32 portid = oskb ? NETLINK_CB(oskb).portid : 0;
@@ -1835,13 +1846,14 @@ static int tfilter_del_notify(struct net *net, struct sk_buff *oskb,
                return -ENOBUFS;
 
        if (tcf_fill_node(net, skb, tp, block, q, parent, fh, portid,
-                         n->nlmsg_seq, n->nlmsg_flags, RTM_DELTFILTER) <= 0) {
+                         n->nlmsg_seq, n->nlmsg_flags, RTM_DELTFILTER,
+                         rtnl_held) <= 0) {
                NL_SET_ERR_MSG(extack, "Failed to build del event notification");
                kfree_skb(skb);
                return -EINVAL;
        }
 
-       err = tp->ops->delete(tp, fh, last, extack);
+       err = tp->ops->delete(tp, fh, last, rtnl_held, extack);
        if (err) {
                kfree_skb(skb);
                return err;
@@ -1860,14 +1872,15 @@ static int tfilter_del_notify(struct net *net, struct sk_buff *oskb,
 static void tfilter_notify_chain(struct net *net, struct sk_buff *oskb,
                                 struct tcf_block *block, struct Qdisc *q,
                                 u32 parent, struct nlmsghdr *n,
-                                struct tcf_chain *chain, int event)
+                                struct tcf_chain *chain, int event,
+                                bool rtnl_held)
 {
        struct tcf_proto *tp;
 
-       for (tp = tcf_get_next_proto(chain, NULL);
-            tp; tp = tcf_get_next_proto(chain, tp))
+       for (tp = tcf_get_next_proto(chain, NULL, rtnl_held);
+            tp; tp = tcf_get_next_proto(chain, tp, rtnl_held))
                tfilter_notify(net, oskb, n, tp, block,
-                              q, parent, NULL, event, false);
+                              q, parent, NULL, event, false, rtnl_held);
 }
 
 static void tfilter_put(struct tcf_proto *tp, void *fh)
@@ -1896,6 +1909,7 @@ static int tc_new_tfilter(struct sk_buff *skb, struct nlmsghdr *n,
        void *fh;
        int err;
        int tp_created;
+       bool rtnl_held = true;
 
        if (!netlink_ns_capable(skb, net->user_ns, CAP_NET_ADMIN))
                return -EPERM;
@@ -1987,14 +2001,16 @@ replay:
 
                mutex_unlock(&chain->filter_chain_lock);
                tp_new = tcf_proto_create(nla_data(tca[TCA_KIND]),
-                                         protocol, prio, chain, extack);
+                                         protocol, prio, chain, rtnl_held,
+                                         extack);
                if (IS_ERR(tp_new)) {
                        err = PTR_ERR(tp_new);
                        goto errout_tp;
                }
 
                tp_created = 1;
-               tp = tcf_chain_tp_insert_unique(chain, tp_new, protocol, prio);
+               tp = tcf_chain_tp_insert_unique(chain, tp_new, protocol, prio,
+                                               rtnl_held);
                if (IS_ERR(tp)) {
                        err = PTR_ERR(tp);
                        goto errout_tp;
@@ -2032,24 +2048,24 @@ replay:
 
        err = tp->ops->change(net, skb, tp, cl, t->tcm_handle, tca, &fh,
                              n->nlmsg_flags & NLM_F_CREATE ? TCA_ACT_NOREPLACE : TCA_ACT_REPLACE,
-                             extack);
+                             rtnl_held, extack);
        if (err == 0) {
                tfilter_notify(net, skb, n, tp, block, q, parent, fh,
-                              RTM_NEWTFILTER, false);
+                              RTM_NEWTFILTER, false, rtnl_held);
                tfilter_put(tp, fh);
        }
 
 errout:
        if (err && tp_created)
-               tcf_chain_tp_delete_empty(chain, tp, NULL);
+               tcf_chain_tp_delete_empty(chain, tp, rtnl_held, NULL);
 errout_tp:
        if (chain) {
                if (tp && !IS_ERR(tp))
-                       tcf_proto_put(tp, NULL);
+                       tcf_proto_put(tp, rtnl_held, NULL);
                if (!tp_created)
                        tcf_chain_put(chain);
        }
-       tcf_block_release(q, block);
+       tcf_block_release(q, block, rtnl_held);
        if (err == -EAGAIN)
                /* Replay the request. */
                goto replay;
@@ -2078,6 +2094,7 @@ static int tc_del_tfilter(struct sk_buff *skb, struct nlmsghdr *n,
        unsigned long cl = 0;
        void *fh = NULL;
        int err;
+       bool rtnl_held = true;
 
        if (!netlink_ns_capable(skb, net->user_ns, CAP_NET_ADMIN))
                return -EPERM;
@@ -2127,8 +2144,8 @@ static int tc_del_tfilter(struct sk_buff *skb, struct nlmsghdr *n,
 
        if (prio == 0) {
                tfilter_notify_chain(net, skb, block, q, parent, n,
-                                    chain, RTM_DELTFILTER);
-               tcf_chain_flush(chain);
+                                    chain, RTM_DELTFILTER, rtnl_held);
+               tcf_chain_flush(chain, rtnl_held);
                err = 0;
                goto errout;
        }
@@ -2148,9 +2165,9 @@ static int tc_del_tfilter(struct sk_buff *skb, struct nlmsghdr *n,
                tcf_chain_tp_remove(chain, &chain_info, tp);
                mutex_unlock(&chain->filter_chain_lock);
 
-               tcf_proto_put(tp, NULL);
+               tcf_proto_put(tp, rtnl_held, NULL);
                tfilter_notify(net, skb, n, tp, block, q, parent, fh,
-                              RTM_DELTFILTER, false);
+                              RTM_DELTFILTER, false, rtnl_held);
                err = 0;
                goto errout;
        }
@@ -2166,20 +2183,21 @@ static int tc_del_tfilter(struct sk_buff *skb, struct nlmsghdr *n,
 
                err = tfilter_del_notify(net, skb, n, tp, block,
                                         q, parent, fh, false, &last,
-                                        extack);
+                                        rtnl_held, extack);
+
                if (err)
                        goto errout;
                if (last)
-                       tcf_chain_tp_delete_empty(chain, tp, extack);
+                       tcf_chain_tp_delete_empty(chain, tp, rtnl_held, extack);
        }
 
 errout:
        if (chain) {
                if (tp && !IS_ERR(tp))
-                       tcf_proto_put(tp, NULL);
+                       tcf_proto_put(tp, rtnl_held, NULL);
                tcf_chain_put(chain);
        }
-       tcf_block_release(q, block);
+       tcf_block_release(q, block, rtnl_held);
        return err;
 
 errout_locked:
@@ -2205,6 +2223,7 @@ static int tc_get_tfilter(struct sk_buff *skb, struct nlmsghdr *n,
        unsigned long cl = 0;
        void *fh = NULL;
        int err;
+       bool rtnl_held = true;
 
        err = nlmsg_parse(n, sizeof(*t), tca, TCA_MAX, rtm_tca_policy, extack);
        if (err < 0)
@@ -2263,7 +2282,7 @@ static int tc_get_tfilter(struct sk_buff *skb, struct nlmsghdr *n,
                err = -ENOENT;
        } else {
                err = tfilter_notify(net, skb, n, tp, block, q, parent,
-                                    fh, RTM_NEWTFILTER, true);
+                                    fh, RTM_NEWTFILTER, true, rtnl_held);
                if (err < 0)
                        NL_SET_ERR_MSG(extack, "Failed to send filter notify message");
        }
@@ -2272,10 +2291,10 @@ static int tc_get_tfilter(struct sk_buff *skb, struct nlmsghdr *n,
 errout:
        if (chain) {
                if (tp && !IS_ERR(tp))
-                       tcf_proto_put(tp, NULL);
+                       tcf_proto_put(tp, rtnl_held, NULL);
                tcf_chain_put(chain);
        }
-       tcf_block_release(q, block);
+       tcf_block_release(q, block, rtnl_held);
        return err;
 }
 
@@ -2296,7 +2315,7 @@ static int tcf_node_dump(struct tcf_proto *tp, void *n, struct tcf_walker *arg)
        return tcf_fill_node(net, a->skb, tp, a->block, a->q, a->parent,
                             n, NETLINK_CB(a->cb->skb).portid,
                             a->cb->nlh->nlmsg_seq, NLM_F_MULTI,
-                            RTM_NEWTFILTER);
+                            RTM_NEWTFILTER, true);
 }
 
 static bool tcf_chain_dump(struct tcf_chain *chain, struct Qdisc *q, u32 parent,
@@ -2313,7 +2332,7 @@ static bool tcf_chain_dump(struct tcf_chain *chain, struct Qdisc *q, u32 parent,
             tp;
             tp_prev = tp,
                     tp = __tcf_get_next_proto(chain, tp),
-                    tcf_proto_put(tp_prev, NULL),
+                    tcf_proto_put(tp_prev, true, NULL),
                     (*p_index)++) {
                if (*p_index < index_start)
                        continue;
@@ -2330,9 +2349,8 @@ static bool tcf_chain_dump(struct tcf_chain *chain, struct Qdisc *q, u32 parent,
                        if (tcf_fill_node(net, skb, tp, block, q, parent, NULL,
                                          NETLINK_CB(cb->skb).portid,
                                          cb->nlh->nlmsg_seq, NLM_F_MULTI,
-                                         RTM_NEWTFILTER) <= 0)
+                                         RTM_NEWTFILTER, true) <= 0)
                                goto errout;
-
                        cb->args[1] = 1;
                }
                if (!tp->ops->walk)
@@ -2347,7 +2365,7 @@ static bool tcf_chain_dump(struct tcf_chain *chain, struct Qdisc *q, u32 parent,
                arg.w.skip = cb->args[1] - 1;
                arg.w.count = 0;
                arg.w.cookie = cb->args[2];
-               tp->ops->walk(tp, &arg.w);
+               tp->ops->walk(tp, &arg.w, true);
                cb->args[2] = arg.w.cookie;
                cb->args[1] = arg.w.count + 1;
                if (arg.w.stop)
@@ -2356,7 +2374,7 @@ static bool tcf_chain_dump(struct tcf_chain *chain, struct Qdisc *q, u32 parent,
        return true;
 
 errout:
-       tcf_proto_put(tp, NULL);
+       tcf_proto_put(tp, true, NULL);
        return false;
 }
 
@@ -2448,7 +2466,7 @@ static int tc_dump_tfilter(struct sk_buff *skb, struct netlink_callback *cb)
        }
 
        if (tcm->tcm_ifindex == TCM_IFINDEX_MAGIC_BLOCK)
-               tcf_block_refcnt_put(block);
+               tcf_block_refcnt_put(block, true);
        cb->args[0] = index;
 
 out:
@@ -2569,7 +2587,7 @@ static int tc_chain_tmplt_add(struct tcf_chain *chain, struct net *net,
        if (!tca[TCA_KIND])
                return 0;
 
-       ops = tcf_proto_lookup_ops(nla_data(tca[TCA_KIND]), extack);
+       ops = tcf_proto_lookup_ops(nla_data(tca[TCA_KIND]), true, extack);
        if (IS_ERR(ops))
                return PTR_ERR(ops);
        if (!ops->tmplt_create || !ops->tmplt_destroy || !ops->tmplt_dump) {
@@ -2699,9 +2717,9 @@ replay:
                break;
        case RTM_DELCHAIN:
                tfilter_notify_chain(net, skb, block, q, parent, n,
-                                    chain, RTM_DELTFILTER);
+                                    chain, RTM_DELTFILTER, true);
                /* Flush the chain first as the user requested chain removal. */
-               tcf_chain_flush(chain);
+               tcf_chain_flush(chain, true);
                /* In case the chain was successfully deleted, put a reference
                 * to the chain previously taken during addition.
                 */
@@ -2722,7 +2740,7 @@ replay:
 errout:
        tcf_chain_put(chain);
 errout_block:
-       tcf_block_release(q, block);
+       tcf_block_release(q, block, true);
        if (err == -EAGAIN)
                /* Replay the request. */
                goto replay;
@@ -2829,7 +2847,7 @@ static int tc_dump_chain(struct sk_buff *skb, struct netlink_callback *cb)
        }
 
        if (tcm->tcm_ifindex == TCM_IFINDEX_MAGIC_BLOCK)
-               tcf_block_refcnt_put(block);
+               tcf_block_refcnt_put(block, true);
        cb->args[0] = index;
 
 out:
index eaf9c02fe792e54c0ade135abbd924f4488cf856..2383f449d2bcef05169fec66642c07bc17626291 100644 (file)
@@ -107,7 +107,8 @@ static void basic_delete_filter_work(struct work_struct *work)
        rtnl_unlock();
 }
 
-static void basic_destroy(struct tcf_proto *tp, struct netlink_ext_ack *extack)
+static void basic_destroy(struct tcf_proto *tp, bool rtnl_held,
+                         struct netlink_ext_ack *extack)
 {
        struct basic_head *head = rtnl_dereference(tp->root);
        struct basic_filter *f, *n;
@@ -126,7 +127,7 @@ static void basic_destroy(struct tcf_proto *tp, struct netlink_ext_ack *extack)
 }
 
 static int basic_delete(struct tcf_proto *tp, void *arg, bool *last,
-                       struct netlink_ext_ack *extack)
+                       bool rtnl_held, struct netlink_ext_ack *extack)
 {
        struct basic_head *head = rtnl_dereference(tp->root);
        struct basic_filter *f = arg;
@@ -173,7 +174,7 @@ static int basic_set_parms(struct net *net, struct tcf_proto *tp,
 static int basic_change(struct net *net, struct sk_buff *in_skb,
                        struct tcf_proto *tp, unsigned long base, u32 handle,
                        struct nlattr **tca, void **arg, bool ovr,
-                       struct netlink_ext_ack *extack)
+                       bool rtnl_held, struct netlink_ext_ack *extack)
 {
        int err;
        struct basic_head *head = rtnl_dereference(tp->root);
@@ -247,7 +248,8 @@ errout:
        return err;
 }
 
-static void basic_walk(struct tcf_proto *tp, struct tcf_walker *arg)
+static void basic_walk(struct tcf_proto *tp, struct tcf_walker *arg,
+                      bool rtnl_held)
 {
        struct basic_head *head = rtnl_dereference(tp->root);
        struct basic_filter *f;
@@ -274,7 +276,7 @@ static void basic_bind_class(void *fh, u32 classid, unsigned long cl)
 }
 
 static int basic_dump(struct net *net, struct tcf_proto *tp, void *fh,
-                     struct sk_buff *skb, struct tcmsg *t)
+                     struct sk_buff *skb, struct tcmsg *t, bool rtnl_held)
 {
        struct tc_basic_pcnt gpf = {};
        struct basic_filter *f = fh;
index 656b3423ad3587bba2864832771be6ac81b987ae..062350c6621cfd07a9a1489ba65389d617e2f1dc 100644 (file)
@@ -298,7 +298,7 @@ static void __cls_bpf_delete(struct tcf_proto *tp, struct cls_bpf_prog *prog,
 }
 
 static int cls_bpf_delete(struct tcf_proto *tp, void *arg, bool *last,
-                         struct netlink_ext_ack *extack)
+                         bool rtnl_held, struct netlink_ext_ack *extack)
 {
        struct cls_bpf_head *head = rtnl_dereference(tp->root);
 
@@ -307,7 +307,7 @@ static int cls_bpf_delete(struct tcf_proto *tp, void *arg, bool *last,
        return 0;
 }
 
-static void cls_bpf_destroy(struct tcf_proto *tp,
+static void cls_bpf_destroy(struct tcf_proto *tp, bool rtnl_held,
                            struct netlink_ext_ack *extack)
 {
        struct cls_bpf_head *head = rtnl_dereference(tp->root);
@@ -456,7 +456,8 @@ static int cls_bpf_set_parms(struct net *net, struct tcf_proto *tp,
 static int cls_bpf_change(struct net *net, struct sk_buff *in_skb,
                          struct tcf_proto *tp, unsigned long base,
                          u32 handle, struct nlattr **tca,
-                         void **arg, bool ovr, struct netlink_ext_ack *extack)
+                         void **arg, bool ovr, bool rtnl_held,
+                         struct netlink_ext_ack *extack)
 {
        struct cls_bpf_head *head = rtnl_dereference(tp->root);
        struct cls_bpf_prog *oldprog = *arg;
@@ -576,7 +577,7 @@ static int cls_bpf_dump_ebpf_info(const struct cls_bpf_prog *prog,
 }
 
 static int cls_bpf_dump(struct net *net, struct tcf_proto *tp, void *fh,
-                       struct sk_buff *skb, struct tcmsg *tm)
+                       struct sk_buff *skb, struct tcmsg *tm, bool rtnl_held)
 {
        struct cls_bpf_prog *prog = fh;
        struct nlattr *nest;
@@ -636,7 +637,8 @@ static void cls_bpf_bind_class(void *fh, u32 classid, unsigned long cl)
                prog->res.class = cl;
 }
 
-static void cls_bpf_walk(struct tcf_proto *tp, struct tcf_walker *arg)
+static void cls_bpf_walk(struct tcf_proto *tp, struct tcf_walker *arg,
+                        bool rtnl_held)
 {
        struct cls_bpf_head *head = rtnl_dereference(tp->root);
        struct cls_bpf_prog *prog;
index 663ee1c6d6065113480daab7332c89f1a7f12046..1cef3b41609405a535094e4faeec3609d0219ff4 100644 (file)
@@ -78,7 +78,7 @@ static void cls_cgroup_destroy_work(struct work_struct *work)
 static int cls_cgroup_change(struct net *net, struct sk_buff *in_skb,
                             struct tcf_proto *tp, unsigned long base,
                             u32 handle, struct nlattr **tca,
-                            void **arg, bool ovr,
+                            void **arg, bool ovr, bool rtnl_held,
                             struct netlink_ext_ack *extack)
 {
        struct nlattr *tb[TCA_CGROUP_MAX + 1];
@@ -130,7 +130,7 @@ errout:
        return err;
 }
 
-static void cls_cgroup_destroy(struct tcf_proto *tp,
+static void cls_cgroup_destroy(struct tcf_proto *tp, bool rtnl_held,
                               struct netlink_ext_ack *extack)
 {
        struct cls_cgroup_head *head = rtnl_dereference(tp->root);
@@ -145,12 +145,13 @@ static void cls_cgroup_destroy(struct tcf_proto *tp,
 }
 
 static int cls_cgroup_delete(struct tcf_proto *tp, void *arg, bool *last,
-                            struct netlink_ext_ack *extack)
+                            bool rtnl_held, struct netlink_ext_ack *extack)
 {
        return -EOPNOTSUPP;
 }
 
-static void cls_cgroup_walk(struct tcf_proto *tp, struct tcf_walker *arg)
+static void cls_cgroup_walk(struct tcf_proto *tp, struct tcf_walker *arg,
+                           bool rtnl_held)
 {
        struct cls_cgroup_head *head = rtnl_dereference(tp->root);
 
@@ -166,7 +167,7 @@ skip:
 }
 
 static int cls_cgroup_dump(struct net *net, struct tcf_proto *tp, void *fh,
-                          struct sk_buff *skb, struct tcmsg *t)
+                          struct sk_buff *skb, struct tcmsg *t, bool rtnl_held)
 {
        struct cls_cgroup_head *head = rtnl_dereference(tp->root);
        struct nlattr *nest;
index 39a6407d48328cceadd5243e21f95c9d102f3b9e..204e2edae8d538a24a0b1c02309821502bb0f0c2 100644 (file)
@@ -391,7 +391,8 @@ static void flow_destroy_filter_work(struct work_struct *work)
 static int flow_change(struct net *net, struct sk_buff *in_skb,
                       struct tcf_proto *tp, unsigned long base,
                       u32 handle, struct nlattr **tca,
-                      void **arg, bool ovr, struct netlink_ext_ack *extack)
+                      void **arg, bool ovr, bool rtnl_held,
+                      struct netlink_ext_ack *extack)
 {
        struct flow_head *head = rtnl_dereference(tp->root);
        struct flow_filter *fold, *fnew;
@@ -566,7 +567,7 @@ err1:
 }
 
 static int flow_delete(struct tcf_proto *tp, void *arg, bool *last,
-                      struct netlink_ext_ack *extack)
+                      bool rtnl_held, struct netlink_ext_ack *extack)
 {
        struct flow_head *head = rtnl_dereference(tp->root);
        struct flow_filter *f = arg;
@@ -590,7 +591,8 @@ static int flow_init(struct tcf_proto *tp)
        return 0;
 }
 
-static void flow_destroy(struct tcf_proto *tp, struct netlink_ext_ack *extack)
+static void flow_destroy(struct tcf_proto *tp, bool rtnl_held,
+                        struct netlink_ext_ack *extack)
 {
        struct flow_head *head = rtnl_dereference(tp->root);
        struct flow_filter *f, *next;
@@ -617,7 +619,7 @@ static void *flow_get(struct tcf_proto *tp, u32 handle)
 }
 
 static int flow_dump(struct net *net, struct tcf_proto *tp, void *fh,
-                    struct sk_buff *skb, struct tcmsg *t)
+                    struct sk_buff *skb, struct tcmsg *t, bool rtnl_held)
 {
        struct flow_filter *f = fh;
        struct nlattr *nest;
@@ -677,7 +679,8 @@ nla_put_failure:
        return -1;
 }
 
-static void flow_walk(struct tcf_proto *tp, struct tcf_walker *arg)
+static void flow_walk(struct tcf_proto *tp, struct tcf_walker *arg,
+                     bool rtnl_held)
 {
        struct flow_head *head = rtnl_dereference(tp->root);
        struct flow_filter *f;
index 5e3f74ab68ca28eb73accd54a8218fa9c64b07c2..32fa3e20adc56c9f2e278a13a0390a72d9d891f3 100644 (file)
@@ -465,7 +465,8 @@ static void fl_destroy_sleepable(struct work_struct *work)
        module_put(THIS_MODULE);
 }
 
-static void fl_destroy(struct tcf_proto *tp, struct netlink_ext_ack *extack)
+static void fl_destroy(struct tcf_proto *tp, bool rtnl_held,
+                      struct netlink_ext_ack *extack)
 {
        struct cls_fl_head *head = rtnl_dereference(tp->root);
        struct fl_flow_mask *mask, *next_mask;
@@ -1300,7 +1301,8 @@ static int fl_set_parms(struct net *net, struct tcf_proto *tp,
 static int fl_change(struct net *net, struct sk_buff *in_skb,
                     struct tcf_proto *tp, unsigned long base,
                     u32 handle, struct nlattr **tca,
-                    void **arg, bool ovr, struct netlink_ext_ack *extack)
+                    void **arg, bool ovr, bool rtnl_held,
+                    struct netlink_ext_ack *extack)
 {
        struct cls_fl_head *head = rtnl_dereference(tp->root);
        struct cls_fl_filter *fold = *arg;
@@ -1437,7 +1439,7 @@ errout_mask_alloc:
 }
 
 static int fl_delete(struct tcf_proto *tp, void *arg, bool *last,
-                    struct netlink_ext_ack *extack)
+                    bool rtnl_held, struct netlink_ext_ack *extack)
 {
        struct cls_fl_head *head = rtnl_dereference(tp->root);
        struct cls_fl_filter *f = arg;
@@ -1449,7 +1451,8 @@ static int fl_delete(struct tcf_proto *tp, void *arg, bool *last,
        return 0;
 }
 
-static void fl_walk(struct tcf_proto *tp, struct tcf_walker *arg)
+static void fl_walk(struct tcf_proto *tp, struct tcf_walker *arg,
+                   bool rtnl_held)
 {
        struct cls_fl_head *head = rtnl_dereference(tp->root);
        struct cls_fl_filter *f;
@@ -2044,7 +2047,7 @@ nla_put_failure:
 }
 
 static int fl_dump(struct net *net, struct tcf_proto *tp, void *fh,
-                  struct sk_buff *skb, struct tcmsg *t)
+                  struct sk_buff *skb, struct tcmsg *t, bool rtnl_held)
 {
        struct cls_fl_filter *f = fh;
        struct nlattr *nest;
index c8173ebb69f28e645570e9070ce6be7c8c78852b..317151bae73b5a07ecc64894a75700b0f6c29d55 100644 (file)
@@ -139,7 +139,8 @@ static void fw_delete_filter_work(struct work_struct *work)
        rtnl_unlock();
 }
 
-static void fw_destroy(struct tcf_proto *tp, struct netlink_ext_ack *extack)
+static void fw_destroy(struct tcf_proto *tp, bool rtnl_held,
+                      struct netlink_ext_ack *extack)
 {
        struct fw_head *head = rtnl_dereference(tp->root);
        struct fw_filter *f;
@@ -163,7 +164,7 @@ static void fw_destroy(struct tcf_proto *tp, struct netlink_ext_ack *extack)
 }
 
 static int fw_delete(struct tcf_proto *tp, void *arg, bool *last,
-                    struct netlink_ext_ack *extack)
+                    bool rtnl_held, struct netlink_ext_ack *extack)
 {
        struct fw_head *head = rtnl_dereference(tp->root);
        struct fw_filter *f = arg;
@@ -250,7 +251,8 @@ static int fw_set_parms(struct net *net, struct tcf_proto *tp,
 static int fw_change(struct net *net, struct sk_buff *in_skb,
                     struct tcf_proto *tp, unsigned long base,
                     u32 handle, struct nlattr **tca, void **arg,
-                    bool ovr, struct netlink_ext_ack *extack)
+                    bool ovr, bool rtnl_held,
+                    struct netlink_ext_ack *extack)
 {
        struct fw_head *head = rtnl_dereference(tp->root);
        struct fw_filter *f = *arg;
@@ -354,7 +356,8 @@ errout:
        return err;
 }
 
-static void fw_walk(struct tcf_proto *tp, struct tcf_walker *arg)
+static void fw_walk(struct tcf_proto *tp, struct tcf_walker *arg,
+                   bool rtnl_held)
 {
        struct fw_head *head = rtnl_dereference(tp->root);
        int h;
@@ -384,7 +387,7 @@ static void fw_walk(struct tcf_proto *tp, struct tcf_walker *arg)
 }
 
 static int fw_dump(struct net *net, struct tcf_proto *tp, void *fh,
-                  struct sk_buff *skb, struct tcmsg *t)
+                  struct sk_buff *skb, struct tcmsg *t, bool rtnl_held)
 {
        struct fw_head *head = rtnl_dereference(tp->root);
        struct fw_filter *f = fh;
index 8848a147c4bf18e3d2d3d67db85cee20927ddb38..a37137430e61ecf5dd487bb18ebf05c03d67b60e 100644 (file)
@@ -109,7 +109,8 @@ static int mall_replace_hw_filter(struct tcf_proto *tp,
        return 0;
 }
 
-static void mall_destroy(struct tcf_proto *tp, struct netlink_ext_ack *extack)
+static void mall_destroy(struct tcf_proto *tp, bool rtnl_held,
+                        struct netlink_ext_ack *extack)
 {
        struct cls_mall_head *head = rtnl_dereference(tp->root);
 
@@ -160,7 +161,8 @@ static int mall_set_parms(struct net *net, struct tcf_proto *tp,
 static int mall_change(struct net *net, struct sk_buff *in_skb,
                       struct tcf_proto *tp, unsigned long base,
                       u32 handle, struct nlattr **tca,
-                      void **arg, bool ovr, struct netlink_ext_ack *extack)
+                      void **arg, bool ovr, bool rtnl_held,
+                      struct netlink_ext_ack *extack)
 {
        struct cls_mall_head *head = rtnl_dereference(tp->root);
        struct nlattr *tb[TCA_MATCHALL_MAX + 1];
@@ -233,12 +235,13 @@ err_exts_init:
 }
 
 static int mall_delete(struct tcf_proto *tp, void *arg, bool *last,
-                      struct netlink_ext_ack *extack)
+                      bool rtnl_held, struct netlink_ext_ack *extack)
 {
        return -EOPNOTSUPP;
 }
 
-static void mall_walk(struct tcf_proto *tp, struct tcf_walker *arg)
+static void mall_walk(struct tcf_proto *tp, struct tcf_walker *arg,
+                     bool rtnl_held)
 {
        struct cls_mall_head *head = rtnl_dereference(tp->root);
 
@@ -280,7 +283,7 @@ static int mall_reoffload(struct tcf_proto *tp, bool add, tc_setup_cb_t *cb,
 }
 
 static int mall_dump(struct net *net, struct tcf_proto *tp, void *fh,
-                    struct sk_buff *skb, struct tcmsg *t)
+                    struct sk_buff *skb, struct tcmsg *t, bool rtnl_held)
 {
        struct tc_matchall_pcnt gpf = {};
        struct cls_mall_head *head = fh;
index 44b26038c4c41df52d7f28200c63b98bba7ba838..e590c3a2999d5372af2b78387ea1b2a14c359569 100644 (file)
@@ -276,7 +276,8 @@ static void route4_queue_work(struct route4_filter *f)
        tcf_queue_work(&f->rwork, route4_delete_filter_work);
 }
 
-static void route4_destroy(struct tcf_proto *tp, struct netlink_ext_ack *extack)
+static void route4_destroy(struct tcf_proto *tp, bool rtnl_held,
+                          struct netlink_ext_ack *extack)
 {
        struct route4_head *head = rtnl_dereference(tp->root);
        int h1, h2;
@@ -312,7 +313,7 @@ static void route4_destroy(struct tcf_proto *tp, struct netlink_ext_ack *extack)
 }
 
 static int route4_delete(struct tcf_proto *tp, void *arg, bool *last,
-                        struct netlink_ext_ack *extack)
+                        bool rtnl_held, struct netlink_ext_ack *extack)
 {
        struct route4_head *head = rtnl_dereference(tp->root);
        struct route4_filter *f = arg;
@@ -468,7 +469,7 @@ static int route4_set_parms(struct net *net, struct tcf_proto *tp,
 static int route4_change(struct net *net, struct sk_buff *in_skb,
                         struct tcf_proto *tp, unsigned long base, u32 handle,
                         struct nlattr **tca, void **arg, bool ovr,
-                        struct netlink_ext_ack *extack)
+                        bool rtnl_held, struct netlink_ext_ack *extack)
 {
        struct route4_head *head = rtnl_dereference(tp->root);
        struct route4_filter __rcu **fp;
@@ -560,7 +561,8 @@ errout:
        return err;
 }
 
-static void route4_walk(struct tcf_proto *tp, struct tcf_walker *arg)
+static void route4_walk(struct tcf_proto *tp, struct tcf_walker *arg,
+                       bool rtnl_held)
 {
        struct route4_head *head = rtnl_dereference(tp->root);
        unsigned int h, h1;
@@ -597,7 +599,7 @@ static void route4_walk(struct tcf_proto *tp, struct tcf_walker *arg)
 }
 
 static int route4_dump(struct net *net, struct tcf_proto *tp, void *fh,
-                      struct sk_buff *skb, struct tcmsg *t)
+                      struct sk_buff *skb, struct tcmsg *t, bool rtnl_held)
 {
        struct route4_filter *f = fh;
        struct nlattr *nest;
index 9dd9530e6a526b3e8d2817b079d73e8f1ad9fc1e..4d3836178fa5d91e8c843a5113cadb6e966bdf7a 100644 (file)
@@ -312,7 +312,8 @@ static void rsvp_delete_filter(struct tcf_proto *tp, struct rsvp_filter *f)
                __rsvp_delete_filter(f);
 }
 
-static void rsvp_destroy(struct tcf_proto *tp, struct netlink_ext_ack *extack)
+static void rsvp_destroy(struct tcf_proto *tp, bool rtnl_held,
+                        struct netlink_ext_ack *extack)
 {
        struct rsvp_head *data = rtnl_dereference(tp->root);
        int h1, h2;
@@ -341,7 +342,7 @@ static void rsvp_destroy(struct tcf_proto *tp, struct netlink_ext_ack *extack)
 }
 
 static int rsvp_delete(struct tcf_proto *tp, void *arg, bool *last,
-                      struct netlink_ext_ack *extack)
+                      bool rtnl_held, struct netlink_ext_ack *extack)
 {
        struct rsvp_head *head = rtnl_dereference(tp->root);
        struct rsvp_filter *nfp, *f = arg;
@@ -477,7 +478,8 @@ static int rsvp_change(struct net *net, struct sk_buff *in_skb,
                       struct tcf_proto *tp, unsigned long base,
                       u32 handle,
                       struct nlattr **tca,
-                      void **arg, bool ovr, struct netlink_ext_ack *extack)
+                      void **arg, bool ovr, bool rtnl_held,
+                      struct netlink_ext_ack *extack)
 {
        struct rsvp_head *data = rtnl_dereference(tp->root);
        struct rsvp_filter *f, *nfp;
@@ -655,7 +657,8 @@ errout2:
        return err;
 }
 
-static void rsvp_walk(struct tcf_proto *tp, struct tcf_walker *arg)
+static void rsvp_walk(struct tcf_proto *tp, struct tcf_walker *arg,
+                     bool rtnl_held)
 {
        struct rsvp_head *head = rtnl_dereference(tp->root);
        unsigned int h, h1;
@@ -689,7 +692,7 @@ static void rsvp_walk(struct tcf_proto *tp, struct tcf_walker *arg)
 }
 
 static int rsvp_dump(struct net *net, struct tcf_proto *tp, void *fh,
-                    struct sk_buff *skb, struct tcmsg *t)
+                    struct sk_buff *skb, struct tcmsg *t, bool rtnl_held)
 {
        struct rsvp_filter *f = fh;
        struct rsvp_session *s;
index b7dc667b6ec0567e51a6228af9fb6ecb42a11651..14d6b4058045d70279294a5ec14379502a4169e1 100644 (file)
@@ -173,7 +173,7 @@ static void tcindex_destroy_fexts_work(struct work_struct *work)
 }
 
 static int tcindex_delete(struct tcf_proto *tp, void *arg, bool *last,
-                         struct netlink_ext_ack *extack)
+                         bool rtnl_held, struct netlink_ext_ack *extack)
 {
        struct tcindex_data *p = rtnl_dereference(tp->root);
        struct tcindex_filter_result *r = arg;
@@ -226,7 +226,7 @@ static int tcindex_destroy_element(struct tcf_proto *tp,
 {
        bool last;
 
-       return tcindex_delete(tp, arg, &last, NULL);
+       return tcindex_delete(tp, arg, &last, false, NULL);
 }
 
 static void __tcindex_destroy(struct rcu_head *head)
@@ -499,7 +499,7 @@ static int
 tcindex_change(struct net *net, struct sk_buff *in_skb,
               struct tcf_proto *tp, unsigned long base, u32 handle,
               struct nlattr **tca, void **arg, bool ovr,
-              struct netlink_ext_ack *extack)
+              bool rtnl_held, struct netlink_ext_ack *extack)
 {
        struct nlattr *opt = tca[TCA_OPTIONS];
        struct nlattr *tb[TCA_TCINDEX_MAX + 1];
@@ -522,7 +522,8 @@ tcindex_change(struct net *net, struct sk_buff *in_skb,
                                 tca[TCA_RATE], ovr, extack);
 }
 
-static void tcindex_walk(struct tcf_proto *tp, struct tcf_walker *walker)
+static void tcindex_walk(struct tcf_proto *tp, struct tcf_walker *walker,
+                        bool rtnl_held)
 {
        struct tcindex_data *p = rtnl_dereference(tp->root);
        struct tcindex_filter *f, *next;
@@ -558,7 +559,7 @@ static void tcindex_walk(struct tcf_proto *tp, struct tcf_walker *walker)
        }
 }
 
-static void tcindex_destroy(struct tcf_proto *tp,
+static void tcindex_destroy(struct tcf_proto *tp, bool rtnl_held,
                            struct netlink_ext_ack *extack)
 {
        struct tcindex_data *p = rtnl_dereference(tp->root);
@@ -568,14 +569,14 @@ static void tcindex_destroy(struct tcf_proto *tp,
        walker.count = 0;
        walker.skip = 0;
        walker.fn = tcindex_destroy_element;
-       tcindex_walk(tp, &walker);
+       tcindex_walk(tp, &walker, true);
 
        call_rcu(&p->rcu, __tcindex_destroy);
 }
 
 
 static int tcindex_dump(struct net *net, struct tcf_proto *tp, void *fh,
-                       struct sk_buff *skb, struct tcmsg *t)
+                       struct sk_buff *skb, struct tcmsg *t, bool rtnl_held)
 {
        struct tcindex_data *p = rtnl_dereference(tp->root);
        struct tcindex_filter_result *r = fh;
index e891f30d42e9ec01b434da0179ace8b5068197a0..27d29c04dcc9c0b83505abb7c7fdf52237b9dec8 100644 (file)
@@ -629,7 +629,8 @@ static int u32_destroy_hnode(struct tcf_proto *tp, struct tc_u_hnode *ht,
        return -ENOENT;
 }
 
-static void u32_destroy(struct tcf_proto *tp, struct netlink_ext_ack *extack)
+static void u32_destroy(struct tcf_proto *tp, bool rtnl_held,
+                       struct netlink_ext_ack *extack)
 {
        struct tc_u_common *tp_c = tp->data;
        struct tc_u_hnode *root_ht = rtnl_dereference(tp->root);
@@ -663,7 +664,7 @@ static void u32_destroy(struct tcf_proto *tp, struct netlink_ext_ack *extack)
 }
 
 static int u32_delete(struct tcf_proto *tp, void *arg, bool *last,
-                     struct netlink_ext_ack *extack)
+                     bool rtnl_held, struct netlink_ext_ack *extack)
 {
        struct tc_u_hnode *ht = arg;
        struct tc_u_common *tp_c = tp->data;
@@ -858,7 +859,7 @@ static struct tc_u_knode *u32_init_knode(struct tcf_proto *tp,
 
 static int u32_change(struct net *net, struct sk_buff *in_skb,
                      struct tcf_proto *tp, unsigned long base, u32 handle,
-                     struct nlattr **tca, void **arg, bool ovr,
+                     struct nlattr **tca, void **arg, bool ovr, bool rtnl_held,
                      struct netlink_ext_ack *extack)
 {
        struct tc_u_common *tp_c = tp->data;
@@ -1123,7 +1124,8 @@ erridr:
        return err;
 }
 
-static void u32_walk(struct tcf_proto *tp, struct tcf_walker *arg)
+static void u32_walk(struct tcf_proto *tp, struct tcf_walker *arg,
+                    bool rtnl_held)
 {
        struct tc_u_common *tp_c = tp->data;
        struct tc_u_hnode *ht;
@@ -1281,7 +1283,7 @@ static void u32_bind_class(void *fh, u32 classid, unsigned long cl)
 }
 
 static int u32_dump(struct net *net, struct tcf_proto *tp, void *fh,
-                   struct sk_buff *skb, struct tcmsg *t)
+                   struct sk_buff *skb, struct tcmsg *t, bool rtnl_held)
 {
        struct tc_u_knode *n = fh;
        struct tc_u_hnode *ht_up, *ht_down;
index 9a530cad27597335197bd5ecc3bae9ec6a33af79..2283924fb56d57622d06691cb7f5dd13ec1e6783 100644 (file)
@@ -1914,14 +1914,14 @@ static void tc_bind_tclass(struct Qdisc *q, u32 portid, u32 clid,
             chain = tcf_get_next_chain(block, chain)) {
                struct tcf_proto *tp;
 
-               for (tp = tcf_get_next_proto(chain, NULL);
-                    tp; tp = tcf_get_next_proto(chain, tp)) {
+               for (tp = tcf_get_next_proto(chain, NULL, true);
+                    tp; tp = tcf_get_next_proto(chain, tp, true)) {
                        struct tcf_bind_args arg = {};
 
                        arg.w.fn = tcf_node_bind;
                        arg.classid = clid;
                        arg.cl = new_cl;
-                       tp->ops->walk(tp, &arg.w);
+                       tp->ops->walk(tp, &arg.w, true);
                }
        }
 }