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 */ 26eda14cbcSMatt Macy /* 27eda14cbcSMatt Macy * Copyright (c) 2013 by Saso Kiselkov. All rights reserved. 28eda14cbcSMatt Macy */ 29eda14cbcSMatt Macy 30eda14cbcSMatt Macy /* 31eda14cbcSMatt Macy * Copyright (c) 2013, 2018 by Delphix. All rights reserved. 32eda14cbcSMatt Macy * Copyright (c) 2019, Klara Inc. 33eda14cbcSMatt Macy * Copyright (c) 2019, Allan Jude 34eda14cbcSMatt Macy */ 35eda14cbcSMatt Macy 36eda14cbcSMatt Macy #include <sys/zfs_context.h> 37eda14cbcSMatt Macy #include <sys/spa.h> 38eda14cbcSMatt Macy #include <sys/zfeature.h> 39eda14cbcSMatt Macy #include <sys/zio.h> 40eda14cbcSMatt Macy #include <sys/zio_compress.h> 41eda14cbcSMatt Macy #include <sys/zstd/zstd.h> 42eda14cbcSMatt Macy 43eda14cbcSMatt Macy /* 44eda14cbcSMatt Macy * If nonzero, every 1/X decompression attempts will fail, simulating 45eda14cbcSMatt Macy * an undetected memory error. 46eda14cbcSMatt Macy */ 47dbd5678dSMartin Matuska static unsigned long zio_decompress_fail_fraction = 0; 48eda14cbcSMatt Macy 49eda14cbcSMatt Macy /* 50eda14cbcSMatt Macy * Compression vectors. 51eda14cbcSMatt Macy */ 52be181ee2SMartin Matuska zio_compress_info_t zio_compress_table[ZIO_COMPRESS_FUNCTIONS] = { 53eda14cbcSMatt Macy {"inherit", 0, NULL, NULL, NULL}, 54eda14cbcSMatt Macy {"on", 0, NULL, NULL, NULL}, 55eda14cbcSMatt Macy {"uncompressed", 0, NULL, NULL, NULL}, 56eda14cbcSMatt Macy {"lzjb", 0, lzjb_compress, lzjb_decompress, NULL}, 57eda14cbcSMatt Macy {"empty", 0, NULL, NULL, NULL}, 58eda14cbcSMatt Macy {"gzip-1", 1, gzip_compress, gzip_decompress, NULL}, 59eda14cbcSMatt Macy {"gzip-2", 2, gzip_compress, gzip_decompress, NULL}, 60eda14cbcSMatt Macy {"gzip-3", 3, gzip_compress, gzip_decompress, NULL}, 61eda14cbcSMatt Macy {"gzip-4", 4, gzip_compress, gzip_decompress, NULL}, 62eda14cbcSMatt Macy {"gzip-5", 5, gzip_compress, gzip_decompress, NULL}, 63eda14cbcSMatt Macy {"gzip-6", 6, gzip_compress, gzip_decompress, NULL}, 64eda14cbcSMatt Macy {"gzip-7", 7, gzip_compress, gzip_decompress, NULL}, 65eda14cbcSMatt Macy {"gzip-8", 8, gzip_compress, gzip_decompress, NULL}, 66eda14cbcSMatt Macy {"gzip-9", 9, gzip_compress, gzip_decompress, NULL}, 67eda14cbcSMatt Macy {"zle", 64, zle_compress, zle_decompress, NULL}, 68eda14cbcSMatt Macy {"lz4", 0, lz4_compress_zfs, lz4_decompress_zfs, NULL}, 69e3aa18adSMartin Matuska {"zstd", ZIO_ZSTD_LEVEL_DEFAULT, zfs_zstd_compress_wrap, 70eda14cbcSMatt Macy zfs_zstd_decompress, zfs_zstd_decompress_level}, 71eda14cbcSMatt Macy }; 72eda14cbcSMatt Macy 73eda14cbcSMatt Macy uint8_t 74eda14cbcSMatt Macy zio_complevel_select(spa_t *spa, enum zio_compress compress, uint8_t child, 75eda14cbcSMatt Macy uint8_t parent) 76eda14cbcSMatt Macy { 77e92ffd9bSMartin Matuska (void) spa; 78eda14cbcSMatt Macy uint8_t result; 79eda14cbcSMatt Macy 80eda14cbcSMatt Macy if (!ZIO_COMPRESS_HASLEVEL(compress)) 81eda14cbcSMatt Macy return (0); 82eda14cbcSMatt Macy 83eda14cbcSMatt Macy result = child; 84eda14cbcSMatt Macy if (result == ZIO_COMPLEVEL_INHERIT) 85eda14cbcSMatt Macy result = parent; 86eda14cbcSMatt Macy 87eda14cbcSMatt Macy return (result); 88eda14cbcSMatt Macy } 89eda14cbcSMatt Macy 90eda14cbcSMatt Macy enum zio_compress 91eda14cbcSMatt Macy zio_compress_select(spa_t *spa, enum zio_compress child, 92eda14cbcSMatt Macy enum zio_compress parent) 93eda14cbcSMatt Macy { 94eda14cbcSMatt Macy enum zio_compress result; 95eda14cbcSMatt Macy 96eda14cbcSMatt Macy ASSERT(child < ZIO_COMPRESS_FUNCTIONS); 97eda14cbcSMatt Macy ASSERT(parent < ZIO_COMPRESS_FUNCTIONS); 98eda14cbcSMatt Macy ASSERT(parent != ZIO_COMPRESS_INHERIT); 99eda14cbcSMatt Macy 100eda14cbcSMatt Macy result = child; 101eda14cbcSMatt Macy if (result == ZIO_COMPRESS_INHERIT) 102eda14cbcSMatt Macy result = parent; 103eda14cbcSMatt Macy 104eda14cbcSMatt Macy if (result == ZIO_COMPRESS_ON) { 105eda14cbcSMatt Macy if (spa_feature_is_active(spa, SPA_FEATURE_LZ4_COMPRESS)) 106eda14cbcSMatt Macy result = ZIO_COMPRESS_LZ4_ON_VALUE; 107eda14cbcSMatt Macy else 108eda14cbcSMatt Macy result = ZIO_COMPRESS_LEGACY_ON_VALUE; 109eda14cbcSMatt Macy } 110eda14cbcSMatt Macy 111eda14cbcSMatt Macy return (result); 112eda14cbcSMatt Macy } 113eda14cbcSMatt Macy 114eda14cbcSMatt Macy static int 115eda14cbcSMatt Macy zio_compress_zeroed_cb(void *data, size_t len, void *private) 116eda14cbcSMatt Macy { 117e92ffd9bSMartin Matuska (void) private; 118e92ffd9bSMartin Matuska 119eda14cbcSMatt Macy uint64_t *end = (uint64_t *)((char *)data + len); 120eda14cbcSMatt Macy for (uint64_t *word = (uint64_t *)data; word < end; word++) 121eda14cbcSMatt Macy if (*word != 0) 122eda14cbcSMatt Macy return (1); 123eda14cbcSMatt Macy 124eda14cbcSMatt Macy return (0); 125eda14cbcSMatt Macy } 126eda14cbcSMatt Macy 127eda14cbcSMatt Macy size_t 128*2a58b312SMartin Matuska zio_compress_data(enum zio_compress c, abd_t *src, void **dst, size_t s_len, 129eda14cbcSMatt Macy uint8_t level) 130eda14cbcSMatt Macy { 131eda14cbcSMatt Macy size_t c_len, d_len; 132eda14cbcSMatt Macy uint8_t complevel; 133eda14cbcSMatt Macy zio_compress_info_t *ci = &zio_compress_table[c]; 134eda14cbcSMatt Macy 135eda14cbcSMatt Macy ASSERT((uint_t)c < ZIO_COMPRESS_FUNCTIONS); 136eda14cbcSMatt Macy ASSERT((uint_t)c == ZIO_COMPRESS_EMPTY || ci->ci_compress != NULL); 137eda14cbcSMatt Macy 138eda14cbcSMatt Macy /* 139eda14cbcSMatt Macy * If the data is all zeroes, we don't even need to allocate 140eda14cbcSMatt Macy * a block for it. We indicate this by returning zero size. 141eda14cbcSMatt Macy */ 142eda14cbcSMatt Macy if (abd_iterate_func(src, 0, s_len, zio_compress_zeroed_cb, NULL) == 0) 143eda14cbcSMatt Macy return (0); 144eda14cbcSMatt Macy 145eda14cbcSMatt Macy if (c == ZIO_COMPRESS_EMPTY) 146eda14cbcSMatt Macy return (s_len); 147eda14cbcSMatt Macy 148eda14cbcSMatt Macy /* Compress at least 12.5% */ 149eda14cbcSMatt Macy d_len = s_len - (s_len >> 3); 150eda14cbcSMatt Macy 151eda14cbcSMatt Macy complevel = ci->ci_level; 152eda14cbcSMatt Macy 153eda14cbcSMatt Macy if (c == ZIO_COMPRESS_ZSTD) { 154eda14cbcSMatt Macy /* If we don't know the level, we can't compress it */ 155eda14cbcSMatt Macy if (level == ZIO_COMPLEVEL_INHERIT) 156eda14cbcSMatt Macy return (s_len); 157eda14cbcSMatt Macy 158eda14cbcSMatt Macy if (level == ZIO_COMPLEVEL_DEFAULT) 159eda14cbcSMatt Macy complevel = ZIO_ZSTD_LEVEL_DEFAULT; 160eda14cbcSMatt Macy else 161eda14cbcSMatt Macy complevel = level; 162eda14cbcSMatt Macy 163eda14cbcSMatt Macy ASSERT3U(complevel, !=, ZIO_COMPLEVEL_INHERIT); 164eda14cbcSMatt Macy } 165eda14cbcSMatt Macy 166*2a58b312SMartin Matuska if (*dst == NULL) 167*2a58b312SMartin Matuska *dst = zio_buf_alloc(s_len); 168*2a58b312SMartin Matuska 169eda14cbcSMatt Macy /* No compression algorithms can read from ABDs directly */ 170eda14cbcSMatt Macy void *tmp = abd_borrow_buf_copy(src, s_len); 171*2a58b312SMartin Matuska c_len = ci->ci_compress(tmp, *dst, s_len, d_len, complevel); 172eda14cbcSMatt Macy abd_return_buf(src, tmp, s_len); 173eda14cbcSMatt Macy 174eda14cbcSMatt Macy if (c_len > d_len) 175eda14cbcSMatt Macy return (s_len); 176eda14cbcSMatt Macy 177eda14cbcSMatt Macy ASSERT3U(c_len, <=, d_len); 178eda14cbcSMatt Macy return (c_len); 179eda14cbcSMatt Macy } 180eda14cbcSMatt Macy 181eda14cbcSMatt Macy int 182eda14cbcSMatt Macy zio_decompress_data_buf(enum zio_compress c, void *src, void *dst, 183eda14cbcSMatt Macy size_t s_len, size_t d_len, uint8_t *level) 184eda14cbcSMatt Macy { 185eda14cbcSMatt Macy zio_compress_info_t *ci = &zio_compress_table[c]; 186eda14cbcSMatt Macy if ((uint_t)c >= ZIO_COMPRESS_FUNCTIONS || ci->ci_decompress == NULL) 187eda14cbcSMatt Macy return (SET_ERROR(EINVAL)); 188eda14cbcSMatt Macy 189eda14cbcSMatt Macy if (ci->ci_decompress_level != NULL && level != NULL) 190eda14cbcSMatt Macy return (ci->ci_decompress_level(src, dst, s_len, d_len, level)); 191eda14cbcSMatt Macy 192eda14cbcSMatt Macy return (ci->ci_decompress(src, dst, s_len, d_len, ci->ci_level)); 193eda14cbcSMatt Macy } 194eda14cbcSMatt Macy 195eda14cbcSMatt Macy int 196eda14cbcSMatt Macy zio_decompress_data(enum zio_compress c, abd_t *src, void *dst, 197eda14cbcSMatt Macy size_t s_len, size_t d_len, uint8_t *level) 198eda14cbcSMatt Macy { 199eda14cbcSMatt Macy void *tmp = abd_borrow_buf_copy(src, s_len); 200eda14cbcSMatt Macy int ret = zio_decompress_data_buf(c, tmp, dst, s_len, d_len, level); 201eda14cbcSMatt Macy abd_return_buf(src, tmp, s_len); 202eda14cbcSMatt Macy 203eda14cbcSMatt Macy /* 204eda14cbcSMatt Macy * Decompression shouldn't fail, because we've already verified 205eda14cbcSMatt Macy * the checksum. However, for extra protection (e.g. against bitflips 206eda14cbcSMatt Macy * in non-ECC RAM), we handle this error (and test it). 207eda14cbcSMatt Macy */ 208eda14cbcSMatt Macy if (zio_decompress_fail_fraction != 0 && 20933b8c039SMartin Matuska random_in_range(zio_decompress_fail_fraction) == 0) 210eda14cbcSMatt Macy ret = SET_ERROR(EINVAL); 211eda14cbcSMatt Macy 212eda14cbcSMatt Macy return (ret); 213eda14cbcSMatt Macy } 214eda14cbcSMatt Macy 215eda14cbcSMatt Macy int 216eda14cbcSMatt Macy zio_compress_to_feature(enum zio_compress comp) 217eda14cbcSMatt Macy { 218eda14cbcSMatt Macy switch (comp) { 219eda14cbcSMatt Macy case ZIO_COMPRESS_ZSTD: 220eda14cbcSMatt Macy return (SPA_FEATURE_ZSTD_COMPRESS); 221eda14cbcSMatt Macy default: 22253b70c86SMartin Matuska break; 223eda14cbcSMatt Macy } 224eda14cbcSMatt Macy return (SPA_FEATURE_NONE); 225eda14cbcSMatt Macy } 226