Skip to content

Commit e3b16f5

Browse files
committed
linuxkpi: Add folio and folio_batch APIs
They are used by the i915 DRM driver in Linux 6.6 (although this change was only backported with Linux 6.7 DRM drivers). `struct folio` simply wraps `struct page` for now. `struct folio_batch` is the same as `struct pagevec` but it works with `struct folio` instead of `struct page` directly. Reviewed by: bz, kib, markj Sponsored by: The FreeBSD Foundation Differential Revision: https://reviews.freebsd.org/D48743
1 parent c808981 commit e3b16f5

File tree

13 files changed

+248
-4
lines changed

13 files changed

+248
-4
lines changed

sys/compat/linuxkpi/common/include/linux/gfp.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -134,6 +134,8 @@ dev_alloc_pages(unsigned int order)
134134
return (linux_alloc_pages(GFP_ATOMIC, order));
135135
}
136136

137+
struct folio *folio_alloc(gfp_t gfp, unsigned int order);
138+
137139
/*
138140
* Page management for mapped pages:
139141
*/

sys/compat/linuxkpi/common/include/linux/mm.h

Lines changed: 62 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -161,6 +161,14 @@ virt_to_head_page(const void *p)
161161
return (virt_to_page(p));
162162
}
163163

164+
static inline struct folio *
165+
virt_to_folio(const void *p)
166+
{
167+
struct page *page = virt_to_page(p);
168+
169+
return (page_folio(page));
170+
}
171+
164172
/*
165173
* Compute log2 of the power of two rounded up count of pages
166174
* needed for size bytes.
@@ -282,8 +290,30 @@ put_page(struct page *page)
282290
__free_page(page);
283291
}
284292

285-
void linux_release_pages(struct page **pages, int nr);
286-
#define release_pages(pages, nr) linux_release_pages((pages), (nr))
293+
static inline void
294+
folio_get(struct folio *folio)
295+
{
296+
get_page(&folio->page);
297+
}
298+
299+
static inline void
300+
folio_put(struct folio *folio)
301+
{
302+
put_page(&folio->page);
303+
}
304+
305+
/*
306+
* Linux uses the following "transparent" union so that `release_pages()`
307+
* accepts both a list of `struct page` or a list of `struct folio`. This
308+
* relies on the fact that a `struct folio` can be cast to a `struct page`.
309+
*/
310+
typedef union {
311+
struct page **pages;
312+
struct folio **folios;
313+
} release_pages_arg __attribute__ ((__transparent_union__));
314+
315+
void linux_release_pages(release_pages_arg arg, int nr);
316+
#define release_pages(arg, nr) linux_release_pages((arg), (nr))
287317

288318
extern long
289319
lkpi_get_user_pages(unsigned long start, unsigned long nr_pages,
@@ -416,4 +446,34 @@ want_init_on_free(void)
416446
return (false);
417447
}
418448

449+
static inline unsigned long
450+
folio_pfn(struct folio *folio)
451+
{
452+
return (page_to_pfn(&folio->page));
453+
}
454+
455+
static inline long
456+
folio_nr_pages(struct folio *folio)
457+
{
458+
return (1);
459+
}
460+
461+
static inline size_t
462+
folio_size(struct folio *folio)
463+
{
464+
return (PAGE_SIZE);
465+
}
466+
467+
static inline void
468+
folio_mark_dirty(struct folio *folio)
469+
{
470+
set_page_dirty(&folio->page);
471+
}
472+
473+
static inline void *
474+
folio_address(const struct folio *folio)
475+
{
476+
return (page_address(&folio->page));
477+
}
478+
419479
#endif /* _LINUXKPI_LINUX_MM_H_ */

sys/compat/linuxkpi/common/include/linux/mm_types.h

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -79,4 +79,15 @@ mmgrab(struct mm_struct *mm)
7979
extern struct mm_struct *linux_get_task_mm(struct task_struct *);
8080
#define get_task_mm(task) linux_get_task_mm(task)
8181

