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