Skip to content

Commit fa0f5aa

Browse files
Eric Dumazetdavem330
authored andcommitted
net_sched: qdisc_alloc_handle() can be too slow
When trying to allocate ~32768 qdiscs using autohandle mechanism, we can fill the space managed by kernel (handles in [8000-FFFF]:0000 range) But O(N^2) qdisc_alloc_handle() loops 0x10000 times instead of 0x8000 time tc add qdisc add dev eth0 parent 10:7fff pfifo limit 10 RTNETLINK answers: Cannot allocate memory real 1m54.826s user 0m0.000s sys 0m0.004s INFO: rcu_sched_state detected stall on CPU 0 (t=60000 jiffies) Half number of loops, and add a cond_resched() call. We hold rtnl at this point. Signed-off-by: Eric Dumazet <eric.dumazet@gmail.com> CC: Dave Taht <dave.taht@gmail.com> Signed-off-by: David S. Miller <davem@davemloft.net>
1 parent d32ae76 commit fa0f5aa

File tree

1 file changed

+9
-5
lines changed

1 file changed

+9
-5
lines changed

net/sched/sch_api.c

Lines changed: 9 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -618,20 +618,24 @@ void qdisc_class_hash_remove(struct Qdisc_class_hash *clhash,
618618
}
619619
EXPORT_SYMBOL(qdisc_class_hash_remove);
620620

621-
/* Allocate an unique handle from space managed by kernel */
622-
621+
/* Allocate an unique handle from space managed by kernel
622+
* Possible range is [8000-FFFF]:0000 (0x8000 values)
623+
*/
623624
static u32 qdisc_alloc_handle(struct net_device *dev)
624625
{
625-
int i = 0x10000;
626+
int i = 0x8000;
626627
static u32 autohandle = TC_H_MAKE(0x80000000U, 0);
627628

628629
do {
629630
autohandle += TC_H_MAKE(0x10000U, 0);
630631
if (autohandle == TC_H_MAKE(TC_H_ROOT, 0))
631632
autohandle = TC_H_MAKE(0x80000000U, 0);
632-
} while (qdisc_lookup(dev, autohandle) && --i > 0);
633+
if (!qdisc_lookup(dev, autohandle))
634+
return autohandle;
635+
cond_resched();
636+
} while (--i > 0);
633637

634-
return i > 0 ? autohandle : 0;
638+
return 0;
635639
}
636640

637641
void qdisc_tree_decrease_qlen(struct Qdisc *sch, unsigned int n)

0 commit comments

Comments
 (0)