linux-mm.kvack.org archive mirror
 help / color / mirror / Atom feed
From: Yunsheng Lin <linyunsheng@huawei.com>
To: <davem@davemloft.net>, <kuba@kernel.org>, <pabeni@redhat.com>
Cc: <netdev@vger.kernel.org>, <linux-kernel@vger.kernel.org>,
	Yunsheng Lin <linyunsheng@huawei.com>,
	Alexander Duyck <alexander.duyck@gmail.com>,
	Andrew Morton <akpm@linux-foundation.org>,
	Linux-MM <linux-mm@kvack.org>, Jonathan Corbet <corbet@lwn.net>,
	<linux-doc@vger.kernel.org>
Subject: [PATCH RFC 06/10] mm: page_frag: introduce alloc_refill prepare & commit API
Date: Mon, 28 Oct 2024 19:58:46 +0800	[thread overview]
Message-ID: <20241028115850.3409893-7-linyunsheng@huawei.com> (raw)
In-Reply-To: <20241028115850.3409893-1-linyunsheng@huawei.com>

Currently alloc related API returns virtual address of the
allocated fragment and refill related API returns page info
of the allocated fragment through 'struct page_frag'.

There are use cases that need both the virtual address and
page info of the allocated fragment. Introduce alloc_refill
API for those use cases.

CC: Alexander Duyck <alexander.duyck@gmail.com>
CC: Andrew Morton <akpm@linux-foundation.org>
CC: Linux-MM <linux-mm@kvack.org>
Signed-off-by: Yunsheng Lin <linyunsheng@huawei.com>
---
 Documentation/mm/page_frags.rst | 45 +++++++++++++++++++++
 include/linux/page_frag_cache.h | 71 +++++++++++++++++++++++++++++++++
 2 files changed, 116 insertions(+)

diff --git a/Documentation/mm/page_frags.rst b/Documentation/mm/page_frags.rst
index 4cfdbe7db55a..dcfceee3b923 100644
--- a/Documentation/mm/page_frags.rst
+++ b/Documentation/mm/page_frags.rst
@@ -111,6 +111,9 @@ page is aligned according to the 'align/alignment' parameter. Note the size of
 the allocated fragment is not aligned, the caller needs to provide an aligned
 fragsz if there is an alignment requirement for the size of the fragment.
 
+Depending on different use cases, callers expecting to deal with va, or both va
+and page may call alloc or alloc_refill API accordingly.
+
 There is a use case that needs minimum memory in order for forward progress, but
 more performant if more memory is available. By using the prepare and commit
 related API, the caller calls prepare API to requests the minimum memory it
@@ -123,6 +126,9 @@ uses, or not do so if deciding to not use any memory.
 		 __page_frag_alloc_align page_frag_alloc_align page_frag_alloc
 		 page_frag_alloc_abort __page_frag_refill_prepare_align
 		 page_frag_refill_prepare_align page_frag_refill_prepare
+		 __page_frag_alloc_refill_prepare_align
+		 page_frag_alloc_refill_prepare_align
+		 page_frag_alloc_refill_prepare
 
 .. kernel-doc:: mm/page_frag_cache.c
    :identifiers: page_frag_cache_drain page_frag_free page_frag_alloc_abort_ref
@@ -193,3 +199,42 @@ Refill Preparation & committing API
         skb_fill_page_desc(skb, i, pfrag->page, pfrag->offset, copy);
         page_frag_refill_commit(nc, pfrag, copy);
     }
+
+
+Alloc_Refill Preparation & committing API
+-----------------------------------------
+
+.. code-block:: c
+
+    struct page_frag page_frag, *pfrag;
+    bool merge = true;
+    void *va;
+
+    pfrag = &page_frag;
+    va = page_frag_alloc_refill_prepare(nc, 32U, pfrag, GFP_KERNEL);
+    if (!va)
+        goto wait_for_space;
+
+    copy = min_t(unsigned int, copy, pfrag->size);
+    if (!skb_can_coalesce(skb, i, pfrag->page, pfrag->offset)) {
+        if (i >= max_skb_frags)
+            goto new_segment;
+
+        merge = false;
+    }
+
+    copy = mem_schedule(copy);
+    if (!copy)
+        goto wait_for_space;
+
+    err = copy_from_iter_full_nocache(va, copy, iter);
+    if (err)
+        goto do_error;
+
+    if (merge) {
+        skb_frag_size_add(&skb_shinfo(skb)->frags[i - 1], copy);
+        page_frag_refill_commit_noref(nc, pfrag, copy);
+    } else {
+        skb_fill_page_desc(skb, i, pfrag->page, pfrag->offset, copy);
+        page_frag_refill_commit(nc, pfrag, copy);
+    }
diff --git a/include/linux/page_frag_cache.h b/include/linux/page_frag_cache.h
index 1e699334646a..329390afbe78 100644
--- a/include/linux/page_frag_cache.h
+++ b/include/linux/page_frag_cache.h
@@ -211,6 +211,77 @@ static inline bool page_frag_refill_prepare(struct page_frag_cache *nc,
 						~0u);
 }
 
