aboutsummaryrefslogtreecommitdiffstats
path: root/include/net/sch_generic.h
diff options
context:
space:
mode:
authorJohn Fastabend <john.fastabend@gmail.com>2014-09-28 14:52:56 -0400
committerDavid S. Miller <davem@davemloft.net>2014-09-30 01:02:26 -0400
commit22e0f8b9322cb1a48b1357e8f4ae6f5a9eca8cfa (patch)
tree2c9ef18dca9d9a441d92ea57cf7f7a292f4ceb3f /include/net/sch_generic.h
parent79cf79abce71eb7dbc40e2f3121048ca5405cb47 (diff)
net: sched: make bstats per cpu and estimator RCU safe
In order to run qdisc's without locking statistics and estimators need to be handled correctly. To resolve bstats make the statistics per cpu. And because this is only needed for qdiscs that are running without locks which is not the case for most qdiscs in the near future only create percpu stats when qdiscs set the TCQ_F_CPUSTATS flag. Next because estimators use the bstats to calculate packets per second and bytes per second the estimator code paths are updated to use the per cpu statistics. Signed-off-by: John Fastabend <john.r.fastabend@intel.com> Signed-off-by: David S. Miller <davem@davemloft.net>
Diffstat (limited to 'include/net/sch_generic.h')
-rw-r--r--include/net/sch_generic.h22
1 files changed, 21 insertions, 1 deletions
diff --git a/include/net/sch_generic.h b/include/net/sch_generic.h
index e65b8e0752af..4b9351120fd8 100644
--- a/include/net/sch_generic.h
+++ b/include/net/sch_generic.h
@@ -6,6 +6,7 @@
6#include <linux/rcupdate.h> 6#include <linux/rcupdate.h>
7#include <linux/pkt_sched.h> 7#include <linux/pkt_sched.h>
8#include <linux/pkt_cls.h> 8#include <linux/pkt_cls.h>
9#include <linux/percpu.h>
9#include <net/gen_stats.h> 10#include <net/gen_stats.h>
10#include <net/rtnetlink.h> 11#include <net/rtnetlink.h>
11 12
@@ -58,6 +59,7 @@ struct Qdisc {
58 * multiqueue device. 59 * multiqueue device.
59 */ 60 */
60#define TCQ_F_WARN_NONWC (1 << 16) 61#define TCQ_F_WARN_NONWC (1 << 16)
62#define TCQ_F_CPUSTATS 0x20 /* run using percpu statistics */
61 u32 limit; 63 u32 limit;
62 const struct Qdisc_ops *ops; 64 const struct Qdisc_ops *ops;
63 struct qdisc_size_table __rcu *stab; 65 struct qdisc_size_table __rcu *stab;
@@ -83,7 +85,10 @@ struct Qdisc {
83 */ 85 */
84 unsigned long state; 86 unsigned long state;
85 struct sk_buff_head q; 87 struct sk_buff_head q;
86 struct gnet_stats_basic_packed bstats; 88 union {
89 struct gnet_stats_basic_packed bstats;
90 struct gnet_stats_basic_cpu __percpu *cpu_bstats;
91 } __packed;
87 unsigned int __state; 92 unsigned int __state;
88 struct gnet_stats_queue qstats; 93 struct gnet_stats_queue qstats;
89 struct rcu_head rcu_head; 94 struct rcu_head rcu_head;
@@ -487,6 +492,10 @@ static inline int qdisc_enqueue_root(struct sk_buff *skb, struct Qdisc *sch)
487 return qdisc_enqueue(skb, sch) & NET_XMIT_MASK; 492 return qdisc_enqueue(skb, sch) & NET_XMIT_MASK;
488} 493}
489 494
495static inline bool qdisc_is_percpu_stats(const struct Qdisc *q)
496{
497 return q->flags & TCQ_F_CPUSTATS;
498}
490 499
491static inline void bstats_update(struct gnet_stats_basic_packed *bstats, 500static inline void bstats_update(struct gnet_stats_basic_packed *bstats,
492 const struct sk_buff *skb) 501 const struct sk_buff *skb)
@@ -495,6 +504,17 @@ static inline void bstats_update(struct gnet_stats_basic_packed *bstats,
495 bstats->packets += skb_is_gso(skb) ? skb_shinfo(skb)->gso_segs : 1; 504 bstats->packets += skb_is_gso(skb) ? skb_shinfo(skb)->gso_segs : 1;
496} 505}
497 506
507static inline void qdisc_bstats_update_cpu(struct Qdisc *sch,
508 const struct sk_buff *skb)
509{
510 struct gnet_stats_basic_cpu *bstats =
511 this_cpu_ptr(sch->cpu_bstats);
512
513 u64_stats_update_begin(&bstats->syncp);
514 bstats_update(&bstats->bstats, skb);
515 u64_stats_update_end(&bstats->syncp);
516}
517
498static inline void qdisc_bstats_update(struct Qdisc *sch, 518static inline void qdisc_bstats_update(struct Qdisc *sch,
499 const struct sk_buff *skb) 519 const struct sk_buff *skb)
500{ 520{