1 // SPDX-License-Identifier: GPL-2.0-or-later 2 /* 3 * Squashfs - a compressed read only filesystem for Linux 4 * 5 * Copyright (c) 2010 LG Electronics 6 * Chan Jeong <chan.jeong@lge.com> 7 * 8 * lzo_wrapper.c 9 */ 10 11 #include <linux/mutex.h> 12 #include <linux/buffer_head.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(sizeof(*stream), GFP_KERNEL); 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 buffer_head **bh, int b, int offset, int length, 67 struct squashfs_page_actor *output) 68 { 69 struct squashfs_lzo *stream = strm; 70 void *buff = stream->input, *data; 71 int avail, i, bytes = length, res; 72 size_t out_len = output->length; 73 74 for (i = 0; i < b; i++) { 75 avail = min(bytes, msblk->devblksize - offset); 76 memcpy(buff, bh[i]->b_data + offset, avail); 77 buff += avail; 78 bytes -= avail; 79 offset = 0; 80 put_bh(bh[i]); 81 } 82 83 res = lzo1x_decompress_safe(stream->input, (size_t)length, 84 stream->output, &out_len); 85 if (res != LZO_E_OK) 86 goto failed; 87 88 res = bytes = (int)out_len; 89 data = squashfs_first_page(output); 90 buff = stream->output; 91 while (data) { 92 if (bytes <= PAGE_SIZE) { 93 memcpy(data, buff, bytes); 94 break; 95 } else { 96 memcpy(data, buff, PAGE_SIZE); 97 buff += PAGE_SIZE; 98 bytes -= PAGE_SIZE; 99 data = squashfs_next_page(output); 100 } 101 } 102 squashfs_finish_page(output); 103 104 return res; 105 106 failed: 107 return -EIO; 108 } 109 110 const struct squashfs_decompressor squashfs_lzo_comp_ops = { 111 .init = lzo_init, 112 .free = lzo_free, 113 .decompress = lzo_uncompress, 114 .id = LZO_COMPRESSION, 115 .name = "lzo", 116 .supported = 1 117 }; 118