From owner-svn-src-head@freebsd.org Wed Jun 3 17:42:18 2020 Return-Path: Delivered-To: svn-src-head@mailman.nyi.freebsd.org Received: from mx1.freebsd.org (mx1.freebsd.org [IPv6:2610:1c1:1:606c::19:1]) by mailman.nyi.freebsd.org (Postfix) with ESMTP id B63FC33C7B4; Wed, 3 Jun 2020 17:42:18 +0000 (UTC) (envelope-from vmaffione@FreeBSD.org) Received: from mxrelay.nyi.freebsd.org (mxrelay.nyi.freebsd.org [IPv6:2610:1c1:1:606c::19:3]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits) key-exchange X25519 server-signature RSA-PSS (4096 bits) server-digest SHA256 client-signature RSA-PSS (4096 bits) client-digest SHA256) (Client CN "mxrelay.nyi.freebsd.org", Issuer "Let's Encrypt Authority X3" (verified OK)) by mx1.freebsd.org (Postfix) with ESMTPS id 49cbp24RRcz3wkb; Wed, 3 Jun 2020 17:42:18 +0000 (UTC) (envelope-from vmaffione@FreeBSD.org) Received: from repo.freebsd.org (repo.freebsd.org [IPv6:2610:1c1:1:6068::e6a:0]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (Client did not present a certificate) by mxrelay.nyi.freebsd.org (Postfix) with ESMTPS id 93AFB11E85; Wed, 3 Jun 2020 17:42:18 +0000 (UTC) (envelope-from vmaffione@FreeBSD.org) Received: from repo.freebsd.org ([127.0.1.37]) by repo.freebsd.org (8.15.2/8.15.2) with ESMTP id 053HgI5l035359; Wed, 3 Jun 2020 17:42:18 GMT (envelope-from vmaffione@FreeBSD.org) Received: (from vmaffione@localhost) by repo.freebsd.org (8.15.2/8.15.2/Submit) id 053HgIus035358; Wed, 3 Jun 2020 17:42:18 GMT (envelope-from vmaffione@FreeBSD.org) Message-Id: <202006031742.053HgIus035358@repo.freebsd.org> X-Authentication-Warning: repo.freebsd.org: vmaffione set sender to vmaffione@FreeBSD.org using -f From: Vincenzo Maffione Date: Wed, 3 Jun 2020 17:42:18 +0000 (UTC) To: src-committers@freebsd.org, svn-src-all@freebsd.org, svn-src-head@freebsd.org Subject: svn commit: r361758 - in head/sys/dev: netmap virtio/network X-SVN-Group: head X-SVN-Commit-Author: vmaffione X-SVN-Commit-Paths: in head/sys/dev: netmap virtio/network X-SVN-Commit-Revision: 361758 X-SVN-Commit-Repository: base MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit X-BeenThere: svn-src-head@freebsd.org X-Mailman-Version: 2.1.33 Precedence: list List-Id: SVN commit messages for the src tree for head/-current List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , X-List-Received-Date: Wed, 03 Jun 2020 17:42:18 -0000 Author: vmaffione Date: Wed Jun 3 17:42:17 2020 New Revision: 361758 URL: https://svnweb.freebsd.org/changeset/base/361758 Log: netmap: vtnet: add vtnrx_nm_refill index to receive queues The new index tracks the next netmap slot that is going to be enqueued into the virtqueue. The index is necessary to prevent the receive VQ and the netmap rx ring from going out of sync, considering that we never enqueue N slots, but at most N-1. This change fixes a bug that causes the VQ and the netmap ring to go out of sync after N-1 packets have been received. MFC after: 1 week Modified: head/sys/dev/netmap/if_vtnet_netmap.h head/sys/dev/virtio/network/if_vtnetvar.h Modified: head/sys/dev/netmap/if_vtnet_netmap.h ============================================================================== --- head/sys/dev/netmap/if_vtnet_netmap.h Wed Jun 3 17:26:00 2020 (r361757) +++ head/sys/dev/netmap/if_vtnet_netmap.h Wed Jun 3 17:42:17 2020 (r361758) @@ -196,9 +196,11 @@ vtnet_netmap_txsync(struct netmap_kring *kring, int fl } /* - * Publish (up to) num netmap receive buffers to the host, - * starting from the first one that the user made available - * (kring->nr_hwcur). + * Publish 'num 'netmap receive buffers to the host, starting + * from the next available one (rx->vtnrx_nm_refill). + * Return a positive error code on error, and 0 on success. + * If we could not publish all of the buffers that's an error, + * since the netmap ring and the virtqueue would go out of sync. */ static int vtnet_netmap_kring_refill(struct netmap_kring *kring, u_int num) @@ -208,7 +210,7 @@ vtnet_netmap_kring_refill(struct netmap_kring *kring, struct netmap_ring *ring = kring->ring; u_int ring_nr = kring->ring_id; u_int const lim = kring->nkr_num_slots - 1; - u_int nm_i = kring->nr_hwcur; + u_int nm_i; /* device-specific */ struct vtnet_softc *sc = ifp->if_softc; @@ -219,7 +221,8 @@ vtnet_netmap_kring_refill(struct netmap_kring *kring, struct sglist_seg ss[2]; struct sglist sg = { ss, 0, 0, 2 }; - for (; num > 0; nm_i = nm_next(nm_i, lim), num--) { + for (nm_i = rxq->vtnrx_nm_refill; num > 0; + nm_i = nm_next(nm_i, lim), num--) { struct netmap_slot *slot = &ring->slot[nm_i]; uint64_t paddr; void *addr = PNMB(na, slot, &paddr); @@ -227,7 +230,7 @@ vtnet_netmap_kring_refill(struct netmap_kring *kring, if (addr == NETMAP_BUF_BASE(na)) { /* bad buf */ if (netmap_ring_reinit(kring)) - return -1; + return EFAULT; } slot->flags &= ~NS_BUF_CHANGED; @@ -240,14 +243,14 @@ vtnet_netmap_kring_refill(struct netmap_kring *kring, err = virtqueue_enqueue(vq, /*cookie=*/rxq, &sg, /*readable=*/0, /*writeable=*/sg.sg_nseg); if (unlikely(err)) { - if (err != ENOSPC) - nm_prerr("virtqueue_enqueue(%s) failed: %d", - kring->name, err); + nm_prerr("virtqueue_enqueue(%s) failed: %d", + kring->name, err); break; } } + rxq->vtnrx_nm_refill = nm_i; - return nm_i; + return num == 0 ? 0 : ENOSPC; } /* @@ -274,11 +277,14 @@ vtnet_netmap_rxq_populate(struct vtnet_rxq *rxq) /* Expose all the RX netmap buffers we can. In case of no indirect * buffers, the number of netmap slots in the RX ring matches the * maximum number of 2-elements sglist that the RX virtqueue can - * accommodate (minus 1 to avoid netmap ring wraparound). */ + * accommodate. We need to start from kring->nr_hwcur, which is 0 + * on netmap register and may be different from 0 if a virtio + * re-init happens while the device is in use by netmap. */ + rxq->vtnrx_nm_refill = kring->nr_hwcur; error = vtnet_netmap_kring_refill(kring, na->num_rx_desc - 1); virtqueue_notify(rxq->vtnrx_vq); - return error < 0 ? ENXIO : 0; + return error; } /* Reconcile kernel and user view of the receive ring. */ @@ -350,15 +356,19 @@ vtnet_netmap_rxsync(struct netmap_kring *kring, int fl */ nm_i = kring->nr_hwcur; /* netmap ring index */ if (nm_i != head) { - int howmany = head - nm_i; - int nm_j; + int released; + int error; - if (howmany < 0) - howmany += kring->nkr_num_slots; - nm_j = vtnet_netmap_kring_refill(kring, howmany); - if (nm_j < 0) - return nm_j; - kring->nr_hwcur = nm_j; + released = head - nm_i; + if (released < 0) + released += kring->nkr_num_slots; + error = vtnet_netmap_kring_refill(kring, released); + if (error) { + nm_prerr("Failed to replenish RX VQ with %u sgs", + released); + return error; + } + kring->nr_hwcur = head; virtqueue_notify(vq); } Modified: head/sys/dev/virtio/network/if_vtnetvar.h ============================================================================== --- head/sys/dev/virtio/network/if_vtnetvar.h Wed Jun 3 17:26:00 2020 (r361757) +++ head/sys/dev/virtio/network/if_vtnetvar.h Wed Jun 3 17:42:17 2020 (r361758) @@ -80,6 +80,7 @@ struct vtnet_rxq { struct taskqueue *vtnrx_tq; struct task vtnrx_intrtask; #ifdef DEV_NETMAP + uint32_t vtnrx_nm_refill; struct virtio_net_hdr_mrg_rxbuf vtnrx_shrhdr; #endif /* DEV_NETMAP */ char vtnrx_name[16];