From mboxrd@z Thu Jan 1 00:00:00 1970 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org Received: from kanga.kvack.org (kanga.kvack.org [205.233.56.17]) by smtp.lore.kernel.org (Postfix) with ESMTP id D9E68C10F1A for ; Thu, 9 May 2024 16:58:18 +0000 (UTC) Received: by kanga.kvack.org (Postfix) id 4DF636B0088; Thu, 9 May 2024 12:58:18 -0400 (EDT) Received: by kanga.kvack.org (Postfix, from userid 40) id 48F5E6B0089; Thu, 9 May 2024 12:58:18 -0400 (EDT) X-Delivered-To: int-list-linux-mm@kvack.org Received: by kanga.kvack.org (Postfix, from userid 63042) id 330376B008A; Thu, 9 May 2024 12:58:18 -0400 (EDT) X-Delivered-To: linux-mm@kvack.org Received: from relay.hostedemail.com (smtprelay0015.hostedemail.com [216.40.44.15]) by kanga.kvack.org (Postfix) with ESMTP id 0E7636B0088 for ; Thu, 9 May 2024 12:58:18 -0400 (EDT) Received: from smtpin15.hostedemail.com (a10.router.float.18 [10.200.18.1]) by unirelay02.hostedemail.com (Postfix) with ESMTP id B8A8812010C for ; Thu, 9 May 2024 16:58:17 +0000 (UTC) X-FDA: 82099465434.15.43054EB Received: from sin.source.kernel.org (sin.source.kernel.org [145.40.73.55]) by imf17.hostedemail.com (Postfix) with ESMTP id 5C8D940017 for ; Thu, 9 May 2024 16:58:14 +0000 (UTC) Authentication-Results: imf17.hostedemail.com; dkim=pass header.d=kernel.org header.s=k20201202 header.b=itWjunuv; dmarc=pass (policy=none) header.from=kernel.org; spf=pass (imf17.hostedemail.com: domain of martineau@kernel.org designates 145.40.73.55 as permitted sender) smtp.mailfrom=martineau@kernel.org ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=hostedemail.com; s=arc-20220608; t=1715273896; h=from:from:sender:reply-to:subject:subject:date:date: message-id:message-id:to:to:cc:cc:mime-version:mime-version: content-type:content-type:content-transfer-encoding: in-reply-to:in-reply-to:references:references:dkim-signature; bh=og2cj/zQDR1fLLZmjHA0UMoE0hzhmjdCanAqcwldgIA=; b=4gp5E1TKsuHZE8n7QdHdDMHysufXg7aUfvFumyw8hX1JVDh1BHYffdA53ZKEwnhEfRcA+q a/Xck907aqI329tKEGgppf6Fihny5iSSSrQ7p2y/wq3V6Z6KfrZ0lLrFtmJuEt6U5cIhiH DblgwZq/4m4sYLt29UcfCk3X7O8u81k= ARC-Authentication-Results: i=1; imf17.hostedemail.com; dkim=pass header.d=kernel.org header.s=k20201202 header.b=itWjunuv; dmarc=pass (policy=none) header.from=kernel.org; spf=pass (imf17.hostedemail.com: domain of martineau@kernel.org designates 145.40.73.55 as permitted sender) smtp.mailfrom=martineau@kernel.org ARC-Seal: i=1; s=arc-20220608; d=hostedemail.com; t=1715273896; a=rsa-sha256; cv=none; b=jmPGm86IJ87NrFlKXnSTF6KbE06Ytmlce8LJW7vzYBacbrlL2hyzuGvbAujO2MV+yIa5Gs +kqQ4rnjC+iERScemAshLfaU94oJgFxcRxyl3Aq6MFOBejX0ju4hoRC/6gaQ8PsfH9Iwzf lmag4hG7WDYcWjXA8qUtw5YI/Zw4yZw= Received: from smtp.kernel.org (transwarp.subspace.kernel.org [100.75.92.58]) by sin.source.kernel.org (Postfix) with ESMTP id 53B3DCE18F1; Thu, 9 May 2024 16:58:10 +0000 (UTC) Received: by smtp.kernel.org (Postfix) with ESMTPSA id 634FEC116B1; Thu, 9 May 2024 16:58:09 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=kernel.org; s=k20201202; t=1715273889; bh=Rv252xbtK7kqw+580zaOJQJK+pd6z69TPTUWEDC6nyM=; h=Date:From:To:cc:Subject:In-Reply-To:References:From; b=itWjunuvy+dTZ+EsBfr1IqpAG1KcaAzX0rJXlkbUu9lRhUc+WvAlHORJtkkUPZ3jZ S90VqQzlFYWiHkGkTDZvWrIwBsV9FTIVSgOYiFs8spI+0WGrbGoCNm6R9xLwDloGqX SPS97+jnlPPw/eJ8jSUdXZxd5vNU+dnYJEQQWWyl2Bj3hl6KVAm/zqt9y7X2Pa4TIK n64Vp5ws8SuWMDxoJpRo5G06pmzCeP7QotCHNxAFHmpMwO6E+VnZuFVqtxgnzcW7W6 FAAgWwwAorCP5U+5fdHhVmJzMVA3q8btwmLZEE/TkhfCfIcSGqxmPJWqxwgtOuP95D s80BrgVZnDjSw== Date: Thu, 9 May 2024 09:58:08 -0700 (PDT) From: Mat Martineau To: Yunsheng Lin cc: davem@davemloft.net, kuba@kernel.org, pabeni@redhat.com, netdev@vger.kernel.org, linux-kernel@vger.kernel.org, Alexander Duyck , Jonathan Corbet , Andrew Morton , linux-mm@kvack.org, linux-doc@vger.kernel.org Subject: Re: [PATCH net-next v3 12/13] mm: page_frag: update documentation for page_frag In-Reply-To: <20240508133408.54708-13-linyunsheng@huawei.com> Message-ID: <2dc46fd0-fe7a-436a-5238-ff6b3f69e1a8@kernel.org> References: <20240508133408.54708-1-linyunsheng@huawei.com> <20240508133408.54708-13-linyunsheng@huawei.com> MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8; format=flowed X-Rspamd-Server: rspam07 X-Rspamd-Queue-Id: 5C8D940017 X-Stat-Signature: e1zjueqs8axdrubpo46nutjijbea8m8s X-Rspam-User: X-HE-Tag: 1715273894-979004 X-HE-Meta: U2FsdGVkX18Ohme8blpxPUe8sXQnRj8bGjb+g7SdWP8YL8c8j4bVzXCnbuTobmXF+Lh1BMnXoMpetDK5xhWu7EFh9q7nWtaP4rp2SQVp4OXAEvwmEEDbpFWMSSaQdjW3GzNIBTq5x82n+vqaP50qOEAuYd/9+mYfHiMxOW7QgeNAavbbtLikKW5SEI7bV0wDDdtrCirdklKPWaZNjmmkeS0x5+2hH3PjIU5wL3E7wDooQ58l3U9UxO9+GNXClGioamWBtD06rAl5GFLRdua14pF6uBf0xPx0zor3ffJYq5vntrJhIj2Ti/S+dogIFIRnFlUA76BWXCOVKhGfKcwyk0BUMvkrYevd+36ZYhw21Uo9xz2ho0X+K6XEZex7wKZ+MTupTelvRt7O+OZmClsHKkcUPX+3slXIazZYw9UoX3HhGbZZmSEJIDx91MptTynSGC4DihTi+aLR+kWKXSJPK+ZIsxOF3fjlwoDKZGpAFghg0qvB/2Ly+Oy5EJFy78512/VLtqglU5+Ye5oOWeWDDQkg++VI1UtbQ8KhY+ianXRhBeHJBI3chyT2KoCSWdUIXqQ48Eq+bQiTcxhgHQBD92lb82toC4cLJcJqwddDh38pzFfUufp0drzwNugWwgVJZB6hzAuVvFqm18nmLPpKercbF6EGjXu+PZf6oNhyKU1vWCghv+eUcItkwW29i6B2fJ7h3LQc3eUsTkz61Xgcy9PkSs7ZbbwS+wrpX0LCOazIvnn+GqtZ7ANODsWkAT3DmbsMFmtfy40tuprGNX6bkQcSKpjymmLZp7OMztOeRHSdbtrROPQTaQstR7F2ub90NaJgCf6fCpsGSd1Zasn1WlfrbdFz9Fw4y/PguKpfLNhgX9B7ksg7FAlhmtxk1LzQbgfChi7q9hslw7OiOHphmBeYWEvEv2uIFGBZCA+osWGCKFxeSJDgBucOVUV55rnhqL0ufgqG2S7+RGLwKCe ahxEjbwY 7SyYkyghkAEe/UmoUUFBoXx15CoT0AiB4CuYZlhInI8KtzAau/D/DMeo7xfrmVN2aHBTyUotfnyhe0z1WmbefJqZj3AxS+gBiogfMXbKl3NKJwS1EeHB6bJ+/RyPhy3tJDG7nA54M/ZJr4O73yQTO1ueDkIeDWtph+qoccpXLKZJmWguCW+Fo90JetDlE1h2YWLbkbyYXYx2qa75G+adqg2NrcftP1Lr9vnCkeniZSudrNY2Zhhf5Z9YUZeh6/QD8fswm61VEnAhsOGys2Ga+TnzG6wJe8t8WHFcPn+8CJb/ZHbWRfoegxAv/1XLZDJkURO2q+39aOxraTj60jsYfVvDh7i2Ku4v+E3FN X-Bogosity: Ham, tests=bogofilter, spamicity=0.000000, version=1.2.4 Sender: owner-linux-mm@kvack.org Precedence: bulk X-Loop: owner-majordomo@kvack.org List-ID: List-Subscribe: List-Unsubscribe: On Wed, 8 May 2024, Yunsheng Lin wrote: > Update documentation about design, implementation and API usages > for page_frag. > > CC: Alexander Duyck > Signed-off-by: Yunsheng Lin > --- > Documentation/mm/page_frags.rst | 156 +++++++++++++++++++++++++++++++- > include/linux/page_frag_cache.h | 96 ++++++++++++++++++++ > mm/page_frag_cache.c | 65 ++++++++++++- > 3 files changed, 314 insertions(+), 3 deletions(-) > > diff --git a/Documentation/mm/page_frags.rst b/Documentation/mm/page_frags.rst > index 503ca6cdb804..9c25c0fd81f0 100644 > --- a/Documentation/mm/page_frags.rst > +++ b/Documentation/mm/page_frags.rst > @@ -1,3 +1,5 @@ > +.. SPDX-License-Identifier: GPL-2.0 > + > ============== > Page fragments > ============== > @@ -40,4 +42,156 @@ page via a single call. The advantage to doing this is that it allows for > cleaning up the multiple references that were added to a page in order to > avoid calling get_page per allocation. > > -Alexander Duyck, Nov 29, 2016. > + > +Architecture overview > +===================== > + > +.. code-block:: none > + > + +----------------------+ > + | page_frag API caller | > + +----------------------+ > + ^ > + | > + | > + | > + v > + +------------------------------------------------+ > + | request page fragment | > + +------------------------------------------------+ > + ^ ^ ^ > + | | Cache not enough | > + | Cache empty v | > + | +-----------------+ | > + | | drain old cache | | > + | +-----------------+ | > + | ^ | > + | | | > + v v | > + +----------------------------------+ | > + | refill cache with order 3 page | | > + +----------------------------------+ | > + ^ ^ | > + | | | > + | | Refill failed | > + | | | Cache is enough > + | | | > + | v | > + | +----------------------------------+ | > + | | refill cache with order 0 page | | > + | +----------------------------------+ | > + | ^ | > + | Refill succeed | | > + | | Refill succeed | > + | | | > + v v v > + +------------------------------------------------+ > + | allocate fragment from cache | > + +------------------------------------------------+ > + > +API interface > +============= > +As the design and implementation of page_frag API implies, the allocation side > +does not allow concurrent calling. Instead it is assumed that the caller must > +ensure there is not concurrent alloc calling to the same page_frag_cache > +instance by using its own lock or rely on some lockless guarantee like NAPI > +softirq. > + > +Depending on different aligning requirement, the page_frag API caller may call > +page_frag_alloc*_align*() to ensure the returned virtual address or offset of > +the page is aligned according to the 'align/alignment' parameter. Note the size > +of the allocated fragment is not aligned, the caller need to provide a aligned > +fragsz if there is a alignment requirement for the size of the fragment. > + > +Depending on different use cases, callers expecting to deal with va, page or > +both va and page for them may call page_frag_alloc_va*, page_frag_alloc_pg*, > +or page_frag_alloc* API accordingly. > + > +There is also a use case that need minimum memory in order for forward > +progressing, but more performant if more memory is available. Using > +page_frag_alloc_prepare() and page_frag_alloc_commit() related API, the caller > +requests the minimum memory it need and the prepare API will return the maximum > +size of the fragment returned, the caller needs to either call the commit API to > +report how much memory it actually uses, or not do so if deciding to not use any > +memory. > + > +.. kernel-doc:: include/linux/page_frag_cache.h > + :identifiers: page_frag_cache_init page_frag_cache_is_pfmemalloc > + page_frag_cache_page_offset page_frag_alloc_va > + page_frag_alloc_va_align page_frag_alloc_va_prepare_align > + page_frag_alloc_probe page_frag_alloc_commit > + page_frag_alloc_commit_noref > + > +.. kernel-doc:: mm/page_frag_cache.c > + :identifiers: __page_frag_alloc_va_align page_frag_alloc_va_prepare > + page_frag_alloc_pg_prepare page_frag_alloc_prepare > + page_frag_cache_drain page_frag_free_va > + > +Coding examples > +=============== > + > +Init & Drain API > +---------------- > + > +.. code-block:: c > + > + page_frag_cache_init(pfrag); > + ... > + page_frag_cache_drain(pfrag); > + > + > +Alloc & Free API > +---------------- > + > +.. code-block:: c > + > + void *va; > + > + va = page_frag_alloc_va_align(pfrag, size, gfp, align); > + if (!va) > + goto do_error; > + > + err = do_something(va, size); > + if (err) { > + page_frag_free_va(va); > + goto do_error; > + } > + > +Prepare & Commit API > +-------------------- > + > +.. code-block:: c > + > + unsigned int offset, size; > + bool merge = true; > + struct page *page; > + void *va; > + > + size = 32U; > + page = page_frag_alloc_prepare(pfrag, &offset, &size, &va); > + if (!page) > + goto wait_for_space; > + > + copy = min_t(int, copy, size); > + if (!skb_can_coalesce(skb, i, page, 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_alloc_commit_noref(pfrag, offset, copy); > + } else { > + skb_fill_page_desc(skb, i, page, offset, copy); > + page_frag_alloc_commit(pfrag, offset, copy); > + } > diff --git a/include/linux/page_frag_cache.h b/include/linux/page_frag_cache.h > index 30893638155b..8925397262a1 100644 > --- a/include/linux/page_frag_cache.h > +++ b/include/linux/page_frag_cache.h > @@ -61,11 +61,28 @@ struct page_frag_cache { > #endif > }; > > +/** > + * page_frag_cache_init() - Init page_frag cache. > + * @nc: page_frag cache from which to init > + * > + * Inline helper to init the page_frag cache. > + */ > static inline void page_frag_cache_init(struct page_frag_cache *nc) > { > memset(nc, 0, sizeof(*nc)); > } > > +/** > + * page_frag_cache_is_pfmemalloc() - Check for pfmemalloc. > + * @nc: page_frag cache from which to check > + * > + * Used to check if the current page in page_frag cache is pfmemalloc'ed. > + * It has the same calling context expection as the alloc API. > + * > + * Return: > + * Return true if the current page in page_frag cache is pfmemalloc'ed, > + * otherwise return false. > + */ > static inline bool page_frag_cache_is_pfmemalloc(struct page_frag_cache *nc) > { > return encoded_page_pfmemalloc(nc->encoded_va); > @@ -92,6 +109,19 @@ void *__page_frag_alloc_va_align(struct page_frag_cache *nc, > unsigned int fragsz, gfp_t gfp_mask, > unsigned int align_mask); > > +/** > + * page_frag_alloc_va_align() - Alloc a page fragment with aligning requirement. > + * @nc: page_frag cache from which to allocate > + * @fragsz: the requested fragment size > + * @gfp_mask: the allocation gfp to use when cache need to be refilled > + * @align: the requested aligning requirement for 'va' > + * > + * WARN_ON_ONCE() checking for 'align' before allocing a page fragment from > + * page_frag cache with aligning requirement for 'va'. > + * > + * Return: > + * Return va of the page fragment, otherwise return NULL. > + */ > static inline void *page_frag_alloc_va_align(struct page_frag_cache *nc, > unsigned int fragsz, > gfp_t gfp_mask, unsigned int align) > @@ -100,11 +130,32 @@ static inline void *page_frag_alloc_va_align(struct page_frag_cache *nc, > return __page_frag_alloc_va_align(nc, fragsz, gfp_mask, -align); > } > > +/** > + * page_frag_cache_page_offset() - Return the current page fragment's offset. > + * @nc: page_frag cache from which to check > + * > + * The API is only used in net/sched/em_meta.c for historical reason, do not use > + * it for new caller unless there is a strong reason. > + * > + * Return: > + * Return the offset of the current page fragment in the page_frag cache. > + */ > static inline unsigned int page_frag_cache_page_offset(const struct page_frag_cache *nc) > { > return __page_frag_cache_page_offset(nc->encoded_va, nc->remaining); > } > > +/** > + * page_frag_alloc_va() - Alloc a page fragment. > + * @nc: page_frag cache from which to allocate > + * @fragsz: the requested fragment size > + * @gfp_mask: the allocation gfp to use when cache need to be refilled > + * > + * Get a page fragment from page_frag cache. > + * > + * Return: > + * Return va of the page fragment, otherwise return NULL. > + */ > static inline void *page_frag_alloc_va(struct page_frag_cache *nc, > unsigned int fragsz, gfp_t gfp_mask) > { > @@ -114,6 +165,21 @@ static inline void *page_frag_alloc_va(struct page_frag_cache *nc, > void *page_frag_alloc_va_prepare(struct page_frag_cache *nc, unsigned int *fragsz, > gfp_t gfp); > > +/** > + * page_frag_alloc_va_prepare_align() - Prepare allocing a page fragment with > + * aligning requirement. > + * @nc: page_frag cache from which to prepare > + * @fragsz: in as the requested size, out as the available size > + * @gfp: the allocation gfp to use when cache need to be refilled > + * @align: the requested aligning requirement for 'va' > + * > + * WARN_ON_ONCE() checking for 'align' before preparing an aligned page fragment > + * with minimum size of ???fragsz???, 'fragsz' is also used to report the maximum > + * size of the page fragment the caller can use. > + * > + * Return: > + * Return va of the page fragment, otherwise return NULL. > + */ > static inline void *page_frag_alloc_va_prepare_align(struct page_frag_cache *nc, > unsigned int *fragsz, > gfp_t gfp, > @@ -148,6 +214,19 @@ static inline struct encoded_va *__page_frag_alloc_probe(struct page_frag_cache > return encoded_va; > } > > +/** > + * page_frag_alloc_probe - Probe the avaiable page fragment. > + * @nc: page_frag cache from which to probe > + * @offset: out as the offset of the page fragment > + * @fragsz: in as the requested size, out as the available size Hi Yunsheng - fragsz is never used as an input in this function. I think it would be good to make the code consistent with this documentation by checking that *fragsz <= (nc)->remaining > + * @va: out as the virtual address of the returned page fragment > + * > + * Probe the current available memory to caller without doing cache refilling. > + * If the cache is empty, return NULL. Instead of this line, is it more accurate to say "if no space is available in the page_frag cache, return NULL" ? I also suggest adding some documentation here like: "If the requested space is available, up to fragsz bytes may be added to the fragment using page_frag_alloc_commit()". > + * > + * Return: > + * Return the page fragment, otherwise return NULL. > + */ > #define page_frag_alloc_probe(nc, offset, fragsz, va) \ > ({ \ > struct encoded_va *__encoded_va; \ > @@ -162,6 +241,13 @@ static inline struct encoded_va *__page_frag_alloc_probe(struct page_frag_cache > __page; \ > }) > > +/** > + * page_frag_alloc_commit - Commit allocing a page fragment. > + * @nc: page_frag cache from which to commit > + * @fragsz: size of the page fragment has been used > + * > + * Commit the alloc preparing by passing the actual used size. Rephrasing suggestion: "Commit the actual used size for the allocation that was either prepared or probed" Thanks, Mat > + */ > static inline void page_frag_alloc_commit(struct page_frag_cache *nc, > unsigned int fragsz) > { > @@ -170,6 +256,16 @@ static inline void page_frag_alloc_commit(struct page_frag_cache *nc, > nc->remaining -= fragsz; > } > > +/** > + * page_frag_alloc_commit_noref - Commit allocing a page fragment without taking > + * page refcount. > + * @nc: page_frag cache from which to commit > + * @fragsz: size of the page fragment has been used > + * > + * Commit the alloc preparing by passing the actual used size, but not taking > + * page refcount. Mostly used for fragmemt coaleasing case when the current > + * fragmemt can share the same refcount with previous fragmemt. > + */ > static inline void page_frag_alloc_commit_noref(struct page_frag_cache *nc, > unsigned int fragsz) > { > diff --git a/mm/page_frag_cache.c b/mm/page_frag_cache.c > index eb8bf59b26bb..85e23d5cbdcc 100644 > --- a/mm/page_frag_cache.c > +++ b/mm/page_frag_cache.c > @@ -89,6 +89,18 @@ static struct page *page_frag_cache_refill(struct page_frag_cache *nc, > return __page_frag_cache_refill(nc, gfp_mask); > } > > +/** > + * page_frag_alloc_va_prepare() - Prepare allocing a page fragment. > + * @nc: page_frag cache from which to prepare > + * @fragsz: in as the requested size, out as the available size > + * @gfp: the allocation gfp to use when cache need to be refilled > + * > + * Prepare a page fragment with minimum size of ???fragsz???, 'fragsz' is also used > + * to report the maximum size of the page fragment the caller can use. > + * > + * Return: > + * Return va of the page fragment, otherwise return NULL. > + */ > void *page_frag_alloc_va_prepare(struct page_frag_cache *nc, > unsigned int *fragsz, gfp_t gfp) > { > @@ -111,6 +123,19 @@ void *page_frag_alloc_va_prepare(struct page_frag_cache *nc, > } > EXPORT_SYMBOL(page_frag_alloc_va_prepare); > > +/** > + * page_frag_alloc_pg_prepare - Prepare allocing a page fragment. > + * @nc: page_frag cache from which to prepare > + * @offset: out as the offset of the page fragment > + * @fragsz: in as the requested size, out as the available size > + * @gfp: the allocation gfp to use when cache need to be refilled > + * > + * Prepare a page fragment with minimum size of ???fragsz???, 'fragsz' is also used > + * to report the maximum size of the page fragment the caller can use. > + * > + * Return: > + * Return the page fragment, otherwise return NULL. > + */ > struct page *page_frag_alloc_pg_prepare(struct page_frag_cache *nc, > unsigned int *offset, > unsigned int *fragsz, gfp_t gfp) > @@ -141,6 +166,21 @@ struct page *page_frag_alloc_pg_prepare(struct page_frag_cache *nc, > } > EXPORT_SYMBOL(page_frag_alloc_pg_prepare); > > +/** > + * page_frag_alloc_prepare - Prepare allocing a page fragment. > + * @nc: page_frag cache from which to prepare > + * @offset: out as the offset of the page fragment > + * @fragsz: in as the requested size, out as the available size > + * @va: out as the virtual address of the returned page fragment > + * @gfp: the allocation gfp to use when cache need to be refilled > + * > + * Prepare a page fragment with minimum size of ???fragsz???, 'fragsz' is also used > + * to report the maximum size of the page fragment. Return both 'page' and 'va' > + * of the fragment to the caller. > + * > + * Return: > + * Return the page fragment, otherwise return NULL. > + */ > struct page *page_frag_alloc_prepare(struct page_frag_cache *nc, > unsigned int *offset, > unsigned int *fragsz, > @@ -173,6 +213,10 @@ struct page *page_frag_alloc_prepare(struct page_frag_cache *nc, > } > EXPORT_SYMBOL(page_frag_alloc_prepare); > > +/** > + * page_frag_cache_drain - Drain the current page from page_frag cache. > + * @nc: page_frag cache from which to drain > + */ > void page_frag_cache_drain(struct page_frag_cache *nc) > { > if (!nc->encoded_va) > @@ -193,6 +237,19 @@ void __page_frag_cache_drain(struct page *page, unsigned int count) > } > EXPORT_SYMBOL(__page_frag_cache_drain); > > +/** > + * __page_frag_alloc_va_align() - Alloc a page fragment with aligning > + * requirement. > + * @nc: page_frag cache from which to allocate > + * @fragsz: the requested fragment size > + * @gfp_mask: the allocation gfp to use when cache need to be refilled > + * @align_mask: the requested aligning requirement for the 'va' > + * > + * Get a page fragment from page_frag cache with aligning requirement. > + * > + * Return: > + * Return va of the page fragment, otherwise return NULL. > + */ > void *__page_frag_alloc_va_align(struct page_frag_cache *nc, > unsigned int fragsz, gfp_t gfp_mask, > unsigned int align_mask) > @@ -263,8 +320,12 @@ void *__page_frag_alloc_va_align(struct page_frag_cache *nc, > } > EXPORT_SYMBOL(__page_frag_alloc_va_align); > > -/* > - * Frees a page fragment allocated out of either a compound or order 0 page. > +/** > + * page_frag_free_va - Free a page fragment. > + * @addr: va of page fragment to be freed > + * > + * Free a page fragment allocated out of either a compound or order 0 page by > + * virtual address. > */ > void page_frag_free_va(void *addr) > { > -- > 2.33.0 > > >