[PATCH 05/16] squashfs: add a folio based page actor

From: Tal Zussman

Date: Tue Nov 03 2026 - 09:01:12 EST


Add squashfs_page_actor_init_folios() and
squashfs_page_actor_free_folios(), folio versions of the page actor
init and free. The page implementation stays until its users are
converted.

Signed-off-by: Tal Zussman <tz2294@xxxxxxxxxxxx>
---
fs/squashfs/page_actor.c | 82 ++++++++++++++++++++++++++++++++++++++++++++++++
fs/squashfs/page_actor.h | 16 ++++++++++
2 files changed, 98 insertions(+)

diff --git a/fs/squashfs/page_actor.c b/fs/squashfs/page_actor.c
index 79b73e98abab..8471f69e5cbe 100644
--- a/fs/squashfs/page_actor.c
+++ b/fs/squashfs/page_actor.c
@@ -139,3 +139,85 @@ struct squashfs_page_actor *squashfs_page_actor_init_special(struct squashfs_sb_
actor->squashfs_finish_page = direct_finish_page;
return actor;
}
+
+/* Implementation of page_actor for decompressing directly into folios. */
+static void *handle_next_folio(struct squashfs_page_actor *actor)
+{
+ int max_pages = (actor->length + PAGE_SIZE - 1) >> PAGE_SHIFT;
+ struct folio *folio;
+
+ if (actor->returned_pages == max_pages)
+ return NULL;
+
+ actor->next_index++;
+ actor->returned_pages++;
+
+ if (actor->next_page == actor->pages)
+ goto missing;
+
+ folio = actor->folio[actor->next_page];
+ if (actor->next_index - 1 != folio->index)
+ goto missing;
+
+ actor->next_page++;
+ actor->last_folio = folio;
+ return actor->pageaddr = kmap_local_folio(folio, 0);
+
+missing:
+ actor->last_folio = NULL;
+ return actor->alloc_buffer ? actor->tmp_buffer : ERR_PTR(-ENOMEM);
+}
+
+static void *direct_folio_first_page(struct squashfs_page_actor *actor)
+{
+ return handle_next_folio(actor);
+}
+
+static void *direct_folio_next_page(struct squashfs_page_actor *actor)
+{
+ if (actor->pageaddr) {
+ kunmap_local(actor->pageaddr);
+ actor->pageaddr = NULL;
+ }
+
+ return handle_next_folio(actor);
+}
+
+static void direct_folio_finish_page(struct squashfs_page_actor *actor)
+{
+ if (actor->pageaddr)
+ kunmap_local(actor->pageaddr);
+}
+
+struct squashfs_page_actor *squashfs_page_actor_init_folios(struct squashfs_sb_info *msblk,
+ struct folio **folio, int nr_folios, int length, loff_t start)
+{
+ struct squashfs_page_actor *actor = kmalloc_obj(*actor);
+
+ if (actor == NULL)
+ return NULL;
+
+ if (msblk->decompressor->alloc_buffer) {
+ actor->tmp_buffer = kmalloc(PAGE_SIZE, GFP_KERNEL);
+
+ if (actor->tmp_buffer == NULL) {
+ kfree(actor);
+ return NULL;
+ }
+ } else
+ actor->tmp_buffer = NULL;
+
+ actor->length = length ? : nr_folios * PAGE_SIZE;
+ actor->folio = folio;
+ actor->pages = nr_folios;
+ actor->next_page = 0;
+ actor->returned_pages = 0;
+ actor->next_index = start >> PAGE_SHIFT;
+ actor->pageaddr = NULL;
+ actor->last_folio = NULL;
+ actor->alloc_buffer = msblk->decompressor->alloc_buffer;
+ actor->squashfs_first_page = direct_folio_first_page;
+ actor->squashfs_next_page = direct_folio_next_page;
+ actor->squashfs_finish_page = direct_folio_finish_page;
+ return actor;
+}
diff --git a/fs/squashfs/page_actor.h b/fs/squashfs/page_actor.h
index ffe25eb77c32..bab0a19be266 100644
--- a/fs/squashfs/page_actor.h
+++ b/fs/squashfs/page_actor.h
@@ -10,6 +10,7 @@ struct squashfs_page_actor {
union {
void **buffer;
struct page **page;
+ struct folio **folio;
};
void *pageaddr;
void *tmp_buffer;
@@ -17,6 +18,7 @@ struct squashfs_page_actor {
void *(*squashfs_next_page)(struct squashfs_page_actor *);
void (*squashfs_finish_page)(struct squashfs_page_actor *);
struct page *last_page;
+ struct folio *last_folio;
int pages;
int length;
int next_page;
@@ -31,6 +33,10 @@ extern struct squashfs_page_actor *squashfs_page_actor_init_special(
struct squashfs_sb_info *msblk,
struct page **page, int pages, int length,
loff_t start_index);
+struct squashfs_page_actor *squashfs_page_actor_init_folios(
+ struct squashfs_sb_info *msblk,
+ struct folio **folio, int nr_folios, int length,
+ loff_t start);
static inline struct page *squashfs_page_actor_free(struct squashfs_page_actor *actor)
{
struct page *last_page = actor->next_page == actor->pages ? actor->last_page : ERR_PTR(-EIO);
@@ -40,6 +46,16 @@ static inline struct page *squashfs_page_actor_free(struct squashfs_page_actor *

return last_page;
}
+static inline struct folio *squashfs_page_actor_free_folios(struct squashfs_page_actor *actor)
+{
+ struct folio *last_folio = actor->next_page == actor->pages ?
+ actor->last_folio : ERR_PTR(-EIO);
+
+ kfree(actor->tmp_buffer);
+ kfree(actor);
+
+ return last_folio;
+}
static inline void *squashfs_first_page(struct squashfs_page_actor *actor)
{
return actor->squashfs_first_page(actor);

--
2.39.5