xref: /linux/fs/squashfs/page_actor.c (revision 75bf465f0bc33e9b776a46d6a1b9b990f5fb7c37)
1*20c8ccb1SThomas 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>
100d455c12SPhillip Lougher #include "page_actor.h"
110d455c12SPhillip Lougher 
120d455c12SPhillip Lougher /*
130d455c12SPhillip Lougher  * This file contains implementations of page_actor for decompressing into
140d455c12SPhillip Lougher  * an intermediate buffer, and for decompressing directly into the
150d455c12SPhillip Lougher  * page cache.
160d455c12SPhillip Lougher  *
170d455c12SPhillip Lougher  * Calling code should avoid sleeping between calls to squashfs_first_page()
180d455c12SPhillip Lougher  * and squashfs_finish_page().
190d455c12SPhillip Lougher  */
200d455c12SPhillip Lougher 
210d455c12SPhillip Lougher /* Implementation of page_actor for decompressing into intermediate buffer */
220d455c12SPhillip Lougher static void *cache_first_page(struct squashfs_page_actor *actor)
230d455c12SPhillip Lougher {
240d455c12SPhillip Lougher 	actor->next_page = 1;
250d455c12SPhillip Lougher 	return actor->buffer[0];
260d455c12SPhillip Lougher }
270d455c12SPhillip Lougher 
280d455c12SPhillip Lougher static void *cache_next_page(struct squashfs_page_actor *actor)
290d455c12SPhillip Lougher {
300d455c12SPhillip Lougher 	if (actor->next_page == actor->pages)
310d455c12SPhillip Lougher 		return NULL;
320d455c12SPhillip Lougher 
330d455c12SPhillip Lougher 	return actor->buffer[actor->next_page++];
340d455c12SPhillip Lougher }
350d455c12SPhillip Lougher 
360d455c12SPhillip Lougher static void cache_finish_page(struct squashfs_page_actor *actor)
370d455c12SPhillip Lougher {
380d455c12SPhillip Lougher 	/* empty */
390d455c12SPhillip Lougher }
400d455c12SPhillip Lougher 
410d455c12SPhillip Lougher struct squashfs_page_actor *squashfs_page_actor_init(void **buffer,
420d455c12SPhillip Lougher 	int pages, int length)
430d455c12SPhillip Lougher {
440d455c12SPhillip Lougher 	struct squashfs_page_actor *actor = kmalloc(sizeof(*actor), GFP_KERNEL);
450d455c12SPhillip Lougher 
460d455c12SPhillip Lougher 	if (actor == NULL)
470d455c12SPhillip Lougher 		return NULL;
480d455c12SPhillip Lougher 
4909cbfeafSKirill A. Shutemov 	actor->length = length ? : pages * PAGE_SIZE;
500d455c12SPhillip Lougher 	actor->buffer = buffer;
510d455c12SPhillip Lougher 	actor->pages = pages;
520d455c12SPhillip Lougher 	actor->next_page = 0;
530d455c12SPhillip Lougher 	actor->squashfs_first_page = cache_first_page;
540d455c12SPhillip Lougher 	actor->squashfs_next_page = cache_next_page;
550d455c12SPhillip Lougher 	actor->squashfs_finish_page = cache_finish_page;
560d455c12SPhillip Lougher 	return actor;
570d455c12SPhillip Lougher }
580d455c12SPhillip Lougher 
590d455c12SPhillip Lougher /* Implementation of page_actor for decompressing directly into page cache. */
600d455c12SPhillip Lougher static void *direct_first_page(struct squashfs_page_actor *actor)
610d455c12SPhillip Lougher {
620d455c12SPhillip Lougher 	actor->next_page = 1;
630d455c12SPhillip Lougher 	return actor->pageaddr = kmap_atomic(actor->page[0]);
640d455c12SPhillip Lougher }
650d455c12SPhillip Lougher 
660d455c12SPhillip Lougher static void *direct_next_page(struct squashfs_page_actor *actor)
670d455c12SPhillip Lougher {
680d455c12SPhillip Lougher 	if (actor->pageaddr)
690d455c12SPhillip Lougher 		kunmap_atomic(actor->pageaddr);
700d455c12SPhillip Lougher 
710d455c12SPhillip Lougher 	return actor->pageaddr = actor->next_page == actor->pages ? NULL :
720d455c12SPhillip Lougher 		kmap_atomic(actor->page[actor->next_page++]);
730d455c12SPhillip Lougher }
740d455c12SPhillip Lougher 
750d455c12SPhillip Lougher static void direct_finish_page(struct squashfs_page_actor *actor)
760d455c12SPhillip Lougher {
770d455c12SPhillip Lougher 	if (actor->pageaddr)
780d455c12SPhillip Lougher 		kunmap_atomic(actor->pageaddr);
790d455c12SPhillip Lougher }
800d455c12SPhillip Lougher 
810d455c12SPhillip Lougher struct squashfs_page_actor *squashfs_page_actor_init_special(struct page **page,
820d455c12SPhillip Lougher 	int pages, int length)
830d455c12SPhillip Lougher {
840d455c12SPhillip Lougher 	struct squashfs_page_actor *actor = kmalloc(sizeof(*actor), GFP_KERNEL);
850d455c12SPhillip Lougher 
860d455c12SPhillip Lougher 	if (actor == NULL)
870d455c12SPhillip Lougher 		return NULL;
880d455c12SPhillip Lougher 
8909cbfeafSKirill A. Shutemov 	actor->length = length ? : pages * PAGE_SIZE;
900d455c12SPhillip Lougher 	actor->page = page;
910d455c12SPhillip Lougher 	actor->pages = pages;
920d455c12SPhillip Lougher 	actor->next_page = 0;
930d455c12SPhillip Lougher 	actor->pageaddr = NULL;
940d455c12SPhillip Lougher 	actor->squashfs_first_page = direct_first_page;
950d455c12SPhillip Lougher 	actor->squashfs_next_page = direct_next_page;
960d455c12SPhillip Lougher 	actor->squashfs_finish_page = direct_finish_page;
970d455c12SPhillip Lougher 	return actor;
980d455c12SPhillip Lougher }
99