1eda14cbcSMatt Macy /* 2eda14cbcSMatt Macy * CDDL HEADER START 3eda14cbcSMatt Macy * 4eda14cbcSMatt Macy * The contents of this file are subject to the terms of the 5eda14cbcSMatt Macy * Common Development and Distribution License (the "License"). 6eda14cbcSMatt Macy * You may not use this file except in compliance with the License. 7eda14cbcSMatt Macy * 8eda14cbcSMatt Macy * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 9271171e0SMartin Matuska * or https://opensource.org/licenses/CDDL-1.0. 10eda14cbcSMatt Macy * See the License for the specific language governing permissions 11eda14cbcSMatt Macy * and limitations under the License. 12eda14cbcSMatt Macy * 13eda14cbcSMatt Macy * When distributing Covered Code, include this CDDL HEADER in each 14eda14cbcSMatt Macy * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 15eda14cbcSMatt Macy * If applicable, add the following below this CDDL HEADER, with the 16eda14cbcSMatt Macy * fields enclosed by brackets "[]" replaced with your own identifying 17eda14cbcSMatt Macy * information: Portions Copyright [yyyy] [name of copyright owner] 18eda14cbcSMatt Macy * 19eda14cbcSMatt Macy * CDDL HEADER END 20eda14cbcSMatt Macy */ 21eda14cbcSMatt Macy 22eda14cbcSMatt Macy /* 23eda14cbcSMatt Macy * Copyright 2009 Sun Microsystems, Inc. All rights reserved. 24eda14cbcSMatt Macy * Use is subject to license terms. 25eda14cbcSMatt Macy * Copyright (c) 2013 by Saso Kiselkov. All rights reserved. 26eda14cbcSMatt Macy * Copyright (c) 2013, 2018 by Delphix. All rights reserved. 27e2df9bb4SMartin Matuska * Copyright (c) 2019, 2024, Klara, Inc. 28eda14cbcSMatt Macy * Copyright (c) 2019, Allan Jude 29*7a7741afSMartin Matuska * Copyright (c) 2021, 2024 by George Melikov. All rights reserved. 30eda14cbcSMatt Macy */ 31eda14cbcSMatt Macy 32eda14cbcSMatt Macy #include <sys/zfs_context.h> 33eda14cbcSMatt Macy #include <sys/spa.h> 34eda14cbcSMatt Macy #include <sys/zfeature.h> 35eda14cbcSMatt Macy #include <sys/zio.h> 36eda14cbcSMatt Macy #include <sys/zio_compress.h> 37eda14cbcSMatt Macy #include <sys/zstd/zstd.h> 38eda14cbcSMatt Macy 39eda14cbcSMatt Macy /* 40eda14cbcSMatt Macy * If nonzero, every 1/X decompression attempts will fail, simulating 41eda14cbcSMatt Macy * an undetected memory error. 42eda14cbcSMatt Macy */ 43dbd5678dSMartin Matuska static unsigned long zio_decompress_fail_fraction = 0; 44eda14cbcSMatt Macy 45eda14cbcSMatt Macy /* 46eda14cbcSMatt Macy * Compression vectors. 47eda14cbcSMatt Macy */ 48be181ee2SMartin Matuska zio_compress_info_t zio_compress_table[ZIO_COMPRESS_FUNCTIONS] = { 49eda14cbcSMatt Macy {"inherit", 0, NULL, NULL, NULL}, 50eda14cbcSMatt Macy {"on", 0, NULL, NULL, NULL}, 51eda14cbcSMatt Macy {"uncompressed", 0, NULL, NULL, NULL}, 52e2df9bb4SMartin Matuska {"lzjb", 0, 53e2df9bb4SMartin Matuska zfs_lzjb_compress, zfs_lzjb_decompress, NULL}, 54eda14cbcSMatt Macy {"empty", 0, NULL, NULL, NULL}, 55e2df9bb4SMartin Matuska {"gzip-1", 1, 56e2df9bb4SMartin Matuska zfs_gzip_compress, zfs_gzip_decompress, NULL}, 57e2df9bb4SMartin Matuska {"gzip-2", 2, 58e2df9bb4SMartin Matuska zfs_gzip_compress, zfs_gzip_decompress, NULL}, 59e2df9bb4SMartin Matuska {"gzip-3", 3, 60e2df9bb4SMartin Matuska zfs_gzip_compress, zfs_gzip_decompress, NULL}, 61e2df9bb4SMartin Matuska {"gzip-4", 4, 62e2df9bb4SMartin Matuska zfs_gzip_compress, zfs_gzip_decompress, NULL}, 63e2df9bb4SMartin Matuska {"gzip-5", 5, 64e2df9bb4SMartin Matuska zfs_gzip_compress, zfs_gzip_decompress, NULL}, 65e2df9bb4SMartin Matuska {"gzip-6", 6, 66e2df9bb4SMartin Matuska zfs_gzip_compress, zfs_gzip_decompress, NULL}, 67e2df9bb4SMartin Matuska {"gzip-7", 7, 68e2df9bb4SMartin Matuska zfs_gzip_compress, zfs_gzip_decompress, NULL}, 69e2df9bb4SMartin Matuska {"gzip-8", 8, 70e2df9bb4SMartin Matuska zfs_gzip_compress, zfs_gzip_decompress, NULL}, 71e2df9bb4SMartin Matuska {"gzip-9", 9, 72e2df9bb4SMartin Matuska zfs_gzip_compress, zfs_gzip_decompress, NULL}, 73e2df9bb4SMartin Matuska {"zle", 64, 74e2df9bb4SMartin Matuska zfs_zle_compress, zfs_zle_decompress, NULL}, 75e2df9bb4SMartin Matuska {"lz4", 0, 76e2df9bb4SMartin Matuska zfs_lz4_compress, zfs_lz4_decompress, NULL}, 77e2df9bb4SMartin Matuska {"zstd", ZIO_ZSTD_LEVEL_DEFAULT, 78e2df9bb4SMartin Matuska zfs_zstd_compress, zfs_zstd_decompress, zfs_zstd_decompress_level}, 79eda14cbcSMatt Macy }; 80eda14cbcSMatt Macy 81eda14cbcSMatt Macy uint8_t 82eda14cbcSMatt Macy zio_complevel_select(spa_t *spa, enum zio_compress compress, uint8_t child, 83eda14cbcSMatt Macy uint8_t parent) 84eda14cbcSMatt Macy { 85e92ffd9bSMartin Matuska (void) spa; 86eda14cbcSMatt Macy uint8_t result; 87eda14cbcSMatt Macy 88eda14cbcSMatt Macy if (!ZIO_COMPRESS_HASLEVEL(compress)) 89eda14cbcSMatt Macy return (0); 90eda14cbcSMatt Macy 91eda14cbcSMatt Macy result = child; 92eda14cbcSMatt Macy if (result == ZIO_COMPLEVEL_INHERIT) 93eda14cbcSMatt Macy result = parent; 94eda14cbcSMatt Macy 95eda14cbcSMatt Macy return (result); 96eda14cbcSMatt Macy } 97eda14cbcSMatt Macy 98eda14cbcSMatt Macy enum zio_compress 99eda14cbcSMatt Macy zio_compress_select(spa_t *spa, enum zio_compress child, 100eda14cbcSMatt Macy enum zio_compress parent) 101eda14cbcSMatt Macy { 102eda14cbcSMatt Macy enum zio_compress result; 103eda14cbcSMatt Macy 104eda14cbcSMatt Macy ASSERT(child < ZIO_COMPRESS_FUNCTIONS); 105eda14cbcSMatt Macy ASSERT(parent < ZIO_COMPRESS_FUNCTIONS); 106eda14cbcSMatt Macy ASSERT(parent != ZIO_COMPRESS_INHERIT); 107eda14cbcSMatt Macy 108eda14cbcSMatt Macy result = child; 109eda14cbcSMatt Macy if (result == ZIO_COMPRESS_INHERIT) 110eda14cbcSMatt Macy result = parent; 111eda14cbcSMatt Macy 112eda14cbcSMatt Macy if (result == ZIO_COMPRESS_ON) { 113eda14cbcSMatt Macy if (spa_feature_is_active(spa, SPA_FEATURE_LZ4_COMPRESS)) 114eda14cbcSMatt Macy result = ZIO_COMPRESS_LZ4_ON_VALUE; 115eda14cbcSMatt Macy else 116eda14cbcSMatt Macy result = ZIO_COMPRESS_LEGACY_ON_VALUE; 117eda14cbcSMatt Macy } 118eda14cbcSMatt Macy 119eda14cbcSMatt Macy return (result); 120eda14cbcSMatt Macy } 121eda14cbcSMatt Macy 122eda14cbcSMatt Macy size_t 123e2df9bb4SMartin Matuska zio_compress_data(enum zio_compress c, abd_t *src, abd_t **dst, size_t s_len, 124*7a7741afSMartin Matuska size_t d_len, uint8_t level) 125eda14cbcSMatt Macy { 126*7a7741afSMartin Matuska size_t c_len; 127eda14cbcSMatt Macy uint8_t complevel; 128eda14cbcSMatt Macy zio_compress_info_t *ci = &zio_compress_table[c]; 129eda14cbcSMatt Macy 130ce4dcb97SMartin Matuska ASSERT3U(ci->ci_compress, !=, NULL); 131ce4dcb97SMartin Matuska ASSERT3U(s_len, >, 0); 132eda14cbcSMatt Macy 133eda14cbcSMatt Macy complevel = ci->ci_level; 134eda14cbcSMatt Macy 135eda14cbcSMatt Macy if (c == ZIO_COMPRESS_ZSTD) { 136eda14cbcSMatt Macy /* If we don't know the level, we can't compress it */ 137eda14cbcSMatt Macy if (level == ZIO_COMPLEVEL_INHERIT) 138eda14cbcSMatt Macy return (s_len); 139eda14cbcSMatt Macy 140eda14cbcSMatt Macy if (level == ZIO_COMPLEVEL_DEFAULT) 141eda14cbcSMatt Macy complevel = ZIO_ZSTD_LEVEL_DEFAULT; 142eda14cbcSMatt Macy else 143eda14cbcSMatt Macy complevel = level; 144eda14cbcSMatt Macy 145eda14cbcSMatt Macy ASSERT3U(complevel, !=, ZIO_COMPLEVEL_INHERIT); 146eda14cbcSMatt Macy } 147eda14cbcSMatt Macy 1482a58b312SMartin Matuska if (*dst == NULL) 149e2df9bb4SMartin Matuska *dst = abd_alloc_sametype(src, s_len); 1502a58b312SMartin Matuska 151e2df9bb4SMartin Matuska c_len = ci->ci_compress(src, *dst, s_len, d_len, complevel); 152eda14cbcSMatt Macy 153eda14cbcSMatt Macy if (c_len > d_len) 154eda14cbcSMatt Macy return (s_len); 155eda14cbcSMatt Macy 156eda14cbcSMatt Macy return (c_len); 157eda14cbcSMatt Macy } 158eda14cbcSMatt Macy 159eda14cbcSMatt Macy int 160e2df9bb4SMartin Matuska zio_decompress_data(enum zio_compress c, abd_t *src, abd_t *dst, 161eda14cbcSMatt Macy size_t s_len, size_t d_len, uint8_t *level) 162eda14cbcSMatt Macy { 163eda14cbcSMatt Macy zio_compress_info_t *ci = &zio_compress_table[c]; 164eda14cbcSMatt Macy if ((uint_t)c >= ZIO_COMPRESS_FUNCTIONS || ci->ci_decompress == NULL) 165eda14cbcSMatt Macy return (SET_ERROR(EINVAL)); 166eda14cbcSMatt Macy 167e2df9bb4SMartin Matuska int err; 168eda14cbcSMatt Macy if (ci->ci_decompress_level != NULL && level != NULL) 169e2df9bb4SMartin Matuska err = ci->ci_decompress_level(src, dst, s_len, d_len, level); 170e2df9bb4SMartin Matuska else 171e2df9bb4SMartin Matuska err = ci->ci_decompress(src, dst, s_len, d_len, ci->ci_level); 172eda14cbcSMatt Macy 173eda14cbcSMatt Macy /* 174eda14cbcSMatt Macy * Decompression shouldn't fail, because we've already verified 175eda14cbcSMatt Macy * the checksum. However, for extra protection (e.g. against bitflips 176eda14cbcSMatt Macy * in non-ECC RAM), we handle this error (and test it). 177eda14cbcSMatt Macy */ 178eda14cbcSMatt Macy if (zio_decompress_fail_fraction != 0 && 17933b8c039SMartin Matuska random_in_range(zio_decompress_fail_fraction) == 0) 180e2df9bb4SMartin Matuska err = SET_ERROR(EINVAL); 181eda14cbcSMatt Macy 182e2df9bb4SMartin Matuska return (err); 183eda14cbcSMatt Macy } 184eda14cbcSMatt Macy 185eda14cbcSMatt Macy int 186eda14cbcSMatt Macy zio_compress_to_feature(enum zio_compress comp) 187eda14cbcSMatt Macy { 188eda14cbcSMatt Macy switch (comp) { 189eda14cbcSMatt Macy case ZIO_COMPRESS_ZSTD: 190eda14cbcSMatt Macy return (SPA_FEATURE_ZSTD_COMPRESS); 191eda14cbcSMatt Macy default: 19253b70c86SMartin Matuska break; 193eda14cbcSMatt Macy } 194eda14cbcSMatt Macy return (SPA_FEATURE_NONE); 195eda14cbcSMatt Macy } 196