summaryrefslogtreecommitdiffstats
path: root/sys/cddl
diff options
context:
space:
mode:
authorkevans <kevans@FreeBSD.org>2018-02-05 04:00:59 +0000
committerkevans <kevans@FreeBSD.org>2018-02-05 04:00:59 +0000
commite8f715edec8f4dc88f556e93e1169b3086f25976 (patch)
tree97f284ee593088a9c411f73fc7301e726a943a5e /sys/cddl
parent6ae261d01a5f3356b0d863f3784b48c8f81be7fd (diff)
downloadFreeBSD-src-e8f715edec8f4dc88f556e93e1169b3086f25976.zip
FreeBSD-src-e8f715edec8f4dc88f556e93e1169b3086f25976.tar.gz
MFC r304321,304753,304754,306751,316077,316110:
SHA512, skein, large block support for loader zfs MFC r304321: Add SHA512, skein, large blocks support for loader zfs. MFC r304753: loader: zio_checksum_verify() must test spa for NULL pointer MFC r304754: r304321 broken bhyve zvol VM bhyveload hang 100% WCPU MFC r306751: Disable loop unrolling in skein for sys/boot MFC r316077: Unbreak compilation with gcc 4.2.1 MFC r316110: Use `-Wno-missing-declarations` with CWARNFLAGS for skein.c
Diffstat (limited to 'sys/cddl')
-rw-r--r--sys/cddl/boot/zfs/fletcher.c14
-rw-r--r--sys/cddl/boot/zfs/sha256.c242
-rw-r--r--sys/cddl/boot/zfs/skein_zfs.c92
-rw-r--r--sys/cddl/boot/zfs/zfsimpl.h25
-rw-r--r--sys/cddl/boot/zfs/zfssubr.c148
5 files changed, 456 insertions, 65 deletions
diff --git a/sys/cddl/boot/zfs/fletcher.c b/sys/cddl/boot/zfs/fletcher.c
index 3c60036..2aa381a 100644
--- a/sys/cddl/boot/zfs/fletcher.c
+++ b/sys/cddl/boot/zfs/fletcher.c
@@ -23,10 +23,9 @@
* Use is subject to license terms.
*/
-/*#pragma ident "%Z%%M% %I% %E% SMI"*/
-
static void
-fletcher_2_native(const void *buf, uint64_t size, zio_cksum_t *zcp)
+fletcher_2_native(const void *buf, uint64_t size,
+ const void *ctx_template __unused, zio_cksum_t *zcp)
{
const uint64_t *ip = buf;
const uint64_t *ipend = ip + (size / sizeof (uint64_t));
@@ -43,7 +42,8 @@ fletcher_2_native(const void *buf, uint64_t size, zio_cksum_t *zcp)
}
static void
-fletcher_2_byteswap(const void *buf, uint64_t size, zio_cksum_t *zcp)
+fletcher_2_byteswap(const void *buf, uint64_t size,
+ const void *ctx_template __unused, zio_cksum_t *zcp)
{
const uint64_t *ip = buf;
const uint64_t *ipend = ip + (size / sizeof (uint64_t));
@@ -60,7 +60,8 @@ fletcher_2_byteswap(const void *buf, uint64_t size, zio_cksum_t *zcp)
}
static void
-fletcher_4_native(const void *buf, uint64_t size, zio_cksum_t *zcp)
+fletcher_4_native(const void *buf, uint64_t size,
+ const void *ctx_template __unused, zio_cksum_t *zcp)
{
const uint32_t *ip = buf;
const uint32_t *ipend = ip + (size / sizeof (uint32_t));
@@ -77,7 +78,8 @@ fletcher_4_native(const void *buf, uint64_t size, zio_cksum_t *zcp)
}
static void
-fletcher_4_byteswap(const void *buf, uint64_t size, zio_cksum_t *zcp)
+fletcher_4_byteswap(const void *buf, uint64_t size,
+ const void *ctx_template __unused, zio_cksum_t *zcp)
{
const uint32_t *ip = buf;
const uint32_t *ipend = ip + (size / sizeof (uint32_t));
diff --git a/sys/cddl/boot/zfs/sha256.c b/sys/cddl/boot/zfs/sha256.c
index f0d83ac..eee98e6 100644
--- a/sys/cddl/boot/zfs/sha256.c
+++ b/sys/cddl/boot/zfs/sha256.c
@@ -23,19 +23,21 @@
* Copyright 2005 Sun Microsystems, Inc. All rights reserved.
* Use is subject to license terms.
*/
-
-/*#pragma ident "%Z%%M% %I% %E% SMI"*/
+/*
+ * Copyright 2013 Saso Kiselkov. All rights reserved.
+ * Copyright 2015 Toomas Soome <tsoome@me.com>
+ */
/*
- * SHA-256 checksum, as specified in FIPS 180-2, available at:
+ * SHA-256 and SHA-512/256 hashes, as specified in FIPS 180-4, available at:
* http://csrc.nist.gov/cryptval
*
- * This is a very compact implementation of SHA-256.
+ * This is a very compact implementation of SHA-256 and SHA-512/256.
* It is designed to be simple and portable, not to be fast.
*/
/*
- * The literal definitions according to FIPS180-2 would be:
+ * The literal definitions according to FIPS180-4 would be:
*
* Ch(x, y, z) (((x) & (y)) ^ ((~(x)) & (z)))
* Maj(x, y, z) (((x) & (y)) | ((x) & (z)) | ((y) & (z)))
@@ -44,12 +46,21 @@
*/
#define Ch(x, y, z) ((z) ^ ((x) & ((y) ^ (z))))
#define Maj(x, y, z) (((x) & (y)) ^ ((z) & ((x) ^ (y))))
-#define Rot32(x, s) (((x) >> s) | ((x) << (32 - s)))
-#define SIGMA0(x) (Rot32(x, 2) ^ Rot32(x, 13) ^ Rot32(x, 22))
-#define SIGMA1(x) (Rot32(x, 6) ^ Rot32(x, 11) ^ Rot32(x, 25))
-#define sigma0(x) (Rot32(x, 7) ^ Rot32(x, 18) ^ ((x) >> 3))
-#define sigma1(x) (Rot32(x, 17) ^ Rot32(x, 19) ^ ((x) >> 10))
+#define ROTR(x, n) (((x) >> (n)) | ((x) << ((sizeof (x) * NBBY)-(n))))
+
+/* SHA-224/256 operations */
+#define BIGSIGMA0_256(x) (ROTR(x, 2) ^ ROTR(x, 13) ^ ROTR(x, 22))
+#define BIGSIGMA1_256(x) (ROTR(x, 6) ^ ROTR(x, 11) ^ ROTR(x, 25))
+#define SIGMA0_256(x) (ROTR(x, 7) ^ ROTR(x, 18) ^ ((x) >> 3))
+#define SIGMA1_256(x) (ROTR(x, 17) ^ ROTR(x, 19) ^ ((x) >> 10))
+/* SHA-384/512 operations */
+#define BIGSIGMA0_512(x) (ROTR((x), 28) ^ ROTR((x), 34) ^ ROTR((x), 39))
+#define BIGSIGMA1_512(x) (ROTR((x), 14) ^ ROTR((x), 18) ^ ROTR((x), 41))
+#define SIGMA0_512(x) (ROTR((x), 1) ^ ROTR((x), 8) ^ ((x) >> 7))
+#define SIGMA1_512(x) (ROTR((x), 19) ^ ROTR((x), 61) ^ ((x) >> 6))
+
+/* SHA-256 round constants */
static const uint32_t SHA256_K[64] = {
0x428a2f98, 0x71374491, 0xb5c0fbcf, 0xe9b5dba5,
0x3956c25b, 0x59f111f1, 0x923f82a4, 0xab1c5ed5,
@@ -69,46 +80,134 @@ static const uint32_t SHA256_K[64] = {
0x90befffa, 0xa4506ceb, 0xbef9a3f7, 0xc67178f2
};
+/* SHA-512 round constants */
+static const uint64_t SHA512_K[80] = {
+ 0x428A2F98D728AE22ULL, 0x7137449123EF65CDULL,
+ 0xB5C0FBCFEC4D3B2FULL, 0xE9B5DBA58189DBBCULL,
+ 0x3956C25BF348B538ULL, 0x59F111F1B605D019ULL,
+ 0x923F82A4AF194F9BULL, 0xAB1C5ED5DA6D8118ULL,
+ 0xD807AA98A3030242ULL, 0x12835B0145706FBEULL,
+ 0x243185BE4EE4B28CULL, 0x550C7DC3D5FFB4E2ULL,
+ 0x72BE5D74F27B896FULL, 0x80DEB1FE3B1696B1ULL,
+ 0x9BDC06A725C71235ULL, 0xC19BF174CF692694ULL,
+ 0xE49B69C19EF14AD2ULL, 0xEFBE4786384F25E3ULL,
+ 0x0FC19DC68B8CD5B5ULL, 0x240CA1CC77AC9C65ULL,
+ 0x2DE92C6F592B0275ULL, 0x4A7484AA6EA6E483ULL,
+ 0x5CB0A9DCBD41FBD4ULL, 0x76F988DA831153B5ULL,
+ 0x983E5152EE66DFABULL, 0xA831C66D2DB43210ULL,
+ 0xB00327C898FB213FULL, 0xBF597FC7BEEF0EE4ULL,
+ 0xC6E00BF33DA88FC2ULL, 0xD5A79147930AA725ULL,
+ 0x06CA6351E003826FULL, 0x142929670A0E6E70ULL,
+ 0x27B70A8546D22FFCULL, 0x2E1B21385C26C926ULL,
+ 0x4D2C6DFC5AC42AEDULL, 0x53380D139D95B3DFULL,
+ 0x650A73548BAF63DEULL, 0x766A0ABB3C77B2A8ULL,
+ 0x81C2C92E47EDAEE6ULL, 0x92722C851482353BULL,
+ 0xA2BFE8A14CF10364ULL, 0xA81A664BBC423001ULL,
+ 0xC24B8B70D0F89791ULL, 0xC76C51A30654BE30ULL,
+ 0xD192E819D6EF5218ULL, 0xD69906245565A910ULL,
+ 0xF40E35855771202AULL, 0x106AA07032BBD1B8ULL,
+ 0x19A4C116B8D2D0C8ULL, 0x1E376C085141AB53ULL,
+ 0x2748774CDF8EEB99ULL, 0x34B0BCB5E19B48A8ULL,
+ 0x391C0CB3C5C95A63ULL, 0x4ED8AA4AE3418ACBULL,
+ 0x5B9CCA4F7763E373ULL, 0x682E6FF3D6B2B8A3ULL,
+ 0x748F82EE5DEFB2FCULL, 0x78A5636F43172F60ULL,
+ 0x84C87814A1F0AB72ULL, 0x8CC702081A6439ECULL,
+ 0x90BEFFFA23631E28ULL, 0xA4506CEBDE82BDE9ULL,
+ 0xBEF9A3F7B2C67915ULL, 0xC67178F2E372532BULL,
+ 0xCA273ECEEA26619CULL, 0xD186B8C721C0C207ULL,
+ 0xEADA7DD6CDE0EB1EULL, 0xF57D4F7FEE6ED178ULL,
+ 0x06F067AA72176FBAULL, 0x0A637DC5A2C898A6ULL,
+ 0x113F9804BEF90DAEULL, 0x1B710B35131C471BULL,
+ 0x28DB77F523047D84ULL, 0x32CAAB7B40C72493ULL,
+ 0x3C9EBE0A15C9BEBCULL, 0x431D67C49C100D4CULL,
+ 0x4CC5D4BECB3E42B6ULL, 0x597F299CFC657E2AULL,
+ 0x5FCB6FAB3AD6FAECULL, 0x6C44198C4A475817ULL
+};
+
static void
SHA256Transform(uint32_t *H, const uint8_t *cp)
{
uint32_t a, b, c, d, e, f, g, h, t, T1, T2, W[64];
- for (t = 0; t < 16; t++, cp += 4)
+ /* copy chunk into the first 16 words of the message schedule */
+ for (t = 0; t < 16; t++, cp += sizeof (uint32_t))
W[t] = (cp[0] << 24) | (cp[1] << 16) | (cp[2] << 8) | cp[3];
+ /* extend the first 16 words into the remaining 48 words */
for (t = 16; t < 64; t++)
- W[t] = sigma1(W[t - 2]) + W[t - 7] +
- sigma0(W[t - 15]) + W[t - 16];
+ W[t] = SIGMA1_256(W[t - 2]) + W[t - 7] +
+ SIGMA0_256(W[t - 15]) + W[t - 16];
+ /* init working variables to the current hash value */
a = H[0]; b = H[1]; c = H[2]; d = H[3];
e = H[4]; f = H[5]; g = H[6]; h = H[7];
+ /* iterate the compression function for all rounds of the hash */
for (t = 0; t < 64; t++) {
- T1 = h + SIGMA1(e) + Ch(e, f, g) + SHA256_K[t] + W[t];
- T2 = SIGMA0(a) + Maj(a, b, c);
+ T1 = h + BIGSIGMA1_256(e) + Ch(e, f, g) + SHA256_K[t] + W[t];
+ T2 = BIGSIGMA0_256(a) + Maj(a, b, c);
h = g; g = f; f = e; e = d + T1;
d = c; c = b; b = a; a = T1 + T2;
}
+ /* add the compressed chunk to the current hash value */
H[0] += a; H[1] += b; H[2] += c; H[3] += d;
H[4] += e; H[5] += f; H[6] += g; H[7] += h;
}
static void
-zio_checksum_SHA256(const void *buf, uint64_t size, zio_cksum_t *zcp)
+SHA512Transform(uint64_t *H, const uint8_t *cp)
+{
+ uint64_t a, b, c, d, e, f, g, h, t, T1, T2, W[80];
+
+ /* copy chunk into the first 16 words of the message schedule */
+ for (t = 0; t < 16; t++, cp += sizeof (uint64_t))
+ W[t] = ((uint64_t)cp[0] << 56) | ((uint64_t)cp[1] << 48) |
+ ((uint64_t)cp[2] << 40) | ((uint64_t)cp[3] << 32) |
+ ((uint64_t)cp[4] << 24) | ((uint64_t)cp[5] << 16) |
+ ((uint64_t)cp[6] << 8) | (uint64_t)cp[7];
+
+ /* extend the first 16 words into the remaining 64 words */
+ for (t = 16; t < 80; t++)
+ W[t] = SIGMA1_512(W[t - 2]) + W[t - 7] +
+ SIGMA0_512(W[t - 15]) + W[t - 16];
+
+ /* init working variables to the current hash value */
+ a = H[0]; b = H[1]; c = H[2]; d = H[3];
+ e = H[4]; f = H[5]; g = H[6]; h = H[7];
+
+ /* iterate the compression function for all rounds of the hash */
+ for (t = 0; t < 80; t++) {
+ T1 = h + BIGSIGMA1_512(e) + Ch(e, f, g) + SHA512_K[t] + W[t];
+ T2 = BIGSIGMA0_512(a) + Maj(a, b, c);
+ h = g; g = f; f = e; e = d + T1;
+ d = c; c = b; b = a; a = T1 + T2;
+ }
+
+ /* add the compressed chunk to the current hash value */
+ H[0] += a; H[1] += b; H[2] += c; H[3] += d;
+ H[4] += e; H[5] += f; H[6] += g; H[7] += h;
+}
+
+/*
+ * Implements the SHA-224 and SHA-256 hash algos - to select between them
+ * pass the appropriate initial values of 'H' and truncate the last 32 bits
+ * in case of SHA-224.
+ */
+static void
+SHA256(uint32_t *H, const void *buf, uint64_t size, zio_cksum_t *zcp)
{
- uint32_t H[8] = { 0x6a09e667, 0xbb67ae85, 0x3c6ef372, 0xa54ff53a,
- 0x510e527f, 0x9b05688c, 0x1f83d9ab, 0x5be0cd19 };
uint8_t pad[128];
- int padsize = size & 63;
- int i;
+ unsigned padsize = size & 63;
+ unsigned i, k;
+ /* process all blocks up to the last one */
for (i = 0; i < size - padsize; i += 64)
SHA256Transform(H, (uint8_t *)buf + i);
- for (i = 0; i < padsize; i++)
- pad[i] = ((uint8_t *)buf)[i];
+ /* process the last block and padding */
+ for (k = 0; k < padsize; k++)
+ pad[k] = ((uint8_t *)buf)[k+i];
for (pad[padsize++] = 0x80; (padsize & 63) != 56; padsize++)
pad[padsize] = 0;
@@ -125,3 +224,102 @@ zio_checksum_SHA256(const void *buf, uint64_t size, zio_cksum_t *zcp)
(uint64_t)H[4] << 32 | H[5],
(uint64_t)H[6] << 32 | H[7]);
}
+
+/*
+ * encode 64bit data in big-endian format.
+ */
+static void
+Encode64(uint8_t *output, uint64_t *input, size_t len)
+{
+ size_t i, j;
+ for (i = 0, j = 0; j < len; i++, j += 8) {
+ output[j] = (input[i] >> 56) & 0xff;
+ output[j + 1] = (input[i] >> 48) & 0xff;
+ output[j + 2] = (input[i] >> 40) & 0xff;
+ output[j + 3] = (input[i] >> 32) & 0xff;
+ output[j + 4] = (input[i] >> 24) & 0xff;
+ output[j + 5] = (input[i] >> 16) & 0xff;
+ output[j + 6] = (input[i] >> 8) & 0xff;
+ output[j + 7] = input[i] & 0xff;
+ }
+}
+
+/*
+ * Implements the SHA-384, SHA-512 and SHA-512/t hash algos - to select
+ * between them pass the appropriate initial values for 'H'. The output
+ * of this function is truncated to the first 256 bits that fit into 'zcp'.
+ */
+static void
+SHA512(uint64_t *H, const void *buf, uint64_t size, zio_cksum_t *zcp)
+{
+ uint64_t c64[2];
+ uint8_t pad[256];
+ unsigned padsize = size & 127;
+ unsigned i, k;
+
+ /* process all blocks up to the last one */
+ for (i = 0; i < size - padsize; i += 128)
+ SHA512Transform(H, (uint8_t *)buf + i);
+
+ /* process the last block and padding */
+ for (k = 0; k < padsize; k++)
+ pad[k] = ((uint8_t *)buf)[k+i];
+
+ if (padsize < 112) {
+ for (pad[padsize++] = 0x80; padsize < 112; padsize++)
+ pad[padsize] = 0;
+ } else {
+ for (pad[padsize++] = 0x80; padsize < 240; padsize++)
+ pad[padsize] = 0;
+ }
+
+ c64[0] = 0;
+ c64[1] = size << 3;
+ Encode64(pad+padsize, c64, sizeof (c64));
+ padsize += sizeof (c64);
+
+ for (i = 0; i < padsize; i += 128)
+ SHA512Transform(H, pad + i);
+
+ /* truncate the output to the first 256 bits which fit into 'zcp' */
+ Encode64((uint8_t *)zcp, H, sizeof (uint64_t) * 4);
+}
+
+static void
+zio_checksum_SHA256(const void *buf, uint64_t size,
+ const void *ctx_template __unused, zio_cksum_t *zcp)
+{
+ /* SHA-256 as per FIPS 180-4. */
+ uint32_t H[] = {
+ 0x6a09e667, 0xbb67ae85, 0x3c6ef372, 0xa54ff53a,
+ 0x510e527f, 0x9b05688c, 0x1f83d9ab, 0x5be0cd19
+ };
+ SHA256(H, buf, size, zcp);
+}
+
+static void
+zio_checksum_SHA512_native(const void *buf, uint64_t size,
+ const void *ctx_template __unused, zio_cksum_t *zcp)
+{
+ /* SHA-512/256 as per FIPS 180-4. */
+ uint64_t H[] = {
+ 0x22312194FC2BF72CULL, 0x9F555FA3C84C64C2ULL,
+ 0x2393B86B6F53B151ULL, 0x963877195940EABDULL,
+ 0x96283EE2A88EFFE3ULL, 0xBE5E1E2553863992ULL,
+ 0x2B0199FC2C85B8AAULL, 0x0EB72DDC81C52CA2ULL
+ };
+ SHA512(H, buf, size, zcp);
+}
+
+static void
+zio_checksum_SHA512_byteswap(const void *buf, uint64_t size,
+ const void *ctx_template, zio_cksum_t *zcp)
+{
+ zio_cksum_t tmp;
+
+ zio_checksum_SHA512_native(buf, size, ctx_template, &tmp);
+ zcp->zc_word[0] = BSWAP_64(tmp.zc_word[0]);
+ zcp->zc_word[1] = BSWAP_64(tmp.zc_word[1]);
+ zcp->zc_word[2] = BSWAP_64(tmp.zc_word[2]);
+ zcp->zc_word[3] = BSWAP_64(tmp.zc_word[3]);
+}
diff --git a/sys/cddl/boot/zfs/skein_zfs.c b/sys/cddl/boot/zfs/skein_zfs.c
new file mode 100644
index 0000000..5b424c7
--- /dev/null
+++ b/sys/cddl/boot/zfs/skein_zfs.c
@@ -0,0 +1,92 @@
+/*
+ * CDDL HEADER START
+ *
+ * The contents of this file are subject to the terms of the
+ * Common Development and Distribution License (the "License").
+ * You may not use this file except in compliance with the License.
+ *
+ * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+ * or http://opensource.org/licenses/CDDL-1.0.
+ * See the License for the specific language governing permissions
+ * and limitations under the License.
+ *
+ * When distributing Covered Code, include this CDDL HEADER in each
+ * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+ * If applicable, add the following below this CDDL HEADER, with the
+ * fields enclosed by brackets "[]" replaced with your own identifying
+ * information: Portions Copyright [yyyy] [name of copyright owner]
+ *
+ * CDDL HEADER END
+ *
+ * $FreeBSD$
+ */
+/*
+ * Copyright 2013 Saso Kiselkov. All rights reserved.
+ */
+#include <skein.h>
+
+/*
+ * Computes a native 256-bit skein MAC checksum. Please note that this
+ * function requires the presence of a ctx_template that should be allocated
+ * using zio_checksum_skein_tmpl_init.
+ */
+/*ARGSUSED*/
+static void
+zio_checksum_skein_native(const void *buf, uint64_t size,
+ const void *ctx_template, zio_cksum_t *zcp)
+{
+ Skein_512_Ctxt_t ctx;
+
+ ASSERT(ctx_template != NULL);
+ bcopy(ctx_template, &ctx, sizeof (ctx));
+ (void) Skein_512_Update(&ctx, buf, size);
+ (void) Skein_512_Final(&ctx, (uint8_t *)zcp);
+ bzero(&ctx, sizeof (ctx));
+}
+
+/*
+ * Byteswapped version of zio_checksum_skein_native. This just invokes
+ * the native checksum function and byteswaps the resulting checksum (since
+ * skein is internally endian-insensitive).
+ */
+static void
+zio_checksum_skein_byteswap(const void *buf, uint64_t size,
+ const void *ctx_template, zio_cksum_t *zcp)
+{
+ zio_cksum_t tmp;
+
+ zio_checksum_skein_native(buf, size, ctx_template, &tmp);
+ zcp->zc_word[0] = BSWAP_64(tmp.zc_word[0]);
+ zcp->zc_word[1] = BSWAP_64(tmp.zc_word[1]);
+ zcp->zc_word[2] = BSWAP_64(tmp.zc_word[2]);
+ zcp->zc_word[3] = BSWAP_64(tmp.zc_word[3]);
+}
+
+/*
+ * Allocates a skein MAC template suitable for using in skein MAC checksum
+ * computations and returns a pointer to it.
+ */
+static void *
+zio_checksum_skein_tmpl_init(const zio_cksum_salt_t *salt)
+{
+ Skein_512_Ctxt_t *ctx;
+
+ ctx = malloc(sizeof (*ctx));
+ bzero(ctx, sizeof (*ctx));
+ (void) Skein_512_InitExt(ctx, sizeof (zio_cksum_t) * 8, 0,
+ salt->zcs_bytes, sizeof (salt->zcs_bytes));
+ return (ctx);
+}
+
+/*
+ * Frees a skein context template previously allocated using
+ * zio_checksum_skein_tmpl_init.
+ */
+static void
+zio_checksum_skein_tmpl_free(void *ctx_template)
+{
+ Skein_512_Ctxt_t *ctx = ctx_template;
+
+ bzero(ctx, sizeof (*ctx));
+ free(ctx);
+}
diff --git a/sys/cddl/boot/zfs/zfsimpl.h b/sys/cddl/boot/zfs/zfsimpl.h
index f03f9df..08ca499 100644
--- a/sys/cddl/boot/zfs/zfsimpl.h
+++ b/sys/cddl/boot/zfs/zfsimpl.h
@@ -114,13 +114,11 @@ typedef enum { B_FALSE, B_TRUE } boolean_t;
#define BSWAP_32(x) ((BSWAP_16(x) << 16) | BSWAP_16((x) >> 16))
#define BSWAP_64(x) ((BSWAP_32(x) << 32) | BSWAP_32((x) >> 32))
-/*
- * Note: the boot loader can't actually read blocks larger than 128KB,
- * due to lack of memory. Therefore its SPA_MAXBLOCKSIZE is still 128KB.
- */
#define SPA_MINBLOCKSHIFT 9
-#define SPA_MAXBLOCKSHIFT 17
+#define SPA_OLDMAXBLOCKSHIFT 17
+#define SPA_MAXBLOCKSHIFT 24
#define SPA_MINBLOCKSIZE (1ULL << SPA_MINBLOCKSHIFT)
+#define SPA_OLDMAXBLOCKSIZE (1ULL << SPA_OLDMAXBLOCKSHIFT)
#define SPA_MAXBLOCKSIZE (1ULL << SPA_MAXBLOCKSHIFT)
/*
@@ -150,6 +148,14 @@ typedef struct zio_cksum {
} zio_cksum_t;
/*
+ * Some checksums/hashes need a 256-bit initialization salt. This salt is kept
+ * secret and is suitable for use in MAC algorithms as the key.
+ */
+typedef struct zio_cksum_salt {
+ uint8_t zcs_bytes[32];
+} zio_cksum_salt_t;
+
+/*
* Each block is described by its DVAs, time of birth, checksum, etc.
* The word-by-word, bit-by-bit layout of the blkptr is as follows:
*
@@ -528,6 +534,10 @@ enum zio_checksum {
ZIO_CHECKSUM_FLETCHER_4,
ZIO_CHECKSUM_SHA256,
ZIO_CHECKSUM_ZILOG2,
+ ZIO_CHECKSUM_NOPARITY,
+ ZIO_CHECKSUM_SHA512,
+ ZIO_CHECKSUM_SKEIN,
+ ZIO_CHECKSUM_EDONR,
ZIO_CHECKSUM_FUNCTIONS
};
@@ -1158,6 +1168,7 @@ typedef struct dsl_dataset_phys {
#define DMU_POOL_DEFLATE "deflate"
#define DMU_POOL_HISTORY "history"
#define DMU_POOL_PROPS "pool_props"
+#define DMU_POOL_CHECKSUM_SALT "org.illumos:checksum_salt"
#define ZAP_MAGIC 0x2F52AB2ABULL
@@ -1463,6 +1474,7 @@ typedef struct znode_phys {
* In-core vdev representation.
*/
struct vdev;
+struct spa;
typedef int vdev_phys_read_t(struct vdev *vdev, void *priv,
off_t offset, void *buf, size_t bytes);
typedef int vdev_read_t(struct vdev *vdev, const blkptr_t *bp,
@@ -1485,6 +1497,7 @@ typedef struct vdev {
vdev_phys_read_t *v_phys_read; /* read from raw leaf vdev */
vdev_read_t *v_read; /* read from vdev */
void *v_read_priv; /* private data for read function */
+ struct spa *spa; /* link to spa */
} vdev_t;
/*
@@ -1500,6 +1513,8 @@ typedef struct spa {
struct uberblock spa_uberblock; /* best uberblock so far */
vdev_list_t spa_vdevs; /* list of all toplevel vdevs */
objset_phys_t spa_mos; /* MOS for this pool */
+ zio_cksum_salt_t spa_cksum_salt; /* secret salt for cksum */
+ void *spa_cksum_tmpls[ZIO_CHECKSUM_FUNCTIONS];
int spa_inited; /* initialized */
} spa_t;
diff --git a/sys/cddl/boot/zfs/zfssubr.c b/sys/cddl/boot/zfs/zfssubr.c
index a64f065..805cb42 100644
--- a/sys/cddl/boot/zfs/zfssubr.c
+++ b/sys/cddl/boot/zfs/zfssubr.c
@@ -63,7 +63,8 @@ zfs_init_crc(void)
}
static void
-zio_checksum_off(const void *buf, uint64_t size, zio_cksum_t *zcp)
+zio_checksum_off(const void *buf, uint64_t size,
+ const void *ctx_template, zio_cksum_t *zcp)
{
ZIO_SET_CHECKSUM(zcp, 0, 0, 0, 0);
}
@@ -71,38 +72,75 @@ zio_checksum_off(const void *buf, uint64_t size, zio_cksum_t *zcp)
/*
* Signature for checksum functions.
*/
-typedef void zio_checksum_t(const void *data, uint64_t size, zio_cksum_t *zcp);
+typedef void zio_checksum_t(const void *data, uint64_t size,
+ const void *ctx_template, zio_cksum_t *zcp);
+typedef void *zio_checksum_tmpl_init_t(const zio_cksum_salt_t *salt);
+typedef void zio_checksum_tmpl_free_t(void *ctx_template);
+
+typedef enum zio_checksum_flags {
+ /* Strong enough for metadata? */
+ ZCHECKSUM_FLAG_METADATA = (1 << 1),
+ /* ZIO embedded checksum */
+ ZCHECKSUM_FLAG_EMBEDDED = (1 << 2),
+ /* Strong enough for dedup (without verification)? */
+ ZCHECKSUM_FLAG_DEDUP = (1 << 3),
+ /* Uses salt value */
+ ZCHECKSUM_FLAG_SALTED = (1 << 4),
+ /* Strong enough for nopwrite? */
+ ZCHECKSUM_FLAG_NOPWRITE = (1 << 5)
+} zio_checksum_flags_t;
/*
* Information about each checksum function.
*/
typedef struct zio_checksum_info {
- zio_checksum_t *ci_func[2]; /* checksum function for each byteorder */
- int ci_correctable; /* number of correctable bits */
- int ci_eck; /* uses zio embedded checksum? */
- int ci_dedup; /* strong enough for dedup? */
- const char *ci_name; /* descriptive name */
+ /* checksum function for each byteorder */
+ zio_checksum_t *ci_func[2];
+ zio_checksum_tmpl_init_t *ci_tmpl_init;
+ zio_checksum_tmpl_free_t *ci_tmpl_free;
+ zio_checksum_flags_t ci_flags;
+ const char *ci_name; /* descriptive name */
} zio_checksum_info_t;
#include "blkptr.c"
#include "fletcher.c"
#include "sha256.c"
+#include "skein_zfs.c"
static zio_checksum_info_t zio_checksum_table[ZIO_CHECKSUM_FUNCTIONS] = {
- {{NULL, NULL}, 0, 0, 0, "inherit"},
- {{NULL, NULL}, 0, 0, 0, "on"},
- {{zio_checksum_off, zio_checksum_off}, 0, 0, 0, "off"},
- {{zio_checksum_SHA256, zio_checksum_SHA256}, 1, 1, 0, "label"},
- {{zio_checksum_SHA256, zio_checksum_SHA256}, 1, 1, 0, "gang_header"},
- {{fletcher_2_native, fletcher_2_byteswap}, 0, 1, 0, "zilog"},
- {{fletcher_2_native, fletcher_2_byteswap}, 0, 0, 0, "fletcher2"},
- {{fletcher_4_native, fletcher_4_byteswap}, 1, 0, 0, "fletcher4"},
- {{zio_checksum_SHA256, zio_checksum_SHA256}, 1, 0, 1, "SHA256"},
- {{fletcher_4_native, fletcher_4_byteswap}, 0, 1, 0, "zillog2"},
+ {{NULL, NULL}, NULL, NULL, 0, "inherit"},
+ {{NULL, NULL}, NULL, NULL, 0, "on"},
+ {{zio_checksum_off, zio_checksum_off}, NULL, NULL, 0, "off"},
+ {{zio_checksum_SHA256, zio_checksum_SHA256}, NULL, NULL,
+ ZCHECKSUM_FLAG_METADATA | ZCHECKSUM_FLAG_EMBEDDED, "label"},
+ {{zio_checksum_SHA256, zio_checksum_SHA256}, NULL, NULL,
+ ZCHECKSUM_FLAG_METADATA | ZCHECKSUM_FLAG_EMBEDDED, "gang_header"},
+ {{fletcher_2_native, fletcher_2_byteswap}, NULL, NULL,
+ ZCHECKSUM_FLAG_EMBEDDED, "zilog"},
+ {{fletcher_2_native, fletcher_2_byteswap}, NULL, NULL,
+ 0, "fletcher2"},
+ {{fletcher_4_native, fletcher_4_byteswap}, NULL, NULL,
+ ZCHECKSUM_FLAG_METADATA, "fletcher4"},
+ {{zio_checksum_SHA256, zio_checksum_SHA256}, NULL, NULL,
+ ZCHECKSUM_FLAG_METADATA | ZCHECKSUM_FLAG_DEDUP |
+ ZCHECKSUM_FLAG_NOPWRITE, "SHA256"},
+ {{fletcher_4_native, fletcher_4_byteswap}, NULL, NULL,
+ ZCHECKSUM_FLAG_EMBEDDED, "zillog2"},
+ {{zio_checksum_off, zio_checksum_off}, NULL, NULL,
+ 0, "noparity"},
+ {{zio_checksum_SHA512_native, zio_checksum_SHA512_byteswap},
+ NULL, NULL, ZCHECKSUM_FLAG_METADATA | ZCHECKSUM_FLAG_DEDUP |
+ ZCHECKSUM_FLAG_NOPWRITE, "SHA512"},
+ {{zio_checksum_skein_native, zio_checksum_skein_byteswap},
+ zio_checksum_skein_tmpl_init, zio_checksum_skein_tmpl_free,
+ ZCHECKSUM_FLAG_METADATA | ZCHECKSUM_FLAG_DEDUP |
+ ZCHECKSUM_FLAG_SALTED | ZCHECKSUM_FLAG_NOPWRITE, "skein"},
+ /* no edonr for now */
+ {{NULL, NULL}, NULL, NULL, ZCHECKSUM_FLAG_METADATA |
+ ZCHECKSUM_FLAG_SALTED | ZCHECKSUM_FLAG_NOPWRITE, "edonr"}
};
-
/*
* Common signature for all zio compress/decompress functions.
*/
@@ -186,12 +224,53 @@ zio_checksum_label_verifier(zio_cksum_t *zcp, uint64_t offset)
ZIO_SET_CHECKSUM(zcp, offset, 0, 0, 0);
}
+/*
+ * Calls the template init function of a checksum which supports context
+ * templates and installs the template into the spa_t.
+ */
+static void
+zio_checksum_template_init(enum zio_checksum checksum, spa_t *spa)
+{
+ zio_checksum_info_t *ci = &zio_checksum_table[checksum];
+
+ if (ci->ci_tmpl_init == NULL)
+ return;
+
+ if (spa->spa_cksum_tmpls[checksum] != NULL)
+ return;
+
+ if (spa->spa_cksum_tmpls[checksum] == NULL) {
+ spa->spa_cksum_tmpls[checksum] =
+ ci->ci_tmpl_init(&spa->spa_cksum_salt);
+ }
+}
+
+/*
+ * Called by a spa_t that's about to be deallocated. This steps through
+ * all of the checksum context templates and deallocates any that were
+ * initialized using the algorithm-specific template init function.
+ */
+void
+zio_checksum_templates_free(spa_t *spa)
+{
+ for (enum zio_checksum checksum = 0;
+ checksum < ZIO_CHECKSUM_FUNCTIONS; checksum++) {
+ if (spa->spa_cksum_tmpls[checksum] != NULL) {
+ zio_checksum_info_t *ci = &zio_checksum_table[checksum];
+
+ ci->ci_tmpl_free(spa->spa_cksum_tmpls[checksum]);
+ spa->spa_cksum_tmpls[checksum] = NULL;
+ }
+ }
+}
+
static int
-zio_checksum_verify(const blkptr_t *bp, void *data)
+zio_checksum_verify(const spa_t *spa, const blkptr_t *bp, void *data)
{
uint64_t size;
unsigned int checksum;
zio_checksum_info_t *ci;
+ void *ctx = NULL;
zio_cksum_t actual_cksum, expected_cksum, verifier;
int byteswap;
@@ -204,7 +283,12 @@ zio_checksum_verify(const blkptr_t *bp, void *data)
if (ci->ci_func[0] == NULL || ci->ci_func[1] == NULL)
return (EINVAL);
- if (ci->ci_eck) {
+ if (spa != NULL) {
+ zio_checksum_template_init(checksum, (spa_t *) spa);
+ ctx = spa->spa_cksum_tmpls[checksum];
+ }
+
+ if (ci->ci_flags & ZCHECKSUM_FLAG_EMBEDDED) {
zio_eck_t *eck;
ASSERT(checksum == ZIO_CHECKSUM_GANG_HEADER ||
@@ -227,7 +311,7 @@ zio_checksum_verify(const blkptr_t *bp, void *data)
expected_cksum = eck->zec_cksum;
eck->zec_cksum = verifier;
- ci->ci_func[byteswap](data, size, &actual_cksum);
+ ci->ci_func[byteswap](data, size, ctx, &actual_cksum);
eck->zec_cksum = expected_cksum;
if (byteswap)
@@ -235,11 +319,11 @@ zio_checksum_verify(const blkptr_t *bp, void *data)
sizeof (zio_cksum_t));
} else {
expected_cksum = bp->blk_cksum;
- ci->ci_func[0](data, size, &actual_cksum);
+ ci->ci_func[0](data, size, ctx, &actual_cksum);
}
if (!ZIO_CHECKSUM_EQUAL(actual_cksum, expected_cksum)) {
- /*printf("ZFS: read checksum failed\n");*/
+ /*printf("ZFS: read checksum %s failed\n", ci->ci_name);*/
return (EIO);
}
@@ -1249,10 +1333,10 @@ vdev_child(vdev_t *pvd, uint64_t devidx)
* any ereports we generate can note it.
*/
static int
-raidz_checksum_verify(const blkptr_t *bp, void *data, uint64_t size)
+raidz_checksum_verify(const spa_t *spa, const blkptr_t *bp, void *data,
+ uint64_t size)
{
-
- return (zio_checksum_verify(bp, data));
+ return (zio_checksum_verify(spa, bp, data));
}
/*
@@ -1301,8 +1385,8 @@ raidz_parity_verify(raidz_map_t *rm)
* cases we'd only use parity information in column 0.
*/
static int
-vdev_raidz_combrec(raidz_map_t *rm, const blkptr_t *bp, void *data,
- off_t offset, uint64_t bytes, int total_errors, int data_errors)
+vdev_raidz_combrec(const spa_t *spa, raidz_map_t *rm, const blkptr_t *bp,
+ void *data, off_t offset, uint64_t bytes, int total_errors, int data_errors)
{
raidz_col_t *rc;
void *orig[VDEV_RAIDZ_MAXPARITY];
@@ -1381,7 +1465,7 @@ vdev_raidz_combrec(raidz_map_t *rm, const blkptr_t *bp, void *data,
* success.
*/
code = vdev_raidz_reconstruct(rm, tgts, n);
- if (raidz_checksum_verify(bp, data, bytes) == 0) {
+ if (raidz_checksum_verify(spa, bp, data, bytes) == 0) {
for (i = 0; i < n; i++) {
c = tgts[i];
rc = &rm->rm_col[c];
@@ -1552,7 +1636,7 @@ reconstruct:
*/
if (total_errors <= rm->rm_firstdatacol - parity_untried) {
if (data_errors == 0) {
- if (raidz_checksum_verify(bp, data, bytes) == 0) {
+ if (raidz_checksum_verify(vd->spa, bp, data, bytes) == 0) {
/*
* If we read parity information (unnecessarily
* as it happens since no reconstruction was
@@ -1597,7 +1681,7 @@ reconstruct:
code = vdev_raidz_reconstruct(rm, tgts, n);
- if (raidz_checksum_verify(bp, data, bytes) == 0) {
+ if (raidz_checksum_verify(vd->spa, bp, data, bytes) == 0) {
/*
* If we read more parity disks than were used
* for reconstruction, confirm that the other
@@ -1671,7 +1755,7 @@ reconstruct:
if (total_errors > rm->rm_firstdatacol) {
error = EIO;
} else if (total_errors < rm->rm_firstdatacol &&
- (code = vdev_raidz_combrec(rm, bp, data, offset, bytes,
+ (code = vdev_raidz_combrec(vd->spa, rm, bp, data, offset, bytes,
total_errors, data_errors)) != 0) {
/*
* If we didn't use all the available parity for the
OpenPOWER on IntegriCloud