1/* 2 * Squashfs - a compressed read only filesystem for Linux 3 * 4 * Copyright (c) 2010 LG Electronics 5 * Chan Jeong <chan.jeong@lge.com> 6 * 7 * This program is free software; you can redistribute it and/or 8 * modify it under the terms of the GNU General Public License 9 * as published by the Free Software Foundation; either version 2, 10 * or (at your option) any later version. 11 * 12 * This program is distributed in the hope that it will be useful, 13 * but WITHOUT ANY WARRANTY; without even the implied warranty of 14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 15 * GNU General Public License for more details. 16 * 17 * You should have received a copy of the GNU General Public License 18 * along with this program; if not, write to the Free Software 19 * Foundation, 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. 20 * 21 * lzo_wrapper.c 22 */ 23 24#include <linux/mutex.h> 25#include <linux/buffer_head.h> 26#include <linux/slab.h> 27#include <linux/vmalloc.h> 28#include <linux/lzo.h> 29 30#include "squashfs_fs.h" 31#include "squashfs_fs_sb.h" 32#include "squashfs.h" 33#include "decompressor.h" 34#include "page_actor.h" 35 36struct squashfs_lzo { 37 void *input; 38 void *output; 39}; 40 41static void *lzo_init(struct squashfs_sb_info *msblk, void *buff) 42{ 43 int block_size = max_t(int, msblk->block_size, SQUASHFS_METADATA_SIZE); 44 45 struct squashfs_lzo *stream = kzalloc(sizeof(*stream), GFP_KERNEL); 46 if (stream == NULL) 47 goto failed; 48 stream->input = vmalloc(block_size); 49 if (stream->input == NULL) 50 goto failed; 51 stream->output = vmalloc(block_size); 52 if (stream->output == NULL) 53 goto failed2; 54 55 return stream; 56 57failed2: 58 vfree(stream->input); 59failed: 60 ERROR("Failed to allocate lzo workspace\n"); 61 kfree(stream); 62 return ERR_PTR(-ENOMEM); 63} 64 65 66static void lzo_free(void *strm) 67{ 68 struct squashfs_lzo *stream = strm; 69 70 if (stream) { 71 vfree(stream->input); 72 vfree(stream->output); 73 } 74 kfree(stream); 75} 76 77 78static int lzo_uncompress(struct squashfs_sb_info *msblk, void *strm, 79 struct buffer_head **bh, int b, int offset, int length, 80 struct squashfs_page_actor *output) 81{ 82 struct squashfs_lzo *stream = strm; 83 void *buff = stream->input, *data; 84 int avail, i, bytes = length, res; 85 size_t out_len = output->length; 86 87 for (i = 0; i < b; i++) { 88 avail = min(bytes, msblk->devblksize - offset); 89 memcpy(buff, bh[i]->b_data + offset, avail); 90 buff += avail; 91 bytes -= avail; 92 offset = 0; 93 put_bh(bh[i]); 94 } 95 96 res = lzo1x_decompress_safe(stream->input, (size_t)length, 97 stream->output, &out_len); 98 if (res != LZO_E_OK) 99 goto failed; 100 101 res = bytes = (int)out_len; 102 data = squashfs_first_page(output); 103 buff = stream->output; 104 while (data) { 105 if (bytes <= PAGE_CACHE_SIZE) { 106 memcpy(data, buff, bytes); 107 break; 108 } else { 109 memcpy(data, buff, PAGE_CACHE_SIZE); 110 buff += PAGE_CACHE_SIZE; 111 bytes -= PAGE_CACHE_SIZE; 112 data = squashfs_next_page(output); 113 } 114 } 115 squashfs_finish_page(output); 116 117 return res; 118 119failed: 120 return -EIO; 121} 122 123const struct squashfs_decompressor squashfs_lzo_comp_ops = { 124 .init = lzo_init, 125 .free = lzo_free, 126 .decompress = lzo_uncompress, 127 .id = LZO_COMPRESSION, 128 .name = "lzo", 129 .supported = 1 130}; 131