netdev: Create netdev_queue abstraction.
David S. Miller [Tue, 8 Jul 2008 23:55:56 +0000 (16:55 -0700)]
A netdev_queue is an entity managed by a qdisc.

Currently there is one RX and one TX queue, and a netdev_queue merely
contains a backpointer to the net_device.

The Qdisc struct is augmented with a netdev_queue pointer as well.

Eventually the 'dev' Qdisc member will go away and we will have the
resulting hierarchy:

net_device --> netdev_queue --> Qdisc

Also, qdisc_alloc() and qdisc_create_dflt() now take a netdev_queue
pointer argument.

Signed-off-by: David S. Miller <davem@davemloft.net>

14 files changed:
include/linux/netdevice.h
include/net/sch_generic.h
net/core/dev.c
net/mac80211/wme.c
net/sched/sch_api.c
net/sched/sch_atm.c
net/sched/sch_cbq.c
net/sched/sch_dsmark.c
net/sched/sch_fifo.c
net/sched/sch_generic.c
net/sched/sch_hfsc.c
net/sched/sch_htb.c
net/sched/sch_netem.c
net/sched/sch_prio.c

index e009c6f..515fd25 100644 (file)
@@ -448,6 +448,10 @@ static inline void napi_synchronize(const struct napi_struct *n)
 # define napi_synchronize(n)   barrier()
 #endif
 
+struct netdev_queue {
+       struct net_device       *dev;
+};
+
 /*
  *     The DEVICE structure.
  *     Actually, this whole structure is a big mistake.  It mixes I/O
@@ -624,6 +628,9 @@ struct net_device
 
        unsigned char           broadcast[MAX_ADDR_LEN];        /* hw bcast add */
 
+       struct netdev_queue     rx_queue;
+       struct netdev_queue     tx_queue;
+
        /* ingress path synchronizer */
        spinlock_t              ingress_lock;
        struct Qdisc            *qdisc_ingress;
index 073f258..0ab53c5 100644 (file)
@@ -37,6 +37,7 @@ struct Qdisc
        u32                     parent;
        atomic_t                refcnt;
        struct sk_buff_head     q;
+       struct netdev_queue     *dev_queue;
        struct net_device       *dev;
        struct list_head        list;
 
@@ -216,8 +217,11 @@ extern void dev_deactivate(struct net_device *dev);
 extern void qdisc_reset(struct Qdisc *qdisc);
 extern void qdisc_destroy(struct Qdisc *qdisc);
 extern void qdisc_tree_decrease_qlen(struct Qdisc *qdisc, unsigned int n);
-extern struct Qdisc *qdisc_alloc(struct net_device *dev, struct Qdisc_ops *ops);
+extern struct Qdisc *qdisc_alloc(struct net_device *dev,
+                                struct netdev_queue *dev_queue,
+                                struct Qdisc_ops *ops);
 extern struct Qdisc *qdisc_create_dflt(struct net_device *dev,
+                                      struct netdev_queue *dev_queue,
                                       struct Qdisc_ops *ops, u32 parentid);
 extern void tcf_destroy(struct tcf_proto *tp);
 extern void tcf_destroy_chain(struct tcf_proto **fl);
index 7593393..9b281c9 100644 (file)
@@ -4072,6 +4072,12 @@ static struct net_device_stats *internal_stats(struct net_device *dev)
        return &dev->stats;
 }
 
