0001
0002
0003
0004
0005
0006
0007
0008
0009
0010
0011 #include <linux/mutex.h>
0012 #include <linux/bio.h>
0013 #include <linux/slab.h>
0014 #include <linux/zstd.h>
0015 #include <linux/vmalloc.h>
0016
0017 #include "squashfs_fs.h"
0018 #include "squashfs_fs_sb.h"
0019 #include "squashfs.h"
0020 #include "decompressor.h"
0021 #include "page_actor.h"
0022
0023 struct workspace {
0024 void *mem;
0025 size_t mem_size;
0026 size_t window_size;
0027 };
0028
0029 static void *zstd_init(struct squashfs_sb_info *msblk, void *buff)
0030 {
0031 struct workspace *wksp = kmalloc(sizeof(*wksp), GFP_KERNEL);
0032
0033 if (wksp == NULL)
0034 goto failed;
0035 wksp->window_size = max_t(size_t,
0036 msblk->block_size, SQUASHFS_METADATA_SIZE);
0037 wksp->mem_size = zstd_dstream_workspace_bound(wksp->window_size);
0038 wksp->mem = vmalloc(wksp->mem_size);
0039 if (wksp->mem == NULL)
0040 goto failed;
0041
0042 return wksp;
0043
0044 failed:
0045 ERROR("Failed to allocate zstd workspace\n");
0046 kfree(wksp);
0047 return ERR_PTR(-ENOMEM);
0048 }
0049
0050
0051 static void zstd_free(void *strm)
0052 {
0053 struct workspace *wksp = strm;
0054
0055 if (wksp)
0056 vfree(wksp->mem);
0057 kfree(wksp);
0058 }
0059
0060
0061 static int zstd_uncompress(struct squashfs_sb_info *msblk, void *strm,
0062 struct bio *bio, int offset, int length,
0063 struct squashfs_page_actor *output)
0064 {
0065 struct workspace *wksp = strm;
0066 zstd_dstream *stream;
0067 size_t total_out = 0;
0068 int error = 0;
0069 zstd_in_buffer in_buf = { NULL, 0, 0 };
0070 zstd_out_buffer out_buf = { NULL, 0, 0 };
0071 struct bvec_iter_all iter_all = {};
0072 struct bio_vec *bvec = bvec_init_iter_all(&iter_all);
0073
0074 stream = zstd_init_dstream(wksp->window_size, wksp->mem, wksp->mem_size);
0075
0076 if (!stream) {
0077 ERROR("Failed to initialize zstd decompressor\n");
0078 return -EIO;
0079 }
0080
0081 out_buf.size = PAGE_SIZE;
0082 out_buf.dst = squashfs_first_page(output);
0083 if (IS_ERR(out_buf.dst)) {
0084 error = PTR_ERR(out_buf.dst);
0085 goto finish;
0086 }
0087
0088 for (;;) {
0089 size_t zstd_err;
0090
0091 if (in_buf.pos == in_buf.size) {
0092 const void *data;
0093 int avail;
0094
0095 if (!bio_next_segment(bio, &iter_all)) {
0096 error = -EIO;
0097 break;
0098 }
0099
0100 avail = min(length, ((int)bvec->bv_len) - offset);
0101 data = bvec_virt(bvec);
0102 length -= avail;
0103 in_buf.src = data + offset;
0104 in_buf.size = avail;
0105 in_buf.pos = 0;
0106 offset = 0;
0107 }
0108
0109 if (out_buf.pos == out_buf.size) {
0110 out_buf.dst = squashfs_next_page(output);
0111 if (IS_ERR(out_buf.dst)) {
0112 error = PTR_ERR(out_buf.dst);
0113 break;
0114 } else if (out_buf.dst == NULL) {
0115
0116
0117
0118 error = -EIO;
0119 break;
0120 }
0121 out_buf.pos = 0;
0122 out_buf.size = PAGE_SIZE;
0123 }
0124
0125 total_out -= out_buf.pos;
0126 zstd_err = zstd_decompress_stream(stream, &out_buf, &in_buf);
0127 total_out += out_buf.pos;
0128 if (zstd_err == 0)
0129 break;
0130
0131 if (zstd_is_error(zstd_err)) {
0132 ERROR("zstd decompression error: %d\n",
0133 (int)zstd_get_error_code(zstd_err));
0134 error = -EIO;
0135 break;
0136 }
0137 }
0138
0139 finish:
0140
0141 squashfs_finish_page(output);
0142
0143 return error ? error : total_out;
0144 }
0145
0146 const struct squashfs_decompressor squashfs_zstd_comp_ops = {
0147 .init = zstd_init,
0148 .free = zstd_free,
0149 .decompress = zstd_uncompress,
0150 .id = ZSTD_COMPRESSION,
0151 .name = "zstd",
0152 .alloc_buffer = 1,
0153 .supported = 1
0154 };