Index: sys/boot/efi/boot1/Makefile =================================================================== --- sys/boot/efi/boot1/Makefile +++ sys/boot/efi/boot1/Makefile @@ -19,12 +19,16 @@ 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 @@ .if ${MK_ZFS} != "no" CFLAGS+= -I${.CURDIR}/../../zfs/ CFLAGS+= -I${.CURDIR}/../../../cddl/boot/zfs/ +CFLAGS+= -I${.CURDIR}/../../../crypto/skein CFLAGS+= -DEFI_ZFS_BOOT .endif Index: sys/boot/efi/loader/Makefile =================================================================== --- sys/boot/efi/loader/Makefile +++ sys/boot/efi/loader/Makefile @@ -24,6 +24,8 @@ .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 @@ .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 Index: sys/boot/i386/boot2/Makefile =================================================================== --- sys/boot/i386/boot2/Makefile +++ sys/boot/i386/boot2/Makefile @@ -33,7 +33,7 @@ -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 Index: sys/boot/i386/gptboot/Makefile =================================================================== --- sys/boot/i386/gptboot/Makefile +++ sys/boot/i386/gptboot/Makefile @@ -32,10 +32,10 @@ -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 Index: sys/boot/i386/gptboot/gptldr.S =================================================================== --- sys/boot/i386/gptboot/gptldr.S +++ 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 Index: sys/boot/i386/gptzfsboot/Makefile =================================================================== --- sys/boot/i386/gptzfsboot/Makefile +++ sys/boot/i386/gptzfsboot/Makefile @@ -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 @@ -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 @@ ${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 Index: sys/boot/i386/zfsboot/Makefile =================================================================== --- sys/boot/i386/zfsboot/Makefile +++ 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,9 +26,10 @@ -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 @@ ${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.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 Index: sys/boot/i386/zfsboot/zfsboot.c =================================================================== --- sys/boot/i386/zfsboot/zfsboot.c +++ sys/boot/i386/zfsboot/zfsboot.c @@ -105,7 +105,7 @@ /* * 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; Index: sys/boot/i386/zfsboot/zfsldr.S =================================================================== --- sys/boot/i386/zfsboot/zfsldr.S +++ 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 @@ /* * 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 @@ 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. Index: sys/boot/userboot/ficl/Makefile =================================================================== --- sys/boot/userboot/ficl/Makefile +++ sys/boot/userboot/ficl/Makefile @@ -10,6 +10,9 @@ 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 Index: sys/boot/userboot/userboot/Makefile =================================================================== --- sys/boot/userboot/userboot/Makefile +++ sys/boot/userboot/userboot/Makefile @@ -35,6 +35,8 @@ CFLAGS+= -I${.CURDIR}/../../../../lib/libstand CFLAGS+= -ffreestanding -I. +CWARNFLAGS.main.c += -Wno-implicit-function-declaration + LDFLAGS+= -nostdlib -Wl,-Bsymbolic NEWVERSWHAT= "User boot" ${MACHINE_CPUARCH} Index: sys/boot/userboot/zfs/Makefile =================================================================== --- sys/boot/userboot/zfs/Makefile +++ sys/boot/userboot/zfs/Makefile @@ -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 Index: sys/boot/zfs/Makefile =================================================================== --- sys/boot/zfs/Makefile +++ sys/boot/zfs/Makefile @@ -5,10 +5,14 @@ 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 Index: sys/boot/zfs/zfsimpl.c =================================================================== --- sys/boot/zfs/zfsimpl.c +++ sys/boot/zfs/zfsimpl.c @@ -58,6 +58,8 @@ "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 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 @@ 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 @@ } zfs_free(upbuf, VDEV_UBERBLOCK_SIZE(vdev)); + vdev->spa = spa; if (spap) *spap = spa; return (0); @@ -1122,7 +1128,7 @@ 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 @@ 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 @@ 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 @@ 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 @@ * 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_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 @@ 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 @@ 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 @@ /* * 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 @@ /* * 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 @@ 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 @@ 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 @@ 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 @@ 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 @@ 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); Index: sys/cddl/boot/zfs/fletcher.c =================================================================== --- sys/cddl/boot/zfs/fletcher.c +++ 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 @@ } 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 @@ } 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 @@ } 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)); Index: sys/cddl/boot/zfs/sha256.c =================================================================== --- sys/cddl/boot/zfs/sha256.c +++ 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 + */ /* - * 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 @@ 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 @@ (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]); +} Index: sys/cddl/boot/zfs/skein_zfs.c =================================================================== --- /dev/null +++ sys/cddl/boot/zfs/skein_zfs.c @@ -0,0 +1,90 @@ +/* + * CDDL HEADER START + * + * The contents of this file are subject to the terms of the + * Common Development and Distribution License (the "License"). + * You may not use this file except in compliance with the License. + * + * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE + * or http://opensource.org/licenses/CDDL-1.0. + * See the License for the specific language governing permissions + * and limitations under the License. + * + * When distributing Covered Code, include this CDDL HEADER in each + * file and include the License file at usr/src/OPENSOLARIS.LICENSE. + * If applicable, add the following below this CDDL HEADER, with the + * fields enclosed by brackets "[]" replaced with your own identifying + * information: Portions Copyright [yyyy] [name of copyright owner] + * + * CDDL HEADER END + */ +/* + * Copyright 2013 Saso Kiselkov. All rights reserved. + */ +#include + +/* + * 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); +} Index: sys/cddl/boot/zfs/zfsimpl.h =================================================================== --- sys/cddl/boot/zfs/zfsimpl.h +++ sys/cddl/boot/zfs/zfsimpl.h @@ -114,13 +114,11 @@ #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 @@ } 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 @@ 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 @@ #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 @@ * 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 @@ 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 @@ 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; Index: sys/cddl/boot/zfs/zfssubr.c =================================================================== --- sys/cddl/boot/zfs/zfssubr.c +++ sys/cddl/boot/zfs/zfssubr.c @@ -63,7 +63,8 @@ } 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 @@ /* * 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_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 @@ 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 @@ 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 @@ 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 @@ * 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 @@ * 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 @@ * 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 @@ */ 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 @@ 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 @@ 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