18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-only 28c2ecf20Sopenharmony_ci/* 38c2ecf20Sopenharmony_ci * Copyright (c) 2013 48c2ecf20Sopenharmony_ci * Phillip Lougher <phillip@squashfs.org.uk> 58c2ecf20Sopenharmony_ci */ 68c2ecf20Sopenharmony_ci 78c2ecf20Sopenharmony_ci#include <linux/kernel.h> 88c2ecf20Sopenharmony_ci#include <linux/slab.h> 98c2ecf20Sopenharmony_ci#include <linux/pagemap.h> 108c2ecf20Sopenharmony_ci#include "page_actor.h" 118c2ecf20Sopenharmony_ci 128c2ecf20Sopenharmony_ci/* 138c2ecf20Sopenharmony_ci * This file contains implementations of page_actor for decompressing into 148c2ecf20Sopenharmony_ci * an intermediate buffer, and for decompressing directly into the 158c2ecf20Sopenharmony_ci * page cache. 168c2ecf20Sopenharmony_ci * 178c2ecf20Sopenharmony_ci * Calling code should avoid sleeping between calls to squashfs_first_page() 188c2ecf20Sopenharmony_ci * and squashfs_finish_page(). 198c2ecf20Sopenharmony_ci */ 208c2ecf20Sopenharmony_ci 218c2ecf20Sopenharmony_ci/* Implementation of page_actor for decompressing into intermediate buffer */ 228c2ecf20Sopenharmony_cistatic void *cache_first_page(struct squashfs_page_actor *actor) 238c2ecf20Sopenharmony_ci{ 248c2ecf20Sopenharmony_ci actor->next_page = 1; 258c2ecf20Sopenharmony_ci return actor->buffer[0]; 268c2ecf20Sopenharmony_ci} 278c2ecf20Sopenharmony_ci 288c2ecf20Sopenharmony_cistatic void *cache_next_page(struct squashfs_page_actor *actor) 298c2ecf20Sopenharmony_ci{ 308c2ecf20Sopenharmony_ci if (actor->next_page == actor->pages) 318c2ecf20Sopenharmony_ci return NULL; 328c2ecf20Sopenharmony_ci 338c2ecf20Sopenharmony_ci return actor->buffer[actor->next_page++]; 348c2ecf20Sopenharmony_ci} 358c2ecf20Sopenharmony_ci 368c2ecf20Sopenharmony_cistatic void cache_finish_page(struct squashfs_page_actor *actor) 378c2ecf20Sopenharmony_ci{ 388c2ecf20Sopenharmony_ci /* empty */ 398c2ecf20Sopenharmony_ci} 408c2ecf20Sopenharmony_ci 418c2ecf20Sopenharmony_cistruct squashfs_page_actor *squashfs_page_actor_init(void **buffer, 428c2ecf20Sopenharmony_ci int pages, int length) 438c2ecf20Sopenharmony_ci{ 448c2ecf20Sopenharmony_ci struct squashfs_page_actor *actor = kmalloc(sizeof(*actor), GFP_KERNEL); 458c2ecf20Sopenharmony_ci 468c2ecf20Sopenharmony_ci if (actor == NULL) 478c2ecf20Sopenharmony_ci return NULL; 488c2ecf20Sopenharmony_ci 498c2ecf20Sopenharmony_ci actor->length = length ? : pages * PAGE_SIZE; 508c2ecf20Sopenharmony_ci actor->buffer = buffer; 518c2ecf20Sopenharmony_ci actor->pages = pages; 528c2ecf20Sopenharmony_ci actor->next_page = 0; 538c2ecf20Sopenharmony_ci actor->squashfs_first_page = cache_first_page; 548c2ecf20Sopenharmony_ci actor->squashfs_next_page = cache_next_page; 558c2ecf20Sopenharmony_ci actor->squashfs_finish_page = cache_finish_page; 568c2ecf20Sopenharmony_ci return actor; 578c2ecf20Sopenharmony_ci} 588c2ecf20Sopenharmony_ci 598c2ecf20Sopenharmony_ci/* Implementation of page_actor for decompressing directly into page cache. */ 608c2ecf20Sopenharmony_cistatic void *direct_first_page(struct squashfs_page_actor *actor) 618c2ecf20Sopenharmony_ci{ 628c2ecf20Sopenharmony_ci actor->next_page = 1; 638c2ecf20Sopenharmony_ci return actor->pageaddr = kmap_atomic(actor->page[0]); 648c2ecf20Sopenharmony_ci} 658c2ecf20Sopenharmony_ci 668c2ecf20Sopenharmony_cistatic void *direct_next_page(struct squashfs_page_actor *actor) 678c2ecf20Sopenharmony_ci{ 688c2ecf20Sopenharmony_ci if (actor->pageaddr) 698c2ecf20Sopenharmony_ci kunmap_atomic(actor->pageaddr); 708c2ecf20Sopenharmony_ci 718c2ecf20Sopenharmony_ci return actor->pageaddr = actor->next_page == actor->pages ? NULL : 728c2ecf20Sopenharmony_ci kmap_atomic(actor->page[actor->next_page++]); 738c2ecf20Sopenharmony_ci} 748c2ecf20Sopenharmony_ci 758c2ecf20Sopenharmony_cistatic void direct_finish_page(struct squashfs_page_actor *actor) 768c2ecf20Sopenharmony_ci{ 778c2ecf20Sopenharmony_ci if (actor->pageaddr) 788c2ecf20Sopenharmony_ci kunmap_atomic(actor->pageaddr); 798c2ecf20Sopenharmony_ci} 808c2ecf20Sopenharmony_ci 818c2ecf20Sopenharmony_cistruct squashfs_page_actor *squashfs_page_actor_init_special(struct page **page, 828c2ecf20Sopenharmony_ci int pages, int length) 838c2ecf20Sopenharmony_ci{ 848c2ecf20Sopenharmony_ci struct squashfs_page_actor *actor = kmalloc(sizeof(*actor), GFP_KERNEL); 858c2ecf20Sopenharmony_ci 868c2ecf20Sopenharmony_ci if (actor == NULL) 878c2ecf20Sopenharmony_ci return NULL; 888c2ecf20Sopenharmony_ci 898c2ecf20Sopenharmony_ci actor->length = length ? : pages * PAGE_SIZE; 908c2ecf20Sopenharmony_ci actor->page = page; 918c2ecf20Sopenharmony_ci actor->pages = pages; 928c2ecf20Sopenharmony_ci actor->next_page = 0; 938c2ecf20Sopenharmony_ci actor->pageaddr = NULL; 948c2ecf20Sopenharmony_ci actor->squashfs_first_page = direct_first_page; 958c2ecf20Sopenharmony_ci actor->squashfs_next_page = direct_next_page; 968c2ecf20Sopenharmony_ci actor->squashfs_finish_page = direct_finish_page; 978c2ecf20Sopenharmony_ci return actor; 988c2ecf20Sopenharmony_ci} 99