xref: /illumos-gate/usr/src/uts/common/fs/zfs/zio_checksum.c (revision 6cedfc397d92d64e442f0aae4445ac507beaf58f)
1fa9e4066Sahrens /*
2fa9e4066Sahrens  * CDDL HEADER START
3fa9e4066Sahrens  *
4fa9e4066Sahrens  * The contents of this file are subject to the terms of the
5ea8dc4b6Seschrock  * Common Development and Distribution License (the "License").
6ea8dc4b6Seschrock  * You may not use this file except in compliance with the License.
7fa9e4066Sahrens  *
8fa9e4066Sahrens  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9fa9e4066Sahrens  * or http://www.opensolaris.org/os/licensing.
10fa9e4066Sahrens  * See the License for the specific language governing permissions
11fa9e4066Sahrens  * and limitations under the License.
12fa9e4066Sahrens  *
13fa9e4066Sahrens  * When distributing Covered Code, include this CDDL HEADER in each
14fa9e4066Sahrens  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15fa9e4066Sahrens  * If applicable, add the following below this CDDL HEADER, with the
16fa9e4066Sahrens  * fields enclosed by brackets "[]" replaced with your own identifying
17fa9e4066Sahrens  * information: Portions Copyright [yyyy] [name of copyright owner]
18fa9e4066Sahrens  *
19fa9e4066Sahrens  * CDDL HEADER END
20fa9e4066Sahrens  */
21fa9e4066Sahrens /*
22cde58dbcSMatthew Ahrens  * Copyright (c) 2005, 2010, Oracle and/or its affiliates. All rights reserved.
23*6cedfc39SPavel Zakharov  * Copyright (c) 2013, 2016 by Delphix. All rights reserved.
24810e43b2SBill Pijewski  * Copyright (c) 2013, Joyent, Inc. All rights reserved.
2545818ee1SMatthew Ahrens  * Copyright 2013 Saso Kiselkov. All rights reserved.
26fa9e4066Sahrens  */
27fa9e4066Sahrens 
28fa9e4066Sahrens #include <sys/zfs_context.h>
29fa9e4066Sahrens #include <sys/spa.h>
3045818ee1SMatthew Ahrens #include <sys/spa_impl.h>
31fa9e4066Sahrens #include <sys/zio.h>
32fa9e4066Sahrens #include <sys/zio_checksum.h>
336e1f5caaSNeil Perrin #include <sys/zil.h>
34cde58dbcSMatthew Ahrens #include <zfs_fletcher.h>
35fa9e4066Sahrens 
36fa9e4066Sahrens /*
37fa9e4066Sahrens  * Checksum vectors.
38fa9e4066Sahrens  *
39fa9e4066Sahrens  * In the SPA, everything is checksummed.  We support checksum vectors
40fa9e4066Sahrens  * for three distinct reasons:
41fa9e4066Sahrens  *
42fa9e4066Sahrens  *   1. Different kinds of data need different levels of protection.
43fa9e4066Sahrens  *	For SPA metadata, we always want a very strong checksum.
44fa9e4066Sahrens  *	For user data, we let users make the trade-off between speed
45fa9e4066Sahrens  *	and checksum strength.
46fa9e4066Sahrens  *
47fa9e4066Sahrens  *   2. Cryptographic hash and MAC algorithms are an area of active research.
48fa9e4066Sahrens  *	It is likely that in future hash functions will be at least as strong
49fa9e4066Sahrens  *	as current best-of-breed, and may be substantially faster as well.
50fa9e4066Sahrens  *	We want the ability to take advantage of these new hashes as soon as
51fa9e4066Sahrens  *	they become available.
52fa9e4066Sahrens  *
53fa9e4066Sahrens  *   3. If someone develops hardware that can compute a strong hash quickly,
54fa9e4066Sahrens  *	we want the ability to take advantage of that hardware.
55fa9e4066Sahrens  *
56fa9e4066Sahrens  * Of course, we don't want a checksum upgrade to invalidate existing
57b24ab676SJeff Bonwick  * data, so we store the checksum *function* in eight bits of the bp.
58b24ab676SJeff Bonwick  * This gives us room for up to 256 different checksum functions.
59fa9e4066Sahrens  *
60fa9e4066Sahrens  * When writing a block, we always checksum it with the latest-and-greatest
61fa9e4066Sahrens  * checksum function of the appropriate strength.  When reading a block,
62fa9e4066Sahrens  * we compare the expected checksum against the actual checksum, which we
63b24ab676SJeff Bonwick  * compute via the checksum function specified by BP_GET_CHECKSUM(bp).
6445818ee1SMatthew Ahrens  *
6545818ee1SMatthew Ahrens  * SALTED CHECKSUMS
6645818ee1SMatthew Ahrens  *
6745818ee1SMatthew Ahrens  * To enable the use of less secure hash algorithms with dedup, we
6845818ee1SMatthew Ahrens  * introduce the notion of salted checksums (MACs, really).  A salted
6945818ee1SMatthew Ahrens  * checksum is fed both a random 256-bit value (the salt) and the data
7045818ee1SMatthew Ahrens  * to be checksummed.  This salt is kept secret (stored on the pool, but
7145818ee1SMatthew Ahrens  * never shown to the user).  Thus even if an attacker knew of collision
7245818ee1SMatthew Ahrens  * weaknesses in the hash algorithm, they won't be able to mount a known
7345818ee1SMatthew Ahrens  * plaintext attack on the DDT, since the actual hash value cannot be
7445818ee1SMatthew Ahrens  * known ahead of time.  How the salt is used is algorithm-specific
7545818ee1SMatthew Ahrens  * (some might simply prefix it to the data block, others might need to
7645818ee1SMatthew Ahrens  * utilize a full-blown HMAC).  On disk the salt is stored in a ZAP
7745818ee1SMatthew Ahrens  * object in the MOS (DMU_POOL_CHECKSUM_SALT).
7845818ee1SMatthew Ahrens  *
7945818ee1SMatthew Ahrens  * CONTEXT TEMPLATES
8045818ee1SMatthew Ahrens  *
8145818ee1SMatthew Ahrens  * Some hashing algorithms need to perform a substantial amount of
8245818ee1SMatthew Ahrens  * initialization work (e.g. salted checksums above may need to pre-hash
8345818ee1SMatthew Ahrens  * the salt) before being able to process data.  Performing this
8445818ee1SMatthew Ahrens  * redundant work for each block would be wasteful, so we instead allow
8545818ee1SMatthew Ahrens  * a checksum algorithm to do the work once (the first time it's used)
8645818ee1SMatthew Ahrens  * and then keep this pre-initialized context as a template inside the
8745818ee1SMatthew Ahrens  * spa_t (spa_cksum_tmpls).  If the zio_checksum_info_t contains
8845818ee1SMatthew Ahrens  * non-NULL ci_tmpl_init and ci_tmpl_free callbacks, they are used to
8945818ee1SMatthew Ahrens  * construct and destruct the pre-initialized checksum context.  The
9045818ee1SMatthew Ahrens  * pre-initialized context is then reused during each checksum
9145818ee1SMatthew Ahrens  * invocation and passed to the checksum function.
92fa9e4066Sahrens  */
93fa9e4066Sahrens 
94fa9e4066Sahrens /*ARGSUSED*/
95fa9e4066Sahrens static void
9645818ee1SMatthew Ahrens zio_checksum_off(const void *buf, uint64_t size,
9745818ee1SMatthew Ahrens     const void *ctx_template, zio_cksum_t *zcp)
98fa9e4066Sahrens {
99fa9e4066Sahrens 	ZIO_SET_CHECKSUM(zcp, 0, 0, 0, 0);
100fa9e4066Sahrens }
101fa9e4066Sahrens 
102fa9e4066Sahrens zio_checksum_info_t zio_checksum_table[ZIO_CHECKSUM_FUNCTIONS] = {
10345818ee1SMatthew Ahrens 	{{NULL, NULL}, NULL, NULL, 0, "inherit"},
10445818ee1SMatthew Ahrens 	{{NULL, NULL}, NULL, NULL, 0, "on"},
10545818ee1SMatthew Ahrens 	{{zio_checksum_off,		zio_checksum_off},
10645818ee1SMatthew Ahrens 	    NULL, NULL, 0, "off"},
10745818ee1SMatthew Ahrens 	{{zio_checksum_SHA256,		zio_checksum_SHA256},
10845818ee1SMatthew Ahrens 	    NULL, NULL, ZCHECKSUM_FLAG_METADATA | ZCHECKSUM_FLAG_EMBEDDED,
10945818ee1SMatthew Ahrens 	    "label"},
11045818ee1SMatthew Ahrens 	{{zio_checksum_SHA256,		zio_checksum_SHA256},
11145818ee1SMatthew Ahrens 	    NULL, NULL, ZCHECKSUM_FLAG_METADATA | ZCHECKSUM_FLAG_EMBEDDED,
11245818ee1SMatthew Ahrens 	    "gang_header"},
11345818ee1SMatthew Ahrens 	{{fletcher_2_native,		fletcher_2_byteswap},
11445818ee1SMatthew Ahrens 	    NULL, NULL, ZCHECKSUM_FLAG_EMBEDDED, "zilog"},
11545818ee1SMatthew Ahrens 	{{fletcher_2_native,		fletcher_2_byteswap},
11645818ee1SMatthew Ahrens 	    NULL, NULL, 0, "fletcher2"},
11745818ee1SMatthew Ahrens 	{{fletcher_4_native,		fletcher_4_byteswap},
11845818ee1SMatthew Ahrens 	    NULL, NULL, ZCHECKSUM_FLAG_METADATA, "fletcher4"},
11945818ee1SMatthew Ahrens 	{{zio_checksum_SHA256,		zio_checksum_SHA256},
12045818ee1SMatthew Ahrens 	    NULL, NULL, ZCHECKSUM_FLAG_METADATA | ZCHECKSUM_FLAG_DEDUP |
12145818ee1SMatthew Ahrens 	    ZCHECKSUM_FLAG_NOPWRITE, "sha256"},
12245818ee1SMatthew Ahrens 	{{fletcher_4_native,		fletcher_4_byteswap},
12345818ee1SMatthew Ahrens 	    NULL, NULL, ZCHECKSUM_FLAG_EMBEDDED, "zilog2"},
12445818ee1SMatthew Ahrens 	{{zio_checksum_off,		zio_checksum_off},
12545818ee1SMatthew Ahrens 	    NULL, NULL, 0, "noparity"},
12645818ee1SMatthew Ahrens 	{{zio_checksum_SHA512_native,	zio_checksum_SHA512_byteswap},
12745818ee1SMatthew Ahrens 	    NULL, NULL, ZCHECKSUM_FLAG_METADATA | ZCHECKSUM_FLAG_DEDUP |
12845818ee1SMatthew Ahrens 	    ZCHECKSUM_FLAG_NOPWRITE, "sha512"},
12945818ee1SMatthew Ahrens 	{{zio_checksum_skein_native,	zio_checksum_skein_byteswap},
13045818ee1SMatthew Ahrens 	    zio_checksum_skein_tmpl_init, zio_checksum_skein_tmpl_free,
13145818ee1SMatthew Ahrens 	    ZCHECKSUM_FLAG_METADATA | ZCHECKSUM_FLAG_DEDUP |
13245818ee1SMatthew Ahrens 	    ZCHECKSUM_FLAG_SALTED | ZCHECKSUM_FLAG_NOPWRITE, "skein"},
13345818ee1SMatthew Ahrens 	{{zio_checksum_edonr_native,	zio_checksum_edonr_byteswap},
13445818ee1SMatthew Ahrens 	    zio_checksum_edonr_tmpl_init, zio_checksum_edonr_tmpl_free,
13545818ee1SMatthew Ahrens 	    ZCHECKSUM_FLAG_METADATA | ZCHECKSUM_FLAG_SALTED |
13645818ee1SMatthew Ahrens 	    ZCHECKSUM_FLAG_NOPWRITE, "edonr"},
137fa9e4066Sahrens };
138fa9e4066Sahrens 
139971640e6Silovezfs /*
140971640e6Silovezfs  * The flag corresponding to the "verify" in dedup=[checksum,]verify
141971640e6Silovezfs  * must be cleared first, so callers should use ZIO_CHECKSUM_MASK.
142971640e6Silovezfs  */
14345818ee1SMatthew Ahrens spa_feature_t
14445818ee1SMatthew Ahrens zio_checksum_to_feature(enum zio_checksum cksum)
14545818ee1SMatthew Ahrens {
146971640e6Silovezfs 	VERIFY((cksum & ~ZIO_CHECKSUM_MASK) == 0);
147971640e6Silovezfs 
14845818ee1SMatthew Ahrens 	switch (cksum) {
14945818ee1SMatthew Ahrens 	case ZIO_CHECKSUM_SHA512:
15045818ee1SMatthew Ahrens 		return (SPA_FEATURE_SHA512);
15145818ee1SMatthew Ahrens 	case ZIO_CHECKSUM_SKEIN:
15245818ee1SMatthew Ahrens 		return (SPA_FEATURE_SKEIN);
15345818ee1SMatthew Ahrens 	case ZIO_CHECKSUM_EDONR:
15445818ee1SMatthew Ahrens 		return (SPA_FEATURE_EDONR);
15545818ee1SMatthew Ahrens 	}
15645818ee1SMatthew Ahrens 	return (SPA_FEATURE_NONE);
15745818ee1SMatthew Ahrens }
15845818ee1SMatthew Ahrens 
159b24ab676SJeff Bonwick enum zio_checksum
160b24ab676SJeff Bonwick zio_checksum_select(enum zio_checksum child, enum zio_checksum parent)
161fa9e4066Sahrens {
162fa9e4066Sahrens 	ASSERT(child < ZIO_CHECKSUM_FUNCTIONS);
163fa9e4066Sahrens 	ASSERT(parent < ZIO_CHECKSUM_FUNCTIONS);
164fa9e4066Sahrens 	ASSERT(parent != ZIO_CHECKSUM_INHERIT && parent != ZIO_CHECKSUM_ON);
165fa9e4066Sahrens 
166fa9e4066Sahrens 	if (child == ZIO_CHECKSUM_INHERIT)
167fa9e4066Sahrens 		return (parent);
168fa9e4066Sahrens 
169fa9e4066Sahrens 	if (child == ZIO_CHECKSUM_ON)
170fa9e4066Sahrens 		return (ZIO_CHECKSUM_ON_VALUE);
171fa9e4066Sahrens 
172fa9e4066Sahrens 	return (child);
173fa9e4066Sahrens }
174fa9e4066Sahrens 
175b24ab676SJeff Bonwick enum zio_checksum
176b24ab676SJeff Bonwick zio_checksum_dedup_select(spa_t *spa, enum zio_checksum child,
177b24ab676SJeff Bonwick     enum zio_checksum parent)
178b24ab676SJeff Bonwick {
179b24ab676SJeff Bonwick 	ASSERT((child & ZIO_CHECKSUM_MASK) < ZIO_CHECKSUM_FUNCTIONS);
180b24ab676SJeff Bonwick 	ASSERT((parent & ZIO_CHECKSUM_MASK) < ZIO_CHECKSUM_FUNCTIONS);
181b24ab676SJeff Bonwick 	ASSERT(parent != ZIO_CHECKSUM_INHERIT && parent != ZIO_CHECKSUM_ON);
182b24ab676SJeff Bonwick 
183b24ab676SJeff Bonwick 	if (child == ZIO_CHECKSUM_INHERIT)
184b24ab676SJeff Bonwick 		return (parent);
185b24ab676SJeff Bonwick 
186b24ab676SJeff Bonwick 	if (child == ZIO_CHECKSUM_ON)
187b24ab676SJeff Bonwick 		return (spa_dedup_checksum(spa));
188b24ab676SJeff Bonwick 
189b24ab676SJeff Bonwick 	if (child == (ZIO_CHECKSUM_ON | ZIO_CHECKSUM_VERIFY))
190b24ab676SJeff Bonwick 		return (spa_dedup_checksum(spa) | ZIO_CHECKSUM_VERIFY);
191b24ab676SJeff Bonwick 
19245818ee1SMatthew Ahrens 	ASSERT((zio_checksum_table[child & ZIO_CHECKSUM_MASK].ci_flags &
19345818ee1SMatthew Ahrens 	    ZCHECKSUM_FLAG_DEDUP) ||
194b24ab676SJeff Bonwick 	    (child & ZIO_CHECKSUM_VERIFY) || child == ZIO_CHECKSUM_OFF);
195b24ab676SJeff Bonwick 
196b24ab676SJeff Bonwick 	return (child);
197b24ab676SJeff Bonwick }
198b24ab676SJeff Bonwick 
199e14bb325SJeff Bonwick /*
200e14bb325SJeff Bonwick  * Set the external verifier for a gang block based on <vdev, offset, txg>,
201e14bb325SJeff Bonwick  * a tuple which is guaranteed to be unique for the life of the pool.
202e14bb325SJeff Bonwick  */
203e14bb325SJeff Bonwick static void
204e14bb325SJeff Bonwick zio_checksum_gang_verifier(zio_cksum_t *zcp, blkptr_t *bp)
205e14bb325SJeff Bonwick {
206e14bb325SJeff Bonwick 	dva_t *dva = BP_IDENTITY(bp);
207b24ab676SJeff Bonwick 	uint64_t txg = BP_PHYSICAL_BIRTH(bp);
208e14bb325SJeff Bonwick 
209e14bb325SJeff Bonwick 	ASSERT(BP_IS_GANG(bp));
210e14bb325SJeff Bonwick 
211e14bb325SJeff Bonwick 	ZIO_SET_CHECKSUM(zcp, DVA_GET_VDEV(dva), DVA_GET_OFFSET(dva), txg, 0);
212e14bb325SJeff Bonwick }
213e14bb325SJeff Bonwick 
214e14bb325SJeff Bonwick /*
215e14bb325SJeff Bonwick  * Set the external verifier for a label block based on its offset.
216e14bb325SJeff Bonwick  * The vdev is implicit, and the txg is unknowable at pool open time --
217e14bb325SJeff Bonwick  * hence the logic in vdev_uberblock_load() to find the most recent copy.
218e14bb325SJeff Bonwick  */
219e14bb325SJeff Bonwick static void
220e14bb325SJeff Bonwick zio_checksum_label_verifier(zio_cksum_t *zcp, uint64_t offset)
221e14bb325SJeff Bonwick {
222e14bb325SJeff Bonwick 	ZIO_SET_CHECKSUM(zcp, offset, 0, 0, 0);
223e14bb325SJeff Bonwick }
224e14bb325SJeff Bonwick 
22545818ee1SMatthew Ahrens /*
22645818ee1SMatthew Ahrens  * Calls the template init function of a checksum which supports context
22745818ee1SMatthew Ahrens  * templates and installs the template into the spa_t.
22845818ee1SMatthew Ahrens  */
22945818ee1SMatthew Ahrens static void
23045818ee1SMatthew Ahrens zio_checksum_template_init(enum zio_checksum checksum, spa_t *spa)
23145818ee1SMatthew Ahrens {
23245818ee1SMatthew Ahrens 	zio_checksum_info_t *ci = &zio_checksum_table[checksum];
23345818ee1SMatthew Ahrens 
23445818ee1SMatthew Ahrens 	if (ci->ci_tmpl_init == NULL)
23545818ee1SMatthew Ahrens 		return;
23645818ee1SMatthew Ahrens 	if (spa->spa_cksum_tmpls[checksum] != NULL)
23745818ee1SMatthew Ahrens 		return;
23845818ee1SMatthew Ahrens 
23945818ee1SMatthew Ahrens 	VERIFY(ci->ci_tmpl_free != NULL);
24045818ee1SMatthew Ahrens 	mutex_enter(&spa->spa_cksum_tmpls_lock);
24145818ee1SMatthew Ahrens 	if (spa->spa_cksum_tmpls[checksum] == NULL) {
24245818ee1SMatthew Ahrens 		spa->spa_cksum_tmpls[checksum] =
24345818ee1SMatthew Ahrens 		    ci->ci_tmpl_init(&spa->spa_cksum_salt);
24445818ee1SMatthew Ahrens 		VERIFY(spa->spa_cksum_tmpls[checksum] != NULL);
24545818ee1SMatthew Ahrens 	}
24645818ee1SMatthew Ahrens 	mutex_exit(&spa->spa_cksum_tmpls_lock);
24745818ee1SMatthew Ahrens }
24845818ee1SMatthew Ahrens 
249fa9e4066Sahrens /*
250fa9e4066Sahrens  * Generate the checksum.
251fa9e4066Sahrens  */
252fa9e4066Sahrens void
253e14bb325SJeff Bonwick zio_checksum_compute(zio_t *zio, enum zio_checksum checksum,
2549a686fbcSPaul Dagnelie     void *data, uint64_t size)
255fa9e4066Sahrens {
256e14bb325SJeff Bonwick 	blkptr_t *bp = zio->io_bp;
257e14bb325SJeff Bonwick 	uint64_t offset = zio->io_offset;
258fa9e4066Sahrens 	zio_checksum_info_t *ci = &zio_checksum_table[checksum];
2596e1f5caaSNeil Perrin 	zio_cksum_t cksum;
26045818ee1SMatthew Ahrens 	spa_t *spa = zio->io_spa;
261fa9e4066Sahrens 
262e14bb325SJeff Bonwick 	ASSERT((uint_t)checksum < ZIO_CHECKSUM_FUNCTIONS);
263fa9e4066Sahrens 	ASSERT(ci->ci_func[0] != NULL);
264fa9e4066Sahrens 
26545818ee1SMatthew Ahrens 	zio_checksum_template_init(checksum, spa);
26645818ee1SMatthew Ahrens 
26745818ee1SMatthew Ahrens 	if (ci->ci_flags & ZCHECKSUM_FLAG_EMBEDDED) {
2686e1f5caaSNeil Perrin 		zio_eck_t *eck;
2696e1f5caaSNeil Perrin 
2706e1f5caaSNeil Perrin 		if (checksum == ZIO_CHECKSUM_ZILOG2) {
2716e1f5caaSNeil Perrin 			zil_chain_t *zilc = data;
2726e1f5caaSNeil Perrin 
2736e1f5caaSNeil Perrin 			size = P2ROUNDUP_TYPED(zilc->zc_nused, ZIL_MIN_BLKSZ,
2746e1f5caaSNeil Perrin 			    uint64_t);
2756e1f5caaSNeil Perrin 			eck = &zilc->zc_eck;
2766e1f5caaSNeil Perrin 		} else {
2776e1f5caaSNeil Perrin 			eck = (zio_eck_t *)((char *)data + size) - 1;
2786e1f5caaSNeil Perrin 		}
279e14bb325SJeff Bonwick 		if (checksum == ZIO_CHECKSUM_GANG_HEADER)
2806e1f5caaSNeil Perrin 			zio_checksum_gang_verifier(&eck->zec_cksum, bp);
281e14bb325SJeff Bonwick 		else if (checksum == ZIO_CHECKSUM_LABEL)
2826e1f5caaSNeil Perrin 			zio_checksum_label_verifier(&eck->zec_cksum, offset);
283e14bb325SJeff Bonwick 		else
2846e1f5caaSNeil Perrin 			bp->blk_cksum = eck->zec_cksum;
2856e1f5caaSNeil Perrin 		eck->zec_magic = ZEC_MAGIC;
28645818ee1SMatthew Ahrens 		ci->ci_func[0](data, size, spa->spa_cksum_tmpls[checksum],
28745818ee1SMatthew Ahrens 		    &cksum);
2886e1f5caaSNeil Perrin 		eck->zec_cksum = cksum;
289fa9e4066Sahrens 	} else {
29045818ee1SMatthew Ahrens 		ci->ci_func[0](data, size, spa->spa_cksum_tmpls[checksum],
29145818ee1SMatthew Ahrens 		    &bp->blk_cksum);
292fa9e4066Sahrens 	}
293fa9e4066Sahrens }
294fa9e4066Sahrens 
295fa9e4066Sahrens int
296dcbf3bd6SGeorge Wilson zio_checksum_error_impl(spa_t *spa, blkptr_t *bp, enum zio_checksum checksum,
297dcbf3bd6SGeorge Wilson     void *data, uint64_t size, uint64_t offset, zio_bad_cksum_t *info)
298fa9e4066Sahrens {
299fa9e4066Sahrens 	zio_checksum_info_t *ci = &zio_checksum_table[checksum];
300dcbf3bd6SGeorge Wilson 	zio_cksum_t actual_cksum, expected_cksum;
301dcbf3bd6SGeorge Wilson 	int byteswap;
302fa9e4066Sahrens 
303fa9e4066Sahrens 	if (checksum >= ZIO_CHECKSUM_FUNCTIONS || ci->ci_func[0] == NULL)
304be6fd75aSMatthew Ahrens 		return (SET_ERROR(EINVAL));
305fa9e4066Sahrens 
30645818ee1SMatthew Ahrens 	zio_checksum_template_init(checksum, spa);
30745818ee1SMatthew Ahrens 
30845818ee1SMatthew Ahrens 	if (ci->ci_flags & ZCHECKSUM_FLAG_EMBEDDED) {
3096e1f5caaSNeil Perrin 		zio_eck_t *eck;
310dcbf3bd6SGeorge Wilson 		zio_cksum_t verifier;
3116e1f5caaSNeil Perrin 
3126e1f5caaSNeil Perrin 		if (checksum == ZIO_CHECKSUM_ZILOG2) {
3136e1f5caaSNeil Perrin 			zil_chain_t *zilc = data;
3146e1f5caaSNeil Perrin 			uint64_t nused;
3156e1f5caaSNeil Perrin 
3166e1f5caaSNeil Perrin 			eck = &zilc->zc_eck;
3176e1f5caaSNeil Perrin 			if (eck->zec_magic == ZEC_MAGIC)
3186e1f5caaSNeil Perrin 				nused = zilc->zc_nused;
3196e1f5caaSNeil Perrin 			else if (eck->zec_magic == BSWAP_64(ZEC_MAGIC))
3206e1f5caaSNeil Perrin 				nused = BSWAP_64(zilc->zc_nused);
3216e1f5caaSNeil Perrin 			else
322be6fd75aSMatthew Ahrens 				return (SET_ERROR(ECKSUM));
3236e1f5caaSNeil Perrin 
3246e1f5caaSNeil Perrin 			if (nused > size)
325be6fd75aSMatthew Ahrens 				return (SET_ERROR(ECKSUM));
3266e1f5caaSNeil Perrin 
3276e1f5caaSNeil Perrin 			size = P2ROUNDUP_TYPED(nused, ZIL_MIN_BLKSZ, uint64_t);
3286e1f5caaSNeil Perrin 		} else {
3296e1f5caaSNeil Perrin 			eck = (zio_eck_t *)((char *)data + size) - 1;
3306e1f5caaSNeil Perrin 		}
3316e1f5caaSNeil Perrin 
332fa9e4066Sahrens 		if (checksum == ZIO_CHECKSUM_GANG_HEADER)
333e14bb325SJeff Bonwick 			zio_checksum_gang_verifier(&verifier, bp);
334e14bb325SJeff Bonwick 		else if (checksum == ZIO_CHECKSUM_LABEL)
335e14bb325SJeff Bonwick 			zio_checksum_label_verifier(&verifier, offset);
336e14bb325SJeff Bonwick 		else
337e14bb325SJeff Bonwick 			verifier = bp->blk_cksum;
338e14bb325SJeff Bonwick 
3396e1f5caaSNeil Perrin 		byteswap = (eck->zec_magic == BSWAP_64(ZEC_MAGIC));
340fa9e4066Sahrens 
341e14bb325SJeff Bonwick 		if (byteswap)
342e14bb325SJeff Bonwick 			byteswap_uint64_array(&verifier, sizeof (zio_cksum_t));
343e14bb325SJeff Bonwick 
3446e1f5caaSNeil Perrin 		expected_cksum = eck->zec_cksum;
3456e1f5caaSNeil Perrin 		eck->zec_cksum = verifier;
34645818ee1SMatthew Ahrens 		ci->ci_func[byteswap](data, size,
34745818ee1SMatthew Ahrens 		    spa->spa_cksum_tmpls[checksum], &actual_cksum);
3486e1f5caaSNeil Perrin 		eck->zec_cksum = expected_cksum;
349e14bb325SJeff Bonwick 
350dcbf3bd6SGeorge Wilson 		if (byteswap) {
351fa9e4066Sahrens 			byteswap_uint64_array(&expected_cksum,
352fa9e4066Sahrens 			    sizeof (zio_cksum_t));
353dcbf3bd6SGeorge Wilson 		}
354fa9e4066Sahrens 	} else {
355e14bb325SJeff Bonwick 		byteswap = BP_SHOULD_BYTESWAP(bp);
356e14bb325SJeff Bonwick 		expected_cksum = bp->blk_cksum;
35745818ee1SMatthew Ahrens 		ci->ci_func[byteswap](data, size,
35845818ee1SMatthew Ahrens 		    spa->spa_cksum_tmpls[checksum], &actual_cksum);
359fa9e4066Sahrens 	}
360fa9e4066Sahrens 
361dcbf3bd6SGeorge Wilson 	if (info != NULL) {
362dcbf3bd6SGeorge Wilson 		info->zbc_expected = expected_cksum;
363dcbf3bd6SGeorge Wilson 		info->zbc_actual = actual_cksum;
364dcbf3bd6SGeorge Wilson 		info->zbc_checksum_name = ci->ci_name;
365dcbf3bd6SGeorge Wilson 		info->zbc_byteswapped = byteswap;
366dcbf3bd6SGeorge Wilson 		info->zbc_injected = 0;
367dcbf3bd6SGeorge Wilson 		info->zbc_has_cksum = 1;
368dcbf3bd6SGeorge Wilson 	}
36922fe2c88SJonathan Adams 
370e14bb325SJeff Bonwick 	if (!ZIO_CHECKSUM_EQUAL(actual_cksum, expected_cksum))
371be6fd75aSMatthew Ahrens 		return (SET_ERROR(ECKSUM));
372fa9e4066Sahrens 
373dcbf3bd6SGeorge Wilson 	return (0);
374dcbf3bd6SGeorge Wilson }
375dcbf3bd6SGeorge Wilson 
376dcbf3bd6SGeorge Wilson int
377dcbf3bd6SGeorge Wilson zio_checksum_error(zio_t *zio, zio_bad_cksum_t *info)
378dcbf3bd6SGeorge Wilson {
379dcbf3bd6SGeorge Wilson 	blkptr_t *bp = zio->io_bp;
380dcbf3bd6SGeorge Wilson 	uint_t checksum = (bp == NULL ? zio->io_prop.zp_checksum :
381dcbf3bd6SGeorge Wilson 	    (BP_IS_GANG(bp) ? ZIO_CHECKSUM_GANG_HEADER : BP_GET_CHECKSUM(bp)));
382dcbf3bd6SGeorge Wilson 	int error;
383dcbf3bd6SGeorge Wilson 	uint64_t size = (bp == NULL ? zio->io_size :
384dcbf3bd6SGeorge Wilson 	    (BP_IS_GANG(bp) ? SPA_GANGBLOCKSIZE : BP_GET_PSIZE(bp)));
385dcbf3bd6SGeorge Wilson 	uint64_t offset = zio->io_offset;
386dcbf3bd6SGeorge Wilson 	void *data = zio->io_data;
387dcbf3bd6SGeorge Wilson 	spa_t *spa = zio->io_spa;
388dcbf3bd6SGeorge Wilson 
389dcbf3bd6SGeorge Wilson 	error = zio_checksum_error_impl(spa, bp, checksum, data, size,
390dcbf3bd6SGeorge Wilson 	    offset, info);
39122fe2c88SJonathan Adams 
392*6cedfc39SPavel Zakharov 	if (zio_injection_enabled && error == 0 && zio->io_error == 0) {
393*6cedfc39SPavel Zakharov 		error = zio_handle_fault_injection(zio, ECKSUM);
394*6cedfc39SPavel Zakharov 		if (error != 0)
395*6cedfc39SPavel Zakharov 			info->zbc_injected = 1;
39622fe2c88SJonathan Adams 	}
397*6cedfc39SPavel Zakharov 
398dcbf3bd6SGeorge Wilson 	return (error);
399fa9e4066Sahrens }
40045818ee1SMatthew Ahrens 
40145818ee1SMatthew Ahrens /*
40245818ee1SMatthew Ahrens  * Called by a spa_t that's about to be deallocated. This steps through
40345818ee1SMatthew Ahrens  * all of the checksum context templates and deallocates any that were
40445818ee1SMatthew Ahrens  * initialized using the algorithm-specific template init function.
40545818ee1SMatthew Ahrens  */
40645818ee1SMatthew Ahrens void
40745818ee1SMatthew Ahrens zio_checksum_templates_free(spa_t *spa)
40845818ee1SMatthew Ahrens {
40945818ee1SMatthew Ahrens 	for (enum zio_checksum checksum = 0;
41045818ee1SMatthew Ahrens 	    checksum < ZIO_CHECKSUM_FUNCTIONS; checksum++) {
41145818ee1SMatthew Ahrens 		if (spa->spa_cksum_tmpls[checksum] != NULL) {
41245818ee1SMatthew Ahrens 			zio_checksum_info_t *ci = &zio_checksum_table[checksum];
41345818ee1SMatthew Ahrens 
41445818ee1SMatthew Ahrens 			VERIFY(ci->ci_tmpl_free != NULL);
41545818ee1SMatthew Ahrens 			ci->ci_tmpl_free(spa->spa_cksum_tmpls[checksum]);
41645818ee1SMatthew Ahrens 			spa->spa_cksum_tmpls[checksum] = NULL;
41745818ee1SMatthew Ahrens 		}
41845818ee1SMatthew Ahrens 	}
41945818ee1SMatthew Ahrens }
420