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

Commit d9568ba9 authored by Herbert Xu's avatar Herbert Xu Committed by David S. Miller
Browse files

[NET] link_watch: Always schedule urgent events



Urgent events may be delayed if we already have a non-urgent event
queued for that device.  This patch changes this by making sure that
an urgent event is always looked at immediately.

I've replaced the LW_RUNNING flag by LW_URGENT since whether work
is scheduled is already kept track by the work queue system.

The only complication is that we have to provide some exclusion for
the setting linkwatch_nextevent which is available in the actual
work function.

Signed-off-by: default avatarHerbert Xu <herbert@gondor.apana.org.au>
Signed-off-by: default avatarDavid S. Miller <davem@davemloft.net>
parent db0ccffe
Loading
Loading
Loading
Loading
+41 −19
Original line number Diff line number Diff line
@@ -26,7 +26,7 @@


enum lw_bits {
	LW_RUNNING = 0,
	LW_URGENT = 0,
};

static unsigned long linkwatch_flags;
@@ -95,18 +95,41 @@ static void linkwatch_add_event(struct net_device *dev)
}


static void linkwatch_schedule_work(unsigned long delay)
static void linkwatch_schedule_work(int urgent)
{
	if (test_and_set_bit(LW_RUNNING, &linkwatch_flags))
	unsigned long delay = linkwatch_nextevent - jiffies;

	if (test_bit(LW_URGENT, &linkwatch_flags))
		return;

	/* If we wrap around we'll delay it by at most HZ. */
	if (delay > HZ) {
		linkwatch_nextevent = jiffies;
	/* Minimise down-time: drop delay for up event. */
	if (urgent) {
		if (test_and_set_bit(LW_URGENT, &linkwatch_flags))
			return;
		delay = 0;
	}

	schedule_delayed_work(&linkwatch_work, delay);
	/* If we wrap around we'll delay it by at most HZ. */
	if (delay > HZ)
		delay = 0;

	/*
	 * This is true if we've scheduled it immeditately or if we don't
	 * need an immediate execution and it's already pending.
	 */
	if (schedule_delayed_work(&linkwatch_work, delay) == !delay)
		return;

	/* Don't bother if there is nothing urgent. */
	if (!test_bit(LW_URGENT, &linkwatch_flags))
		return;

	/* It's already running which is good enough. */
	if (!cancel_delayed_work(&linkwatch_work))
		return;

	/* Otherwise we reschedule it again for immediate exection. */
	schedule_delayed_work(&linkwatch_work, 0);
}


@@ -123,7 +146,11 @@ static void __linkwatch_run_queue(int urgent_only)
	 */
	if (!urgent_only)
		linkwatch_nextevent = jiffies + HZ;
	clear_bit(LW_RUNNING, &linkwatch_flags);
	/* Limit wrap-around effect on delay. */
	else if (time_after(linkwatch_nextevent, jiffies + HZ))
		linkwatch_nextevent = jiffies;

	clear_bit(LW_URGENT, &linkwatch_flags);

	spin_lock_irq(&lweventlist_lock);
	next = lweventlist;
@@ -166,7 +193,7 @@ static void __linkwatch_run_queue(int urgent_only)
	}

	if (lweventlist)
		linkwatch_schedule_work(linkwatch_nextevent - jiffies);
		linkwatch_schedule_work(0);
}


@@ -187,21 +214,16 @@ static void linkwatch_event(struct work_struct *dummy)

void linkwatch_fire_event(struct net_device *dev)
{
	if (!test_and_set_bit(__LINK_STATE_LINKWATCH_PENDING, &dev->state)) {
		unsigned long delay;
	int urgent = linkwatch_urgent_event(dev);

	if (!test_and_set_bit(__LINK_STATE_LINKWATCH_PENDING, &dev->state)) {
		dev_hold(dev);

		linkwatch_add_event(dev);
	} else if (!urgent)
		return;

		delay = linkwatch_nextevent - jiffies;

		/* Minimise down-time: drop delay for up event. */
		if (linkwatch_urgent_event(dev))
			delay = 0;

		linkwatch_schedule_work(delay);
	}
	linkwatch_schedule_work(urgent);
}

EXPORT_SYMBOL(linkwatch_fire_event);