Skip to content

Commit 65941f1

Browse files
Yunsheng Linkuba-moo
authored andcommitted
mm: move the page fragment allocator from page_alloc into its own file
Inspired by [1], move the page fragment allocator from page_alloc into its own c file and header file, as we are about to make more change for it to replace another page_frag implementation in sock.c As this patchset is going to replace 'struct page_frag' with 'struct page_frag_cache' in sched.h, including page_frag_cache.h in sched.h has a compiler error caused by interdependence between mm_types.h and mm.h for asm-offsets.c, see [2]. So avoid the compiler error by moving 'struct page_frag_cache' to mm_types_task.h as suggested by Alexander, see [3]. 1. https://lore.kernel.org/all/[email protected]/ 2. https://lore.kernel.org/all/[email protected]/ 3. https://lore.kernel.org/all/CAKgT0UdH1yD=LSCXFJ=YM_aiA4OomD-2wXykO42bizaWMt_HOA@mail.gmail.com/ CC: David Howells <[email protected]> CC: Linux-MM <[email protected]> Signed-off-by: Yunsheng Lin <[email protected]> Acked-by: Andrew Morton <[email protected]> Reviewed-by: Alexander Duyck <[email protected]> Link: https://patch.msgid.link/[email protected] Signed-off-by: Jakub Kicinski <[email protected]>
1 parent 7fef0de commit 65941f1

File tree

9 files changed

+197
-177
lines changed

9 files changed

+197
-177
lines changed

include/linux/gfp.h

Lines changed: 0 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -371,28 +371,6 @@ __meminit void *alloc_pages_exact_nid_noprof(int nid, size_t size, gfp_t gfp_mas
371371
extern void __free_pages(struct page *page, unsigned int order);
372372
extern void free_pages(unsigned long addr, unsigned int order);
373373

374-
struct page_frag_cache;
375-
void page_frag_cache_drain(struct page_frag_cache *nc);
376-
extern void __page_frag_cache_drain(struct page *page, unsigned int count);
377-
void *__page_frag_alloc_align(struct page_frag_cache *nc, unsigned int fragsz,
378-
gfp_t gfp_mask, unsigned int align_mask);
379-
380-
static inline void *page_frag_alloc_align(struct page_frag_cache *nc,
381-
unsigned int fragsz, gfp_t gfp_mask,
382-
unsigned int align)
383-
{
384-
WARN_ON_ONCE(!is_power_of_2(align));
385-
return __page_frag_alloc_align(nc, fragsz, gfp_mask, -align);
386-
}
387-
388-
static inline void *page_frag_alloc(struct page_frag_cache *nc,
389-
unsigned int fragsz, gfp_t gfp_mask)
390-
{
391-
return __page_frag_alloc_align(nc, fragsz, gfp_mask, ~0u);
392-
}
393-
394-
extern void page_frag_free(void *addr);
395-
396374
#define __free_page(page) __free_pages((page), 0)
397375
#define free_page(addr) free_pages((addr), 0)
398376

include/linux/mm_types.h

Lines changed: 0 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -521,9 +521,6 @@ static_assert(sizeof(struct ptdesc) <= sizeof(struct page));
521521
*/
522522
#define STRUCT_PAGE_MAX_SHIFT (order_base_2(sizeof(struct page)))
523523

524-
#define PAGE_FRAG_CACHE_MAX_SIZE __ALIGN_MASK(32768, ~PAGE_MASK)
525-
#define PAGE_FRAG_CACHE_MAX_ORDER get_order(PAGE_FRAG_CACHE_MAX_SIZE)
526-
527524
/*
528525
* page_private can be used on tail pages. However, PagePrivate is only
529526
* checked by the VM on the head page. So page_private on the tail pages
@@ -542,21 +539,6 @@ static inline void *folio_get_private(struct folio *folio)
542539
return folio->private;
543540
}
544541

545-
struct page_frag_cache {
546-
void * va;
547-
#if (PAGE_SIZE < PAGE_FRAG_CACHE_MAX_SIZE)
548-
__u16 offset;
549-
__u16 size;
550-
#else
551-
__u32 offset;
552-
#endif
553-
/* we maintain a pagecount bias, so that we dont dirty cache line
554-
* containing page->_refcount every time we allocate a fragment.
555-
*/
556-
unsigned int pagecnt_bias;
557-
bool pfmemalloc;
558-
};
559-
560542
typedef unsigned long vm_flags_t;
561543

562544
/*

include/linux/mm_types_task.h

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@
88
* (These are defined separately to decouple sched.h from mm_types.h as much as possible.)
99
*/
1010

11+
#include <linux/align.h>
1112
#include <linux/types.h>
1213

1314
#include <asm/page.h>
@@ -43,6 +44,23 @@ struct page_frag {
4344
#endif
4445
};
4546

