From 0982d8debd9d67d80f3862f8b31ff6558f281de3 Mon Sep 17 00:00:00 2001 From: Rostislav Lisovy Date: Thu, 1 Sep 2011 13:44:35 +0200 Subject: [PATCH] Reading and changing struct canprio_rules protected by RCU. --- net/sched/cls_canprio.c | 41 ++++++++++++++++++++++++++++++----------- 1 file changed, 30 insertions(+), 11 deletions(-) diff --git a/net/sched/cls_canprio.c b/net/sched/cls_canprio.c index bba0f4dd4fa..7efed62009f 100644 --- a/net/sched/cls_canprio.c +++ b/net/sched/cls_canprio.c @@ -70,6 +70,8 @@ struct canprio_rules { int rules_count; int eff_rules_count; int sff_rules_count; + + struct rcu_head rcu; }; struct canprio_head { @@ -136,40 +138,46 @@ static int canprio_classify(struct sk_buff *skb, struct tcf_proto *tp, { struct canprio_head *head = (struct canprio_head *)tp->root; struct canprio_filter *f; + struct canprio_rules *r; u32 can_id; int i; printk(" canprio_classify() invoked\n"); can_id = (u32)canprio_get_id(skb); + rcu_read_lock(); list_for_each_entry(f, &head->flist, link) { bool match = false; + r = rcu_dereference(f->rules); + if (can_id & CAN_EFF_FLAG) { can_id &= CAN_EFF_MASK; - for (i = 0; i < f->rules->eff_rules_count; i++) { - if ((f->rules->rules_raw[i].can_id & f->rules->rules_raw[i].can_mask & CAN_EFF_MASK) == - (can_id & f->rules->rules_raw[i].can_mask & CAN_EFF_MASK)) { + for (i = 0; i < r->eff_rules_count; i++) { + if ((r->rules_raw[i].can_id & r->rules_raw[i].can_mask & CAN_EFF_MASK) == + (can_id & r->rules_raw[i].can_mask & CAN_EFF_MASK)) { match = true; break; } } } else { - match = test_bit(can_id, f->rules->match_sff); + match = test_bit(can_id, r->match_sff); } - //if (f->rules->inv_match_en) + //if (r->inv_match_en) // match = !match; if (match) { *res = f->res; printk( " canprio_classify() match ok: ID 0x%x\n", can_id); + rcu_read_unlock(); return TC_POLICE_OK; } } + rcu_read_unlock(); return TC_POLICE_UNSPEC; } @@ -231,6 +239,11 @@ static unsigned int canprio_gen_handle(struct tcf_proto *tp) } +static void canprio_rules_free_rcu(struct rcu_head *rcu) +{ + kfree(container_of(rcu, struct canprio_rules, rcu)); +} + static int canprio_set_parms(struct tcf_proto *tp, struct canprio_filter *f, unsigned long base, struct nlattr **tb, struct nlattr *est) @@ -301,13 +314,12 @@ static int canprio_set_parms(struct tcf_proto *tp, struct canprio_filter *f, rules_tmp->inv_match_en = nla_get_u32(tb[TCA_CANPRIO_INV_EN]); if (f->rules == NULL) { // Setting parameters for newly created filter - f->rules = rules_tmp; + rcu_assign_pointer(f->rules, rules_tmp); } else { // Changing existing filter struct canprio_rules *rules_old; - rules_old = f->rules; - f->rules = rules_tmp; - kfree(rules_old); + rules_old = xchg(&f->rules, rules_tmp); + call_rcu(&rules_old->rcu, canprio_rules_free_rcu); } return 0; @@ -408,6 +420,8 @@ errout: static void canprio_delete_filter(struct tcf_proto *tp, struct canprio_filter *f) { tcf_unbind_filter(tp, &f->res); + + rcu_barrier(); kfree(f->rules->rules_raw); kfree(f->rules); kfree(f); @@ -503,11 +517,14 @@ static int canprio_dump(struct tcf_proto *tp, unsigned long fh, { struct canprio_filter *f = (struct canprio_filter *) fh; struct nlattr *nest; + struct canprio_rules *r; printk("%s() invoked\n", __FUNCTION__); if (f == NULL) return skb->len; + rcu_read_lock(); + r = rcu_dereference(f->rules); t->tcm_handle = f->handle; nest = nla_nest_start(skb, TCA_OPTIONS); @@ -517,16 +534,18 @@ static int canprio_dump(struct tcf_proto *tp, unsigned long fh, if (f->res.classid) NLA_PUT_U32(skb, TCA_CANPRIO_CLASSID, f->res.classid); - NLA_PUT(skb, TCA_CANPRIO_RULES, f->rules->rules_count * - sizeof(struct can_filter), f->rules->rules_raw); + NLA_PUT(skb, TCA_CANPRIO_RULES, r->rules_count * + sizeof(struct can_filter), r->rules_raw); nla_nest_end(skb, nest); + rcu_read_unlock(); return skb->len; nla_put_failure: nla_nest_cancel(skb, nest); + rcu_read_unlock(); return -1; } -- 2.39.2