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

Commit 27ba4059 authored by Yunsheng Lin's avatar Yunsheng Lin Committed by David S. Miller
Browse files

net: link_watch: prevent starvation when processing linkwatch wq



When user has configured a large number of virtual netdev, such
as 4K vlans, the carrier on/off operation of the real netdev
will also cause it's virtual netdev's link state to be processed
in linkwatch. Currently, the processing is done in a work queue,
which may cause rtnl locking starvation problem and worker
starvation problem for other work queue, such as irqfd_inject wq.

This patch releases the cpu when link watch worker has processed
a fixed number of netdev' link watch event, and schedule the
work queue again when there is still link watch event remaining.

Signed-off-by: default avatarYunsheng Lin <linyunsheng@huawei.com>
Signed-off-by: default avatarDavid S. Miller <davem@davemloft.net>
parent 0d0bcacc
Loading
Loading
Loading
Loading
+12 −1
Original line number Diff line number Diff line
@@ -163,9 +163,16 @@ static void linkwatch_do_dev(struct net_device *dev)

static void __linkwatch_run_queue(int urgent_only)
{
#define MAX_DO_DEV_PER_LOOP	100

	int do_dev = MAX_DO_DEV_PER_LOOP;
	struct net_device *dev;
	LIST_HEAD(wrk);

	/* Give urgent case more budget */
	if (urgent_only)
		do_dev += MAX_DO_DEV_PER_LOOP;

	/*
	 * Limit the number of linkwatch events to one
	 * per second so that a runaway driver does not
@@ -184,7 +191,7 @@ static void __linkwatch_run_queue(int urgent_only)
	spin_lock_irq(&lweventlist_lock);
	list_splice_init(&lweventlist, &wrk);

	while (!list_empty(&wrk)) {
	while (!list_empty(&wrk) && do_dev > 0) {

		dev = list_first_entry(&wrk, struct net_device, link_watch_list);
		list_del_init(&dev->link_watch_list);
@@ -195,9 +202,13 @@ static void __linkwatch_run_queue(int urgent_only)
		}
		spin_unlock_irq(&lweventlist_lock);
		linkwatch_do_dev(dev);
		do_dev--;
		spin_lock_irq(&lweventlist_lock);
	}

	/* Add the remaining work back to lweventlist */
	list_splice_init(&wrk, &lweventlist);

	if (!list_empty(&lweventlist))
		linkwatch_schedule_work(0);
	spin_unlock_irq(&lweventlist_lock);