diff --git a/sys/compat/linuxkpi/common/include/linux/gfp.h b/sys/compat/linuxkpi/common/include/linux/gfp.h --- a/sys/compat/linuxkpi/common/include/linux/gfp.h +++ b/sys/compat/linuxkpi/common/include/linux/gfp.h @@ -134,6 +134,18 @@ return (linux_alloc_pages(GFP_ATOMIC, order)); } +static inline struct folio * +folio_alloc(gfp_t gfp, unsigned int order) +{ + struct page *page; + struct folio *folio; + + page = alloc_pages(gfp | __GFP_COMP, order); + folio = (struct folio *)page; + + return (folio); +} + /* * Page management for mapped pages: */ diff --git a/sys/compat/linuxkpi/common/include/linux/mm.h b/sys/compat/linuxkpi/common/include/linux/mm.h --- a/sys/compat/linuxkpi/common/include/linux/mm.h +++ b/sys/compat/linuxkpi/common/include/linux/mm.h @@ -161,6 +161,23 @@ return (virt_to_page(p)); } +static inline struct folio * +virt_to_folio(const void *p) +{ + struct page *page = virt_to_page(p); + + return page_folio(page); +} + +static inline void +folio_put(struct folio *folio) +{ + struct page *page; + + page = &folio->page; + __free_page(page); +} + /* * Compute log2 of the power of two rounded up count of pages * needed for size bytes. @@ -184,7 +201,7 @@ * * NOTE: This function only works for pages allocated by the kernel. */ -void *linux_page_address(struct page *); +void *linux_page_address(const struct page *); #define page_address(page) linux_page_address(page) static inline void * @@ -412,4 +429,34 @@ return (false); } +static inline unsigned long +folio_pfn(struct folio *folio) +{ + return page_to_pfn(&folio->page); +} + +static inline long +folio_nr_pages(struct folio *folio) +{ + return 1; +} + +static inline size_t +folio_size(struct folio *folio) +{ + return PAGE_SIZE; +} + +static inline void +folio_mark_dirty(struct folio *folio) +{ + set_page_dirty(&folio->page); +} + +static inline void * +folio_address(const struct folio *folio) +{ + return page_address(&folio->page); +} + #endif /* _LINUXKPI_LINUX_MM_H_ */ diff --git a/sys/compat/linuxkpi/common/include/linux/mm_types.h b/sys/compat/linuxkpi/common/include/linux/mm_types.h --- a/sys/compat/linuxkpi/common/include/linux/mm_types.h +++ b/sys/compat/linuxkpi/common/include/linux/mm_types.h @@ -79,4 +79,10 @@ extern struct mm_struct *linux_get_task_mm(struct task_struct *); #define get_task_mm(task) linux_get_task_mm(task) +struct folio { + /* The page member must be at the beginning because `page_folio(p)` + * casts from a struct page to a struct folio. */ + struct page page; +}; + #endif /* _LINUXKPI_LINUX_MM_TYPES_H_ */ diff --git a/sys/compat/linuxkpi/common/include/linux/page-flags.h b/sys/compat/linuxkpi/common/include/linux/page-flags.h --- a/sys/compat/linuxkpi/common/include/linux/page-flags.h +++ b/sys/compat/linuxkpi/common/include/linux/page-flags.h @@ -29,6 +29,13 @@ #ifndef _LINUXKPI_LINUX_PAGEFLAGS_H_ #define _LINUXKPI_LINUX_PAGEFLAGS_H_ +#include + #define PageHighMem(p) (0) +#define page_folio(p) \ + (_Generic((p), \ + const struct page *: (const struct folio *)(p), \ + struct page *: (struct folio *)(p))) + #endif /* _LINUXKPI_LINUX_PAGEFLAGS_H_ */ diff --git a/sys/compat/linuxkpi/common/include/linux/pagemap.h b/sys/compat/linuxkpi/common/include/linux/pagemap.h --- a/sys/compat/linuxkpi/common/include/linux/pagemap.h +++ b/sys/compat/linuxkpi/common/include/linux/pagemap.h @@ -33,6 +33,8 @@ #include #include +struct folio_batch; + #define invalidate_mapping_pages(...) \ linux_invalidate_mapping_pages(__VA_ARGS__) diff --git a/sys/compat/linuxkpi/common/include/linux/pagevec.h b/sys/compat/linuxkpi/common/include/linux/pagevec.h --- a/sys/compat/linuxkpi/common/include/linux/pagevec.h +++ b/sys/compat/linuxkpi/common/include/linux/pagevec.h @@ -66,4 +66,60 @@ { } +/* ------------------------------------------------------------------- */ + +struct folio; + +struct folio_batch { + uint8_t nr; + struct folio *folios[PAGEVEC_SIZE]; +}; + +static inline void +folio_batch_init(struct folio_batch *fbatch) +{ + fbatch->nr = 0; +} + +static inline void +folio_batch_reinit(struct folio_batch *fbatch) +{ + fbatch->nr = 0; +} + +static inline unsigned int +folio_batch_count(struct folio_batch *fbatch) +{ + return fbatch->nr; +} + +static inline unsigned int +folio_batch_space(struct folio_batch *fbatch) +{ + return PAGEVEC_SIZE - fbatch->nr; +} + +static inline unsigned int +folio_batch_add(struct folio_batch *fbatch, struct folio *folio) +{ + fbatch->folios[fbatch->nr++] = folio; + return PAGEVEC_SIZE - fbatch->nr; +} + +static inline void +__folio_batch_release(struct folio_batch *fbatch) +{ + release_pages( + (struct page **)fbatch->folios, + folio_batch_count(fbatch)); + folio_batch_reinit(fbatch); +} + +static inline void +folio_batch_release(struct folio_batch *fbatch) +{ + if (folio_batch_count(fbatch)) + __folio_batch_release(fbatch); +} + #endif /* _LINUXKPI_LINUX_PAGEVEC_H_ */ diff --git a/sys/compat/linuxkpi/common/include/linux/scatterlist.h b/sys/compat/linuxkpi/common/include/linux/scatterlist.h --- a/sys/compat/linuxkpi/common/include/linux/scatterlist.h +++ b/sys/compat/linuxkpi/common/include/linux/scatterlist.h @@ -674,4 +674,11 @@ return (total); } +static inline void +sg_set_folio(struct scatterlist *sg, struct folio *folio, size_t len, + size_t offset) +{ + sg_set_page(sg, &folio->page, len, offset); +} + #endif /* _LINUXKPI_LINUX_SCATTERLIST_H_ */ diff --git a/sys/compat/linuxkpi/common/include/linux/shmem_fs.h b/sys/compat/linuxkpi/common/include/linux/shmem_fs.h --- a/sys/compat/linuxkpi/common/include/linux/shmem_fs.h +++ b/sys/compat/linuxkpi/common/include/linux/shmem_fs.h @@ -54,4 +54,14 @@ #define shmem_truncate_range(...) \ linux_shmem_truncate_range(__VA_ARGS__) +static inline struct folio * +shmem_read_folio_gfp(vm_object_t obj, int pindex, gfp_t gfp) +{ + struct page *page; + + page = shmem_read_mapping_page_gfp(obj, pindex, gfp); + + return page_folio(page); +} + #endif /* _LINUXKPI_LINUX_SHMEM_FS_H_ */ diff --git a/sys/compat/linuxkpi/common/include/linux/swap.h b/sys/compat/linuxkpi/common/include/linux/swap.h --- a/sys/compat/linuxkpi/common/include/linux/swap.h +++ b/sys/compat/linuxkpi/common/include/linux/swap.h @@ -37,6 +37,9 @@ #include #include +#include +#include + static inline long get_nr_swap_pages(void) { @@ -54,4 +57,15 @@ return (curproc == pageproc); } +static inline void +folio_mark_accessed(struct folio *folio) +{ + vm_page_reference(&folio->page); +} + +static inline void +check_move_unevictable_folios(struct folio_batch *fbatch) +{ +} + #endif diff --git a/sys/compat/linuxkpi/common/src/linux_page.c b/sys/compat/linuxkpi/common/src/linux_page.c --- a/sys/compat/linuxkpi/common/src/linux_page.c +++ b/sys/compat/linuxkpi/common/src/linux_page.c @@ -83,7 +83,7 @@ } void * -linux_page_address(struct page *page) +linux_page_address(const struct page *page) { if (page->object != kernel_object) {