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

Commit b37c0fbe authored by Alexander Duyck's avatar Alexander Duyck Committed by Jeff Kirsher
Browse files

net: Add memory barriers to prevent possible race in byte queue limits



This change adds a memory barrier to the byte queue limit code to address a
possible race as has been seen in the past with the
netif_stop_queue/netif_wake_queue logic.

Signed-off-by: default avatarAlexander Duyck <alexander.h.duyck@intel.com>
Tested-by: default avatarStephen Ko <stephen.s.ko@intel.com>
Signed-off-by: default avatarJeff Kirsher <jeffrey.t.kirsher@intel.com>
parent 5c490354
Loading
Loading
Loading
Loading
+33 −16
Original line number Diff line number Diff line
@@ -1899,12 +1899,22 @@ static inline void netdev_tx_sent_queue(struct netdev_queue *dev_queue,
{
#ifdef CONFIG_BQL
	dql_queued(&dev_queue->dql, bytes);
	if (unlikely(dql_avail(&dev_queue->dql) < 0)) {

	if (likely(dql_avail(&dev_queue->dql) >= 0))
		return;

	set_bit(__QUEUE_STATE_STACK_XOFF, &dev_queue->state);

	/*
	 * The XOFF flag must be set before checking the dql_avail below,
	 * because in netdev_tx_completed_queue we update the dql_completed
	 * before checking the XOFF flag.
	 */
	smp_mb();

	/* check again in case another CPU has just made room avail */
	if (unlikely(dql_avail(&dev_queue->dql) >= 0))
			clear_bit(__QUEUE_STATE_STACK_XOFF,
			    &dev_queue->state);
	}
		clear_bit(__QUEUE_STATE_STACK_XOFF, &dev_queue->state);
#endif
}

@@ -1917,16 +1927,23 @@ static inline void netdev_tx_completed_queue(struct netdev_queue *dev_queue,
					     unsigned pkts, unsigned bytes)
{
#ifdef CONFIG_BQL
	if (likely(bytes)) {
	if (unlikely(!bytes))
		return;

	dql_completed(&dev_queue->dql, bytes);
		if (unlikely(test_bit(__QUEUE_STATE_STACK_XOFF,
		    &dev_queue->state) &&
		    dql_avail(&dev_queue->dql) >= 0)) {
			if (test_and_clear_bit(__QUEUE_STATE_STACK_XOFF,
			     &dev_queue->state))

	/*
	 * Without the memory barrier there is a small possiblity that
	 * netdev_tx_sent_queue will miss the update and cause the queue to
	 * be stopped forever
	 */
	smp_mb();

	if (dql_avail(&dev_queue->dql) < 0)
		return;

	if (test_and_clear_bit(__QUEUE_STATE_STACK_XOFF, &dev_queue->state))
		netif_schedule_queue(dev_queue);
		}
	}
#endif
}