On Thu, Jun 26, 2025 at 12:10 AM Bui Quang Minh <minhquangbu...@gmail.com> wrote: > > When the mergeable receive buffer is prefilled before XDP is set, it > does not reserve the space for XDP_PACKET_HEADROOM and skb_shared_info. > So when XDP is set and this buffer is used to receive frame, we need to > create a new buffer with reserved headroom, tailroom and copy the frame > data over. Currently, the new buffer's size is restricted to PAGE_SIZE > only. If the frame data's length + headroom + tailroom exceeds > PAGE_SIZE, the frame is dropped. > > However, it seems like there is no restriction on the total size in XDP. > So we can just increase the size of new buffer to 2 * PAGE_SIZE in that > case and continue to process the frame. > > In my opinion, the current drop behavior is fine and expected so this > commit is just an improvement not a bug fix.
Then this should go for net-next. > > Signed-off-by: Bui Quang Minh <minhquangbu...@gmail.com> > --- > drivers/net/virtio_net.c | 19 +++++++++++++++---- > 1 file changed, 15 insertions(+), 4 deletions(-) > > diff --git a/drivers/net/virtio_net.c b/drivers/net/virtio_net.c > index 844cb2a78be0..663cec686045 100644 > --- a/drivers/net/virtio_net.c > +++ b/drivers/net/virtio_net.c > @@ -2277,13 +2277,26 @@ static void *mergeable_xdp_get_buf(struct > virtnet_info *vi, > len); > if (!xdp_page) > return NULL; > + > + *frame_sz = PAGE_SIZE; > } else { > + unsigned int total_len; > + > xdp_room = SKB_DATA_ALIGN(XDP_PACKET_HEADROOM + > sizeof(struct skb_shared_info)); > - if (*len + xdp_room > PAGE_SIZE) > + total_len = *len + xdp_room; > + > + /* This must never happen because len cannot exceed PAGE_SIZE > */ > + if (unlikely(total_len > 2 * PAGE_SIZE)) > return NULL; > > - xdp_page = alloc_page(GFP_ATOMIC); > + if (total_len > PAGE_SIZE) { > + xdp_page = alloc_pages(GFP_ATOMIC, 1); I'm not sure it's worth optimizing the corner case here that may bring burdens for maintenance. And a good optimization here is to reduce the logic duplication by reusing xdp_linearize_page(). > + *frame_sz = 2 * PAGE_SIZE; > + } else { > + xdp_page = alloc_page(GFP_ATOMIC); > + *frame_sz = PAGE_SIZE; > + } > if (!xdp_page) > return NULL; > > @@ -2291,8 +2304,6 @@ static void *mergeable_xdp_get_buf(struct virtnet_info > *vi, > page_address(*page) + offset, *len); > } > > - *frame_sz = PAGE_SIZE; > - > put_page(*page); > > *page = xdp_page; > -- Thanks > 2.43.0 >