git: 1bfdb812c786 - main - iflib_stop: drain rx tasks to prevent any data races

From: Andriy Gapon <avg_at_FreeBSD.org>
Date: Fri, 19 Nov 2021 08:01:37 UTC
The branch main has been updated by avg:

URL: https://cgit.FreeBSD.org/src/commit/?id=1bfdb812c786ac2607a82633f9c84a5d16f54079

commit 1bfdb812c786ac2607a82633f9c84a5d16f54079
Author:     Andriy Gapon <avg@FreeBSD.org>
AuthorDate: 2021-11-19 07:56:30 +0000
Commit:     Andriy Gapon <avg@FreeBSD.org>
CommitDate: 2021-11-19 08:00:38 +0000

    iflib_stop: drain rx tasks to prevent any data races
    
    iflib_stop modifies iflib data structures that are used by _task_fn_rx,
    most prominently the free lists.  So, iflib_stop has to ensure that the
    rx task threads are not active.
    
    This should help to fix a crash seen when iflib_if_ioctl (e.g.,
    SIOCSIFCAP) is called while there is already traffic flowing.
    
    The crash has been seen on VMWare guests with vmxnet3 driver.
    
    My guess is that on physical hardware the couple of 1ms delays that
    iflib_stop has after disabling interrupts are enough for the queued work
    to be completed before any iflib state is touched.
    
    But on busy hypervisors the guests might not get enough CPU time to
    complete the work, thus there can be a race between the taskqueue
    threads and the work done to handle an ioctl, specifically in iflib_stop
    and iflib_init_locked.
    
    PR:             259458
    Reviewed by:    markj
    MFC after:      3 weeks
    Differential Revision:  https://reviews.freebsd.org/D32926
---
 sys/net/iflib.c | 3 ++-
 1 file changed, 2 insertions(+), 1 deletion(-)

diff --git a/sys/net/iflib.c b/sys/net/iflib.c
index 8c8cc6936f7e..1fdda2ef8462 100644
--- a/sys/net/iflib.c
+++ b/sys/net/iflib.c
@@ -2634,7 +2634,8 @@ iflib_stop(if_ctx_t ctx)
 			bzero((void *)di->idi_vaddr, di->idi_size);
 	}
 	for (i = 0; i < scctx->isc_nrxqsets; i++, rxq++) {
-		/* make sure all transmitters have completed before proceeding XXX */
+		gtaskqueue_drain(rxq->ifr_task.gt_taskqueue,
+		    &rxq->ifr_task.gt_task);
 
 		rxq->ifr_cq_cidx = 0;
 		for (j = 0, di = rxq->ifr_ifdi; j < sctx->isc_nrxqs; j++, di++)