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 /* 22*22fe2c88SJonathan Adams * Copyright 2009 Sun Microsystems, Inc. All rights reserved. 23fa9e4066Sahrens * Use is subject to license terms. 24fa9e4066Sahrens */ 25fa9e4066Sahrens 26fa9e4066Sahrens #include <sys/zfs_context.h> 27fa9e4066Sahrens #include <sys/spa.h> 28fa9e4066Sahrens #include <sys/zio.h> 29fa9e4066Sahrens #include <sys/zio_checksum.h> 30fa9e4066Sahrens 31fa9e4066Sahrens /* 32fa9e4066Sahrens * Checksum vectors. 33fa9e4066Sahrens * 34fa9e4066Sahrens * In the SPA, everything is checksummed. We support checksum vectors 35fa9e4066Sahrens * for three distinct reasons: 36fa9e4066Sahrens * 37fa9e4066Sahrens * 1. Different kinds of data need different levels of protection. 38fa9e4066Sahrens * For SPA metadata, we always want a very strong checksum. 39fa9e4066Sahrens * For user data, we let users make the trade-off between speed 40fa9e4066Sahrens * and checksum strength. 41fa9e4066Sahrens * 42fa9e4066Sahrens * 2. Cryptographic hash and MAC algorithms are an area of active research. 43fa9e4066Sahrens * It is likely that in future hash functions will be at least as strong 44fa9e4066Sahrens * as current best-of-breed, and may be substantially faster as well. 45fa9e4066Sahrens * We want the ability to take advantage of these new hashes as soon as 46fa9e4066Sahrens * they become available. 47fa9e4066Sahrens * 48fa9e4066Sahrens * 3. If someone develops hardware that can compute a strong hash quickly, 49fa9e4066Sahrens * we want the ability to take advantage of that hardware. 50fa9e4066Sahrens * 51fa9e4066Sahrens * Of course, we don't want a checksum upgrade to invalidate existing 52fa9e4066Sahrens * data, so we store the checksum *function* in five bits of the DVA. 53fa9e4066Sahrens * This gives us room for up to 32 different checksum functions. 54fa9e4066Sahrens * 55fa9e4066Sahrens * When writing a block, we always checksum it with the latest-and-greatest 56fa9e4066Sahrens * checksum function of the appropriate strength. When reading a block, 57fa9e4066Sahrens * we compare the expected checksum against the actual checksum, which we 58fa9e4066Sahrens * compute via the checksum function specified in the DVA encoding. 59fa9e4066Sahrens */ 60fa9e4066Sahrens 61fa9e4066Sahrens /*ARGSUSED*/ 62fa9e4066Sahrens static void 63fa9e4066Sahrens zio_checksum_off(const void *buf, uint64_t size, zio_cksum_t *zcp) 64fa9e4066Sahrens { 65fa9e4066Sahrens ZIO_SET_CHECKSUM(zcp, 0, 0, 0, 0); 66fa9e4066Sahrens } 67fa9e4066Sahrens 68fa9e4066Sahrens zio_checksum_info_t zio_checksum_table[ZIO_CHECKSUM_FUNCTIONS] = { 695ad82045Snd {{NULL, NULL}, 0, 0, "inherit"}, 705ad82045Snd {{NULL, NULL}, 0, 0, "on"}, 715ad82045Snd {{zio_checksum_off, zio_checksum_off}, 0, 0, "off"}, 725ad82045Snd {{zio_checksum_SHA256, zio_checksum_SHA256}, 1, 1, "label"}, 735ad82045Snd {{zio_checksum_SHA256, zio_checksum_SHA256}, 1, 1, "gang_header"}, 745ad82045Snd {{fletcher_2_native, fletcher_2_byteswap}, 0, 1, "zilog"}, 755ad82045Snd {{fletcher_2_native, fletcher_2_byteswap}, 0, 0, "fletcher2"}, 765ad82045Snd {{fletcher_4_native, fletcher_4_byteswap}, 1, 0, "fletcher4"}, 775ad82045Snd {{zio_checksum_SHA256, zio_checksum_SHA256}, 1, 0, "SHA256"}, 78fa9e4066Sahrens }; 79fa9e4066Sahrens 80fa9e4066Sahrens uint8_t 81fa9e4066Sahrens zio_checksum_select(uint8_t child, uint8_t parent) 82fa9e4066Sahrens { 83fa9e4066Sahrens ASSERT(child < ZIO_CHECKSUM_FUNCTIONS); 84fa9e4066Sahrens ASSERT(parent < ZIO_CHECKSUM_FUNCTIONS); 85fa9e4066Sahrens ASSERT(parent != ZIO_CHECKSUM_INHERIT && parent != ZIO_CHECKSUM_ON); 86fa9e4066Sahrens 87fa9e4066Sahrens if (child == ZIO_CHECKSUM_INHERIT) 88fa9e4066Sahrens return (parent); 89fa9e4066Sahrens 90fa9e4066Sahrens if (child == ZIO_CHECKSUM_ON) 91fa9e4066Sahrens return (ZIO_CHECKSUM_ON_VALUE); 92fa9e4066Sahrens 93fa9e4066Sahrens return (child); 94fa9e4066Sahrens } 95fa9e4066Sahrens 96e14bb325SJeff Bonwick /* 97e14bb325SJeff Bonwick * Set the external verifier for a gang block based on <vdev, offset, txg>, 98e14bb325SJeff Bonwick * a tuple which is guaranteed to be unique for the life of the pool. 99e14bb325SJeff Bonwick */ 100e14bb325SJeff Bonwick static void 101e14bb325SJeff Bonwick zio_checksum_gang_verifier(zio_cksum_t *zcp, blkptr_t *bp) 102e14bb325SJeff Bonwick { 103e14bb325SJeff Bonwick dva_t *dva = BP_IDENTITY(bp); 104e14bb325SJeff Bonwick uint64_t txg = bp->blk_birth; 105e14bb325SJeff Bonwick 106e14bb325SJeff Bonwick ASSERT(BP_IS_GANG(bp)); 107e14bb325SJeff Bonwick 108e14bb325SJeff Bonwick ZIO_SET_CHECKSUM(zcp, DVA_GET_VDEV(dva), DVA_GET_OFFSET(dva), txg, 0); 109e14bb325SJeff Bonwick } 110e14bb325SJeff Bonwick 111e14bb325SJeff Bonwick /* 112e14bb325SJeff Bonwick * Set the external verifier for a label block based on its offset. 113e14bb325SJeff Bonwick * The vdev is implicit, and the txg is unknowable at pool open time -- 114e14bb325SJeff Bonwick * hence the logic in vdev_uberblock_load() to find the most recent copy. 115e14bb325SJeff Bonwick */ 116e14bb325SJeff Bonwick static void 117e14bb325SJeff Bonwick zio_checksum_label_verifier(zio_cksum_t *zcp, uint64_t offset) 118e14bb325SJeff Bonwick { 119e14bb325SJeff Bonwick ZIO_SET_CHECKSUM(zcp, offset, 0, 0, 0); 120e14bb325SJeff Bonwick } 121e14bb325SJeff Bonwick 122fa9e4066Sahrens /* 123fa9e4066Sahrens * Generate the checksum. 124fa9e4066Sahrens */ 125fa9e4066Sahrens void 126e14bb325SJeff Bonwick zio_checksum_compute(zio_t *zio, enum zio_checksum checksum, 127e14bb325SJeff Bonwick void *data, uint64_t size) 128fa9e4066Sahrens { 129e14bb325SJeff Bonwick blkptr_t *bp = zio->io_bp; 130e14bb325SJeff Bonwick uint64_t offset = zio->io_offset; 131fa9e4066Sahrens zio_block_tail_t *zbt = (zio_block_tail_t *)((char *)data + size) - 1; 132fa9e4066Sahrens zio_checksum_info_t *ci = &zio_checksum_table[checksum]; 133fa9e4066Sahrens zio_cksum_t zbt_cksum; 134fa9e4066Sahrens 135e14bb325SJeff Bonwick ASSERT((uint_t)checksum < ZIO_CHECKSUM_FUNCTIONS); 136fa9e4066Sahrens ASSERT(ci->ci_func[0] != NULL); 137fa9e4066Sahrens 138fa9e4066Sahrens if (ci->ci_zbt) { 139e14bb325SJeff Bonwick if (checksum == ZIO_CHECKSUM_GANG_HEADER) 140e14bb325SJeff Bonwick zio_checksum_gang_verifier(&zbt->zbt_cksum, bp); 141e14bb325SJeff Bonwick else if (checksum == ZIO_CHECKSUM_LABEL) 142e14bb325SJeff Bonwick zio_checksum_label_verifier(&zbt->zbt_cksum, offset); 143e14bb325SJeff Bonwick else 144e14bb325SJeff Bonwick bp->blk_cksum = zbt->zbt_cksum; 145fa9e4066Sahrens zbt->zbt_magic = ZBT_MAGIC; 146fa9e4066Sahrens ci->ci_func[0](data, size, &zbt_cksum); 147fa9e4066Sahrens zbt->zbt_cksum = zbt_cksum; 148fa9e4066Sahrens } else { 149e14bb325SJeff Bonwick ci->ci_func[0](data, size, &bp->blk_cksum); 150fa9e4066Sahrens } 151fa9e4066Sahrens } 152fa9e4066Sahrens 153fa9e4066Sahrens int 154*22fe2c88SJonathan Adams zio_checksum_error(zio_t *zio, zio_bad_cksum_t *info) 155fa9e4066Sahrens { 156fa9e4066Sahrens blkptr_t *bp = zio->io_bp; 157e14bb325SJeff Bonwick uint_t checksum = (bp == NULL ? zio->io_prop.zp_checksum : 158e14bb325SJeff Bonwick (BP_IS_GANG(bp) ? ZIO_CHECKSUM_GANG_HEADER : BP_GET_CHECKSUM(bp))); 159e14bb325SJeff Bonwick int byteswap; 160*22fe2c88SJonathan Adams int error; 161e14bb325SJeff Bonwick uint64_t size = (bp == NULL ? zio->io_size : 162e14bb325SJeff Bonwick (BP_IS_GANG(bp) ? SPA_GANGBLOCKSIZE : BP_GET_PSIZE(bp))); 163e14bb325SJeff Bonwick uint64_t offset = zio->io_offset; 164*22fe2c88SJonathan Adams void *data = zio->io_data; 165fa9e4066Sahrens zio_block_tail_t *zbt = (zio_block_tail_t *)((char *)data + size) - 1; 166fa9e4066Sahrens zio_checksum_info_t *ci = &zio_checksum_table[checksum]; 167e14bb325SJeff Bonwick zio_cksum_t actual_cksum, expected_cksum, verifier; 168fa9e4066Sahrens 169fa9e4066Sahrens if (checksum >= ZIO_CHECKSUM_FUNCTIONS || ci->ci_func[0] == NULL) 170fa9e4066Sahrens return (EINVAL); 171fa9e4066Sahrens 172fa9e4066Sahrens if (ci->ci_zbt) { 173fa9e4066Sahrens if (checksum == ZIO_CHECKSUM_GANG_HEADER) 174e14bb325SJeff Bonwick zio_checksum_gang_verifier(&verifier, bp); 175e14bb325SJeff Bonwick else if (checksum == ZIO_CHECKSUM_LABEL) 176e14bb325SJeff Bonwick zio_checksum_label_verifier(&verifier, offset); 177e14bb325SJeff Bonwick else 178e14bb325SJeff Bonwick verifier = bp->blk_cksum; 179e14bb325SJeff Bonwick 180e14bb325SJeff Bonwick byteswap = (zbt->zbt_magic == BSWAP_64(ZBT_MAGIC)); 181fa9e4066Sahrens 182e14bb325SJeff Bonwick if (byteswap) 183e14bb325SJeff Bonwick byteswap_uint64_array(&verifier, sizeof (zio_cksum_t)); 184e14bb325SJeff Bonwick 185e14bb325SJeff Bonwick expected_cksum = zbt->zbt_cksum; 186e14bb325SJeff Bonwick zbt->zbt_cksum = verifier; 187e14bb325SJeff Bonwick ci->ci_func[byteswap](data, size, &actual_cksum); 188e14bb325SJeff Bonwick zbt->zbt_cksum = expected_cksum; 189e14bb325SJeff Bonwick 190e14bb325SJeff Bonwick if (byteswap) 191fa9e4066Sahrens byteswap_uint64_array(&expected_cksum, 192fa9e4066Sahrens sizeof (zio_cksum_t)); 193fa9e4066Sahrens } else { 19444cd46caSbillm ASSERT(!BP_IS_GANG(bp)); 195e14bb325SJeff Bonwick byteswap = BP_SHOULD_BYTESWAP(bp); 196e14bb325SJeff Bonwick expected_cksum = bp->blk_cksum; 197fa9e4066Sahrens ci->ci_func[byteswap](data, size, &actual_cksum); 198fa9e4066Sahrens } 199fa9e4066Sahrens 200*22fe2c88SJonathan Adams info->zbc_expected = expected_cksum; 201*22fe2c88SJonathan Adams info->zbc_actual = actual_cksum; 202*22fe2c88SJonathan Adams info->zbc_checksum_name = ci->ci_name; 203*22fe2c88SJonathan Adams info->zbc_byteswapped = byteswap; 204*22fe2c88SJonathan Adams info->zbc_injected = 0; 205*22fe2c88SJonathan Adams info->zbc_has_cksum = 1; 206*22fe2c88SJonathan Adams 207e14bb325SJeff Bonwick if (!ZIO_CHECKSUM_EQUAL(actual_cksum, expected_cksum)) 208fa9e4066Sahrens return (ECKSUM); 209fa9e4066Sahrens 210*22fe2c88SJonathan Adams if (zio_injection_enabled && !zio->io_error && 211*22fe2c88SJonathan Adams (error = zio_handle_fault_injection(zio, ECKSUM)) != 0) { 212*22fe2c88SJonathan Adams 213*22fe2c88SJonathan Adams info->zbc_injected = 1; 214*22fe2c88SJonathan Adams return (error); 215*22fe2c88SJonathan Adams } 216ea8dc4b6Seschrock 217fa9e4066Sahrens return (0); 218fa9e4066Sahrens } 219