mirror of
https://github.com/freebsd/freebsd-src
synced 2024-09-06 17:18:32 +00:00
MFV r289310:
4185 add new cryptographic checksums to ZFS: SHA-512, Skein, Edon-R Reviewed by: George Wilson <george.wilson@delphix.com> Reviewed by: Prakash Surya <prakash.surya@delphix.com> Reviewed by: Saso Kiselkov <saso.kiselkov@nexenta.com> Reviewed by: Richard Lowe <richlowe@richlowe.net> Approved by: Garrett D'Amore <garrett@damore.org> Author: Matthew Ahrens <mahrens@delphix.com> illumos/illumos-gate@45818ee124 This is only a partial merge of respective ZFS infrastructure changes. At this moment FreeBSD kernel has no those crypto algorithms, so the parts of the code to enable them are commented out. When they are implemented, it will be trivial to plug them in.
This commit is contained in:
commit
43f774f296
Notes:
svn2git
2020-12-20 02:59:44 +00:00
svn path=/head/; revision=289422
|
@ -1493,6 +1493,12 @@ zfs_setprop_error(libzfs_handle_t *hdl, zfs_prop_t prop, int err,
|
|||
"property setting is not allowed on "
|
||||
"bootable datasets"));
|
||||
(void) zfs_error(hdl, EZFS_NOTSUP, errbuf);
|
||||
} else if (prop == ZFS_PROP_CHECKSUM ||
|
||||
prop == ZFS_PROP_DEDUP) {
|
||||
(void) zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,
|
||||
"property setting is not allowed on "
|
||||
"root pools"));
|
||||
(void) zfs_error(hdl, EZFS_NOTSUP, errbuf);
|
||||
} else {
|
||||
(void) zfs_standard_error(hdl, err, errbuf);
|
||||
}
|
||||
|
|
|
@ -1423,7 +1423,7 @@ zfs_send_resume_token_to_nvlist(libzfs_handle_t *hdl, const char *token)
|
|||
|
||||
/* verify checksum */
|
||||
zio_cksum_t cksum;
|
||||
fletcher_4_native(compressed, len, &cksum);
|
||||
fletcher_4_native(compressed, len, NULL, &cksum);
|
||||
if (cksum.zc_word[0] != checksum) {
|
||||
free(compressed);
|
||||
zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,
|
||||
|
|
|
@ -230,4 +230,19 @@ zpool_feature_init(void)
|
|||
"org.open-zfs:large_blocks", "large_blocks",
|
||||
"Support for blocks larger than 128KB.",
|
||||
ZFEATURE_FLAG_PER_DATASET, large_blocks_deps);
|
||||
|
||||
#ifdef illumos
|
||||
zfeature_register(SPA_FEATURE_SHA512,
|
||||
"org.illumos:sha512", "sha512",
|
||||
"SHA-512/256 hash algorithm.",
|
||||
ZFEATURE_FLAG_PER_DATASET, NULL);
|
||||
zfeature_register(SPA_FEATURE_SKEIN,
|
||||
"org.illumos:skein", "skein",
|
||||
"Skein hash algorithm.",
|
||||
ZFEATURE_FLAG_PER_DATASET, NULL);
|
||||
zfeature_register(SPA_FEATURE_EDONR,
|
||||
"org.illumos:edonr", "edonr",
|
||||
"Edon-R hash algorithm.",
|
||||
ZFEATURE_FLAG_PER_DATASET, NULL);
|
||||
#endif
|
||||
}
|
||||
|
|
|
@ -51,6 +51,11 @@ typedef enum spa_feature {
|
|||
SPA_FEATURE_BOOKMARKS,
|
||||
SPA_FEATURE_FS_SS_LIMIT,
|
||||
SPA_FEATURE_LARGE_BLOCKS,
|
||||
#ifdef illumos
|
||||
SPA_FEATURE_SHA512,
|
||||
SPA_FEATURE_SKEIN,
|
||||
SPA_FEATURE_EDONR,
|
||||
#endif
|
||||
SPA_FEATURES
|
||||
} spa_feature_t;
|
||||
|
||||
|
|
|
@ -22,6 +22,9 @@
|
|||
* Copyright 2009 Sun Microsystems, Inc. All rights reserved.
|
||||
* Use is subject to license terms.
|
||||
*/
|
||||
/*
|
||||
* Copyright 2013 Saso Kiselkov. All rights reserved.
|
||||
*/
|
||||
|
||||
/*
|
||||
* Fletcher Checksums
|
||||
|
@ -131,8 +134,10 @@
|
|||
#include <sys/zio.h>
|
||||
#include <sys/spa.h>
|
||||
|
||||
/*ARGSUSED*/
|
||||
void
|
||||
fletcher_2_native(const void *buf, uint64_t size, zio_cksum_t *zcp)
|
||||
fletcher_2_native(const void *buf, uint64_t size,
|
||||
const void *ctx_template, zio_cksum_t *zcp)
|
||||
{
|
||||
const uint64_t *ip = buf;
|
||||
const uint64_t *ipend = ip + (size / sizeof (uint64_t));
|
||||
|
@ -148,8 +153,10 @@ fletcher_2_native(const void *buf, uint64_t size, zio_cksum_t *zcp)
|
|||
ZIO_SET_CHECKSUM(zcp, a0, a1, b0, b1);
|
||||
}
|
||||
|
||||
/*ARGSUSED*/
|
||||
void
|
||||
fletcher_2_byteswap(const void *buf, uint64_t size, zio_cksum_t *zcp)
|
||||
fletcher_2_byteswap(const void *buf, uint64_t size,
|
||||
const void *ctx_template, zio_cksum_t *zcp)
|
||||
{
|
||||
const uint64_t *ip = buf;
|
||||
const uint64_t *ipend = ip + (size / sizeof (uint64_t));
|
||||
|
@ -165,8 +172,10 @@ fletcher_2_byteswap(const void *buf, uint64_t size, zio_cksum_t *zcp)
|
|||
ZIO_SET_CHECKSUM(zcp, a0, a1, b0, b1);
|
||||
}
|
||||
|
||||
/*ARGSUSED*/
|
||||
void
|
||||
fletcher_4_native(const void *buf, uint64_t size, zio_cksum_t *zcp)
|
||||
fletcher_4_native(const void *buf, uint64_t size,
|
||||
const void *ctx_template, zio_cksum_t *zcp)
|
||||
{
|
||||
const uint32_t *ip = buf;
|
||||
const uint32_t *ipend = ip + (size / sizeof (uint32_t));
|
||||
|
@ -182,8 +191,10 @@ fletcher_4_native(const void *buf, uint64_t size, zio_cksum_t *zcp)
|
|||
ZIO_SET_CHECKSUM(zcp, a, b, c, d);
|
||||
}
|
||||
|
||||
/*ARGSUSED*/
|
||||
void
|
||||
fletcher_4_byteswap(const void *buf, uint64_t size, zio_cksum_t *zcp)
|
||||
fletcher_4_byteswap(const void *buf, uint64_t size,
|
||||
const void *ctx_template, zio_cksum_t *zcp)
|
||||
{
|
||||
const uint32_t *ip = buf;
|
||||
const uint32_t *ipend = ip + (size / sizeof (uint32_t));
|
||||
|
|
|
@ -22,6 +22,9 @@
|
|||
* Copyright 2009 Sun Microsystems, Inc. All rights reserved.
|
||||
* Use is subject to license terms.
|
||||
*/
|
||||
/*
|
||||
* Copyright 2013 Saso Kiselkov. All rights reserved.
|
||||
*/
|
||||
|
||||
#ifndef _ZFS_FLETCHER_H
|
||||
#define _ZFS_FLETCHER_H
|
||||
|
@ -37,14 +40,12 @@ extern "C" {
|
|||
* fletcher checksum functions
|
||||
*/
|
||||
|
||||
void fletcher_2_native(const void *, uint64_t, zio_cksum_t *);
|
||||
void fletcher_2_byteswap(const void *, uint64_t, zio_cksum_t *);
|
||||
void fletcher_4_native(const void *, uint64_t, zio_cksum_t *);
|
||||
void fletcher_4_byteswap(const void *, uint64_t, zio_cksum_t *);
|
||||
void fletcher_4_incremental_native(const void *, uint64_t,
|
||||
zio_cksum_t *);
|
||||
void fletcher_4_incremental_byteswap(const void *, uint64_t,
|
||||
zio_cksum_t *);
|
||||
void fletcher_2_native(const void *, uint64_t, const void *, zio_cksum_t *);
|
||||
void fletcher_2_byteswap(const void *, uint64_t, const void *, zio_cksum_t *);
|
||||
void fletcher_4_native(const void *, uint64_t, const void *, zio_cksum_t *);
|
||||
void fletcher_4_byteswap(const void *, uint64_t, const void *, zio_cksum_t *);
|
||||
void fletcher_4_incremental_native(const void *, uint64_t, zio_cksum_t *);
|
||||
void fletcher_4_incremental_byteswap(const void *, uint64_t, zio_cksum_t *);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
|
|
|
@ -71,6 +71,11 @@ zfs_prop_init(void)
|
|||
{ "fletcher4", ZIO_CHECKSUM_FLETCHER_4 },
|
||||
{ "sha256", ZIO_CHECKSUM_SHA256 },
|
||||
{ "noparity", ZIO_CHECKSUM_NOPARITY },
|
||||
#ifdef illumos
|
||||
{ "sha512", ZIO_CHECKSUM_SHA512 },
|
||||
{ "skein", ZIO_CHECKSUM_SKEIN },
|
||||
{ "edonr", ZIO_CHECKSUM_EDONR },
|
||||
#endif
|
||||
{ NULL }
|
||||
};
|
||||
|
||||
|
@ -81,6 +86,16 @@ zfs_prop_init(void)
|
|||
{ "sha256", ZIO_CHECKSUM_SHA256 },
|
||||
{ "sha256,verify",
|
||||
ZIO_CHECKSUM_SHA256 | ZIO_CHECKSUM_VERIFY },
|
||||
#ifdef illumos
|
||||
{ "sha512", ZIO_CHECKSUM_SHA512 },
|
||||
{ "sha512,verify",
|
||||
ZIO_CHECKSUM_SHA512 | ZIO_CHECKSUM_VERIFY },
|
||||
{ "skein", ZIO_CHECKSUM_SKEIN },
|
||||
{ "skein,verify",
|
||||
ZIO_CHECKSUM_SKEIN | ZIO_CHECKSUM_VERIFY },
|
||||
{ "edonr,verify",
|
||||
ZIO_CHECKSUM_EDONR | ZIO_CHECKSUM_VERIFY },
|
||||
#endif
|
||||
{ NULL }
|
||||
};
|
||||
|
||||
|
@ -225,12 +240,12 @@ zfs_prop_init(void)
|
|||
zprop_register_index(ZFS_PROP_CHECKSUM, "checksum",
|
||||
ZIO_CHECKSUM_DEFAULT, PROP_INHERIT, ZFS_TYPE_FILESYSTEM |
|
||||
ZFS_TYPE_VOLUME,
|
||||
"on | off | fletcher2 | fletcher4 | sha256", "CHECKSUM",
|
||||
checksum_table);
|
||||
"on | off | fletcher2 | fletcher4 | sha256 | sha512 | "
|
||||
"skein | edonr", "CHECKSUM", checksum_table);
|
||||
zprop_register_index(ZFS_PROP_DEDUP, "dedup", ZIO_CHECKSUM_OFF,
|
||||
PROP_INHERIT, ZFS_TYPE_FILESYSTEM | ZFS_TYPE_VOLUME,
|
||||
"on | off | verify | sha256[,verify]", "DEDUP",
|
||||
dedup_table);
|
||||
"on | off | verify | sha256[,verify], sha512[,verify], "
|
||||
"skein[,verify], edonr,verify", "DEDUP", dedup_table);
|
||||
zprop_register_index(ZFS_PROP_COMPRESSION, "compression",
|
||||
ZIO_COMPRESS_DEFAULT, PROP_INHERIT,
|
||||
ZFS_TYPE_FILESYSTEM | ZFS_TYPE_VOLUME,
|
||||
|
|
|
@ -1552,7 +1552,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);
|
||||
|
@ -1565,7 +1565,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);
|
||||
|
||||
|
@ -1585,7 +1585,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);
|
||||
#ifdef illumos
|
||||
arc_buf_watch(buf);
|
||||
|
|
|
@ -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 <sys/zfs_context.h>
|
||||
|
@ -64,7 +64,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);
|
||||
|
|
|
@ -1493,7 +1493,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;
|
||||
|
@ -1840,8 +1841,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 ||
|
||||
|
@ -1880,17 +1883,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);
|
||||
}
|
||||
|
||||
|
|
|
@ -292,7 +292,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));
|
||||
|
|
|
@ -52,6 +52,8 @@
|
|||
#include <sys/dsl_destroy.h>
|
||||
#include <sys/dsl_userhold.h>
|
||||
#include <sys/dsl_bookmark.h>
|
||||
#include <sys/dmu_send.h>
|
||||
#include <sys/zio_checksum.h>
|
||||
#include <sys/zio_compress.h>
|
||||
#include <zfs_fletcher.h>
|
||||
|
||||
|
@ -133,10 +135,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);
|
||||
|
@ -1791,7 +1799,7 @@ get_receive_resume_stats(dsl_dataset_t *ds, nvlist_t *nv)
|
|||
packed_size, packed_size, 6);
|
||||
|
||||
zio_cksum_t cksum;
|
||||
fletcher_4_native(compressed, compressed_size, &cksum);
|
||||
fletcher_4_native(compressed, compressed_size, NULL, &cksum);
|
||||
|
||||
str = kmem_alloc(compressed_size * 2 + 1, KM_SLEEP);
|
||||
for (int i = 0; i < compressed_size; i++) {
|
||||
|
|
102
sys/cddl/contrib/opensolaris/uts/common/fs/zfs/edonr_zfs.c
Normal file
102
sys/cddl/contrib/opensolaris/uts/common/fs/zfs/edonr_zfs.c
Normal file
|
@ -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 <sys/zfs_context.h>
|
||||
#include <sys/zio.h>
|
||||
#include <sys/edonr.h>
|
||||
|
||||
#define EDONR_MODE 512
|
||||
#define EDONR_BLOCK_SIZE EdonR512_BLOCK_SIZE
|
||||
|
||||
/*
|
||||
* Native zio_checksum interface for the Edon-R hash function.
|
||||
*/
|
||||
/*ARGSUSED*/
|
||||
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));
|
||||
}
|
|
@ -22,6 +22,9 @@
|
|||
* Copyright 2009 Sun Microsystems, Inc. All rights reserved.
|
||||
* Use is subject to license terms.
|
||||
*/
|
||||
/*
|
||||
* Copyright 2013 Saso Kiselkov. All rights reserved.
|
||||
*/
|
||||
#include <sys/zfs_context.h>
|
||||
#include <sys/zio.h>
|
||||
#ifdef _KERNEL
|
||||
|
@ -30,8 +33,10 @@
|
|||
#include <sha256.h>
|
||||
#endif
|
||||
|
||||
/*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)
|
||||
{
|
||||
SHA256_CTX ctx;
|
||||
zio_cksum_t tmp;
|
||||
|
@ -52,3 +57,31 @@ 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]);
|
||||
}
|
||||
|
||||
#ifdef illumos
|
||||
/*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]);
|
||||
}
|
||||
#endif
|
||||
|
|
91
sys/cddl/contrib/opensolaris/uts/common/fs/zfs/skein_zfs.c
Normal file
91
sys/cddl/contrib/opensolaris/uts/common/fs/zfs/skein_zfs.c
Normal file
|
@ -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 <sys/zfs_context.h>
|
||||
#include <sys/zio.h>
|
||||
#include <sys/skein.h>
|
||||
|
||||
/*
|
||||
* Computes a native 256-bit skein MAC checksum. Please note that this
|
||||
* function requires the presence of a ctx_template that should be allocated
|
||||
* using zio_checksum_skein_tmpl_init.
|
||||
*/
|
||||
/*ARGSUSED*/
|
||||
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));
|
||||
}
|
|
@ -25,6 +25,7 @@
|
|||
* Copyright (c) 2015, Nexenta Systems, Inc. All rights reserved.
|
||||
* Copyright (c) 2013 Martin Matuska <mm@FreeBSD.org>. All rights reserved.
|
||||
* Copyright (c) 2014 Spectra Logic Corporation, All rights reserved.
|
||||
* Copyright 2013 Saso Kiselkov. All rights reserved.
|
||||
*/
|
||||
|
||||
/*
|
||||
|
@ -2582,6 +2583,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);
|
||||
|
@ -3749,6 +3763,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.
|
||||
*/
|
||||
|
@ -6551,6 +6571,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);
|
||||
}
|
||||
|
||||
|
|
|
@ -24,6 +24,7 @@
|
|||
* Copyright 2011 Nexenta Systems, Inc. All rights reserved.
|
||||
* Copyright 2013 Martin Matuska <mm@FreeBSD.org>. All rights reserved.
|
||||
* Copyright (c) 2014 Spectra Logic Corporation, All rights reserved.
|
||||
* Copyright 2013 Saso Kiselkov. All rights reserved.
|
||||
*/
|
||||
|
||||
#include <sys/zfs_context.h>
|
||||
|
@ -51,7 +52,7 @@
|
|||
#include <sys/arc.h>
|
||||
#include <sys/ddt.h>
|
||||
#include "zfs_prop.h"
|
||||
#include "zfeature_common.h"
|
||||
#include <sys/zfeature.h>
|
||||
|
||||
/*
|
||||
* SPA locking
|
||||
|
@ -631,6 +632,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);
|
||||
|
@ -793,6 +795,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);
|
||||
|
@ -806,6 +810,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);
|
||||
|
|
|
@ -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 */
|
||||
|
@ -320,6 +321,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
|
||||
|
|
|
@ -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
|
||||
|
@ -162,6 +163,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:
|
||||
|
|
|
@ -24,6 +24,7 @@
|
|||
* Copyright 2011 Nexenta Systems, Inc. All rights reserved.
|
||||
* Copyright 2013 Martin Matuska <mm@FreeBSD.org>. All rights reserved.
|
||||
* Copyright (c) 2014 Spectra Logic Corporation, All rights reserved.
|
||||
* Copyright 2013 Saso Kiselkov. All rights reserved.
|
||||
*/
|
||||
|
||||
#ifndef _SYS_SPA_IMPL_H
|
||||
|
@ -166,6 +167,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 */
|
||||
|
|
|
@ -82,6 +82,11 @@ enum zio_checksum {
|
|||
ZIO_CHECKSUM_SHA256,
|
||||
ZIO_CHECKSUM_ZILOG2,
|
||||
ZIO_CHECKSUM_NOPARITY,
|
||||
#ifdef illumos
|
||||
ZIO_CHECKSUM_SHA512,
|
||||
ZIO_CHECKSUM_SKEIN,
|
||||
ZIO_CHECKSUM_EDONR,
|
||||
#endif
|
||||
ZIO_CHECKSUM_FUNCTIONS
|
||||
};
|
||||
|
||||
|
|
|
@ -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 <sys/zio.h>
|
||||
#include <zfeature_common.h>
|
||||
|
||||
#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,30 @@ 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;
|
||||
#ifdef illumos
|
||||
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;
|
||||
#endif
|
||||
|
||||
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
|
||||
}
|
||||
|
|
|
@ -188,6 +188,7 @@
|
|||
#include <sys/dsl_bookmark.h>
|
||||
#include <sys/dsl_userhold.h>
|
||||
#include <sys/zfeature.h>
|
||||
#include <sys/zio_checksum.h>
|
||||
|
||||
#include "zfs_namecheck.h"
|
||||
#include "zfs_prop.h"
|
||||
|
@ -3903,11 +3904,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 &&
|
||||
|
@ -3958,6 +3954,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()));
|
||||
|
|
|
@ -997,7 +997,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.
|
||||
|
@ -1209,8 +1209,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);
|
||||
|
@ -2072,12 +2072,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)
|
||||
|
@ -2100,7 +2110,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) ||
|
||||
|
@ -2112,7 +2123,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);
|
||||
|
@ -2393,7 +2405,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;
|
||||
|
|
|
@ -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 <sys/zfs_context.h>
|
||||
#include <sys/spa.h>
|
||||
#include <sys/spa_impl.h>
|
||||
#include <sys/zio.h>
|
||||
#include <sys/zio_checksum.h>
|
||||
#include <sys/zil.h>
|
||||
|
@ -59,29 +61,99 @@
|
|||
* 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"},
|
||||
#ifdef illumos
|
||||
{{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"},
|
||||
#endif
|
||||
};
|
||||
|
||||
spa_feature_t
|
||||
zio_checksum_to_feature(enum zio_checksum cksum)
|
||||
{
|
||||
#ifdef illumos
|
||||
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);
|
||||
}
|
||||
#endif
|
||||
return (SPA_FEATURE_NONE);
|
||||
}
|
||||
|
||||
enum zio_checksum
|
||||
zio_checksum_select(enum zio_checksum child, enum zio_checksum parent)
|
||||
{
|
||||
|
@ -115,7 +187,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 +220,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 +255,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 +281,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 +304,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 +348,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 +359,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 +382,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;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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 */
|
||||
|
@ -123,6 +124,16 @@ _NOTE(CONSTCOND) } while (0)
|
|||
#define ASSERT0(x) ((void)0)
|
||||
#endif
|
||||
|
||||
/*
|
||||
* Compile-time assertion. The condition 'x' must be constant.
|
||||
*/
|
||||
#ifndef CTASSERT
|
||||
#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]
|
||||
#endif
|
||||
|
||||
#ifdef _KERNEL
|
||||
|
||||
extern void abort_sequence_enter(char *);
|
||||
|
|
Loading…
Reference in a new issue