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 * Compression vectors. 42 */ 43 zio_compress_info_t zio_compress_table[ZIO_COMPRESS_FUNCTIONS] = { 44 {"inherit", 0, NULL, NULL, NULL}, 45 {"on", 0, NULL, NULL, NULL}, 46 {"uncompressed", 0, NULL, NULL, NULL}, 47 {"lzjb", 0, 48 zfs_lzjb_compress, zfs_lzjb_decompress, NULL}, 49 {"empty", 0, NULL, NULL, NULL}, 50 {"gzip-1", 1, 51 zfs_gzip_compress, zfs_gzip_decompress, NULL}, 52 {"gzip-2", 2, 53 zfs_gzip_compress, zfs_gzip_decompress, NULL}, 54 {"gzip-3", 3, 55 zfs_gzip_compress, zfs_gzip_decompress, NULL}, 56 {"gzip-4", 4, 57 zfs_gzip_compress, zfs_gzip_decompress, NULL}, 58 {"gzip-5", 5, 59 zfs_gzip_compress, zfs_gzip_decompress, NULL}, 60 {"gzip-6", 6, 61 zfs_gzip_compress, zfs_gzip_decompress, NULL}, 62 {"gzip-7", 7, 63 zfs_gzip_compress, zfs_gzip_decompress, NULL}, 64 {"gzip-8", 8, 65 zfs_gzip_compress, zfs_gzip_decompress, NULL}, 66 {"gzip-9", 9, 67 zfs_gzip_compress, zfs_gzip_decompress, NULL}, 68 {"zle", 64, 69 zfs_zle_compress, zfs_zle_decompress, NULL}, 70 {"lz4", 0, 71 zfs_lz4_compress, zfs_lz4_decompress, NULL}, 72 {"zstd", ZIO_ZSTD_LEVEL_DEFAULT, 73 zfs_zstd_compress, zfs_zstd_decompress, zfs_zstd_decompress_level}, 74 }; 75 76 uint8_t 77 zio_complevel_select(spa_t *spa, enum zio_compress compress, uint8_t child, 78 uint8_t parent) 79 { 80 (void) spa; 81 uint8_t result; 82 83 if (!ZIO_COMPRESS_HASLEVEL(compress)) 84 return (0); 85 86 result = child; 87 if (result == ZIO_COMPLEVEL_INHERIT) 88 result = parent; 89 90 return (result); 91 } 92 93 enum zio_compress 94 zio_compress_select(spa_t *spa, enum zio_compress child, 95 enum zio_compress parent) 96 { 97 enum zio_compress result; 98 99 ASSERT(child < ZIO_COMPRESS_FUNCTIONS); 100 ASSERT(parent < ZIO_COMPRESS_FUNCTIONS); 101 ASSERT(parent != ZIO_COMPRESS_INHERIT); 102 103 result = child; 104 if (result == ZIO_COMPRESS_INHERIT) 105 result = parent; 106 107 if (result == ZIO_COMPRESS_ON) { 108 if (spa_feature_is_active(spa, SPA_FEATURE_LZ4_COMPRESS)) 109 result = ZIO_COMPRESS_LZ4_ON_VALUE; 110 else 111 result = ZIO_COMPRESS_LEGACY_ON_VALUE; 112 } 113 114 return (result); 115 } 116 117 size_t 118 zio_compress_data(enum zio_compress c, abd_t *src, abd_t **dst, size_t s_len, 119 size_t d_len, uint8_t level) 120 { 121 size_t c_len; 122 uint8_t complevel; 123 zio_compress_info_t *ci = &zio_compress_table[c]; 124 125 ASSERT3U(ci->ci_compress, !=, NULL); 126 ASSERT3U(s_len, >, 0); 127 128 complevel = ci->ci_level; 129 130 if (c == ZIO_COMPRESS_ZSTD) { 131 /* If we don't know the level, we can't compress it */ 132 if (level == ZIO_COMPLEVEL_INHERIT) 133 return (s_len); 134 135 if (level == ZIO_COMPLEVEL_DEFAULT) 136 complevel = ZIO_ZSTD_LEVEL_DEFAULT; 137 else 138 complevel = level; 139 140 ASSERT3U(complevel, !=, ZIO_COMPLEVEL_INHERIT); 141 } 142 143 if (*dst == NULL) 144 *dst = abd_alloc_sametype(src, s_len); 145 146 c_len = ci->ci_compress(src, *dst, s_len, d_len, complevel); 147 148 if (c_len > d_len) 149 return (s_len); 150 151 return (c_len); 152 } 153 154 int 155 zio_decompress_data(enum zio_compress c, abd_t *src, abd_t *dst, 156 size_t s_len, size_t d_len, uint8_t *level) 157 { 158 zio_compress_info_t *ci = &zio_compress_table[c]; 159 if ((uint_t)c >= ZIO_COMPRESS_FUNCTIONS || ci->ci_decompress == NULL) 160 return (SET_ERROR(EINVAL)); 161 162 int err; 163 if (ci->ci_decompress_level != NULL && level != NULL) 164 err = ci->ci_decompress_level(src, dst, s_len, d_len, level); 165 else 166 err = ci->ci_decompress(src, dst, s_len, d_len, ci->ci_level); 167 168 return (err); 169 } 170 171 int 172 zio_compress_to_feature(enum zio_compress comp) 173 { 174 switch (comp) { 175 case ZIO_COMPRESS_ZSTD: 176 return (SPA_FEATURE_ZSTD_COMPRESS); 177 default: 178 break; 179 } 180 return (SPA_FEATURE_NONE); 181 } 182