82+
struct folio {
83+
/*
84+
* The page member must be at the beginning because `page_folio(p)`
85+
* casts from a `struct page` to a `struct folio`.
86+
*
87+
* `release_pages()` also relies on this to be able to accept either a
88+
* list of `struct page` or a list of `struct folio`.
89+
*/
90+
struct page page;
91+
};
92+
8293
#endif /* _LINUXKPI_LINUX_MM_TYPES_H_ */

sys/compat/linuxkpi/common/include/linux/page-flags.h

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,13 @@
2929
#ifndef _LINUXKPI_LINUX_PAGEFLAGS_H_
3030
#define _LINUXKPI_LINUX_PAGEFLAGS_H_
3131

32+
#include <linux/mm_types.h>
33+
3234
#define PageHighMem(p) (0)
3335

36+
#define page_folio(p) \
37+
(_Generic((p), \
38+
const struct page *: (const struct folio *)(p), \
39+
struct page *: (struct folio *)(p)))
40+
3441
#endif /* _LINUXKPI_LINUX_PAGEFLAGS_H_ */

sys/compat/linuxkpi/common/include/linux/pagemap.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -33,6 +33,8 @@
3333
#include <linux/highmem.h>
3434
#include <linux/vmalloc.h>
3535

36+
struct folio_batch;
37+
3638
#define invalidate_mapping_pages(...) \
3739
linux_invalidate_mapping_pages(__VA_ARGS__)
3840

sys/compat/linuxkpi/common/include/linux/pagevec.h

Lines changed: 68 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -66,4 +66,72 @@ check_move_unevictable_pages(struct pagevec *pvec)
6666
{
6767
}
6868

69+
/*
70+
* struct folio
71+
*
72+
* On Linux, `struct folio` replaces `struct page`. To manage a list of folios,
73+
* there is `struct folio_batch` on top of this, which replaces `struct
74+
* pagevec` above.
75+
*
76+
* Here is the original description when `struct folio` was added to the Linux
77+
* kernel:
78+
* "A struct folio is a new abstraction to replace the venerable struct page.
79+
* A function which takes a struct folio argument declares that it will
80+
* operate on the entire (possibly compound) page, not just PAGE_SIZE bytes.
81+
* In return, the caller guarantees that the pointer it is passing does not
82+
* point to a tail page. No change to generated code."
83+
*/
84+
85+
struct folio;
86+
87+
struct folio_batch {
88+
uint8_t nr;
89+
struct folio *folios[PAGEVEC_SIZE];
90+
};
91+
92+
static inline void
93+
folio_batch_init(struct folio_batch *fbatch)
94+
{
95+
fbatch->nr = 0;
96+
}
97+
98+
static inline void
99+
folio_batch_reinit(struct folio_batch *fbatch)
100+
{
101+
fbatch->nr = 0;
102+
}
103+
104+
static inline unsigned int
105+
folio_batch_count(struct folio_batch *fbatch)
106+
{
107+
return (fbatch->nr);
108+
}
109+
110+
static inline unsigned int
111+
folio_batch_space(struct folio_batch *fbatch)
112+
{
113+
return (PAGEVEC_SIZE - fbatch->nr);
114+
}
115+
116+
static inline unsigned int
117+
folio_batch_add(struct folio_batch *fbatch, struct folio *folio)
118+
{
119+
KASSERT(
120+
fbatch->nr < PAGEVEC_SIZE,
121+
("struct folio_batch %p is full", fbatch));
122+
123+
fbatch->folios[fbatch->nr++] = folio;
124+
125+
return (folio_batch_space(fbatch));
126+
}
127+
128+
void __folio_batch_release(struct folio_batch *fbatch);
129+
130+
static inline void
131+
folio_batch_release(struct folio_batch *fbatch)
132+
{
133+
if (folio_batch_count(fbatch))
134+
__folio_batch_release(fbatch);
135+
}
136+
69137
#endif /* _LINUXKPI_LINUX_PAGEVEC_H_ */

