int rules_count;
int eff_rules_count;
int sff_rules_count;
+
+ struct rcu_head rcu;
};
struct canprio_head {
{
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;
}
}
+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)
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;
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);
{
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);
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;
}