pkt_sched: Fix tx queue selection in tc_modify_qdisc
authorJarek Poplawski <jarkao2@gmail.com>
Tue, 15 Sep 2009 09:53:07 +0000 (02:53 -0700)
committerDavid S. Miller <davem@davemloft.net>
Tue, 15 Sep 2009 09:53:07 +0000 (02:53 -0700)
After the recent mq change there is the new select_queue qdisc class
method used in tc_modify_qdisc, but it works OK only for direct child
qdiscs of mq qdisc. Grandchildren always get the first tx queue, which
would give wrong qdisc_root etc. results (e.g. for sch_htb as child of
sch_prio). This patch fixes it by using parent's dev_queue for such
grandchildren qdiscs. The select_queue method's return type is changed
BTW.

With feedback from: Patrick McHardy <kaber@trash.net>

Signed-off-by: Jarek Poplawski <jarkao2@gmail.com>
Signed-off-by: David S. Miller <davem@davemloft.net>
include/net/sch_generic.h
net/sched/sch_api.c
net/sched/sch_mq.c

index 88eb9de095de21006ed26fd84db96ca7f58c3b38..c33180dd42b4916e9cb6b73544b757b71755aecb 100644 (file)
@@ -81,7 +81,7 @@ struct Qdisc
 struct Qdisc_class_ops
 {
        /* Child qdisc manipulation */
-       unsigned int            (*select_queue)(struct Qdisc *, struct tcmsg *);
+       struct netdev_queue *   (*select_queue)(struct Qdisc *, struct tcmsg *);
        int                     (*graft)(struct Qdisc *, unsigned long cl,
                                        struct Qdisc *, struct Qdisc **);
        struct Qdisc *          (*leaf)(struct Qdisc *, unsigned long cl);
index c6e4063f698c5ea768a4f0122bf3474ccf5dd50b..1367aa21fad5224a3e60157e4c9b366a26bbada0 100644 (file)
@@ -1116,12 +1116,16 @@ create_n_graft:
                                 tcm->tcm_parent, tcm->tcm_parent,
                                 tca, &err);
        else {
-               unsigned int ntx = 0;
+               struct netdev_queue *dev_queue;
 
                if (p && p->ops->cl_ops && p->ops->cl_ops->select_queue)
-                       ntx = p->ops->cl_ops->select_queue(p, tcm);
+                       dev_queue = p->ops->cl_ops->select_queue(p, tcm);
+               else if (p)
+                       dev_queue = p->dev_queue;
+               else
+                       dev_queue = netdev_get_tx_queue(dev, 0);
 
-               q = qdisc_create(dev, netdev_get_tx_queue(dev, ntx), p,
+               q = qdisc_create(dev, dev_queue, p,
                                 tcm->tcm_parent, tcm->tcm_handle,
                                 tca, &err);
        }
index dd5ee022f1f7c1d76b28b4fd76028880db6ecaa5..600c50143cc7072f3a3fdcf46c1f0a3dcad0f9c0 100644 (file)
@@ -125,13 +125,18 @@ static struct netdev_queue *mq_queue_get(struct Qdisc *sch, unsigned long cl)
        return netdev_get_tx_queue(dev, ntx);
 }
 
-static unsigned int mq_select_queue(struct Qdisc *sch, struct tcmsg *tcm)
+static struct netdev_queue *mq_select_queue(struct Qdisc *sch,
+                                           struct tcmsg *tcm)
 {
        unsigned int ntx = TC_H_MIN(tcm->tcm_parent);
+       struct netdev_queue *dev_queue = mq_queue_get(sch, ntx);
 
-       if (!mq_queue_get(sch, ntx))
-               return 0;
-       return ntx - 1;
+       if (!dev_queue) {
+               struct net_device *dev = qdisc_dev(sch);
+
+               return netdev_get_tx_queue(dev, 0);
+       }
+       return dev_queue;
 }
 
 static int mq_graft(struct Qdisc *sch, unsigned long cl, struct Qdisc *new,