Source
fq->flows = kcalloc(fq->flows_cnt, sizeof(fq->flows[0]), GFP_KERNEL);
/*
* Copyright (c) 2016 Qualcomm Atheros, Inc
*
* GPL v2
*
* Based on net/sched/sch_fq_codel.c
*/
/* functions that are embedded into includer */
static void fq_adjust_removal(struct fq *fq,
struct fq_flow *flow,
struct sk_buff *skb)
{
struct fq_tin *tin = flow->tin;
tin->backlog_bytes -= skb->len;
tin->backlog_packets--;
flow->backlog -= skb->len;
fq->backlog--;
fq->memory_usage -= skb->truesize;
}
static void fq_rejigger_backlog(struct fq *fq, struct fq_flow *flow)
{
struct fq_flow *i;
if (flow->backlog == 0) {
list_del_init(&flow->backlogchain);
} else {
i = flow;
list_for_each_entry_continue(i, &fq->backlogs, backlogchain)
if (i->backlog < flow->backlog)
break;
list_move_tail(&flow->backlogchain,
&i->backlogchain);
}
}
static struct sk_buff *fq_flow_dequeue(struct fq *fq,
struct fq_flow *flow)
{
struct sk_buff *skb;
lockdep_assert_held(&fq->lock);
skb = __skb_dequeue(&flow->queue);
if (!skb)
return NULL;
fq_adjust_removal(fq, flow, skb);
fq_rejigger_backlog(fq, flow);
return skb;
}
static struct sk_buff *fq_tin_dequeue(struct fq *fq,
struct fq_tin *tin,
fq_tin_dequeue_t dequeue_func)
{
struct fq_flow *flow;
struct list_head *head;
struct sk_buff *skb;
lockdep_assert_held(&fq->lock);
begin:
head = &tin->new_flows;
if (list_empty(head)) {
head = &tin->old_flows;
if (list_empty(head))
return NULL;
}
flow = list_first_entry(head, struct fq_flow, flowchain);
if (flow->deficit <= 0) {
flow->deficit += fq->quantum;
list_move_tail(&flow->flowchain,
&tin->old_flows);
goto begin;
}
skb = dequeue_func(fq, tin, flow);
if (!skb) {
/* force a pass through old_flows to prevent starvation */