summaryrefslogtreecommitdiffstats
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
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
-rw-r--r--sys/boot/efi/boot1/Makefile11
-rw-r--r--sys/boot/efi/loader/Makefile5
-rw-r--r--sys/boot/i386/boot2/Makefile2
-rw-r--r--sys/boot/i386/gptboot/Makefile4
-rw-r--r--sys/boot/i386/gptboot/gptldr.S2
-rw-r--r--sys/boot/i386/gptzfsboot/Makefile22
-rw-r--r--sys/boot/i386/zfsboot/Makefile17
-rw-r--r--sys/boot/i386/zfsboot/zfsboot.c2
-rw-r--r--sys/boot/i386/zfsboot/zfsldr.S65
-rw-r--r--sys/boot/userboot/ficl/Makefile3
-rw-r--r--sys/boot/userboot/userboot/Makefile2
-rw-r--r--sys/boot/userboot/userboot/main.c2
-rw-r--r--sys/boot/userboot/zfs/Makefile8
-rw-r--r--sys/boot/zfs/Makefile6
-rw-r--r--sys/boot/zfs/zfsimpl.c121
-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
20 files changed, 668 insertions, 125 deletions
diff --git a/sys/boot/efi/boot1/Makefile b/sys/boot/efi/boot1/Makefile
index 73f349f..4e25f51 100644
--- a/sys/boot/efi/boot1/Makefile
+++ b/sys/boot/efi/boot1/Makefile
@@ -19,12 +19,22 @@ CWARNFLAGS.zfs_module.c += -Wno-missing-prototypes
CWARNFLAGS.zfs_module.c += -Wno-sign-compare
CWARNFLAGS.zfs_module.c += -Wno-unused-parameter
CWARNFLAGS.zfs_module.c += -Wno-unused-function
+CWARNFLAGS.skein.c += -Wno-cast-align
+.if ${COMPILER_TYPE} == "clang"
+CWARNFLAGS.skein.c += -Wno-missing-variable-declarations
+.else if ${COMPILER_TYPE} == "gcc"
+CWARNFLAGS.skein.c += -Wno-missing-declarations
+.endif
.endif
# architecture-specific loader code
SRCS= boot1.c self_reloc.c start.S ufs_module.c
.if ${MK_ZFS} != "no"
SRCS+= zfs_module.c
+SRCS+= skein.c skein_block.c
+# Do not unroll skein loops, reduce code size
+CFLAGS+= -DSKEIN_LOOP=111
+.PATH: ${.CURDIR}/../../../crypto/skein
.endif
.if ${COMPILER_TYPE} == "gcc" && ${COMPILER_VERSION} > 40201
@@ -44,6 +54,7 @@ CFLAGS+= -DEFI_DEBUG
.if ${MK_ZFS} != "no"
CFLAGS+= -I${.CURDIR}/../../zfs/
CFLAGS+= -I${.CURDIR}/../../../cddl/boot/zfs/
+CFLAGS+= -I${.CURDIR}/../../../crypto/skein
CFLAGS+= -DEFI_ZFS_BOOT
.endif
diff --git a/sys/boot/efi/loader/Makefile b/sys/boot/efi/loader/Makefile
index a2aaa78a..69540ef 100644
--- a/sys/boot/efi/loader/Makefile
+++ b/sys/boot/efi/loader/Makefile
@@ -24,6 +24,10 @@ SRCS= autoload.c \
.if ${MK_ZFS} != "no"
SRCS+= zfs.c
.PATH: ${.CURDIR}/../../zfs
+SRCS+= skein.c skein_block.c
+# Do not unroll skein loops, reduce code size
+CFLAGS+= -DSKEIN_LOOP=111
+.PATH: ${.CURDIR}/../../../crypto/skein
# Disable warnings that are currently incompatible with the zfs boot code
CWARNFLAGS.zfs.c+= -Wno-sign-compare
@@ -57,6 +61,7 @@ CFLAGS+= -I${.CURDIR}/../../i386/libi386
.if ${MK_ZFS} != "no"
CFLAGS+= -I${.CURDIR}/../../zfs
CFLAGS+= -I${.CURDIR}/../../../cddl/boot/zfs
+CFLAGS+= -I${.CURDIR}/../../../crypto/skein
CFLAGS+= -DEFI_ZFS_BOOT
.endif
CFLAGS+= -DNO_PCI -DEFI
diff --git a/sys/boot/i386/boot2/Makefile b/sys/boot/i386/boot2/Makefile
index c4328dc2..bb3ecdc 100644
--- a/sys/boot/i386/boot2/Makefile
+++ b/sys/boot/i386/boot2/Makefile
@@ -33,7 +33,7 @@ CFLAGS= -fomit-frame-pointer \
-DSIOSPD=${BOOT_COMCONSOLE_SPEED} \
-I${.CURDIR}/../../common \
-I${.CURDIR}/../btx/lib -I. \
- -Wall -Waggregate-return -Wbad-function-cast -Wcast-align \
+ -Wall -Waggregate-return -Wbad-function-cast -Wno-cast-align \
-Wmissing-declarations -Wmissing-prototypes -Wnested-externs \
-Wpointer-arith -Wshadow -Wstrict-prototypes -Wwrite-strings \
-Winline
diff --git a/sys/boot/i386/gptboot/Makefile b/sys/boot/i386/gptboot/Makefile
index cc8251c..b89a472 100644
--- a/sys/boot/i386/gptboot/Makefile
+++ b/sys/boot/i386/gptboot/Makefile
@@ -32,10 +32,10 @@ CFLAGS= -DBOOTPROG=\"gptboot\" \
-I${.CURDIR}/../btx/lib -I. \
-I${.CURDIR}/../boot2 \
-I${.CURDIR}/../../.. \
- -Wall -Waggregate-return -Wbad-function-cast -Wcast-align \
+ -Wall -Waggregate-return -Wbad-function-cast -Wno-cast-align \
-Wmissing-declarations -Wmissing-prototypes -Wnested-externs \
-Wpointer-arith -Wshadow -Wstrict-prototypes -Wwrite-strings \
- -Winline
+ -Winline -Wno-pointer-sign
CFLAGS.gcc+= --param max-inline-insns-single=100
diff --git a/sys/boot/i386/gptboot/gptldr.S b/sys/boot/i386/gptboot/gptldr.S
index bbd32ba..088122f 100644
--- a/sys/boot/i386/gptboot/gptldr.S
+++ b/sys/boot/i386/gptboot/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/sys/boot/i386/gptzfsboot/Makefile b/sys/boot/i386/gptzfsboot/Makefile
index e8d46a6..0278508 100644
--- a/sys/boot/i386/gptzfsboot/Makefile
+++ b/sys/boot/i386/gptzfsboot/Makefile
@@ -1,8 +1,10 @@
# $FreeBSD$
+.include <bsd.own.mk>
+
.PATH: ${.CURDIR}/../boot2 ${.CURDIR}/../gptboot \
${.CURDIR}/../zfsboot ${.CURDIR}/../common \
- ${.CURDIR}/../../common
+ ${.CURDIR}/../../common ${.CURDIR}/../../../crypto/skein
FILES= gptzfsboot
MAN= gptzfsboot.8
@@ -27,13 +29,22 @@ CFLAGS= -DBOOTPROG=\"gptzfsboot\" \
-I${.CURDIR}/../common \
-I${.CURDIR}/../../zfs \
-I${.CURDIR}/../../../cddl/boot/zfs \
+ -I${.CURDIR}/../../../crypto/skein \
-I${.CURDIR}/../btx/lib -I. \
-I${.CURDIR}/../boot2 \
-I${.CURDIR}/../../.. \
- -Wall -Waggregate-return -Wbad-function-cast -Wcast-align \
+ -Wall -Waggregate-return -Wbad-function-cast -Wno-cast-align \
-Wmissing-declarations -Wmissing-prototypes -Wnested-externs \
-Wpointer-arith -Wshadow -Wstrict-prototypes -Wwrite-strings \
- -Winline
+ -Winline -Wno-pointer-sign
+
+.if ${COMPILER_TYPE} == "clang" || \
+ (${COMPILER_TYPE} == "gcc" && ${COMPILER_VERSION} > 40201)
+CFLAGS+= -Wno-tentative-definition-incomplete-type
+.endif
+
+# Do not unroll skein loops, reduce code size
+CFLAGS+= -DSKEIN_LOOP=111
.if !defined(LOADER_NO_GELI_SUPPORT)
CFLAGS+= -DLOADER_GELI_SUPPORT
@@ -67,12 +78,13 @@ gptldr.out: gptldr.o
${LD} ${LD_FLAGS} -e start -Ttext ${ORG1} -o ${.TARGET} gptldr.o
CLEANFILES+= gptzfsboot.bin gptzfsboot.out zfsboot.o sio.o cons.o \
- drv.o gpt.o util.o ${OPENCRYPTO_XTS}
+ drv.o gpt.o util.o skein.o skein_block.o ${OPENCRYPTO_XTS}
gptzfsboot.bin: gptzfsboot.out
${OBJCOPY} -S -O binary gptzfsboot.out ${.TARGET}
-gptzfsboot.out: ${BTXCRT} zfsboot.o sio.o gpt.o drv.o cons.o util.o ${OPENCRYPTO_XTS}
+gptzfsboot.out: ${BTXCRT} zfsboot.o sio.o gpt.o drv.o cons.o util.o \
+ skein.o skein_block.o ${OPENCRYPTO_XTS}
${LD} ${LD_FLAGS} -Ttext ${ORG2} -o ${.TARGET} ${.ALLSRC} ${LIBSTAND} ${LIBGELIBOOT}
zfsboot.o: ${.CURDIR}/../../zfs/zfsimpl.c
diff --git a/sys/boot/i386/zfsboot/Makefile b/sys/boot/i386/zfsboot/Makefile
index d7b6636..9786b7b 100644
--- a/sys/boot/i386/zfsboot/Makefile
+++ b/sys/boot/i386/zfsboot/Makefile
@@ -1,6 +1,7 @@
# $FreeBSD$
-.PATH: ${.CURDIR}/../boot2 ${.CURDIR}/../common ${.CURDIR}/../../common
+.PATH: ${.CURDIR}/../boot2 ${.CURDIR}/../common \
+ ${.CURDIR}/../../common ${.CURDIR}/../../../crypto/skein
FILES= zfsboot
MAN= zfsboot.8
@@ -25,14 +26,17 @@ CFLAGS= -DBOOTPROG=\"zfsboot\" \
-I${.CURDIR}/../common \
-I${.CURDIR}/../../zfs \
-I${.CURDIR}/../../../cddl/boot/zfs \
+ -I${.CURDIR}/../../../crypto/skein \
-I${.CURDIR}/../btx/lib -I. \
-I${.CURDIR}/../boot2 \
- -Wall -Waggregate-return -Wbad-function-cast -Wcast-align \
+ -Wall -Waggregate-return -Wbad-function-cast -Wno-cast-align \
-Wmissing-declarations -Wmissing-prototypes -Wnested-externs \
-Wpointer-arith -Wshadow -Wstrict-prototypes -Wwrite-strings \
-Winline
CFLAGS.gcc+= --param max-inline-insns-single=100
+# Do not unroll skein loops, reduce code size
+CFLAGS+= -DSKEIN_LOOP=111
LD_FLAGS=-static -N --gc-sections
@@ -55,12 +59,13 @@ zfsldr.out: zfsldr.o
${LD} ${LD_FLAGS} -e start -Ttext ${ORG1} -o ${.TARGET} zfsldr.o
CLEANFILES+= zfsboot2 zfsboot.ld zfsboot.ldr zfsboot.bin zfsboot.out \
- zfsboot.o zfsboot.s zfsboot.s.tmp sio.o cons.o drv.o util.o
+ zfsboot.o zfsboot.s zfsboot.s.tmp sio.o cons.o drv.o util.o \
+ skein.o skein_block.o
-# We currently allow 65536 bytes for zfsboot - in practice it could be
+# We currently allow 128k bytes for zfsboot - in practice it could be
# any size up to 3.5Mb but keeping it fixed size simplifies zfsldr.
#
-BOOT2SIZE= 65536
+BOOT2SIZE= 131072
zfsboot2: zfsboot.ld
@set -- `ls -l ${.ALLSRC}`; x=$$((${BOOT2SIZE}-$$5)); \
@@ -77,7 +82,7 @@ zfsboot.ldr:
zfsboot.bin: zfsboot.out
${OBJCOPY} -S -O binary zfsboot.out ${.TARGET}
-zfsboot.out: ${BTXCRT} zfsboot.o sio.o drv.o cons.o util.o
+zfsboot.out: ${BTXCRT} zfsboot.o sio.o drv.o cons.o util.o skein.o skein_block.o
${LD} ${LD_FLAGS} -Ttext ${ORG2} -o ${.TARGET} ${.ALLSRC} ${LIBSTAND}
SRCS= zfsboot.c
diff --git a/sys/boot/i386/zfsboot/zfsboot.c b/sys/boot/i386/zfsboot/zfsboot.c
index 3998511..bb64384 100644
--- a/sys/boot/i386/zfsboot/zfsboot.c
+++ b/sys/boot/i386/zfsboot/zfsboot.c
@@ -105,7 +105,7 @@ static struct bios_smap smap;
/*
* The minimum amount of memory to reserve in bios_extmem for the heap.
*/
-#define HEAP_MIN (3 * 1024 * 1024)
+#define HEAP_MIN (64 * 1024 * 1024)
static char *heap_next;
static char *heap_end;
diff --git a/sys/boot/i386/zfsboot/zfsldr.S b/sys/boot/i386/zfsboot/zfsldr.S
index b8be282..3e85e27 100644
--- a/sys/boot/i386/zfsboot/zfsldr.S
+++ b/sys/boot/i386/zfsboot/zfsldr.S
@@ -32,8 +32,11 @@
/* Misc. Constants */
.set SIZ_PAG,0x1000 # Page size
.set SIZ_SEC,0x200 # Sector size
-
- .set NSECT,0x80
+ .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
+ .set NSECT,(COPY_BLK_SZ / SIZ_SEC * COPY_BLKS)
.globl start
.code16
@@ -88,12 +91,12 @@ main.3: add $0x10,%si # Next entry
/*
* Ok, we have a slice and drive in %dx now, so use that to locate and
* load boot2. %si references the start of the slice we are looking
- * for, so go ahead and load up the 128 sectors starting at sector 1024
- * (i.e. after the two vdev labels). We don't have do anything fancy
- * here to allow for an extra copy of boot1 and a partition table
- * (compare to this section of the UFS bootstrap) so we just load it
- * all at 0x9000. The first part of boot2 is BTX, which wants to run
- * at 0x9000. The boot2.bin binary starts right after the end of BTX,
+ * for, so go ahead and load up the COPY_BLKS*COPY_BLK_SZ/SIZ_SEC sectors
+ * starting at sector 1024 (i.e. after the two vdev labels). We don't
+ * have do anything fancy here to allow for an extra copy of boot1 and
+ * a partition table (compare to this section of the UFS bootstrap) so we
+ * just load it all at 0x9000. The first part of boot2 is BTX, which wants
+ * to run at 0x9000. The boot2.bin binary starts right after the end of BTX,
* so we have to figure out where the start of it is and then move the
* binary to 0xc000. Normally, BTX clients start at MEM_USR, or 0xa000,
* but when we use btxld to create zfsboot2, we use an entry point of
@@ -116,23 +119,37 @@ main.6: pushal # Save params
incl %eax # Advance to
add $SIZ_SEC,%ebx # next sector
loop main.6 # If not last, read another
- mov MEM_BTX+0xa,%bx # Get BTX length
- mov $NSECT*SIZ_SEC-1,%di # Size of load area (less one)
- mov %di,%si # End of load area, 0x9000 rel
- sub %bx,%di # End of client, 0xc000 rel
- mov %di,%cx # Size of
- inc %cx # client
- mov $(MEM_BTX)>>4,%dx # Segment
- mov %dx,%ds # addressing 0x9000
- mov $(MEM_USR+2*SIZ_PAG)>>4,%dx # Segment
- mov %dx,%es # addressing 0xc000
- std # Move with decrement
- rep # Relocate
- movsb # client
+
+ mov $MEM_BTX,%bx # BTX
+ mov 0xa(%bx),%si # Get BTX length and set
+ add %bx,%si # %si to start of boot2
+ dec %si # Set %ds:%si to point at the
+ mov %si,%ax # last byte we want to copy
+ shr $4,%ax # from boot2, with %si made as
+ add $(COPY_BLKS*COPY_BLK_SZ/16),%ax # small as possible.
+ and $0xf,%si #
+ mov %ax,%ds #
+ mov $(MEM_USR+2*SIZ_PAG)/16,%ax # Set %es:(-1) to point at
+ add $(COPY_BLKS*COPY_BLK_SZ/16),%ax # the last byte we
+ mov %ax,%es # want to copy boot2 into.
+ mov $COPY_BLKS,%bx # Copy COPY_BLKS 32k blocks
+copyloop:
+ add $COPY_BLK_SZ,%si # Adjust %ds:%si to point at
+ mov %ds,%ax # the end of the next 32k to
+ sub $COPY_BLK_SZ/16,%ax # copy from boot2
+ mov %ax,%ds
+ mov $COPY_BLK_SZ-1,%di # Adjust %es:%di to point at
+ mov %es,%ax # the end of the next 32k into
+ sub $COPY_BLK_SZ/16,%ax # which we want boot2 copied
+ mov %ax,%es
+ mov $COPY_BLK_SZ,%cx # Copy 32k
+ std
+ rep movsb
+ dec %bx
+ jnz copyloop
+ mov %cx,%ds # Reset %ds and %es
+ mov %cx,%es
cld # Back to increment
- xor %dx,%dx # Back
- mov %ds,%dx # to zero
- mov %dx,%es # segment
/*
* Enable A20 so we can access memory above 1 meg.
diff --git a/sys/boot/userboot/ficl/Makefile b/sys/boot/userboot/ficl/Makefile
index fd6c7f0..927a504 100644
--- a/sys/boot/userboot/ficl/Makefile
+++ b/sys/boot/userboot/ficl/Makefile
@@ -10,6 +10,9 @@ BASE_SRCS= dict.c ficl.c fileaccess.c float.c loader.c math64.c \
SRCS= ${BASE_SRCS} sysdep.c softcore.c
CLEANFILES= softcore.c testmain testmain.o
+
+CWARNFLAGS.loader.c.c += -Wno-implicit-function-declaration
+
.if HAVE_PNP
CFLAGS+= -DHAVE_PNP
.endif
diff --git a/sys/boot/userboot/userboot/Makefile b/sys/boot/userboot/userboot/Makefile
index a6a5d16..44376b8 100644
--- a/sys/boot/userboot/userboot/Makefile
+++ b/sys/boot/userboot/userboot/Makefile
@@ -35,6 +35,8 @@ CFLAGS+= -I${.CURDIR}/../../..
CFLAGS+= -I${.CURDIR}/../../../../lib/libstand
CFLAGS+= -ffreestanding -I.
+CWARNFLAGS.main.c += -Wno-implicit-function-declaration
+
LDFLAGS+= -nostdlib -Wl,-Bsymbolic
NEWVERSWHAT= "User boot" ${MACHINE_CPUARCH}
diff --git a/sys/boot/userboot/userboot/main.c b/sys/boot/userboot/userboot/main.c
index a8ff315..87733cd 100644
--- a/sys/boot/userboot/userboot/main.c
+++ b/sys/boot/userboot/userboot/main.c
@@ -46,7 +46,7 @@ static int userboot_zfs_found;
/* Minimum version required */
#define USERBOOT_VERSION USERBOOT_VERSION_3
-#define MALLOCSZ (10*1024*1024)
+#define MALLOCSZ (64*1024*1024)
struct loader_callbacks *callbacks;
void *callbacks_arg;
diff --git a/sys/boot/userboot/zfs/Makefile b/sys/boot/userboot/zfs/Makefile
index 8fe315b..3180b94 100644
--- a/sys/boot/userboot/zfs/Makefile
+++ b/sys/boot/userboot/zfs/Makefile
@@ -2,15 +2,19 @@
S= ${.CURDIR}/../../zfs
-.PATH: ${S}
+.PATH: ${S} ${.CURDIR}/../../../crypto/skein
LIB= zfsboot
INTERNALLIB=
-SRCS+= zfs.c
+SRCS+= zfs.c skein.c skein_block.c
+
+# Do not unroll skein loops, reduce code size
+CFLAGS+= -DSKEIN_LOOP=111
CFLAGS+= -I${.CURDIR}/../../common -I${.CURDIR}/../../.. -I.
CFLAGS+= -I${.CURDIR}/../../../../lib/libstand
CFLAGS+= -I${.CURDIR}/../../../cddl/boot/zfs
+CFLAGS+= -I${.CURDIR}/../../../crypto/skein
CFLAGS+= -ffreestanding -fPIC
CFLAGS+= -Wformat -Wall
diff --git a/sys/boot/zfs/Makefile b/sys/boot/zfs/Makefile
index 3ab2251..9180049 100644
--- a/sys/boot/zfs/Makefile
+++ b/sys/boot/zfs/Makefile
@@ -5,10 +5,16 @@ INTERNALLIB=
SRCS+= zfs.c
+SRCS+= skein.c skein_block.c
+# Do not unroll skein loops, reduce code size
+CFLAGS+= -DSKEIN_LOOP=111
+.PATH: ${.CURDIR}/../../crypto/skein
+
CFLAGS+= -DBOOTPROG=\"zfsloader\"
CFLAGS+= -I${.CURDIR}/../common -I${.CURDIR}/../.. -I.
CFLAGS+= -I${.CURDIR}/../../../lib/libstand
CFLAGS+= -I${.CURDIR}/../../cddl/boot/zfs
+CFLAGS+= -I${.CURDIR}/../../crypto/skein
.if ${MACHINE_CPUARCH} == "i386" || ${MACHINE_CPUARCH} == "amd64"
CFLAGS+= -march=i386
diff --git a/sys/boot/zfs/zfsimpl.c b/sys/boot/zfs/zfsimpl.c
index e00e056..d5fee46 100644
--- a/sys/boot/zfs/zfsimpl.c
+++ b/sys/boot/zfs/zfsimpl.c
@@ -58,6 +58,8 @@ static const char *features_for_read[] = {
"com.delphix:extensible_dataset",
"com.delphix:embedded_data",
"org.open-zfs:large_blocks",
+ "org.illumos:sha512",
+ "org.illumos:skein",
NULL
};
@@ -77,6 +79,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)
@@ -419,7 +424,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);
@@ -1073,6 +1078,7 @@ vdev_probe(vdev_phys_read_t *_read, void *read_priv, spa_t **spap)
}
zfs_free(upbuf, VDEV_UBERBLOCK_SIZE(vdev));
+ vdev->spa = spa;
if (spap)
*spap = spa;
return (0);
@@ -1121,7 +1127,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);
}
@@ -1223,7 +1229,8 @@ dnode_read(const spa_t *spa, const dnode_phys_t *dnode, off_t offset, void *buf,
int i, rc;
if (bsize > SPA_MAXBLOCKSIZE) {
- printf("ZFS: I/O error - blocks larger than 128K are not supported\n");
+ printf("ZFS: I/O error - blocks larger than %llu are not "
+ "supported\n", SPA_MAXBLOCKSIZE);
return (EIO);
}
@@ -1363,12 +1370,73 @@ 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;
+ }
+}
+
/*
* 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;
@@ -1435,9 +1503,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)
+ if (zc->l_entry.le_value_intlen * zc->l_entry.le_value_numints >
+ integer_size * num_integers)
return (E2BIG);
- *value = fzap_leaf_value(&zl, zc);
+ fzap_leaf_array(&zl, zc, integer_size, num_integers, value);
return (0);
}
@@ -1448,7 +1517,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;
@@ -1461,8 +1531,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);
}
@@ -1801,7 +1873,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;
@@ -1831,7 +1904,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);
}
@@ -1961,9 +2035,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;
@@ -1972,7 +2046,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);
@@ -2046,7 +2120,8 @@ check_mos_features(const spa_t *spa)
if ((rc = objset_get_dnode(spa, &spa->spa_mos, DMU_OT_OBJECT_DIRECTORY,
&dir)) != 0)
return (rc);
- if ((rc = zap_lookup(spa, &dir, DMU_POOL_FEATURES_FOR_READ, &objnum)) != 0) {
+ if ((rc = zap_lookup(spa, &dir, DMU_POOL_FEATURES_FOR_READ,
+ sizeof (objnum), 1, &objnum)) != 0) {
/*
* It is older pool without features. As we have already
* tested the label, just return without raising the error.
@@ -2076,6 +2151,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)) {
@@ -2087,6 +2163,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);
@@ -2239,7 +2326,7 @@ zfs_lookup(const struct zfsmount *mount, 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);
@@ -2299,7 +2386,7 @@ zfs_lookup(const struct zfsmount *mount, 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/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