^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1) // SPDX-License-Identifier: GPL-2.0-or-later
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3) * Squashfs - a compressed read only filesystem for Linux
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 4) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 5) * Copyright (c) 2016-present, Facebook, Inc.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 6) * All rights reserved.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 7) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 8) * zstd_wrapper.c
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 9) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 10)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 11) #include <linux/mutex.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 12) #include <linux/bio.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 13) #include <linux/slab.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 14) #include <linux/zstd.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 15) #include <linux/vmalloc.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 16)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 17) #include "squashfs_fs.h"
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 18) #include "squashfs_fs_sb.h"
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 19) #include "squashfs.h"
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 20) #include "decompressor.h"
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 21) #include "page_actor.h"
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 22)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 23) struct workspace {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 24) void *mem;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 25) size_t mem_size;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 26) size_t window_size;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 27) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 28)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 29) static void *zstd_init(struct squashfs_sb_info *msblk, void *buff)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 30) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 31) struct workspace *wksp = kmalloc(sizeof(*wksp), GFP_KERNEL);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 32)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 33) if (wksp == NULL)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 34) goto failed;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 35) wksp->window_size = max_t(size_t,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 36) msblk->block_size, SQUASHFS_METADATA_SIZE);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 37) wksp->mem_size = ZSTD_DStreamWorkspaceBound(wksp->window_size);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 38) wksp->mem = vmalloc(wksp->mem_size);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 39) if (wksp->mem == NULL)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 40) goto failed;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 41)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 42) return wksp;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 43)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 44) failed:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 45) ERROR("Failed to allocate zstd workspace\n");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 46) kfree(wksp);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 47) return ERR_PTR(-ENOMEM);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 48) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 49)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 50)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 51) static void zstd_free(void *strm)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 52) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 53) struct workspace *wksp = strm;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 54)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 55) if (wksp)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 56) vfree(wksp->mem);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 57) kfree(wksp);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 58) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 59)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 60)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 61) static int zstd_uncompress(struct squashfs_sb_info *msblk, void *strm,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 62) struct bio *bio, int offset, int length,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 63) struct squashfs_page_actor *output)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 64) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 65) struct workspace *wksp = strm;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 66) ZSTD_DStream *stream;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 67) size_t total_out = 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 68) int error = 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 69) ZSTD_inBuffer in_buf = { NULL, 0, 0 };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 70) ZSTD_outBuffer out_buf = { NULL, 0, 0 };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 71) struct bvec_iter_all iter_all = {};
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 72) struct bio_vec *bvec = bvec_init_iter_all(&iter_all);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 73)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 74) stream = ZSTD_initDStream(wksp->window_size, wksp->mem, wksp->mem_size);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 75)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 76) if (!stream) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 77) ERROR("Failed to initialize zstd decompressor\n");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 78) return -EIO;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 79) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 80)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 81) out_buf.size = PAGE_SIZE;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 82) out_buf.dst = squashfs_first_page(output);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 83)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 84) for (;;) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 85) size_t zstd_err;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 86)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 87) if (in_buf.pos == in_buf.size) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 88) const void *data;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 89) int avail;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 90)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 91) if (!bio_next_segment(bio, &iter_all)) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 92) error = -EIO;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 93) break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 94) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 95)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 96) avail = min(length, ((int)bvec->bv_len) - offset);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 97) data = page_address(bvec->bv_page) + bvec->bv_offset;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 98) length -= avail;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 99) in_buf.src = data + offset;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 100) in_buf.size = avail;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 101) in_buf.pos = 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 102) offset = 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 103) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 104)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 105) if (out_buf.pos == out_buf.size) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 106) out_buf.dst = squashfs_next_page(output);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 107) if (out_buf.dst == NULL) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 108) /* Shouldn't run out of pages
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 109) * before stream is done.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 110) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 111) error = -EIO;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 112) break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 113) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 114) out_buf.pos = 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 115) out_buf.size = PAGE_SIZE;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 116) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 117)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 118) total_out -= out_buf.pos;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 119) zstd_err = ZSTD_decompressStream(stream, &out_buf, &in_buf);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 120) total_out += out_buf.pos; /* add the additional data produced */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 121) if (zstd_err == 0)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 122) break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 123)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 124) if (ZSTD_isError(zstd_err)) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 125) ERROR("zstd decompression error: %d\n",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 126) (int)ZSTD_getErrorCode(zstd_err));
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 127) error = -EIO;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 128) break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 129) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 130) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 131)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 132) squashfs_finish_page(output);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 133)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 134) return error ? error : total_out;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 135) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 136)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 137) const struct squashfs_decompressor squashfs_zstd_comp_ops = {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 138) .init = zstd_init,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 139) .free = zstd_free,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 140) .decompress = zstd_uncompress,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 141) .id = ZSTD_COMPRESSION,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 142) .name = "zstd",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 143) .supported = 1
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 144) };