diff options
author | David S. Miller <davem@davemloft.net> | 2008-07-16 10:42:40 +0200 |
---|---|---|
committer | David S. Miller <davem@davemloft.net> | 2008-07-18 04:21:19 +0200 |
commit | 7698b4fcabcd790efc4f226bada1e7b5870653af (patch) | |
tree | 031ce7a911fc5bff995421a5615d9ab25416a479 /net/sched/sch_generic.c | |
parent | pkt_sched: Make QDISC_RUNNING a qdisc state. (diff) | |
download | linux-7698b4fcabcd790efc4f226bada1e7b5870653af.tar.xz linux-7698b4fcabcd790efc4f226bada1e7b5870653af.zip |
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>
Diffstat (limited to 'net/sched/sch_generic.c')
-rw-r--r-- | net/sched/sch_generic.c | 21 |
1 files changed, 16 insertions, 5 deletions
diff --git a/net/sched/sch_generic.c b/net/sched/sch_generic.c index ac208c2b2d10..739a8711ab30 100644 --- a/net/sched/sch_generic.c +++ b/net/sched/sch_generic.c @@ -151,14 +151,17 @@ static inline int qdisc_restart(struct netdev_queue *txq, { 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 @@ static inline int qdisc_restart(struct netdev_queue *txq, 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 @@ struct Qdisc_ops noop_qdisc_ops __read_mostly = { .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 @@ static bool some_qdisc_is_running(struct net_device *dev, int lock) 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; |