From 25d8c0d55f241ce2d360df1bea48e23a55836ee6 Mon Sep 17 00:00:00 2001 From: John Fastabend Date: Fri, 12 Sep 2014 20:05:27 -0700 Subject: net: rcu-ify tcf_proto rcu'ify tcf_proto this allows calling tc_classify() without holding any locks. Updaters are protected by RTNL. This patch prepares the core net_sched infrastracture for running the classifier/action chains without holding the qdisc lock however it does nothing to ensure cls_xxx and act_xxx types also work without locking. Additional patches are required to address the fall out. Signed-off-by: John Fastabend Acked-by: Eric Dumazet Signed-off-by: David S. Miller --- net/sched/cls_api.c | 30 +++++++++++++++--------------- 1 file changed, 15 insertions(+), 15 deletions(-) (limited to 'net/sched/cls_api.c') diff --git a/net/sched/cls_api.c b/net/sched/cls_api.c index c28b0d327b1..e547efdaba9 100644 --- a/net/sched/cls_api.c +++ b/net/sched/cls_api.c @@ -117,7 +117,6 @@ static int tc_ctl_tfilter(struct sk_buff *skb, struct nlmsghdr *n) { struct net *net = sock_net(skb->sk); struct nlattr *tca[TCA_MAX + 1]; - spinlock_t *root_lock; struct tcmsg *t; u32 protocol; u32 prio; @@ -125,7 +124,8 @@ static int tc_ctl_tfilter(struct sk_buff *skb, struct nlmsghdr *n) u32 parent; struct net_device *dev; struct Qdisc *q; - struct tcf_proto **back, **chain; + struct tcf_proto __rcu **back; + struct tcf_proto __rcu **chain; struct tcf_proto *tp; const struct tcf_proto_ops *tp_ops; const struct Qdisc_class_ops *cops; @@ -197,7 +197,9 @@ replay: goto errout; /* Check the chain for existence of proto-tcf with this priority */ - for (back = chain; (tp = *back) != NULL; back = &tp->next) { + for (back = chain; + (tp = rtnl_dereference(*back)) != NULL; + back = &tp->next) { if (tp->prio >= prio) { if (tp->prio == prio) { if (!nprio || @@ -209,8 +211,6 @@ replay: } } - root_lock = qdisc_root_sleeping_lock(q); - if (tp == NULL) { /* Proto-tcf does not exist, create new one */ @@ -259,7 +259,8 @@ replay: } tp->ops = tp_ops; tp->protocol = protocol; - tp->prio = nprio ? : TC_H_MAJ(tcf_auto_prio(*back)); + tp->prio = nprio ? : + TC_H_MAJ(tcf_auto_prio(rtnl_dereference(*back))); tp->q = q; tp->classify = tp_ops->classify; tp->classid = parent; @@ -280,9 +281,9 @@ replay: if (fh == 0) { if (n->nlmsg_type == RTM_DELTFILTER && t->tcm_handle == 0) { - spin_lock_bh(root_lock); - *back = tp->next; - spin_unlock_bh(root_lock); + struct tcf_proto *next = rtnl_dereference(tp->next); + + RCU_INIT_POINTER(*back, next); tfilter_notify(net, skb, n, tp, fh, RTM_DELTFILTER); tcf_destroy(tp); @@ -322,10 +323,8 @@ replay: n->nlmsg_flags & NLM_F_CREATE ? TCA_ACT_NOREPLACE : TCA_ACT_REPLACE); if (err == 0) { if (tp_created) { - spin_lock_bh(root_lock); - tp->next = *back; - *back = tp; - spin_unlock_bh(root_lock); + RCU_INIT_POINTER(tp->next, rtnl_dereference(*back)); + rcu_assign_pointer(*back, tp); } tfilter_notify(net, skb, n, tp, fh, RTM_NEWTFILTER); } else { @@ -420,7 +419,7 @@ static int tc_dump_tfilter(struct sk_buff *skb, struct netlink_callback *cb) int s_t; struct net_device *dev; struct Qdisc *q; - struct tcf_proto *tp, **chain; + struct tcf_proto *tp, __rcu **chain; struct tcmsg *tcm = nlmsg_data(cb->nlh); unsigned long cl = 0; const struct Qdisc_class_ops *cops; @@ -454,7 +453,8 @@ static int tc_dump_tfilter(struct sk_buff *skb, struct netlink_callback *cb) s_t = cb->args[0]; - for (tp = *chain, t = 0; tp; tp = tp->next, t++) { + for (tp = rtnl_dereference(*chain), t = 0; + tp; tp = rtnl_dereference(tp->next), t++) { if (t < s_t) continue; if (TC_H_MAJ(tcm->tcm_info) && -- cgit v1.2.3-70-g09d2 From 18d0264f630e200772bf236ac5747c47e908501e Mon Sep 17 00:00:00 2001 From: WANG Cong Date: Thu, 25 Sep 2014 10:26:37 -0700 Subject: net_sched: remove the first parameter from tcf_exts_destroy() Cc: Jamal Hadi Salim Signed-off-by: Cong Wang Acked-by: Jamal Hadi Salim Signed-off-by: David S. Miller --- include/net/pkt_cls.h | 2 +- net/sched/cls_api.c | 2 +- net/sched/cls_basic.c | 4 ++-- net/sched/cls_bpf.c | 4 ++-- net/sched/cls_cgroup.c | 6 +++--- net/sched/cls_flow.c | 4 ++-- net/sched/cls_fw.c | 4 ++-- net/sched/cls_route.c | 4 ++-- net/sched/cls_rsvp.h | 4 ++-- net/sched/cls_tcindex.c | 4 ++-- net/sched/cls_u32.c | 4 ++-- 11 files changed, 21 insertions(+), 21 deletions(-) (limited to 'net/sched/cls_api.c') diff --git a/include/net/pkt_cls.h b/include/net/pkt_cls.h index 6da46dcf104..73f9532ee58 100644 --- a/include/net/pkt_cls.h +++ b/include/net/pkt_cls.h @@ -137,7 +137,7 @@ tcf_exts_exec(struct sk_buff *skb, struct tcf_exts *exts, int tcf_exts_validate(struct net *net, struct tcf_proto *tp, struct nlattr **tb, struct nlattr *rate_tlv, struct tcf_exts *exts, bool ovr); -void tcf_exts_destroy(struct tcf_proto *tp, struct tcf_exts *exts); +void tcf_exts_destroy(struct tcf_exts *exts); void tcf_exts_change(struct tcf_proto *tp, struct tcf_exts *dst, struct tcf_exts *src); int tcf_exts_dump(struct sk_buff *skb, struct tcf_exts *exts); diff --git a/net/sched/cls_api.c b/net/sched/cls_api.c index e547efdaba9..77147c8c4ac 100644 --- a/net/sched/cls_api.c +++ b/net/sched/cls_api.c @@ -496,7 +496,7 @@ out: return skb->len; } -void tcf_exts_destroy(struct tcf_proto *tp, struct tcf_exts *exts) +void tcf_exts_destroy(struct tcf_exts *exts) { #ifdef CONFIG_NET_CLS_ACT tcf_action_destroy(&exts->actions, TCA_ACT_UNBIND); diff --git a/net/sched/cls_basic.c b/net/sched/cls_basic.c index 1937298d677..fe20826a79e 100644 --- a/net/sched/cls_basic.c +++ b/net/sched/cls_basic.c @@ -94,7 +94,7 @@ static void basic_delete_filter(struct rcu_head *head) struct tcf_proto *tp = f->tp; tcf_unbind_filter(tp, &f->res); - tcf_exts_destroy(tp, &f->exts); + tcf_exts_destroy(&f->exts); tcf_em_tree_destroy(tp, &f->ematches); kfree(f); } @@ -161,7 +161,7 @@ static int basic_set_parms(struct net *net, struct tcf_proto *tp, return 0; errout: - tcf_exts_destroy(tp, &e); + tcf_exts_destroy(&e); return err; } diff --git a/net/sched/cls_bpf.c b/net/sched/cls_bpf.c index 4e3f5bfc0b2..4318d067b0a 100644 --- a/net/sched/cls_bpf.c +++ b/net/sched/cls_bpf.c @@ -93,7 +93,7 @@ static int cls_bpf_init(struct tcf_proto *tp) static void cls_bpf_delete_prog(struct tcf_proto *tp, struct cls_bpf_prog *prog) { tcf_unbind_filter(tp, &prog->res); - tcf_exts_destroy(tp, &prog->exts); + tcf_exts_destroy(&prog->exts); bpf_prog_destroy(prog->filter); @@ -217,7 +217,7 @@ static int cls_bpf_modify_existing(struct net *net, struct tcf_proto *tp, errout_free: kfree(bpf_ops); errout: - tcf_exts_destroy(tp, &exts); + tcf_exts_destroy(&exts); return ret; } diff --git a/net/sched/cls_cgroup.c b/net/sched/cls_cgroup.c index 15c34d4ccd9..3409f168225 100644 --- a/net/sched/cls_cgroup.c +++ b/net/sched/cls_cgroup.c @@ -86,7 +86,7 @@ static void cls_cgroup_destroy_rcu(struct rcu_head *root) struct cls_cgroup_head, rcu); - tcf_exts_destroy(head->tp, &head->exts); + tcf_exts_destroy(&head->exts); tcf_em_tree_destroy(head->tp, &head->ematches); kfree(head); } @@ -135,7 +135,7 @@ static int cls_cgroup_change(struct net *net, struct sk_buff *in_skb, err = tcf_em_tree_validate(tp, tb[TCA_CGROUP_EMATCHES], &t); if (err < 0) { - tcf_exts_destroy(tp, &e); + tcf_exts_destroy(&e); goto errout; } @@ -156,7 +156,7 @@ static void cls_cgroup_destroy(struct tcf_proto *tp) struct cls_cgroup_head *head = rtnl_dereference(tp->root); if (head) { - tcf_exts_destroy(tp, &head->exts); + tcf_exts_destroy(&head->exts); tcf_em_tree_destroy(tp, &head->ematches); RCU_INIT_POINTER(tp->root, NULL); kfree_rcu(head, rcu); diff --git a/net/sched/cls_flow.c b/net/sched/cls_flow.c index 95736fa479f..f18d27f7b5f 100644 --- a/net/sched/cls_flow.c +++ b/net/sched/cls_flow.c @@ -354,7 +354,7 @@ static void flow_destroy_filter(struct rcu_head *head) struct flow_filter *f = container_of(head, struct flow_filter, rcu); del_timer_sync(&f->perturb_timer); - tcf_exts_destroy(f->tp, &f->exts); + tcf_exts_destroy(&f->exts); tcf_em_tree_destroy(f->tp, &f->ematches); kfree(f); } @@ -533,7 +533,7 @@ err2: tcf_em_tree_destroy(tp, &t); kfree(fnew); err1: - tcf_exts_destroy(tp, &e); + tcf_exts_destroy(&e); return err; } diff --git a/net/sched/cls_fw.c b/net/sched/cls_fw.c index 2650285620e..da805aeeb65 100644 --- a/net/sched/cls_fw.c +++ b/net/sched/cls_fw.c @@ -126,7 +126,7 @@ static void fw_delete_filter(struct rcu_head *head) struct tcf_proto *tp = f->tp; tcf_unbind_filter(tp, &f->res); - tcf_exts_destroy(tp, &f->exts); + tcf_exts_destroy(&f->exts); kfree(f); } @@ -223,7 +223,7 @@ fw_change_attrs(struct net *net, struct tcf_proto *tp, struct fw_filter *f, return 0; errout: - tcf_exts_destroy(tp, &e); + tcf_exts_destroy(&e); return err; } diff --git a/net/sched/cls_route.c b/net/sched/cls_route.c index ba96deacf27..b665aee661f 100644 --- a/net/sched/cls_route.c +++ b/net/sched/cls_route.c @@ -272,7 +272,7 @@ route4_delete_filter(struct rcu_head *head) struct tcf_proto *tp = f->tp; tcf_unbind_filter(tp, &f->res); - tcf_exts_destroy(tp, &f->exts); + tcf_exts_destroy(&f->exts); kfree(f); } @@ -456,7 +456,7 @@ static int route4_set_parms(struct net *net, struct tcf_proto *tp, return 0; errout: - tcf_exts_destroy(tp, &e); + tcf_exts_destroy(&e); return err; } diff --git a/net/sched/cls_rsvp.h b/net/sched/cls_rsvp.h index b044c208b13..1c64a09753c 100644 --- a/net/sched/cls_rsvp.h +++ b/net/sched/cls_rsvp.h @@ -264,7 +264,7 @@ static void rsvp_delete_filter(struct tcf_proto *tp, struct rsvp_filter *f) { tcf_unbind_filter(tp, &f->res); - tcf_exts_destroy(tp, &f->exts); + tcf_exts_destroy(&f->exts); kfree_rcu(f, rcu); } @@ -577,7 +577,7 @@ insert: errout: kfree(f); errout2: - tcf_exts_destroy(tp, &e); + tcf_exts_destroy(&e); return err; } diff --git a/net/sched/cls_tcindex.c b/net/sched/cls_tcindex.c index 5054fae33a4..e3c6fa3ea3d 100644 --- a/net/sched/cls_tcindex.c +++ b/net/sched/cls_tcindex.c @@ -169,7 +169,7 @@ found: rcu_assign_pointer(*walk, rtnl_dereference(f->next)); } tcf_unbind_filter(tp, &r->res); - tcf_exts_destroy(tp, &r->exts); + tcf_exts_destroy(&r->exts); if (f) kfree_rcu(f, rcu); return 0; @@ -401,7 +401,7 @@ errout_alloc: kfree(cp->h); errout: kfree(cp); - tcf_exts_destroy(tp, &e); + tcf_exts_destroy(&e); return err; } diff --git a/net/sched/cls_u32.c b/net/sched/cls_u32.c index ef97a646ee9..4be3ebf46d6 100644 --- a/net/sched/cls_u32.c +++ b/net/sched/cls_u32.c @@ -359,7 +359,7 @@ static int u32_destroy_key(struct tcf_proto *tp, bool free_pf) { tcf_unbind_filter(tp, &n->res); - tcf_exts_destroy(tp, &n->exts); + tcf_exts_destroy(&n->exts); if (n->ht_down) n->ht_down->refcnt--; #ifdef CONFIG_CLS_U32_PERF @@ -606,7 +606,7 @@ static int u32_set_parms(struct net *net, struct tcf_proto *tp, return 0; errout: - tcf_exts_destroy(tp, &e); + tcf_exts_destroy(&e); return err; } -- cgit v1.2.3-70-g09d2 From 5301e3e117d88ef0967ce278912e54757f1a31a2 Mon Sep 17 00:00:00 2001 From: WANG Cong Date: Mon, 6 Oct 2014 17:21:54 -0700 Subject: net_sched: copy exts->type in tcf_exts_change() We need to copy exts->type when committing the change, otherwise it would be always 0. This is a quick fix for -net and -stable, for net-next tcf_exts will be removed. Fixes: commit 33be627159913b094bb578e83 ("net_sched: act: use standard struct list_head") Reported-by: Jamal Hadi Salim Cc: Jamal Hadi Salim Cc: John Fastabend Signed-off-by: Cong Wang Acked-by: Jamal Hadi Salim Signed-off-by: David S. Miller --- net/sched/cls_api.c | 1 + 1 file changed, 1 insertion(+) (limited to 'net/sched/cls_api.c') diff --git a/net/sched/cls_api.c b/net/sched/cls_api.c index c28b0d327b1..4f4e08b0e2b 100644 --- a/net/sched/cls_api.c +++ b/net/sched/cls_api.c @@ -549,6 +549,7 @@ void tcf_exts_change(struct tcf_proto *tp, struct tcf_exts *dst, tcf_tree_lock(tp); list_splice_init(&dst->actions, &tmp); list_splice(&src->actions, &dst->actions); + dst->type = src->type; tcf_tree_unlock(tp); tcf_action_destroy(&tmp, TCA_ACT_UNBIND); #endif -- cgit v1.2.3-70-g09d2