As pp_magic is used to identify pp page for a skb's frag page in previous patch, so do the similar handling for the head page of a skb too.
And it seems head to frag converting for a skb during GRO and GSO processing does not need handling when using pp_magic to identify pp page for a skb' head page and frag page, see NAPI_GRO_FREE_STOLEN_HEAD for GRO in skb_gro_receive() and skb_head_frag_to_page_desc() for GSO in skb_segment().
As pp_magic only exist in the head page of a compound page, and the freeing of a head page for a skb is eventually operated on the head page of a compound page for both pp and non-pp page, so use virt_to_head_page() and __page_frag_cache_drain() in skb_free_head() to avoid unnecessary virt_to_head_page() calling in page_frag_free().
Signed-off-by: Yunsheng Lin linyunsheng@huawei.com --- include/linux/skbuff.h | 15 --------------- net/core/skbuff.c | 11 +++++++++-- 2 files changed, 9 insertions(+), 17 deletions(-)
diff --git a/include/linux/skbuff.h b/include/linux/skbuff.h index a2d3b6fe0c32..b77ee060b64d 100644 --- a/include/linux/skbuff.h +++ b/include/linux/skbuff.h @@ -4728,20 +4728,5 @@ static inline void skb_mark_for_recycle(struct sk_buff *skb) } #endif
-static inline bool skb_pp_recycle(struct sk_buff *skb, void *data) -{ - struct page *page; - - if (!IS_ENABLED(CONFIG_PAGE_POOL) || !skb->pp_recycle) - return false; - - page = virt_to_head_page(data); - if (!page_pool_is_pp_page(page)) - return false; - - page_pool_return_skb_page(page); - return true; -} - #endif /* __KERNEL__ */ #endif /* _LINUX_SKBUFF_H */ diff --git a/net/core/skbuff.c b/net/core/skbuff.c index db8af3eff255..3718898da499 100644 --- a/net/core/skbuff.c +++ b/net/core/skbuff.c @@ -647,9 +647,16 @@ static void skb_free_head(struct sk_buff *skb) unsigned char *head = skb->head;
if (skb->head_frag) { - if (skb_pp_recycle(skb, head)) + struct page *page = virt_to_head_page(head); + +#ifdef CONFIG_PAGE_POOL + if (page_pool_is_pp_page(page)) { + page_pool_return_skb_page(page); return; - skb_free_frag(head); + } +#endif + + __page_frag_cache_drain(page, 1); } else { kfree(head); }