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