gve: Fix bug in gve_rx_alloc/free_ring
In gve_rx_free_ring, now that we are setting the pagecount high, rather
than just freeing the page with put_page we need to make sure we
subtract off the bias first.
In gve_rx_alloc_ring, we need to unfill the ring if the allocation fails
to properly cleanup.
In gve_prefill_buffers, if a page allocation failed we weren't cleaning
up properly. In addition to freeing the page we need to reduce the page
count so we should be using free_buffer. We should also be actually
iterating over the buffers that were successfully alloced not using the
local page and addr vars.
BUG=b/184636169
Signed-off-by: Catherine Sullivan <csully@google.com>
Change-Id: Ic944a6f59ad522fb7fdd96a5e28d492bf855561a
Reviewed-on: https://cos-review.googlesource.com/c/third_party/kernel/+/14552
Reviewed-by: Oleksandr Tymoshenko <ovt@google.com>
Tested-by: Vaibhav Rustagi <vaibhavrustagi@google.com>
diff --git a/drivers/net/ethernet/google/gve/gve_rx.c b/drivers/net/ethernet/google/gve/gve_rx.c
index 302f443..d852204 100644
--- a/drivers/net/ethernet/google/gve/gve_rx.c
+++ b/drivers/net/ethernet/google/gve/gve_rx.c
@@ -27,6 +27,25 @@
gve_free_page(dev, page_info->page, dma, DMA_FROM_DEVICE);
}
+static void gve_rx_unfill_pages(struct gve_priv *priv, struct gve_rx_ring *rx) {
+ u32 slots = rx->mask + 1;
+ int i;
+
+ if (rx->data.raw_addressing) {
+ for (i = 0; i < slots; i++)
+ gve_rx_free_buffer(&priv->pdev->dev, &rx->data.page_info[i],
+ &rx->data.data_ring[i]);
+ } else {
+ for (i = 0; i < slots; i++)
+ page_ref_sub(rx->data.page_info[i].page,
+ rx->data.page_info[i].pagecnt_bias - 1);
+ gve_unassign_qpl(priv, rx->data.qpl->id);
+ rx->data.qpl = NULL;
+ }
+ kfree(rx->data.page_info);
+ rx->data.page_info = NULL;
+}
+
static void gve_rx_free_ring(struct gve_priv *priv, int idx)
{
struct gve_rx_ring *rx = &priv->rx[idx];
@@ -44,17 +63,7 @@
rx->q_resources, rx->q_resources_bus);
rx->q_resources = NULL;
- if (rx->data.raw_addressing) {
- int i;
-
- for (i = 0; i < slots; i++)
- gve_rx_free_buffer(dev, &rx->data.page_info[i],
- &rx->data.data_ring[i]);
- } else {
- gve_unassign_qpl(priv, rx->data.qpl->id);
- rx->data.qpl = NULL;
- }
- kfree(rx->data.page_info);
+ gve_rx_unfill_pages(priv, rx);
bytes = sizeof(*rx->data.data_ring) * slots;
dma_free_coherent(dev, bytes, rx->data.data_ring,
@@ -115,8 +124,9 @@
rx->rx_buf_alloc_fail++;
u64_stats_update_end(&rx->statss);
for (j = 0; j < i; j++)
- gve_free_page(&priv->pdev->dev, page,
- addr, DMA_FROM_DEVICE);
+ gve_rx_free_buffer(&priv->pdev->dev,
+ &rx->data.page_info[j],
+ &rx->data.data_ring[j]);
return err;
}
} else {
@@ -219,7 +229,7 @@
rx->q_resources, rx->q_resources_bus);
rx->q_resources = NULL;
abort_filled:
- kfree(rx->data.page_info);
+ gve_rx_unfill_pages(priv, rx);
abort_with_slots:
bytes = sizeof(*rx->data.data_ring) * slots;
dma_free_coherent(hdev, bytes, rx->data.data_ring, rx->data.data_bus);