Date: Wed, 10 Jun 2020 20:05:07 +0000 (UTC) From: Vincenzo Maffione <vmaffione@FreeBSD.org> To: src-committers@freebsd.org, svn-src-all@freebsd.org, svn-src-stable@freebsd.org, svn-src-stable-12@freebsd.org Subject: svn commit: r362025 - stable/12/sys/dev/netmap Message-ID: <202006102005.05AK572r031823@repo.freebsd.org>
next in thread | raw e-mail | index | archive | help
Author: vmaffione Date: Wed Jun 10 20:05:07 2020 New Revision: 362025 URL: https://svnweb.freebsd.org/changeset/base/362025 Log: MFC r361759 netmap: vtnet: fix race condition in rxsync This change prevents a race that happens when rxsync dequeues N-1 rx packets (with N being the size of the netmap rx ring). In this situation, the loop exits without re-enabling the rx interrupts, thus causing the VQ to stall. Modified: stable/12/sys/dev/netmap/if_vtnet_netmap.h Directory Properties: stable/12/ (props changed) Modified: stable/12/sys/dev/netmap/if_vtnet_netmap.h ============================================================================== --- stable/12/sys/dev/netmap/if_vtnet_netmap.h Wed Jun 10 20:04:20 2020 (r362024) +++ stable/12/sys/dev/netmap/if_vtnet_netmap.h Wed Jun 10 20:05:07 2020 (r362025) @@ -310,8 +310,11 @@ vtnet_netmap_rxsync(struct netmap_kring *kring, int fl /* * First part: import newly received packets. * Only accept our own buffers (matching the token). We should only get - * matching buffers. We may need to stop early to avoid hwtail to overrun - * hwcur. + * matching buffers. The hwtail should never overrun hwcur, because + * we publish only N-1 receive buffers (and non N). + * In any case we must not leave this routine with the interrupts + * disabled, pending packets in the VQ and hwtail == (hwcur - 1), + * otherwise the pending packets could stall. */ if (netmap_no_pendintr || force_update) { uint32_t hwtail_lim = nm_prev(kring->nr_hwcur, lim); @@ -320,10 +323,17 @@ vtnet_netmap_rxsync(struct netmap_kring *kring, int fl vtnet_rxq_disable_intr(rxq); nm_i = kring->nr_hwtail; - while (nm_i != hwtail_lim) { + for (;;) { int len; token = virtqueue_dequeue(vq, &len); if (token == NULL) { + /* + * Enable the interrupts again and double-check + * for more work. We can go on until we win the + * race condition, since we are not replenishing + * in the meanwhile, and thus we will process at + * most N-1 slots. + */ if (interrupts && vtnet_rxq_enable_intr(rxq)) { vtnet_rxq_disable_intr(rxq); continue; @@ -333,6 +343,11 @@ vtnet_netmap_rxsync(struct netmap_kring *kring, int fl if (unlikely(token != (void *)rxq)) { nm_prerr("BUG: RX token mismatch"); } else { + if (nm_i == hwtail_lim) { + KASSERT(false, ("hwtail would " + "overrun hwcur")); + } + /* Skip the virtio-net header. */ len -= sc->vtnet_hdr_size; if (unlikely(len < 0)) {
Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?202006102005.05AK572r031823>