net/netvsc: resize event buffer as needed

The event buffer was changed to be a fixed size value,
had a couple of issues. The big one is that rte_free was still
being called for a pointer that was not setup with rte_malloc().

The event buffer was also too small to handle heavy receive
traffic; and running the event buffer out would crash
the application.

Fix by going back to a dynamically resized event buffer.
And grow it by 25% to avoid lots of realloc's.

Fixes: 530af95a78 ("bus/vmbus: avoid signalling host on read")
Cc: stable@dpdk.org

Signed-off-by: Stephen Hemminger <sthemmin@microsoft.com>
This commit is contained in:
Stephen Hemminger 2018-08-14 09:45:25 -07:00 committed by Ferruh Yigit
parent 7a866f0d1b
commit 1f2766b7ee
2 changed files with 38 additions and 14 deletions

View File

@ -10,6 +10,7 @@
#include <errno.h>
#include <unistd.h>
#include <strings.h>
#include <malloc.h>
#include <rte_ethdev.h>
#include <rte_memcpy.h>
@ -718,16 +719,24 @@ struct hn_rx_queue *hn_rx_queue_alloc(struct hn_data *hv,
{
struct hn_rx_queue *rxq;
rxq = rte_zmalloc_socket("HN_RXQ",
sizeof(*rxq) + HN_RXQ_EVENT_DEFAULT,
rxq = rte_zmalloc_socket("HN_RXQ", sizeof(*rxq),
RTE_CACHE_LINE_SIZE, socket_id);
if (rxq) {
rxq->hv = hv;
rxq->chan = hv->channels[queue_id];
rte_spinlock_init(&rxq->ring_lock);
rxq->port_id = hv->port_id;
rxq->queue_id = queue_id;
if (!rxq)
return NULL;
rxq->hv = hv;
rxq->chan = hv->channels[queue_id];
rte_spinlock_init(&rxq->ring_lock);
rxq->port_id = hv->port_id;
rxq->queue_id = queue_id;
rxq->event_sz = HN_RXQ_EVENT_DEFAULT;
rxq->event_buf = rte_malloc_socket("HN_EVENTS", HN_RXQ_EVENT_DEFAULT,
RTE_CACHE_LINE_SIZE, socket_id);
if (!rxq->event_buf) {
rte_free(rxq);
return NULL;
}
return rxq;
}
@ -863,19 +872,34 @@ uint32_t hn_process_events(struct hn_data *hv, uint16_t queue_id,
for (;;) {
const struct vmbus_chanpkt_hdr *pkt;
uint32_t len = HN_RXQ_EVENT_DEFAULT;
uint32_t len = rxq->event_sz;
const void *data;
retry:
ret = rte_vmbus_chan_recv_raw(rxq->chan, rxq->event_buf, &len);
if (ret == -EAGAIN)
break; /* ring is empty */
else if (ret == -ENOBUFS)
rte_exit(EXIT_FAILURE, "event buffer not big enough (%u < %u)",
HN_RXQ_EVENT_DEFAULT, len);
else if (ret <= 0)
if (unlikely(ret == -ENOBUFS)) {
/* event buffer not large enough to read ring */
PMD_DRV_LOG(DEBUG,
"event buffer expansion (need %u)", len);
rxq->event_sz = len + len / 4;
rxq->event_buf = rte_realloc(rxq->event_buf, rxq->event_sz,
RTE_CACHE_LINE_SIZE);
if (rxq->event_buf)
goto retry;
/* out of memory, no more events now */
rxq->event_sz = 0;
break;
}
if (unlikely(ret <= 0)) {
/* This indicates a failure to communicate (or worse) */
rte_exit(EXIT_FAILURE,
"vmbus ring buffer error: %d", ret);
}
bytes_read += ret;
pkt = (const struct vmbus_chanpkt_hdr *)rxq->event_buf;

View File

@ -80,7 +80,7 @@ struct hn_rx_queue {
struct hn_stats stats;
uint64_t ring_full;
uint8_t event_buf[];
void *event_buf;
};