[<prev] [next>] [<thread-prev] [thread-next>] [day] [month] [year] [list]
Message-Id: <155360909248.12643.10847731197567084727.email-sent-by-dnelson@cyan>
Date: Tue, 26 Mar 2019 10:04:54 -0400
From: Dean Nelson <dnelson@...hat.com>
To: Robert Richter <rric@...nel.org>,
Sunil Goutham <sgoutham@...ium.com>,
David Miller <davem@...emloft.net>
Cc: netdev@...r.kernel.org, linux-arm-kernel@...ts.infradead.org,
Vadim Lomovtsev <vlomovtsev@...vell.com>
Subject: [PATCH net 2/2] thunderx: eliminate extra calls to put_page() for pages held for recycling
For the non-XDP case, commit 773225388dae15e72790 added code to
nicvf_free_rbdr() that, when releasing the additional receive buffer page
reference held for recycling, repeatedly calls put_page() until the page's
_refcount goes to zero. Which results in the page being freed.
This is not okay if the page's _refcount was greater than 1 (in the non-XDP
case), because nicvf_free_rbdr() should not be subtracting more than what
nicvf_alloc_page() had previously added to the page's _refcount, which was
only 1 (in the non-XDP case).
This can arise if a received packet is still being processed and the receive
buffer (i.e., skb->head) has not yet been freed via skb_free_head() when
nicvf_free_rbdr() is spinning through the aforementioned put_page() loop.
If this should occur, when the received packet finishes processing and
skb_free_head() is called, various problems can ensue. Exactly what, depends on
whether the page has already been reallocated or not, anything from "BUG: Bad
page state ... ", to "Unable to handle kernel NULL pointer dereference ..." or
"Unable to handle kernel paging request...".
So this patch changes nicvf_free_rbdr() to only call put_page() once for pages
held for recycling (in the non-XDP case).
Signed-off-by: Dean Nelson <dnelson@...hat.com>
---
drivers/net/ethernet/cavium/thunder/nicvf_queues.c | 7 +++----
1 file changed, 3 insertions(+), 4 deletions(-)
diff --git a/drivers/net/ethernet/cavium/thunder/nicvf_queues.c b/drivers/net/ethernet/cavium/thunder/nicvf_queues.c
index 55dbf02c42af..e246f9733bb8 100644
--- a/drivers/net/ethernet/cavium/thunder/nicvf_queues.c
+++ b/drivers/net/ethernet/cavium/thunder/nicvf_queues.c
@@ -364,11 +364,10 @@ static void nicvf_free_rbdr(struct nicvf *nic, struct rbdr *rbdr)
while (head < rbdr->pgcnt) {
pgcache = &rbdr->pgcache[head];
if (pgcache->page && page_ref_count(pgcache->page) != 0) {
- if (!rbdr->is_xdp) {
- put_page(pgcache->page);
- continue;
+ if (rbdr->is_xdp) {
+ page_ref_sub(pgcache->page,
+ pgcache->ref_count - 1);
}
- page_ref_sub(pgcache->page, pgcache->ref_count - 1);
put_page(pgcache->page);
}
head++;
Powered by blists - more mailing lists