linux/fs/squashfs/zlib_wrapper.c
<<
>>
Prefs
   1// SPDX-License-Identifier: GPL-2.0-or-later
   2/*
   3 * Squashfs - a compressed read only filesystem for Linux
   4 *
   5 * Copyright (c) 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009
   6 * Phillip Lougher <phillip@squashfs.org.uk>
   7 *
   8 * zlib_wrapper.c
   9 */
  10
  11
  12#include <linux/mutex.h>
  13#include <linux/bio.h>
  14#include <linux/slab.h>
  15#include <linux/zlib.h>
  16#include <linux/vmalloc.h>
  17
  18#include "squashfs_fs.h"
  19#include "squashfs_fs_sb.h"
  20#include "squashfs.h"
  21#include "decompressor.h"
  22#include "page_actor.h"
  23
  24static void *zlib_init(struct squashfs_sb_info *dummy, void *buff)
  25{
  26        z_stream *stream = kmalloc(sizeof(z_stream), GFP_KERNEL);
  27        if (stream == NULL)
  28                goto failed;
  29        stream->workspace = vmalloc(zlib_inflate_workspacesize());
  30        if (stream->workspace == NULL)
  31                goto failed;
  32
  33        return stream;
  34
  35failed:
  36        ERROR("Failed to allocate zlib workspace\n");
  37        kfree(stream);
  38        return ERR_PTR(-ENOMEM);
  39}
  40
  41
  42static void zlib_free(void *strm)
  43{
  44        z_stream *stream = strm;
  45
  46        if (stream)
  47                vfree(stream->workspace);
  48        kfree(stream);
  49}
  50
  51
  52static int zlib_uncompress(struct squashfs_sb_info *msblk, void *strm,
  53        struct bio *bio, int offset, int length,
  54        struct squashfs_page_actor *output)
  55{
  56        struct bvec_iter_all iter_all = {};
  57        struct bio_vec *bvec = bvec_init_iter_all(&iter_all);
  58        int zlib_init = 0, error = 0;
  59        z_stream *stream = strm;
  60
  61        stream->avail_out = PAGE_SIZE;
  62        stream->next_out = squashfs_first_page(output);
  63        stream->avail_in = 0;
  64
  65        for (;;) {
  66                int zlib_err;
  67
  68                if (stream->avail_in == 0) {
  69                        const void *data;
  70                        int avail;
  71
  72                        if (!bio_next_segment(bio, &iter_all)) {
  73                                /* Z_STREAM_END must be reached. */
  74                                error = -EIO;
  75                                break;
  76                        }
  77
  78                        avail = min(length, ((int)bvec->bv_len) - offset);
  79                        data = bvec_virt(bvec);
  80                        length -= avail;
  81                        stream->next_in = data + offset;
  82                        stream->avail_in = avail;
  83                        offset = 0;
  84                }
  85
  86                if (stream->avail_out == 0) {
  87                        stream->next_out = squashfs_next_page(output);
  88                        if (stream->next_out != NULL)
  89                                stream->avail_out = PAGE_SIZE;
  90                }
  91
  92                if (!zlib_init) {
  93                        zlib_err = zlib_inflateInit(stream);
  94                        if (zlib_err != Z_OK) {
  95                                error = -EIO;
  96                                break;
  97                        }
  98                        zlib_init = 1;
  99                }
 100
 101                zlib_err = zlib_inflate(stream, Z_SYNC_FLUSH);
 102                if (zlib_err == Z_STREAM_END)
 103                        break;
 104                if (zlib_err != Z_OK) {
 105                        error = -EIO;
 106                        break;
 107                }
 108        }
 109
 110        squashfs_finish_page(output);
 111
 112        if (!error)
 113                if (zlib_inflateEnd(stream) != Z_OK)
 114                        error = -EIO;
 115
 116        return error ? error : stream->total_out;
 117}
 118
 119const struct squashfs_decompressor squashfs_zlib_comp_ops = {
 120        .init = zlib_init,
 121        .free = zlib_free,
 122        .decompress = zlib_uncompress,
 123        .id = ZLIB_COMPRESSION,
 124        .name = "zlib",
 125        .supported = 1
 126};
 127
 128