| From 955a9630bd94f4f44632e7ffff77df81a19c9872 Mon Sep 17 00:00:00 2001 |
| From: Jarek Poplawski <jarkao2@gmail.com> |
| Date: Sat, 3 May 2008 20:46:29 -0700 |
| Subject: sch_htb: remove from event queue in htb_parent_to_leaf() |
| |
| From: Jarek Poplawski <jarkao2@gmail.com> |
| |
| [ Upstream commit: 3ba08b00e0d8413d79be9cab8ec085ceb6ae6fd6 ] |
| |
| There is lack of removing a class from the event queue while changing |
| from parent to leaf which can cause corruption of this rb tree. This |
| patch fixes a bug introduced by my patch: "sch_htb: turn intermediate |
| classes into leaves" commit: 160d5e10f87b1dc88fd9b84b31b1718e0fd76398. |
| |
| Many thanks to Jan 'yanek' Bortl for finding a way to reproduce this |
| rare bug and narrowing the test case, which made possible proper |
| diagnosing. |
| |
| This patch is recommended for all kernels starting from 2.6.20. |
| |
| Reported-and-tested-by: Jan 'yanek' Bortl <yanek@ya.bofh.cz> |
| Signed-off-by: Jarek Poplawski <jarkao2@gmail.com> |
| Signed-off-by: David S. Miller <davem@davemloft.net> |
| Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de> |
| |
| --- |
| net/sched/sch_htb.c | 8 ++++++-- |
| 1 file changed, 6 insertions(+), 2 deletions(-) |
| |
| --- a/net/sched/sch_htb.c |
| +++ b/net/sched/sch_htb.c |
| @@ -1197,12 +1197,16 @@ static inline int htb_parent_last_child( |
| return 1; |
| } |
| |
| -static void htb_parent_to_leaf(struct htb_class *cl, struct Qdisc *new_q) |
| +static void htb_parent_to_leaf(struct htb_sched *q, struct htb_class *cl, |
| + struct Qdisc *new_q) |
| { |
| struct htb_class *parent = cl->parent; |
| |
| BUG_TRAP(!cl->level && cl->un.leaf.q && !cl->prio_activity); |
| |
| + if (parent->cmode != HTB_CAN_SEND) |
| + htb_safe_rb_erase(&parent->pq_node, q->wait_pq + parent->level); |
| + |
| parent->level = 0; |
| memset(&parent->un.inner, 0, sizeof(parent->un.inner)); |
| INIT_LIST_HEAD(&parent->un.leaf.drop_list); |
| @@ -1300,7 +1304,7 @@ static int htb_delete(struct Qdisc *sch, |
| htb_deactivate(q, cl); |
| |
| if (last_child) |
| - htb_parent_to_leaf(cl, new_q); |
| + htb_parent_to_leaf(q, cl, new_q); |
| |
| if (--cl->refcnt == 0) |
| htb_destroy_class(sch, cl); |