aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorEric Dumazet <edumazet@google.com>2016-06-06 12:37:15 -0400
committerDavid S. Miller <davem@davemloft.net>2016-06-07 19:37:13 -0400
commitf9eb8aea2a1e12fc2f584d1627deeb957435a801 (patch)
treebc3cf06664da45bc0e6ce9b5165dba534ed11751
parent64151ae36ed93c45654069c8aff2a7f0125075e8 (diff)
net_sched: transform qdisc running bit into a seqcount
Instead of using a single bit (__QDISC___STATE_RUNNING) in sch->__state, use a seqcount. This adds lockdep support, but more importantly it will allow us to sample qdisc/class statistics without having to grab qdisc root lock. Signed-off-by: Eric Dumazet <edumazet@google.com> Cc: Cong Wang <xiyou.wangcong@gmail.com> Cc: Jamal Hadi Salim <jhs@mojatatu.com> Signed-off-by: David S. Miller <davem@davemloft.net>
-rw-r--r--drivers/net/bonding/bond_main.c2
-rw-r--r--drivers/net/ppp/ppp_generic.c3
-rw-r--r--drivers/net/team/team.c2
-rw-r--r--include/linux/netdevice.h1
-rw-r--r--include/net/sch_generic.h15
-rw-r--r--net/bluetooth/6lowpan.c2
-rw-r--r--net/core/dev.c2
-rw-r--r--net/ieee802154/6lowpan/core.c3
-rw-r--r--net/l2tp/l2tp_eth.c4
-rw-r--r--net/sched/sch_generic.c14
10 files changed, 32 insertions, 16 deletions
diff --git a/drivers/net/bonding/bond_main.c b/drivers/net/bonding/bond_main.c
index 941ec99cd3b6..681af31a60ed 100644
--- a/drivers/net/bonding/bond_main.c
+++ b/drivers/net/bonding/bond_main.c
@@ -4610,6 +4610,7 @@ static int bond_check_params(struct bond_params *params)
4610static struct lock_class_key bonding_netdev_xmit_lock_key; 4610static struct lock_class_key bonding_netdev_xmit_lock_key;
4611static struct lock_class_key bonding_netdev_addr_lock_key; 4611static struct lock_class_key bonding_netdev_addr_lock_key;
4612static struct lock_class_key bonding_tx_busylock_key; 4612static struct lock_class_key bonding_tx_busylock_key;
4613static struct lock_class_key bonding_qdisc_running_key;
4613 4614
4614static void bond_set_lockdep_class_one(struct net_device *dev, 4615static void bond_set_lockdep_class_one(struct net_device *dev,
4615 struct netdev_queue *txq, 4616 struct netdev_queue *txq,
@@ -4625,6 +4626,7 @@ static void bond_set_lockdep_class(struct net_device *dev)
4625 &bonding_netdev_addr_lock_key); 4626 &bonding_netdev_addr_lock_key);
4626 netdev_for_each_tx_queue(dev, bond_set_lockdep_class_one, NULL); 4627 netdev_for_each_tx_queue(dev, bond_set_lockdep_class_one, NULL);
4627 dev->qdisc_tx_busylock = &bonding_tx_busylock_key; 4628 dev->qdisc_tx_busylock = &bonding_tx_busylock_key;
4629 dev->qdisc_running_key = &bonding_qdisc_running_key;
4628} 4630}
4629 4631
4630/* Called from registration process */ 4632/* Called from registration process */
diff --git a/drivers/net/ppp/ppp_generic.c b/drivers/net/ppp/ppp_generic.c
index 8dedafa1a95d..aeabaa42317f 100644
--- a/drivers/net/ppp/ppp_generic.c
+++ b/drivers/net/ppp/ppp_generic.c
@@ -1313,9 +1313,12 @@ ppp_get_stats64(struct net_device *dev, struct rtnl_link_stats64 *stats64)
1313} 1313}
1314 1314
1315static struct lock_class_key ppp_tx_busylock; 1315static struct lock_class_key ppp_tx_busylock;
1316static struct lock_class_key ppp_qdisc_running_key;
1317
1316static int ppp_dev_init(struct net_device *dev) 1318static int ppp_dev_init(struct net_device *dev)
1317{ 1319{
1318 dev->qdisc_tx_busylock = &ppp_tx_busylock; 1320 dev->qdisc_tx_busylock = &ppp_tx_busylock;
1321 dev->qdisc_running_key = &ppp_qdisc_running_key;
1319 return 0; 1322 return 0;
1320} 1323}
1321 1324
diff --git a/drivers/net/team/team.c b/drivers/net/team/team.c
index 2ace126533cd..00eb38956a2c 100644
--- a/drivers/net/team/team.c
+++ b/drivers/net/team/team.c
@@ -1577,6 +1577,7 @@ static const struct team_option team_options[] = {
1577static struct lock_class_key team_netdev_xmit_lock_key; 1577static struct lock_class_key team_netdev_xmit_lock_key;
1578static struct lock_class_key team_netdev_addr_lock_key; 1578static struct lock_class_key team_netdev_addr_lock_key;
1579static struct lock_class_key team_tx_busylock_key; 1579static struct lock_class_key team_tx_busylock_key;
1580static struct lock_class_key team_qdisc_running_key;
1580 1581
1581static void team_set_lockdep_class_one(struct net_device *dev, 1582static void team_set_lockdep_class_one(struct net_device *dev,
1582 struct netdev_queue *txq, 1583 struct netdev_queue *txq,
@@ -1590,6 +1591,7 @@ static void team_set_lockdep_class(struct net_device *dev)
1590 lockdep_set_class(&dev->addr_list_lock, &team_netdev_addr_lock_key); 1591 lockdep_set_class(&dev->addr_list_lock, &team_netdev_addr_lock_key);
1591 netdev_for_each_tx_queue(dev, team_set_lockdep_class_one, NULL); 1592 netdev_for_each_tx_queue(dev, team_set_lockdep_class_one, NULL);
1592 dev->qdisc_tx_busylock = &team_tx_busylock_key; 1593 dev->qdisc_tx_busylock = &team_tx_busylock_key;
1594 dev->qdisc_running_key = &team_qdisc_running_key;
1593} 1595}
1594 1596
1595static int team_init(struct net_device *dev) 1597static int team_init(struct net_device *dev)
diff --git a/include/linux/netdevice.h b/include/linux/netdevice.h
index fa6df2699532..59d7e06d88d5 100644
--- a/include/linux/netdevice.h
+++ b/include/linux/netdevice.h
@@ -1862,6 +1862,7 @@ struct net_device {
1862#endif 1862#endif
1863 struct phy_device *phydev; 1863 struct phy_device *phydev;
1864 struct lock_class_key *qdisc_tx_busylock; 1864 struct lock_class_key *qdisc_tx_busylock;
1865 struct lock_class_key *qdisc_running_key;
1865 bool proto_down; 1866 bool proto_down;
1866}; 1867};
1867#define to_net_dev(d) container_of(d, struct net_device, dev) 1868#define to_net_dev(d) container_of(d, struct net_device, dev)
diff --git a/include/net/sch_generic.h b/include/net/sch_generic.h
index a1fd76c22a59..bff8d895ef8a 100644
--- a/include/net/sch_generic.h
+++ b/include/net/sch_generic.h
@@ -29,13 +29,6 @@ enum qdisc_state_t {
29 __QDISC_STATE_THROTTLED, 29 __QDISC_STATE_THROTTLED,
30}; 30};
31 31
32/*
33 * following bits are only changed while qdisc lock is held
34 */
35enum qdisc___state_t {
36 __QDISC___STATE_RUNNING = 1,
37};
38
39struct qdisc_size_table { 32struct qdisc_size_table {
40 struct rcu_head rcu; 33 struct rcu_head rcu;
41 struct list_head list; 34 struct list_head list;
@@ -93,7 +86,7 @@ struct Qdisc {
93 unsigned long state; 86 unsigned long state;
94 struct sk_buff_head q; 87 struct sk_buff_head q;
95 struct gnet_stats_basic_packed bstats; 88 struct gnet_stats_basic_packed bstats;
96 unsigned int __state; 89 seqcount_t running;
97 struct gnet_stats_queue qstats; 90 struct gnet_stats_queue qstats;
98 struct rcu_head rcu_head; 91 struct rcu_head rcu_head;
99 int padded; 92 int padded;
@@ -104,20 +97,20 @@ struct Qdisc {
104 97
105static inline bool qdisc_is_running(const struct Qdisc *qdisc) 98static inline bool qdisc_is_running(const struct Qdisc *qdisc)
106{ 99{
107 return (qdisc->__state & __QDISC___STATE_RUNNING) ? true : false; 100 return (raw_read_seqcount(&qdisc->running) & 1) ? true : false;
108} 101}
109 102
110static inline bool qdisc_run_begin(struct Qdisc *qdisc) 103static inline bool qdisc_run_begin(struct Qdisc *qdisc)
111{ 104{
112 if (qdisc_is_running(qdisc)) 105 if (qdisc_is_running(qdisc))
113 return false; 106 return false;
114 qdisc->__state |= __QDISC___STATE_RUNNING; 107 write_seqcount_begin(&qdisc->running);
115 return true; 108 return true;
116} 109}
117 110
118static inline void qdisc_run_end(struct Qdisc *qdisc) 111static inline void qdisc_run_end(struct Qdisc *qdisc)
119{ 112{
120 qdisc->__state &= ~__QDISC___STATE_RUNNING; 113 write_seqcount_end(&qdisc->running);
121} 114}
122 115
123static inline bool qdisc_may_bulk(const struct Qdisc *qdisc) 116static inline bool qdisc_may_bulk(const struct Qdisc *qdisc)
diff --git a/net/bluetooth/6lowpan.c b/net/bluetooth/6lowpan.c
index 780089d75915..977a11e418d0 100644
--- a/net/bluetooth/6lowpan.c
+++ b/net/bluetooth/6lowpan.c
@@ -629,6 +629,7 @@ static netdev_tx_t bt_xmit(struct sk_buff *skb, struct net_device *netdev)
629 629
630static struct lock_class_key bt_tx_busylock; 630static struct lock_class_key bt_tx_busylock;
631static struct lock_class_key bt_netdev_xmit_lock_key; 631static struct lock_class_key bt_netdev_xmit_lock_key;
632static struct lock_class_key bt_qdisc_running_key;
632 633
633static void bt_set_lockdep_class_one(struct net_device *dev, 634static void bt_set_lockdep_class_one(struct net_device *dev,
634 struct netdev_queue *txq, 635 struct netdev_queue *txq,
@@ -641,6 +642,7 @@ static int bt_dev_init(struct net_device *dev)
641{ 642{
642 netdev_for_each_tx_queue(dev, bt_set_lockdep_class_one, NULL); 643 netdev_for_each_tx_queue(dev, bt_set_lockdep_class_one, NULL);
643 dev->qdisc_tx_busylock = &bt_tx_busylock; 644 dev->qdisc_tx_busylock = &bt_tx_busylock;
645 dev->qdisc_running_key = &bt_qdisc_running_key;
644 646
645 return 0; 647 return 0;
646} 648}
diff --git a/net/core/dev.c b/net/core/dev.c
index 896b686d1966..e0bcc39f4a7d 100644
--- a/net/core/dev.c
+++ b/net/core/dev.c
@@ -3075,7 +3075,7 @@ static inline int __dev_xmit_skb(struct sk_buff *skb, struct Qdisc *q,
3075 /* 3075 /*
3076 * Heuristic to force contended enqueues to serialize on a 3076 * Heuristic to force contended enqueues to serialize on a
3077 * separate lock before trying to get qdisc main lock. 3077 * separate lock before trying to get qdisc main lock.
3078 * This permits __QDISC___STATE_RUNNING owner to get the lock more 3078 * This permits qdisc->running owner to get the lock more
3079 * often and dequeue packets faster. 3079 * often and dequeue packets faster.
3080 */ 3080 */
3081 contended = qdisc_is_running(q); 3081 contended = qdisc_is_running(q);
diff --git a/net/ieee802154/6lowpan/core.c b/net/ieee802154/6lowpan/core.c
index dd085db8580e..14aa5effd29a 100644
--- a/net/ieee802154/6lowpan/core.c
+++ b/net/ieee802154/6lowpan/core.c
@@ -60,6 +60,7 @@ static struct header_ops lowpan_header_ops = {
60 60
61static struct lock_class_key lowpan_tx_busylock; 61static struct lock_class_key lowpan_tx_busylock;
62static struct lock_class_key lowpan_netdev_xmit_lock_key; 62static struct lock_class_key lowpan_netdev_xmit_lock_key;
63static struct lock_class_key lowpan_qdisc_running_key;
63 64
64static void lowpan_set_lockdep_class_one(struct net_device *ldev, 65static void lowpan_set_lockdep_class_one(struct net_device *ldev,
65 struct netdev_queue *txq, 66 struct netdev_queue *txq,
@@ -73,6 +74,8 @@ static int lowpan_dev_init(struct net_device *ldev)
73{ 74{
74 netdev_for_each_tx_queue(ldev, lowpan_set_lockdep_class_one, NULL); 75 netdev_for_each_tx_queue(ldev, lowpan_set_lockdep_class_one, NULL);
75 ldev->qdisc_tx_busylock = &lowpan_tx_busylock; 76 ldev->qdisc_tx_busylock = &lowpan_tx_busylock;
77 ldev->qdisc_running_key = &lowpan_qdisc_running_key;
78
76 return 0; 79 return 0;
77} 80}
78 81
diff --git a/net/l2tp/l2tp_eth.c b/net/l2tp/l2tp_eth.c
index e253c26f31ac..c00d72d182fa 100644
--- a/net/l2tp/l2tp_eth.c
+++ b/net/l2tp/l2tp_eth.c
@@ -68,6 +68,8 @@ static inline struct l2tp_eth_net *l2tp_eth_pernet(struct net *net)
68} 68}
69 69
70static struct lock_class_key l2tp_eth_tx_busylock; 70static struct lock_class_key l2tp_eth_tx_busylock;
71static struct lock_class_key l2tp_qdisc_running_key;
72
71static int l2tp_eth_dev_init(struct net_device *dev) 73static int l2tp_eth_dev_init(struct net_device *dev)
72{ 74{
73 struct l2tp_eth *priv = netdev_priv(dev); 75 struct l2tp_eth *priv = netdev_priv(dev);
@@ -76,6 +78,8 @@ static int l2tp_eth_dev_init(struct net_device *dev)
76 eth_hw_addr_random(dev); 78 eth_hw_addr_random(dev);
77 eth_broadcast_addr(dev->broadcast); 79 eth_broadcast_addr(dev->broadcast);
78 dev->qdisc_tx_busylock = &l2tp_eth_tx_busylock; 80 dev->qdisc_tx_busylock = &l2tp_eth_tx_busylock;
81 dev->qdisc_running_key = &l2tp_qdisc_running_key;
82
79 return 0; 83 return 0;
80} 84}
81 85
diff --git a/net/sched/sch_generic.c b/net/sched/sch_generic.c
index 269dd71b3828..cebea73e70ac 100644
--- a/net/sched/sch_generic.c
+++ b/net/sched/sch_generic.c
@@ -110,7 +110,7 @@ static struct sk_buff *dequeue_skb(struct Qdisc *q, bool *validate,
110 110
111/* 111/*
112 * Transmit possibly several skbs, and handle the return status as 112 * Transmit possibly several skbs, and handle the return status as
113 * required. Holding the __QDISC___STATE_RUNNING bit guarantees that 113 * required. Owning running seqcount bit guarantees that
114 * only one CPU can execute this function. 114 * only one CPU can execute this function.
115 * 115 *
116 * Returns to the caller: 116 * Returns to the caller:
@@ -137,10 +137,10 @@ int sch_direct_xmit(struct sk_buff *skb, struct Qdisc *q,
137 137
138 HARD_TX_UNLOCK(dev, txq); 138 HARD_TX_UNLOCK(dev, txq);
139 } else { 139 } else {
140 spin_lock(root_lock); 140 spin_lock_nested(root_lock, SINGLE_DEPTH_NESTING);
141 return qdisc_qlen(q); 141 return qdisc_qlen(q);
142 } 142 }
143 spin_lock(root_lock); 143 spin_lock_nested(root_lock, SINGLE_DEPTH_NESTING);
144 144
145 if (dev_xmit_complete(ret)) { 145 if (dev_xmit_complete(ret)) {
146 /* Driver sent out skb successfully or skb was consumed */ 146 /* Driver sent out skb successfully or skb was consumed */
@@ -163,7 +163,7 @@ int sch_direct_xmit(struct sk_buff *skb, struct Qdisc *q,
163/* 163/*
164 * NOTE: Called under qdisc_lock(q) with locally disabled BH. 164 * NOTE: Called under qdisc_lock(q) with locally disabled BH.
165 * 165 *
166 * __QDISC___STATE_RUNNING guarantees only one CPU can process 166 * running seqcount guarantees only one CPU can process
167 * this qdisc at a time. qdisc_lock(q) serializes queue accesses for 167 * this qdisc at a time. qdisc_lock(q) serializes queue accesses for
168 * this queue. 168 * this queue.
169 * 169 *
@@ -379,6 +379,7 @@ struct Qdisc noop_qdisc = {
379 .list = LIST_HEAD_INIT(noop_qdisc.list), 379 .list = LIST_HEAD_INIT(noop_qdisc.list),
380 .q.lock = __SPIN_LOCK_UNLOCKED(noop_qdisc.q.lock), 380 .q.lock = __SPIN_LOCK_UNLOCKED(noop_qdisc.q.lock),
381 .dev_queue = &noop_netdev_queue, 381 .dev_queue = &noop_netdev_queue,
382 .running = SEQCNT_ZERO(noop_qdisc.running),
382 .busylock = __SPIN_LOCK_UNLOCKED(noop_qdisc.busylock), 383 .busylock = __SPIN_LOCK_UNLOCKED(noop_qdisc.busylock),
383}; 384};
384EXPORT_SYMBOL(noop_qdisc); 385EXPORT_SYMBOL(noop_qdisc);
@@ -537,6 +538,7 @@ struct Qdisc_ops pfifo_fast_ops __read_mostly = {
537EXPORT_SYMBOL(pfifo_fast_ops); 538EXPORT_SYMBOL(pfifo_fast_ops);
538 539
539static struct lock_class_key qdisc_tx_busylock; 540static struct lock_class_key qdisc_tx_busylock;
541static struct lock_class_key qdisc_running_key;
540 542
541struct Qdisc *qdisc_alloc(struct netdev_queue *dev_queue, 543struct Qdisc *qdisc_alloc(struct netdev_queue *dev_queue,
542 const struct Qdisc_ops *ops) 544 const struct Qdisc_ops *ops)
@@ -570,6 +572,10 @@ struct Qdisc *qdisc_alloc(struct netdev_queue *dev_queue,
570 lockdep_set_class(&sch->busylock, 572 lockdep_set_class(&sch->busylock,
571 dev->qdisc_tx_busylock ?: &qdisc_tx_busylock); 573 dev->qdisc_tx_busylock ?: &qdisc_tx_busylock);
572 574
575 seqcount_init(&sch->running);
576 lockdep_set_class(&sch->running,
577 dev->qdisc_running_key ?: &qdisc_running_key);
578
573 sch->ops = ops; 579 sch->ops = ops;
574 sch->enqueue = ops->enqueue; 580 sch->enqueue = ops->enqueue;
575 sch->dequeue = ops->dequeue; 581 sch->dequeue = ops->dequeue;