]> git.proxmox.com Git - mirror_ubuntu-artful-kernel.git/blobdiff - net/sched/sch_sfq.c
net: sched: restrict use of qstats qlen
[mirror_ubuntu-artful-kernel.git] / net / sched / sch_sfq.c
index 1af2f73906d07aa5bf6f428ffe37b81523178ee4..d4afcbc1c6f7d6fe2d7bbbe7fc586695ab3f5e87 100644 (file)
@@ -125,7 +125,7 @@ struct sfq_sched_data {
        u8              cur_depth;      /* depth of longest slot */
        u8              flags;
        unsigned short  scaled_quantum; /* SFQ_ALLOT_SIZE(quantum) */
-       struct tcf_proto *filter_list;
+       struct tcf_proto __rcu *filter_list;
        sfq_index       *ht;            /* Hash table ('divisor' slots) */
        struct sfq_slot *slots;         /* Flows table ('maxflows' entries) */
 
@@ -187,6 +187,7 @@ static unsigned int sfq_classify(struct sk_buff *skb, struct Qdisc *sch,
 {
        struct sfq_sched_data *q = qdisc_priv(sch);
        struct tcf_result res;
+       struct tcf_proto *fl;
        int result;
 
        if (TC_H_MAJ(skb->priority) == sch->handle &&
@@ -194,13 +195,14 @@ static unsigned int sfq_classify(struct sk_buff *skb, struct Qdisc *sch,
            TC_H_MIN(skb->priority) <= q->divisor)
                return TC_H_MIN(skb->priority);
 
-       if (!q->filter_list) {
+       fl = rcu_dereference_bh(q->filter_list);
+       if (!fl) {
                skb_flow_dissect(skb, &sfq_skb_cb(skb)->keys);
                return sfq_hash(q, skb) + 1;
        }
 
        *qerr = NET_XMIT_SUCCESS | __NET_XMIT_BYPASS;
-       result = tc_classify(skb, q->filter_list, &res);
+       result = tc_classify(skb, fl, &res);
        if (result >= 0) {
 #ifdef CONFIG_NET_CLS_ACT
                switch (result) {
@@ -310,11 +312,6 @@ static inline void slot_queue_add(struct sfq_slot *slot, struct sk_buff *skb)
        slot->skblist_prev = skb;
 }
 
-#define        slot_queue_walk(slot, skb)              \
-       for (skb = slot->skblist_next;          \
-            skb != (struct sk_buff *)slot;     \
-            skb = skb->next)
-
 static unsigned int sfq_drop(struct Qdisc *sch)
 {
        struct sfq_sched_data *q = qdisc_priv(sch);
@@ -334,8 +331,8 @@ drop:
                sfq_dec(q, x);
                kfree_skb(skb);
                sch->q.qlen--;
-               sch->qstats.drops++;
-               sch->qstats.backlog -= len;
+               qdisc_qstats_drop(sch);
+               qdisc_qstats_backlog_dec(sch, skb);
                return len;
        }
 
@@ -382,7 +379,7 @@ sfq_enqueue(struct sk_buff *skb, struct Qdisc *sch)
        hash = sfq_classify(skb, sch, &ret);
        if (hash == 0) {
                if (ret & __NET_XMIT_BYPASS)
-                       sch->qstats.drops++;
+                       qdisc_qstats_drop(sch);
                kfree_skb(skb);
                return ret;
        }
@@ -412,7 +409,7 @@ sfq_enqueue(struct sk_buff *skb, struct Qdisc *sch)
                        break;
 
                case RED_PROB_MARK:
-                       sch->qstats.overlimits++;
+                       qdisc_qstats_overlimit(sch);
                        if (sfq_prob_mark(q)) {
                                /* We know we have at least one packet in queue */
                                if (sfq_headdrop(q) &&
@@ -429,7 +426,7 @@ sfq_enqueue(struct sk_buff *skb, struct Qdisc *sch)
                        goto congestion_drop;
 
                case RED_HARD_MARK:
-                       sch->qstats.overlimits++;
+                       qdisc_qstats_overlimit(sch);
                        if (sfq_hard_mark(q)) {
                                /* We know we have at least one packet in queue */
                                if (sfq_headdrop(q) &&
@@ -464,7 +461,7 @@ congestion_drop:
        }
 
 enqueue:
-       sch->qstats.backlog += qdisc_pkt_len(skb);
+       qdisc_qstats_backlog_inc(sch, skb);
        slot->backlog += qdisc_pkt_len(skb);
        slot_queue_add(slot, skb);
        sfq_inc(q, x);
@@ -523,7 +520,7 @@ next_slot:
        sfq_dec(q, a);
        qdisc_bstats_update(sch, skb);
        sch->q.qlen--;
-       sch->qstats.backlog -= qdisc_pkt_len(skb);
+       qdisc_qstats_backlog_dec(sch, skb);
        slot->backlog -= qdisc_pkt_len(skb);
        /* Is the slot empty? */
        if (slot->qlen == 0) {
@@ -589,7 +586,8 @@ static void sfq_rehash(struct Qdisc *sch)
                if (x == SFQ_EMPTY_SLOT) {
                        x = q->dep[0].next; /* get a free slot */
                        if (x >= SFQ_MAX_FLOWS) {
-drop:                          sch->qstats.backlog -= qdisc_pkt_len(skb);
+drop:
+                               qdisc_qstats_backlog_dec(sch, skb);
                                kfree_skb(skb);
                                dropped++;
                                continue;
@@ -841,7 +839,8 @@ static void sfq_put(struct Qdisc *q, unsigned long cl)
 {
 }
 
-static struct tcf_proto **sfq_find_tcf(struct Qdisc *sch, unsigned long cl)
+static struct tcf_proto __rcu **sfq_find_tcf(struct Qdisc *sch,
+                                            unsigned long cl)
 {
        struct sfq_sched_data *q = qdisc_priv(sch);
 
@@ -872,7 +871,7 @@ static int sfq_dump_class_stats(struct Qdisc *sch, unsigned long cl,
                qs.qlen = slot->qlen;
                qs.backlog = slot->backlog;
        }
-       if (gnet_stats_copy_queue(d, &qs) < 0)
+       if (gnet_stats_copy_queue(d, &qs, qs.qlen) < 0)
                return -1;
        return gnet_stats_copy_app(d, &xstats, sizeof(xstats));
 }