diff options
Diffstat (limited to 'net/sched/cls_tcindex.c')
-rw-r--r-- | net/sched/cls_tcindex.c | 68 |
1 files changed, 27 insertions, 41 deletions
diff --git a/net/sched/cls_tcindex.c b/net/sched/cls_tcindex.c index 38bb882bb958..e1981628047b 100644 --- a/net/sched/cls_tcindex.c +++ b/net/sched/cls_tcindex.c @@ -48,7 +48,7 @@ struct tcindex_data { u32 hash; /* hash table size; 0 if undefined */ u32 alloc_hash; /* allocated size */ u32 fall_through; /* 0: only classify if explicit match */ - struct rcu_work rwork; + struct rcu_head rcu; }; static inline int tcindex_filter_is_set(struct tcindex_filter_result *r) @@ -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; @@ -221,11 +221,17 @@ found: return 0; } -static void tcindex_destroy_work(struct work_struct *work) +static int tcindex_destroy_element(struct tcf_proto *tp, + void *arg, struct tcf_walker *walker) +{ + bool last; + + return tcindex_delete(tp, arg, &last, false, NULL); +} + +static void __tcindex_destroy(struct rcu_head *head) { - struct tcindex_data *p = container_of(to_rcu_work(work), - struct tcindex_data, - rwork); + struct tcindex_data *p = container_of(head, struct tcindex_data, rcu); kfree(p->perfect); kfree(p->h); @@ -252,11 +258,9 @@ static int tcindex_filter_result_init(struct tcindex_filter_result *r) return tcf_exts_init(&r->exts, TCA_TCINDEX_ACT, TCA_TCINDEX_POLICE); } -static void tcindex_partial_destroy_work(struct work_struct *work) +static void __tcindex_partial_destroy(struct rcu_head *head) { - struct tcindex_data *p = container_of(to_rcu_work(work), - struct tcindex_data, - rwork); + struct tcindex_data *p = container_of(head, struct tcindex_data, rcu); kfree(p->perfect); kfree(p); @@ -313,7 +317,7 @@ tcindex_set_parms(struct net *net, struct tcf_proto *tp, unsigned long base, err = tcf_exts_init(&e, TCA_TCINDEX_ACT, TCA_TCINDEX_POLICE); if (err < 0) return err; - err = tcf_exts_validate(net, tp, tb, est, &e, ovr, extack); + err = tcf_exts_validate(net, tp, tb, est, &e, ovr, true, extack); if (err < 0) goto errout; @@ -476,7 +480,7 @@ tcindex_set_parms(struct net *net, struct tcf_proto *tp, unsigned long base, } if (oldp) - tcf_queue_work(&oldp->rwork, tcindex_partial_destroy_work); + call_rcu(&oldp->rcu, __tcindex_partial_destroy); return 0; errout_alloc: @@ -496,7 +500,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]; @@ -519,7 +523,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; @@ -555,43 +560,24 @@ 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); - int i; + struct tcf_walker walker; pr_debug("tcindex_destroy(tp %p),p %p\n", tp, p); + walker.count = 0; + walker.skip = 0; + walker.fn = tcindex_destroy_element; + tcindex_walk(tp, &walker, true); - if (p->perfect) { - for (i = 0; i < p->hash; i++) { - struct tcindex_filter_result *r = p->perfect + i; - - tcf_unbind_filter(tp, &r->res); - if (tcf_exts_get_net(&r->exts)) - tcf_queue_work(&r->rwork, - tcindex_destroy_rexts_work); - else - __tcindex_destroy_rexts(r); - } - } - - for (i = 0; p->h && i < p->hash; i++) { - struct tcindex_filter *f, *next; - bool last; - - for (f = rtnl_dereference(p->h[i]); f; f = next) { - next = rtnl_dereference(f->next); - tcindex_delete(tp, &f->result, &last, NULL); - } - } - - tcf_queue_work(&p->rwork, tcindex_destroy_work); + 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; |