Blame view
fs/squashfs/lz4_wrapper.c
2.89 KB
9c06a46f1 Squashfs: add LZ4... |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 |
/* * Copyright (c) 2013, 2014 * Phillip Lougher <phillip@squashfs.org.uk> * * This work is licensed under the terms of the GNU GPL, version 2. See * the COPYING file in the top-level directory. */ #include <linux/buffer_head.h> #include <linux/mutex.h> #include <linux/slab.h> #include <linux/vmalloc.h> #include <linux/lz4.h> #include "squashfs_fs.h" #include "squashfs_fs_sb.h" #include "squashfs.h" #include "decompressor.h" #include "page_actor.h" #define LZ4_LEGACY 1 struct lz4_comp_opts { __le32 version; __le32 flags; }; struct squashfs_lz4 { void *input; void *output; }; static void *lz4_comp_opts(struct squashfs_sb_info *msblk, void *buff, int len) { struct lz4_comp_opts *comp_opts = buff; /* LZ4 compressed filesystems always have compression options */ if (comp_opts == NULL || len < sizeof(*comp_opts)) return ERR_PTR(-EIO); if (le32_to_cpu(comp_opts->version) != LZ4_LEGACY) { /* LZ4 format currently used by the kernel is the 'legacy' * format */ ERROR("Unknown LZ4 version "); return ERR_PTR(-EINVAL); } return NULL; } static void *lz4_init(struct squashfs_sb_info *msblk, void *buff) { int block_size = max_t(int, msblk->block_size, SQUASHFS_METADATA_SIZE); struct squashfs_lz4 *stream; stream = kzalloc(sizeof(*stream), GFP_KERNEL); if (stream == NULL) goto failed; stream->input = vmalloc(block_size); if (stream->input == NULL) goto failed2; stream->output = vmalloc(block_size); if (stream->output == NULL) goto failed3; return stream; failed3: vfree(stream->input); failed2: kfree(stream); failed: ERROR("Failed to initialise LZ4 decompressor "); return ERR_PTR(-ENOMEM); } static void lz4_free(void *strm) { struct squashfs_lz4 *stream = strm; if (stream) { vfree(stream->input); vfree(stream->output); } kfree(stream); } static int lz4_uncompress(struct squashfs_sb_info *msblk, void *strm, struct buffer_head **bh, int b, int offset, int length, struct squashfs_page_actor *output) { struct squashfs_lz4 *stream = strm; void *buff = stream->input, *data; int avail, i, bytes = length, res; |
9c06a46f1 Squashfs: add LZ4... |
102 103 104 105 106 107 108 109 110 |
for (i = 0; i < b; i++) { avail = min(bytes, msblk->devblksize - offset); memcpy(buff, bh[i]->b_data + offset, avail); buff += avail; bytes -= avail; offset = 0; put_bh(bh[i]); } |
d21b5ff12 fs/pstore: fs/squ... |
111 112 113 114 |
res = LZ4_decompress_safe(stream->input, stream->output, length, output->length); if (res < 0) |
9c06a46f1 Squashfs: add LZ4... |
115 |
return -EIO; |
d21b5ff12 fs/pstore: fs/squ... |
116 |
bytes = res; |
9c06a46f1 Squashfs: add LZ4... |
117 118 119 |
data = squashfs_first_page(output); buff = stream->output; while (data) { |
09cbfeaf1 mm, fs: get rid o... |
120 |
if (bytes <= PAGE_SIZE) { |
9c06a46f1 Squashfs: add LZ4... |
121 122 123 |
memcpy(data, buff, bytes); break; } |
09cbfeaf1 mm, fs: get rid o... |
124 125 126 |
memcpy(data, buff, PAGE_SIZE); buff += PAGE_SIZE; bytes -= PAGE_SIZE; |
9c06a46f1 Squashfs: add LZ4... |
127 128 129 |
data = squashfs_next_page(output); } squashfs_finish_page(output); |
d21b5ff12 fs/pstore: fs/squ... |
130 |
return res; |
9c06a46f1 Squashfs: add LZ4... |
131 132 133 134 135 136 137 138 139 140 141 |
} const struct squashfs_decompressor squashfs_lz4_comp_ops = { .init = lz4_init, .comp_opts = lz4_comp_opts, .free = lz4_free, .decompress = lz4_uncompress, .id = LZ4_COMPRESSION, .name = "lz4", .supported = 1 }; |