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