aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--include/net/pkt_sched.h2
-rw-r--r--include/net/sch_generic.h1
-rw-r--r--net/sched/sch_generic.c15
3 files changed, 15 insertions, 3 deletions
diff --git a/include/net/pkt_sched.h b/include/net/pkt_sched.h
index b6cdc33b39c1..9d4d87cc970e 100644
--- a/include/net/pkt_sched.h
+++ b/include/net/pkt_sched.h
@@ -12,7 +12,7 @@ struct qdisc_walker {
12 int (*fn)(struct Qdisc *, unsigned long cl, struct qdisc_walker *); 12 int (*fn)(struct Qdisc *, unsigned long cl, struct qdisc_walker *);
13}; 13};
14 14
15#define QDISC_ALIGNTO 32 15#define QDISC_ALIGNTO 64
16#define QDISC_ALIGN(len) (((len) + QDISC_ALIGNTO-1) & ~(QDISC_ALIGNTO-1)) 16#define QDISC_ALIGN(len) (((len) + QDISC_ALIGNTO-1) & ~(QDISC_ALIGNTO-1))
17 17
18static inline void *qdisc_priv(struct Qdisc *q) 18static inline void *qdisc_priv(struct Qdisc *q)
diff --git a/include/net/sch_generic.h b/include/net/sch_generic.h
index 67dc08eaaa45..03ca5d826757 100644
--- a/include/net/sch_generic.h
+++ b/include/net/sch_generic.h
@@ -73,6 +73,7 @@ struct Qdisc {
73 struct sk_buff_head q; 73 struct sk_buff_head q;
74 struct gnet_stats_basic_packed bstats; 74 struct gnet_stats_basic_packed bstats;
75 struct gnet_stats_queue qstats; 75 struct gnet_stats_queue qstats;
76 struct rcu_head rcu_head;
76}; 77};
77 78
78struct Qdisc_class_ops { 79struct Qdisc_class_ops {
diff --git a/net/sched/sch_generic.c b/net/sched/sch_generic.c
index 5173c1e1b19c..17513252e83f 100644
--- a/net/sched/sch_generic.c
+++ b/net/sched/sch_generic.c
@@ -528,7 +528,7 @@ struct Qdisc *qdisc_alloc(struct netdev_queue *dev_queue,
528 unsigned int size; 528 unsigned int size;
529 int err = -ENOBUFS; 529 int err = -ENOBUFS;
530 530
531 /* ensure that the Qdisc and the private data are 32-byte aligned */ 531 /* ensure that the Qdisc and the private data are 64-byte aligned */
532 size = QDISC_ALIGN(sizeof(*sch)); 532 size = QDISC_ALIGN(sizeof(*sch));
533 size += ops->priv_size + (QDISC_ALIGNTO - 1); 533 size += ops->priv_size + (QDISC_ALIGNTO - 1);
534 534
@@ -590,6 +590,13 @@ void qdisc_reset(struct Qdisc *qdisc)
590} 590}
591EXPORT_SYMBOL(qdisc_reset); 591EXPORT_SYMBOL(qdisc_reset);
592 592
593static void qdisc_rcu_free(struct rcu_head *head)
594{
595 struct Qdisc *qdisc = container_of(head, struct Qdisc, rcu_head);
596
597 kfree((char *) qdisc - qdisc->padded);
598}
599
593void qdisc_destroy(struct Qdisc *qdisc) 600void qdisc_destroy(struct Qdisc *qdisc)
594{ 601{
595 const struct Qdisc_ops *ops = qdisc->ops; 602 const struct Qdisc_ops *ops = qdisc->ops;
@@ -613,7 +620,11 @@ void qdisc_destroy(struct Qdisc *qdisc)
613 dev_put(qdisc_dev(qdisc)); 620 dev_put(qdisc_dev(qdisc));
614 621
615 kfree_skb(qdisc->gso_skb); 622 kfree_skb(qdisc->gso_skb);
616 kfree((char *) qdisc - qdisc->padded); 623 /*
624 * gen_estimator est_timer() might access qdisc->q.lock,
625 * wait a RCU grace period before freeing qdisc.
626 */
627 call_rcu(&qdisc->rcu_head, qdisc_rcu_free);
617} 628}
618EXPORT_SYMBOL(qdisc_destroy); 629EXPORT_SYMBOL(qdisc_destroy);
619 630