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. 239a686fbcSPaul Dagnelie * Copyright (c) 2013, 2015 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 139*971640e6Silovezfs /* 140*971640e6Silovezfs * The flag corresponding to the "verify" in dedup=[checksum,]verify 141*971640e6Silovezfs * must be cleared first, so callers should use ZIO_CHECKSUM_MASK. 142*971640e6Silovezfs */ 14345818ee1SMatthew Ahrens spa_feature_t 14445818ee1SMatthew Ahrens zio_checksum_to_feature(enum zio_checksum cksum) 14545818ee1SMatthew Ahrens { 146*971640e6Silovezfs VERIFY((cksum & ~ZIO_CHECKSUM_MASK) == 0); 147*971640e6Silovezfs 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 199fa9e4066Sahrens /* 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 225e14bb325SJeff Bonwick /* 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 24945818ee1SMatthew Ahrens /* 250fa9e4066Sahrens * Generate the checksum. 251fa9e4066Sahrens */ 252fa9e4066Sahrens void 253e14bb325SJeff Bonwick zio_checksum_compute(zio_t *zio, enum zio_checksum checksum, 254e14bb325SJeff Bonwick 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 29622fe2c88SJonathan Adams zio_checksum_error(zio_t *zio, zio_bad_cksum_t *info) 297fa9e4066Sahrens { 298fa9e4066Sahrens blkptr_t *bp = zio->io_bp; 299e14bb325SJeff Bonwick uint_t checksum = (bp == NULL ? zio->io_prop.zp_checksum : 300e14bb325SJeff Bonwick (BP_IS_GANG(bp) ? ZIO_CHECKSUM_GANG_HEADER : BP_GET_CHECKSUM(bp))); 301e14bb325SJeff Bonwick int byteswap; 30222fe2c88SJonathan Adams int error; 303e14bb325SJeff Bonwick uint64_t size = (bp == NULL ? zio->io_size : 304e14bb325SJeff Bonwick (BP_IS_GANG(bp) ? SPA_GANGBLOCKSIZE : BP_GET_PSIZE(bp))); 305e14bb325SJeff Bonwick uint64_t offset = zio->io_offset; 30622fe2c88SJonathan Adams void *data = zio->io_data; 307fa9e4066Sahrens zio_checksum_info_t *ci = &zio_checksum_table[checksum]; 308e14bb325SJeff Bonwick zio_cksum_t actual_cksum, expected_cksum, verifier; 30945818ee1SMatthew Ahrens spa_t *spa = zio->io_spa; 310fa9e4066Sahrens 311fa9e4066Sahrens if (checksum >= ZIO_CHECKSUM_FUNCTIONS || ci->ci_func[0] == NULL) 312be6fd75aSMatthew Ahrens return (SET_ERROR(EINVAL)); 313fa9e4066Sahrens 31445818ee1SMatthew Ahrens zio_checksum_template_init(checksum, spa); 31545818ee1SMatthew Ahrens 31645818ee1SMatthew Ahrens if (ci->ci_flags & ZCHECKSUM_FLAG_EMBEDDED) { 3176e1f5caaSNeil Perrin zio_eck_t *eck; 3186e1f5caaSNeil Perrin 3196e1f5caaSNeil Perrin if (checksum == ZIO_CHECKSUM_ZILOG2) { 3206e1f5caaSNeil Perrin zil_chain_t *zilc = data; 3216e1f5caaSNeil Perrin uint64_t nused; 3226e1f5caaSNeil Perrin 3236e1f5caaSNeil Perrin eck = &zilc->zc_eck; 3246e1f5caaSNeil Perrin if (eck->zec_magic == ZEC_MAGIC) 3256e1f5caaSNeil Perrin nused = zilc->zc_nused; 3266e1f5caaSNeil Perrin else if (eck->zec_magic == BSWAP_64(ZEC_MAGIC)) 3276e1f5caaSNeil Perrin nused = BSWAP_64(zilc->zc_nused); 3286e1f5caaSNeil Perrin else 329be6fd75aSMatthew Ahrens return (SET_ERROR(ECKSUM)); 3306e1f5caaSNeil Perrin 3316e1f5caaSNeil Perrin if (nused > size) 332be6fd75aSMatthew Ahrens return (SET_ERROR(ECKSUM)); 3336e1f5caaSNeil Perrin 3346e1f5caaSNeil Perrin size = P2ROUNDUP_TYPED(nused, ZIL_MIN_BLKSZ, uint64_t); 3356e1f5caaSNeil Perrin } else { 3366e1f5caaSNeil Perrin eck = (zio_eck_t *)((char *)data + size) - 1; 3376e1f5caaSNeil Perrin } 3386e1f5caaSNeil Perrin 339fa9e4066Sahrens if (checksum == ZIO_CHECKSUM_GANG_HEADER) 340e14bb325SJeff Bonwick zio_checksum_gang_verifier(&verifier, bp); 341e14bb325SJeff Bonwick else if (checksum == ZIO_CHECKSUM_LABEL) 342e14bb325SJeff Bonwick zio_checksum_label_verifier(&verifier, offset); 343e14bb325SJeff Bonwick else 344e14bb325SJeff Bonwick verifier = bp->blk_cksum; 345fa9e4066Sahrens 3466e1f5caaSNeil Perrin byteswap = (eck->zec_magic == BSWAP_64(ZEC_MAGIC)); 347e14bb325SJeff Bonwick 348e14bb325SJeff Bonwick if (byteswap) 349e14bb325SJeff Bonwick byteswap_uint64_array(&verifier, sizeof (zio_cksum_t)); 350e14bb325SJeff Bonwick 3516e1f5caaSNeil Perrin expected_cksum = eck->zec_cksum; 3526e1f5caaSNeil Perrin eck->zec_cksum = verifier; 35345818ee1SMatthew Ahrens ci->ci_func[byteswap](data, size, 35445818ee1SMatthew Ahrens spa->spa_cksum_tmpls[checksum], &actual_cksum); 3556e1f5caaSNeil Perrin eck->zec_cksum = expected_cksum; 356e14bb325SJeff Bonwick 357e14bb325SJeff Bonwick if (byteswap) 358fa9e4066Sahrens byteswap_uint64_array(&expected_cksum, 359fa9e4066Sahrens sizeof (zio_cksum_t)); 360fa9e4066Sahrens } else { 36144cd46caSbillm ASSERT(!BP_IS_GANG(bp)); 362e14bb325SJeff Bonwick byteswap = BP_SHOULD_BYTESWAP(bp); 363e14bb325SJeff Bonwick expected_cksum = bp->blk_cksum; 36445818ee1SMatthew Ahrens ci->ci_func[byteswap](data, size, 36545818ee1SMatthew Ahrens spa->spa_cksum_tmpls[checksum], &actual_cksum); 366fa9e4066Sahrens } 367fa9e4066Sahrens 36822fe2c88SJonathan Adams info->zbc_expected = expected_cksum; 36922fe2c88SJonathan Adams info->zbc_actual = actual_cksum; 37022fe2c88SJonathan Adams info->zbc_checksum_name = ci->ci_name; 37122fe2c88SJonathan Adams info->zbc_byteswapped = byteswap; 37222fe2c88SJonathan Adams info->zbc_injected = 0; 37322fe2c88SJonathan Adams info->zbc_has_cksum = 1; 37422fe2c88SJonathan Adams 375e14bb325SJeff Bonwick if (!ZIO_CHECKSUM_EQUAL(actual_cksum, expected_cksum)) 376be6fd75aSMatthew Ahrens return (SET_ERROR(ECKSUM)); 377fa9e4066Sahrens 37822fe2c88SJonathan Adams if (zio_injection_enabled && !zio->io_error && 37922fe2c88SJonathan Adams (error = zio_handle_fault_injection(zio, ECKSUM)) != 0) { 38022fe2c88SJonathan Adams 38122fe2c88SJonathan Adams info->zbc_injected = 1; 38222fe2c88SJonathan Adams return (error); 38322fe2c88SJonathan Adams } 384ea8dc4b6Seschrock 385fa9e4066Sahrens return (0); 386fa9e4066Sahrens } 38745818ee1SMatthew Ahrens 38845818ee1SMatthew Ahrens /* 38945818ee1SMatthew Ahrens * Called by a spa_t that's about to be deallocated. This steps through 39045818ee1SMatthew Ahrens * all of the checksum context templates and deallocates any that were 39145818ee1SMatthew Ahrens * initialized using the algorithm-specific template init function. 39245818ee1SMatthew Ahrens */ 39345818ee1SMatthew Ahrens void 39445818ee1SMatthew Ahrens zio_checksum_templates_free(spa_t *spa) 39545818ee1SMatthew Ahrens { 39645818ee1SMatthew Ahrens for (enum zio_checksum checksum = 0; 39745818ee1SMatthew Ahrens checksum < ZIO_CHECKSUM_FUNCTIONS; checksum++) { 39845818ee1SMatthew Ahrens if (spa->spa_cksum_tmpls[checksum] != NULL) { 39945818ee1SMatthew Ahrens zio_checksum_info_t *ci = &zio_checksum_table[checksum]; 40045818ee1SMatthew Ahrens 40145818ee1SMatthew Ahrens VERIFY(ci->ci_tmpl_free != NULL); 40245818ee1SMatthew Ahrens ci->ci_tmpl_free(spa->spa_cksum_tmpls[checksum]); 40345818ee1SMatthew Ahrens spa->spa_cksum_tmpls[checksum] = NULL; 40445818ee1SMatthew Ahrens } 40545818ee1SMatthew Ahrens } 40645818ee1SMatthew Ahrens } 407