aboutsummaryrefslogtreecommitdiffstats
path: root/net/sched
diff options
context:
space:
mode:
authorEric Dumazet <eric.dumazet@gmail.com>2011-01-19 22:48:19 -0500
committerDavid S. Miller <davem@davemloft.net>2011-01-20 19:59:32 -0500
commita2da570d62fcb9e8816f6920e1ec02c706b289fa (patch)
tree9a24b76262c40ec2f1be11e29e224c7d7b20fa26 /net/sched
parentfd245a4adb5288eac37250875f237c40a20a1944 (diff)
net_sched: RCU conversion of stab
This patch converts stab qdisc management to RCU, so that we can perform the qdisc_calculate_pkt_len() call before getting qdisc lock. This shortens the lock's held time in __dev_xmit_skb(). This permits more qdiscs to get TCQ_F_CAN_BYPASS status, avoiding lot of cache misses and so reducing latencies. Signed-off-by: Eric Dumazet <eric.dumazet@gmail.com> CC: Patrick McHardy <kaber@trash.net> CC: Jesper Dangaard Brouer <hawk@diku.dk> CC: Jarek Poplawski <jarkao2@gmail.com> CC: Jamal Hadi Salim <hadi@cyberus.ca> CC: Stephen Hemminger <shemminger@vyatta.com> Signed-off-by: David S. Miller <davem@davemloft.net>
Diffstat (limited to 'net/sched')
-rw-r--r--net/sched/sch_api.c26
-rw-r--r--net/sched/sch_generic.c2
2 files changed, 18 insertions, 10 deletions
diff --git a/net/sched/sch_api.c b/net/sched/sch_api.c
index 374fcbef80e8..150741579408 100644
--- a/net/sched/sch_api.c
+++ b/net/sched/sch_api.c
@@ -398,6 +398,11 @@ static struct qdisc_size_table *qdisc_get_stab(struct nlattr *opt)
398 return stab; 398 return stab;
399} 399}
400 400
401static void stab_kfree_rcu(struct rcu_head *head)
402{
403 kfree(container_of(head, struct qdisc_size_table, rcu));
404}
405
401void qdisc_put_stab(struct qdisc_size_table *tab) 406void qdisc_put_stab(struct qdisc_size_table *tab)
402{ 407{
403 if (!tab) 408 if (!tab)
@@ -407,7 +412,7 @@ void qdisc_put_stab(struct qdisc_size_table *tab)
407 412
408 if (--tab->refcnt == 0) { 413 if (--tab->refcnt == 0) {
409 list_del(&tab->list); 414 list_del(&tab->list);
410 kfree(tab); 415 call_rcu_bh(&tab->rcu, stab_kfree_rcu);
411 } 416 }
412 417
413 spin_unlock(&qdisc_stab_lock); 418 spin_unlock(&qdisc_stab_lock);
@@ -430,7 +435,7 @@ nla_put_failure:
430 return -1; 435 return -1;
431} 436}
432 437
433void qdisc_calculate_pkt_len(struct sk_buff *skb, struct qdisc_size_table *stab) 438void __qdisc_calculate_pkt_len(struct sk_buff *skb, const struct qdisc_size_table *stab)
434{ 439{
435 int pkt_len, slot; 440 int pkt_len, slot;
436 441
@@ -456,7 +461,7 @@ out:
456 pkt_len = 1; 461 pkt_len = 1;
457 qdisc_skb_cb(skb)->pkt_len = pkt_len; 462 qdisc_skb_cb(skb)->pkt_len = pkt_len;
458} 463}
459EXPORT_SYMBOL(qdisc_calculate_pkt_len); 464EXPORT_SYMBOL(__qdisc_calculate_pkt_len);
460 465
461void qdisc_warn_nonwc(char *txt, struct Qdisc *qdisc) 466void qdisc_warn_nonwc(char *txt, struct Qdisc *qdisc)
462{ 467{
@@ -835,7 +840,7 @@ qdisc_create(struct net_device *dev, struct netdev_queue *dev_queue,
835 err = PTR_ERR(stab); 840 err = PTR_ERR(stab);
836 goto err_out4; 841 goto err_out4;
837 } 842 }
838 sch->stab = stab; 843 rcu_assign_pointer(sch->stab, stab);
839 } 844 }
840 if (tca[TCA_RATE]) { 845 if (tca[TCA_RATE]) {
841 spinlock_t *root_lock; 846 spinlock_t *root_lock;
@@ -875,7 +880,7 @@ err_out4:
875 * Any broken qdiscs that would require a ops->reset() here? 880 * Any broken qdiscs that would require a ops->reset() here?
876 * The qdisc was never in action so it shouldn't be necessary. 881 * The qdisc was never in action so it shouldn't be necessary.
877 */ 882 */
878 qdisc_put_stab(sch->stab); 883 qdisc_put_stab(rtnl_dereference(sch->stab));
879 if (ops->destroy) 884 if (ops->destroy)
880 ops->destroy(sch); 885 ops->destroy(sch);
881 goto err_out3; 886 goto err_out3;
@@ -883,7 +888,7 @@ err_out4:
883 888
884static int qdisc_change(struct Qdisc *sch, struct nlattr **tca) 889static int qdisc_change(struct Qdisc *sch, struct nlattr **tca)
885{ 890{
886 struct qdisc_size_table *stab = NULL; 891 struct qdisc_size_table *ostab, *stab = NULL;
887 int err = 0; 892 int err = 0;
888 893
889 if (tca[TCA_OPTIONS]) { 894 if (tca[TCA_OPTIONS]) {
@@ -900,8 +905,9 @@ static int qdisc_change(struct Qdisc *sch, struct nlattr **tca)
900 return PTR_ERR(stab); 905 return PTR_ERR(stab);
901 } 906 }
902 907
903 qdisc_put_stab(sch->stab); 908 ostab = rtnl_dereference(sch->stab);
904 sch->stab = stab; 909 rcu_assign_pointer(sch->stab, stab);
910 qdisc_put_stab(ostab);
905 911
906 if (tca[TCA_RATE]) { 912 if (tca[TCA_RATE]) {
907 /* NB: ignores errors from replace_estimator 913 /* NB: ignores errors from replace_estimator
@@ -1180,6 +1186,7 @@ static int tc_fill_qdisc(struct sk_buff *skb, struct Qdisc *q, u32 clid,
1180 struct nlmsghdr *nlh; 1186 struct nlmsghdr *nlh;
1181 unsigned char *b = skb_tail_pointer(skb); 1187 unsigned char *b = skb_tail_pointer(skb);
1182 struct gnet_dump d; 1188 struct gnet_dump d;
1189 struct qdisc_size_table *stab;
1183 1190
1184 nlh = NLMSG_NEW(skb, pid, seq, event, sizeof(*tcm), flags); 1191 nlh = NLMSG_NEW(skb, pid, seq, event, sizeof(*tcm), flags);
1185 tcm = NLMSG_DATA(nlh); 1192 tcm = NLMSG_DATA(nlh);
@@ -1195,7 +1202,8 @@ static int tc_fill_qdisc(struct sk_buff *skb, struct Qdisc *q, u32 clid,
1195 goto nla_put_failure; 1202 goto nla_put_failure;
1196 q->qstats.qlen = q->q.qlen; 1203 q->qstats.qlen = q->q.qlen;
1197 1204
1198 if (q->stab && qdisc_dump_stab(skb, q->stab) < 0) 1205 stab = rtnl_dereference(q->stab);
1206 if (stab && qdisc_dump_stab(skb, stab) < 0)
1199 goto nla_put_failure; 1207 goto nla_put_failure;
1200 1208
1201 if (gnet_stats_start_copy_compat(skb, TCA_STATS2, TCA_STATS, TCA_XSTATS, 1209 if (gnet_stats_start_copy_compat(skb, TCA_STATS2, TCA_STATS, TCA_XSTATS,
diff --git a/net/sched/sch_generic.c b/net/sched/sch_generic.c
index 2f1cb62130da..cc17e794c41e 100644
--- a/net/sched/sch_generic.c
+++ b/net/sched/sch_generic.c
@@ -632,7 +632,7 @@ void qdisc_destroy(struct Qdisc *qdisc)
632#ifdef CONFIG_NET_SCHED 632#ifdef CONFIG_NET_SCHED
633 qdisc_list_del(qdisc); 633 qdisc_list_del(qdisc);
634 634
635 qdisc_put_stab(qdisc->stab); 635 qdisc_put_stab(rtnl_dereference(qdisc->stab));
636#endif 636#endif
637 gen_kill_estimator(&qdisc->bstats, &qdisc->rate_est); 637 gen_kill_estimator(&qdisc->bstats, &qdisc->rate_est);
638 if (ops->reset) 638 if (ops->reset)