From: Linus Lüssing Date: Wed, 3 Jan 2018 06:33:18 +0100 Subject: kernel: pkt_sched: fq_codel: debug/asserts for fq codel memory_usage diff --git a/target/linux/generic/patches-4.4/665-0002-pkt_sched-fq_codel-debug-asserts-for-fq-codel-memory.patch b/target/linux/generic/patches-4.4/665-0002-pkt_sched-fq_codel-debug-asserts-for-fq-codel-memory.patch new file mode 100644 index 0000000000000000000000000000000000000000..2dd5c1e2e20f7533e1b27e4d795e23cdeef8f20e --- /dev/null +++ b/target/linux/generic/patches-4.4/665-0002-pkt_sched-fq_codel-debug-asserts-for-fq-codel-memory.patch @@ -0,0 +1,157 @@ +From 0176de697a170b70591609f3e6ff8b178c16acb6 Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Linus=20L=C3=BCssing?= +Date: Wed, 3 Jan 2018 06:27:10 +0100 +Subject: [PATCH 2/2] pkt_sched: fq_codel: debug/asserts for fq codel + memory_usage usage + +--- + net/sched/sch_fq_codel.c | 55 +++++++++++++++++++++++++++++++++++++++++++++++- + 1 file changed, 54 insertions(+), 1 deletion(-) + +diff --git a/net/sched/sch_fq_codel.c b/net/sched/sch_fq_codel.c +index aac564433d40..56c440ca88e2 100644 +--- a/net/sched/sch_fq_codel.c ++++ b/net/sched/sch_fq_codel.c +@@ -154,6 +154,7 @@ static unsigned int fq_codel_drop(struct Qdisc *sch, unsigned int max_packets) + struct fq_codel_flow *flow; + unsigned int threshold; + unsigned int mem = 0; ++ unsigned int old_mem; + + /* Queue is full! Find the fat flow and drop packet(s) from it. + * This might sound expensive, but with 1024 flows, we scan +@@ -178,12 +179,29 @@ static unsigned int fq_codel_drop(struct Qdisc *sch, unsigned int max_packets) + do { + skb = dequeue_head(flow); + len += qdisc_pkt_len(skb); ++ ++ if (skb->truesize > 3000) ++ printk_ratelimited("~~~ %s: %s: dropping packet with weird truesize? skb->truesize %u (skb->len: %u, skb->data_len: %u)\n", __func__, SCH_DEV_NAME(sch), skb->truesize, skb->len, skb->data_len); ++ if (skb->truesize < skb->len) ++ printk_ratelimited("~~~ %s: %s: dropping packet with invalid truesize? skb->truesize %u vs. skb->len %u (skb->data_len: %u)\n", __func__, SCH_DEV_NAME(sch), skb->truesize, skb->len, skb->data_len); ++ ++ old_mem = mem; + mem += skb->truesize; ++ ++ if (mem < old_mem) ++ printk_ratelimited("~~~ %s: %s: oh oh, overflow happened here... mem: %u, old_mem: %u, skb->truesize: %u\n", __func__, SCH_DEV_NAME(sch), mem, old_mem, skb->truesize); ++ else if (old_mem + skb->truesize != mem) ++ printk_ratelimited("~~~ %s: %s: locking error? mem: %u, old_mem: %u, skb->truesize: %u\n", __func__, SCH_DEV_NAME(sch), mem, old_mem, skb->truesize); ++ + kfree_skb(skb); + } while (++i < max_packets && len < threshold); + + flow->dropped += i; + q->backlogs[idx] -= len; ++ ++ if (mem > q->memory_usage) ++ printk_ratelimited("~~~ %s: %s: oh, oh, underflow to happen for memory_usage... q->memory_usage: %u, mem: %u\n", __func__, SCH_DEV_NAME(sch), q->memory_usage, mem); ++ + q->memory_usage -= mem; + sch->qstats.drops += i; + sch->qstats.backlog -= len; +@@ -208,6 +226,7 @@ static int fq_codel_enqueue(struct sk_buff *skb, struct Qdisc *sch) + int uninitialized_var(ret); + unsigned int pkt_len; + bool memory_limited; ++ u32 old_memory_usage; + + idx = fq_codel_classify(skb, sch, &ret); + if (idx == 0) { +@@ -230,7 +249,20 @@ static int fq_codel_enqueue(struct sk_buff *skb, struct Qdisc *sch) + flow->deficit = q->quantum; + flow->dropped = 0; + } ++ ++ if (skb->truesize > 3000) ++ printk_ratelimited("~~~ %s: %s: enqueueing packet with weird truesize? skb->truesize %u (skb->len: %u, skb->data_len: %u)\n", __func__, SCH_DEV_NAME(sch), skb->truesize, skb->len, skb->data_len); ++ if (skb->truesize < skb->len) ++ printk_ratelimited("~~~ %s: %s: enqueueing packet with invalid truesize? skb->truesize %u vs. skb->len %u (skb->data_len: %u)\n", __func__, SCH_DEV_NAME(sch), skb->truesize, skb->len, skb->data_len); ++ ++ old_memory_usage = q->memory_usage; + q->memory_usage += skb->truesize; ++ ++ if (q->memory_usage < old_memory_usage) ++ printk_ratelimited("~~~ %s: %s: oh, oh, overflow happened for memory_usage... q->memory_usage: %u, skb->truesize: %u, old memory_usage: %u\n", __func__, SCH_DEV_NAME(sch), q->memory_usage, skb->truesize, old_memory_usage); ++ else if (old_memory_usage + skb->truesize != q->memory_usage) ++ printk_ratelimited("~~~ %s: %s: locking error? memory_usage: %lu, old_mem_memory_usage: %lu, skb->truesize: %u\n", __func__, SCH_DEV_NAME(sch), q->memory_usage, old_memory_usage, skb->truesize); ++ + memory_limited = q->memory_usage > q->memory_limit; + if (++sch->q.qlen <= sch->limit && !memory_limited) + return NET_XMIT_SUCCESS; +@@ -280,6 +312,15 @@ static struct sk_buff *dequeue(struct codel_vars *vars, struct Qdisc *sch) + if (flow->head) { + skb = dequeue_head(flow); + q->backlogs[flow - q->flows] -= qdisc_pkt_len(skb); ++ ++ if (skb->truesize > 3000) ++ printk_ratelimited("~~~ %s: %s: dequeueing packet with weird truesize? skb->truesize %u (skb->len: %u, skb->data_len: %u)\n", __func__, SCH_DEV_NAME(sch), skb->truesize, skb->len, skb->data_len); ++ if (skb->truesize < skb->len) ++ printk_ratelimited("~~~ %s: %s: dequeueing packet with invalid truesize? skb->truesize %u vs. skb->len %u (skb->data_len: %u)\n", __func__, SCH_DEV_NAME(sch), skb->truesize, skb->len, skb->data_len); ++ ++ if (skb->truesize > q->memory_usage) ++ printk_ratelimited("~~~ %s: %s: oh, oh, underflow to happen for memory_usage... q->memory_usage: %u, skb->truesize: %u\n", __func__, SCH_DEV_NAME(sch), q->memory_usage, skb->truesize); ++ + q->memory_usage -= skb->truesize; + sch->q.qlen--; + } +@@ -349,6 +390,9 @@ static void fq_codel_reset(struct Qdisc *sch) + + INIT_LIST_HEAD(&q->new_flows); + INIT_LIST_HEAD(&q->old_flows); ++ ++ printk("~~~ %s: %s: flows_cnt: %lu, &flows: %p\n", __func__, SCH_DEV_NAME(sch), q->flows_cnt, q->flows); ++ + for (i = 0; i < q->flows_cnt; i++) { + struct fq_codel_flow *flow = q->flows + i; + +@@ -434,6 +478,8 @@ static int fq_codel_change(struct Qdisc *sch, struct nlattr *opt) + if (tb[TCA_FQ_CODEL_MEMORY_LIMIT]) + q->memory_limit = min(1U << 31, nla_get_u32(tb[TCA_FQ_CODEL_MEMORY_LIMIT])); + ++ printk("~~~ %s: %s: (1) flows_cnt: %u, memory_limit: %u, memory_usage: %u\n", __func__, SCH_DEV_NAME(sch), q->flows_cnt, q->memory_limit, q->memory_usage); ++ + while (sch->q.qlen > sch->limit || + q->memory_usage > q->memory_limit) { + struct sk_buff *skb = fq_codel_dequeue(sch); +@@ -446,6 +492,8 @@ static int fq_codel_change(struct Qdisc *sch, struct nlattr *opt) + q->cstats.drop_count = 0; + q->cstats.drop_len = 0; + ++ printk("~~~ %s: %s: (2) flows_cnt: %u, memory_limit: %u, memory_usage: %u\n", __func__, SCH_DEV_NAME(sch), q->flows_cnt, q->memory_limit, q->memory_usage); ++ + sch_tree_unlock(sch); + return 0; + } +@@ -504,6 +552,8 @@ static int fq_codel_init(struct Qdisc *sch, struct nlattr *opt) + return err; + } + ++ printk("~~~ %s: %s: flows_cnt: %u, memory_limit: %u, memory_usage: %u\n", __func__, SCH_DEV_NAME(sch), q->flows_cnt, q->memory_limit, q->memory_usage); ++ + if (!q->flows) { + printk("~~~ %s: %s: Calling fq_codel_zalloc() with sz: %lu (cnt: %u, szof(): %lu) for flows\n", + __func__, +@@ -513,8 +563,10 @@ static int fq_codel_init(struct Qdisc *sch, struct nlattr *opt) + + q->flows = fq_codel_zalloc(q->flows_cnt * + sizeof(struct fq_codel_flow)); +- if (!q->flows) ++ if (!q->flows) { ++ printk("~~~ %s: %s: Allocation failure for flows! flows_cnt: %u, memory_limit: %u, memory_usage: %u\n", __func__, SCH_DEV_NAME(sch), q->flows_cnt, q->memory_limit, q->memory_usage); + return -ENOMEM; ++ } + + printk("~~~ %s: %s: Calling fq_codel_zalloc() with sz: %lu (cnt: %u, szof(): %lu) for backlogs\n", + __func__, +@@ -524,6 +576,7 @@ static int fq_codel_init(struct Qdisc *sch, struct nlattr *opt) + + q->backlogs = fq_codel_zalloc(q->flows_cnt * sizeof(u32)); + if (!q->backlogs) { ++ printk("~~~ %s: %s: Allocation failure for backlogs! flows_cnt: %u, memory_limit: %u, memory_usage: %u\n", __func__, SCH_DEV_NAME(sch), q->flows_cnt, q->memory_limit, q->memory_usage); + fq_codel_free(q->flows); + return -ENOMEM; + } +-- +2.11.0 +