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.
23be6fd75aSMatthew Ahrens * Copyright (c) 2013 by Delphix. All rights reserved.
24*810e43b2SBill Pijewski * Copyright (c) 2013, Joyent, Inc. All rights reserved.
25fa9e4066Sahrens */
26fa9e4066Sahrens
27fa9e4066Sahrens #include <sys/zfs_context.h>
28fa9e4066Sahrens #include <sys/spa.h>
29fa9e4066Sahrens #include <sys/zio.h>
30fa9e4066Sahrens #include <sys/zio_checksum.h>
316e1f5caaSNeil Perrin #include <sys/zil.h>
32cde58dbcSMatthew Ahrens #include <zfs_fletcher.h>
33fa9e4066Sahrens
34fa9e4066Sahrens /*
35fa9e4066Sahrens * Checksum vectors.
36fa9e4066Sahrens *
37fa9e4066Sahrens * In the SPA, everything is checksummed. We support checksum vectors
38fa9e4066Sahrens * for three distinct reasons:
39fa9e4066Sahrens *
40fa9e4066Sahrens * 1. Different kinds of data need different levels of protection.
41fa9e4066Sahrens * For SPA metadata, we always want a very strong checksum.
42fa9e4066Sahrens * For user data, we let users make the trade-off between speed
43fa9e4066Sahrens * and checksum strength.
44fa9e4066Sahrens *
45fa9e4066Sahrens * 2. Cryptographic hash and MAC algorithms are an area of active research.
46fa9e4066Sahrens * It is likely that in future hash functions will be at least as strong
47fa9e4066Sahrens * as current best-of-breed, and may be substantially faster as well.
48fa9e4066Sahrens * We want the ability to take advantage of these new hashes as soon as
49fa9e4066Sahrens * they become available.
50fa9e4066Sahrens *
51fa9e4066Sahrens * 3. If someone develops hardware that can compute a strong hash quickly,
52fa9e4066Sahrens * we want the ability to take advantage of that hardware.
53fa9e4066Sahrens *
54fa9e4066Sahrens * Of course, we don't want a checksum upgrade to invalidate existing
55b24ab676SJeff Bonwick * data, so we store the checksum *function* in eight bits of the bp.
56b24ab676SJeff Bonwick * This gives us room for up to 256 different checksum functions.
57fa9e4066Sahrens *
58fa9e4066Sahrens * When writing a block, we always checksum it with the latest-and-greatest
59fa9e4066Sahrens * checksum function of the appropriate strength. When reading a block,
60fa9e4066Sahrens * we compare the expected checksum against the actual checksum, which we
61b24ab676SJeff Bonwick * compute via the checksum function specified by BP_GET_CHECKSUM(bp).
62fa9e4066Sahrens */
63fa9e4066Sahrens
64fa9e4066Sahrens /*ARGSUSED*/
65fa9e4066Sahrens static void
zio_checksum_off(const void * buf,uint64_t size,zio_cksum_t * zcp)66fa9e4066Sahrens zio_checksum_off(const void *buf, uint64_t size, zio_cksum_t *zcp)
67fa9e4066Sahrens {
68fa9e4066Sahrens ZIO_SET_CHECKSUM(zcp, 0, 0, 0, 0);
69fa9e4066Sahrens }
70fa9e4066Sahrens
71fa9e4066Sahrens zio_checksum_info_t zio_checksum_table[ZIO_CHECKSUM_FUNCTIONS] = {
72b24ab676SJeff Bonwick {{NULL, NULL}, 0, 0, 0, "inherit"},
73b24ab676SJeff Bonwick {{NULL, NULL}, 0, 0, 0, "on"},
74b24ab676SJeff Bonwick {{zio_checksum_off, zio_checksum_off}, 0, 0, 0, "off"},
75b24ab676SJeff Bonwick {{zio_checksum_SHA256, zio_checksum_SHA256}, 1, 1, 0, "label"},
76b24ab676SJeff Bonwick {{zio_checksum_SHA256, zio_checksum_SHA256}, 1, 1, 0, "gang_header"},
77b24ab676SJeff Bonwick {{fletcher_2_native, fletcher_2_byteswap}, 0, 1, 0, "zilog"},
78b24ab676SJeff Bonwick {{fletcher_2_native, fletcher_2_byteswap}, 0, 0, 0, "fletcher2"},
79b24ab676SJeff Bonwick {{fletcher_4_native, fletcher_4_byteswap}, 1, 0, 0, "fletcher4"},
80b24ab676SJeff Bonwick {{zio_checksum_SHA256, zio_checksum_SHA256}, 1, 0, 1, "sha256"},
816e1f5caaSNeil Perrin {{fletcher_4_native, fletcher_4_byteswap}, 0, 1, 0, "zilog2"},
82*810e43b2SBill Pijewski {{zio_checksum_off, zio_checksum_off}, 0, 0, 0, "noparity"},
83fa9e4066Sahrens };
84fa9e4066Sahrens
85b24ab676SJeff Bonwick enum zio_checksum
zio_checksum_select(enum zio_checksum child,enum zio_checksum parent)86b24ab676SJeff Bonwick zio_checksum_select(enum zio_checksum child, enum zio_checksum parent)
87fa9e4066Sahrens {
88fa9e4066Sahrens ASSERT(child < ZIO_CHECKSUM_FUNCTIONS);
89fa9e4066Sahrens ASSERT(parent < ZIO_CHECKSUM_FUNCTIONS);
90fa9e4066Sahrens ASSERT(parent != ZIO_CHECKSUM_INHERIT && parent != ZIO_CHECKSUM_ON);
91fa9e4066Sahrens
92fa9e4066Sahrens if (child == ZIO_CHECKSUM_INHERIT)
93fa9e4066Sahrens return (parent);
94fa9e4066Sahrens
95fa9e4066Sahrens if (child == ZIO_CHECKSUM_ON)
96fa9e4066Sahrens return (ZIO_CHECKSUM_ON_VALUE);
97fa9e4066Sahrens
98fa9e4066Sahrens return (child);
99fa9e4066Sahrens }
100fa9e4066Sahrens
101b24ab676SJeff Bonwick enum zio_checksum
zio_checksum_dedup_select(spa_t * spa,enum zio_checksum child,enum zio_checksum parent)102b24ab676SJeff Bonwick zio_checksum_dedup_select(spa_t *spa, enum zio_checksum child,
103b24ab676SJeff Bonwick enum zio_checksum parent)
104b24ab676SJeff Bonwick {
105b24ab676SJeff Bonwick ASSERT((child & ZIO_CHECKSUM_MASK) < ZIO_CHECKSUM_FUNCTIONS);
106b24ab676SJeff Bonwick ASSERT((parent & ZIO_CHECKSUM_MASK) < ZIO_CHECKSUM_FUNCTIONS);
107b24ab676SJeff Bonwick ASSERT(parent != ZIO_CHECKSUM_INHERIT && parent != ZIO_CHECKSUM_ON);
108b24ab676SJeff Bonwick
109b24ab676SJeff Bonwick if (child == ZIO_CHECKSUM_INHERIT)
110b24ab676SJeff Bonwick return (parent);
111b24ab676SJeff Bonwick
112b24ab676SJeff Bonwick if (child == ZIO_CHECKSUM_ON)
113b24ab676SJeff Bonwick return (spa_dedup_checksum(spa));
114b24ab676SJeff Bonwick
115b24ab676SJeff Bonwick if (child == (ZIO_CHECKSUM_ON | ZIO_CHECKSUM_VERIFY))
116b24ab676SJeff Bonwick return (spa_dedup_checksum(spa) | ZIO_CHECKSUM_VERIFY);
117b24ab676SJeff Bonwick
118b24ab676SJeff Bonwick ASSERT(zio_checksum_table[child & ZIO_CHECKSUM_MASK].ci_dedup ||
119b24ab676SJeff Bonwick (child & ZIO_CHECKSUM_VERIFY) || child == ZIO_CHECKSUM_OFF);
120b24ab676SJeff Bonwick
121b24ab676SJeff Bonwick return (child);
122b24ab676SJeff Bonwick }
123b24ab676SJeff Bonwick
124fa9e4066Sahrens /*
125e14bb325SJeff Bonwick * Set the external verifier for a gang block based on <vdev, offset, txg>,
126e14bb325SJeff Bonwick * a tuple which is guaranteed to be unique for the life of the pool.
127e14bb325SJeff Bonwick */
128e14bb325SJeff Bonwick static void
zio_checksum_gang_verifier(zio_cksum_t * zcp,blkptr_t * bp)129e14bb325SJeff Bonwick zio_checksum_gang_verifier(zio_cksum_t *zcp, blkptr_t *bp)
130e14bb325SJeff Bonwick {
131e14bb325SJeff Bonwick dva_t *dva = BP_IDENTITY(bp);
132b24ab676SJeff Bonwick uint64_t txg = BP_PHYSICAL_BIRTH(bp);
133e14bb325SJeff Bonwick
134e14bb325SJeff Bonwick ASSERT(BP_IS_GANG(bp));
135e14bb325SJeff Bonwick
136e14bb325SJeff Bonwick ZIO_SET_CHECKSUM(zcp, DVA_GET_VDEV(dva), DVA_GET_OFFSET(dva), txg, 0);
137e14bb325SJeff Bonwick }
138e14bb325SJeff Bonwick
139e14bb325SJeff Bonwick /*
140e14bb325SJeff Bonwick * Set the external verifier for a label block based on its offset.
141e14bb325SJeff Bonwick * The vdev is implicit, and the txg is unknowable at pool open time --
142e14bb325SJeff Bonwick * hence the logic in vdev_uberblock_load() to find the most recent copy.
143e14bb325SJeff Bonwick */
144e14bb325SJeff Bonwick static void
zio_checksum_label_verifier(zio_cksum_t * zcp,uint64_t offset)145e14bb325SJeff Bonwick zio_checksum_label_verifier(zio_cksum_t *zcp, uint64_t offset)
146e14bb325SJeff Bonwick {
147e14bb325SJeff Bonwick ZIO_SET_CHECKSUM(zcp, offset, 0, 0, 0);
148e14bb325SJeff Bonwick }
149e14bb325SJeff Bonwick
150e14bb325SJeff Bonwick /*
151fa9e4066Sahrens * Generate the checksum.
152fa9e4066Sahrens */
153fa9e4066Sahrens void
zio_checksum_compute(zio_t * zio,enum zio_checksum checksum,void * data,uint64_t size)154e14bb325SJeff Bonwick zio_checksum_compute(zio_t *zio, enum zio_checksum checksum,
155e14bb325SJeff Bonwick void *data, uint64_t size)
156fa9e4066Sahrens {
157e14bb325SJeff Bonwick blkptr_t *bp = zio->io_bp;
158e14bb325SJeff Bonwick uint64_t offset = zio->io_offset;
159fa9e4066Sahrens zio_checksum_info_t *ci = &zio_checksum_table[checksum];
1606e1f5caaSNeil Perrin zio_cksum_t cksum;
161fa9e4066Sahrens
162e14bb325SJeff Bonwick ASSERT((uint_t)checksum < ZIO_CHECKSUM_FUNCTIONS);
163fa9e4066Sahrens ASSERT(ci->ci_func[0] != NULL);
164fa9e4066Sahrens
1656e1f5caaSNeil Perrin if (ci->ci_eck) {
1666e1f5caaSNeil Perrin zio_eck_t *eck;
1676e1f5caaSNeil Perrin
1686e1f5caaSNeil Perrin if (checksum == ZIO_CHECKSUM_ZILOG2) {
1696e1f5caaSNeil Perrin zil_chain_t *zilc = data;
1706e1f5caaSNeil Perrin
1716e1f5caaSNeil Perrin size = P2ROUNDUP_TYPED(zilc->zc_nused, ZIL_MIN_BLKSZ,
1726e1f5caaSNeil Perrin uint64_t);
1736e1f5caaSNeil Perrin eck = &zilc->zc_eck;
1746e1f5caaSNeil Perrin } else {
1756e1f5caaSNeil Perrin eck = (zio_eck_t *)((char *)data + size) - 1;
1766e1f5caaSNeil Perrin }
177e14bb325SJeff Bonwick if (checksum == ZIO_CHECKSUM_GANG_HEADER)
1786e1f5caaSNeil Perrin zio_checksum_gang_verifier(&eck->zec_cksum, bp);
179e14bb325SJeff Bonwick else if (checksum == ZIO_CHECKSUM_LABEL)
1806e1f5caaSNeil Perrin zio_checksum_label_verifier(&eck->zec_cksum, offset);
181e14bb325SJeff Bonwick else
1826e1f5caaSNeil Perrin bp->blk_cksum = eck->zec_cksum;
1836e1f5caaSNeil Perrin eck->zec_magic = ZEC_MAGIC;
1846e1f5caaSNeil Perrin ci->ci_func[0](data, size, &cksum);
1856e1f5caaSNeil Perrin eck->zec_cksum = cksum;
186fa9e4066Sahrens } else {
187e14bb325SJeff Bonwick ci->ci_func[0](data, size, &bp->blk_cksum);
188fa9e4066Sahrens }
189fa9e4066Sahrens }
190fa9e4066Sahrens
191fa9e4066Sahrens int
zio_checksum_error(zio_t * zio,zio_bad_cksum_t * info)19222fe2c88SJonathan Adams zio_checksum_error(zio_t *zio, zio_bad_cksum_t *info)
193fa9e4066Sahrens {
194fa9e4066Sahrens blkptr_t *bp = zio->io_bp;
195e14bb325SJeff Bonwick uint_t checksum = (bp == NULL ? zio->io_prop.zp_checksum :
196e14bb325SJeff Bonwick (BP_IS_GANG(bp) ? ZIO_CHECKSUM_GANG_HEADER : BP_GET_CHECKSUM(bp)));
197e14bb325SJeff Bonwick int byteswap;
19822fe2c88SJonathan Adams int error;
199e14bb325SJeff Bonwick uint64_t size = (bp == NULL ? zio->io_size :
200e14bb325SJeff Bonwick (BP_IS_GANG(bp) ? SPA_GANGBLOCKSIZE : BP_GET_PSIZE(bp)));
201e14bb325SJeff Bonwick uint64_t offset = zio->io_offset;
20222fe2c88SJonathan Adams void *data = zio->io_data;
203fa9e4066Sahrens zio_checksum_info_t *ci = &zio_checksum_table[checksum];
204e14bb325SJeff Bonwick zio_cksum_t actual_cksum, expected_cksum, verifier;
205fa9e4066Sahrens
206fa9e4066Sahrens if (checksum >= ZIO_CHECKSUM_FUNCTIONS || ci->ci_func[0] == NULL)
207be6fd75aSMatthew Ahrens return (SET_ERROR(EINVAL));
208fa9e4066Sahrens
2096e1f5caaSNeil Perrin if (ci->ci_eck) {
2106e1f5caaSNeil Perrin zio_eck_t *eck;
2116e1f5caaSNeil Perrin
2126e1f5caaSNeil Perrin if (checksum == ZIO_CHECKSUM_ZILOG2) {
2136e1f5caaSNeil Perrin zil_chain_t *zilc = data;
2146e1f5caaSNeil Perrin uint64_t nused;
2156e1f5caaSNeil Perrin
2166e1f5caaSNeil Perrin eck = &zilc->zc_eck;
2176e1f5caaSNeil Perrin if (eck->zec_magic == ZEC_MAGIC)
2186e1f5caaSNeil Perrin nused = zilc->zc_nused;
2196e1f5caaSNeil Perrin else if (eck->zec_magic == BSWAP_64(ZEC_MAGIC))
2206e1f5caaSNeil Perrin nused = BSWAP_64(zilc->zc_nused);
2216e1f5caaSNeil Perrin else
222be6fd75aSMatthew Ahrens return (SET_ERROR(ECKSUM));
2236e1f5caaSNeil Perrin
2246e1f5caaSNeil Perrin if (nused > size)
225be6fd75aSMatthew Ahrens return (SET_ERROR(ECKSUM));
2266e1f5caaSNeil Perrin
2276e1f5caaSNeil Perrin size = P2ROUNDUP_TYPED(nused, ZIL_MIN_BLKSZ, uint64_t);
2286e1f5caaSNeil Perrin } else {
2296e1f5caaSNeil Perrin eck = (zio_eck_t *)((char *)data + size) - 1;
2306e1f5caaSNeil Perrin }
2316e1f5caaSNeil Perrin
232fa9e4066Sahrens if (checksum == ZIO_CHECKSUM_GANG_HEADER)
233e14bb325SJeff Bonwick zio_checksum_gang_verifier(&verifier, bp);
234e14bb325SJeff Bonwick else if (checksum == ZIO_CHECKSUM_LABEL)
235e14bb325SJeff Bonwick zio_checksum_label_verifier(&verifier, offset);
236e14bb325SJeff Bonwick else
237e14bb325SJeff Bonwick verifier = bp->blk_cksum;
238fa9e4066Sahrens
2396e1f5caaSNeil Perrin byteswap = (eck->zec_magic == BSWAP_64(ZEC_MAGIC));
240e14bb325SJeff Bonwick
241e14bb325SJeff Bonwick if (byteswap)
242e14bb325SJeff Bonwick byteswap_uint64_array(&verifier, sizeof (zio_cksum_t));
243e14bb325SJeff Bonwick
2446e1f5caaSNeil Perrin expected_cksum = eck->zec_cksum;
2456e1f5caaSNeil Perrin eck->zec_cksum = verifier;
246e14bb325SJeff Bonwick ci->ci_func[byteswap](data, size, &actual_cksum);
2476e1f5caaSNeil Perrin eck->zec_cksum = expected_cksum;
248e14bb325SJeff Bonwick
249e14bb325SJeff Bonwick if (byteswap)
250fa9e4066Sahrens byteswap_uint64_array(&expected_cksum,
251fa9e4066Sahrens sizeof (zio_cksum_t));
252fa9e4066Sahrens } else {
25344cd46caSbillm ASSERT(!BP_IS_GANG(bp));
254e14bb325SJeff Bonwick byteswap = BP_SHOULD_BYTESWAP(bp);
255e14bb325SJeff Bonwick expected_cksum = bp->blk_cksum;
256fa9e4066Sahrens ci->ci_func[byteswap](data, size, &actual_cksum);
257fa9e4066Sahrens }
258fa9e4066Sahrens
25922fe2c88SJonathan Adams info->zbc_expected = expected_cksum;
26022fe2c88SJonathan Adams info->zbc_actual = actual_cksum;
26122fe2c88SJonathan Adams info->zbc_checksum_name = ci->ci_name;
26222fe2c88SJonathan Adams info->zbc_byteswapped = byteswap;
26322fe2c88SJonathan Adams info->zbc_injected = 0;
26422fe2c88SJonathan Adams info->zbc_has_cksum = 1;
26522fe2c88SJonathan Adams
266e14bb325SJeff Bonwick if (!ZIO_CHECKSUM_EQUAL(actual_cksum, expected_cksum))
267be6fd75aSMatthew Ahrens return (SET_ERROR(ECKSUM));
268fa9e4066Sahrens
26922fe2c88SJonathan Adams if (zio_injection_enabled && !zio->io_error &&
27022fe2c88SJonathan Adams (error = zio_handle_fault_injection(zio, ECKSUM)) != 0) {
27122fe2c88SJonathan Adams
27222fe2c88SJonathan Adams info->zbc_injected = 1;
27322fe2c88SJonathan Adams return (error);
27422fe2c88SJonathan Adams }
275ea8dc4b6Seschrock
276fa9e4066Sahrens return (0);
277fa9e4066Sahrens }
278