pkt_sched: fq: qdisc dismantle fixes
fq_reset() should drops all packets in queue, including throttled flows. This patch moves code from fq_destroy() to fq_reset() to do the cleaning. fq_change() must stop calling fq_dequeue() if all remaining packets are from throttled flows. Signed-off-by: Eric Dumazet <edumazet@google.com> Signed-off-by: David S. Miller <davem@davemloft.net>
This commit is contained in:
		
							parent
							
								
									b86783587b
								
							
						
					
					
						commit
						8d34ce10c5
					
				@ -285,7 +285,7 @@ static struct fq_flow *fq_classify(struct sk_buff *skb, struct fq_sched_data *q)
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
/* remove one skb from head of flow queue */
 | 
			
		||||
static struct sk_buff *fq_dequeue_head(struct fq_flow *flow)
 | 
			
		||||
static struct sk_buff *fq_dequeue_head(struct Qdisc *sch, struct fq_flow *flow)
 | 
			
		||||
{
 | 
			
		||||
	struct sk_buff *skb = flow->head;
 | 
			
		||||
 | 
			
		||||
@ -293,6 +293,8 @@ static struct sk_buff *fq_dequeue_head(struct fq_flow *flow)
 | 
			
		||||
		flow->head = skb->next;
 | 
			
		||||
		skb->next = NULL;
 | 
			
		||||
		flow->qlen--;
 | 
			
		||||
		sch->qstats.backlog -= qdisc_pkt_len(skb);
 | 
			
		||||
		sch->q.qlen--;
 | 
			
		||||
	}
 | 
			
		||||
	return skb;
 | 
			
		||||
}
 | 
			
		||||
@ -419,7 +421,7 @@ static struct sk_buff *fq_dequeue(struct Qdisc *sch)
 | 
			
		||||
	struct sk_buff *skb;
 | 
			
		||||
	struct fq_flow *f;
 | 
			
		||||
 | 
			
		||||
	skb = fq_dequeue_head(&q->internal);
 | 
			
		||||
	skb = fq_dequeue_head(sch, &q->internal);
 | 
			
		||||
	if (skb)
 | 
			
		||||
		goto out;
 | 
			
		||||
	fq_check_throttled(q, now);
 | 
			
		||||
@ -449,7 +451,7 @@ begin:
 | 
			
		||||
		goto begin;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	skb = fq_dequeue_head(f);
 | 
			
		||||
	skb = fq_dequeue_head(sch, f);
 | 
			
		||||
	if (!skb) {
 | 
			
		||||
		head->first = f->next;
 | 
			
		||||
		/* force a pass through old_flows to prevent starvation */
 | 
			
		||||
@ -490,19 +492,44 @@ begin:
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
out:
 | 
			
		||||
	sch->qstats.backlog -= qdisc_pkt_len(skb);
 | 
			
		||||
	qdisc_bstats_update(sch, skb);
 | 
			
		||||
	sch->q.qlen--;
 | 
			
		||||
	qdisc_unthrottled(sch);
 | 
			
		||||
	return skb;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static void fq_reset(struct Qdisc *sch)
 | 
			
		||||
{
 | 
			
		||||
	struct fq_sched_data *q = qdisc_priv(sch);
 | 
			
		||||
	struct rb_root *root;
 | 
			
		||||
	struct sk_buff *skb;
 | 
			
		||||
	struct rb_node *p;
 | 
			
		||||
	struct fq_flow *f;
 | 
			
		||||
	unsigned int idx;
 | 
			
		||||
 | 
			
		||||
	while ((skb = fq_dequeue(sch)) != NULL)
 | 
			
		||||
	while ((skb = fq_dequeue_head(sch, &q->internal)) != NULL)
 | 
			
		||||
		kfree_skb(skb);
 | 
			
		||||
 | 
			
		||||
	if (!q->fq_root)
 | 
			
		||||
		return;
 | 
			
		||||
 | 
			
		||||
	for (idx = 0; idx < (1U << q->fq_trees_log); idx++) {
 | 
			
		||||
		root = &q->fq_root[idx];
 | 
			
		||||
		while ((p = rb_first(root)) != NULL) {
 | 
			
		||||
			f = container_of(p, struct fq_flow, fq_node);
 | 
			
		||||
			rb_erase(p, root);
 | 
			
		||||
 | 
			
		||||
			while ((skb = fq_dequeue_head(sch, f)) != NULL)
 | 
			
		||||
				kfree_skb(skb);
 | 
			
		||||
 | 
			
		||||
			kmem_cache_free(fq_flow_cachep, f);
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
	q->new_flows.first	= NULL;
 | 
			
		||||
	q->old_flows.first	= NULL;
 | 
			
		||||
	q->delayed		= RB_ROOT;
 | 
			
		||||
	q->flows		= 0;
 | 
			
		||||
	q->inactive_flows	= 0;
 | 
			
		||||
	q->throttled_flows	= 0;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static void fq_rehash(struct fq_sched_data *q,
 | 
			
		||||
@ -645,6 +672,8 @@ static int fq_change(struct Qdisc *sch, struct nlattr *opt)
 | 
			
		||||
	while (sch->q.qlen > sch->limit) {
 | 
			
		||||
		struct sk_buff *skb = fq_dequeue(sch);
 | 
			
		||||
 | 
			
		||||
		if (!skb)
 | 
			
		||||
			break;
 | 
			
		||||
		kfree_skb(skb);
 | 
			
		||||
		drop_count++;
 | 
			
		||||
	}
 | 
			
		||||
@ -657,21 +686,9 @@ static int fq_change(struct Qdisc *sch, struct nlattr *opt)
 | 
			
		||||
static void fq_destroy(struct Qdisc *sch)
 | 
			
		||||
{
 | 
			
		||||
	struct fq_sched_data *q = qdisc_priv(sch);
 | 
			
		||||
	struct rb_root *root;
 | 
			
		||||
	struct rb_node *p;
 | 
			
		||||
	unsigned int idx;
 | 
			
		||||
 | 
			
		||||
	if (q->fq_root) {
 | 
			
		||||
		for (idx = 0; idx < (1U << q->fq_trees_log); idx++) {
 | 
			
		||||
			root = &q->fq_root[idx];
 | 
			
		||||
			while ((p = rb_first(root)) != NULL) {
 | 
			
		||||
				rb_erase(p, root);
 | 
			
		||||
				kmem_cache_free(fq_flow_cachep,
 | 
			
		||||
						container_of(p, struct fq_flow, fq_node));
 | 
			
		||||
			}
 | 
			
		||||
		}
 | 
			
		||||
		kfree(q->fq_root);
 | 
			
		||||
	}
 | 
			
		||||
	fq_reset(sch);
 | 
			
		||||
	kfree(q->fq_root);
 | 
			
		||||
	qdisc_watchdog_cancel(&q->watchdog);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
		Loading…
	
		Reference in New Issue
	
	Block a user