Back to home page

OSCL-LXR

 
 

    


0001 // SPDX-License-Identifier: GPL-2.0-only
0002 /*
0003  * Copyright (c) 2013, 2014
0004  * Phillip Lougher <phillip@squashfs.org.uk>
0005  */
0006 
0007 #include <linux/bio.h>
0008 #include <linux/mutex.h>
0009 #include <linux/slab.h>
0010 #include <linux/vmalloc.h>
0011 #include <linux/lz4.h>
0012 
0013 #include "squashfs_fs.h"
0014 #include "squashfs_fs_sb.h"
0015 #include "squashfs.h"
0016 #include "decompressor.h"
0017 #include "page_actor.h"
0018 
0019 #define LZ4_LEGACY  1
0020 
0021 struct lz4_comp_opts {
0022     __le32 version;
0023     __le32 flags;
0024 };
0025 
0026 struct squashfs_lz4 {
0027     void *input;
0028     void *output;
0029 };
0030 
0031 
0032 static void *lz4_comp_opts(struct squashfs_sb_info *msblk,
0033     void *buff, int len)
0034 {
0035     struct lz4_comp_opts *comp_opts = buff;
0036 
0037     /* LZ4 compressed filesystems always have compression options */
0038     if (comp_opts == NULL || len < sizeof(*comp_opts))
0039         return ERR_PTR(-EIO);
0040 
0041     if (le32_to_cpu(comp_opts->version) != LZ4_LEGACY) {
0042         /* LZ4 format currently used by the kernel is the 'legacy'
0043          * format */
0044         ERROR("Unknown LZ4 version\n");
0045         return ERR_PTR(-EINVAL);
0046     }
0047 
0048     return NULL;
0049 }
0050 
0051 
0052 static void *lz4_init(struct squashfs_sb_info *msblk, void *buff)
0053 {
0054     int block_size = max_t(int, msblk->block_size, SQUASHFS_METADATA_SIZE);
0055     struct squashfs_lz4 *stream;
0056 
0057     stream = kzalloc(sizeof(*stream), GFP_KERNEL);
0058     if (stream == NULL)
0059         goto failed;
0060     stream->input = vmalloc(block_size);
0061     if (stream->input == NULL)
0062         goto failed2;
0063     stream->output = vmalloc(block_size);
0064     if (stream->output == NULL)
0065         goto failed3;
0066 
0067     return stream;
0068 
0069 failed3:
0070     vfree(stream->input);
0071 failed2:
0072     kfree(stream);
0073 failed:
0074     ERROR("Failed to initialise LZ4 decompressor\n");
0075     return ERR_PTR(-ENOMEM);
0076 }
0077 
0078 
0079 static void lz4_free(void *strm)
0080 {
0081     struct squashfs_lz4 *stream = strm;
0082 
0083     if (stream) {
0084         vfree(stream->input);
0085         vfree(stream->output);
0086     }
0087     kfree(stream);
0088 }
0089 
0090 
0091 static int lz4_uncompress(struct squashfs_sb_info *msblk, void *strm,
0092     struct bio *bio, int offset, int length,
0093     struct squashfs_page_actor *output)
0094 {
0095     struct bvec_iter_all iter_all = {};
0096     struct bio_vec *bvec = bvec_init_iter_all(&iter_all);
0097     struct squashfs_lz4 *stream = strm;
0098     void *buff = stream->input, *data;
0099     int bytes = length, res;
0100 
0101     while (bio_next_segment(bio, &iter_all)) {
0102         int avail = min(bytes, ((int)bvec->bv_len) - offset);
0103 
0104         data = bvec_virt(bvec);
0105         memcpy(buff, data + offset, avail);
0106         buff += avail;
0107         bytes -= avail;
0108         offset = 0;
0109     }
0110 
0111     res = LZ4_decompress_safe(stream->input, stream->output,
0112         length, output->length);
0113 
0114     if (res < 0)
0115         return -EIO;
0116 
0117     bytes = res;
0118     data = squashfs_first_page(output);
0119     buff = stream->output;
0120     while (data) {
0121         if (bytes <= PAGE_SIZE) {
0122             if (!IS_ERR(data))
0123                 memcpy(data, buff, bytes);
0124             break;
0125         }
0126         if (!IS_ERR(data))
0127             memcpy(data, buff, PAGE_SIZE);
0128         buff += PAGE_SIZE;
0129         bytes -= PAGE_SIZE;
0130         data = squashfs_next_page(output);
0131     }
0132     squashfs_finish_page(output);
0133 
0134     return res;
0135 }
0136 
0137 const struct squashfs_decompressor squashfs_lz4_comp_ops = {
0138     .init = lz4_init,
0139     .comp_opts = lz4_comp_opts,
0140     .free = lz4_free,
0141     .decompress = lz4_uncompress,
0142     .id = LZ4_COMPRESSION,
0143     .name = "lz4",
0144     .alloc_buffer = 0,
0145     .supported = 1
0146 };