| 1 | |
| 2 | |
| 3 | * Squashfs - a compressed read only filesystem for Linux
|
| 4 | *
|
| 5 | * Copyright (c) 2010 LG Electronics
|
| 6 | * Chan Jeong <[email protected]>
|
| 7 | *
|
| 8 | * lzo_wrapper.c
|
| 9 |
|
| 10 |
|
| 11 | #include <linux/mutex.h>
|
| 12 | #include <linux/bio.h>
|
| 13 | #include <linux/slab.h>
|
| 14 | #include <linux/vmalloc.h>
|
| 15 | #include <linux/lzo.h>
|
| 16 |
|
| 17 | #include "squashfs_fs.h"
|
| 18 | #include "squashfs_fs_sb.h"
|
| 19 | #include "squashfs.h"
|
| 20 | #include "decompressor.h"
|
| 21 | #include "page_actor.h"
|
| 22 |
|
| 23 | struct squashfs_lzo {
|
| 24 | void *input;
|
| 25 | void *output;
|
| 26 | };
|
| 27 |
|
| 28 | static void *lzo_init(struct squashfs_sb_info *msblk, void *buff)
|
| 29 | {
|
| 30 | int block_size = max_t(int, msblk->block_size, SQUASHFS_METADATA_SIZE);
|
| 31 |
|
| 32 | struct squashfs_lzo *stream = kzalloc_obj(*stream);
|
| 33 | if (stream == NULL)
|
| 34 | goto failed;
|
| 35 | stream->input = vmalloc(block_size);
|
| 36 | if (stream->input == NULL)
|
| 37 | goto failed;
|
| 38 | stream->output = vmalloc(block_size);
|
| 39 | if (stream->output == NULL)
|
| 40 | goto failed2;
|
| 41 |
|
| 42 | return stream;
|
| 43 |
|
| 44 | failed2:
|
| 45 | vfree(stream->input);
|
| 46 | failed:
|
| 47 | ERROR("Failed to allocate lzo workspace\n");
|
| 48 | kfree(stream);
|
| 49 | return ERR_PTR(-ENOMEM);
|
| 50 | }
|
| 51 |
|
| 52 |
|
| 53 | static void lzo_free(void *strm)
|
| 54 | {
|
| 55 | struct squashfs_lzo *stream = strm;
|
| 56 |
|
| 57 | if (stream) {
|
| 58 | vfree(stream->input);
|
| 59 | vfree(stream->output);
|
| 60 | }
|
| 61 | kfree(stream);
|
| 62 | }
|
| 63 |
|
| 64 |
|
| 65 | static int lzo_uncompress(struct squashfs_sb_info *msblk, void *strm,
|
| 66 | struct bio *bio, int offset, int length,
|
| 67 | struct squashfs_page_actor *output)
|
| 68 | {
|
| 69 | struct bvec_iter_all iter_all = {};
|
| 70 | struct bio_vec *bvec = bvec_init_iter_all(&iter_all);
|
| 71 | struct squashfs_lzo *stream = strm;
|
| 72 | void *buff = stream->input, *data;
|
| 73 | int bytes = length, res;
|
| 74 | size_t out_len = output->length;
|
| 75 |
|
| 76 | while (bio_next_segment(bio, &iter_all)) {
|
| 77 | int avail = min(bytes, ((int)bvec->bv_len) - offset);
|
| 78 |
|
| 79 | data = bvec_virt(bvec);
|
| 80 | memcpy(buff, data + offset, avail);
|
| 81 | buff += avail;
|
| 82 | bytes -= avail;
|
| 83 | offset = 0;
|
| 84 | }
|
| 85 |
|
| 86 | res = lzo1x_decompress_safe(stream->input, (size_t)length,
|
| 87 | stream->output, &out_len);
|
| 88 | if (res != LZO_E_OK)
|
| 89 | goto failed;
|
| 90 |
|
| 91 | res = bytes = (int)out_len;
|
| 92 | data = squashfs_first_page(output);
|
| 93 | buff = stream->output;
|
| 94 | while (data) {
|
| 95 | if (bytes <= PAGE_SIZE) {
|
| 96 | if (!IS_ERR(data))
|
| 97 | memcpy(data, buff, bytes);
|
| 98 | break;
|
| 99 | } else {
|
| 100 | if (!IS_ERR(data))
|
| 101 | memcpy(data, buff, PAGE_SIZE);
|
| 102 | buff += PAGE_SIZE;
|
| 103 | bytes -= PAGE_SIZE;
|
| 104 | data = squashfs_next_page(output);
|
| 105 | }
|
| 106 | }
|
| 107 | squashfs_finish_page(output);
|
| 108 |
|
| 109 | return res;
|
| 110 |
|
| 111 | failed:
|
| 112 | return -EIO;
|
| 113 | }
|
| 114 |
|
| 115 | const struct squashfs_decompressor squashfs_lzo_comp_ops = {
|
| 116 | .init = lzo_init,
|
| 117 | .free = lzo_free,
|
| 118 | .decompress = lzo_uncompress,
|
| 119 | .id = LZO_COMPRESSION,
|
| 120 | .name = "lzo",
|
| 121 | .alloc_buffer = 0,
|
| 122 | .supported = 1
|
| 123 | };
|