netgpu pages will always have a refcount of at least one (held by the netgpu module). This logic and the codepath obviously needs work, but suffices for a proof-of-concept.
Signed-off-by: Jonathan Lemon <jonathan.le...@gmail.com> --- net/core/skbuff.c | 27 +++++++++++++++++++++++++-- 1 file changed, 25 insertions(+), 2 deletions(-) diff --git a/net/core/skbuff.c b/net/core/skbuff.c index 2a391042be53..2b4176cab578 100644 --- a/net/core/skbuff.c +++ b/net/core/skbuff.c @@ -69,6 +69,7 @@ #include <net/xfrm.h> #include <net/mpls.h> #include <net/mptcp.h> +#include <net/netgpu.h> #include <linux/uaccess.h> #include <trace/events/skb.h> @@ -590,6 +591,24 @@ static void skb_free_head(struct sk_buff *skb) kfree(head); } +static void skb_netgpu_unref(struct skb_shared_info *shinfo) +{ + struct page *page; + int count; + int i; + + /* pages attached for skbs for TX shouldn't come here, since + * the skb is not marked as "zc_netgpu". (only RX skbs have this). + * dummy page does come here, but always has elevated refc. + */ + for (i = 0; i < shinfo->nr_frags; i++) { + page = skb_frag_page(&shinfo->frags[i]); + count = page_ref_dec_return(page); + if (count <= 2) + __netgpu_put_page(g_ctx, page, false); + } +} + static void skb_release_data(struct sk_buff *skb) { struct skb_shared_info *shinfo = skb_shinfo(skb); @@ -600,8 +619,12 @@ static void skb_release_data(struct sk_buff *skb) &shinfo->dataref)) return; - for (i = 0; i < shinfo->nr_frags; i++) - __skb_frag_unref(&shinfo->frags[i]); + if (skb->zc_netgpu && shinfo->nr_frags) { + skb_netgpu_unref(shinfo); + } else { + for (i = 0; i < shinfo->nr_frags; i++) + __skb_frag_unref(&shinfo->frags[i]); + } if (shinfo->frag_list) kfree_skb_list(shinfo->frag_list); -- 2.24.1