FreeBSD ZFS
The Zettabyte File System

zio_checksum.c

Go to the documentation of this file.
00001 /*
00002  * CDDL HEADER START
00003  *
00004  * The contents of this file are subject to the terms of the
00005  * Common Development and Distribution License (the "License").
00006  * You may not use this file except in compliance with the License.
00007  *
00008  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
00009  * or http://www.opensolaris.org/os/licensing.
00010  * See the License for the specific language governing permissions
00011  * and limitations under the License.
00012  *
00013  * When distributing Covered Code, include this CDDL HEADER in each
00014  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
00015  * If applicable, add the following below this CDDL HEADER, with the
00016  * fields enclosed by brackets "[]" replaced with your own identifying
00017  * information: Portions Copyright [yyyy] [name of copyright owner]
00018  *
00019  * CDDL HEADER END
00020  */
00021 /*
00022  * Copyright (c) 2005, 2010, Oracle and/or its affiliates. All rights reserved.
00023  */
00024 
00025 #include <sys/zfs_context.h>
00026 #include <sys/spa.h>
00027 #include <sys/zio.h>
00028 #include <sys/zio_checksum.h>
00029 #include <sys/zil.h>
00030 #include <zfs_fletcher.h>
00031 
00063 /*ARGSUSED*/
00064 static void
00065 zio_checksum_off(const void *buf, uint64_t size, zio_cksum_t *zcp)
00066 {
00067         ZIO_SET_CHECKSUM(zcp, 0, 0, 0, 0);
00068 }
00069 
00070 zio_checksum_info_t zio_checksum_table[ZIO_CHECKSUM_FUNCTIONS] = {
00071         {{NULL,                 NULL},                  0, 0, 0, "inherit"},
00072         {{NULL,                 NULL},                  0, 0, 0, "on"},
00073         {{zio_checksum_off,     zio_checksum_off},      0, 0, 0, "off"},
00074         {{zio_checksum_SHA256,  zio_checksum_SHA256},   1, 1, 0, "label"},
00075         {{zio_checksum_SHA256,  zio_checksum_SHA256},   1, 1, 0, "gang_header"},
00076         {{fletcher_2_native,    fletcher_2_byteswap},   0, 1, 0, "zilog"},
00077         {{fletcher_2_native,    fletcher_2_byteswap},   0, 0, 0, "fletcher2"},
00078         {{fletcher_4_native,    fletcher_4_byteswap},   1, 0, 0, "fletcher4"},
00079         {{zio_checksum_SHA256,  zio_checksum_SHA256},   1, 0, 1, "sha256"},
00080         {{fletcher_4_native,    fletcher_4_byteswap},   0, 1, 0, "zilog2"},
00081 };
00082 
00083 enum zio_checksum
00084 zio_checksum_select(enum zio_checksum child, enum zio_checksum parent)
00085 {
00086         ASSERT(child < ZIO_CHECKSUM_FUNCTIONS);
00087         ASSERT(parent < ZIO_CHECKSUM_FUNCTIONS);
00088         ASSERT(parent != ZIO_CHECKSUM_INHERIT && parent != ZIO_CHECKSUM_ON);
00089 
00090         if (child == ZIO_CHECKSUM_INHERIT)
00091                 return (parent);
00092 
00093         if (child == ZIO_CHECKSUM_ON)
00094                 return (ZIO_CHECKSUM_ON_VALUE);
00095 
00096         return (child);
00097 }
00098 
00099 enum zio_checksum
00100 zio_checksum_dedup_select(spa_t *spa, enum zio_checksum child,
00101     enum zio_checksum parent)
00102 {
00103         ASSERT((child & ZIO_CHECKSUM_MASK) < ZIO_CHECKSUM_FUNCTIONS);
00104         ASSERT((parent & ZIO_CHECKSUM_MASK) < ZIO_CHECKSUM_FUNCTIONS);
00105         ASSERT(parent != ZIO_CHECKSUM_INHERIT && parent != ZIO_CHECKSUM_ON);
00106 
00107         if (child == ZIO_CHECKSUM_INHERIT)
00108                 return (parent);
00109 
00110         if (child == ZIO_CHECKSUM_ON)
00111                 return (spa_dedup_checksum(spa));
00112 
00113         if (child == (ZIO_CHECKSUM_ON | ZIO_CHECKSUM_VERIFY))
00114                 return (spa_dedup_checksum(spa) | ZIO_CHECKSUM_VERIFY);
00115 
00116         ASSERT(zio_checksum_table[child & ZIO_CHECKSUM_MASK].ci_dedup ||
00117             (child & ZIO_CHECKSUM_VERIFY) || child == ZIO_CHECKSUM_OFF);
00118 
00119         return (child);
00120 }
00121 
00126 static void
00127 zio_checksum_gang_verifier(zio_cksum_t *zcp, blkptr_t *bp)
00128 {
00129         dva_t *dva = BP_IDENTITY(bp);
00130         uint64_t txg = BP_PHYSICAL_BIRTH(bp);
00131 
00132         ASSERT(BP_IS_GANG(bp));
00133 
00134         ZIO_SET_CHECKSUM(zcp, DVA_GET_VDEV(dva), DVA_GET_OFFSET(dva), txg, 0);
00135 }
00136 
00142 static void
00143 zio_checksum_label_verifier(zio_cksum_t *zcp, uint64_t offset)
00144 {
00145         ZIO_SET_CHECKSUM(zcp, offset, 0, 0, 0);
00146 }
00147 
00151 void
00152 zio_checksum_compute(zio_t *zio, enum zio_checksum checksum,
00153         void *data, uint64_t size)
00154 {
00155         blkptr_t *bp = zio->io_bp;
00156         uint64_t offset = zio->io_offset;
00157         zio_checksum_info_t *ci = &zio_checksum_table[checksum];
00158         zio_cksum_t cksum;
00159 
00160         ASSERT((uint_t)checksum < ZIO_CHECKSUM_FUNCTIONS);
00161         ASSERT(ci->ci_func[0] != NULL);
00162 
00163         if (ci->ci_eck) {
00164                 zio_eck_t *eck;
00165 
00166                 if (checksum == ZIO_CHECKSUM_ZILOG2) {
00167                         zil_chain_t *zilc = data;
00168 
00169                         size = P2ROUNDUP_TYPED(zilc->zc_nused, ZIL_MIN_BLKSZ,
00170                             uint64_t);
00171                         eck = &zilc->zc_eck;
00172                 } else {
00173                         eck = (zio_eck_t *)((char *)data + size) - 1;
00174                 }
00175                 if (checksum == ZIO_CHECKSUM_GANG_HEADER)
00176                         zio_checksum_gang_verifier(&eck->zec_cksum, bp);
00177                 else if (checksum == ZIO_CHECKSUM_LABEL)
00178                         zio_checksum_label_verifier(&eck->zec_cksum, offset);
00179                 else
00180                         bp->blk_cksum = eck->zec_cksum;
00181                 eck->zec_magic = ZEC_MAGIC;
00182                 ci->ci_func[0](data, size, &cksum);
00183                 eck->zec_cksum = cksum;
00184         } else {
00185                 ci->ci_func[0](data, size, &bp->blk_cksum);
00186         }
00187 }
00188 
00189 int
00190 zio_checksum_error(zio_t *zio, zio_bad_cksum_t *info)
00191 {
00192         blkptr_t *bp = zio->io_bp;
00193         uint_t checksum = (bp == NULL ? zio->io_prop.zp_checksum :
00194             (BP_IS_GANG(bp) ? ZIO_CHECKSUM_GANG_HEADER : BP_GET_CHECKSUM(bp)));
00195         int byteswap;
00196         int error;
00197         uint64_t size = (bp == NULL ? zio->io_size :
00198             (BP_IS_GANG(bp) ? SPA_GANGBLOCKSIZE : BP_GET_PSIZE(bp)));
00199         uint64_t offset = zio->io_offset;
00200         void *data = zio->io_data;
00201         zio_checksum_info_t *ci = &zio_checksum_table[checksum];
00202         zio_cksum_t actual_cksum, expected_cksum, verifier;
00203 
00204         if (checksum >= ZIO_CHECKSUM_FUNCTIONS || ci->ci_func[0] == NULL)
00205                 return (EINVAL);
00206 
00207         if (ci->ci_eck) {
00208                 zio_eck_t *eck;
00209 
00210                 if (checksum == ZIO_CHECKSUM_ZILOG2) {
00211                         zil_chain_t *zilc = data;
00212                         uint64_t nused;
00213 
00214                         eck = &zilc->zc_eck;
00215                         if (eck->zec_magic == ZEC_MAGIC)
00216                                 nused = zilc->zc_nused;
00217                         else if (eck->zec_magic == BSWAP_64(ZEC_MAGIC))
00218                                 nused = BSWAP_64(zilc->zc_nused);
00219                         else
00220                                 return (ECKSUM);
00221 
00222                         if (nused > size)
00223                                 return (ECKSUM);
00224 
00225                         size = P2ROUNDUP_TYPED(nused, ZIL_MIN_BLKSZ, uint64_t);
00226                 } else {
00227                         eck = (zio_eck_t *)((char *)data + size) - 1;
00228                 }
00229 
00230                 if (checksum == ZIO_CHECKSUM_GANG_HEADER)
00231                         zio_checksum_gang_verifier(&verifier, bp);
00232                 else if (checksum == ZIO_CHECKSUM_LABEL)
00233                         zio_checksum_label_verifier(&verifier, offset);
00234                 else
00235                         verifier = bp->blk_cksum;
00236 
00237                 byteswap = (eck->zec_magic == BSWAP_64(ZEC_MAGIC));
00238 
00239                 if (byteswap)
00240                         byteswap_uint64_array(&verifier, sizeof (zio_cksum_t));
00241 
00242                 expected_cksum = eck->zec_cksum;
00243                 eck->zec_cksum = verifier;
00244                 ci->ci_func[byteswap](data, size, &actual_cksum);
00245                 eck->zec_cksum = expected_cksum;
00246 
00247                 if (byteswap)
00248                         byteswap_uint64_array(&expected_cksum,
00249                             sizeof (zio_cksum_t));
00250         } else {
00251                 ASSERT(!BP_IS_GANG(bp));
00252                 byteswap = BP_SHOULD_BYTESWAP(bp);
00253                 expected_cksum = bp->blk_cksum;
00254                 ci->ci_func[byteswap](data, size, &actual_cksum);
00255         }
00256 
00257         info->zbc_expected = expected_cksum;
00258         info->zbc_actual = actual_cksum;
00259         info->zbc_checksum_name = ci->ci_name;
00260         info->zbc_byteswapped = byteswap;
00261         info->zbc_injected = 0;
00262         info->zbc_has_cksum = 1;
00263 
00264         if (!ZIO_CHECKSUM_EQUAL(actual_cksum, expected_cksum))
00265                 return (ECKSUM);
00266 
00267         if (zio_injection_enabled && !zio->io_error &&
00268             (error = zio_handle_fault_injection(zio, ECKSUM)) != 0) {
00269 
00270                 info->zbc_injected = 1;
00271                 return (error);
00272         }
00273 
00274         return (0);
00275 }
 All Data Structures Files Functions Variables Typedefs Enumerations Enumerator Defines