Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

Merge branch 'fix-generating-skb-from-non-linear-xdp_buff-for-mlx5'

Tariq Toukan says:

====================
Fix generating skb from non-linear xdp_buff for mlx5

Link: https://lore.kernel.org/20250915225857.3024997-1-ameryhung@gmail.com
====================

Link: https://patch.msgid.link/1760644540-899148-1-git-send-email-tariqt@nvidia.com
Signed-off-by: Jakub Kicinski <kuba@kernel.org>

+42 -9
+42 -9
drivers/net/ethernet/mellanox/mlx5/core/en_rx.c
··· 1794 1794 } 1795 1795 1796 1796 prog = rcu_dereference(rq->xdp_prog); 1797 - if (prog && mlx5e_xdp_handle(rq, prog, mxbuf)) { 1798 - if (__test_and_clear_bit(MLX5E_RQ_FLAG_XDP_XMIT, rq->flags)) { 1799 - struct mlx5e_wqe_frag_info *pwi; 1797 + if (prog) { 1798 + u8 nr_frags_free, old_nr_frags = sinfo->nr_frags; 1800 1799 1801 - for (pwi = head_wi; pwi < wi; pwi++) 1802 - pwi->frag_page->frags++; 1800 + if (mlx5e_xdp_handle(rq, prog, mxbuf)) { 1801 + if (__test_and_clear_bit(MLX5E_RQ_FLAG_XDP_XMIT, 1802 + rq->flags)) { 1803 + struct mlx5e_wqe_frag_info *pwi; 1804 + 1805 + wi -= old_nr_frags - sinfo->nr_frags; 1806 + 1807 + for (pwi = head_wi; pwi < wi; pwi++) 1808 + pwi->frag_page->frags++; 1809 + } 1810 + return NULL; /* page/packet was consumed by XDP */ 1803 1811 } 1804 - return NULL; /* page/packet was consumed by XDP */ 1812 + 1813 + nr_frags_free = old_nr_frags - sinfo->nr_frags; 1814 + if (unlikely(nr_frags_free)) { 1815 + wi -= nr_frags_free; 1816 + truesize -= nr_frags_free * frag_info->frag_stride; 1817 + } 1805 1818 } 1806 1819 1807 1820 skb = mlx5e_build_linear_skb( ··· 2040 2027 u32 byte_cnt = cqe_bcnt; 2041 2028 struct skb_shared_info *sinfo; 2042 2029 unsigned int truesize = 0; 2030 + u32 pg_consumed_bytes; 2043 2031 struct bpf_prog *prog; 2044 2032 struct sk_buff *skb; 2045 2033 u32 linear_frame_sz; ··· 2094 2080 2095 2081 while (byte_cnt) { 2096 2082 /* Non-linear mode, hence non-XSK, which always uses PAGE_SIZE. */ 2097 - u32 pg_consumed_bytes = min_t(u32, PAGE_SIZE - frag_offset, byte_cnt); 2083 + pg_consumed_bytes = 2084 + min_t(u32, PAGE_SIZE - frag_offset, byte_cnt); 2098 2085 2099 2086 if (test_bit(MLX5E_RQ_STATE_SHAMPO, &rq->state)) 2100 2087 truesize += pg_consumed_bytes; ··· 2111 2096 } 2112 2097 2113 2098 if (prog) { 2099 + u8 nr_frags_free, old_nr_frags = sinfo->nr_frags; 2100 + u32 len; 2101 + 2114 2102 if (mlx5e_xdp_handle(rq, prog, mxbuf)) { 2115 2103 if (__test_and_clear_bit(MLX5E_RQ_FLAG_XDP_XMIT, rq->flags)) { 2116 2104 struct mlx5e_frag_page *pfp; 2105 + 2106 + frag_page -= old_nr_frags - sinfo->nr_frags; 2117 2107 2118 2108 for (pfp = head_page; pfp < frag_page; pfp++) 2119 2109 pfp->frags++; ··· 2130 2110 return NULL; /* page/packet was consumed by XDP */ 2131 2111 } 2132 2112 2113 + nr_frags_free = old_nr_frags - sinfo->nr_frags; 2114 + if (unlikely(nr_frags_free)) { 2115 + frag_page -= nr_frags_free; 2116 + truesize -= (nr_frags_free - 1) * PAGE_SIZE + 2117 + ALIGN(pg_consumed_bytes, 2118 + BIT(rq->mpwqe.log_stride_sz)); 2119 + } 2120 + 2121 + len = mxbuf->xdp.data_end - mxbuf->xdp.data; 2122 + 2133 2123 skb = mlx5e_build_linear_skb( 2134 2124 rq, mxbuf->xdp.data_hard_start, linear_frame_sz, 2135 - mxbuf->xdp.data - mxbuf->xdp.data_hard_start, 0, 2125 + mxbuf->xdp.data - mxbuf->xdp.data_hard_start, len, 2136 2126 mxbuf->xdp.data - mxbuf->xdp.data_meta); 2137 2127 if (unlikely(!skb)) { 2138 2128 mlx5e_page_release_fragmented(rq->page_pool, ··· 2167 2137 do 2168 2138 pagep->frags++; 2169 2139 while (++pagep < frag_page); 2140 + 2141 + headlen = min_t(u16, MLX5E_RX_MAX_HEAD - len, 2142 + skb->data_len); 2143 + __pskb_pull_tail(skb, headlen); 2170 2144 } 2171 - __pskb_pull_tail(skb, headlen); 2172 2145 } else { 2173 2146 dma_addr_t addr; 2174 2147