Refactor some of the skb frag ref/unref helpers for improved clarity. Implement napi_pp_get_page() to be the mirror counterpart of napi_pp_put_page(). Implement skb_page_ref() to be the mirror of skb_page_unref(). Improve __skb_frag_ref() to become a mirror counterpart of __skb_frag_unref(). Previously unref could handle pp & non-pp pages, while the ref could only handle non-pp pages. Now both the ref & unref helpers can correctly handle both pp & non-pp pages. Now that __skb_frag_ref() can handle both pp & non-pp pages, remove skb_pp_frag_ref(), and use __skb_frag_ref() instead. This lets us remove pp specific handling from skb_try_coalesce. Additionally, since __skb_frag_ref() can now handle both pp & non-pp pages, a latent issue in skb_shift() should now be fixed. Previously this function would do a non-pp ref & pp unref on potential pp frags (fragfrom). After this patch, skb_shift() should correctly do a pp ref/unref on pp frags. Signed-off-by: Mina Almasry <almasrymina@google.com> Reviewed-by: Dragos Tatulea <dtatulea@nvidia.com> Reviewed-by: Jacob Keller <jacob.e.keller@intel.com> Link: https://lore.kernel.org/r/20240410190505.1225848-3-almasrymina@google.com Signed-off-by: Jakub Kicinski <kuba@kernel.org>
107 lines
2.5 KiB
C
107 lines
2.5 KiB
C
/* SPDX-License-Identifier: GPL-2.0-or-later */
|
|
/*
|
|
* Skb ref helpers.
|
|
*
|
|
*/
|
|
|
|
#ifndef _LINUX_SKBUFF_REF_H
|
|
#define _LINUX_SKBUFF_REF_H
|
|
|
|
#include <linux/skbuff.h>
|
|
#include <net/page_pool/helpers.h>
|
|
|
|
#ifdef CONFIG_PAGE_POOL
|
|
static inline bool is_pp_page(struct page *page)
|
|
{
|
|
return (page->pp_magic & ~0x3UL) == PP_SIGNATURE;
|
|
}
|
|
|
|
static inline bool napi_pp_get_page(struct page *page)
|
|
{
|
|
page = compound_head(page);
|
|
|
|
if (!is_pp_page(page))
|
|
return false;
|
|
|
|
page_pool_ref_page(page);
|
|
return true;
|
|
}
|
|
#endif
|
|
|
|
static inline void skb_page_ref(struct page *page, bool recycle)
|
|
{
|
|
#ifdef CONFIG_PAGE_POOL
|
|
if (recycle && napi_pp_get_page(page))
|
|
return;
|
|
#endif
|
|
get_page(page);
|
|
}
|
|
|
|
/**
|
|
* __skb_frag_ref - take an addition reference on a paged fragment.
|
|
* @frag: the paged fragment
|
|
* @recycle: skb->pp_recycle param of the parent skb. False if no parent skb.
|
|
*
|
|
* Takes an additional reference on the paged fragment @frag. Obtains the
|
|
* correct reference count depending on whether skb->pp_recycle is set and
|
|
* whether the frag is a page pool frag.
|
|
*/
|
|
static inline void __skb_frag_ref(skb_frag_t *frag, bool recycle)
|
|
{
|
|
skb_page_ref(skb_frag_page(frag), recycle);
|
|
}
|
|
|
|
/**
|
|
* skb_frag_ref - take an addition reference on a paged fragment of an skb.
|
|
* @skb: the buffer
|
|
* @f: the fragment offset.
|
|
*
|
|
* Takes an additional reference on the @f'th paged fragment of @skb.
|
|
*/
|
|
static inline void skb_frag_ref(struct sk_buff *skb, int f)
|
|
{
|
|
__skb_frag_ref(&skb_shinfo(skb)->frags[f], skb->pp_recycle);
|
|
}
|
|
|
|
bool napi_pp_put_page(struct page *page);
|
|
|
|
static inline void
|
|
skb_page_unref(struct page *page, bool recycle)
|
|
{
|
|
#ifdef CONFIG_PAGE_POOL
|
|
if (recycle && napi_pp_put_page(page))
|
|
return;
|
|
#endif
|
|
put_page(page);
|
|
}
|
|
|
|
/**
|
|
* __skb_frag_unref - release a reference on a paged fragment.
|
|
* @frag: the paged fragment
|
|
* @recycle: recycle the page if allocated via page_pool
|
|
*
|
|
* Releases a reference on the paged fragment @frag
|
|
* or recycles the page via the page_pool API.
|
|
*/
|
|
static inline void __skb_frag_unref(skb_frag_t *frag, bool recycle)
|
|
{
|
|
skb_page_unref(skb_frag_page(frag), recycle);
|
|
}
|
|
|
|
/**
|
|
* skb_frag_unref - release a reference on a paged fragment of an skb.
|
|
* @skb: the buffer
|
|
* @f: the fragment offset
|
|
*
|
|
* Releases a reference on the @f'th paged fragment of @skb.
|
|
*/
|
|
static inline void skb_frag_unref(struct sk_buff *skb, int f)
|
|
{
|
|
struct skb_shared_info *shinfo = skb_shinfo(skb);
|
|
|
|
if (!skb_zcopy_managed(skb))
|
|
__skb_frag_unref(&shinfo->frags[f], skb->pp_recycle);
|
|
}
|
|
|
|
#endif /* _LINUX_SKBUFF_REF_H */
|