Skip to content

Commit 11c4aa0

Browse files
mfijalkoanguy11
authored andcommitted
ice: gather page_count()'s of each frag right before XDP prog call
If we store the pgcnt on few fragments while being in the middle of gathering the whole frame and we stumbled upon DD bit not being set, we terminate the NAPI Rx processing loop and come back later on. Then on next NAPI execution we work on previously stored pgcnt. Imagine that second half of page was used actively by networking stack and by the time we came back, stack is not busy with this page anymore and decremented the refcnt. The page reuse algorithm in this case should be good to reuse the page but given the old refcnt it will not do so and attempt to release the page via page_frag_cache_drain() with pagecnt_bias used as an arg. This in turn will result in negative refcnt on struct page, which was initially observed by Xu Du. Therefore, move the page count storage from ice_get_rx_buf() to a place where we are sure that whole frame has been collected, but before calling XDP program as it internally can also change the page count of fragments belonging to xdp_buff. Fixes: ac07533 ("ice: Store page count inside ice_rx_buf") Reported-and-tested-by: Xu Du <[email protected]> Reviewed-by: Przemek Kitszel <[email protected]> Reviewed-by: Simon Horman <[email protected]> Co-developed-by: Jacob Keller <[email protected]> Signed-off-by: Jacob Keller <[email protected]> Signed-off-by: Maciej Fijalkowski <[email protected]> Tested-by: Chandan Kumar Rout <[email protected]> (A Contingent Worker at Intel) Signed-off-by: Tony Nguyen <[email protected]>
1 parent 743bbd9 commit 11c4aa0

File tree

1 file changed

+26
-1
lines changed

1 file changed

+26
-1
lines changed

drivers/net/ethernet/intel/ice/ice_txrx.c

Lines changed: 26 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -924,7 +924,6 @@ ice_get_rx_buf(struct ice_rx_ring *rx_ring, const unsigned int size,
924924
struct ice_rx_buf *rx_buf;
925925

926926
rx_buf = &rx_ring->rx_buf[ntc];
927-
rx_buf->pgcnt = page_count(rx_buf->page);
928927
prefetchw(rx_buf->page);
929928

930929
if (!size)
@@ -940,6 +939,31 @@ ice_get_rx_buf(struct ice_rx_ring *rx_ring, const unsigned int size,
940939
return rx_buf;
941940
}
942941

942+
/**
943+
* ice_get_pgcnts - grab page_count() for gathered fragments
944+
* @rx_ring: Rx descriptor ring to store the page counts on
945+
*
946+
* This function is intended to be called right before running XDP
947+
* program so that the page recycling mechanism will be able to take
948+
* a correct decision regarding underlying pages; this is done in such
949+
* way as XDP program can change the refcount of page
950+
*/
951+
static void ice_get_pgcnts(struct ice_rx_ring *rx_ring)
952+
{
953+
u32 nr_frags = rx_ring->nr_frags + 1;
954+
u32 idx = rx_ring->first_desc;
955+
struct ice_rx_buf *rx_buf;
956+
u32 cnt = rx_ring->count;
957+
958+
for (int i = 0; i < nr_frags; i++) {
959+
rx_buf = &rx_ring->rx_buf[idx];
960+
rx_buf->pgcnt = page_count(rx_buf->page);
961+
962+
if (++idx == cnt)
963+
idx = 0;
964+
}
965+
}
966+
943967
/**
944968
* ice_build_skb - Build skb around an existing buffer
945969
* @rx_ring: Rx descriptor ring to transact packets on
@@ -1241,6 +1265,7 @@ int ice_clean_rx_irq(struct ice_rx_ring *rx_ring, int budget)
12411265
if (ice_is_non_eop(rx_ring, rx_desc))
12421266
continue;
12431267

1268+
ice_get_pgcnts(rx_ring);
12441269
ice_run_xdp(rx_ring, xdp, xdp_prog, xdp_ring, rx_buf, rx_desc);
12451270
if (rx_buf->act == ICE_XDP_PASS)
12461271
goto construct_skb;

0 commit comments

Comments
 (0)