+/**
+ * __page_frag_alloc_refill_prepare_align() - Prepare allocating a fragment and
+ * refilling a page_frag with aligning requirement.
+ * @nc: page_frag cache from which to allocate and refill
+ * @fragsz: the requested fragment size
+ * @pfrag: the page_frag to be refilled.
+ * @gfp_mask: the allocation gfp to use when cache need to be refilled
+ * @align_mask: the requested aligning requirement for the fragment.
+ *
+ * Prepare allocating a fragment and refilling a page_frag from page_frag cache.
+ *
+ * Return:
+ * virtual address of the page fragment, otherwise return NULL.
+ */
+static inline void
+*__page_frag_alloc_refill_prepare_align(struct page_frag_cache *nc,
+					unsigned int fragsz,
+					struct page_frag *pfrag,
+					gfp_t gfp_mask, unsigned int align_mask)
+{
+	return __page_frag_cache_prepare(nc, fragsz, pfrag, gfp_mask, align_mask);
+}
+
+/**
+ * page_frag_alloc_refill_prepare_align() - Prepare allocating a fragment and
+ * refilling a page_frag with aligning requirement.
+ * @nc: page_frag cache from which to allocate and refill
+ * @fragsz: the requested fragment size
+ * @pfrag: the page_frag to be refilled.
+ * @gfp_mask: the allocation gfp to use when cache need to be refilled
+ * @align: the requested aligning requirement for the fragment.
+ *
+ * WARN_ON_ONCE() checking for @align before prepare allocating a fragment and
+ * refilling a page_frag from page_frag cache.
+ *
+ * Return:
+ * virtual address of the page fragment, otherwise return NULL.
+ */
+static inline void
+*page_frag_alloc_refill_prepare_align(struct page_frag_cache *nc,
+				      unsigned int fragsz,
+				      struct page_frag *pfrag, gfp_t gfp_mask,
+				      unsigned int align)
+{
+	WARN_ON_ONCE(!is_power_of_2(align));
+	return __page_frag_alloc_refill_prepare_align(nc, fragsz, pfrag,
+						      gfp_mask, -align);
+}
+
+/**
+ * page_frag_alloc_refill_prepare() - Prepare allocating a fragment and
+ * refilling a page_frag.
+ * @nc: page_frag cache from which to allocate and refill
+ * @fragsz: the requested fragment size
+ * @pfrag: the page_frag to be refilled.
+ * @gfp_mask: the allocation gfp to use when cache need to be refilled
+ *
+ * Prepare allocating a fragment and refilling a page_frag from page_frag cache.
+ *
+ * Return:
+ * virtual address of the page fragment, otherwise return NULL.
+ */
+static inline void *page_frag_alloc_refill_prepare(struct page_frag_cache *nc,
+						   unsigned int fragsz,
+						   struct page_frag *pfrag,
+						   gfp_t gfp_mask)
+{
+	return __page_frag_alloc_refill_prepare_align(nc, fragsz, pfrag,
+						      gfp_mask, ~0u);
+}
+
 /**
  * page_frag_refill_commit - Commit a prepare refilling.
  * @nc: page_frag cache from which to commit
-- 
2.33.0



  parent reply	other threads:[~2024-10-28 12:05 UTC|newest]

Thread overview: 17+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
     [not found] <20241028115850.3409893-1-linyunsheng@huawei.com>
2024-10-28 11:58 ` [PATCH RFC 01/10] mm: page_frag: some minor refactoring before adding new API Yunsheng Lin
2024-10-28 11:58 ` [PATCH RFC 02/10] net: rename skb_copy_to_page_nocache() helper Yunsheng Lin
2024-10-28 17:49   ` Alexander Duyck
2024-10-28 11:58 ` [PATCH RFC 03/10] mm: page_frag: update documentation for page_frag Yunsheng Lin
2024-10-28 11:58 ` [PATCH RFC 04/10] mm: page_frag: introduce page_frag_alloc_abort() related API Yunsheng Lin
2024-10-28 17:53   ` Alexander Duyck
2024-10-29  9:39     ` Yunsheng Lin
2024-10-28 11:58 ` [PATCH RFC 05/10] mm: page_frag: introduce refill prepare & commit API Yunsheng Lin
2024-10-28 11:58 ` Yunsheng Lin [this message]
2024-10-28 11:58 ` [PATCH RFC 07/10] mm: page_frag: introduce probe related API Yunsheng Lin
2024-10-28 11:58 ` [PATCH RFC 08/10] mm: page_frag: add testing for the newly added API Yunsheng Lin
2024-10-28 11:58 ` [PATCH RFC 09/10] net: replace page_frag with page_frag_cache Yunsheng Lin
2024-10-28 11:58 ` [PATCH RFC 10/10] mm: page_frag: add an entry in MAINTAINERS for page_frag Yunsheng Lin
2024-10-28 23:27   ` Jakub Kicinski
2024-10-29  9:40     ` Yunsheng Lin
2024-10-29 14:33       ` Jakub Kicinski
2024-10-30 11:32         ` Yunsheng Lin

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=20241028115850.3409893-7-linyunsheng@huawei.com \
    --to=linyunsheng@huawei.com \
    --cc=akpm@linux-foundation.org \
    --cc=alexander.duyck@gmail.com \
    --cc=corbet@lwn.net \
    --cc=davem@davemloft.net \
    --cc=kuba@kernel.org \
    --cc=linux-doc@vger.kernel.org \
    --cc=linux-kernel@vger.kernel.org \
    --cc=linux-mm@kvack.org \
    --cc=netdev@vger.kernel.org \
    --cc=pabeni@redhat.com \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox