pkt_sched: Add and use qdisc_root() and qdisc_root_lock().

When code wants to lock the qdisc tree state, the logic
operation it's doing is locking the top-level qdisc that
sits of the root of the netdev_queue.

Add qdisc_root_lock() to represent this and convert the
easiest cases.

In order for this to work out in all cases, we have to
hook up the noop_qdisc to a dummy netdev_queue.

Signed-off-by: David S. Miller <davem@davemloft.net>
diff --git a/net/sched/sch_generic.c b/net/sched/sch_generic.c
index ac208c2..739a871 100644
--- a/net/sched/sch_generic.c
+++ b/net/sched/sch_generic.c
@@ -151,14 +151,17 @@
 {
 	int ret = NETDEV_TX_BUSY;
 	struct net_device *dev;
+	spinlock_t *root_lock;
 	struct sk_buff *skb;
 
 	/* Dequeue packet */
 	if (unlikely((skb = dequeue_skb(q)) == NULL))
 		return 0;
 
-	/* And release queue */
-	spin_unlock(&txq->lock);
+	root_lock = qdisc_root_lock(q);
+
+	/* And release qdisc */
+	spin_unlock(root_lock);
 
 	dev = txq->dev;
 
@@ -167,7 +170,7 @@
 		ret = dev_hard_start_xmit(skb, dev, txq);
 	HARD_TX_UNLOCK(dev, txq);
 
-	spin_lock(&txq->lock);
+	spin_lock(root_lock);
 
 	switch (ret) {
 	case NETDEV_TX_OK:
@@ -345,12 +348,18 @@
 	.owner		=	THIS_MODULE,
 };
 
+static struct netdev_queue noop_netdev_queue = {
+	.lock		=	__SPIN_LOCK_UNLOCKED(noop_netdev_queue.lock),
+	.qdisc		=	&noop_qdisc,
+};
+
 struct Qdisc noop_qdisc = {
 	.enqueue	=	noop_enqueue,
 	.dequeue	=	noop_dequeue,
 	.flags		=	TCQ_F_BUILTIN,
 	.ops		=	&noop_qdisc_ops,
 	.list		=	LIST_HEAD_INIT(noop_qdisc.list),
+	.dev_queue	=	&noop_netdev_queue,
 };
 EXPORT_SYMBOL(noop_qdisc);
 
@@ -666,19 +675,21 @@
 
 	for (i = 0; i < dev->num_tx_queues; i++) {
 		struct netdev_queue *dev_queue;
+		spinlock_t *root_lock;
 		struct Qdisc *q;
 		int val;
 
 		dev_queue = netdev_get_tx_queue(dev, i);
 		q = dev_queue->qdisc;
+		root_lock = qdisc_root_lock(q);
 
 		if (lock)
-			spin_lock_bh(&dev_queue->lock);
+			spin_lock_bh(root_lock);
 
 		val = test_bit(__QDISC_STATE_RUNNING, &q->state);
 
 		if (lock)
-			spin_unlock_bh(&dev_queue->lock);
+			spin_unlock_bh(root_lock);
 
 		if (val)
 			return true;