Add SHA512, skein, large blocks support for loader zfs.

Updated sha512 from illumos.
Using skein from freebsd crypto tree.
Since loader itself is using 64MB memory for heap, updated zfsboot to
use same, and this also allows to support zfs large blocks.

Note, adding additional features does increate zfsboot code, therefore
this update does increase zfsboot code to 128k, also I have ported gptldr.S
update to zfsldr.S to support 64k+ code.

With this update, boot1.efi has almost reached the current limit of the size
set for it, so one of the future patches for boot1.efi will need to
increase the limit.

Currently known missing zfs features in boot loader are edonr and gzip support.

Reviewed by:	delphij, imp
Approved by:	imp (mentor)
Obtained from:	sha256.c update and skein_zfs.c stub from illumos.
Differential Revision:	https://reviews.freebsd.org/D7418
This commit is contained in:
Toomas Soome 2016-08-18 00:37:07 +00:00
parent d8a16c14cb
commit 2c55d0903d
19 changed files with 640 additions and 125 deletions

View file

@ -19,12 +19,16 @@ 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
CWARNFLAGS.skein.c += -Wno-missing-variable-declarations
.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
.PATH: ${.CURDIR}/../../../crypto/skein
.endif
CFLAGS+= -I.
@ -40,6 +44,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

View file

@ -24,6 +24,8 @@ SRCS= autoload.c \
.if ${MK_ZFS} != "no"
SRCS+= zfs.c
.PATH: ${.CURDIR}/../../zfs
SRCS+= skein.c skein_block.c
.PATH: ${.CURDIR}/../../../crypto/skein
# Disable warnings that are currently incompatible with the zfs boot code
CWARNFLAGS.zfs.c+= -Wno-sign-compare
@ -53,6 +55,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

View file

@ -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

View file

@ -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

View file

@ -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

View file

@ -2,7 +2,7 @@
.PATH: ${.CURDIR}/../boot2 ${.CURDIR}/../gptboot \
${.CURDIR}/../zfsboot ${.CURDIR}/../common \
${.CURDIR}/../../common
${.CURDIR}/../../common ${.CURDIR}/../../../crypto/skein
FILES= gptzfsboot
MAN= gptzfsboot.8
@ -27,13 +27,14 @@ 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-tentative-definition-incomplete-type -Wno-pointer-sign
.if !defined(LOADER_NO_GELI_SUPPORT)
CFLAGS+= -DLOADER_GELI_SUPPORT
@ -67,12 +68,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

View file

@ -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,9 +26,10 @@ 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
@ -55,12 +57,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 zfsboot.ld`; x=$$((${BOOT2SIZE}-$$5)); \
@ -77,7 +80,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

View file

@ -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;

View file

@ -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.

View file

@ -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

View file

@ -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}

View file

@ -2,15 +2,16 @@
S= ${.CURDIR}/../../zfs
.PATH: ${S}
.PATH: ${S} ${.CURDIR}/../../../crypto/skein
LIB= zfsboot
INTERNALLIB=
SRCS+= zfs.c
SRCS+= zfs.c skein.c skein_block.c
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

View file

@ -5,10 +5,14 @@ INTERNALLIB=
SRCS+= zfs.c
SRCS+= skein.c skein_block.c
.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

View file

@ -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
};
@ -78,6 +80,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)
@ -420,7 +425,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);
@ -1074,6 +1079,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);
@ -1122,7 +1128,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);
}
@ -1224,7 +1230,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);
}
@ -1364,12 +1371,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;
@ -1436,9 +1504,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);
}
@ -1449,7 +1518,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;
@ -1462,8 +1532,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);
}
@ -1802,7 +1874,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;
@ -1832,7 +1905,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);
}
@ -1962,9 +2036,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;
@ -1973,7 +2047,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);
@ -2047,7 +2121,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)
return (rc);
if ((rc = objset_get_dnode(spa, &spa->spa_mos, objnum, &dir)) != 0)
@ -2072,6 +2147,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)) {
@ -2083,6 +2159,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);
@ -2173,7 +2260,7 @@ zfs_lookup(const struct zfsmount *mount, const char *upath, dnode_phys_t *dnode)
if (rc)
return (rc);
rc = zap_lookup(spa, &dn, ZFS_ROOT_OBJ, &rootnum);
rc = zap_lookup(spa, &dn, ZFS_ROOT_OBJ, sizeof (rootnum), 1, &rootnum);
if (rc)
return (rc);
@ -2205,7 +2292,7 @@ zfs_lookup(const struct zfsmount *mount, const char *upath, dnode_phys_t *dnode)
return (ENOTDIR);
parentnum = objnum;
rc = zap_lookup(spa, &dn, element, &objnum);
rc = zap_lookup(spa, &dn, element, sizeof (objnum), 1, &objnum);
if (rc)
return (rc);
objnum = ZFS_DIRENT_OBJ(objnum);

View file

@ -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));

View file

@ -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)
{
uint32_t H[8] = { 0x6a09e667, 0xbb67ae85, 0x3c6ef372, 0xa54ff53a,
0x510e527f, 0x9b05688c, 0x1f83d9ab, 0x5be0cd19 };
uint8_t pad[128];
int padsize = size & 63;
int i;
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)
{
uint8_t pad[128];
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]);
}

View file

@ -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);
}

View file

@ -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)
/*
@ -149,6 +147,14 @@ typedef struct zio_cksum {
uint64_t zc_word[4];
} 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
};
@ -1157,6 +1167,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
@ -1462,6 +1473,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,
@ -1484,6 +1496,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;
/*
@ -1499,6 +1512,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;

View file

@ -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,8 +224,48 @@ 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;
@ -204,7 +282,8 @@ 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) {
zio_checksum_template_init(checksum, (spa_t *) spa);
if (ci->ci_flags & ZCHECKSUM_FLAG_EMBEDDED) {
zio_eck_t *eck;
ASSERT(checksum == ZIO_CHECKSUM_GANG_HEADER ||
@ -227,7 +306,8 @@ 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,
spa->spa_cksum_tmpls[checksum], &actual_cksum);
eck->zec_cksum = expected_cksum;
if (byteswap)
@ -235,11 +315,12 @@ 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, spa->spa_cksum_tmpls[checksum],
&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 +1330,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 +1382,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 +1462,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 +1633,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 +1678,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 +1752,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