Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit fa0f5aa7 authored by Eric Dumazet's avatar Eric Dumazet Committed by David S. Miller
Browse files

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: default avatarEric Dumazet <eric.dumazet@gmail.com>
CC: Dave Taht <dave.taht@gmail.com>
Signed-off-by: default avatarDavid S. Miller <davem@davemloft.net>
parent d32ae76f
Loading
Loading
Loading
Loading
+9 −5
Original line number Diff line number Diff line
@@ -618,20 +618,24 @@ void qdisc_class_hash_remove(struct Qdisc_class_hash *clhash,
}
EXPORT_SYMBOL(qdisc_class_hash_remove);

/* Allocate an unique handle from space managed by kernel */

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

	do {
		autohandle += TC_H_MAKE(0x10000U, 0);
		if (autohandle == TC_H_MAKE(TC_H_ROOT, 0))
			autohandle = TC_H_MAKE(0x80000000U, 0);
	} while	(qdisc_lookup(dev, autohandle) && --i > 0);
		if (!qdisc_lookup(dev, autohandle))
			return autohandle;
		cond_resched();
	} while	(--i > 0);

	return i > 0 ? autohandle : 0;
	return 0;
}

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