> Once tcp_zerocopy_receive() maps an order-0 RX fragment page into a > userspace VMA via vm_insert_pages(), vm_insert_pages() increments > page->_refcount, which prevents the page from being recycled back into > its page_pool when the RX SKB is freed. However, while the RX SKB still > holds its fragment reference, the page remains marked as a page_pool > page (page_pool_page_is_pp(page) == true) inside the userspace VMA, so > subsequent GUP callers such as sendmsg(MSG_ZEROCOPY) or vmsplice() can > encounter a page_pool page while holding only a raw struct page > reference. > > Establish the invariant that pp_ref_count is only incremented by callers > that already hold an active pp_ref_count (>= 1) on that netmem, and a > raw page_ref_count is never converted into a pp_ref_count: > - In can_map_frag(), require !skb_cloned(skb), page_pool_ref_count == 1, > and page_ref_count == 1 for page_pool pages so the fragment being > mapped holds the sole reference to the page; cloned SKBs or page_pool > pages with additional references (including drivers holding an > undrained fragment bias) fall back to copying. > - In tcp_zerocopy_receive(), convert the fragment's sole pp_ref_count > into a regular page reference and detach the page from its page_pool > via get_page(page) + napi_pp_put_page(page_to_netmem(page)) before > queueing the page for vm_insert_pages(). If vm_insert_pages() > subsequently fails, the detached page remains referenced by the RX SKB > via its regular page reference and is freed back to the page allocator > when the SKB is consumed. > > Signed-off-by: Mina Almasry <[email protected]>
Sashiko has reviewed this patch and found no issues. -- Sashiko AI review ยท https://sashiko.dev/#/patchset/[email protected]?part=3
