Print this page
Integrated Edon-R hash function.
Split |
Close |
Expand all |
Collapse all |
--- old/usr/src/uts/common/fs/zfs/zio_checksum.c
+++ new/usr/src/uts/common/fs/zfs/zio_checksum.c
1 1 /*
2 2 * CDDL HEADER START
3 3 *
4 4 * The contents of this file are subject to the terms of the
5 5 * Common Development and Distribution License (the "License").
6 6 * You may not use this file except in compliance with the License.
7 7 *
8 8 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9 9 * or http://www.opensolaris.org/os/licensing.
10 10 * See the License for the specific language governing permissions
11 11 * and limitations under the License.
12 12 *
13 13 * When distributing Covered Code, include this CDDL HEADER in each
14 14 * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15 15 * If applicable, add the following below this CDDL HEADER, with the
16 16 * fields enclosed by brackets "[]" replaced with your own identifying
17 17 * information: Portions Copyright [yyyy] [name of copyright owner]
18 18 *
19 19 * CDDL HEADER END
20 20 */
21 21 /*
22 22 * Copyright (c) 2005, 2010, Oracle and/or its affiliates. All rights reserved.
23 23 */
24 24
25 25 #include <sys/zfs_context.h>
26 26 #include <sys/spa.h>
27 27 #include <sys/zio.h>
28 28 #include <sys/zio_checksum.h>
29 29 #include <sys/zil.h>
30 30 #include <zfs_fletcher.h>
31 31
32 32 /*
33 33 * Checksum vectors.
34 34 *
35 35 * In the SPA, everything is checksummed. We support checksum vectors
36 36 * for three distinct reasons:
37 37 *
38 38 * 1. Different kinds of data need different levels of protection.
39 39 * For SPA metadata, we always want a very strong checksum.
40 40 * For user data, we let users make the trade-off between speed
41 41 * and checksum strength.
42 42 *
43 43 * 2. Cryptographic hash and MAC algorithms are an area of active research.
44 44 * It is likely that in future hash functions will be at least as strong
45 45 * as current best-of-breed, and may be substantially faster as well.
46 46 * We want the ability to take advantage of these new hashes as soon as
47 47 * they become available.
48 48 *
49 49 * 3. If someone develops hardware that can compute a strong hash quickly,
50 50 * we want the ability to take advantage of that hardware.
51 51 *
52 52 * Of course, we don't want a checksum upgrade to invalidate existing
53 53 * data, so we store the checksum *function* in eight bits of the bp.
54 54 * This gives us room for up to 256 different checksum functions.
55 55 *
56 56 * When writing a block, we always checksum it with the latest-and-greatest
57 57 * checksum function of the appropriate strength. When reading a block,
58 58 * we compare the expected checksum against the actual checksum, which we
59 59 * compute via the checksum function specified by BP_GET_CHECKSUM(bp).
60 60 */
61 61
62 62 /*ARGSUSED*/
63 63 static void
64 64 zio_checksum_off(const void *buf, uint64_t size, zio_cksum_t *zcp)
65 65 {
66 66 ZIO_SET_CHECKSUM(zcp, 0, 0, 0, 0);
67 67 }
68 68
69 69 zio_checksum_info_t zio_checksum_table[ZIO_CHECKSUM_FUNCTIONS] = {
↓ open down ↓ |
69 lines elided |
↑ open up ↑ |
70 70 {{NULL, NULL}, 0, 0, 0, "inherit"},
71 71 {{NULL, NULL}, 0, 0, 0, "on"},
72 72 {{zio_checksum_off, zio_checksum_off}, 0, 0, 0, "off"},
73 73 {{zio_checksum_SHA256, zio_checksum_SHA256}, 1, 1, 0, "label"},
74 74 {{zio_checksum_SHA256, zio_checksum_SHA256}, 1, 1, 0, "gang_header"},
75 75 {{fletcher_2_native, fletcher_2_byteswap}, 0, 1, 0, "zilog"},
76 76 {{fletcher_2_native, fletcher_2_byteswap}, 0, 0, 0, "fletcher2"},
77 77 {{fletcher_4_native, fletcher_4_byteswap}, 1, 0, 0, "fletcher4"},
78 78 {{zio_checksum_SHA256, zio_checksum_SHA256}, 1, 0, 1, "sha256"},
79 79 {{fletcher_4_native, fletcher_4_byteswap}, 0, 1, 0, "zilog2"},
80 + {{zio_checksum_EdonR512_256, zio_checksum_EdonR512_256_byteswap},
81 + 1, 0, 1, "edonr512/256"},
80 82 };
81 83
82 84 enum zio_checksum
83 85 zio_checksum_select(enum zio_checksum child, enum zio_checksum parent)
84 86 {
85 87 ASSERT(child < ZIO_CHECKSUM_FUNCTIONS);
86 88 ASSERT(parent < ZIO_CHECKSUM_FUNCTIONS);
87 89 ASSERT(parent != ZIO_CHECKSUM_INHERIT && parent != ZIO_CHECKSUM_ON);
88 90
89 91 if (child == ZIO_CHECKSUM_INHERIT)
90 92 return (parent);
91 93
92 94 if (child == ZIO_CHECKSUM_ON)
93 95 return (ZIO_CHECKSUM_ON_VALUE);
94 96
95 97 return (child);
96 98 }
97 99
98 100 enum zio_checksum
99 101 zio_checksum_dedup_select(spa_t *spa, enum zio_checksum child,
100 102 enum zio_checksum parent)
101 103 {
102 104 ASSERT((child & ZIO_CHECKSUM_MASK) < ZIO_CHECKSUM_FUNCTIONS);
103 105 ASSERT((parent & ZIO_CHECKSUM_MASK) < ZIO_CHECKSUM_FUNCTIONS);
104 106 ASSERT(parent != ZIO_CHECKSUM_INHERIT && parent != ZIO_CHECKSUM_ON);
105 107
106 108 if (child == ZIO_CHECKSUM_INHERIT)
107 109 return (parent);
108 110
109 111 if (child == ZIO_CHECKSUM_ON)
110 112 return (spa_dedup_checksum(spa));
111 113
112 114 if (child == (ZIO_CHECKSUM_ON | ZIO_CHECKSUM_VERIFY))
113 115 return (spa_dedup_checksum(spa) | ZIO_CHECKSUM_VERIFY);
114 116
115 117 ASSERT(zio_checksum_table[child & ZIO_CHECKSUM_MASK].ci_dedup ||
116 118 (child & ZIO_CHECKSUM_VERIFY) || child == ZIO_CHECKSUM_OFF);
117 119
118 120 return (child);
119 121 }
120 122
121 123 /*
122 124 * Set the external verifier for a gang block based on <vdev, offset, txg>,
123 125 * a tuple which is guaranteed to be unique for the life of the pool.
124 126 */
125 127 static void
126 128 zio_checksum_gang_verifier(zio_cksum_t *zcp, blkptr_t *bp)
127 129 {
128 130 dva_t *dva = BP_IDENTITY(bp);
129 131 uint64_t txg = BP_PHYSICAL_BIRTH(bp);
130 132
131 133 ASSERT(BP_IS_GANG(bp));
132 134
133 135 ZIO_SET_CHECKSUM(zcp, DVA_GET_VDEV(dva), DVA_GET_OFFSET(dva), txg, 0);
134 136 }
135 137
136 138 /*
137 139 * Set the external verifier for a label block based on its offset.
138 140 * The vdev is implicit, and the txg is unknowable at pool open time --
139 141 * hence the logic in vdev_uberblock_load() to find the most recent copy.
140 142 */
141 143 static void
142 144 zio_checksum_label_verifier(zio_cksum_t *zcp, uint64_t offset)
143 145 {
144 146 ZIO_SET_CHECKSUM(zcp, offset, 0, 0, 0);
145 147 }
146 148
147 149 /*
148 150 * Generate the checksum.
149 151 */
150 152 void
151 153 zio_checksum_compute(zio_t *zio, enum zio_checksum checksum,
152 154 void *data, uint64_t size)
153 155 {
154 156 blkptr_t *bp = zio->io_bp;
155 157 uint64_t offset = zio->io_offset;
156 158 zio_checksum_info_t *ci = &zio_checksum_table[checksum];
157 159 zio_cksum_t cksum;
158 160
159 161 ASSERT((uint_t)checksum < ZIO_CHECKSUM_FUNCTIONS);
160 162 ASSERT(ci->ci_func[0] != NULL);
161 163
162 164 if (ci->ci_eck) {
163 165 zio_eck_t *eck;
164 166
165 167 if (checksum == ZIO_CHECKSUM_ZILOG2) {
166 168 zil_chain_t *zilc = data;
167 169
168 170 size = P2ROUNDUP_TYPED(zilc->zc_nused, ZIL_MIN_BLKSZ,
169 171 uint64_t);
170 172 eck = &zilc->zc_eck;
171 173 } else {
172 174 eck = (zio_eck_t *)((char *)data + size) - 1;
173 175 }
174 176 if (checksum == ZIO_CHECKSUM_GANG_HEADER)
175 177 zio_checksum_gang_verifier(&eck->zec_cksum, bp);
176 178 else if (checksum == ZIO_CHECKSUM_LABEL)
177 179 zio_checksum_label_verifier(&eck->zec_cksum, offset);
178 180 else
179 181 bp->blk_cksum = eck->zec_cksum;
180 182 eck->zec_magic = ZEC_MAGIC;
181 183 ci->ci_func[0](data, size, &cksum);
182 184 eck->zec_cksum = cksum;
183 185 } else {
184 186 ci->ci_func[0](data, size, &bp->blk_cksum);
185 187 }
186 188 }
187 189
188 190 int
189 191 zio_checksum_error(zio_t *zio, zio_bad_cksum_t *info)
190 192 {
191 193 blkptr_t *bp = zio->io_bp;
192 194 uint_t checksum = (bp == NULL ? zio->io_prop.zp_checksum :
193 195 (BP_IS_GANG(bp) ? ZIO_CHECKSUM_GANG_HEADER : BP_GET_CHECKSUM(bp)));
194 196 int byteswap;
195 197 int error;
196 198 uint64_t size = (bp == NULL ? zio->io_size :
197 199 (BP_IS_GANG(bp) ? SPA_GANGBLOCKSIZE : BP_GET_PSIZE(bp)));
198 200 uint64_t offset = zio->io_offset;
199 201 void *data = zio->io_data;
200 202 zio_checksum_info_t *ci = &zio_checksum_table[checksum];
201 203 zio_cksum_t actual_cksum, expected_cksum, verifier;
202 204
203 205 if (checksum >= ZIO_CHECKSUM_FUNCTIONS || ci->ci_func[0] == NULL)
204 206 return (EINVAL);
205 207
206 208 if (ci->ci_eck) {
207 209 zio_eck_t *eck;
208 210
209 211 if (checksum == ZIO_CHECKSUM_ZILOG2) {
210 212 zil_chain_t *zilc = data;
211 213 uint64_t nused;
212 214
213 215 eck = &zilc->zc_eck;
214 216 if (eck->zec_magic == ZEC_MAGIC)
215 217 nused = zilc->zc_nused;
216 218 else if (eck->zec_magic == BSWAP_64(ZEC_MAGIC))
217 219 nused = BSWAP_64(zilc->zc_nused);
218 220 else
219 221 return (ECKSUM);
220 222
221 223 if (nused > size)
222 224 return (ECKSUM);
223 225
224 226 size = P2ROUNDUP_TYPED(nused, ZIL_MIN_BLKSZ, uint64_t);
225 227 } else {
226 228 eck = (zio_eck_t *)((char *)data + size) - 1;
227 229 }
228 230
229 231 if (checksum == ZIO_CHECKSUM_GANG_HEADER)
230 232 zio_checksum_gang_verifier(&verifier, bp);
231 233 else if (checksum == ZIO_CHECKSUM_LABEL)
232 234 zio_checksum_label_verifier(&verifier, offset);
233 235 else
234 236 verifier = bp->blk_cksum;
235 237
236 238 byteswap = (eck->zec_magic == BSWAP_64(ZEC_MAGIC));
237 239
238 240 if (byteswap)
239 241 byteswap_uint64_array(&verifier, sizeof (zio_cksum_t));
240 242
241 243 expected_cksum = eck->zec_cksum;
242 244 eck->zec_cksum = verifier;
243 245 ci->ci_func[byteswap](data, size, &actual_cksum);
244 246 eck->zec_cksum = expected_cksum;
245 247
246 248 if (byteswap)
247 249 byteswap_uint64_array(&expected_cksum,
248 250 sizeof (zio_cksum_t));
249 251 } else {
250 252 ASSERT(!BP_IS_GANG(bp));
251 253 byteswap = BP_SHOULD_BYTESWAP(bp);
252 254 expected_cksum = bp->blk_cksum;
253 255 ci->ci_func[byteswap](data, size, &actual_cksum);
254 256 }
255 257
256 258 info->zbc_expected = expected_cksum;
257 259 info->zbc_actual = actual_cksum;
258 260 info->zbc_checksum_name = ci->ci_name;
259 261 info->zbc_byteswapped = byteswap;
260 262 info->zbc_injected = 0;
261 263 info->zbc_has_cksum = 1;
262 264
263 265 if (!ZIO_CHECKSUM_EQUAL(actual_cksum, expected_cksum))
264 266 return (ECKSUM);
265 267
266 268 if (zio_injection_enabled && !zio->io_error &&
267 269 (error = zio_handle_fault_injection(zio, ECKSUM)) != 0) {
268 270
269 271 info->zbc_injected = 1;
270 272 return (error);
271 273 }
272 274
273 275 return (0);
274 276 }
↓ open down ↓ |
185 lines elided |
↑ open up ↑ |
XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX