Date: Wed, 3 Jun 2020 17:46:21 +0000 (UTC) From: Vincenzo Maffione <vmaffione@FreeBSD.org> To: src-committers@freebsd.org, svn-src-all@freebsd.org, svn-src-head@freebsd.org Subject: svn commit: r361759 - head/sys/dev/netmap Message-ID: <202006031746.053HkLBB035616@repo.freebsd.org>
next in thread | raw e-mail | index | archive | help
Author: vmaffione Date: Wed Jun 3 17:46:21 2020 New Revision: 361759 URL: https://svnweb.freebsd.org/changeset/base/361759 Log: 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. MFC after: 1 week Modified: head/sys/dev/netmap/if_vtnet_netmap.h Modified: head/sys/dev/netmap/if_vtnet_netmap.h ============================================================================== --- head/sys/dev/netmap/if_vtnet_netmap.h Wed Jun 3 17:42:17 2020 (r361758) +++ head/sys/dev/netmap/if_vtnet_netmap.h Wed Jun 3 17:46:21 2020 (r361759) @@ -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?202006031746.053HkLBB035616>