summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorToomas Soome <tsoome@me.com>2017-12-04 12:26:50 +0200
committerDan McDonald <danmcd@joyent.com>2018-06-19 14:05:33 -0400
commit4a04e8db7f069cc2eb910470e630778f35ef3c44 (patch)
treef47141ae0d42a8987c8b493a5f8ca540ce5a00f3
parent9d1ccc13a7df03b1b5b6754fc08c980a323c5a37 (diff)
downloadillumos-joyent-4a04e8db7f069cc2eb910470e630778f35ef3c44.tar.gz
8905 loader: add skein/edonr support
Reviewed by: Andy Fiddaman <omnios@citrus-it.co.uk> Reviewed by: Ken Mays <kmays2000@gmail.com> Reviewed by: C Fraire <cfraire@me.com> Approved by: Dan McDonald <danmcd@joyent.com>
-rw-r--r--usr/src/boot/sys/boot/efi/boot1/Makefile5
-rw-r--r--usr/src/boot/sys/boot/i386/gptzfsboot/gptldr.S2
-rw-r--r--usr/src/boot/sys/boot/zfs/Makefile.com18
-rw-r--r--usr/src/boot/sys/boot/zfs/zfsimpl.c146
-rw-r--r--usr/src/boot/sys/cddl/boot/zfs/edonr_zfs.c100
-rw-r--r--usr/src/boot/sys/cddl/boot/zfs/skein_zfs.c90
-rw-r--r--usr/src/boot/sys/cddl/boot/zfs/zfsimpl.h7
-rw-r--r--usr/src/boot/sys/cddl/boot/zfs/zfssubr.c75
-rw-r--r--usr/src/boot/sys/sys/types.h5
-rw-r--r--usr/src/uts/common/sys/debug.h2
-rw-r--r--usr/src/uts/common/sys/systm.h7
11 files changed, 410 insertions, 47 deletions
diff --git a/usr/src/boot/sys/boot/efi/boot1/Makefile b/usr/src/boot/sys/boot/efi/boot1/Makefile
index aee4ba24fb..9c0f56d75e 100644
--- a/usr/src/boot/sys/boot/efi/boot1/Makefile
+++ b/usr/src/boot/sys/boot/efi/boot1/Makefile
@@ -33,7 +33,7 @@ OBJS= multiboot.o boot1.o self_reloc.o start.o ufs_module.o zfs_module.o \
ASFLAGS=-m64 -fPIC
CFLAGS= -O2
-CPPFLAGS= -nostdinc
+CPPFLAGS= -nostdinc -D_STANDALONE
CPPFLAGS += -I.
CPPFLAGS += -I./../include
CPPFLAGS += -I./../include/${MACHINE}
@@ -51,6 +51,9 @@ CPPFLAGS += -I./../../../cddl/boot/zfs/
# Always add MI sources and REGULAR efi loader bits
CPPFLAGS += -I./../../common
+# For sys/skein.h
+CPPFLAGS += -I$(SRC)/uts/common
+
include ../Makefile.inc
FILES= boot1.efi
diff --git a/usr/src/boot/sys/boot/i386/gptzfsboot/gptldr.S b/usr/src/boot/sys/boot/i386/gptzfsboot/gptldr.S
index 9b646aee66..1b1fd9ba9c 100644
--- a/usr/src/boot/sys/boot/i386/gptzfsboot/gptldr.S
+++ b/usr/src/boot/sys/boot/i386/gptzfsboot/gptldr.S
@@ -45,7 +45,7 @@
/* Misc. Constants */
.set SIZ_PAG,0x1000 # Page size
.set SIZ_SEC,0x200 # Sector size
- .set COPY_BLKS,0x4 # Number of blocks
+ .set COPY_BLKS,0x8 # Number of blocks
# to copy for boot2
.set COPY_BLK_SZ,0x8000 # Copy in 32k blocks; must be
# a multiple of 16 bytes
diff --git a/usr/src/boot/sys/boot/zfs/Makefile.com b/usr/src/boot/sys/boot/zfs/Makefile.com
index 9873feb785..ee5c8ac1b8 100644
--- a/usr/src/boot/sys/boot/zfs/Makefile.com
+++ b/usr/src/boot/sys/boot/zfs/Makefile.com
@@ -29,13 +29,21 @@ CC= $(GCC_ROOT)/bin/gcc
CPPFLAGS=
SRCS += ../zfs.c ../gzip.c
-OBJS += zfs.o gzip.o
+SRCS += $(SRC)/common/crypto/edonr/edonr.c
+SRCS += $(SRC)/common/crypto/skein/skein.c
+SRCS += $(SRC)/common/crypto/skein/skein_iv.c
+SRCS += $(SRC)/common/crypto/skein/skein_block.c
+OBJS += zfs.o gzip.o edonr.o skein.o skein_iv.o skein_block.o
-CFLAGS= -O2 -nostdinc -I../../../../include -I../../..
+CFLAGS= -O2 -D_STANDALONE -nostdinc -I../../../../include -I../../..
CFLAGS += -I../../common -I../../.. -I.. -I.
CFLAGS += -I../../../../lib/libstand
CFLAGS += -I../../../../lib/libz
CFLAGS += -I../../../cddl/boot/zfs
+CFLAGS += -I$(SRC)/uts/common
+
+# Do not unroll skein loops, reduce code size
+CFLAGS += -DSKEIN_LOOP=111
CFLAGS += -ffreestanding
CFLAGS += -mno-mmx -mno-3dnow -mno-sse -mno-sse2 -mno-sse3 -msoft-float
@@ -59,4 +67,10 @@ libzfsboot.a: $(OBJS)
%.o: ../%.c
$(COMPILE.c) -o $@ $<
+%.o: $(SRC)/common/crypto/edonr/%.c
+ $(COMPILE.c) -o $@ $<
+
+%.o: $(SRC)/common/crypto/skein/%.c
+ $(COMPILE.c) -o $@ $<
+
zfs.o: ../zfsimpl.c
diff --git a/usr/src/boot/sys/boot/zfs/zfsimpl.c b/usr/src/boot/sys/boot/zfs/zfsimpl.c
index 73c9d52e0a..b3edf4653a 100644
--- a/usr/src/boot/sys/boot/zfs/zfsimpl.c
+++ b/usr/src/boot/sys/boot/zfs/zfsimpl.c
@@ -58,6 +58,8 @@ static const char *features_for_read[] = {
"com.delphix:embedded_data",
"org.open-zfs:large_blocks",
"org.illumos:sha512",
+ "org.illumos:skein",
+ "org.illumos:edonr",
"org.zfsonlinux:large_dnode",
"com.joyent:multi_vdev_crash_dump",
NULL
@@ -79,6 +81,9 @@ static char *zfs_temp_buf, *zfs_temp_end, *zfs_temp_ptr;
static int zio_read(const spa_t *spa, const blkptr_t *bp, void *buf);
static int zfs_get_root(const spa_t *spa, uint64_t *objid);
static int zfs_rlookup(const spa_t *spa, uint64_t objnum, char *result);
+static int zap_lookup(const spa_t *spa, const dnode_phys_t *dnode,
+ const char *name, uint64_t integer_size, uint64_t num_integers,
+ void *value);
static void
zfs_init(void)
@@ -421,7 +426,7 @@ vdev_read_phys(vdev_t *vdev, const blkptr_t *bp, void *buf,
rc = vdev->v_phys_read(vdev, vdev->v_read_priv, offset, buf, psize);
if (rc)
return (rc);
- if (bp && zio_checksum_verify(bp, buf))
+ if (bp && zio_checksum_verify(vdev->spa, bp, buf))
return (EIO);
return (0);
@@ -1091,8 +1096,10 @@ vdev_probe(vdev_phys_read_t *phys_read, void *read_priv, spa_t **spap)
STAILQ_FOREACH(pool_vdev, &spa->spa_vdevs, v_childlink)
if (top_vdev == pool_vdev)
break;
- if (!pool_vdev && top_vdev)
+ if (!pool_vdev && top_vdev) {
+ top_vdev->spa = spa;
STAILQ_INSERT_TAIL(&spa->spa_vdevs, top_vdev, v_childlink);
+ }
/*
* We should already have created an incomplete vdev for this
@@ -1153,6 +1160,7 @@ vdev_probe(vdev_phys_read_t *phys_read, void *read_priv, spa_t **spap)
}
zfs_free(upbuf, VDEV_UBERBLOCK_SIZE(vdev));
+ vdev->spa = spa;
if (spap != NULL)
*spap = spa;
return (0);
@@ -1201,7 +1209,7 @@ zio_read_gang(const spa_t *spa, const blkptr_t *bp, void *buf)
pbuf += BP_GET_PSIZE(gbp);
}
- if (zio_checksum_verify(bp, buf))
+ if (zio_checksum_verify(spa, bp, buf))
return (EIO);
return (0);
}
@@ -1451,12 +1459,93 @@ fzap_leaf_value(const zap_leaf_t *zl, const zap_leaf_chunk_t *zc)
return value;
}
+static void
+stv(int len, void *addr, uint64_t value)
+{
+ switch (len) {
+ case 1:
+ *(uint8_t *)addr = value;
+ return;
+ case 2:
+ *(uint16_t *)addr = value;
+ return;
+ case 4:
+ *(uint32_t *)addr = value;
+ return;
+ case 8:
+ *(uint64_t *)addr = value;
+ return;
+ }
+}
+
+/*
+ * Extract a array from a zap leaf entry.
+ */
+static void
+fzap_leaf_array(const zap_leaf_t *zl, const zap_leaf_chunk_t *zc,
+ uint64_t integer_size, uint64_t num_integers, void *buf)
+{
+ uint64_t array_int_len = zc->l_entry.le_value_intlen;
+ uint64_t value = 0;
+ uint64_t *u64 = buf;
+ char *p = buf;
+ int len = MIN(zc->l_entry.le_value_numints, num_integers);
+ int chunk = zc->l_entry.le_value_chunk;
+ int byten = 0;
+
+ if (integer_size == 8 && len == 1) {
+ *u64 = fzap_leaf_value(zl, zc);
+ return;
+ }
+
+ while (len > 0) {
+ struct zap_leaf_array *la = &ZAP_LEAF_CHUNK(zl, chunk).l_array;
+ int i;
+
+ ASSERT3U(chunk, <, ZAP_LEAF_NUMCHUNKS(zl));
+ for (i = 0; i < ZAP_LEAF_ARRAY_BYTES && len > 0; i++) {
+ value = (value << 8) | la->la_array[i];
+ byten++;
+ if (byten == array_int_len) {
+ stv(integer_size, p, value);
+ byten = 0;
+ len--;
+ if (len == 0)
+ return;
+ p += integer_size;
+ }
+ }
+ chunk = la->la_next;
+ }
+}
+
+static int
+fzap_check_size(uint64_t integer_size, uint64_t num_integers)
+{
+
+ switch (integer_size) {
+ case 1:
+ case 2:
+ case 4:
+ case 8:
+ break;
+ default:
+ return (EINVAL);
+ }
+
+ if (integer_size * num_integers > ZAP_MAXVALUELEN)
+ return (E2BIG);
+
+ return (0);
+}
+
/*
* Lookup a value in a fatzap directory. Assumes that the zap scratch
* buffer contains the directory header.
*/
static int
-fzap_lookup(const spa_t *spa, const dnode_phys_t *dnode, const char *name, uint64_t *value)
+fzap_lookup(const spa_t *spa, const dnode_phys_t *dnode, const char *name,
+ uint64_t integer_size, uint64_t num_integers, void *value)
{
int bsize = dnode->dn_datablkszsec << SPA_MINBLOCKSHIFT;
zap_phys_t zh = *(zap_phys_t *) zap_scratch;
@@ -1468,6 +1557,9 @@ fzap_lookup(const spa_t *spa, const dnode_phys_t *dnode, const char *name, uint6
if (zh.zap_magic != ZAP_MAGIC)
return (EIO);
+ if ((rc = fzap_check_size(integer_size, num_integers)) != 0)
+ return (rc);
+
z.zap_block_shift = ilog2(bsize);
z.zap_phys = (zap_phys_t *) zap_scratch;
@@ -1523,9 +1615,10 @@ fzap_lookup(const spa_t *spa, const dnode_phys_t *dnode, const char *name, uint6
zc = &ZAP_LEAF_CHUNK(&zl, zc->l_entry.le_next);
}
if (fzap_name_equal(&zl, zc, name)) {
- if (zc->l_entry.le_value_intlen * zc->l_entry.le_value_numints > 8)
- return (E2BIG);
- *value = fzap_leaf_value(&zl, zc);
+ if (zc->l_entry.le_value_intlen > integer_size)
+ return (EINVAL);
+
+ fzap_leaf_array(&zl, zc, integer_size, num_integers, value);
return (0);
}
@@ -1536,7 +1629,8 @@ fzap_lookup(const spa_t *spa, const dnode_phys_t *dnode, const char *name, uint6
* Lookup a name in a zap object and return its value as a uint64_t.
*/
static int
-zap_lookup(const spa_t *spa, const dnode_phys_t *dnode, const char *name, uint64_t *value)
+zap_lookup(const spa_t *spa, const dnode_phys_t *dnode, const char *name,
+ uint64_t integer_size, uint64_t num_integers, void *value)
{
int rc;
uint64_t zap_type;
@@ -1549,8 +1643,10 @@ zap_lookup(const spa_t *spa, const dnode_phys_t *dnode, const char *name, uint64
zap_type = *(uint64_t *) zap_scratch;
if (zap_type == ZBT_MICRO)
return mzap_lookup(dnode, name, value);
- else if (zap_type == ZBT_HEADER)
- return fzap_lookup(spa, dnode, name, value);
+ else if (zap_type == ZBT_HEADER) {
+ return fzap_lookup(spa, dnode, name, integer_size,
+ num_integers, value);
+ }
printf("ZFS: invalid zap_type=%d\n", (int)zap_type);
return (EIO);
}
@@ -1889,7 +1985,8 @@ zfs_lookup_dataset(const spa_t *spa, const char *name, uint64_t *objnum)
if (objset_get_dnode(spa, &spa->spa_mos, DMU_POOL_DIRECTORY_OBJECT, &dir))
return (EIO);
- if (zap_lookup(spa, &dir, DMU_POOL_ROOT_DATASET, &dir_obj))
+ if (zap_lookup(spa, &dir, DMU_POOL_ROOT_DATASET, sizeof (dir_obj),
+ 1, &dir_obj))
return (EIO);
p = name;
@@ -1919,7 +2016,8 @@ zfs_lookup_dataset(const spa_t *spa, const char *name, uint64_t *objnum)
return (EIO);
/* Actual loop condition #2. */
- if (zap_lookup(spa, &child_dir_zap, element, &dir_obj) != 0)
+ if (zap_lookup(spa, &child_dir_zap, element, sizeof (dir_obj),
+ 1, &dir_obj) != 0)
return (ENOENT);
}
@@ -2048,9 +2146,9 @@ zfs_get_root(const spa_t *spa, uint64_t *objid)
/*
* Lookup the pool_props and see if we can find a bootfs.
*/
- if (zap_lookup(spa, &dir, DMU_POOL_PROPS, &props) == 0
+ if (zap_lookup(spa, &dir, DMU_POOL_PROPS, sizeof (props), 1, &props) == 0
&& objset_get_dnode(spa, &spa->spa_mos, props, &propdir) == 0
- && zap_lookup(spa, &propdir, "bootfs", &bootfs) == 0
+ && zap_lookup(spa, &propdir, "bootfs", sizeof (bootfs), 1, &bootfs) == 0
&& bootfs != 0)
{
*objid = bootfs;
@@ -2059,7 +2157,7 @@ zfs_get_root(const spa_t *spa, uint64_t *objid)
/*
* Lookup the root dataset directory
*/
- if (zap_lookup(spa, &dir, DMU_POOL_ROOT_DATASET, &root)
+ if (zap_lookup(spa, &dir, DMU_POOL_ROOT_DATASET, sizeof (root), 1, &root)
|| objset_get_dnode(spa, &spa->spa_mos, root, &dir)) {
printf("ZFS: can't find root dsl_dir\n");
return (EIO);
@@ -2134,7 +2232,7 @@ check_mos_features(const spa_t *spa)
&dir)) != 0)
return (rc);
if ((rc = zap_lookup(spa, &dir, DMU_POOL_FEATURES_FOR_READ,
- &objnum)) != 0) {
+ sizeof (objnum), 1, &objnum)) != 0) {
/*
* It is older pool without features. As we have already
* tested the label, just return without raising the error.
@@ -2166,6 +2264,7 @@ check_mos_features(const spa_t *spa)
static int
zfs_spa_init(spa_t *spa)
{
+ dnode_phys_t dir;
int rc;
if (zio_read(spa, &spa->spa_uberblock.ub_rootbp, &spa->spa_mos)) {
@@ -2177,6 +2276,17 @@ zfs_spa_init(spa_t *spa)
return (EIO);
}
+ if (objset_get_dnode(spa, &spa->spa_mos, DMU_POOL_DIRECTORY_OBJECT,
+ &dir)) {
+ printf("ZFS: failed to read pool %s directory object\n",
+ spa->spa_name);
+ return (EIO);
+ }
+ /* this is allowed to fail, older pools do not have salt */
+ rc = zap_lookup(spa, &dir, DMU_POOL_CHECKSUM_SALT, 1,
+ sizeof (spa->spa_cksum_salt.zcs_bytes),
+ spa->spa_cksum_salt.zcs_bytes);
+
rc = check_mos_features(spa);
if (rc != 0) {
printf("ZFS: pool %s is not supported\n", spa->spa_name);
@@ -2329,7 +2439,7 @@ zfs_lookup(const struct zfsmount *mnt, const char *upath, dnode_phys_t *dnode)
return (rc);
}
- rc = zap_lookup(spa, &dn, ZFS_ROOT_OBJ, &objnum);
+ rc = zap_lookup(spa, &dn, ZFS_ROOT_OBJ, sizeof(objnum), 1, &objnum);
if (rc) {
free(entry);
return (rc);
@@ -2389,7 +2499,7 @@ zfs_lookup(const struct zfsmount *mnt, const char *upath, dnode_phys_t *dnode)
goto done;
}
- rc = zap_lookup(spa, &dn, element, &objnum);
+ rc = zap_lookup(spa, &dn, element, sizeof(objnum), 1, &objnum);
if (rc)
goto done;
objnum = ZFS_DIRENT_OBJ(objnum);
diff --git a/usr/src/boot/sys/cddl/boot/zfs/edonr_zfs.c b/usr/src/boot/sys/cddl/boot/zfs/edonr_zfs.c
new file mode 100644
index 0000000000..ff1cd0566f
--- /dev/null
+++ b/usr/src/boot/sys/cddl/boot/zfs/edonr_zfs.c
@@ -0,0 +1,100 @@
+/*
+ * 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
+ */
+/*
+ * Copyright 2013 Saso Kiselkov. All rights reserved.
+ * Use is subject to license terms.
+ */
+#include <sys/edonr.h>
+
+#define EDONR_MODE 512
+#define EDONR_BLOCK_SIZE EdonR512_BLOCK_SIZE
+
+/*
+ * Native zio_checksum interface for the Edon-R hash function.
+ */
+/*ARGSUSED*/
+static void
+zio_checksum_edonr_native(const void *buf, uint64_t size,
+ const void *ctx_template, zio_cksum_t *zcp)
+{
+ uint8_t digest[EDONR_MODE / 8];
+ EdonRState ctx;
+
+ ASSERT(ctx_template != NULL);
+ bcopy(ctx_template, &ctx, sizeof (ctx));
+ EdonRUpdate(&ctx, buf, size * 8);
+ EdonRFinal(&ctx, digest);
+ bcopy(digest, zcp->zc_word, sizeof (zcp->zc_word));
+}
+
+/*
+ * Byteswapped zio_checksum interface for the Edon-R hash function.
+ */
+static void
+zio_checksum_edonr_byteswap(const void *buf, uint64_t size,
+ const void *ctx_template, zio_cksum_t *zcp)
+{
+ zio_cksum_t tmp;
+
+ zio_checksum_edonr_native(buf, size, ctx_template, &tmp);
+ zcp->zc_word[0] = BSWAP_64(zcp->zc_word[0]);
+ zcp->zc_word[1] = BSWAP_64(zcp->zc_word[1]);
+ zcp->zc_word[2] = BSWAP_64(zcp->zc_word[2]);
+ zcp->zc_word[3] = BSWAP_64(zcp->zc_word[3]);
+}
+
+static void *
+zio_checksum_edonr_tmpl_init(const zio_cksum_salt_t *salt)
+{
+ EdonRState *ctx;
+ uint8_t salt_block[EDONR_BLOCK_SIZE];
+
+ /*
+ * Edon-R needs all but the last hash invocation to be on full-size
+ * blocks, but the salt is too small. Rather than simply padding it
+ * with zeros, we expand the salt into a new salt block of proper
+ * size by double-hashing it (the new salt block will be composed of
+ * H(salt) || H(H(salt))).
+ */
+ EdonRHash(EDONR_MODE, salt->zcs_bytes, sizeof (salt->zcs_bytes) * 8,
+ salt_block);
+ EdonRHash(EDONR_MODE, salt_block, EDONR_MODE, salt_block +
+ EDONR_MODE / 8);
+
+ /*
+ * Feed the new salt block into the hash function - this will serve
+ * as our MAC key.
+ */
+ ctx = malloc(sizeof (*ctx));
+ bzero(ctx, sizeof (*ctx));
+ EdonRInit(ctx, EDONR_MODE);
+ EdonRUpdate(ctx, salt_block, sizeof (salt_block) * 8);
+ return (ctx);
+}
+
+static void
+zio_checksum_edonr_tmpl_free(void *ctx_template)
+{
+ EdonRState *ctx = ctx_template;
+
+ bzero(ctx, sizeof (*ctx));
+ free(ctx);
+}
diff --git a/usr/src/boot/sys/cddl/boot/zfs/skein_zfs.c b/usr/src/boot/sys/cddl/boot/zfs/skein_zfs.c
new file mode 100644
index 0000000000..d8ef49d399
--- /dev/null
+++ b/usr/src/boot/sys/cddl/boot/zfs/skein_zfs.c
@@ -0,0 +1,90 @@
+/*
+ * 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
+ */
+/*
+ * Copyright 2013 Saso Kiselkov. All rights reserved.
+ */
+#include <sys/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/usr/src/boot/sys/cddl/boot/zfs/zfsimpl.h b/usr/src/boot/sys/cddl/boot/zfs/zfsimpl.h
index cfddbfe974..8cd5cf8f2b 100644
--- a/usr/src/boot/sys/cddl/boot/zfs/zfsimpl.h
+++ b/usr/src/boot/sys/cddl/boot/zfs/zfsimpl.h
@@ -1073,6 +1073,8 @@ typedef enum dmu_objset_type {
DMU_OST_NUMTYPES
} dmu_objset_type_t;
+#define ZAP_MAXVALUELEN (1024 * 8)
+
/*
* header for all bonus and spill buffers.
* The header has a fixed portion with a variable number
@@ -1208,6 +1210,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
@@ -1513,6 +1516,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,
@@ -1537,6 +1541,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;
/*
@@ -1552,6 +1557,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 */
vdev_t *spa_boot_vdev; /* boot device for kernel */
} spa_t;
diff --git a/usr/src/boot/sys/cddl/boot/zfs/zfssubr.c b/usr/src/boot/sys/cddl/boot/zfs/zfssubr.c
index 30d6a71e8d..e38f14f33b 100644
--- a/usr/src/boot/sys/cddl/boot/zfs/zfssubr.c
+++ b/usr/src/boot/sys/cddl/boot/zfs/zfssubr.c
@@ -105,6 +105,8 @@ typedef struct zio_checksum_info {
#include "fletcher.c"
#include "sha256.c"
+#include "skein_zfs.c"
+#include "edonr_zfs.c"
static zio_checksum_info_t zio_checksum_table[ZIO_CHECKSUM_FUNCTIONS] = {
{{NULL, NULL}, NULL, NULL, 0, "inherit"},
@@ -131,11 +133,14 @@ static zio_checksum_info_t zio_checksum_table[ZIO_CHECKSUM_FUNCTIONS] = {
NULL, NULL, ZCHECKSUM_FLAG_METADATA | ZCHECKSUM_FLAG_DEDUP |
ZCHECKSUM_FLAG_NOPWRITE, "SHA512"},
/* no skein and edonr for now */
- {{NULL, NULL}, NULL, NULL, ZCHECKSUM_FLAG_METADATA |
- ZCHECKSUM_FLAG_DEDUP | ZCHECKSUM_FLAG_SALTED |
- ZCHECKSUM_FLAG_NOPWRITE, "skein"},
- {{NULL, NULL}, NULL, NULL, ZCHECKSUM_FLAG_METADATA |
- ZCHECKSUM_FLAG_SALTED | ZCHECKSUM_FLAG_NOPWRITE, "edonr"},
+ {{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"},
+ {{zio_checksum_edonr_native, zio_checksum_edonr_byteswap},
+ zio_checksum_edonr_tmpl_init, zio_checksum_edonr_tmpl_free,
+ ZCHECKSUM_FLAG_METADATA | ZCHECKSUM_FLAG_SALTED |
+ ZCHECKSUM_FLAG_NOPWRITE, "edonr"},
};
/*
@@ -228,33 +233,48 @@ zio_checksum_label_verifier(zio_cksum_t *zcp, uint64_t offset)
* templates and installs the template into the spa_t.
*/
static void
-zio_checksum_template_init(enum zio_checksum checksum, const spa_t *spa)
+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 0 /* for now we dont have anything here */
+
if (spa->spa_cksum_tmpls[checksum] != NULL)
return;
- VERIFY(ci->ci_tmpl_free != NULL);
- mutex_enter(&spa->spa_cksum_tmpls_lock);
if (spa->spa_cksum_tmpls[checksum] == NULL) {
spa->spa_cksum_tmpls[checksum] =
ci->ci_tmpl_init(&spa->spa_cksum_salt);
- VERIFY(spa->spa_cksum_tmpls[checksum] != NULL);
}
- mutex_exit(&spa->spa_cksum_tmpls_lock);
-#endif
+}
+
+/*
+ * 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;
@@ -267,7 +287,11 @@ zio_checksum_verify(const blkptr_t *bp, void *data)
if (ci->ci_func[0] == NULL || ci->ci_func[1] == NULL)
return (EINVAL);
- zio_checksum_template_init(checksum, NULL);
+ 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;
@@ -291,7 +315,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, NULL, &actual_cksum);
+ ci->ci_func[byteswap](data, size, ctx, &actual_cksum);
eck->zec_cksum = expected_cksum;
if (byteswap)
@@ -299,11 +323,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, NULL, &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);
}
@@ -1313,10 +1337,11 @@ 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));
}
/*
@@ -1365,8 +1390,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];
@@ -1445,7 +1470,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];
@@ -1616,7 +1641,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
@@ -1661,7 +1686,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
@@ -1735,7 +1760,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
diff --git a/usr/src/boot/sys/sys/types.h b/usr/src/boot/sys/sys/types.h
index 579b104924..ee3d847278 100644
--- a/usr/src/boot/sys/sys/types.h
+++ b/usr/src/boot/sys/sys/types.h
@@ -58,6 +58,11 @@ typedef unsigned int uint; /* Sys V compatibility */
#endif
/*
+ * POSIX Extensions
+ */
+typedef unsigned int uint_t;
+
+/*
* XXX POSIX sized integrals that should appear only in <sys/stdint.h>.
*/
#include <sys/_stdint.h>
diff --git a/usr/src/uts/common/sys/debug.h b/usr/src/uts/common/sys/debug.h
index 645716cd9c..e4a959205a 100644
--- a/usr/src/uts/common/sys/debug.h
+++ b/usr/src/uts/common/sys/debug.h
@@ -36,7 +36,9 @@
#ifndef _SYS_DEBUG_H
#define _SYS_DEBUG_H
+#if !defined(_STANDALONE)
#include <sys/isa_defs.h>
+#endif
#include <sys/types.h>
#include <sys/note.h>
diff --git a/usr/src/uts/common/sys/systm.h b/usr/src/uts/common/sys/systm.h
index 32af97f4fa..0a56d5d191 100644
--- a/usr/src/uts/common/sys/systm.h
+++ b/usr/src/uts/common/sys/systm.h
@@ -31,15 +31,21 @@
#ifndef _SYS_SYSTM_H
#define _SYS_SYSTM_H
+#if defined(_STANDALONE)
+#include <sys/cdefs.h>
+#include <string.h>
+#else
#include <sys/types.h>
#include <sys/t_lock.h>
#include <sys/proc.h>
#include <sys/dditypes.h>
+#endif
#ifdef __cplusplus
extern "C" {
#endif
+#if !defined(_STANDALONE)
/*
* The pc_t is the type of the kernel's program counter. In general, a
* pc_t is a uintptr_t -- except for a sparcv9 kernel, in which case all
@@ -508,6 +514,7 @@ extern int __lintzero; /* for spoofing lint */
#define __lintzero 0
#endif /* __lint */
#endif /* _KERNEL || _BOOT */
+#endif /* !_STANDALONE */
#ifdef __cplusplus
}