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

Configure Feed

Select the types of activity you want to include in your feed.

Merge branch 'xsk-fixes-for-af_xdp-fragment-handling'

Nikhil P. Rao says:

====================
xsk: Fixes for AF_XDP fragment handling

This series fixes two issues in AF_XDP zero-copy fragment handling:

Patch 1 fixes a buffer leak caused by incorrect list node handling after
commit b692bf9a7543. The list_node field is now reused for both the xskb
pool list and the buffer free list. Using list_del() instead of
list_del_init() causes list_empty() checks in xp_free() to fail, preventing
buffers from being added to the free list.

Patch 2 fixes partial packet delivery to userspace. In the zero-copy path,
if the Rx queue fills up while enqueuing fragments, the remaining fragments
are dropped, causing the application to receive incomplete packets. The fix
ensures the Rx queue has sufficient space for all fragments before starting
to enqueue them.

[1] https://lore.kernel.org/oe-kbuild-all/202602051720.YfZO23pZ-lkp@intel.com/
[2] https://lore.kernel.org/oe-kbuild-all/202602172046.vf9DtpdF-lkp@intel.com/
====================

Link: https://patch.msgid.link/20260225000456.107806-1-nikhil.rao@amd.com
Signed-off-by: Jakub Kicinski <kuba@kernel.org>

+20 -14
+3 -3
include/net/xdp_sock_drv.h
··· 122 122 goto out; 123 123 124 124 list_for_each_entry_safe(pos, tmp, xskb_list, list_node) { 125 - list_del(&pos->list_node); 125 + list_del_init(&pos->list_node); 126 126 xp_free(pos); 127 127 } 128 128 ··· 157 157 frag = list_first_entry_or_null(&xskb->pool->xskb_list, 158 158 struct xdp_buff_xsk, list_node); 159 159 if (frag) { 160 - list_del(&frag->list_node); 160 + list_del_init(&frag->list_node); 161 161 ret = &frag->xdp; 162 162 } 163 163 ··· 168 168 { 169 169 struct xdp_buff_xsk *xskb = container_of(xdp, struct xdp_buff_xsk, xdp); 170 170 171 - list_del(&xskb->list_node); 171 + list_del_init(&xskb->list_node); 172 172 } 173 173 174 174 static inline struct xdp_buff *xsk_buff_get_head(struct xdp_buff *first)
+17 -11
net/xdp/xsk.c
··· 167 167 struct xdp_buff_xsk *pos, *tmp; 168 168 struct list_head *xskb_list; 169 169 u32 contd = 0; 170 + u32 num_desc; 170 171 int err; 171 172 172 - if (frags) 173 - contd = XDP_PKT_CONTD; 174 - 175 - err = __xsk_rcv_zc(xs, xskb, len, contd); 176 - if (err) 177 - goto err; 178 - if (likely(!frags)) 173 + if (likely(!frags)) { 174 + err = __xsk_rcv_zc(xs, xskb, len, contd); 175 + if (err) 176 + goto err; 179 177 return 0; 178 + } 180 179 180 + contd = XDP_PKT_CONTD; 181 + num_desc = xdp_get_shared_info_from_buff(xdp)->nr_frags + 1; 182 + if (xskq_prod_nb_free(xs->rx, num_desc) < num_desc) { 183 + xs->rx_queue_full++; 184 + err = -ENOBUFS; 185 + goto err; 186 + } 187 + 188 + __xsk_rcv_zc(xs, xskb, len, contd); 181 189 xskb_list = &xskb->pool->xskb_list; 182 190 list_for_each_entry_safe(pos, tmp, xskb_list, list_node) { 183 191 if (list_is_singular(xskb_list)) 184 192 contd = 0; 185 193 len = pos->xdp.data_end - pos->xdp.data; 186 - err = __xsk_rcv_zc(xs, pos, len, contd); 187 - if (err) 188 - goto err; 189 - list_del(&pos->list_node); 194 + __xsk_rcv_zc(xs, pos, len, contd); 195 + list_del_init(&pos->list_node); 190 196 } 191 197 192 198 return 0;