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