linux/fs/squashfs/page_actor.c
<<
>>
Prefs
   1/*
   2 * Copyright (c) 2013
   3 * Phillip Lougher <phillip@squashfs.org.uk>
   4 *
   5 * This work is licensed under the terms of the GNU GPL, version 2. See
   6 * the COPYING file in the top-level directory.
   7 */
   8
   9#include <linux/kernel.h>
  10#include <linux/slab.h>
  11#include <linux/pagemap.h>
  12#include "page_actor.h"
  13
  14/*
  15 * This file contains implementations of page_actor for decompressing into
  16 * an intermediate buffer, and for decompressing directly into the
  17 * 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_CACHE_SIZE;
  52        actor->buffer = buffer;
  53        actor->pages = pages;
  54        actor->next_page = 0;
  55        actor->squashfs_first_page = cache_first_page;
  56        actor->squashfs_next_page = cache_next_page;
  57        actor->squashfs_finish_page = cache_finish_page;
  58        return actor;
  59}
  60
  61/* Implementation of page_actor for decompressing directly into page cache. */
  62static void *direct_first_page(struct squashfs_page_actor *actor)
  63{
  64        actor->next_page = 1;
  65        return actor->pageaddr = kmap_atomic(actor->page[0]);
  66}
  67
  68static void *direct_next_page(struct squashfs_page_actor *actor)
  69{
  70        if (actor->pageaddr)
  71                kunmap_atomic(actor->pageaddr);
  72
  73        return actor->pageaddr = actor->next_page == actor->pages ? NULL :
  74                kmap_atomic(actor->page[actor->next_page++]);
  75}
  76
  77static void direct_finish_page(struct squashfs_page_actor *actor)
  78{
  79        if (actor->pageaddr)
  80                kunmap_atomic(actor->pageaddr);
  81}
  82
  83struct squashfs_page_actor *squashfs_page_actor_init_special(struct page **page,
  84        int pages, int length)
  85{
  86        struct squashfs_page_actor *actor = kmalloc(sizeof(*actor), GFP_KERNEL);
  87
  88        if (actor == NULL)
  89                return NULL;
  90
  91        actor->length = length ? : pages * PAGE_CACHE_SIZE;
  92        actor->page = page;
  93        actor->pages = pages;
  94        actor->next_page = 0;
  95        actor->pageaddr = NULL;
  96        actor->squashfs_first_page = direct_first_page;
  97        actor->squashfs_next_page = direct_next_page;
  98        actor->squashfs_finish_page = direct_finish_page;
  99        return actor;
 100}
 101