]>
Commit | Line | Data |
---|---|---|
34dc7c2f BB |
1 | /* |
2 | * CDDL HEADER START | |
3 | * | |
4 | * The contents of this file are subject to the terms of the | |
5 | * Common Development and Distribution License (the "License"). | |
6 | * You may not use this file except in compliance with the License. | |
7 | * | |
8 | * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE | |
9 | * or http://www.opensolaris.org/os/licensing. | |
10 | * See the License for the specific language governing permissions | |
11 | * and limitations under the License. | |
12 | * | |
13 | * When distributing Covered Code, include this CDDL HEADER in each | |
14 | * file and include the License file at usr/src/OPENSOLARIS.LICENSE. | |
15 | * If applicable, add the following below this CDDL HEADER, with the | |
16 | * fields enclosed by brackets "[]" replaced with your own identifying | |
17 | * information: Portions Copyright [yyyy] [name of copyright owner] | |
18 | * | |
19 | * CDDL HEADER END | |
20 | */ | |
21 | ||
22 | /* | |
428870ff | 23 | * Copyright 2009 Sun Microsystems, Inc. All rights reserved. |
34dc7c2f BB |
24 | * Use is subject to license terms. |
25 | */ | |
9759c60f ED |
26 | /* |
27 | * Copyright (c) 2013 by Saso Kiselkov. All rights reserved. | |
28 | */ | |
34dc7c2f | 29 | |
2e528b49 | 30 | /* |
c3bd3fb4 | 31 | * Copyright (c) 2013, 2018 by Delphix. All rights reserved. |
2e528b49 MA |
32 | */ |
33 | ||
34dc7c2f | 34 | #include <sys/zfs_context.h> |
34dc7c2f | 35 | #include <sys/spa.h> |
99197f03 | 36 | #include <sys/zfeature.h> |
34dc7c2f BB |
37 | #include <sys/zio.h> |
38 | #include <sys/zio_compress.h> | |
39 | ||
c3bd3fb4 TC |
40 | /* |
41 | * If nonzero, every 1/X decompression attempts will fail, simulating | |
42 | * an undetected memory error. | |
43 | */ | |
44 | unsigned long zio_decompress_fail_fraction = 0; | |
45 | ||
34dc7c2f BB |
46 | /* |
47 | * Compression vectors. | |
48 | */ | |
34dc7c2f | 49 | zio_compress_info_t zio_compress_table[ZIO_COMPRESS_FUNCTIONS] = { |
a6255b7f DQ |
50 | {"inherit", 0, NULL, NULL}, |
51 | {"on", 0, NULL, NULL}, | |
52 | {"uncompressed", 0, NULL, NULL}, | |
53 | {"lzjb", 0, lzjb_compress, lzjb_decompress}, | |
54 | {"empty", 0, NULL, NULL}, | |
55 | {"gzip-1", 1, gzip_compress, gzip_decompress}, | |
56 | {"gzip-2", 2, gzip_compress, gzip_decompress}, | |
57 | {"gzip-3", 3, gzip_compress, gzip_decompress}, | |
58 | {"gzip-4", 4, gzip_compress, gzip_decompress}, | |
59 | {"gzip-5", 5, gzip_compress, gzip_decompress}, | |
60 | {"gzip-6", 6, gzip_compress, gzip_decompress}, | |
61 | {"gzip-7", 7, gzip_compress, gzip_decompress}, | |
62 | {"gzip-8", 8, gzip_compress, gzip_decompress}, | |
63 | {"gzip-9", 9, gzip_compress, gzip_decompress}, | |
64 | {"zle", 64, zle_compress, zle_decompress}, | |
65 | {"lz4", 0, lz4_compress_zfs, lz4_decompress_zfs} | |
34dc7c2f BB |
66 | }; |
67 | ||
428870ff | 68 | enum zio_compress |
99197f03 JG |
69 | zio_compress_select(spa_t *spa, enum zio_compress child, |
70 | enum zio_compress parent) | |
34dc7c2f | 71 | { |
99197f03 JG |
72 | enum zio_compress result; |
73 | ||
34dc7c2f BB |
74 | ASSERT(child < ZIO_COMPRESS_FUNCTIONS); |
75 | ASSERT(parent < ZIO_COMPRESS_FUNCTIONS); | |
99197f03 | 76 | ASSERT(parent != ZIO_COMPRESS_INHERIT); |
34dc7c2f | 77 | |
99197f03 JG |
78 | result = child; |
79 | if (result == ZIO_COMPRESS_INHERIT) | |
80 | result = parent; | |
34dc7c2f | 81 | |
99197f03 JG |
82 | if (result == ZIO_COMPRESS_ON) { |
83 | if (spa_feature_is_active(spa, SPA_FEATURE_LZ4_COMPRESS)) | |
84 | result = ZIO_COMPRESS_LZ4_ON_VALUE; | |
85 | else | |
86 | result = ZIO_COMPRESS_LEGACY_ON_VALUE; | |
87 | } | |
34dc7c2f | 88 | |
99197f03 | 89 | return (result); |
34dc7c2f BB |
90 | } |
91 | ||
a6255b7f DQ |
92 | /*ARGSUSED*/ |
93 | static int | |
94 | zio_compress_zeroed_cb(void *data, size_t len, void *private) | |
95 | { | |
96 | uint64_t *end = (uint64_t *)((char *)data + len); | |
1c27024e | 97 | for (uint64_t *word = (uint64_t *)data; word < end; word++) |
a6255b7f DQ |
98 | if (*word != 0) |
99 | return (1); | |
100 | ||
101 | return (0); | |
102 | } | |
103 | ||
428870ff | 104 | size_t |
a6255b7f | 105 | zio_compress_data(enum zio_compress c, abd_t *src, void *dst, size_t s_len) |
34dc7c2f | 106 | { |
9b67f605 | 107 | size_t c_len, d_len; |
428870ff | 108 | zio_compress_info_t *ci = &zio_compress_table[c]; |
34dc7c2f | 109 | |
428870ff BB |
110 | ASSERT((uint_t)c < ZIO_COMPRESS_FUNCTIONS); |
111 | ASSERT((uint_t)c == ZIO_COMPRESS_EMPTY || ci->ci_compress != NULL); | |
34dc7c2f BB |
112 | |
113 | /* | |
114 | * If the data is all zeroes, we don't even need to allocate | |
428870ff | 115 | * a block for it. We indicate this by returning zero size. |
34dc7c2f | 116 | */ |
a6255b7f | 117 | if (abd_iterate_func(src, 0, s_len, zio_compress_zeroed_cb, NULL) == 0) |
34dc7c2f BB |
118 | return (0); |
119 | ||
428870ff BB |
120 | if (c == ZIO_COMPRESS_EMPTY) |
121 | return (s_len); | |
122 | ||
34dc7c2f | 123 | /* Compress at least 12.5% */ |
9b67f605 | 124 | d_len = s_len - (s_len >> 3); |
a6255b7f DQ |
125 | |
126 | /* No compression algorithms can read from ABDs directly */ | |
1c27024e | 127 | void *tmp = abd_borrow_buf_copy(src, s_len); |
a6255b7f DQ |
128 | c_len = ci->ci_compress(tmp, dst, s_len, d_len, ci->ci_level); |
129 | abd_return_buf(src, tmp, s_len); | |
34dc7c2f | 130 | |
428870ff BB |
131 | if (c_len > d_len) |
132 | return (s_len); | |
34dc7c2f | 133 | |
428870ff | 134 | ASSERT3U(c_len, <=, d_len); |
428870ff | 135 | return (c_len); |
34dc7c2f BB |
136 | } |
137 | ||
138 | int | |
a6255b7f | 139 | zio_decompress_data_buf(enum zio_compress c, void *src, void *dst, |
428870ff | 140 | size_t s_len, size_t d_len) |
34dc7c2f | 141 | { |
428870ff | 142 | zio_compress_info_t *ci = &zio_compress_table[c]; |
428870ff | 143 | if ((uint_t)c >= ZIO_COMPRESS_FUNCTIONS || ci->ci_decompress == NULL) |
2e528b49 | 144 | return (SET_ERROR(EINVAL)); |
34dc7c2f | 145 | |
428870ff | 146 | return (ci->ci_decompress(src, dst, s_len, d_len, ci->ci_level)); |
34dc7c2f | 147 | } |
a6255b7f DQ |
148 | |
149 | int | |
150 | zio_decompress_data(enum zio_compress c, abd_t *src, void *dst, | |
151 | size_t s_len, size_t d_len) | |
152 | { | |
153 | void *tmp = abd_borrow_buf_copy(src, s_len); | |
154 | int ret = zio_decompress_data_buf(c, tmp, dst, s_len, d_len); | |
155 | abd_return_buf(src, tmp, s_len); | |
156 | ||
c3bd3fb4 TC |
157 | /* |
158 | * Decompression shouldn't fail, because we've already verifyied | |
159 | * the checksum. However, for extra protection (e.g. against bitflips | |
160 | * in non-ECC RAM), we handle this error (and test it). | |
161 | */ | |
162 | ASSERT0(ret); | |
163 | if (zio_decompress_fail_fraction != 0 && | |
164 | spa_get_random(zio_decompress_fail_fraction) == 0) | |
165 | ret = SET_ERROR(EINVAL); | |
166 | ||
a6255b7f DQ |
167 | return (ret); |
168 | } |