On 23/04/2022 18:23, Nikolay Aleksandrov wrote: > On 23/04/2022 18:01, Xuan Zhuo wrote: >> On Sat, 23 Apr 2022 17:58:05 +0300, Nikolay Aleksandrov <razor@xxxxxxxxxxxxx> wrote: >>> On 23/04/2022 17:36, Xuan Zhuo wrote: >>>> On Sat, 23 Apr 2022 17:30:11 +0300, Nikolay Aleksandrov <razor@xxxxxxxxxxxxx> wrote: >>>>> On 23/04/2022 17:16, Nikolay Aleksandrov wrote: >>>>>> On 23/04/2022 16:31, Xuan Zhuo wrote: >>>>>>> On Sat, 23 Apr 2022 14:26:12 +0300, Nikolay Aleksandrov <razor@xxxxxxxxxxxxx> wrote: [snip] >>>>>>> + VIRTIO_XDP_HEADROOM - metazie); >>>>>>> return head_skb; >>>>>>> } >>>>>>> break; >>>>>> >>>>>> That patch doesn't fix it, as I said with xdp you can move both data and data_meta. >>>>>> So just doing that would take care of the meta, but won't take care of moving data. >>>>>> >>>>> >>>>> Also it doesn't take care of the case where page_to_skb() is called with the original page >>>>> i.e. when we already have headroom, so we hit the next/standard page_to_skb() call (xdp_page == page). >>>> >>>> Yes, you are right. >>>> >>>>> >>>>> The above change guarantees that buf and p will be in the same page >>>> >>>> >>>> How can this be guaranteed? >>>> >>>> 1. For example, we applied for a 32k buffer first, and took away 1500 + hdr_len >>>> from the allocation. >>>> 2. set xdp >>>> 3. alloc for new buffer >>>> >>> >>> p = page_address(page) + offset; >>> buf = p & PAGE_MASK; // whatever page p lands in is where buf is set >>> >>> => p and buf are always in the same page, no? >> >> I don't think it is, it's entirely possible to split on two pages. >> >>> >>>> The buffer allocated in the third step must be unaligned, and it is entirely >>>> possible that p and buf are not on the same page. >>>> >>>> I fixed my previous patch. >>>> >>>> Thanks. >>>> >>>> diff --git a/drivers/net/virtio_net.c b/drivers/net/virtio_net.c >>>> index 87838cbe38cf..d95e82255b94 100644 >>>> --- a/drivers/net/virtio_net.c >>>> +++ b/drivers/net/virtio_net.c >>>> @@ -1005,6 +1005,8 @@ static struct sk_buff *receive_mergeable(struct net_device *dev, >>>> * xdp.data_meta were adjusted >>>> */ >>>> len = xdp.data_end - xdp.data + vi->hdr_len + metasize; >>>> + >>>> + headroom = xdp.data - vi->hdr_len - metasize - (buf - headroom); >>> >>> This is wrong, xdp.data isn't related to buf in the xdp_linearize_page() case. >> >> Yes, you are right. For the case of xdp_linearize_page() , we should change it. >> >> headroom = xdp.data - vi->hdr_len - metasize - page_address(xdp_page); >> >> Thanks. >> > > That is equal to offset: > offset = xdp.data - page_address(xdp_page) - > vi->hdr_len - metasize; > > So I do agree that it will work, it is effectively what I also suggested in the > other email and it will be equal to just doing buf = page_address() in the xdp_linearize > case because p = page_address + offset, and now we do buf = p - headroom where headroom also > equals offset, so we get buf = page_address(). > All of the above is equivalent to: diff --git a/drivers/net/virtio_net.c b/drivers/net/virtio_net.c index 87838cbe38cf..12e88980e4b3 100644 --- a/drivers/net/virtio_net.c +++ b/drivers/net/virtio_net.c @@ -1012,8 +1012,10 @@ static struct sk_buff *receive_mergeable(struct net_device *dev, head_skb = page_to_skb(vi, rq, xdp_page, offset, len, PAGE_SIZE, false, metasize, - VIRTIO_XDP_HEADROOM); + offset); return head_skb; + } else { + headroom = xdp.data - (buf - headroom) - vi->hdr_len - metasize; } break; case XDP_TX: I agree with that, it is also equivalent to my proposal in the other email. It adjusts the new headroom after the xdp prog which is ok. I'll wait (and test it in the meantime) for other feedback and if all agree I'll post v2. >> >>> >>>> /* We can only create skb based on xdp_page. */ >>>> if (unlikely(xdp_page != page)) { >>>> rcu_read_unlock(); >>>> @@ -1012,7 +1014,7 @@ static struct sk_buff *receive_mergeable(struct net_device *dev, >>>> head_skb = page_to_skb(vi, rq, xdp_page, offset, >>>> len, PAGE_SIZE, false, >>>> metasize, >>>> - VIRTIO_XDP_HEADROOM); >>>> + headroom); >>>> return head_skb; >>>> } >>>> break; >>> >