linux/fs/squashfs/page_actor.c
<<
>>
Prefs
   1// SPDX-License-Identifier: GPL-2.0-only
   2/*
   3 * Copyright (c) 2013
   4 * 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 "page_actor.h"
  11
  12/*
  13 * This file contains implementations of page_actor for decompressing into
  14 * an intermediate buffer, and for decompressing directly into the
  15 * page cache.
  16 *
  17 * Calling code should avoid sleeping between calls to squashfs_first_page()
  18 * and squashfs_finish_page().
  19 */
  20
  21/* Implementation of page_actor for decompressing into intermediate buffer */
  22static void *cache_first_page(struct squashfs_page_actor *actor)
  23{
  24        actor->next_page = 1;
  25        return actor->buffer[0];
  26}
  27
  28static void *cache_next_page(struct squashfs_page_actor *actor)
  29{
  30        if (actor->next_page == actor->pages)
  31                return NULL;
  32
  33        return actor->buffer[actor->next_page++];
  34}
  35
  36static void cache_finish_page(struct squashfs_page_actor *actor)
  37{
  38        /* empty */
  39}
  40
  41struct squashfs_page_actor *squashfs_page_actor_init(void **buffer,
  42        int pages, int length)
  43{
  44        struct squashfs_page_actor *actor = kmalloc(sizeof(*actor), GFP_KERNEL);
  45
  46        if (actor == NULL)
  47                return NULL;
  48
  49        actor->length = length ? : pages * PAGE_SIZE;
  50        actor->buffer = buffer;
  51        actor->pages = pages;
  52        actor->next_page = 0;
  53        actor->squashfs_first_page = cache_first_page;
  54        actor->squashfs_next_page = cache_next_page;
  55        actor->squashfs_finish_page = cache_finish_page;
  56        return actor;
  57}
  58
  59/* Implementation of page_actor for decompressing directly into page cache. */
  60static void *direct_first_page(struct squashfs_page_actor *actor)
  61{
  62        actor->next_page = 1;
  63        return actor->pageaddr = kmap_atomic(actor->page[0]);
  64}
  65
  66static void *direct_next_page(struct squashfs_page_actor *actor)
  67{
  68        if (actor->pageaddr)
  69                kunmap_atomic(actor->pageaddr);
  70
  71        return actor->pageaddr = actor->next_page == actor->pages ? NULL :
  72                kmap_atomic(actor->page[actor->next_page++]);
  73}
  74
  75static void direct_finish_page(struct squashfs_page_actor *actor)
  76{
  77        if (actor->pageaddr)
  78                kunmap_atomic(actor->pageaddr);
  79}
  80
  81struct squashfs_page_actor *squashfs_page_actor_init_special(struct page **page,
  82        int pages, int length)
  83{
  84        struct squashfs_page_actor *actor = kmalloc(sizeof(*actor), GFP_KERNEL);
  85
  86        if (actor == NULL)
  87                return NULL;
  88
  89        actor->length = length ? : pages * PAGE_SIZE;
  90        actor->page = page;
  91        actor->pages = pages;
  92        actor->next_page = 0;
  93        actor->pageaddr = NULL;
  94        actor->squashfs_first_page = direct_first_page;
  95        actor->squashfs_next_page = direct_next_page;
  96        actor->squashfs_finish_page = direct_finish_page;
  97        return actor;
  98}
  99