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:
parent
7a866f0d1b
commit
1f2766b7ee
@ -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) {
|
||||
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;
|
||||
|
@ -80,7 +80,7 @@ struct hn_rx_queue {
|
||||
struct hn_stats stats;
|
||||
uint64_t ring_full;
|
||||
|
||||
uint8_t event_buf[];
|
||||
void *event_buf;
|
||||
};
|
||||
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user