+static void netdev_init_queues(struct net_device *dev)
+{
+       dev->rx_queue.dev = dev;
+       dev->tx_queue.dev = dev;
+}
+
 /**
  *     alloc_netdev_mq - allocate network device
  *     @sizeof_priv:   size of private data to allocate space for
@@ -4124,6 +4130,8 @@ struct net_device *alloc_netdev_mq(int sizeof_priv, const char *name,
        dev->egress_subqueue_count = queue_count;
        dev->gso_max_size = GSO_MAX_SIZE;
 
+       netdev_init_queues(dev);
+
        dev->get_stats = internal_stats;
        netpoll_netdev_init(dev);
        setup(dev);
index 5c666f7..770f1c0 100644 (file)
@@ -359,7 +359,8 @@ static int wme_qdiscop_init(struct Qdisc *qd, struct nlattr *opt)
        /* create child queues */
        for (i = 0; i < QD_NUM(hw); i++) {
                skb_queue_head_init(&q->requeued[i]);
-               q->queues[i] = qdisc_create_dflt(qd->dev, &pfifo_qdisc_ops,
+               q->queues[i] = qdisc_create_dflt(qd->dev, qd->dev_queue,
+                                                &pfifo_qdisc_ops,
                                                 qd->handle);
                if (!q->queues[i]) {
                        q->queues[i] = &noop_qdisc;
@@ -575,7 +576,8 @@ void ieee80211_install_qdisc(struct net_device *dev)
 {
        struct Qdisc *qdisc;
 
-       qdisc = qdisc_create_dflt(dev, &wme_qdisc_ops, TC_H_ROOT);
+       qdisc = qdisc_create_dflt(dev, &dev->tx_queue,
+                                 &wme_qdisc_ops, TC_H_ROOT);
        if (!qdisc) {
                printk(KERN_ERR "%s: qdisc installation failed\n", dev->name);
                return;
index 69e918b..b86c98b 100644 (file)
@@ -552,8 +552,8 @@ static int qdisc_graft(struct net_device *dev, struct Qdisc *parent,
  */
 
 static struct Qdisc *
-qdisc_create(struct net_device *dev, u32 parent, u32 handle,
-          struct nlattr **tca, int *errp)
+qdisc_create(struct net_device *dev, struct netdev_queue *dev_queue,
+            u32 parent, u32 handle, struct nlattr **tca, int *errp)
 {
        int err;
        struct nlattr *kind = tca[TCA_KIND];
@@ -593,7 +593,7 @@ qdisc_create(struct net_device *dev, u32 parent, u32 handle,
        if (ops == NULL)
                goto err_out;
 
-       sch = qdisc_alloc(dev, ops);
+       sch = qdisc_alloc(dev, dev_queue, ops);
        if (IS_ERR(sch)) {
                err = PTR_ERR(sch);
                goto err_out2;
@@ -892,10 +892,12 @@ create_n_graft:
        if (!(n->nlmsg_flags&NLM_F_CREATE))
                return -ENOENT;
        if (clid == TC_H_INGRESS)
-               q = qdisc_create(dev, tcm->tcm_parent, tcm->tcm_parent,
+               q = qdisc_create(dev, &dev->rx_queue,
+                                tcm->tcm_parent, tcm->tcm_parent,
                                 tca, &err);
        else
-               q = qdisc_create(dev, tcm->tcm_parent, tcm->tcm_handle,
+               q = qdisc_create(dev, &dev->tx_queue,
+                                tcm->tcm_parent, tcm->tcm_handle,
                                 tca, &err);
        if (q == NULL) {
                if (err == -EAGAIN)
index db0e23a..3dddab5 100644 (file)
@@ -296,7 +296,8 @@ static int atm_tc_change(struct Qdisc *sch, u32 classid, u32 parent,
                goto err_out;
        }
        flow->filter_list = NULL;
-       flow->q = qdisc_create_dflt(sch->dev, &pfifo_qdisc_ops, classid);
+       flow->q = qdisc_create_dflt(sch->dev, sch->dev_queue,
+                                   &pfifo_qdisc_ops, classid);
        if (!flow->q)
                flow->q = &noop_qdisc;
        pr_debug("atm_tc_change: qdisc %p\n", flow->q);
@@ -555,7 +556,8 @@ static int atm_tc_init(struct Qdisc *sch, struct nlattr *opt)
 
        pr_debug("atm_tc_init(sch %p,[qdisc %p],opt %p)\n", sch, p, opt);
        p->flows = &p->link;
-       p->link.q = qdisc_create_dflt(sch->dev, &pfifo_qdisc_ops, sch->handle);
+       p->link.q = qdisc_create_dflt(sch->dev, sch->dev_queue,
+                                     &pfifo_qdisc_ops, sch->handle);
        if (!p->link.q)
                p->link.q = &noop_qdisc;
        pr_debug("atm_tc_init: link (%p) qdisc %p\n", &p->link, p->link.q);
index 968b4c7..d360dcd 100644 (file)
@@ -1401,7 +1401,8 @@ static int cbq_init(struct Qdisc *sch, struct nlattr *opt)
        q->link.sibling = &q->link;
        q->link.common.classid = sch->handle;
        q->link.qdisc = sch;
-       if (!(q->link.q = qdisc_create_dflt(sch->dev, &pfifo_qdisc_ops,
+       if (!(q->link.q = qdisc_create_dflt(sch->dev, sch->dev_queue,
+                                           &pfifo_qdisc_ops,
                                            sch->handle)))
                q->link.q = &noop_qdisc;
 
@@ -1645,7 +1646,8 @@ static int cbq_graft(struct Qdisc *sch, unsigned long arg, struct Qdisc *new,
 
        if (cl) {
                if (new == NULL) {
-                       new = qdisc_create_dflt(sch->dev, &pfifo_qdisc_ops,
+                       new = qdisc_create_dflt(sch->dev, sch->dev_queue,
+                                               &pfifo_qdisc_ops,
                                                cl->common.classid);
                        if (new == NULL)
                                return -ENOBUFS;
@@ -1877,7 +1879,8 @@ cbq_change_class(struct Qdisc *sch, u32 classid, u32 parentid, struct nlattr **t
        cl->R_tab = rtab;
        rtab = NULL;
        cl->refcnt = 1;
-       if (!(cl->q = qdisc_create_dflt(sch->dev, &pfifo_qdisc_ops, classid)))
+       if (!(cl->q = qdisc_create_dflt(sch->dev, sch->dev_queue,
+                                       &pfifo_qdisc_ops, classid)))
                cl->q = &noop_qdisc;
        cl->common.classid = classid;
        cl->tparent = parent;
index c4c1317..c955ba2 100644 (file)
@@ -60,7 +60,8 @@ static int dsmark_graft(struct Qdisc *sch, unsigned long arg,
                sch, p, new, old);
 
        if (new == NULL) {
-               new = qdisc_create_dflt(sch->dev, &pfifo_qdisc_ops,
+               new = qdisc_create_dflt(sch->dev, sch->dev_queue,
+                                       &pfifo_qdisc_ops,
                                        sch->handle);
                if (new == NULL)
                        new = &noop_qdisc;
@@ -390,7 +391,8 @@ static int dsmark_init(struct Qdisc *sch, struct nlattr *opt)
        p->default_index = default_index;
        p->set_tc_index = nla_get_flag(tb[TCA_DSMARK_SET_TC_INDEX]);
 
-       p->q = qdisc_create_dflt(sch->dev, &pfifo_qdisc_ops, sch->handle);
+       p->q = qdisc_create_dflt(sch->dev, sch->dev_queue,
+                                &pfifo_qdisc_ops, sch->handle);
        if (p->q == NULL)
                p->q = &noop_qdisc;
 
index 82d7d7b..779eae8 100644 (file)
@@ -137,7 +137,8 @@ struct Qdisc *fifo_create_dflt(struct Qdisc *sch, struct Qdisc_ops *ops,
        struct Qdisc *q;
        int err = -ENOMEM;
 
-       q = qdisc_create_dflt(sch->dev, ops, TC_H_MAKE(sch->handle, 1));
+       q = qdisc_create_dflt(sch->dev, sch->dev_queue,
+                             ops, TC_H_MAKE(sch->handle, 1));
        if (q) {
                err = fifo_set_limit(q, limit);
                if (err < 0) {
index 13afa72..d970864 100644 (file)
@@ -440,7 +440,9 @@ static struct Qdisc_ops pfifo_fast_ops __read_mostly = {
        .owner          =       THIS_MODULE,
 };
 
-struct Qdisc *qdisc_alloc(struct net_device *dev, struct Qdisc_ops *ops)
+struct Qdisc *qdisc_alloc(struct net_device *dev,
+                         struct netdev_queue *dev_queue,
+                         struct Qdisc_ops *ops)
 {
        void *p;
        struct Qdisc *sch;
@@ -462,6 +464,7 @@ struct Qdisc *qdisc_alloc(struct net_device *dev, struct Qdisc_ops *ops)
        sch->ops = ops;
        sch->enqueue = ops->enqueue;
        sch->dequeue = ops->dequeue;
+       sch->dev_queue = dev_queue;
        sch->dev = dev;
        dev_hold(dev);
        atomic_set(&sch->refcnt, 1);
@@ -471,12 +474,14 @@ errout:
        return ERR_PTR(err);
 }
 
-struct Qdisc * qdisc_create_dflt(struct net_device *dev, struct Qdisc_ops *ops,
+struct Qdisc * qdisc_create_dflt(struct net_device *dev,
+                                struct netdev_queue *dev_queue,
+                                struct Qdisc_ops *ops,
                                 unsigned int parentid)
 {
        struct Qdisc *sch;
 
-       sch = qdisc_alloc(dev, ops);
+       sch = qdisc_alloc(dev, dev_queue, ops);
        if (IS_ERR(sch))
                goto errout;
        sch->stats_lock = &dev->queue_lock;
@@ -545,7 +550,8 @@ void dev_activate(struct net_device *dev)
        if (dev->qdisc_sleeping == &noop_qdisc) {
                struct Qdisc *qdisc;
                if (dev->tx_queue_len) {
-                       qdisc = qdisc_create_dflt(dev, &pfifo_fast_ops,
+                       qdisc = qdisc_create_dflt(dev, &dev->tx_queue,
+                                                 &pfifo_fast_ops,
                                                  TC_H_ROOT);
                        if (qdisc == NULL) {
                                printk(KERN_INFO "%s: activation failed\n", dev->name);
index 3a82672..5a22fec 100644 (file)
@@ -1083,7 +1083,8 @@ hfsc_change_class(struct Qdisc *sch, u32 classid, u32 parentid,
        cl->refcnt    = 1;
        cl->sched     = q;
        cl->cl_parent = parent;
-       cl->qdisc = qdisc_create_dflt(sch->dev, &pfifo_qdisc_ops, classid);
+       cl->qdisc = qdisc_create_dflt(sch->dev, sch->dev_queue,
+                                     &pfifo_qdisc_ops, classid);
        if (cl->qdisc == NULL)
                cl->qdisc = &noop_qdisc;
        INIT_LIST_HEAD(&cl->children);
@@ -1201,7 +1202,8 @@ hfsc_graft_class(struct Qdisc *sch, unsigned long arg, struct Qdisc *new,
        if (cl->level > 0)
                return -EINVAL;
        if (new == NULL) {
-               new = qdisc_create_dflt(sch->dev, &pfifo_qdisc_ops,
+               new = qdisc_create_dflt(sch->dev, sch->dev_queue,
+                                       &pfifo_qdisc_ops,
                                        cl->cl_common.classid);
                if (new == NULL)
                        new = &noop_qdisc;
@@ -1443,7 +1445,8 @@ hfsc_init_qdisc(struct Qdisc *sch, struct nlattr *opt)
        q->root.cl_common.classid = sch->handle;
        q->root.refcnt  = 1;
        q->root.sched   = q;
-       q->root.qdisc = qdisc_create_dflt(sch->dev, &pfifo_qdisc_ops,
+       q->root.qdisc = qdisc_create_dflt(sch->dev, sch->dev_queue,
+                                         &pfifo_qdisc_ops,
                                          sch->handle);
        if (q->root.qdisc == NULL)
                q->root.qdisc = &noop_qdisc;
index ee8b4ff..956a67f 100644 (file)
@@ -1129,7 +1129,8 @@ static int htb_graft(struct Qdisc *sch, unsigned long arg, struct Qdisc *new,
 
        if (cl && !cl->level) {
                if (new == NULL &&
-                   (new = qdisc_create_dflt(sch->dev, &pfifo_qdisc_ops,
+                   (new = qdisc_create_dflt(sch->dev, sch->dev_queue,
+                                            &pfifo_qdisc_ops,
                                             cl->common.classid))
                    == NULL)
                        return -ENOBUFS;
@@ -1256,8 +1257,9 @@ static int htb_delete(struct Qdisc *sch, unsigned long arg)
                return -EBUSY;
 
        if (!cl->level && htb_parent_last_child(cl)) {
-               new_q = qdisc_create_dflt(sch->dev, &pfifo_qdisc_ops,
-                                               cl->parent->common.classid);
+               new_q = qdisc_create_dflt(sch->dev, sch->dev_queue,
+                                         &pfifo_qdisc_ops,
+                                         cl->parent->common.classid);
                last_child = 1;
        }
 
@@ -1376,7 +1378,8 @@ static int htb_change_class(struct Qdisc *sch, u32 classid,
                /* create leaf qdisc early because it uses kmalloc(GFP_KERNEL)
                   so that can't be used inside of sch_tree_lock
                   -- thanks to Karlis Peisenieks */
-               new_q = qdisc_create_dflt(sch->dev, &pfifo_qdisc_ops, classid);
+               new_q = qdisc_create_dflt(sch->dev, sch->dev_queue,
+                                         &pfifo_qdisc_ops, classid);
                sch_tree_lock(sch);
                if (parent && !parent->level) {
                        unsigned int qlen = parent->un.leaf.q->q.qlen;
index 2469766..aa7a04e 100644 (file)
@@ -536,7 +536,8 @@ static int netem_init(struct Qdisc *sch, struct nlattr *opt)
 
        qdisc_watchdog_init(&q->watchdog, sch);
 
-       q->qdisc = qdisc_create_dflt(sch->dev, &tfifo_qdisc_ops,
+       q->qdisc = qdisc_create_dflt(sch->dev, sch->dev_queue,
+                                    &tfifo_qdisc_ops,
                                     TC_H_MAKE(sch->handle, 1));
        if (!q->qdisc) {
                pr_debug("netem: qdisc create failed\n");
index 5532f10..ca58a03 100644 (file)
@@ -281,7 +281,8 @@ static int prio_tune(struct Qdisc *sch, struct nlattr *opt)
        for (i=0; i<q->bands; i++) {
                if (q->queues[i] == &noop_qdisc) {
                        struct Qdisc *child;
-                       child = qdisc_create_dflt(sch->dev, &pfifo_qdisc_ops,
+                       child = qdisc_create_dflt(sch->dev, sch->dev_queue,
+                                                 &pfifo_qdisc_ops,
                                                  TC_H_MAKE(sch->handle, i + 1));
                        if (child) {
                                sch_tree_lock(sch);