diff options
author | John Fastabend <john.fastabend@gmail.com> | 2014-09-12 23:05:27 -0400 |
---|---|---|
committer | David S. Miller <davem@davemloft.net> | 2014-09-13 12:30:25 -0400 |
commit | 25d8c0d55f241ce2d360df1bea48e23a55836ee6 (patch) | |
tree | c0aca67607e7ce560a4a2cebef5fb6d55adf4112 /net/sched/sch_atm.c | |
parent | 46e5da40aec256155cfedee96dd21a75da941f2c (diff) |
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 <john.r.fastabend@intel.com>
Acked-by: Eric Dumazet <edumazet@google.com>
Signed-off-by: David S. Miller <davem@davemloft.net>
Diffstat (limited to 'net/sched/sch_atm.c')
-rw-r--r-- | net/sched/sch_atm.c | 20 |
1 files changed, 11 insertions, 9 deletions
diff --git a/net/sched/sch_atm.c b/net/sched/sch_atm.c index 8449b337f9e3..c398f9c3dbdd 100644 --- a/net/sched/sch_atm.c +++ b/net/sched/sch_atm.c | |||
@@ -41,7 +41,7 @@ | |||
41 | 41 | ||
42 | struct atm_flow_data { | 42 | struct atm_flow_data { |
43 | struct Qdisc *q; /* FIFO, TBF, etc. */ | 43 | struct Qdisc *q; /* FIFO, TBF, etc. */ |
44 | struct tcf_proto *filter_list; | 44 | struct tcf_proto __rcu *filter_list; |
45 | struct atm_vcc *vcc; /* VCC; NULL if VCC is closed */ | 45 | struct atm_vcc *vcc; /* VCC; NULL if VCC is closed */ |
46 | void (*old_pop)(struct atm_vcc *vcc, | 46 | void (*old_pop)(struct atm_vcc *vcc, |
47 | struct sk_buff *skb); /* chaining */ | 47 | struct sk_buff *skb); /* chaining */ |
@@ -273,7 +273,7 @@ static int atm_tc_change(struct Qdisc *sch, u32 classid, u32 parent, | |||
273 | error = -ENOBUFS; | 273 | error = -ENOBUFS; |
274 | goto err_out; | 274 | goto err_out; |
275 | } | 275 | } |
276 | flow->filter_list = NULL; | 276 | RCU_INIT_POINTER(flow->filter_list, NULL); |
277 | flow->q = qdisc_create_dflt(sch->dev_queue, &pfifo_qdisc_ops, classid); | 277 | flow->q = qdisc_create_dflt(sch->dev_queue, &pfifo_qdisc_ops, classid); |
278 | if (!flow->q) | 278 | if (!flow->q) |
279 | flow->q = &noop_qdisc; | 279 | flow->q = &noop_qdisc; |
@@ -311,7 +311,7 @@ static int atm_tc_delete(struct Qdisc *sch, unsigned long arg) | |||
311 | pr_debug("atm_tc_delete(sch %p,[qdisc %p],flow %p)\n", sch, p, flow); | 311 | pr_debug("atm_tc_delete(sch %p,[qdisc %p],flow %p)\n", sch, p, flow); |
312 | if (list_empty(&flow->list)) | 312 | if (list_empty(&flow->list)) |
313 | return -EINVAL; | 313 | return -EINVAL; |
314 | if (flow->filter_list || flow == &p->link) | 314 | if (rcu_access_pointer(flow->filter_list) || flow == &p->link) |
315 | return -EBUSY; | 315 | return -EBUSY; |
316 | /* | 316 | /* |
317 | * Reference count must be 2: one for "keepalive" (set at class | 317 | * Reference count must be 2: one for "keepalive" (set at class |
@@ -345,7 +345,8 @@ static void atm_tc_walk(struct Qdisc *sch, struct qdisc_walker *walker) | |||
345 | } | 345 | } |
346 | } | 346 | } |
347 | 347 | ||
348 | static struct tcf_proto **atm_tc_find_tcf(struct Qdisc *sch, unsigned long cl) | 348 | static struct tcf_proto __rcu **atm_tc_find_tcf(struct Qdisc *sch, |
349 | unsigned long cl) | ||
349 | { | 350 | { |
350 | struct atm_qdisc_data *p = qdisc_priv(sch); | 351 | struct atm_qdisc_data *p = qdisc_priv(sch); |
351 | struct atm_flow_data *flow = (struct atm_flow_data *)cl; | 352 | struct atm_flow_data *flow = (struct atm_flow_data *)cl; |
@@ -369,11 +370,12 @@ static int atm_tc_enqueue(struct sk_buff *skb, struct Qdisc *sch) | |||
369 | flow = NULL; | 370 | flow = NULL; |
370 | if (TC_H_MAJ(skb->priority) != sch->handle || | 371 | if (TC_H_MAJ(skb->priority) != sch->handle || |
371 | !(flow = (struct atm_flow_data *)atm_tc_get(sch, skb->priority))) { | 372 | !(flow = (struct atm_flow_data *)atm_tc_get(sch, skb->priority))) { |
373 | struct tcf_proto *fl; | ||
374 | |||
372 | list_for_each_entry(flow, &p->flows, list) { | 375 | list_for_each_entry(flow, &p->flows, list) { |
373 | if (flow->filter_list) { | 376 | fl = rcu_dereference_bh(flow->filter_list); |
374 | result = tc_classify_compat(skb, | 377 | if (fl) { |
375 | flow->filter_list, | 378 | result = tc_classify_compat(skb, fl, &res); |
376 | &res); | ||
377 | if (result < 0) | 379 | if (result < 0) |
378 | continue; | 380 | continue; |
379 | flow = (struct atm_flow_data *)res.class; | 381 | flow = (struct atm_flow_data *)res.class; |
@@ -544,7 +546,7 @@ static int atm_tc_init(struct Qdisc *sch, struct nlattr *opt) | |||
544 | if (!p->link.q) | 546 | if (!p->link.q) |
545 | p->link.q = &noop_qdisc; | 547 | p->link.q = &noop_qdisc; |
546 | pr_debug("atm_tc_init: link (%p) qdisc %p\n", &p->link, p->link.q); | 548 | pr_debug("atm_tc_init: link (%p) qdisc %p\n", &p->link, p->link.q); |
547 | p->link.filter_list = NULL; | 549 | RCU_INIT_POINTER(p->link.filter_list, NULL); |
548 | p->link.vcc = NULL; | 550 | p->link.vcc = NULL; |
549 | p->link.sock = NULL; | 551 | p->link.sock = NULL; |
550 | p->link.classid = sch->handle; | 552 | p->link.classid = sch->handle; |