0001
0002
0003
0004
0005
0006
0007
0008
0009
0010
0011
0012 #include <linux/mutex.h>
0013 #include <linux/bio.h>
0014 #include <linux/slab.h>
0015 #include <linux/zlib.h>
0016 #include <linux/vmalloc.h>
0017
0018 #include "squashfs_fs.h"
0019 #include "squashfs_fs_sb.h"
0020 #include "squashfs.h"
0021 #include "decompressor.h"
0022 #include "page_actor.h"
0023
0024 static void *zlib_init(struct squashfs_sb_info *dummy, void *buff)
0025 {
0026 z_stream *stream = kmalloc(sizeof(z_stream), GFP_KERNEL);
0027 if (stream == NULL)
0028 goto failed;
0029 stream->workspace = vmalloc(zlib_inflate_workspacesize());
0030 if (stream->workspace == NULL)
0031 goto failed;
0032
0033 return stream;
0034
0035 failed:
0036 ERROR("Failed to allocate zlib workspace\n");
0037 kfree(stream);
0038 return ERR_PTR(-ENOMEM);
0039 }
0040
0041
0042 static void zlib_free(void *strm)
0043 {
0044 z_stream *stream = strm;
0045
0046 if (stream)
0047 vfree(stream->workspace);
0048 kfree(stream);
0049 }
0050
0051
0052 static int zlib_uncompress(struct squashfs_sb_info *msblk, void *strm,
0053 struct bio *bio, int offset, int length,
0054 struct squashfs_page_actor *output)
0055 {
0056 struct bvec_iter_all iter_all = {};
0057 struct bio_vec *bvec = bvec_init_iter_all(&iter_all);
0058 int zlib_init = 0, error = 0;
0059 z_stream *stream = strm;
0060
0061 stream->avail_out = PAGE_SIZE;
0062 stream->next_out = squashfs_first_page(output);
0063 stream->avail_in = 0;
0064
0065 if (IS_ERR(stream->next_out)) {
0066 error = PTR_ERR(stream->next_out);
0067 goto finish;
0068 }
0069
0070 for (;;) {
0071 int zlib_err;
0072
0073 if (stream->avail_in == 0) {
0074 const void *data;
0075 int avail;
0076
0077 if (!bio_next_segment(bio, &iter_all)) {
0078
0079 error = -EIO;
0080 break;
0081 }
0082
0083 avail = min(length, ((int)bvec->bv_len) - offset);
0084 data = bvec_virt(bvec);
0085 length -= avail;
0086 stream->next_in = data + offset;
0087 stream->avail_in = avail;
0088 offset = 0;
0089 }
0090
0091 if (stream->avail_out == 0) {
0092 stream->next_out = squashfs_next_page(output);
0093 if (IS_ERR(stream->next_out)) {
0094 error = PTR_ERR(stream->next_out);
0095 break;
0096 } else if (stream->next_out != NULL)
0097 stream->avail_out = PAGE_SIZE;
0098 }
0099
0100 if (!zlib_init) {
0101 zlib_err = zlib_inflateInit(stream);
0102 if (zlib_err != Z_OK) {
0103 error = -EIO;
0104 break;
0105 }
0106 zlib_init = 1;
0107 }
0108
0109 zlib_err = zlib_inflate(stream, Z_SYNC_FLUSH);
0110 if (zlib_err == Z_STREAM_END)
0111 break;
0112 if (zlib_err != Z_OK) {
0113 error = -EIO;
0114 break;
0115 }
0116 }
0117
0118 finish:
0119 squashfs_finish_page(output);
0120
0121 if (!error)
0122 if (zlib_inflateEnd(stream) != Z_OK)
0123 error = -EIO;
0124
0125 return error ? error : stream->total_out;
0126 }
0127
0128 const struct squashfs_decompressor squashfs_zlib_comp_ops = {
0129 .init = zlib_init,
0130 .free = zlib_free,
0131 .decompress = zlib_uncompress,
0132 .id = ZLIB_COMPRESSION,
0133 .name = "zlib",
0134 .alloc_buffer = 1,
0135 .supported = 1
0136 };
0137