47+
#define PAGE_FRAG_CACHE_MAX_SIZE __ALIGN_MASK(32768, ~PAGE_MASK)
48+
#define PAGE_FRAG_CACHE_MAX_ORDER get_order(PAGE_FRAG_CACHE_MAX_SIZE)
49+
struct page_frag_cache {
50+
void *va;
51+
#if (PAGE_SIZE < PAGE_FRAG_CACHE_MAX_SIZE)
52+
__u16 offset;
53+
__u16 size;
54+
#else
55+
__u32 offset;
56+
#endif
57+
/* we maintain a pagecount bias, so that we dont dirty cache line
58+
* containing page->_refcount every time we allocate a fragment.
59+
*/
60+
unsigned int pagecnt_bias;
61+
bool pfmemalloc;
62+
};
63+
4664
/* Track pages that require TLB flushes */
4765
struct tlbflush_unmap_batch {
4866
#ifdef CONFIG_ARCH_WANT_BATCHED_UNMAP_TLB_FLUSH

include/linux/page_frag_cache.h

Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,31 @@
1+
/* SPDX-License-Identifier: GPL-2.0 */
2+
3+
#ifndef _LINUX_PAGE_FRAG_CACHE_H
4+
#define _LINUX_PAGE_FRAG_CACHE_H
5+
6+
#include <linux/log2.h>
7+
#include <linux/mm_types_task.h>
8+
#include <linux/types.h>
9+
10+
void page_frag_cache_drain(struct page_frag_cache *nc);
11+
void __page_frag_cache_drain(struct page *page, unsigned int count);
12+
void *__page_frag_alloc_align(struct page_frag_cache *nc, unsigned int fragsz,
13+
gfp_t gfp_mask, unsigned int align_mask);
14+
15+
static inline void *page_frag_alloc_align(struct page_frag_cache *nc,
16+
unsigned int fragsz, gfp_t gfp_mask,
17+
unsigned int align)
18+
{
19+
WARN_ON_ONCE(!is_power_of_2(align));
20+
return __page_frag_alloc_align(nc, fragsz, gfp_mask, -align);
21+
}
22+
23+
static inline void *page_frag_alloc(struct page_frag_cache *nc,
24+
unsigned int fragsz, gfp_t gfp_mask)
25+
{
26+
return __page_frag_alloc_align(nc, fragsz, gfp_mask, ~0u);
27+
}
28+
29+
void page_frag_free(void *addr);
30+
31+
#endif

include/linux/skbuff.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,7 @@
3131
#include <linux/in6.h>
3232
#include <linux/if_packet.h>
3333
#include <linux/llist.h>
34+
#include <linux/page_frag_cache.h>
3435
#include <net/flow.h>
3536
#if IS_ENABLED(CONFIG_NF_CONNTRACK)
3637
#include <linux/netfilter/nf_conntrack_common.h>

mm/Makefile

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -65,6 +65,7 @@ page-alloc-$(CONFIG_SHUFFLE_PAGE_ALLOCATOR) += shuffle.o
6565
memory-hotplug-$(CONFIG_MEMORY_HOTPLUG) += memory_hotplug.o
6666

6767
obj-y += page-alloc.o
68+
obj-y += page_frag_cache.o
6869
obj-y += init-mm.o
6970
obj-y += memblock.o
7071
obj-y += $(memory-hotplug-y)

mm/page_alloc.c

Lines changed: 0 additions & 136 deletions
Original file line numberDiff line numberDiff line change
@@ -4836,142 +4836,6 @@ void free_pages(unsigned long addr, unsigned int order)
48364836

48374837
EXPORT_SYMBOL(free_pages);
48384838

4839-
/*
4840-
* Page Fragment:
4841-
* An arbitrary-length arbitrary-offset area of memory which resides
4842-
* within a 0 or higher order page. Multiple fragments within that page
4843-
* are individually refcounted, in the page's reference counter.
4844-
*
4845-
* The page_frag functions below provide a simple allocation framework for
4846-
* page fragments. This is used by the network stack and network device
4847-
* drivers to provide a backing region of memory for use as either an
4848-
* sk_buff->head, or to be used in the "frags" portion of skb_shared_info.
4849-
*/
4850-
static struct page *__page_frag_cache_refill(struct page_frag_cache *nc,
4851-
gfp_t gfp_mask)
4852-
{
4853-
struct page *page = NULL;
4854-
gfp_t gfp = gfp_mask;
4855-
4856-
#if (PAGE_SIZE < PAGE_FRAG_CACHE_MAX_SIZE)
4857-
gfp_mask = (gfp_mask & ~__GFP_DIRECT_RECLAIM) | __GFP_COMP |
4858-
__GFP_NOWARN | __GFP_NORETRY | __GFP_NOMEMALLOC;
4859-
page = alloc_pages_node(NUMA_NO_NODE, gfp_mask,
4860-
PAGE_FRAG_CACHE_MAX_ORDER);
4861-
nc->size = page ? PAGE_FRAG_CACHE_MAX_SIZE : PAGE_SIZE;
4862-
#endif
4863-
if (unlikely(!page))
4864-
page = alloc_pages_node(NUMA_NO_NODE, gfp, 0);
4865-
4866-
nc->va = page ? page_address(page) : NULL;
4867-
4868-
return page;
4869-
}
4870-
4871-
void page_frag_cache_drain(struct page_frag_cache *nc)
4872-
{
4873-
if (!nc->va)
4874-
return;
4875-
4876-
__page_frag_cache_drain(virt_to_head_page(nc->va), nc->pagecnt_bias);
4877-
nc->va = NULL;
4878-
}
4879-
EXPORT_SYMBOL(page_frag_cache_drain);
4880-
4881-
void __page_frag_cache_drain(struct page *page, unsigned int count)
4882-
{
4883-
VM_BUG_ON_PAGE(page_ref_count(page) == 0, page);
4884-
4885-
if (page_ref_sub_and_test(page, count))
4886-
free_unref_page(page, compound_order(page));
4887-
}
4888-
EXPORT_SYMBOL(__page_frag_cache_drain);
4889-
4890-
void *__page_frag_alloc_align(struct page_frag_cache *nc,
4891-
unsigned int fragsz, gfp_t gfp_mask,
4892-
unsigned int align_mask)
4893-
{
4894-
unsigned int size = PAGE_SIZE;
4895-
struct page *page;
4896-
int offset;
4897-
4898-
if (unlikely(!nc->va)) {
4899-
refill:
4900-
page = __page_frag_cache_refill(nc, gfp_mask);
4901-
if (!page)
4902-
return NULL;
4903-
4904-
#if (PAGE_SIZE < PAGE_FRAG_CACHE_MAX_SIZE)
4905-
/* if size can vary use size else just use PAGE_SIZE */
4906-
size = nc->size;
4907-
#endif
4908-
/* Even if we own the page, we do not use atomic_set().
4909-
* This would break get_page_unless_zero() users.
4910-
*/
4911-
page_ref_add(page, PAGE_FRAG_CACHE_MAX_SIZE);
4912-
4913-
/* reset page count bias and offset to start of new frag */
4914-
nc->pfmemalloc = page_is_pfmemalloc(page);
4915-
nc->pagecnt_bias = PAGE_FRAG_CACHE_MAX_SIZE + 1;
4916-
nc->offset = size;
4917-
}
4918-
4919-
offset = nc->offset - fragsz;
4920-
if (unlikely(offset < 0)) {
4921-
page = virt_to_page(nc->va);
4922-
4923-
if (!page_ref_sub_and_test(page, nc->pagecnt_bias))
4924-
goto refill;
4925-
4926-
if (unlikely(nc->pfmemalloc)) {
4927-
free_unref_page(page, compound_order(page));
4928-
goto refill;
4929-
}
4930-
4931-
#if (PAGE_SIZE < PAGE_FRAG_CACHE_MAX_SIZE)
4932-
/* if size can vary use size else just use PAGE_SIZE */
4933-
size = nc->size;
4934-
#endif
4935-
/* OK, page count is 0, we can safely set it */
4936-
set_page_count(page, PAGE_FRAG_CACHE_MAX_SIZE + 1);
4937-
4938-
/* reset page count bias and offset to start of new frag */
4939-
nc->pagecnt_bias = PAGE_FRAG_CACHE_MAX_SIZE + 1;
4940-
offset = size - fragsz;
4941-
if (unlikely(offset < 0)) {
4942-
/*
4943-
* The caller is trying to allocate a fragment
4944-
* with fragsz > PAGE_SIZE but the cache isn't big
4945-
* enough to satisfy the request, this may
4946-
* happen in low memory conditions.
4947-
* We don't release the cache page because
4948-
* it could make memory pressure worse
4949-
* so we simply return NULL here.
4950-
*/
4951-
return NULL;
4952-
}
4953-
}
4954-
4955-
nc->pagecnt_bias--;
4956-
offset &= align_mask;
4957-
nc->offset = offset;
4958-
4959-
return nc->va + offset;
4960-
}
4961-
EXPORT_SYMBOL(__page_frag_alloc_align);
4962-
4963-
/*
4964-
* Frees a page fragment allocated out of either a compound or order 0 page.
4965-
*/
4966-
void page_frag_free(void *addr)
4967-
{
4968-
struct page *page = virt_to_head_page(addr);
4969-
4970-
if (unlikely(put_page_testzero(page)))
4971-
free_unref_page(page, compound_order(page));
4972-
}
4973-
EXPORT_SYMBOL(page_frag_free);
4974-
49754839
static void *make_alloc_exact(unsigned long addr, unsigned int order,
49764840
size_t size)
49774841
{

0 commit comments

Comments
 (0)