brintos

brintos / linux-shallow public Read only

0
0
Text · 3.6 KiB · 2b3e807 Raw
142 lines · c
1// SPDX-License-Identifier: GPL-2.0-only2/*3 * Copyright (c) 20134 * Phillip Lougher <phillip@squashfs.org.uk>5 */6 7#include <linux/kernel.h>8#include <linux/slab.h>9#include <linux/pagemap.h>10#include "squashfs_fs_sb.h"11#include "decompressor.h"12#include "page_actor.h"13 14/*15 * This file contains implementations of page_actor for decompressing into16 * an intermediate buffer, and for decompressing directly into the17 * page cache.18 *19 * Calling code should avoid sleeping between calls to squashfs_first_page()20 * and squashfs_finish_page().21 */22 23/* Implementation of page_actor for decompressing into intermediate buffer */24static void *cache_first_page(struct squashfs_page_actor *actor)25{26	actor->next_page = 1;27	return actor->buffer[0];28}29 30static void *cache_next_page(struct squashfs_page_actor *actor)31{32	if (actor->next_page == actor->pages)33		return NULL;34 35	return actor->buffer[actor->next_page++];36}37 38static void cache_finish_page(struct squashfs_page_actor *actor)39{40	/* empty */41}42 43struct squashfs_page_actor *squashfs_page_actor_init(void **buffer,44	int pages, int length)45{46	struct squashfs_page_actor *actor = kmalloc(sizeof(*actor), GFP_KERNEL);47 48	if (actor == NULL)49		return NULL;50 51	actor->length = length ? : pages * PAGE_SIZE;52	actor->buffer = buffer;53	actor->pages = pages;54	actor->next_page = 0;55	actor->tmp_buffer = NULL;56	actor->squashfs_first_page = cache_first_page;57	actor->squashfs_next_page = cache_next_page;58	actor->squashfs_finish_page = cache_finish_page;59	return actor;60}61 62/* Implementation of page_actor for decompressing directly into page cache. */63static loff_t page_next_index(struct squashfs_page_actor *actor)64{65	return page_folio(actor->page[actor->next_page])->index;66}67 68static void *handle_next_page(struct squashfs_page_actor *actor)69{70	int max_pages = (actor->length + PAGE_SIZE - 1) >> PAGE_SHIFT;71 72	if (actor->returned_pages == max_pages)73		return NULL;74 75	if ((actor->next_page == actor->pages) ||76			(actor->next_index != page_next_index(actor))) {77		actor->next_index++;78		actor->returned_pages++;79		actor->last_page = NULL;80		return actor->alloc_buffer ? actor->tmp_buffer : ERR_PTR(-ENOMEM);81	}82 83	actor->next_index++;84	actor->returned_pages++;85	actor->last_page = actor->page[actor->next_page];86	return actor->pageaddr = kmap_local_page(actor->page[actor->next_page++]);87}88 89static void *direct_first_page(struct squashfs_page_actor *actor)90{91	return handle_next_page(actor);92}93 94static void *direct_next_page(struct squashfs_page_actor *actor)95{96	if (actor->pageaddr) {97		kunmap_local(actor->pageaddr);98		actor->pageaddr = NULL;99	}100 101	return handle_next_page(actor);102}103 104static void direct_finish_page(struct squashfs_page_actor *actor)105{106	if (actor->pageaddr)107		kunmap_local(actor->pageaddr);108}109 110struct squashfs_page_actor *squashfs_page_actor_init_special(struct squashfs_sb_info *msblk,111	struct page **page, int pages, int length, loff_t start_index)112{113	struct squashfs_page_actor *actor = kmalloc(sizeof(*actor), GFP_KERNEL);114 115	if (actor == NULL)116		return NULL;117 118	if (msblk->decompressor->alloc_buffer) {119		actor->tmp_buffer = kmalloc(PAGE_SIZE, GFP_KERNEL);120 121		if (actor->tmp_buffer == NULL) {122			kfree(actor);123			return NULL;124		}125	} else126		actor->tmp_buffer = NULL;127 128	actor->length = length ? : pages * PAGE_SIZE;129	actor->page = page;130	actor->pages = pages;131	actor->next_page = 0;132	actor->returned_pages = 0;133	actor->next_index = start_index >> PAGE_SHIFT;134	actor->pageaddr = NULL;135	actor->last_page = NULL;136	actor->alloc_buffer = msblk->decompressor->alloc_buffer;137	actor->squashfs_first_page = direct_first_page;138	actor->squashfs_next_page = direct_next_page;139	actor->squashfs_finish_page = direct_finish_page;140	return actor;141}142