From 45818ee124adeaaf947698996b4f4c722afc6d1f Mon Sep 17 00:00:00 2001 From: Matthew Ahrens Date: Sat, 22 Aug 2015 09:14:41 -0700 Subject: 4185 add new cryptographic checksums to ZFS: SHA-512, Skein, Edon-R Reviewed by: George Wilson Reviewed by: Prakash Surya Reviewed by: Saso Kiselkov Reviewed by: Richard Lowe Approved by: Garrett D'Amore --- usr/src/uts/common/Makefile.files | 6 + usr/src/uts/common/Makefile.rules | 15 + usr/src/uts/common/crypto/io/edonr_mod.c | 63 ++ usr/src/uts/common/crypto/io/skein_mod.c | 830 +++++++++++++++++++++++++++ usr/src/uts/common/fs/zfs/arc.c | 6 +- usr/src/uts/common/fs/zfs/ddt.c | 5 +- usr/src/uts/common/fs/zfs/dmu.c | 24 +- usr/src/uts/common/fs/zfs/dmu_send.c | 3 +- usr/src/uts/common/fs/zfs/dsl_dataset.c | 8 + usr/src/uts/common/fs/zfs/edonr_zfs.c | 102 ++++ usr/src/uts/common/fs/zfs/sha256.c | 33 +- usr/src/uts/common/fs/zfs/skein_zfs.c | 91 +++ usr/src/uts/common/fs/zfs/spa.c | 34 ++ usr/src/uts/common/fs/zfs/spa_misc.c | 7 +- usr/src/uts/common/fs/zfs/sys/dmu.h | 2 + usr/src/uts/common/fs/zfs/sys/spa.h | 9 + usr/src/uts/common/fs/zfs/sys/spa_impl.h | 5 + usr/src/uts/common/fs/zfs/sys/zio.h | 3 + usr/src/uts/common/fs/zfs/sys/zio_checksum.h | 51 +- usr/src/uts/common/fs/zfs/zfs_ioctl.c | 45 +- usr/src/uts/common/fs/zfs/zio.c | 37 +- usr/src/uts/common/fs/zfs/zio_checksum.c | 161 +++++- usr/src/uts/common/sys/Makefile | 3 + usr/src/uts/common/sys/crypto/common.h | 5 + usr/src/uts/common/sys/debug.h | 9 + usr/src/uts/common/sys/edonr.h | 93 +++ usr/src/uts/common/sys/sha2.h | 11 +- usr/src/uts/common/sys/skein.h | 178 ++++++ usr/src/uts/intel/Makefile.intel | 2 + usr/src/uts/intel/edonr/Makefile | 92 +++ usr/src/uts/intel/skein/Makefile | 92 +++ usr/src/uts/intel/zfs/Makefile | 6 +- usr/src/uts/sparc/Makefile.sparc | 4 +- usr/src/uts/sparc/edonr/Makefile | 92 +++ usr/src/uts/sparc/skein/Makefile | 92 +++ usr/src/uts/sparc/zfs/Makefile | 5 +- 36 files changed, 2159 insertions(+), 65 deletions(-) create mode 100644 usr/src/uts/common/crypto/io/edonr_mod.c create mode 100644 usr/src/uts/common/crypto/io/skein_mod.c create mode 100644 usr/src/uts/common/fs/zfs/edonr_zfs.c create mode 100644 usr/src/uts/common/fs/zfs/skein_zfs.c create mode 100644 usr/src/uts/common/sys/edonr.h create mode 100644 usr/src/uts/common/sys/skein.h create mode 100644 usr/src/uts/intel/edonr/Makefile create mode 100644 usr/src/uts/intel/skein/Makefile create mode 100644 usr/src/uts/sparc/edonr/Makefile create mode 100644 usr/src/uts/sparc/skein/Makefile (limited to 'usr/src/uts') diff --git a/usr/src/uts/common/Makefile.files b/usr/src/uts/common/Makefile.files index d9d0bfa6fd..6bb8f4ad00 100644 --- a/usr/src/uts/common/Makefile.files +++ b/usr/src/uts/common/Makefile.files @@ -509,6 +509,10 @@ SHA1_OBJS += sha1.o sha1_mod.o SHA2_OBJS += sha2.o sha2_mod.o +SKEIN_OBJS += skein.o skein_block.o skein_iv.o skein_mod.o + +EDONR_OBJS += edonr.o edonr_mod.o + IPGPC_OBJS += classifierddi.o classifier.o filters.o trie.o table.o \ ba_table.o @@ -1367,6 +1371,8 @@ ZFS_COMMON_OBJS += \ rrwlock.o \ sa.o \ sha256.o \ + edonr_zfs.o \ + skein_zfs.o \ spa.o \ spa_config.o \ spa_errlog.o \ diff --git a/usr/src/uts/common/Makefile.rules b/usr/src/uts/common/Makefile.rules index cf2e880c5e..94d236a560 100644 --- a/usr/src/uts/common/Makefile.rules +++ b/usr/src/uts/common/Makefile.rules @@ -23,6 +23,7 @@ # Copyright (c) 1991, 2010, Oracle and/or its affiliates. All rights reserved. # Copyright 2013 Garrett D'Amore # Copyright 2015 Nexenta Systems, Inc. All rights reserved. +# Copyright 2013 Saso Kiselkov. All rights reserved. # # @@ -1532,6 +1533,10 @@ $(OBJS_DIR)/%.o: $(UTSBASE)/common/rpc/sec_gss/%.c $(COMPILE.c) -o $@ $< $(CTFCONVERT_O) +$(OBJS_DIR)/%.o: $(COMMONBASE)/crypto/edonr/%.c + $(COMPILE.c) -o $@ $< + $(CTFCONVERT_O) + $(OBJS_DIR)/%.o: $(COMMONBASE)/crypto/sha1/%.c $(COMPILE.c) -o $@ $< $(CTFCONVERT_O) @@ -1540,6 +1545,10 @@ $(OBJS_DIR)/%.o: $(COMMONBASE)/crypto/sha2/%.c $(COMPILE.c) -o $@ $< $(CTFCONVERT_O) +$(OBJS_DIR)/%.o: $(COMMONBASE)/crypto/skein/%.c + $(COMPILE.c) -o $@ $< + $(CTFCONVERT_O) + $(OBJS_DIR)/%.o: $(UTSBASE)/common/syscall/%.c $(COMPILE.c) -o $@ $< $(CTFCONVERT_O) @@ -2667,12 +2676,18 @@ $(LINTS_DIR)/%.ln: $(UTSBASE)/common/rpc/sec/%.c $(LINTS_DIR)/%.ln: $(UTSBASE)/common/rpc/sec_gss/%.c @($(LHEAD) $(LINT.c) $< $(LTAIL)) +$(LINTS_DIR)/%.ln: $(COMMONBASE)/crypto/edonr/%.c + @($(LHEAD) $(LINT.c) $< $(LTAIL)) + $(LINTS_DIR)/%.ln: $(COMMONBASE)/crypto/sha1/%.c @($(LHEAD) $(LINT.c) $< $(LTAIL)) $(LINTS_DIR)/%.ln: $(COMMONBASE)/crypto/sha2/%.c @($(LHEAD) $(LINT.c) $< $(LTAIL)) +$(LINTS_DIR)/%.ln: $(COMMONBASE)/crypto/skein/%.c + @($(LHEAD) $(LINT.c) $< $(LTAIL)) + $(LINTS_DIR)/%.ln: $(UTSBASE)/common/syscall/%.c @($(LHEAD) $(LINT.c) $< $(LTAIL)) diff --git a/usr/src/uts/common/crypto/io/edonr_mod.c b/usr/src/uts/common/crypto/io/edonr_mod.c new file mode 100644 index 0000000000..d17bbe9900 --- /dev/null +++ b/usr/src/uts/common/crypto/io/edonr_mod.c @@ -0,0 +1,63 @@ +/* + * 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 +#include +#include +#include +#include +#include + +/* + * Unlike sha2 or skein, we won't expose edonr via the Kernel Cryptographic + * Framework (KCF), because Edon-R is *NOT* suitable for general-purpose + * cryptographic use. Users of Edon-R must interface directly to this module. + */ + +static struct modlmisc modlmisc = { + &mod_miscops, + "Edon-R Message-Digest Algorithm" +}; + +static struct modlinkage modlinkage = { + MODREV_1, &modlmisc, NULL +}; + +int +_init(void) +{ + int error; + + if ((error = mod_install(&modlinkage)) != 0) + return (error); + + return (0); +} + +int +_info(struct modinfo *modinfop) +{ + return (mod_info(&modlinkage, modinfop)); +} diff --git a/usr/src/uts/common/crypto/io/skein_mod.c b/usr/src/uts/common/crypto/io/skein_mod.c new file mode 100644 index 0000000000..aca7582dcb --- /dev/null +++ b/usr/src/uts/common/crypto/io/skein_mod.c @@ -0,0 +1,830 @@ +/* + * 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 +#include +#include +#include +#include +#include +#define SKEIN_MODULE_IMPL +#include + +/* + * Like the sha2 module, we create the skein module with two modlinkages: + * - modlmisc to allow direct calls to Skein_* API functions. + * - modlcrypto to integrate well into the Kernel Crypto Framework (KCF). + */ +static struct modlmisc modlmisc = { + &mod_miscops, + "Skein Message-Digest Algorithm" +}; + +static struct modlcrypto modlcrypto = { + &mod_cryptoops, + "Skein Kernel SW Provider" +}; + +static struct modlinkage modlinkage = { + MODREV_1, &modlmisc, &modlcrypto, NULL +}; + +static crypto_mech_info_t skein_mech_info_tab[] = { + {CKM_SKEIN_256, SKEIN_256_MECH_INFO_TYPE, + CRYPTO_FG_DIGEST | CRYPTO_FG_DIGEST_ATOMIC, + 0, 0, CRYPTO_KEYSIZE_UNIT_IN_BITS}, + {CKM_SKEIN_256_MAC, SKEIN_256_MAC_MECH_INFO_TYPE, + CRYPTO_FG_MAC | CRYPTO_FG_MAC_ATOMIC, 1, INT_MAX, + CRYPTO_KEYSIZE_UNIT_IN_BYTES}, + {CKM_SKEIN_512, SKEIN_512_MECH_INFO_TYPE, + CRYPTO_FG_DIGEST | CRYPTO_FG_DIGEST_ATOMIC, + 0, 0, CRYPTO_KEYSIZE_UNIT_IN_BITS}, + {CKM_SKEIN_512_MAC, SKEIN_512_MAC_MECH_INFO_TYPE, + CRYPTO_FG_MAC | CRYPTO_FG_MAC_ATOMIC, 1, INT_MAX, + CRYPTO_KEYSIZE_UNIT_IN_BYTES}, + {CKM_SKEIN1024, SKEIN1024_MECH_INFO_TYPE, + CRYPTO_FG_DIGEST | CRYPTO_FG_DIGEST_ATOMIC, + 0, 0, CRYPTO_KEYSIZE_UNIT_IN_BITS}, + {CKM_SKEIN1024_MAC, SKEIN1024_MAC_MECH_INFO_TYPE, + CRYPTO_FG_MAC | CRYPTO_FG_MAC_ATOMIC, 1, INT_MAX, + CRYPTO_KEYSIZE_UNIT_IN_BYTES} +}; + +static void skein_provider_status(crypto_provider_handle_t, uint_t *); + +static crypto_control_ops_t skein_control_ops = { + skein_provider_status +}; + +static int skein_digest_init(crypto_ctx_t *, crypto_mechanism_t *, + crypto_req_handle_t); +static int skein_digest(crypto_ctx_t *, crypto_data_t *, crypto_data_t *, + crypto_req_handle_t); +static int skein_update(crypto_ctx_t *, crypto_data_t *, crypto_req_handle_t); +static int skein_final(crypto_ctx_t *, crypto_data_t *, crypto_req_handle_t); +static int skein_digest_atomic(crypto_provider_handle_t, crypto_session_id_t, + crypto_mechanism_t *, crypto_data_t *, crypto_data_t *, + crypto_req_handle_t); + +static crypto_digest_ops_t skein_digest_ops = { + skein_digest_init, + skein_digest, + skein_update, + NULL, + skein_final, + skein_digest_atomic +}; + +static int skein_mac_init(crypto_ctx_t *, crypto_mechanism_t *, crypto_key_t *, + crypto_spi_ctx_template_t, crypto_req_handle_t); +static int skein_mac_atomic(crypto_provider_handle_t, crypto_session_id_t, + crypto_mechanism_t *, crypto_key_t *, crypto_data_t *, crypto_data_t *, + crypto_spi_ctx_template_t, crypto_req_handle_t); + +static crypto_mac_ops_t skein_mac_ops = { + skein_mac_init, + NULL, + skein_update, /* using regular digest update is OK here */ + skein_final, /* using regular digest final is OK here */ + skein_mac_atomic, + NULL +}; + +static int skein_create_ctx_template(crypto_provider_handle_t, + crypto_mechanism_t *, crypto_key_t *, crypto_spi_ctx_template_t *, + size_t *, crypto_req_handle_t); +static int skein_free_context(crypto_ctx_t *); + +static crypto_ctx_ops_t skein_ctx_ops = { + skein_create_ctx_template, + skein_free_context +}; + +static crypto_ops_t skein_crypto_ops = { + &skein_control_ops, + &skein_digest_ops, + NULL, + &skein_mac_ops, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + &skein_ctx_ops, + NULL, + NULL, + NULL +}; + +static crypto_provider_info_t skein_prov_info = { + CRYPTO_SPI_VERSION_4, + "Skein Software Provider", + CRYPTO_SW_PROVIDER, + {&modlinkage}, + NULL, + &skein_crypto_ops, + sizeof (skein_mech_info_tab) / sizeof (crypto_mech_info_t), + skein_mech_info_tab +}; + +static crypto_kcf_provider_handle_t skein_prov_handle = NULL; + +typedef struct skein_ctx { + skein_mech_type_t sc_mech_type; + size_t sc_digest_bitlen; + /*LINTED(E_ANONYMOUS_UNION_DECL)*/ + union { + Skein_256_Ctxt_t sc_256; + Skein_512_Ctxt_t sc_512; + Skein1024_Ctxt_t sc_1024; + }; +} skein_ctx_t; +#define SKEIN_CTX(_ctx_) ((skein_ctx_t *)((_ctx_)->cc_provider_private)) +#define SKEIN_CTX_LVALUE(_ctx_) (_ctx_)->cc_provider_private +#define SKEIN_OP(_skein_ctx, _op, ...) \ + do { \ + skein_ctx_t *sc = (_skein_ctx); \ + switch (sc->sc_mech_type) { \ + case SKEIN_256_MECH_INFO_TYPE: \ + case SKEIN_256_MAC_MECH_INFO_TYPE: \ + (void) Skein_256_ ## _op(&sc->sc_256, __VA_ARGS__);\ + break; \ + case SKEIN_512_MECH_INFO_TYPE: \ + case SKEIN_512_MAC_MECH_INFO_TYPE: \ + (void) Skein_512_ ## _op(&sc->sc_512, __VA_ARGS__);\ + break; \ + case SKEIN1024_MECH_INFO_TYPE: \ + case SKEIN1024_MAC_MECH_INFO_TYPE: \ + (void) Skein1024_ ## _op(&sc->sc_1024, __VA_ARGS__);\ + break; \ + } \ + _NOTE(CONSTCOND) \ + } while (0) + +static int +skein_get_digest_bitlen(const crypto_mechanism_t *mechanism, size_t *result) +{ + if (mechanism->cm_param != NULL) { + /*LINTED(E_BAD_PTR_CAST_ALIGN)*/ + skein_param_t *param = (skein_param_t *)mechanism->cm_param; + + if (mechanism->cm_param_len != sizeof (*param) || + param->sp_digest_bitlen == 0) { + return (CRYPTO_MECHANISM_PARAM_INVALID); + } + *result = param->sp_digest_bitlen; + } else { + switch (mechanism->cm_type) { + case SKEIN_256_MECH_INFO_TYPE: + *result = 256; + break; + case SKEIN_512_MECH_INFO_TYPE: + *result = 512; + break; + case SKEIN1024_MECH_INFO_TYPE: + *result = 1024; + break; + default: + return (CRYPTO_MECHANISM_INVALID); + } + } + return (CRYPTO_SUCCESS); +} + +int +_init(void) +{ + int error; + + if ((error = mod_install(&modlinkage)) != 0) + return (error); + + /* + * Try to register with KCF - failure shouldn't unload us, since we + * still may want to continue providing misc/skein functionality. + */ + (void) crypto_register_provider(&skein_prov_info, &skein_prov_handle); + + return (0); +} + +int +_info(struct modinfo *modinfop) +{ + return (mod_info(&modlinkage, modinfop)); +} + +/* + * KCF software provider control entry points. + */ +/* ARGSUSED */ +static void +skein_provider_status(crypto_provider_handle_t provider, uint_t *status) +{ + *status = CRYPTO_PROVIDER_READY; +} + +/* + * General Skein hashing helper functions. + */ + +/* + * Performs an Update on a context with uio input data. + */ +static int +skein_digest_update_uio(skein_ctx_t *ctx, const crypto_data_t *data) +{ + off_t offset = data->cd_offset; + size_t length = data->cd_length; + uint_t vec_idx; + size_t cur_len; + const uio_t *uio = data->cd_uio; + + /* we support only kernel buffer */ + if (uio->uio_segflg != UIO_SYSSPACE) + return (CRYPTO_ARGUMENTS_BAD); + + /* + * Jump to the first iovec containing data to be + * digested. + */ + for (vec_idx = 0; vec_idx < uio->uio_iovcnt && + offset >= uio->uio_iov[vec_idx].iov_len; + offset -= uio->uio_iov[vec_idx++].iov_len) + ; + if (vec_idx == uio->uio_iovcnt) { + /* + * The caller specified an offset that is larger than the + * total size of the buffers it provided. + */ + return (CRYPTO_DATA_LEN_RANGE); + } + + /* + * Now do the digesting on the iovecs. + */ + while (vec_idx < uio->uio_iovcnt && length > 0) { + cur_len = MIN(uio->uio_iov[vec_idx].iov_len - offset, length); + SKEIN_OP(ctx, Update, (uint8_t *)uio->uio_iov[vec_idx].iov_base + + offset, cur_len); + length -= cur_len; + vec_idx++; + offset = 0; + } + + if (vec_idx == uio->uio_iovcnt && length > 0) { + /* + * The end of the specified iovec's was reached but + * the length requested could not be processed, i.e. + * The caller requested to digest more data than it provided. + */ + return (CRYPTO_DATA_LEN_RANGE); + } + + return (CRYPTO_SUCCESS); +} + +/* + * Performs a Final on a context and writes to a uio digest output. + */ +static int +skein_digest_final_uio(skein_ctx_t *ctx, crypto_data_t *digest, + crypto_req_handle_t req) +{ + off_t offset = digest->cd_offset; + uint_t vec_idx; + uio_t *uio = digest->cd_uio; + + /* we support only kernel buffer */ + if (uio->uio_segflg != UIO_SYSSPACE) + return (CRYPTO_ARGUMENTS_BAD); + + /* + * Jump to the first iovec containing ptr to the digest to be returned. + */ + for (vec_idx = 0; offset >= uio->uio_iov[vec_idx].iov_len && + vec_idx < uio->uio_iovcnt; + offset -= uio->uio_iov[vec_idx++].iov_len) + ; + if (vec_idx == uio->uio_iovcnt) { + /* + * The caller specified an offset that is larger than the + * total size of the buffers it provided. + */ + return (CRYPTO_DATA_LEN_RANGE); + } + if (offset + CRYPTO_BITS2BYTES(ctx->sc_digest_bitlen) <= + uio->uio_iov[vec_idx].iov_len) { + /* The computed digest will fit in the current iovec. */ + SKEIN_OP(ctx, Final, + (uchar_t *)uio->uio_iov[vec_idx].iov_base + offset); + } else { + uint8_t *digest_tmp; + off_t scratch_offset = 0; + size_t length = CRYPTO_BITS2BYTES(ctx->sc_digest_bitlen); + size_t cur_len; + + digest_tmp = kmem_alloc(CRYPTO_BITS2BYTES( + ctx->sc_digest_bitlen), crypto_kmflag(req)); + if (digest_tmp == NULL) + return (CRYPTO_HOST_MEMORY); + SKEIN_OP(ctx, Final, digest_tmp); + while (vec_idx < uio->uio_iovcnt && length > 0) { + cur_len = MIN(uio->uio_iov[vec_idx].iov_len - offset, + length); + bcopy(digest_tmp + scratch_offset, + uio->uio_iov[vec_idx].iov_base + offset, cur_len); + + length -= cur_len; + vec_idx++; + scratch_offset += cur_len; + offset = 0; + } + kmem_free(digest_tmp, CRYPTO_BITS2BYTES(ctx->sc_digest_bitlen)); + + if (vec_idx == uio->uio_iovcnt && length > 0) { + /* + * The end of the specified iovec's was reached but + * the length requested could not be processed, i.e. + * The caller requested to digest more data than it + * provided. + */ + return (CRYPTO_DATA_LEN_RANGE); + } + } + + return (CRYPTO_SUCCESS); +} + +/* + * Performs an Update on a context with mblk input data. + */ +static int +skein_digest_update_mblk(skein_ctx_t *ctx, crypto_data_t *data) +{ + off_t offset = data->cd_offset; + size_t length = data->cd_length; + mblk_t *mp; + size_t cur_len; + + /* Jump to the first mblk_t containing data to be digested. */ + for (mp = data->cd_mp; mp != NULL && offset >= MBLKL(mp); + offset -= MBLKL(mp), mp = mp->b_cont) + ; + if (mp == NULL) { + /* + * The caller specified an offset that is larger than the + * total size of the buffers it provided. + */ + return (CRYPTO_DATA_LEN_RANGE); + } + + /* Now do the digesting on the mblk chain. */ + while (mp != NULL && length > 0) { + cur_len = MIN(MBLKL(mp) - offset, length); + SKEIN_OP(ctx, Update, mp->b_rptr + offset, cur_len); + length -= cur_len; + offset = 0; + mp = mp->b_cont; + } + + if (mp == NULL && length > 0) { + /* + * The end of the mblk was reached but the length requested + * could not be processed, i.e. The caller requested + * to digest more data than it provided. + */ + return (CRYPTO_DATA_LEN_RANGE); + } + + return (CRYPTO_SUCCESS); +} + +/* + * Performs a Final on a context and writes to an mblk digest output. + */ +static int +skein_digest_final_mblk(skein_ctx_t *ctx, crypto_data_t *digest, + crypto_req_handle_t req) +{ + off_t offset = digest->cd_offset; + mblk_t *mp; + + /* Jump to the first mblk_t that will be used to store the digest. */ + for (mp = digest->cd_mp; mp != NULL && offset >= MBLKL(mp); + offset -= MBLKL(mp), mp = mp->b_cont) + ; + if (mp == NULL) { + /* caller specified offset is too large */ + return (CRYPTO_DATA_LEN_RANGE); + } + + if (offset + CRYPTO_BITS2BYTES(ctx->sc_digest_bitlen) <= MBLKL(mp)) { + /* The digest will fit in the current mblk. */ + SKEIN_OP(ctx, Final, mp->b_rptr + offset); + } else { + /* Split the digest up between the individual buffers. */ + uint8_t *digest_tmp; + off_t scratch_offset = 0; + size_t length = CRYPTO_BITS2BYTES(ctx->sc_digest_bitlen); + size_t cur_len; + + digest_tmp = kmem_alloc(CRYPTO_BITS2BYTES( + ctx->sc_digest_bitlen), crypto_kmflag(req)); + if (digest_tmp == NULL) + return (CRYPTO_HOST_MEMORY); + SKEIN_OP(ctx, Final, digest_tmp); + while (mp != NULL && length > 0) { + cur_len = MIN(MBLKL(mp) - offset, length); + bcopy(digest_tmp + scratch_offset, + mp->b_rptr + offset, cur_len); + length -= cur_len; + mp = mp->b_cont; + scratch_offset += cur_len; + offset = 0; + } + kmem_free(digest_tmp, CRYPTO_BITS2BYTES(ctx->sc_digest_bitlen)); + if (mp == NULL && length > 0) { + /* digest too long to fit in the mblk buffers */ + return (CRYPTO_DATA_LEN_RANGE); + } + } + + return (CRYPTO_SUCCESS); +} + +/* + * KCF software provider digest entry points. + */ + +/* + * Initializes a skein digest context to the configuration in `mechanism'. + * The mechanism cm_type must be one of SKEIN_*_MECH_INFO_TYPE. The cm_param + * field may contain a skein_param_t structure indicating the length of the + * digest the algorithm should produce. Otherwise the default output lengths + * are applied (32 bytes for Skein-256, 64 bytes for Skein-512 and 128 bytes + * for Skein-1024). + */ +static int +skein_digest_init(crypto_ctx_t *ctx, crypto_mechanism_t *mechanism, + crypto_req_handle_t req) +{ + int error = CRYPTO_SUCCESS; + + if (!VALID_SKEIN_DIGEST_MECH(mechanism->cm_type)) + return (CRYPTO_MECHANISM_INVALID); + + SKEIN_CTX_LVALUE(ctx) = kmem_alloc(sizeof (*SKEIN_CTX(ctx)), + crypto_kmflag(req)); + if (SKEIN_CTX(ctx) == NULL) + return (CRYPTO_HOST_MEMORY); + + SKEIN_CTX(ctx)->sc_mech_type = mechanism->cm_type; + error = skein_get_digest_bitlen(mechanism, + &SKEIN_CTX(ctx)->sc_digest_bitlen); + if (error != CRYPTO_SUCCESS) + goto errout; + SKEIN_OP(SKEIN_CTX(ctx), Init, SKEIN_CTX(ctx)->sc_digest_bitlen); + + return (CRYPTO_SUCCESS); +errout: + bzero(SKEIN_CTX(ctx), sizeof (*SKEIN_CTX(ctx))); + kmem_free(SKEIN_CTX(ctx), sizeof (*SKEIN_CTX(ctx))); + SKEIN_CTX_LVALUE(ctx) = NULL; + return (error); +} + +/* + * Executes a skein_update and skein_digest on a pre-initialized crypto + * context in a single step. See the documentation to these functions to + * see what to pass here. + */ +static int +skein_digest(crypto_ctx_t *ctx, crypto_data_t *data, crypto_data_t *digest, + crypto_req_handle_t req) +{ + int error = CRYPTO_SUCCESS; + + ASSERT(SKEIN_CTX(ctx) != NULL); + + if (digest->cd_length < + CRYPTO_BITS2BYTES(SKEIN_CTX(ctx)->sc_digest_bitlen)) { + digest->cd_length = + CRYPTO_BITS2BYTES(SKEIN_CTX(ctx)->sc_digest_bitlen); + return (CRYPTO_BUFFER_TOO_SMALL); + } + + error = skein_update(ctx, data, req); + if (error != CRYPTO_SUCCESS) { + bzero(SKEIN_CTX(ctx), sizeof (*SKEIN_CTX(ctx))); + kmem_free(SKEIN_CTX(ctx), sizeof (*SKEIN_CTX(ctx))); + SKEIN_CTX_LVALUE(ctx) = NULL; + digest->cd_length = 0; + return (error); + } + error = skein_final(ctx, digest, req); + + return (error); +} + +/* + * Performs a skein Update with the input message in `data' (successive calls + * can push more data). This is used both for digest and MAC operation. + * Supported input data formats are raw, uio and mblk. + */ +/*ARGSUSED*/ +static int +skein_update(crypto_ctx_t *ctx, crypto_data_t *data, crypto_req_handle_t req) +{ + int error = CRYPTO_SUCCESS; + + ASSERT(SKEIN_CTX(ctx) != NULL); + + switch (data->cd_format) { + case CRYPTO_DATA_RAW: + SKEIN_OP(SKEIN_CTX(ctx), Update, + (uint8_t *)data->cd_raw.iov_base + data->cd_offset, + data->cd_length); + break; + case CRYPTO_DATA_UIO: + error = skein_digest_update_uio(SKEIN_CTX(ctx), data); + break; + case CRYPTO_DATA_MBLK: + error = skein_digest_update_mblk(SKEIN_CTX(ctx), data); + break; + default: + error = CRYPTO_ARGUMENTS_BAD; + } + + return (error); +} + +/* + * Performs a skein Final, writing the output to `digest'. This is used both + * for digest and MAC operation. + * Supported output digest formats are raw, uio and mblk. + */ +/*ARGSUSED*/ +static int +skein_final(crypto_ctx_t *ctx, crypto_data_t *digest, crypto_req_handle_t req) +{ + int error = CRYPTO_SUCCESS; + + ASSERT(SKEIN_CTX(ctx) != NULL); + + if (digest->cd_length < + CRYPTO_BITS2BYTES(SKEIN_CTX(ctx)->sc_digest_bitlen)) { + digest->cd_length = + CRYPTO_BITS2BYTES(SKEIN_CTX(ctx)->sc_digest_bitlen); + return (CRYPTO_BUFFER_TOO_SMALL); + } + + switch (digest->cd_format) { + case CRYPTO_DATA_RAW: + SKEIN_OP(SKEIN_CTX(ctx), Final, + (uint8_t *)digest->cd_raw.iov_base + digest->cd_offset); + break; + case CRYPTO_DATA_UIO: + error = skein_digest_final_uio(SKEIN_CTX(ctx), digest, req); + break; + case CRYPTO_DATA_MBLK: + error = skein_digest_final_mblk(SKEIN_CTX(ctx), digest, req); + break; + default: + error = CRYPTO_ARGUMENTS_BAD; + } + + if (error == CRYPTO_SUCCESS) + digest->cd_length = + CRYPTO_BITS2BYTES(SKEIN_CTX(ctx)->sc_digest_bitlen); + else + digest->cd_length = 0; + + bzero(SKEIN_CTX(ctx), sizeof (*SKEIN_CTX(ctx))); + kmem_free(SKEIN_CTX(ctx), sizeof (*(SKEIN_CTX(ctx)))); + SKEIN_CTX_LVALUE(ctx) = NULL; + + return (error); +} + +/* + * Performs a full skein digest computation in a single call, configuring the + * algorithm according to `mechanism', reading the input to be digested from + * `data' and writing the output to `digest'. + * Supported input/output formats are raw, uio and mblk. + */ +/*ARGSUSED*/ +static int +skein_digest_atomic(crypto_provider_handle_t provider, + crypto_session_id_t session_id, crypto_mechanism_t *mechanism, + crypto_data_t *data, crypto_data_t *digest, crypto_req_handle_t req) +{ + int error; + skein_ctx_t skein_ctx; + crypto_ctx_t ctx; + SKEIN_CTX_LVALUE(&ctx) = &skein_ctx; + + /* Init */ + if (!VALID_SKEIN_DIGEST_MECH(mechanism->cm_type)) + return (CRYPTO_MECHANISM_INVALID); + skein_ctx.sc_mech_type = mechanism->cm_type; + error = skein_get_digest_bitlen(mechanism, &skein_ctx.sc_digest_bitlen); + if (error != CRYPTO_SUCCESS) + goto out; + SKEIN_OP(&skein_ctx, Init, skein_ctx.sc_digest_bitlen); + + if ((error = skein_update(&ctx, data, digest)) != CRYPTO_SUCCESS) + goto out; + if ((error = skein_final(&ctx, data, digest)) != CRYPTO_SUCCESS) + goto out; + +out: + if (error == CRYPTO_SUCCESS) + digest->cd_length = + CRYPTO_BITS2BYTES(skein_ctx.sc_digest_bitlen); + else + digest->cd_length = 0; + bzero(&skein_ctx, sizeof (skein_ctx)); + + return (error); +} + +/* + * Helper function that builds a Skein MAC context from the provided + * mechanism and key. + */ +static int +skein_mac_ctx_build(skein_ctx_t *ctx, crypto_mechanism_t *mechanism, + crypto_key_t *key) +{ + int error; + + if (!VALID_SKEIN_MAC_MECH(mechanism->cm_type)) + return (CRYPTO_MECHANISM_INVALID); + if (key->ck_format != CRYPTO_KEY_RAW) + return (CRYPTO_ARGUMENTS_BAD); + ctx->sc_mech_type = mechanism->cm_type; + error = skein_get_digest_bitlen(mechanism, &ctx->sc_digest_bitlen); + if (error != CRYPTO_SUCCESS) + return (error); + SKEIN_OP(ctx, InitExt, ctx->sc_digest_bitlen, 0, key->ck_data, + CRYPTO_BITS2BYTES(key->ck_length)); + + return (CRYPTO_SUCCESS); +} + +/* + * KCF software provide mac entry points. + */ +/* + * Initializes a skein MAC context. You may pass a ctx_template, in which + * case the template will be reused to make initialization more efficient. + * Otherwise a new context will be constructed. The mechanism cm_type must + * be one of SKEIN_*_MAC_MECH_INFO_TYPE. Same as in skein_digest_init, you + * may pass a skein_param_t in cm_param to configure the length of the + * digest. The key must be in raw format. + */ +static int +skein_mac_init(crypto_ctx_t *ctx, crypto_mechanism_t *mechanism, + crypto_key_t *key, crypto_spi_ctx_template_t ctx_template, + crypto_req_handle_t req) +{ + int error; + + SKEIN_CTX_LVALUE(ctx) = kmem_alloc(sizeof (*SKEIN_CTX(ctx)), + crypto_kmflag(req)); + if (SKEIN_CTX(ctx) == NULL) + return (CRYPTO_HOST_MEMORY); + + if (ctx_template != NULL) { + bcopy(ctx_template, SKEIN_CTX(ctx), + sizeof (*SKEIN_CTX(ctx))); + } else { + error = skein_mac_ctx_build(SKEIN_CTX(ctx), mechanism, key); + if (error != CRYPTO_SUCCESS) + goto errout; + } + + return (CRYPTO_SUCCESS); +errout: + bzero(SKEIN_CTX(ctx), sizeof (*SKEIN_CTX(ctx))); + kmem_free(SKEIN_CTX(ctx), sizeof (*SKEIN_CTX(ctx))); + return (error); +} + +/* + * The MAC update and final calls are reused from the regular digest code. + */ + +/*ARGSUSED*/ +/* + * Same as skein_digest_atomic, performs an atomic Skein MAC operation in + * one step. All the same properties apply to the arguments of this + * function as to those of the partial operations above. + */ +static int +skein_mac_atomic(crypto_provider_handle_t provider, + crypto_session_id_t session_id, crypto_mechanism_t *mechanism, + crypto_key_t *key, crypto_data_t *data, crypto_data_t *mac, + crypto_spi_ctx_template_t ctx_template, crypto_req_handle_t req) +{ + /* faux crypto context just for skein_digest_{update,final} */ + int error; + crypto_ctx_t ctx; + skein_ctx_t skein_ctx; + SKEIN_CTX_LVALUE(&ctx) = &skein_ctx; + + if (ctx_template != NULL) { + bcopy(ctx_template, &skein_ctx, sizeof (skein_ctx)); + } else { + error = skein_mac_ctx_build(&skein_ctx, mechanism, key); + if (error != CRYPTO_SUCCESS) + goto errout; + } + + if ((error = skein_update(&ctx, data, req)) != CRYPTO_SUCCESS) + goto errout; + if ((error = skein_final(&ctx, mac, req)) != CRYPTO_SUCCESS) + goto errout; + + return (CRYPTO_SUCCESS); +errout: + bzero(&skein_ctx, sizeof (skein_ctx)); + return (error); +} + +/* + * KCF software provider context management entry points. + */ + +/* + * Constructs a context template for the Skein MAC algorithm. The same + * properties apply to the arguments of this function as to those of + * skein_mac_init. + */ +/*ARGSUSED*/ +static int +skein_create_ctx_template(crypto_provider_handle_t provider, + crypto_mechanism_t *mechanism, crypto_key_t *key, + crypto_spi_ctx_template_t *ctx_template, size_t *ctx_template_size, + crypto_req_handle_t req) +{ + int error; + skein_ctx_t *ctx_tmpl; + + ctx_tmpl = kmem_alloc(sizeof (*ctx_tmpl), crypto_kmflag(req)); + if (ctx_tmpl == NULL) + return (CRYPTO_HOST_MEMORY); + error = skein_mac_ctx_build(ctx_tmpl, mechanism, key); + if (error != CRYPTO_SUCCESS) + goto errout; + *ctx_template = ctx_tmpl; + *ctx_template_size = sizeof (*ctx_tmpl); + + return (CRYPTO_SUCCESS); +errout: + bzero(ctx_tmpl, sizeof (*ctx_tmpl)); + kmem_free(ctx_tmpl, sizeof (*ctx_tmpl)); + return (error); +} + +/* + * Frees a skein context in a parent crypto context. + */ +static int +skein_free_context(crypto_ctx_t *ctx) +{ + if (SKEIN_CTX(ctx) != NULL) { + bzero(SKEIN_CTX(ctx), sizeof (*SKEIN_CTX(ctx))); + kmem_free(SKEIN_CTX(ctx), sizeof (*SKEIN_CTX(ctx))); + SKEIN_CTX_LVALUE(ctx) = NULL; + } + + return (CRYPTO_SUCCESS); +} diff --git a/usr/src/uts/common/fs/zfs/arc.c b/usr/src/uts/common/fs/zfs/arc.c index 92e089e4b3..aa170859f5 100644 --- a/usr/src/uts/common/fs/zfs/arc.c +++ b/usr/src/uts/common/fs/zfs/arc.c @@ -1372,7 +1372,7 @@ arc_cksum_verify(arc_buf_t *buf) mutex_exit(&buf->b_hdr->b_l1hdr.b_freeze_lock); return; } - fletcher_2_native(buf->b_data, buf->b_hdr->b_size, &zc); + fletcher_2_native(buf->b_data, buf->b_hdr->b_size, NULL, &zc); if (!ZIO_CHECKSUM_EQUAL(*buf->b_hdr->b_freeze_cksum, zc)) panic("buffer modified while frozen!"); mutex_exit(&buf->b_hdr->b_l1hdr.b_freeze_lock); @@ -1385,7 +1385,7 @@ arc_cksum_equal(arc_buf_t *buf) int equal; mutex_enter(&buf->b_hdr->b_l1hdr.b_freeze_lock); - fletcher_2_native(buf->b_data, buf->b_hdr->b_size, &zc); + fletcher_2_native(buf->b_data, buf->b_hdr->b_size, NULL, &zc); equal = ZIO_CHECKSUM_EQUAL(*buf->b_hdr->b_freeze_cksum, zc); mutex_exit(&buf->b_hdr->b_l1hdr.b_freeze_lock); @@ -1405,7 +1405,7 @@ arc_cksum_compute(arc_buf_t *buf, boolean_t force) } buf->b_hdr->b_freeze_cksum = kmem_alloc(sizeof (zio_cksum_t), KM_SLEEP); fletcher_2_native(buf->b_data, buf->b_hdr->b_size, - buf->b_hdr->b_freeze_cksum); + NULL, buf->b_hdr->b_freeze_cksum); mutex_exit(&buf->b_hdr->b_l1hdr.b_freeze_lock); arc_buf_watch(buf); } diff --git a/usr/src/uts/common/fs/zfs/ddt.c b/usr/src/uts/common/fs/zfs/ddt.c index 7d93896572..9955f89e77 100644 --- a/usr/src/uts/common/fs/zfs/ddt.c +++ b/usr/src/uts/common/fs/zfs/ddt.c @@ -21,7 +21,7 @@ /* * Copyright (c) 2009, 2010, Oracle and/or its affiliates. All rights reserved. - * Copyright (c) 2012, 2014 by Delphix. All rights reserved. + * Copyright (c) 2012, 2015 by Delphix. All rights reserved. */ #include @@ -59,7 +59,8 @@ ddt_object_create(ddt_t *ddt, enum ddt_type type, enum ddt_class class, spa_t *spa = ddt->ddt_spa; objset_t *os = ddt->ddt_os; uint64_t *objectp = &ddt->ddt_object[type][class]; - boolean_t prehash = zio_checksum_table[ddt->ddt_checksum].ci_dedup; + boolean_t prehash = zio_checksum_table[ddt->ddt_checksum].ci_flags & + ZCHECKSUM_FLAG_DEDUP; char name[DDT_NAMELEN]; ddt_object_name(ddt, type, class, name); diff --git a/usr/src/uts/common/fs/zfs/dmu.c b/usr/src/uts/common/fs/zfs/dmu.c index 4b02f75d4f..98b92a1dbe 100644 --- a/usr/src/uts/common/fs/zfs/dmu.c +++ b/usr/src/uts/common/fs/zfs/dmu.c @@ -1424,7 +1424,8 @@ dmu_sync_done(zio_t *zio, arc_buf_t *buf, void *varg) ASSERT(BP_EQUAL(bp, bp_orig)); ASSERT(zio->io_prop.zp_compress != ZIO_COMPRESS_OFF); - ASSERT(zio_checksum_table[chksum].ci_dedup); + ASSERT(zio_checksum_table[chksum].ci_flags & + ZCHECKSUM_FLAG_NOPWRITE); } dr->dt.dl.dr_overridden_by = *zio->io_bp; dr->dt.dl.dr_override_state = DR_OVERRIDDEN; @@ -1769,8 +1770,10 @@ dmu_write_policy(objset_t *os, dnode_t *dn, int level, int wp, zio_prop_t *zp) * as well. Otherwise, the metadata checksum defaults * to fletcher4. */ - if (zio_checksum_table[checksum].ci_correctable < 1 || - zio_checksum_table[checksum].ci_eck) + if (!(zio_checksum_table[checksum].ci_flags & + ZCHECKSUM_FLAG_METADATA) || + (zio_checksum_table[checksum].ci_flags & + ZCHECKSUM_FLAG_EMBEDDED)) checksum = ZIO_CHECKSUM_FLETCHER_4; if (os->os_redundant_metadata == ZFS_REDUNDANT_METADATA_ALL || @@ -1809,17 +1812,20 @@ dmu_write_policy(objset_t *os, dnode_t *dn, int level, int wp, zio_prop_t *zp) */ if (dedup_checksum != ZIO_CHECKSUM_OFF) { dedup = (wp & WP_DMU_SYNC) ? B_FALSE : B_TRUE; - if (!zio_checksum_table[checksum].ci_dedup) + if (!(zio_checksum_table[checksum].ci_flags & + ZCHECKSUM_FLAG_DEDUP)) dedup_verify = B_TRUE; } /* - * Enable nopwrite if we have a cryptographically secure - * checksum that has no known collisions (i.e. SHA-256) - * and compression is enabled. We don't enable nopwrite if - * dedup is enabled as the two features are mutually exclusive. + * Enable nopwrite if we have secure enough checksum + * algorithm (see comment in zio_nop_write) and + * compression is enabled. We don't enable nopwrite if + * dedup is enabled as the two features are mutually + * exclusive. */ - nopwrite = (!dedup && zio_checksum_table[checksum].ci_dedup && + nopwrite = (!dedup && (zio_checksum_table[checksum].ci_flags & + ZCHECKSUM_FLAG_NOPWRITE) && compress != ZIO_COMPRESS_OFF && zfs_nopwrite_enabled); } diff --git a/usr/src/uts/common/fs/zfs/dmu_send.c b/usr/src/uts/common/fs/zfs/dmu_send.c index 0b57da6b8a..a0bf23349a 100644 --- a/usr/src/uts/common/fs/zfs/dmu_send.c +++ b/usr/src/uts/common/fs/zfs/dmu_send.c @@ -268,7 +268,8 @@ dump_write(dmu_sendarg_t *dsp, dmu_object_type_t type, drrw->drr_checksumtype = ZIO_CHECKSUM_OFF; } else { drrw->drr_checksumtype = BP_GET_CHECKSUM(bp); - if (zio_checksum_table[drrw->drr_checksumtype].ci_dedup) + if (zio_checksum_table[drrw->drr_checksumtype].ci_flags & + ZCHECKSUM_FLAG_DEDUP) drrw->drr_checksumflags |= DRR_CHECKSUM_DEDUP; DDK_SET_LSIZE(&drrw->drr_key, BP_GET_LSIZE(bp)); DDK_SET_PSIZE(&drrw->drr_key, BP_GET_PSIZE(bp)); diff --git a/usr/src/uts/common/fs/zfs/dsl_dataset.c b/usr/src/uts/common/fs/zfs/dsl_dataset.c index 7f63cd97bc..17d9927974 100644 --- a/usr/src/uts/common/fs/zfs/dsl_dataset.c +++ b/usr/src/uts/common/fs/zfs/dsl_dataset.c @@ -50,6 +50,8 @@ #include #include #include +#include +#include /* * The SPA supports block sizes up to 16MB. However, very large blocks @@ -124,10 +126,16 @@ dsl_dataset_block_born(dsl_dataset_t *ds, const blkptr_t *bp, dmu_tx_t *tx) dsl_dataset_phys(ds)->ds_compressed_bytes += compressed; dsl_dataset_phys(ds)->ds_uncompressed_bytes += uncompressed; dsl_dataset_phys(ds)->ds_unique_bytes += used; + if (BP_GET_LSIZE(bp) > SPA_OLD_MAXBLOCKSIZE) { ds->ds_feature_activation_needed[SPA_FEATURE_LARGE_BLOCKS] = B_TRUE; } + + spa_feature_t f = zio_checksum_to_feature(BP_GET_CHECKSUM(bp)); + if (f != SPA_FEATURE_NONE) + ds->ds_feature_activation_needed[f] = B_TRUE; + mutex_exit(&ds->ds_lock); dsl_dir_diduse_space(ds->ds_dir, DD_USED_HEAD, delta, compressed, uncompressed, tx); diff --git a/usr/src/uts/common/fs/zfs/edonr_zfs.c b/usr/src/uts/common/fs/zfs/edonr_zfs.c new file mode 100644 index 0000000000..93f1221fd5 --- /dev/null +++ b/usr/src/uts/common/fs/zfs/edonr_zfs.c @@ -0,0 +1,102 @@ +/* + * CDDL HEADER START + * + * The contents of this file are subject to the terms of the + * Common Development and Distribution License (the "License"). + * You may not use this file except in compliance with the License. + * + * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE + * or http://opensource.org/licenses/CDDL-1.0. + * See the License for the specific language governing permissions + * and limitations under the License. + * + * When distributing Covered Code, include this CDDL HEADER in each + * file and include the License file at usr/src/OPENSOLARIS.LICENSE. + * If applicable, add the following below this CDDL HEADER, with the + * fields enclosed by brackets "[]" replaced with your own identifying + * information: Portions Copyright [yyyy] [name of copyright owner] + * + * CDDL HEADER END + */ +/* + * Copyright 2013 Saso Kiselkov. All rights reserved. + * Use is subject to license terms. + */ +#include +#include +#include + +#define EDONR_MODE 512 +#define EDONR_BLOCK_SIZE EdonR512_BLOCK_SIZE + +/* + * Native zio_checksum interface for the Edon-R hash function. + */ +/*ARGSUSED*/ +void +zio_checksum_edonr_native(const void *buf, uint64_t size, + const void *ctx_template, zio_cksum_t *zcp) +{ + uint8_t digest[EDONR_MODE / 8]; + EdonRState ctx; + + ASSERT(ctx_template != NULL); + bcopy(ctx_template, &ctx, sizeof (ctx)); + EdonRUpdate(&ctx, buf, size * 8); + EdonRFinal(&ctx, digest); + bcopy(digest, zcp->zc_word, sizeof (zcp->zc_word)); +} + +/* + * Byteswapped zio_checksum interface for the Edon-R hash function. + */ +void +zio_checksum_edonr_byteswap(const void *buf, uint64_t size, + const void *ctx_template, zio_cksum_t *zcp) +{ + zio_cksum_t tmp; + + zio_checksum_edonr_native(buf, size, ctx_template, &tmp); + zcp->zc_word[0] = BSWAP_64(zcp->zc_word[0]); + zcp->zc_word[1] = BSWAP_64(zcp->zc_word[1]); + zcp->zc_word[2] = BSWAP_64(zcp->zc_word[2]); + zcp->zc_word[3] = BSWAP_64(zcp->zc_word[3]); +} + +void * +zio_checksum_edonr_tmpl_init(const zio_cksum_salt_t *salt) +{ + EdonRState *ctx; + uint8_t salt_block[EDONR_BLOCK_SIZE]; + + /* + * Edon-R needs all but the last hash invocation to be on full-size + * blocks, but the salt is too small. Rather than simply padding it + * with zeros, we expand the salt into a new salt block of proper + * size by double-hashing it (the new salt block will be composed of + * H(salt) || H(H(salt))). + */ + CTASSERT(EDONR_BLOCK_SIZE == 2 * (EDONR_MODE / 8)); + EdonRHash(EDONR_MODE, salt->zcs_bytes, sizeof (salt->zcs_bytes) * 8, + salt_block); + EdonRHash(EDONR_MODE, salt_block, EDONR_MODE, salt_block + + EDONR_MODE / 8); + + /* + * Feed the new salt block into the hash function - this will serve + * as our MAC key. + */ + ctx = kmem_zalloc(sizeof (*ctx), KM_SLEEP); + EdonRInit(ctx, EDONR_MODE); + EdonRUpdate(ctx, salt_block, sizeof (salt_block) * 8); + return (ctx); +} + +void +zio_checksum_edonr_tmpl_free(void *ctx_template) +{ + EdonRState *ctx = ctx_template; + + bzero(ctx, sizeof (*ctx)); + kmem_free(ctx, sizeof (*ctx)); +} diff --git a/usr/src/uts/common/fs/zfs/sha256.c b/usr/src/uts/common/fs/zfs/sha256.c index f515be6bb3..81a7f6b1c2 100644 --- a/usr/src/uts/common/fs/zfs/sha256.c +++ b/usr/src/uts/common/fs/zfs/sha256.c @@ -22,12 +22,17 @@ * Copyright 2009 Sun Microsystems, Inc. All rights reserved. * Use is subject to license terms. */ +/* + * Copyright 2013 Saso Kiselkov. All rights reserved. + */ #include #include #include +/*ARGSUSED*/ void -zio_checksum_SHA256(const void *buf, uint64_t size, zio_cksum_t *zcp) +zio_checksum_SHA256(const void *buf, uint64_t size, + const void *ctx_template, zio_cksum_t *zcp) { SHA2_CTX ctx; zio_cksum_t tmp; @@ -48,3 +53,29 @@ zio_checksum_SHA256(const void *buf, uint64_t size, zio_cksum_t *zcp) zcp->zc_word[2] = BE_64(tmp.zc_word[2]); zcp->zc_word[3] = BE_64(tmp.zc_word[3]); } + +/*ARGSUSED*/ +void +zio_checksum_SHA512_native(const void *buf, uint64_t size, + const void *ctx_template, zio_cksum_t *zcp) +{ + SHA2_CTX ctx; + + SHA2Init(SHA512_256, &ctx); + SHA2Update(&ctx, buf, size); + SHA2Final(zcp, &ctx); +} + +/*ARGSUSED*/ +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/usr/src/uts/common/fs/zfs/skein_zfs.c b/usr/src/uts/common/fs/zfs/skein_zfs.c new file mode 100644 index 0000000000..6592340396 --- /dev/null +++ b/usr/src/uts/common/fs/zfs/skein_zfs.c @@ -0,0 +1,91 @@ +/* + * 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 +#include +#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*/ +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). + */ +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. + */ +void * +zio_checksum_skein_tmpl_init(const zio_cksum_salt_t *salt) +{ + Skein_512_Ctxt_t *ctx; + + ctx = kmem_zalloc(sizeof (*ctx), KM_SLEEP); + (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. + */ +void +zio_checksum_skein_tmpl_free(void *ctx_template) +{ + Skein_512_Ctxt_t *ctx = ctx_template; + + bzero(ctx, sizeof (*ctx)); + kmem_free(ctx, sizeof (*ctx)); +} diff --git a/usr/src/uts/common/fs/zfs/spa.c b/usr/src/uts/common/fs/zfs/spa.c index 537c0945d1..95a6b0fae7 100644 --- a/usr/src/uts/common/fs/zfs/spa.c +++ b/usr/src/uts/common/fs/zfs/spa.c @@ -24,6 +24,7 @@ * Copyright (c) 2011, 2014 by Delphix. All rights reserved. * Copyright (c) 2015, Nexenta Systems, Inc. All rights reserved. * Copyright (c) 2014 Spectra Logic Corporation, All rights reserved. + * Copyright 2013 Saso Kiselkov. All rights reserved. */ /* @@ -2512,6 +2513,19 @@ spa_load_impl(spa_t *spa, uint64_t pool_guid, nvlist_t *config, return (spa_load(spa, state, SPA_IMPORT_EXISTING, B_TRUE)); } + /* Grab the secret checksum salt from the MOS. */ + error = zap_lookup(spa->spa_meta_objset, DMU_POOL_DIRECTORY_OBJECT, + DMU_POOL_CHECKSUM_SALT, 1, + sizeof (spa->spa_cksum_salt.zcs_bytes), + spa->spa_cksum_salt.zcs_bytes); + if (error == ENOENT) { + /* Generate a new salt for subsequent use */ + (void) random_get_pseudo_bytes(spa->spa_cksum_salt.zcs_bytes, + sizeof (spa->spa_cksum_salt.zcs_bytes)); + } else if (error != 0) { + return (spa_vdev_err(rvd, VDEV_AUX_CORRUPT_DATA, EIO)); + } + if (spa_dir_prop(spa, DMU_POOL_SYNC_BPOBJ, &obj) != 0) return (spa_vdev_err(rvd, VDEV_AUX_CORRUPT_DATA, EIO)); error = bpobj_open(&spa->spa_deferred_bpobj, spa->spa_meta_objset, obj); @@ -3664,6 +3678,12 @@ spa_create(const char *pool, nvlist_t *nvroot, nvlist_t *props, if (version >= SPA_VERSION_ZPOOL_HISTORY) spa_history_create_obj(spa, tx); + /* + * Generate some random noise for salted checksums to operate on. + */ + (void) random_get_pseudo_bytes(spa->spa_cksum_salt.zcs_bytes, + sizeof (spa->spa_cksum_salt.zcs_bytes)); + /* * Set pool properties. */ @@ -6215,6 +6235,20 @@ spa_sync_upgrades(spa_t *spa, dmu_tx_t *tx) if (lz4_en && !lz4_ac) spa_feature_incr(spa, SPA_FEATURE_LZ4_COMPRESS, tx); } + + /* + * If we haven't written the salt, do so now. Note that the + * feature may not be activated yet, but that's fine since + * the presence of this ZAP entry is backwards compatible. + */ + if (zap_contains(spa->spa_meta_objset, DMU_POOL_DIRECTORY_OBJECT, + DMU_POOL_CHECKSUM_SALT) == ENOENT) { + VERIFY0(zap_add(spa->spa_meta_objset, + DMU_POOL_DIRECTORY_OBJECT, DMU_POOL_CHECKSUM_SALT, 1, + sizeof (spa->spa_cksum_salt.zcs_bytes), + spa->spa_cksum_salt.zcs_bytes, tx)); + } + rrw_exit(&dp->dp_config_rwlock, FTAG); } diff --git a/usr/src/uts/common/fs/zfs/spa_misc.c b/usr/src/uts/common/fs/zfs/spa_misc.c index c5af055a86..9148a03433 100644 --- a/usr/src/uts/common/fs/zfs/spa_misc.c +++ b/usr/src/uts/common/fs/zfs/spa_misc.c @@ -23,6 +23,7 @@ * Copyright (c) 2011, 2015 by Delphix. All rights reserved. * Copyright 2011 Nexenta Systems, Inc. All rights reserved. * Copyright (c) 2014 Spectra Logic Corporation, All rights reserved. + * Copyright 2013 Saso Kiselkov. All rights reserved. */ #include @@ -50,7 +51,7 @@ #include #include #include "zfs_prop.h" -#include "zfeature_common.h" +#include /* * SPA locking @@ -556,6 +557,7 @@ spa_add(const char *name, nvlist_t *config, const char *altroot) mutex_init(&spa->spa_history_lock, NULL, MUTEX_DEFAULT, NULL); mutex_init(&spa->spa_proc_lock, NULL, MUTEX_DEFAULT, NULL); mutex_init(&spa->spa_props_lock, NULL, MUTEX_DEFAULT, NULL); + mutex_init(&spa->spa_cksum_tmpls_lock, NULL, MUTEX_DEFAULT, NULL); mutex_init(&spa->spa_scrub_lock, NULL, MUTEX_DEFAULT, NULL); mutex_init(&spa->spa_suspend_lock, NULL, MUTEX_DEFAULT, NULL); mutex_init(&spa->spa_vdev_top_lock, NULL, MUTEX_DEFAULT, NULL); @@ -716,6 +718,8 @@ spa_remove(spa_t *spa) for (int t = 0; t < TXG_SIZE; t++) bplist_destroy(&spa->spa_free_bplist[t]); + zio_checksum_templates_free(spa); + cv_destroy(&spa->spa_async_cv); cv_destroy(&spa->spa_evicting_os_cv); cv_destroy(&spa->spa_proc_cv); @@ -729,6 +733,7 @@ spa_remove(spa_t *spa) mutex_destroy(&spa->spa_history_lock); mutex_destroy(&spa->spa_proc_lock); mutex_destroy(&spa->spa_props_lock); + mutex_destroy(&spa->spa_cksum_tmpls_lock); mutex_destroy(&spa->spa_scrub_lock); mutex_destroy(&spa->spa_suspend_lock); mutex_destroy(&spa->spa_vdev_top_lock); diff --git a/usr/src/uts/common/fs/zfs/sys/dmu.h b/usr/src/uts/common/fs/zfs/sys/dmu.h index 149cb112f9..c10806989d 100644 --- a/usr/src/uts/common/fs/zfs/sys/dmu.h +++ b/usr/src/uts/common/fs/zfs/sys/dmu.h @@ -27,6 +27,7 @@ * Copyright 2013 DEY Storage Systems, Inc. * Copyright 2014 HybridCluster. All rights reserved. * Copyright (c) 2014 Spectra Logic Corporation, All rights reserved. + * Copyright 2013 Saso Kiselkov. All rights reserved. */ /* Portions Copyright 2010 Robert Milkowski */ @@ -318,6 +319,7 @@ typedef struct dmu_buf { #define DMU_POOL_FREE_BPOBJ "free_bpobj" #define DMU_POOL_BPTREE_OBJ "bptree_obj" #define DMU_POOL_EMPTY_BPOBJ "empty_bpobj" +#define DMU_POOL_CHECKSUM_SALT "org.illumos:checksum_salt" /* * Allocate an object from this objset. The range of object numbers diff --git a/usr/src/uts/common/fs/zfs/sys/spa.h b/usr/src/uts/common/fs/zfs/sys/spa.h index 2c4887b6ca..7ac7839033 100644 --- a/usr/src/uts/common/fs/zfs/sys/spa.h +++ b/usr/src/uts/common/fs/zfs/sys/spa.h @@ -23,6 +23,7 @@ * Copyright (c) 2011, 2014 by Delphix. All rights reserved. * Copyright 2011 Nexenta Systems, Inc. All rights reserved. * Copyright (c) 2014 Spectra Logic Corporation, All rights reserved. + * Copyright 2013 Saso Kiselkov. All rights reserved. */ #ifndef _SYS_SPA_H @@ -146,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: diff --git a/usr/src/uts/common/fs/zfs/sys/spa_impl.h b/usr/src/uts/common/fs/zfs/sys/spa_impl.h index 56e6adb713..4418001982 100644 --- a/usr/src/uts/common/fs/zfs/sys/spa_impl.h +++ b/usr/src/uts/common/fs/zfs/sys/spa_impl.h @@ -23,6 +23,7 @@ * Copyright (c) 2011, 2015 by Delphix. All rights reserved. * Copyright 2011 Nexenta Systems, Inc. All rights reserved. * Copyright (c) 2014 Spectra Logic Corporation, All rights reserved. + * Copyright 2013 Saso Kiselkov. All rights reserved. */ #ifndef _SYS_SPA_IMPL_H @@ -165,6 +166,10 @@ struct spa { uint64_t spa_syncing_txg; /* txg currently syncing */ bpobj_t spa_deferred_bpobj; /* deferred-free bplist */ bplist_t spa_free_bplist[TXG_SIZE]; /* bplist of stuff to free */ + zio_cksum_salt_t spa_cksum_salt; /* secret salt for cksum */ + /* checksum context templates */ + kmutex_t spa_cksum_tmpls_lock; + void *spa_cksum_tmpls[ZIO_CHECKSUM_FUNCTIONS]; uberblock_t spa_ubsync; /* last synced uberblock */ uberblock_t spa_uberblock; /* current uberblock */ boolean_t spa_extreme_rewind; /* rewind past deferred frees */ diff --git a/usr/src/uts/common/fs/zfs/sys/zio.h b/usr/src/uts/common/fs/zfs/sys/zio.h index d160c94686..877e2839bf 100644 --- a/usr/src/uts/common/fs/zfs/sys/zio.h +++ b/usr/src/uts/common/fs/zfs/sys/zio.h @@ -82,6 +82,9 @@ enum zio_checksum { ZIO_CHECKSUM_SHA256, ZIO_CHECKSUM_ZILOG2, ZIO_CHECKSUM_NOPARITY, + ZIO_CHECKSUM_SHA512, + ZIO_CHECKSUM_SKEIN, + ZIO_CHECKSUM_EDONR, ZIO_CHECKSUM_FUNCTIONS }; diff --git a/usr/src/uts/common/fs/zfs/sys/zio_checksum.h b/usr/src/uts/common/fs/zfs/sys/zio_checksum.h index 0c293ab20e..572b29d3cb 100644 --- a/usr/src/uts/common/fs/zfs/sys/zio_checksum.h +++ b/usr/src/uts/common/fs/zfs/sys/zio_checksum.h @@ -20,13 +20,15 @@ */ /* * Copyright (c) 2005, 2010, Oracle and/or its affiliates. All rights reserved. - * Copyright (c) 2014 by Delphix. All rights reserved. + * Copyright (c) 2014, 2015 by Delphix. All rights reserved. + * Copyright Saso Kiselkov 2013, All rights reserved. */ #ifndef _SYS_ZIO_CHECKSUM_H #define _SYS_ZIO_CHECKSUM_H #include +#include #ifdef __cplusplus extern "C" { @@ -35,17 +37,34 @@ extern "C" { /* * Signature for checksum functions. */ -typedef void zio_checksum_func_t(const void *, uint64_t, zio_cksum_t *); +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_func_t *ci_func[2]; /* checksum function per byteorder */ - int ci_correctable; /* number of correctable bits */ - int ci_eck; /* uses zio embedded checksum? */ - boolean_t ci_dedup; /* strong enough for dedup? */ - 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; + char *ci_name; /* descriptive name */ } zio_checksum_info_t; typedef struct zio_bad_cksum { @@ -62,12 +81,28 @@ extern zio_checksum_info_t zio_checksum_table[ZIO_CHECKSUM_FUNCTIONS]; /* * Checksum routines. */ -extern zio_checksum_func_t zio_checksum_SHA256; +extern zio_checksum_t zio_checksum_SHA256; +extern zio_checksum_t zio_checksum_SHA512_native; +extern zio_checksum_t zio_checksum_SHA512_byteswap; + +/* Skein */ +extern zio_checksum_t zio_checksum_skein_native; +extern zio_checksum_t zio_checksum_skein_byteswap; +extern zio_checksum_tmpl_init_t zio_checksum_skein_tmpl_init; +extern zio_checksum_tmpl_free_t zio_checksum_skein_tmpl_free; + +/* Edon-R */ +extern zio_checksum_t zio_checksum_edonr_native; +extern zio_checksum_t zio_checksum_edonr_byteswap; +extern zio_checksum_tmpl_init_t zio_checksum_edonr_tmpl_init; +extern zio_checksum_tmpl_free_t zio_checksum_edonr_tmpl_free; extern void zio_checksum_compute(zio_t *zio, enum zio_checksum checksum, void *data, uint64_t size); extern int zio_checksum_error(zio_t *zio, zio_bad_cksum_t *out); extern enum zio_checksum spa_dedup_checksum(spa_t *spa); +extern void zio_checksum_templates_free(spa_t *spa); +extern spa_feature_t zio_checksum_to_feature(enum zio_checksum cksum); #ifdef __cplusplus } diff --git a/usr/src/uts/common/fs/zfs/zfs_ioctl.c b/usr/src/uts/common/fs/zfs/zfs_ioctl.c index 5a56021c8c..73cf63ad9a 100644 --- a/usr/src/uts/common/fs/zfs/zfs_ioctl.c +++ b/usr/src/uts/common/fs/zfs/zfs_ioctl.c @@ -180,6 +180,7 @@ #include #include #include +#include #include "zfs_namecheck.h" #include "zfs_prop.h" @@ -3817,11 +3818,6 @@ zfs_check_settable(const char *dsname, nvpair_t *pair, cred_t *cr) return (SET_ERROR(ENOTSUP)); break; - case ZFS_PROP_DEDUP: - if (zfs_earlier_version(dsname, SPA_VERSION_DEDUP)) - return (SET_ERROR(ENOTSUP)); - break; - case ZFS_PROP_RECORDSIZE: /* Record sizes above 128k need the feature to be enabled */ if (nvpair_value_uint64(pair, &intval) == 0 && @@ -3872,6 +3868,45 @@ zfs_check_settable(const char *dsname, nvpair_t *pair, cred_t *cr) return (SET_ERROR(ENOTSUP)); } break; + + case ZFS_PROP_CHECKSUM: + case ZFS_PROP_DEDUP: + { + spa_feature_t feature; + spa_t *spa; + + /* dedup feature version checks */ + if (prop == ZFS_PROP_DEDUP && + zfs_earlier_version(dsname, SPA_VERSION_DEDUP)) + return (SET_ERROR(ENOTSUP)); + + if (nvpair_value_uint64(pair, &intval) != 0) + return (SET_ERROR(EINVAL)); + + /* check prop value is enabled in features */ + feature = zio_checksum_to_feature(intval); + if (feature == SPA_FEATURE_NONE) + break; + + if ((err = spa_open(dsname, &spa, FTAG)) != 0) + return (err); + /* + * Salted checksums are not supported on root pools. + */ + if (spa_bootfs(spa) != 0 && + intval < ZIO_CHECKSUM_FUNCTIONS && + (zio_checksum_table[intval].ci_flags & + ZCHECKSUM_FLAG_SALTED)) { + spa_close(spa, FTAG); + return (SET_ERROR(ERANGE)); + } + if (!spa_feature_is_enabled(spa, feature)) { + spa_close(spa, FTAG); + return (SET_ERROR(ENOTSUP)); + } + spa_close(spa, FTAG); + break; + } } return (zfs_secpolicy_setprop(dsname, prop, pair, CRED())); diff --git a/usr/src/uts/common/fs/zfs/zio.c b/usr/src/uts/common/fs/zfs/zio.c index f92ecb4739..7fa795ea8c 100644 --- a/usr/src/uts/common/fs/zfs/zio.c +++ b/usr/src/uts/common/fs/zfs/zio.c @@ -929,7 +929,7 @@ zio_write_phys(zio_t *pio, vdev_t *vd, uint64_t offset, uint64_t size, zio->io_prop.zp_checksum = checksum; - if (zio_checksum_table[checksum].ci_eck) { + if (zio_checksum_table[checksum].ci_flags & ZCHECKSUM_FLAG_EMBEDDED) { /* * zec checksums are necessarily destructive -- they modify * the end of the write buffer to hold the verifier/checksum. @@ -1125,8 +1125,8 @@ zio_write_bp_init(zio_t *zio) if (BP_IS_HOLE(bp) || !zp->zp_dedup) return (ZIO_PIPELINE_CONTINUE); - ASSERT(zio_checksum_table[zp->zp_checksum].ci_dedup || - zp->zp_dedup_verify); + ASSERT((zio_checksum_table[zp->zp_checksum].ci_flags & + ZCHECKSUM_FLAG_DEDUP) || zp->zp_dedup_verify); if (BP_GET_CHECKSUM(bp) == zp->zp_checksum) { BP_SET_DEDUP(bp, 1); @@ -1981,12 +1981,22 @@ zio_write_gang_block(zio_t *pio) } /* - * The zio_nop_write stage in the pipeline determines if allocating - * a new bp is necessary. By leveraging a cryptographically secure checksum, - * such as SHA256, we can compare the checksums of the new data and the old - * to determine if allocating a new block is required. The nopwrite - * feature can handle writes in either syncing or open context (i.e. zil - * writes) and as a result is mutually exclusive with dedup. + * The zio_nop_write stage in the pipeline determines if allocating a + * new bp is necessary. The nopwrite feature can handle writes in + * either syncing or open context (i.e. zil writes) and as a result is + * mutually exclusive with dedup. + * + * By leveraging a cryptographically secure checksum, such as SHA256, we + * can compare the checksums of the new data and the old to determine if + * allocating a new block is required. Note that our requirements for + * cryptographic strength are fairly weak: there can't be any accidental + * hash collisions, but we don't need to be secure against intentional + * (malicious) collisions. To trigger a nopwrite, you have to be able + * to write the file to begin with, and triggering an incorrect (hash + * collision) nopwrite is no worse than simply writing to the file. + * That said, there are no known attacks against the checksum algorithms + * used for nopwrite, assuming that the salt and the checksums + * themselves remain secret. */ static int zio_nop_write(zio_t *zio) @@ -2009,7 +2019,8 @@ zio_nop_write(zio_t *zio) * allocate a new bp. */ if (BP_IS_HOLE(bp_orig) || - !zio_checksum_table[BP_GET_CHECKSUM(bp)].ci_dedup || + !(zio_checksum_table[BP_GET_CHECKSUM(bp)].ci_flags & + ZCHECKSUM_FLAG_NOPWRITE) || BP_GET_CHECKSUM(bp) != BP_GET_CHECKSUM(bp_orig) || BP_GET_COMPRESS(bp) != BP_GET_COMPRESS(bp_orig) || BP_GET_DEDUP(bp) != BP_GET_DEDUP(bp_orig) || @@ -2021,7 +2032,8 @@ zio_nop_write(zio_t *zio) * avoid allocating a new bp and issuing any I/O. */ if (ZIO_CHECKSUM_EQUAL(bp->blk_cksum, bp_orig->blk_cksum)) { - ASSERT(zio_checksum_table[zp->zp_checksum].ci_dedup); + ASSERT(zio_checksum_table[zp->zp_checksum].ci_flags & + ZCHECKSUM_FLAG_NOPWRITE); ASSERT3U(BP_GET_PSIZE(bp), ==, BP_GET_PSIZE(bp_orig)); ASSERT3U(BP_GET_LSIZE(bp), ==, BP_GET_LSIZE(bp_orig)); ASSERT(zp->zp_compress != ZIO_COMPRESS_OFF); @@ -2302,7 +2314,8 @@ zio_ddt_write(zio_t *zio) * we can't resolve it, so just convert to an ordinary write. * (And automatically e-mail a paper to Nature?) */ - if (!zio_checksum_table[zp->zp_checksum].ci_dedup) { + if (!(zio_checksum_table[zp->zp_checksum].ci_flags & + ZCHECKSUM_FLAG_DEDUP)) { zp->zp_checksum = spa_dedup_checksum(spa); zio_pop_transforms(zio); zio->io_stage = ZIO_STAGE_OPEN; diff --git a/usr/src/uts/common/fs/zfs/zio_checksum.c b/usr/src/uts/common/fs/zfs/zio_checksum.c index d1c60c3ffa..b471ad9047 100644 --- a/usr/src/uts/common/fs/zfs/zio_checksum.c +++ b/usr/src/uts/common/fs/zfs/zio_checksum.c @@ -22,10 +22,12 @@ * Copyright (c) 2005, 2010, Oracle and/or its affiliates. All rights reserved. * Copyright (c) 2013 by Delphix. All rights reserved. * Copyright (c) 2013, Joyent, Inc. All rights reserved. + * Copyright 2013 Saso Kiselkov. All rights reserved. */ #include #include +#include #include #include #include @@ -59,29 +61,95 @@ * checksum function of the appropriate strength. When reading a block, * we compare the expected checksum against the actual checksum, which we * compute via the checksum function specified by BP_GET_CHECKSUM(bp). + * + * SALTED CHECKSUMS + * + * To enable the use of less secure hash algorithms with dedup, we + * introduce the notion of salted checksums (MACs, really). A salted + * checksum is fed both a random 256-bit value (the salt) and the data + * to be checksummed. This salt is kept secret (stored on the pool, but + * never shown to the user). Thus even if an attacker knew of collision + * weaknesses in the hash algorithm, they won't be able to mount a known + * plaintext attack on the DDT, since the actual hash value cannot be + * known ahead of time. How the salt is used is algorithm-specific + * (some might simply prefix it to the data block, others might need to + * utilize a full-blown HMAC). On disk the salt is stored in a ZAP + * object in the MOS (DMU_POOL_CHECKSUM_SALT). + * + * CONTEXT TEMPLATES + * + * Some hashing algorithms need to perform a substantial amount of + * initialization work (e.g. salted checksums above may need to pre-hash + * the salt) before being able to process data. Performing this + * redundant work for each block would be wasteful, so we instead allow + * a checksum algorithm to do the work once (the first time it's used) + * and then keep this pre-initialized context as a template inside the + * spa_t (spa_cksum_tmpls). If the zio_checksum_info_t contains + * non-NULL ci_tmpl_init and ci_tmpl_free callbacks, they are used to + * construct and destruct the pre-initialized checksum context. The + * pre-initialized context is then reused during each checksum + * invocation and passed to the checksum function. */ /*ARGSUSED*/ 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); } 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, "zilog2"}, - {{zio_checksum_off, zio_checksum_off}, 0, 0, 0, "noparity"}, + {{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, "zilog2"}, + {{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"}, + {{zio_checksum_edonr_native, zio_checksum_edonr_byteswap}, + zio_checksum_edonr_tmpl_init, zio_checksum_edonr_tmpl_free, + ZCHECKSUM_FLAG_METADATA | ZCHECKSUM_FLAG_SALTED | + ZCHECKSUM_FLAG_NOPWRITE, "edonr"}, }; +spa_feature_t +zio_checksum_to_feature(enum zio_checksum cksum) +{ + switch (cksum) { + case ZIO_CHECKSUM_SHA512: + return (SPA_FEATURE_SHA512); + case ZIO_CHECKSUM_SKEIN: + return (SPA_FEATURE_SKEIN); + case ZIO_CHECKSUM_EDONR: + return (SPA_FEATURE_EDONR); + } + return (SPA_FEATURE_NONE); +} + enum zio_checksum zio_checksum_select(enum zio_checksum child, enum zio_checksum parent) { @@ -115,7 +183,8 @@ zio_checksum_dedup_select(spa_t *spa, enum zio_checksum child, if (child == (ZIO_CHECKSUM_ON | ZIO_CHECKSUM_VERIFY)) return (spa_dedup_checksum(spa) | ZIO_CHECKSUM_VERIFY); - ASSERT(zio_checksum_table[child & ZIO_CHECKSUM_MASK].ci_dedup || + ASSERT((zio_checksum_table[child & ZIO_CHECKSUM_MASK].ci_flags & + ZCHECKSUM_FLAG_DEDUP) || (child & ZIO_CHECKSUM_VERIFY) || child == ZIO_CHECKSUM_OFF); return (child); @@ -147,6 +216,30 @@ 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; + + VERIFY(ci->ci_tmpl_free != NULL); + mutex_enter(&spa->spa_cksum_tmpls_lock); + if (spa->spa_cksum_tmpls[checksum] == NULL) { + spa->spa_cksum_tmpls[checksum] = + ci->ci_tmpl_init(&spa->spa_cksum_salt); + VERIFY(spa->spa_cksum_tmpls[checksum] != NULL); + } + mutex_exit(&spa->spa_cksum_tmpls_lock); +} + /* * Generate the checksum. */ @@ -158,11 +251,14 @@ zio_checksum_compute(zio_t *zio, enum zio_checksum checksum, uint64_t offset = zio->io_offset; zio_checksum_info_t *ci = &zio_checksum_table[checksum]; zio_cksum_t cksum; + spa_t *spa = zio->io_spa; ASSERT((uint_t)checksum < ZIO_CHECKSUM_FUNCTIONS); ASSERT(ci->ci_func[0] != NULL); - if (ci->ci_eck) { + zio_checksum_template_init(checksum, spa); + + if (ci->ci_flags & ZCHECKSUM_FLAG_EMBEDDED) { zio_eck_t *eck; if (checksum == ZIO_CHECKSUM_ZILOG2) { @@ -181,10 +277,12 @@ zio_checksum_compute(zio_t *zio, enum zio_checksum checksum, else bp->blk_cksum = eck->zec_cksum; eck->zec_magic = ZEC_MAGIC; - ci->ci_func[0](data, size, &cksum); + ci->ci_func[0](data, size, spa->spa_cksum_tmpls[checksum], + &cksum); eck->zec_cksum = cksum; } else { - ci->ci_func[0](data, size, &bp->blk_cksum); + ci->ci_func[0](data, size, spa->spa_cksum_tmpls[checksum], + &bp->blk_cksum); } } @@ -202,11 +300,14 @@ zio_checksum_error(zio_t *zio, zio_bad_cksum_t *info) void *data = zio->io_data; zio_checksum_info_t *ci = &zio_checksum_table[checksum]; zio_cksum_t actual_cksum, expected_cksum, verifier; + spa_t *spa = zio->io_spa; if (checksum >= ZIO_CHECKSUM_FUNCTIONS || ci->ci_func[0] == NULL) return (SET_ERROR(EINVAL)); - if (ci->ci_eck) { + zio_checksum_template_init(checksum, spa); + + if (ci->ci_flags & ZCHECKSUM_FLAG_EMBEDDED) { zio_eck_t *eck; if (checksum == ZIO_CHECKSUM_ZILOG2) { @@ -243,7 +344,8 @@ zio_checksum_error(zio_t *zio, zio_bad_cksum_t *info) 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) @@ -253,7 +355,8 @@ zio_checksum_error(zio_t *zio, zio_bad_cksum_t *info) ASSERT(!BP_IS_GANG(bp)); byteswap = BP_SHOULD_BYTESWAP(bp); expected_cksum = bp->blk_cksum; - ci->ci_func[byteswap](data, size, &actual_cksum); + ci->ci_func[byteswap](data, size, + spa->spa_cksum_tmpls[checksum], &actual_cksum); } info->zbc_expected = expected_cksum; @@ -275,3 +378,23 @@ zio_checksum_error(zio_t *zio, zio_bad_cksum_t *info) return (0); } + +/* + * 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]; + + VERIFY(ci->ci_tmpl_free != NULL); + ci->ci_tmpl_free(spa->spa_cksum_tmpls[checksum]); + spa->spa_cksum_tmpls[checksum] = NULL; + } + } +} diff --git a/usr/src/uts/common/sys/Makefile b/usr/src/uts/common/sys/Makefile index fe76386127..90618abb6e 100644 --- a/usr/src/uts/common/sys/Makefile +++ b/usr/src/uts/common/sys/Makefile @@ -22,6 +22,7 @@ # Copyright (c) 1989, 2010, Oracle and/or its affiliates. All rights reserved. # Copyright 2013, Joyent, Inc. All rights reserved. # Copyright 2013 Garrett D'Amore +# Copyright 2013 Saso Kiselkov. All rights reserved. # include $(SRC)/uts/Makefile.uts @@ -201,6 +202,7 @@ CHKHDRS= \ ecppio.h \ ecppreg.h \ ecppvar.h \ + edonr.h \ efi_partition.h \ elf.h \ elf_386.h \ @@ -504,6 +506,7 @@ CHKHDRS= \ sid.h \ siginfo.h \ signal.h \ + skein.h \ sleepq.h \ smbios.h \ smbios_impl.h \ diff --git a/usr/src/uts/common/sys/crypto/common.h b/usr/src/uts/common/sys/crypto/common.h index 8fc7b05de6..68283c390a 100644 --- a/usr/src/uts/common/sys/crypto/common.h +++ b/usr/src/uts/common/sys/crypto/common.h @@ -21,6 +21,9 @@ /* * Copyright (c) 2003, 2010, Oracle and/or its affiliates. All rights reserved. */ +/* + * Copyright 2013 Saso Kiselkov. All rights reserved. + */ #ifndef _SYS_CRYPTO_COMMON_H #define _SYS_CRYPTO_COMMON_H @@ -194,6 +197,8 @@ typedef uint32_t crypto_keysize_unit_t; #define SUN_CKM_SHA512 "CKM_SHA512" #define SUN_CKM_SHA512_HMAC "CKM_SHA512_HMAC" #define SUN_CKM_SHA512_HMAC_GENERAL "CKM_SHA512_HMAC_GENERAL" +#define SUN_CKM_SHA512_224 "CKM_SHA512_224" +#define SUN_CKM_SHA512_256 "CKM_SHA512_256" #define SUN_CKM_DES_CBC "CKM_DES_CBC" #define SUN_CKM_DES3_CBC "CKM_DES3_CBC" #define SUN_CKM_DES_ECB "CKM_DES_ECB" diff --git a/usr/src/uts/common/sys/debug.h b/usr/src/uts/common/sys/debug.h index 27b84beb88..8efc8956b6 100644 --- a/usr/src/uts/common/sys/debug.h +++ b/usr/src/uts/common/sys/debug.h @@ -27,6 +27,7 @@ /* * Copyright (c) 2012 by Delphix. All rights reserved. + * Copyright 2013 Saso Kiselkov. All rights reserved. */ /* Copyright (c) 1984, 1986, 1987, 1988, 1989 AT&T */ @@ -124,6 +125,14 @@ _NOTE(CONSTCOND) } while (0) #define ASSERT0(x) ((void)0) #endif +/* + * Compile-time assertion. The condition 'x' must be constant. + */ +#define CTASSERT(x) _CTASSERT(x, __LINE__) +#define _CTASSERT(x, y) __CTASSERT(x, y) +#define __CTASSERT(x, y) \ + typedef char __compile_time_assertion__ ## y [(x) ? 1 : -1] + #ifdef _KERNEL extern void abort_sequence_enter(char *); diff --git a/usr/src/uts/common/sys/edonr.h b/usr/src/uts/common/sys/edonr.h new file mode 100644 index 0000000000..e65118dc1f --- /dev/null +++ b/usr/src/uts/common/sys/edonr.h @@ -0,0 +1,93 @@ +/* + * IDI,NTNU + * + * 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 (C) 2009, 2010, Jorn Amundsen + * + * Tweaked Edon-R implementation for SUPERCOP, based on NIST API. + * + * $Id: edonr.h 517 2013-02-17 20:34:39Z joern $ + */ +/* + * Portions copyright (c) 2013, Saso Kiselkov, All rights reserved + */ + +#ifndef _SYS_EDONR_H_ +#define _SYS_EDONR_H_ + +#ifdef __cplusplus +extern "C" { +#endif + +#include + +/* + * EdonR allows to call EdonRUpdate() consecutively only if the total length + * of stored unprocessed data and the new supplied data is less than or equal + * to the BLOCK_SIZE on which the compression functions operates. + * Otherwise an assertion failure is invoked. + */ + +/* Specific algorithm definitions */ +#define EdonR224_DIGEST_SIZE 28 +#define EdonR224_BLOCK_SIZE 64 +#define EdonR256_DIGEST_SIZE 32 +#define EdonR256_BLOCK_SIZE 64 +#define EdonR384_DIGEST_SIZE 48 +#define EdonR384_BLOCK_SIZE 128 +#define EdonR512_DIGEST_SIZE 64 +#define EdonR512_BLOCK_SIZE 128 + +#define EdonR256_BLOCK_BITSIZE 512 +#define EdonR512_BLOCK_BITSIZE 1024 + +typedef struct { + uint32_t DoublePipe[16]; + uint8_t LastPart[EdonR256_BLOCK_SIZE * 2]; +} EdonRData256; +typedef struct { + uint64_t DoublePipe[16]; + uint8_t LastPart[EdonR512_BLOCK_SIZE * 2]; +} EdonRData512; + +typedef struct { + size_t hashbitlen; + + /* + algorithm specific parameters */ + int unprocessed_bits; + uint64_t bits_processed; + union { + EdonRData256 p256[1]; + EdonRData512 p512[1]; + } pipe[1]; +} EdonRState; + +void EdonRInit(EdonRState *state, size_t hashbitlen); +void EdonRUpdate(EdonRState *state, const uint8_t *data, size_t databitlen); +void EdonRFinal(EdonRState *state, uint8_t *hashval); +void EdonRHash(size_t hashbitlen, const uint8_t *data, size_t databitlen, + uint8_t *hashval); + +#ifdef __cplusplus +} +#endif + +#endif /* _SYS_EDONR_H_ */ diff --git a/usr/src/uts/common/sys/sha2.h b/usr/src/uts/common/sys/sha2.h index ad46dd683a..4dd966b6ca 100644 --- a/usr/src/uts/common/sys/sha2.h +++ b/usr/src/uts/common/sys/sha2.h @@ -22,6 +22,7 @@ * Copyright 2009 Sun Microsystems, Inc. All rights reserved. * Use is subject to license terms. */ +/* Copyright 2013 Saso Kiselkov. All rights reserved. */ #ifndef _SYS_SHA2_H #define _SYS_SHA2_H @@ -39,6 +40,10 @@ extern "C" { #define SHA384_DIGEST_LENGTH 48 /* SHA384 digest length in bytes */ #define SHA512_DIGEST_LENGTH 64 /* SHA512 digest length in bytes */ +/* Truncated versions of SHA-512 according to FIPS-180-4, section 5.3.6 */ +#define SHA512_224_DIGEST_LENGTH 28 /* SHA512/224 digest length */ +#define SHA512_256_DIGEST_LENGTH 32 /* SHA512/256 digest length */ + #define SHA256_HMAC_BLOCK_SIZE 64 /* SHA256-HMAC block size */ #define SHA512_HMAC_BLOCK_SIZE 128 /* SHA512-HMAC block size */ @@ -51,6 +56,8 @@ extern "C" { #define SHA512 6 #define SHA512_HMAC 7 #define SHA512_HMAC_GEN 8 +#define SHA512_224 9 +#define SHA512_256 10 /* * SHA2 context. @@ -130,7 +137,9 @@ typedef enum sha2_mech_type { SHA384_HMAC_GEN_MECH_INFO_TYPE, /* SUN_CKM_SHA384_HMAC_GENERAL */ SHA512_MECH_INFO_TYPE, /* SUN_CKM_SHA512 */ SHA512_HMAC_MECH_INFO_TYPE, /* SUN_CKM_SHA512_HMAC */ - SHA512_HMAC_GEN_MECH_INFO_TYPE /* SUN_CKM_SHA512_HMAC_GENERAL */ + SHA512_HMAC_GEN_MECH_INFO_TYPE, /* SUN_CKM_SHA512_HMAC_GENERAL */ + SHA512_224_MECH_INFO_TYPE, /* SUN_CKM_SHA512_224 */ + SHA512_256_MECH_INFO_TYPE /* SUN_CKM_SHA512_256 */ } sha2_mech_type_t; #endif /* _SHA2_IMPL */ diff --git a/usr/src/uts/common/sys/skein.h b/usr/src/uts/common/sys/skein.h new file mode 100644 index 0000000000..423e1dc34e --- /dev/null +++ b/usr/src/uts/common/sys/skein.h @@ -0,0 +1,178 @@ +/* + * Interface declarations for Skein hashing. + * Source code author: Doug Whiting, 2008. + * This algorithm and source code is released to the public domain. + * + * The following compile-time switches may be defined to control some + * tradeoffs between speed, code size, error checking, and security. + * + * The "default" note explains what happens when the switch is not defined. + * + * SKEIN_DEBUG -- make callouts from inside Skein code + * to examine/display intermediate values. + * [default: no callouts (no overhead)] + * + * SKEIN_ERR_CHECK -- how error checking is handled inside Skein + * code. If not defined, most error checking + * is disabled (for performance). Otherwise, + * the switch value is interpreted as: + * 0: use assert() to flag errors + * 1: return SKEIN_FAIL to flag errors + */ +/* Copyright 2013 Doug Whiting. This code is released to the public domain. */ +#ifndef _SYS_SKEIN_H_ +#define _SYS_SKEIN_H_ + +#include /* get size_t definition */ + +#ifdef __cplusplus +extern "C" { +#endif + +enum { + SKEIN_SUCCESS = 0, /* return codes from Skein calls */ + SKEIN_FAIL = 1, + SKEIN_BAD_HASHLEN = 2 +}; + +#define SKEIN_MODIFIER_WORDS (2) /* number of modifier (tweak) words */ + +#define SKEIN_256_STATE_WORDS (4) +#define SKEIN_512_STATE_WORDS (8) +#define SKEIN1024_STATE_WORDS (16) +#define SKEIN_MAX_STATE_WORDS (16) + +#define SKEIN_256_STATE_BYTES (8 * SKEIN_256_STATE_WORDS) +#define SKEIN_512_STATE_BYTES (8 * SKEIN_512_STATE_WORDS) +#define SKEIN1024_STATE_BYTES (8 * SKEIN1024_STATE_WORDS) + +#define SKEIN_256_STATE_BITS (64 * SKEIN_256_STATE_WORDS) +#define SKEIN_512_STATE_BITS (64 * SKEIN_512_STATE_WORDS) +#define SKEIN1024_STATE_BITS (64 * SKEIN1024_STATE_WORDS) + +#define SKEIN_256_BLOCK_BYTES (8 * SKEIN_256_STATE_WORDS) +#define SKEIN_512_BLOCK_BYTES (8 * SKEIN_512_STATE_WORDS) +#define SKEIN1024_BLOCK_BYTES (8 * SKEIN1024_STATE_WORDS) + +typedef struct { + size_t hashBitLen; /* size of hash result, in bits */ + size_t bCnt; /* current byte count in buffer b[] */ + /* tweak words: T[0]=byte cnt, T[1]=flags */ + uint64_t T[SKEIN_MODIFIER_WORDS]; +} Skein_Ctxt_Hdr_t; + +typedef struct { /* 256-bit Skein hash context structure */ + Skein_Ctxt_Hdr_t h; /* common header context variables */ + uint64_t X[SKEIN_256_STATE_WORDS]; /* chaining variables */ + /* partial block buffer (8-byte aligned) */ + uint8_t b[SKEIN_256_BLOCK_BYTES]; +} Skein_256_Ctxt_t; + +typedef struct { /* 512-bit Skein hash context structure */ + Skein_Ctxt_Hdr_t h; /* common header context variables */ + uint64_t X[SKEIN_512_STATE_WORDS]; /* chaining variables */ + /* partial block buffer (8-byte aligned) */ + uint8_t b[SKEIN_512_BLOCK_BYTES]; +} Skein_512_Ctxt_t; + +typedef struct { /* 1024-bit Skein hash context structure */ + Skein_Ctxt_Hdr_t h; /* common header context variables */ + uint64_t X[SKEIN1024_STATE_WORDS]; /* chaining variables */ + /* partial block buffer (8-byte aligned) */ + uint8_t b[SKEIN1024_BLOCK_BYTES]; +} Skein1024_Ctxt_t; + +/* Skein APIs for (incremental) "straight hashing" */ +int Skein_256_Init(Skein_256_Ctxt_t *ctx, size_t hashBitLen); +int Skein_512_Init(Skein_512_Ctxt_t *ctx, size_t hashBitLen); +int Skein1024_Init(Skein1024_Ctxt_t *ctx, size_t hashBitLen); + +int Skein_256_Update(Skein_256_Ctxt_t *ctx, const uint8_t *msg, + size_t msgByteCnt); +int Skein_512_Update(Skein_512_Ctxt_t *ctx, const uint8_t *msg, + size_t msgByteCnt); +int Skein1024_Update(Skein1024_Ctxt_t *ctx, const uint8_t *msg, + size_t msgByteCnt); + +int Skein_256_Final(Skein_256_Ctxt_t *ctx, uint8_t *hashVal); +int Skein_512_Final(Skein_512_Ctxt_t *ctx, uint8_t *hashVal); +int Skein1024_Final(Skein1024_Ctxt_t *ctx, uint8_t *hashVal); + +/* + * Skein APIs for "extended" initialization: MAC keys, tree hashing. + * After an InitExt() call, just use Update/Final calls as with Init(). + * + * Notes: Same parameters as _Init() calls, plus treeInfo/key/keyBytes. + * When keyBytes == 0 and treeInfo == SKEIN_SEQUENTIAL, + * the results of InitExt() are identical to calling Init(). + * The function Init() may be called once to "precompute" the IV for + * a given hashBitLen value, then by saving a copy of the context + * the IV computation may be avoided in later calls. + * Similarly, the function InitExt() may be called once per MAC key + * to precompute the MAC IV, then a copy of the context saved and + * reused for each new MAC computation. + */ +int Skein_256_InitExt(Skein_256_Ctxt_t *ctx, size_t hashBitLen, + uint64_t treeInfo, const uint8_t *key, size_t keyBytes); +int Skein_512_InitExt(Skein_512_Ctxt_t *ctx, size_t hashBitLen, + uint64_t treeInfo, const uint8_t *key, size_t keyBytes); +int Skein1024_InitExt(Skein1024_Ctxt_t *ctx, size_t hashBitLen, + uint64_t treeInfo, const uint8_t *key, size_t keyBytes); + +/* + * Skein APIs for MAC and tree hash: + * Final_Pad: pad, do final block, but no OUTPUT type + * Output: do just the output stage + */ +int Skein_256_Final_Pad(Skein_256_Ctxt_t *ctx, uint8_t *hashVal); +int Skein_512_Final_Pad(Skein_512_Ctxt_t *ctx, uint8_t *hashVal); +int Skein1024_Final_Pad(Skein1024_Ctxt_t *ctx, uint8_t *hashVal); + +#ifndef SKEIN_TREE_HASH +#define SKEIN_TREE_HASH (1) +#endif +#if SKEIN_TREE_HASH +int Skein_256_Output(Skein_256_Ctxt_t *ctx, uint8_t *hashVal); +int Skein_512_Output(Skein_512_Ctxt_t *ctx, uint8_t *hashVal); +int Skein1024_Output(Skein1024_Ctxt_t *ctx, uint8_t *hashVal); +#endif + +/* + * When you initialize a Skein KCF hashing method you can pass this param + * structure in cm_param to fine-tune the algorithm's defaults. + */ +typedef struct skein_param { + size_t sp_digest_bitlen; /* length of digest in bits */ +} skein_param_t; + +/* Module definitions */ +#ifdef SKEIN_MODULE_IMPL +#define CKM_SKEIN_256 "CKM_SKEIN_256" +#define CKM_SKEIN_512 "CKM_SKEIN_512" +#define CKM_SKEIN1024 "CKM_SKEIN1024" +#define CKM_SKEIN_256_MAC "CKM_SKEIN_256_MAC" +#define CKM_SKEIN_512_MAC "CKM_SKEIN_512_MAC" +#define CKM_SKEIN1024_MAC "CKM_SKEIN1024_MAC" + +typedef enum skein_mech_type { + SKEIN_256_MECH_INFO_TYPE, + SKEIN_512_MECH_INFO_TYPE, + SKEIN1024_MECH_INFO_TYPE, + SKEIN_256_MAC_MECH_INFO_TYPE, + SKEIN_512_MAC_MECH_INFO_TYPE, + SKEIN1024_MAC_MECH_INFO_TYPE +} skein_mech_type_t; + +#define VALID_SKEIN_DIGEST_MECH(__mech) \ + ((int)(__mech) >= SKEIN_256_MECH_INFO_TYPE && \ + (__mech) <= SKEIN1024_MECH_INFO_TYPE) +#define VALID_SKEIN_MAC_MECH(__mech) \ + ((int)(__mech) >= SKEIN_256_MAC_MECH_INFO_TYPE && \ + (__mech) <= SKEIN1024_MAC_MECH_INFO_TYPE) +#endif /* SKEIN_MODULE_IMPL */ + +#ifdef __cplusplus +} +#endif + +#endif /* _SYS_SKEIN_H_ */ diff --git a/usr/src/uts/intel/Makefile.intel b/usr/src/uts/intel/Makefile.intel index 3b3ee0723d..9001670bf1 100644 --- a/usr/src/uts/intel/Makefile.intel +++ b/usr/src/uts/intel/Makefile.intel @@ -652,11 +652,13 @@ CRYPTO_KMODS += arcfour CRYPTO_KMODS += blowfish CRYPTO_KMODS += des CRYPTO_KMODS += ecc +CRYPTO_KMODS += edonr CRYPTO_KMODS += md4 CRYPTO_KMODS += md5 CRYPTO_KMODS += rsa CRYPTO_KMODS += sha1 CRYPTO_KMODS += sha2 +CRYPTO_KMODS += skein CRYPTO_KMODS += swrand # diff --git a/usr/src/uts/intel/edonr/Makefile b/usr/src/uts/intel/edonr/Makefile new file mode 100644 index 0000000000..90c1ad761e --- /dev/null +++ b/usr/src/uts/intel/edonr/Makefile @@ -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 +# +# +# Copyright 2013 Saso Kiselkov. All rights reserved. +# +# +# This makefile drives the production of the edonr kernel module. +# +# intel architecture dependent +# + +# +# Path to the base of the uts directory tree (usually /usr/src/uts). +# +UTSBASE = ../.. +COMDIR = $(COMMONBASE)/crypto + +# +# Define the module and object file sets. +# +MODULE = edonr +OBJECTS = $(EDONR_OBJS:%=$(OBJS_DIR)/%) +LINTS = $(EDONR_OBJS:%.o=$(LINTS_DIR)/%.ln) +ROOTMODULE = $(ROOT_CRYPTO_DIR)/$(MODULE) +ROOTLINK = $(ROOT_MISC_DIR)/$(MODULE) + +# +# Include common rules. +# +include $(UTSBASE)/intel/Makefile.intel + +# +# Define targets +# +ALL_TARGET = $(BINARY) +LINT_TARGET = $(MODULE).lint +INSTALL_TARGET = $(BINARY) $(ROOTMODULE) $(ROOTLINK) + +# +# Linkage dependencies +# +LDFLAGS += -dy -Nmisc/kcf + +CFLAGS += -I$(COMDIR) +LINTFLAGS += -I$(COMDIR) + +# +# Default build targets. +# +.KEEP_STATE: + +def: $(DEF_DEPS) + +all: $(ALL_DEPS) + +clean: $(CLEAN_DEPS) + +clobber: $(CLOBBER_DEPS) + +lint: $(LINT_DEPS) + +modlintlib: $(MODLINTLIB_DEPS) + +clean.lint: $(CLEAN_LINT_DEPS) + +install: $(INSTALL_DEPS) + +$(ROOTLINK): $(ROOT_MISC_DIR) $(ROOTMODULE) + -$(RM) $@; ln $(ROOTMODULE) $@ + +# +# Include common targets. +# +include $(UTSBASE)/intel/Makefile.targ diff --git a/usr/src/uts/intel/skein/Makefile b/usr/src/uts/intel/skein/Makefile new file mode 100644 index 0000000000..1028a97b80 --- /dev/null +++ b/usr/src/uts/intel/skein/Makefile @@ -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 +# +# +# Copyright 2013 Saso Kiselkov. All rights reserved. +# +# +# This makefile drives the production of the skein crypto kernel module. +# +# intel architecture dependent +# + +# +# Path to the base of the uts directory tree (usually /usr/src/uts). +# +UTSBASE = ../.. +COMDIR = $(COMMONBASE)/crypto + +# +# Define the module and object file sets. +# +MODULE = skein +OBJECTS = $(SKEIN_OBJS:%=$(OBJS_DIR)/%) +LINTS = $(SKEIN_OBJS:%.o=$(LINTS_DIR)/%.ln) +ROOTMODULE = $(ROOT_CRYPTO_DIR)/$(MODULE) +ROOTLINK = $(ROOT_MISC_DIR)/$(MODULE) + +# +# Include common rules. +# +include $(UTSBASE)/intel/Makefile.intel + +# +# Define targets +# +ALL_TARGET = $(BINARY) +LINT_TARGET = $(MODULE).lint +INSTALL_TARGET = $(BINARY) $(ROOTMODULE) $(ROOTLINK) + +# +# Linkage dependencies +# +LDFLAGS += -dy -Nmisc/kcf + +CFLAGS += -I$(COMDIR) +LINTFLAGS += -I$(COMDIR) + +# +# Default build targets. +# +.KEEP_STATE: + +def: $(DEF_DEPS) + +all: $(ALL_DEPS) + +clean: $(CLEAN_DEPS) + +clobber: $(CLOBBER_DEPS) + +lint: $(LINT_DEPS) + +modlintlib: $(MODLINTLIB_DEPS) + +clean.lint: $(CLEAN_LINT_DEPS) + +install: $(INSTALL_DEPS) + +$(ROOTLINK): $(ROOT_MISC_DIR) $(ROOTMODULE) + -$(RM) $@; ln $(ROOTMODULE) $@ + +# +# Include common targets. +# +include $(UTSBASE)/intel/Makefile.targ diff --git a/usr/src/uts/intel/zfs/Makefile b/usr/src/uts/intel/zfs/Makefile index be0f82115c..ea5e947b76 100644 --- a/usr/src/uts/intel/zfs/Makefile +++ b/usr/src/uts/intel/zfs/Makefile @@ -24,6 +24,9 @@ # # This makefile drives the production of the zfs file system # kernel module. +# +# Copyright 2013 Saso Kiselkov. All rights reserved. +# # # Path to the base of the uts directory tree (usually /usr/src/uts). @@ -58,7 +61,8 @@ INSTALL_TARGET = $(BINARY) $(ROOTMODULE) $(ROOTLINK) $(ROOT_CONFFILE) # Overrides and depends_on # MODSTUBS_DIR = $(OBJS_DIR) -LDFLAGS += -dy -Nfs/specfs -Ncrypto/swrand -Nmisc/idmap -Nmisc/sha2 +LDFLAGS += -dy -Nfs/specfs -Ncrypto/swrand -Nmisc/idmap -Nmisc/sha2 \ + -Nmisc/skein -Nmisc/edonr INC_PATH += -I$(UTSBASE)/common/fs/zfs INC_PATH += -I$(SRC)/common diff --git a/usr/src/uts/sparc/Makefile.sparc b/usr/src/uts/sparc/Makefile.sparc index a42fa0be04..3a4a3f9c8b 100644 --- a/usr/src/uts/sparc/Makefile.sparc +++ b/usr/src/uts/sparc/Makefile.sparc @@ -429,12 +429,14 @@ CRYPTO_KMODS += aes CRYPTO_KMODS += arcfour CRYPTO_KMODS += blowfish CRYPTO_KMODS += des +CRYPTO_KMODS += ecc +CRYPTO_KMODS += edonr CRYPTO_KMODS += md4 CRYPTO_KMODS += md5 -CRYPTO_KMODS += ecc CRYPTO_KMODS += rsa CRYPTO_KMODS += sha1 CRYPTO_KMODS += sha2 +CRYPTO_KMODS += skein CRYPTO_KMODS += swrand # diff --git a/usr/src/uts/sparc/edonr/Makefile b/usr/src/uts/sparc/edonr/Makefile new file mode 100644 index 0000000000..b0c6eb0f8c --- /dev/null +++ b/usr/src/uts/sparc/edonr/Makefile @@ -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 +# +# +# Copyright 2013 Saso Kiselkov. All rights reserved. +# +# +# This makefile drives the production of the edonr kernel module. +# +# sparc architecture dependent +# + +# +# Path to the base of the uts directory tree (usually /usr/src/uts). +# +UTSBASE = ../.. +COMDIR = $(COMMONBASE)/crypto + +# +# Define the module and object file sets. +# +MODULE = edonr +OBJECTS = $(EDONR_OBJS:%=$(OBJS_DIR)/%) +LINTS = $(EDONR_OBJS:%.o=$(LINTS_DIR)/%.ln) +ROOTMODULE = $(ROOT_CRYPTO_DIR)/$(MODULE) +ROOTLINK = $(ROOT_MISC_DIR)/$(MODULE) + +# +# Include common rules. +# +include $(UTSBASE)/sparc/Makefile.sparc + +# +# Define targets +# +ALL_TARGET = $(BINARY) +LINT_TARGET = $(MODULE).lint +INSTALL_TARGET = $(BINARY) $(ROOTMODULE) $(ROOTLINK) + +# +# Linkage dependencies +# +LDFLAGS += -dy -Nmisc/kcf + +CFLAGS += -I$(COMDIR) +LINTFLAGS += -I$(COMDIR) + +# +# Default build targets. +# +.KEEP_STATE: + +def: $(DEF_DEPS) + +all: $(ALL_DEPS) + +clean: $(CLEAN_DEPS) + +clobber: $(CLOBBER_DEPS) + +lint: $(LINT_DEPS) + +modlintlib: $(MODLINTLIB_DEPS) + +clean.lint: $(CLEAN_LINT_DEPS) + +install: $(INSTALL_DEPS) + +$(ROOTLINK): $(ROOT_MISC_DIR) $(ROOTMODULE) + -$(RM) $@; ln $(ROOTMODULE) $@ + +# +# Include common targets. +# +include $(UTSBASE)/sparc/Makefile.targ diff --git a/usr/src/uts/sparc/skein/Makefile b/usr/src/uts/sparc/skein/Makefile new file mode 100644 index 0000000000..6f1b4ecfab --- /dev/null +++ b/usr/src/uts/sparc/skein/Makefile @@ -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 +# +# +# Copyright 2013 Saso Kiselkov. All rights reserved. +# +# +# This makefile drives the production of the skein crypto kernel module. +# +# sparc architecture dependent +# + +# +# Path to the base of the uts directory tree (usually /usr/src/uts). +# +UTSBASE = ../.. +COMDIR = $(COMMONBASE)/crypto + +# +# Define the module and object file sets. +# +MODULE = skein +OBJECTS = $(SKEIN_OBJS:%=$(OBJS_DIR)/%) +LINTS = $(SKEIN_OBJS:%.o=$(LINTS_DIR)/%.ln) +ROOTMODULE = $(ROOT_CRYPTO_DIR)/$(MODULE) +ROOTLINK = $(ROOT_MISC_DIR)/$(MODULE) + +# +# Include common rules. +# +include $(UTSBASE)/sparc/Makefile.sparc + +# +# Define targets +# +ALL_TARGET = $(BINARY) +LINT_TARGET = $(MODULE).lint +INSTALL_TARGET = $(BINARY) $(ROOTMODULE) $(ROOTLINK) + +# +# Linkage dependencies +# +LDFLAGS += -dy -Nmisc/kcf + +CFLAGS += -I$(COMDIR) +LINTFLAGS += -I$(COMDIR) + +# +# Default build targets. +# +.KEEP_STATE: + +def: $(DEF_DEPS) + +all: $(ALL_DEPS) + +clean: $(CLEAN_DEPS) + +clobber: $(CLOBBER_DEPS) + +lint: $(LINT_DEPS) + +modlintlib: $(MODLINTLIB_DEPS) + +clean.lint: $(CLEAN_LINT_DEPS) + +install: $(INSTALL_DEPS) + +$(ROOTLINK): $(ROOT_MISC_DIR) $(ROOTMODULE) + -$(RM) $@; ln $(ROOTMODULE) $@ + +# +# Include common targets. +# +include $(UTSBASE)/sparc/Makefile.targ diff --git a/usr/src/uts/sparc/zfs/Makefile b/usr/src/uts/sparc/zfs/Makefile index b891e4fae1..8d6d25df5e 100644 --- a/usr/src/uts/sparc/zfs/Makefile +++ b/usr/src/uts/sparc/zfs/Makefile @@ -24,6 +24,9 @@ # # This makefile drives the production of the zfs file system # kernel module. +# +# Copyright 2013 Saso Kiselkov. All rights reserved. +# # # Path to the base of the uts directory tree (usually /usr/src/uts). @@ -62,7 +65,7 @@ INSTALL_TARGET = $(BINARY) $(ROOTMODULE) $(ROOTLINK) $(ROOT_CONFFILE) # MODSTUBS_DIR = $(OBJS_DIR) LDFLAGS += -dy -Nfs/specfs -Ncrypto/swrand -Nmisc/idmap \ - -Nsched/SDC -Nmisc/sha2 + -Nsched/SDC -Nmisc/sha2 -Nmisc/skein -Nmisc/edonr INC_PATH += -I$(UTSBASE)/common/fs/zfs INC_PATH += -I$(SRC)/common -- cgit v1.2.3 From be32284091554a41d4706e6653adeec1d9127a87 Mon Sep 17 00:00:00 2001 From: Robert Mustacchi Date: Wed, 16 Sep 2015 10:29:32 -0700 Subject: 4185 add new cryptographic checksums to ZFS: SHA-512, Skein, Edon-R (fix studio build) --- usr/src/uts/common/crypto/io/skein_mod.c | 12 +++++++----- 1 file changed, 7 insertions(+), 5 deletions(-) (limited to 'usr/src/uts') diff --git a/usr/src/uts/common/crypto/io/skein_mod.c b/usr/src/uts/common/crypto/io/skein_mod.c index aca7582dcb..49ad9cb0c7 100644 --- a/usr/src/uts/common/crypto/io/skein_mod.c +++ b/usr/src/uts/common/crypto/io/skein_mod.c @@ -158,12 +158,11 @@ static crypto_kcf_provider_handle_t skein_prov_handle = NULL; typedef struct skein_ctx { skein_mech_type_t sc_mech_type; size_t sc_digest_bitlen; - /*LINTED(E_ANONYMOUS_UNION_DECL)*/ union { Skein_256_Ctxt_t sc_256; Skein_512_Ctxt_t sc_512; Skein1024_Ctxt_t sc_1024; - }; + } sc_u; } skein_ctx_t; #define SKEIN_CTX(_ctx_) ((skein_ctx_t *)((_ctx_)->cc_provider_private)) #define SKEIN_CTX_LVALUE(_ctx_) (_ctx_)->cc_provider_private @@ -173,15 +172,18 @@ typedef struct skein_ctx { switch (sc->sc_mech_type) { \ case SKEIN_256_MECH_INFO_TYPE: \ case SKEIN_256_MAC_MECH_INFO_TYPE: \ - (void) Skein_256_ ## _op(&sc->sc_256, __VA_ARGS__);\ + (void) Skein_256_ ## _op(&sc->sc_u.sc_256, \ + __VA_ARGS__); \ break; \ case SKEIN_512_MECH_INFO_TYPE: \ case SKEIN_512_MAC_MECH_INFO_TYPE: \ - (void) Skein_512_ ## _op(&sc->sc_512, __VA_ARGS__);\ + (void) Skein_512_ ## _op(&sc->sc_u.sc_512, \ + __VA_ARGS__); \ break; \ case SKEIN1024_MECH_INFO_TYPE: \ case SKEIN1024_MAC_MECH_INFO_TYPE: \ - (void) Skein1024_ ## _op(&sc->sc_1024, __VA_ARGS__);\ + (void) Skein1024_ ## _op(&sc->sc_u.sc_1024, \ + __VA_ARGS__); \ break; \ } \ _NOTE(CONSTCOND) \ -- cgit v1.2.3 From 03bad06fbb261fd4a7151a70dfeff2f5041cce1f Mon Sep 17 00:00:00 2001 From: Justin Gibbs Date: Thu, 17 Sep 2015 08:05:51 -0400 Subject: 6171 dsl_prop_unregister() slows down dataset eviction. Reviewed by: Matthew Ahrens Reviewed by: Prakash Surya Approved by: Dan McDonald --- usr/src/uts/common/fs/zfs/dmu_objset.c | 36 +---- usr/src/uts/common/fs/zfs/dsl_dataset.c | 4 + usr/src/uts/common/fs/zfs/dsl_dir.c | 12 +- usr/src/uts/common/fs/zfs/dsl_prop.c | 233 +++++++++++++++++----------- usr/src/uts/common/fs/zfs/sys/dsl_dataset.h | 3 + usr/src/uts/common/fs/zfs/sys/dsl_dir.h | 2 +- usr/src/uts/common/fs/zfs/sys/dsl_prop.h | 16 +- usr/src/uts/common/fs/zfs/zfs_vfsops.c | 69 +------- 8 files changed, 171 insertions(+), 204 deletions(-) (limited to 'usr/src/uts') diff --git a/usr/src/uts/common/fs/zfs/dmu_objset.c b/usr/src/uts/common/fs/zfs/dmu_objset.c index 9ad18f0d11..f84ff378c9 100644 --- a/usr/src/uts/common/fs/zfs/dmu_objset.c +++ b/usr/src/uts/common/fs/zfs/dmu_objset.c @@ -680,40 +680,8 @@ dmu_objset_evict(objset_t *os) for (int t = 0; t < TXG_SIZE; t++) ASSERT(!dmu_objset_is_dirty(os, t)); - if (ds) { - if (!ds->ds_is_snapshot) { - VERIFY0(dsl_prop_unregister(ds, - zfs_prop_to_name(ZFS_PROP_CHECKSUM), - checksum_changed_cb, os)); - VERIFY0(dsl_prop_unregister(ds, - zfs_prop_to_name(ZFS_PROP_COMPRESSION), - compression_changed_cb, os)); - VERIFY0(dsl_prop_unregister(ds, - zfs_prop_to_name(ZFS_PROP_COPIES), - copies_changed_cb, os)); - VERIFY0(dsl_prop_unregister(ds, - zfs_prop_to_name(ZFS_PROP_DEDUP), - dedup_changed_cb, os)); - VERIFY0(dsl_prop_unregister(ds, - zfs_prop_to_name(ZFS_PROP_LOGBIAS), - logbias_changed_cb, os)); - VERIFY0(dsl_prop_unregister(ds, - zfs_prop_to_name(ZFS_PROP_SYNC), - sync_changed_cb, os)); - VERIFY0(dsl_prop_unregister(ds, - zfs_prop_to_name(ZFS_PROP_REDUNDANT_METADATA), - redundant_metadata_changed_cb, os)); - VERIFY0(dsl_prop_unregister(ds, - zfs_prop_to_name(ZFS_PROP_RECORDSIZE), - recordsize_changed_cb, os)); - } - VERIFY0(dsl_prop_unregister(ds, - zfs_prop_to_name(ZFS_PROP_PRIMARYCACHE), - primary_cache_changed_cb, os)); - VERIFY0(dsl_prop_unregister(ds, - zfs_prop_to_name(ZFS_PROP_SECONDARYCACHE), - secondary_cache_changed_cb, os)); - } + if (ds) + dsl_prop_unregister_all(ds, os); if (os->os_sa) sa_tear_down(os); diff --git a/usr/src/uts/common/fs/zfs/dsl_dataset.c b/usr/src/uts/common/fs/zfs/dsl_dataset.c index 17d9927974..8f9e26bc16 100644 --- a/usr/src/uts/common/fs/zfs/dsl_dataset.c +++ b/usr/src/uts/common/fs/zfs/dsl_dataset.c @@ -290,6 +290,7 @@ dsl_dataset_evict(void *dbu) ASSERT(!list_link_active(&ds->ds_synced_link)); + list_destroy(&ds->ds_prop_cbs); mutex_destroy(&ds->ds_lock); mutex_destroy(&ds->ds_opening_lock); mutex_destroy(&ds->ds_sendstream_lock); @@ -432,6 +433,9 @@ dsl_dataset_hold_obj(dsl_pool_t *dp, uint64_t dsobj, void *tag, list_create(&ds->ds_sendstreams, sizeof (dmu_sendarg_t), offsetof(dmu_sendarg_t, dsa_link)); + list_create(&ds->ds_prop_cbs, sizeof (dsl_prop_cb_record_t), + offsetof(dsl_prop_cb_record_t, cbr_ds_node)); + if (doi.doi_type == DMU_OTN_ZAP_METADATA) { for (spa_feature_t f = 0; f < SPA_FEATURES; f++) { if (!(spa_feature_table[f].fi_flags & diff --git a/usr/src/uts/common/fs/zfs/dsl_dir.c b/usr/src/uts/common/fs/zfs/dsl_dir.c index 6a20ab3ca2..7d86f72ad1 100644 --- a/usr/src/uts/common/fs/zfs/dsl_dir.c +++ b/usr/src/uts/common/fs/zfs/dsl_dir.c @@ -147,11 +147,7 @@ dsl_dir_evict(void *dbu) spa_async_close(dd->dd_pool->dp_spa, dd); - /* - * The props callback list should have been cleaned up by - * objset_evict(). - */ - list_destroy(&dd->dd_prop_cbs); + dsl_prop_fini(dd); mutex_destroy(&dd->dd_lock); kmem_free(dd, sizeof (dsl_dir_t)); } @@ -186,9 +182,7 @@ dsl_dir_hold_obj(dsl_pool_t *dp, uint64_t ddobj, dd->dd_dbuf = dbuf; dd->dd_pool = dp; mutex_init(&dd->dd_lock, NULL, MUTEX_DEFAULT, NULL); - - list_create(&dd->dd_prop_cbs, sizeof (dsl_prop_cb_record_t), - offsetof(dsl_prop_cb_record_t, cbr_node)); + dsl_prop_init(dd); dsl_dir_snap_cmtime_update(dd); @@ -246,6 +240,7 @@ dsl_dir_hold_obj(dsl_pool_t *dp, uint64_t ddobj, if (winner != NULL) { if (dd->dd_parent) dsl_dir_rele(dd->dd_parent, dd); + dsl_prop_fini(dd); mutex_destroy(&dd->dd_lock); kmem_free(dd, sizeof (dsl_dir_t)); dd = winner; @@ -273,6 +268,7 @@ dsl_dir_hold_obj(dsl_pool_t *dp, uint64_t ddobj, errout: if (dd->dd_parent) dsl_dir_rele(dd->dd_parent, dd); + dsl_prop_fini(dd); mutex_destroy(&dd->dd_lock); kmem_free(dd, sizeof (dsl_dir_t)); dmu_buf_rele(dbuf, tag); diff --git a/usr/src/uts/common/fs/zfs/dsl_prop.c b/usr/src/uts/common/fs/zfs/dsl_prop.c index 09eec21604..353de42d1e 100644 --- a/usr/src/uts/common/fs/zfs/dsl_prop.c +++ b/usr/src/uts/common/fs/zfs/dsl_prop.c @@ -216,6 +216,58 @@ dsl_prop_get_ds(dsl_dataset_t *ds, const char *propname, intsz, numints, buf, setpoint, ds->ds_is_snapshot)); } +static dsl_prop_record_t * +dsl_prop_record_find(dsl_dir_t *dd, const char *propname) +{ + dsl_prop_record_t *pr = NULL; + + ASSERT(MUTEX_HELD(&dd->dd_lock)); + + for (pr = list_head(&dd->dd_props); + pr != NULL; pr = list_next(&dd->dd_props, pr)) { + if (strcmp(pr->pr_propname, propname) == 0) + break; + } + + return (pr); +} + +static dsl_prop_record_t * +dsl_prop_record_create(dsl_dir_t *dd, const char *propname) +{ + dsl_prop_record_t *pr; + + ASSERT(MUTEX_HELD(&dd->dd_lock)); + + pr = kmem_alloc(sizeof (dsl_prop_record_t), KM_SLEEP); + pr->pr_propname = spa_strdup(propname); + list_create(&pr->pr_cbs, sizeof (dsl_prop_cb_record_t), + offsetof(dsl_prop_cb_record_t, cbr_pr_node)); + list_insert_head(&dd->dd_props, pr); + + return (pr); +} + +void +dsl_prop_init(dsl_dir_t *dd) +{ + list_create(&dd->dd_props, sizeof (dsl_prop_record_t), + offsetof(dsl_prop_record_t, pr_node)); +} + +void +dsl_prop_fini(dsl_dir_t *dd) +{ + dsl_prop_record_t *pr; + + while ((pr = list_remove_head(&dd->dd_props)) != NULL) { + list_destroy(&pr->pr_cbs); + strfree((char *)pr->pr_propname); + kmem_free(pr, sizeof (dsl_prop_record_t)); + } + list_destroy(&dd->dd_props); +} + /* * Register interest in the named property. We'll call the callback * once to notify it of the current property value, and again each time @@ -230,6 +282,7 @@ dsl_prop_register(dsl_dataset_t *ds, const char *propname, dsl_dir_t *dd = ds->ds_dir; dsl_pool_t *dp = dd->dd_pool; uint64_t value; + dsl_prop_record_t *pr; dsl_prop_cb_record_t *cbr; int err; @@ -241,12 +294,16 @@ dsl_prop_register(dsl_dataset_t *ds, const char *propname, cbr = kmem_alloc(sizeof (dsl_prop_cb_record_t), KM_SLEEP); cbr->cbr_ds = ds; - cbr->cbr_propname = kmem_alloc(strlen(propname)+1, KM_SLEEP); - (void) strcpy((char *)cbr->cbr_propname, propname); cbr->cbr_func = callback; cbr->cbr_arg = cbarg; + mutex_enter(&dd->dd_lock); - list_insert_head(&dd->dd_prop_cbs, cbr); + pr = dsl_prop_record_find(dd, propname); + if (pr == NULL) + pr = dsl_prop_record_create(dd, propname); + cbr->cbr_pr = pr; + list_insert_head(&pr->pr_cbs, cbr); + list_insert_head(&ds->ds_prop_cbs, cbr); mutex_exit(&dd->dd_lock); cbr->cbr_func(cbr->cbr_arg, value); @@ -377,56 +434,34 @@ dsl_prop_predict(dsl_dir_t *dd, const char *propname, } /* - * Unregister this callback. Return 0 on success, ENOENT if ddname is - * invalid, or ENOMSG if no matching callback registered. + * Unregister all callbacks that are registered with the + * given callback argument. */ -int -dsl_prop_unregister(dsl_dataset_t *ds, const char *propname, - dsl_prop_changed_cb_t *callback, void *cbarg) +void +dsl_prop_unregister_all(dsl_dataset_t *ds, void *cbarg) { + dsl_prop_cb_record_t *cbr, *next_cbr; + dsl_dir_t *dd = ds->ds_dir; - dsl_prop_cb_record_t *cbr; mutex_enter(&dd->dd_lock); - for (cbr = list_head(&dd->dd_prop_cbs); - cbr; cbr = list_next(&dd->dd_prop_cbs, cbr)) { - if (cbr->cbr_ds == ds && - cbr->cbr_func == callback && - cbr->cbr_arg == cbarg && - strcmp(cbr->cbr_propname, propname) == 0) - break; - } - - if (cbr == NULL) { - mutex_exit(&dd->dd_lock); - return (SET_ERROR(ENOMSG)); + next_cbr = list_head(&ds->ds_prop_cbs); + while (next_cbr != NULL) { + cbr = next_cbr; + next_cbr = list_next(&ds->ds_prop_cbs, cbr); + if (cbr->cbr_arg == cbarg) { + list_remove(&ds->ds_prop_cbs, cbr); + list_remove(&cbr->cbr_pr->pr_cbs, cbr); + kmem_free(cbr, sizeof (dsl_prop_cb_record_t)); + } } - - list_remove(&dd->dd_prop_cbs, cbr); mutex_exit(&dd->dd_lock); - kmem_free((void*)cbr->cbr_propname, strlen(cbr->cbr_propname)+1); - kmem_free(cbr, sizeof (dsl_prop_cb_record_t)); - - return (0); } boolean_t dsl_prop_hascb(dsl_dataset_t *ds) { - dsl_dir_t *dd = ds->ds_dir; - boolean_t rv = B_FALSE; - dsl_prop_cb_record_t *cbr; - - mutex_enter(&dd->dd_lock); - for (cbr = list_head(&dd->dd_prop_cbs); cbr; - cbr = list_next(&dd->dd_prop_cbs, cbr)) { - if (cbr->cbr_ds == ds) { - rv = B_TRUE; - break; - } - } - mutex_exit(&dd->dd_lock); - return (rv); + return (!list_is_empty(&ds->ds_prop_cbs)); } /* ARGSUSED */ @@ -434,38 +469,50 @@ static int dsl_prop_notify_all_cb(dsl_pool_t *dp, dsl_dataset_t *ds, void *arg) { dsl_dir_t *dd = ds->ds_dir; + dsl_prop_record_t *pr; dsl_prop_cb_record_t *cbr; mutex_enter(&dd->dd_lock); - for (cbr = list_head(&dd->dd_prop_cbs); cbr; - cbr = list_next(&dd->dd_prop_cbs, cbr)) { - uint64_t value; + for (pr = list_head(&dd->dd_props); + pr; pr = list_next(&dd->dd_props, pr)) { + for (cbr = list_head(&pr->pr_cbs); cbr; + cbr = list_next(&pr->pr_cbs, cbr)) { + uint64_t value; - /* - * Callback entries do not have holds on their datasets - * so that datasets with registered callbacks are still - * eligible for eviction. Unlike operations on callbacks - * for a single dataset, we are performing a recursive - * descent of related datasets and the calling context - * for this iteration only has a dataset hold on the root. - * Without a hold, the callback's pointer to the dataset - * could be invalidated by eviction at any time. - * - * Use dsl_dataset_try_add_ref() to verify that the - * dataset has not begun eviction processing and to - * prevent eviction from occurring for the duration - * of the callback. If the hold attempt fails, this - * object is already being evicted and the callback can - * be safely ignored. - */ - if (!dsl_dataset_try_add_ref(dp, cbr->cbr_ds, FTAG)) - continue; + /* + * Callback entries do not have holds on their + * datasets so that datasets with registered + * callbacks are still eligible for eviction. + * Unlike operations to update properties on a + * single dataset, we are performing a recursive + * descent of related head datasets. The caller + * of this function only has a dataset hold on + * the passed in head dataset, not the snapshots + * associated with this dataset. Without a hold, + * the dataset pointer within callback records + * for snapshots can be invalidated by eviction + * at any time. + * + * Use dsl_dataset_try_add_ref() to verify + * that the dataset for a snapshot has not + * begun eviction processing and to prevent + * eviction from occurring for the duration of + * the callback. If the hold attempt fails, + * this object is already being evicted and the + * callback can be safely ignored. + */ + if (ds != cbr->cbr_ds && + !dsl_dataset_try_add_ref(dp, cbr->cbr_ds, FTAG)) + continue; - if (dsl_prop_get_ds(cbr->cbr_ds, cbr->cbr_propname, - sizeof (value), 1, &value, NULL) == 0) - cbr->cbr_func(cbr->cbr_arg, value); + if (dsl_prop_get_ds(cbr->cbr_ds, + cbr->cbr_pr->pr_propname, sizeof (value), 1, + &value, NULL) == 0) + cbr->cbr_func(cbr->cbr_arg, value); - dsl_dataset_rele(cbr->cbr_ds, FTAG); + if (ds != cbr->cbr_ds) + dsl_dataset_rele(cbr->cbr_ds, FTAG); + } } mutex_exit(&dd->dd_lock); @@ -490,6 +537,7 @@ dsl_prop_changed_notify(dsl_pool_t *dp, uint64_t ddobj, const char *propname, uint64_t value, int first) { dsl_dir_t *dd; + dsl_prop_record_t *pr; dsl_prop_cb_record_t *cbr; objset_t *mos = dp->dp_meta_objset; zap_cursor_t zc; @@ -516,30 +564,33 @@ dsl_prop_changed_notify(dsl_pool_t *dp, uint64_t ddobj, } mutex_enter(&dd->dd_lock); - for (cbr = list_head(&dd->dd_prop_cbs); cbr; - cbr = list_next(&dd->dd_prop_cbs, cbr)) { - uint64_t propobj; + pr = dsl_prop_record_find(dd, propname); + if (pr != NULL) { + for (cbr = list_head(&pr->pr_cbs); cbr; + cbr = list_next(&pr->pr_cbs, cbr)) { + uint64_t propobj; - /* - * cbr->cbf_ds may be invalidated due to eviction, - * requiring the use of dsl_dataset_try_add_ref(). - * See comment block in dsl_prop_notify_all_cb() - * for details. - */ - if (strcmp(cbr->cbr_propname, propname) != 0 || - !dsl_dataset_try_add_ref(dp, cbr->cbr_ds, FTAG)) - continue; + /* + * cbr->cbr_ds may be invalidated due to eviction, + * requiring the use of dsl_dataset_try_add_ref(). + * See comment block in dsl_prop_notify_all_cb() + * for details. + */ + if (!dsl_dataset_try_add_ref(dp, cbr->cbr_ds, FTAG)) + continue; - propobj = dsl_dataset_phys(cbr->cbr_ds)->ds_props_obj; + propobj = dsl_dataset_phys(cbr->cbr_ds)->ds_props_obj; - /* - * If the property is not set on this ds, then it is - * inherited here; call the callback. - */ - if (propobj == 0 || zap_contains(mos, propobj, propname) != 0) - cbr->cbr_func(cbr->cbr_arg, value); + /* + * If the property is not set on this ds, then it is + * inherited here; call the callback. + */ + if (propobj == 0 || + zap_contains(mos, propobj, propname) != 0) + cbr->cbr_func(cbr->cbr_arg, value); - dsl_dataset_rele(cbr->cbr_ds, FTAG); + dsl_dataset_rele(cbr->cbr_ds, FTAG); + } } mutex_exit(&dd->dd_lock); @@ -679,10 +730,10 @@ dsl_prop_set_sync_impl(dsl_dataset_t *ds, const char *propname, * ds here. */ mutex_enter(&ds->ds_dir->dd_lock); - for (cbr = list_head(&ds->ds_dir->dd_prop_cbs); cbr; - cbr = list_next(&ds->ds_dir->dd_prop_cbs, cbr)) { - if (cbr->cbr_ds == ds && - strcmp(cbr->cbr_propname, propname) == 0) + for (cbr = list_head(&ds->ds_prop_cbs); cbr; + cbr = list_next(&ds->ds_prop_cbs, cbr)) { + if (strcmp(cbr->cbr_pr->pr_propname, + propname) == 0) cbr->cbr_func(cbr->cbr_arg, intval); } mutex_exit(&ds->ds_dir->dd_lock); diff --git a/usr/src/uts/common/fs/zfs/sys/dsl_dataset.h b/usr/src/uts/common/fs/zfs/sys/dsl_dataset.h index 001bff566a..c9cd5890aa 100644 --- a/usr/src/uts/common/fs/zfs/sys/dsl_dataset.h +++ b/usr/src/uts/common/fs/zfs/sys/dsl_dataset.h @@ -184,6 +184,9 @@ typedef struct dsl_dataset { kmutex_t ds_sendstream_lock; list_t ds_sendstreams; + /* Protected by our dsl_dir's dd_lock */ + list_t ds_prop_cbs; + /* * For ZFEATURE_FLAG_PER_DATASET features, set if this dataset * uses this feature. diff --git a/usr/src/uts/common/fs/zfs/sys/dsl_dir.h b/usr/src/uts/common/fs/zfs/sys/dsl_dir.h index f50014d95a..93fb73f37e 100644 --- a/usr/src/uts/common/fs/zfs/sys/dsl_dir.h +++ b/usr/src/uts/common/fs/zfs/sys/dsl_dir.h @@ -102,7 +102,7 @@ struct dsl_dir { /* Protected by dd_lock */ kmutex_t dd_lock; - list_t dd_prop_cbs; /* list of dsl_prop_cb_record_t's */ + list_t dd_props; /* list of dsl_prop_record_t's */ timestruc_t dd_snap_cmtime; /* last time snapshot namespace changed */ uint64_t dd_origin_txg; diff --git a/usr/src/uts/common/fs/zfs/sys/dsl_prop.h b/usr/src/uts/common/fs/zfs/sys/dsl_prop.h index 5fe18d6a7c..21e6f4674b 100644 --- a/usr/src/uts/common/fs/zfs/sys/dsl_prop.h +++ b/usr/src/uts/common/fs/zfs/sys/dsl_prop.h @@ -41,10 +41,17 @@ struct dsl_dir; /* The callback func may not call into the DMU or DSL! */ typedef void (dsl_prop_changed_cb_t)(void *arg, uint64_t newval); +typedef struct dsl_prop_record { + list_node_t pr_node; /* link on dd_props */ + const char *pr_propname; + list_t pr_cbs; +} dsl_prop_record_t; + typedef struct dsl_prop_cb_record { - list_node_t cbr_node; /* link on dd_prop_cbs */ + list_node_t cbr_pr_node; /* link on pr_cbs */ + list_node_t cbr_ds_node; /* link on ds_prop_cbs */ + dsl_prop_record_t *cbr_pr; struct dsl_dataset *cbr_ds; - const char *cbr_propname; dsl_prop_changed_cb_t *cbr_func; void *cbr_arg; } dsl_prop_cb_record_t; @@ -54,10 +61,11 @@ typedef struct dsl_props_arg { zprop_source_t pa_source; } dsl_props_arg_t; +void dsl_prop_init(dsl_dir_t *dd); +void dsl_prop_fini(dsl_dir_t *dd); int dsl_prop_register(struct dsl_dataset *ds, const char *propname, dsl_prop_changed_cb_t *callback, void *cbarg); -int dsl_prop_unregister(struct dsl_dataset *ds, const char *propname, - dsl_prop_changed_cb_t *callback, void *cbarg); +void dsl_prop_unregister_all(struct dsl_dataset *ds, void *cbarg); void dsl_prop_notify_all(struct dsl_dir *dd); boolean_t dsl_prop_hascb(struct dsl_dataset *ds); diff --git a/usr/src/uts/common/fs/zfs/zfs_vfsops.c b/usr/src/uts/common/fs/zfs/zfs_vfsops.c index 3559b9b7b3..712ac895a7 100644 --- a/usr/src/uts/common/fs/zfs/zfs_vfsops.c +++ b/usr/src/uts/common/fs/zfs/zfs_vfsops.c @@ -561,33 +561,7 @@ zfs_register_callbacks(vfs_t *vfsp) return (0); unregister: - /* - * We may attempt to unregister some callbacks that are not - * registered, but this is OK; it will simply return ENOMSG, - * which we will ignore. - */ - (void) dsl_prop_unregister(ds, zfs_prop_to_name(ZFS_PROP_ATIME), - atime_changed_cb, zfsvfs); - (void) dsl_prop_unregister(ds, zfs_prop_to_name(ZFS_PROP_XATTR), - xattr_changed_cb, zfsvfs); - (void) dsl_prop_unregister(ds, zfs_prop_to_name(ZFS_PROP_RECORDSIZE), - blksz_changed_cb, zfsvfs); - (void) dsl_prop_unregister(ds, zfs_prop_to_name(ZFS_PROP_READONLY), - readonly_changed_cb, zfsvfs); - (void) dsl_prop_unregister(ds, zfs_prop_to_name(ZFS_PROP_DEVICES), - devices_changed_cb, zfsvfs); - (void) dsl_prop_unregister(ds, zfs_prop_to_name(ZFS_PROP_SETUID), - setuid_changed_cb, zfsvfs); - (void) dsl_prop_unregister(ds, zfs_prop_to_name(ZFS_PROP_EXEC), - exec_changed_cb, zfsvfs); - (void) dsl_prop_unregister(ds, zfs_prop_to_name(ZFS_PROP_SNAPDIR), - snapdir_changed_cb, zfsvfs); - (void) dsl_prop_unregister(ds, zfs_prop_to_name(ZFS_PROP_ACLMODE), - acl_mode_changed_cb, zfsvfs); - (void) dsl_prop_unregister(ds, zfs_prop_to_name(ZFS_PROP_ACLINHERIT), - acl_inherit_changed_cb, zfsvfs); - (void) dsl_prop_unregister(ds, zfs_prop_to_name(ZFS_PROP_VSCAN), - vscan_changed_cb, zfsvfs); + dsl_prop_unregister_all(ds, zfsvfs); return (error); } @@ -1249,46 +1223,9 @@ void zfs_unregister_callbacks(zfsvfs_t *zfsvfs) { objset_t *os = zfsvfs->z_os; - struct dsl_dataset *ds; - - /* - * Unregister properties. - */ - if (!dmu_objset_is_snapshot(os)) { - ds = dmu_objset_ds(os); - VERIFY(dsl_prop_unregister(ds, "atime", atime_changed_cb, - zfsvfs) == 0); - - VERIFY(dsl_prop_unregister(ds, "xattr", xattr_changed_cb, - zfsvfs) == 0); - - VERIFY(dsl_prop_unregister(ds, "recordsize", blksz_changed_cb, - zfsvfs) == 0); - VERIFY(dsl_prop_unregister(ds, "readonly", readonly_changed_cb, - zfsvfs) == 0); - - VERIFY(dsl_prop_unregister(ds, "devices", devices_changed_cb, - zfsvfs) == 0); - - VERIFY(dsl_prop_unregister(ds, "setuid", setuid_changed_cb, - zfsvfs) == 0); - - VERIFY(dsl_prop_unregister(ds, "exec", exec_changed_cb, - zfsvfs) == 0); - - VERIFY(dsl_prop_unregister(ds, "snapdir", snapdir_changed_cb, - zfsvfs) == 0); - - VERIFY(dsl_prop_unregister(ds, "aclmode", acl_mode_changed_cb, - zfsvfs) == 0); - - VERIFY(dsl_prop_unregister(ds, "aclinherit", - acl_inherit_changed_cb, zfsvfs) == 0); - - VERIFY(dsl_prop_unregister(ds, "vscan", - vscan_changed_cb, zfsvfs) == 0); - } + if (!dmu_objset_is_snapshot(os)) + dsl_prop_unregister_all(dmu_objset_ds(os), zfsvfs); } /* -- cgit v1.2.3