]> rtime.felk.cvut.cz Git - lisovros/linux_canprio.git/commitdiff
Reading and changing struct canprio_rules protected by RCU.
authorRostislav Lisovy <lisovy@gmail.com>
Thu, 1 Sep 2011 11:44:35 +0000 (13:44 +0200)
committerRostislav Lisovy <lisovy@gmail.com>
Thu, 1 Sep 2011 11:44:35 +0000 (13:44 +0200)
net/sched/cls_canprio.c

index bba0f4dd4faed528ca835f7892f268ac21be53a4..7efed62009f3e8eeff3834dd4a0691096cbdf9c8 100644 (file)
@@ -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;
 }