sys/compat/linuxkpi/common/include/linux/scatterlist.h

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -674,4 +674,11 @@ sg_pcopy_to_buffer(struct scatterlist *sgl, unsigned int nents,
674674
return (total);
675675
}
676676

677+
static inline void
678+
sg_set_folio(struct scatterlist *sg, struct folio *folio, size_t len,
679+
size_t offset)
680+
{
681+
sg_set_page(sg, &folio->page, len, offset);
682+
}
683+
677684
#endif /* _LINUXKPI_LINUX_SCATTERLIST_H_ */

sys/compat/linuxkpi/common/include/linux/shmem_fs.h

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -54,4 +54,14 @@ void linux_shmem_truncate_range(vm_object_t obj, loff_t lstart,
5454
#define shmem_truncate_range(...) \
5555
linux_shmem_truncate_range(__VA_ARGS__)
5656

57+
static inline struct folio *
58+
shmem_read_folio_gfp(vm_object_t obj, int pindex, gfp_t gfp)
59+
{
60+
struct page *page;
61+
62+
page = shmem_read_mapping_page_gfp(obj, pindex, gfp);
63+
64+
return (page_folio(page));
65+
}
66+
5767
#endif /* _LINUXKPI_LINUX_SHMEM_FS_H_ */

sys/compat/linuxkpi/common/include/linux/swap.h

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -37,6 +37,9 @@
3737
#include <vm/swap_pager.h>
3838
#include <vm/vm_pageout.h>
3939

40+
#include <linux/pagemap.h>
41+
#include <linux/page-flags.h>
42+
4043
static inline long
4144
get_nr_swap_pages(void)
4245
{
@@ -54,4 +57,15 @@ current_is_kswapd(void)
5457
return (curproc == pageproc);
5558
}
5659

60+
static inline void
61+
folio_mark_accessed(struct folio *folio)
62+
{
63+
mark_page_accessed(&folio->page);
64+
}
65+
66+
static inline void
67+
check_move_unevictable_folios(struct folio_batch *fbatch)
68+
{
69+
}
70+
5771
#endif
Lines changed: 58 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,58 @@
1+
/*-
2+
* Copyright (c) 2024-2025 The FreeBSD Foundation
3+
* Copyright (c) 2024-2025 Jean-Sébastien Pédron
4+
*
5+
* This software was developed by Jean-Sébastien Pédron under sponsorship
6+
* from the FreeBSD Foundation.
7+
*
8+
* Redistribution and use in source and binary forms, with or without
9+
* modification, are permitted provided that the following conditions
10+
* are met:
11+
* 1. Redistributions of source code must retain the above copyright
12+
* notice, this list of conditions and the following disclaimer.
13+
* 2. Redistributions in binary form must reproduce the above copyright
14+
* notice, this list of conditions and the following disclaimer in the
15+
* documentation and/or other materials provided with the distribution.
16+
*
17+
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
18+
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
19+
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
20+
* ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
21+
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
22+
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
23+
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
24+
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
25+
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
26+
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
27+
* SUCH DAMAGE.
28+
*/
29+
30+
#include <linux/gfp.h>
31+
#include <linux/mm.h>
32+
#include <linux/mm_types.h>
33+
#include <linux/page.h>
34+
#include <linux/pagevec.h>
35+
36+
struct folio *
37+
folio_alloc(gfp_t gfp, unsigned int order)
38+
{
39+
struct page *page;
40+
struct folio *folio;
41+
42+
/*
43+
* Allocated pages are wired already. There is no need to increase a
44+
* refcount here.
45+
*/
46+
page = alloc_pages(gfp | __GFP_COMP, order);
47+
folio = (struct folio *)page;
48+
49+
return (folio);
50+
}
51+
52+
void
53+
__folio_batch_release(struct folio_batch *fbatch)
54+
{
55+
release_pages(fbatch->folios, folio_batch_count(fbatch));
56+
57+
folio_batch_reinit(fbatch);
58+
}

0 commit comments

Comments
 (0)