xref: /titanic_44/usr/src/uts/common/fs/zfs/zio_checksum.c (revision 810e43b2eb0e320833671a403fdda51917e8b036)
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