xref: /openbmc/linux/fs/squashfs/page_actor.c (revision 9ef8eb61)
120c8ccb1SThomas Gleixner // SPDX-License-Identifier: GPL-2.0-only
20d455c12SPhillip Lougher /*
30d455c12SPhillip Lougher  * Copyright (c) 2013
40d455c12SPhillip Lougher  * Phillip Lougher <phillip@squashfs.org.uk>
50d455c12SPhillip Lougher  */
60d455c12SPhillip Lougher 
70d455c12SPhillip Lougher #include <linux/kernel.h>
80d455c12SPhillip Lougher #include <linux/slab.h>
90d455c12SPhillip Lougher #include <linux/pagemap.h>
10f268eeddSPhillip Lougher #include "squashfs_fs_sb.h"
11f268eeddSPhillip Lougher #include "decompressor.h"
120d455c12SPhillip Lougher #include "page_actor.h"
130d455c12SPhillip Lougher 
140d455c12SPhillip Lougher /*
150d455c12SPhillip Lougher  * This file contains implementations of page_actor for decompressing into
160d455c12SPhillip Lougher  * an intermediate buffer, and for decompressing directly into the
170d455c12SPhillip Lougher  * page cache.
180d455c12SPhillip Lougher  *
190d455c12SPhillip Lougher  * Calling code should avoid sleeping between calls to squashfs_first_page()
200d455c12SPhillip Lougher  * and squashfs_finish_page().
210d455c12SPhillip Lougher  */
220d455c12SPhillip Lougher 
230d455c12SPhillip Lougher /* Implementation of page_actor for decompressing into intermediate buffer */
cache_first_page(struct squashfs_page_actor * actor)240d455c12SPhillip Lougher static void *cache_first_page(struct squashfs_page_actor *actor)
250d455c12SPhillip Lougher {
260d455c12SPhillip Lougher 	actor->next_page = 1;
270d455c12SPhillip Lougher 	return actor->buffer[0];
280d455c12SPhillip Lougher }
290d455c12SPhillip Lougher 
cache_next_page(struct squashfs_page_actor * actor)300d455c12SPhillip Lougher static void *cache_next_page(struct squashfs_page_actor *actor)
310d455c12SPhillip Lougher {
320d455c12SPhillip Lougher 	if (actor->next_page == actor->pages)
330d455c12SPhillip Lougher 		return NULL;
340d455c12SPhillip Lougher 
350d455c12SPhillip Lougher 	return actor->buffer[actor->next_page++];
360d455c12SPhillip Lougher }
370d455c12SPhillip Lougher 
cache_finish_page(struct squashfs_page_actor * actor)380d455c12SPhillip Lougher static void cache_finish_page(struct squashfs_page_actor *actor)
390d455c12SPhillip Lougher {
400d455c12SPhillip Lougher 	/* empty */
410d455c12SPhillip Lougher }
420d455c12SPhillip Lougher 
squashfs_page_actor_init(void ** buffer,int pages,int length)430d455c12SPhillip Lougher struct squashfs_page_actor *squashfs_page_actor_init(void **buffer,
440d455c12SPhillip Lougher 	int pages, int length)
450d455c12SPhillip Lougher {
460d455c12SPhillip Lougher 	struct squashfs_page_actor *actor = kmalloc(sizeof(*actor), GFP_KERNEL);
470d455c12SPhillip Lougher 
480d455c12SPhillip Lougher 	if (actor == NULL)
490d455c12SPhillip Lougher 		return NULL;
500d455c12SPhillip Lougher 
5109cbfeafSKirill A. Shutemov 	actor->length = length ? : pages * PAGE_SIZE;
520d455c12SPhillip Lougher 	actor->buffer = buffer;
530d455c12SPhillip Lougher 	actor->pages = pages;
540d455c12SPhillip Lougher 	actor->next_page = 0;
551f13dff0SPhillip Lougher 	actor->tmp_buffer = NULL;
560d455c12SPhillip Lougher 	actor->squashfs_first_page = cache_first_page;
570d455c12SPhillip Lougher 	actor->squashfs_next_page = cache_next_page;
580d455c12SPhillip Lougher 	actor->squashfs_finish_page = cache_finish_page;
590d455c12SPhillip Lougher 	return actor;
600d455c12SPhillip Lougher }
610d455c12SPhillip Lougher 
620d455c12SPhillip Lougher /* Implementation of page_actor for decompressing directly into page cache. */
handle_next_page(struct squashfs_page_actor * actor)63f268eeddSPhillip Lougher static void *handle_next_page(struct squashfs_page_actor *actor)
64f268eeddSPhillip Lougher {
65f268eeddSPhillip Lougher 	int max_pages = (actor->length + PAGE_SIZE - 1) >> PAGE_SHIFT;
66f268eeddSPhillip Lougher 
67f268eeddSPhillip Lougher 	if (actor->returned_pages == max_pages)
68f268eeddSPhillip Lougher 		return NULL;
69f268eeddSPhillip Lougher 
70f268eeddSPhillip Lougher 	if ((actor->next_page == actor->pages) ||
71f268eeddSPhillip Lougher 			(actor->next_index != actor->page[actor->next_page]->index)) {
72f268eeddSPhillip Lougher 		actor->next_index++;
73f268eeddSPhillip Lougher 		actor->returned_pages++;
74*9ef8eb61SPhillip Lougher 		actor->last_page = NULL;
751f13dff0SPhillip Lougher 		return actor->alloc_buffer ? actor->tmp_buffer : ERR_PTR(-ENOMEM);
76f268eeddSPhillip Lougher 	}
77f268eeddSPhillip Lougher 
78f268eeddSPhillip Lougher 	actor->next_index++;
79f268eeddSPhillip Lougher 	actor->returned_pages++;
80*9ef8eb61SPhillip Lougher 	actor->last_page = actor->page[actor->next_page];
81f268eeddSPhillip Lougher 	return actor->pageaddr = kmap_local_page(actor->page[actor->next_page++]);
82f268eeddSPhillip Lougher }
83f268eeddSPhillip Lougher 
direct_first_page(struct squashfs_page_actor * actor)840d455c12SPhillip Lougher static void *direct_first_page(struct squashfs_page_actor *actor)
850d455c12SPhillip Lougher {
86f268eeddSPhillip Lougher 	return handle_next_page(actor);
870d455c12SPhillip Lougher }
880d455c12SPhillip Lougher 
direct_next_page(struct squashfs_page_actor * actor)890d455c12SPhillip Lougher static void *direct_next_page(struct squashfs_page_actor *actor)
900d455c12SPhillip Lougher {
911f13dff0SPhillip Lougher 	if (actor->pageaddr) {
92f268eeddSPhillip Lougher 		kunmap_local(actor->pageaddr);
931f13dff0SPhillip Lougher 		actor->pageaddr = NULL;
941f13dff0SPhillip Lougher 	}
95f268eeddSPhillip Lougher 
96f268eeddSPhillip Lougher 	return handle_next_page(actor);
970d455c12SPhillip Lougher }
980d455c12SPhillip Lougher 
direct_finish_page(struct squashfs_page_actor * actor)990d455c12SPhillip Lougher static void direct_finish_page(struct squashfs_page_actor *actor)
1000d455c12SPhillip Lougher {
1010d455c12SPhillip Lougher 	if (actor->pageaddr)
102f268eeddSPhillip Lougher 		kunmap_local(actor->pageaddr);
1030d455c12SPhillip Lougher }
1040d455c12SPhillip Lougher 
squashfs_page_actor_init_special(struct squashfs_sb_info * msblk,struct page ** page,int pages,int length)105f268eeddSPhillip Lougher struct squashfs_page_actor *squashfs_page_actor_init_special(struct squashfs_sb_info *msblk,
106f268eeddSPhillip Lougher 	struct page **page, int pages, int length)
1070d455c12SPhillip Lougher {
1080d455c12SPhillip Lougher 	struct squashfs_page_actor *actor = kmalloc(sizeof(*actor), GFP_KERNEL);
1090d455c12SPhillip Lougher 
1100d455c12SPhillip Lougher 	if (actor == NULL)
1110d455c12SPhillip Lougher 		return NULL;
1120d455c12SPhillip Lougher 
1131f13dff0SPhillip Lougher 	if (msblk->decompressor->alloc_buffer) {
1141f13dff0SPhillip Lougher 		actor->tmp_buffer = kmalloc(PAGE_SIZE, GFP_KERNEL);
1151f13dff0SPhillip Lougher 
1161f13dff0SPhillip Lougher 		if (actor->tmp_buffer == NULL) {
1171f13dff0SPhillip Lougher 			kfree(actor);
1181f13dff0SPhillip Lougher 			return NULL;
1191f13dff0SPhillip Lougher 		}
1201f13dff0SPhillip Lougher 	} else
1211f13dff0SPhillip Lougher 		actor->tmp_buffer = NULL;
1221f13dff0SPhillip Lougher 
12309cbfeafSKirill A. Shutemov 	actor->length = length ? : pages * PAGE_SIZE;
1240d455c12SPhillip Lougher 	actor->page = page;
1250d455c12SPhillip Lougher 	actor->pages = pages;
1260d455c12SPhillip Lougher 	actor->next_page = 0;
127f268eeddSPhillip Lougher 	actor->returned_pages = 0;
128f268eeddSPhillip Lougher 	actor->next_index = page[0]->index & ~((1 << (msblk->block_log - PAGE_SHIFT)) - 1);
1290d455c12SPhillip Lougher 	actor->pageaddr = NULL;
130*9ef8eb61SPhillip Lougher 	actor->last_page = NULL;
131f268eeddSPhillip Lougher 	actor->alloc_buffer = msblk->decompressor->alloc_buffer;
1320d455c12SPhillip Lougher 	actor->squashfs_first_page = direct_first_page;
1330d455c12SPhillip Lougher 	actor->squashfs_next_page = direct_next_page;
1340d455c12SPhillip Lougher 	actor->squashfs_finish_page = direct_finish_page;
1350d455c12SPhillip Lougher 	return actor;
1360d455c12SPhillip Lougher }
137