Skip to content

Commit 2883a19

Browse files
mcmilkrincebrain
authored andcommitted
Introduce BLAKE3 checksums as an OpenZFS feature
This commit adds BLAKE3 checksums to OpenZFS, it has similar performance to Edon-R, but without the caveats around the latter. Homepage of BLAKE3: https://github.com/BLAKE3-team/BLAKE3 Wikipedia: https://en.wikipedia.org/wiki/BLAKE_(hash_function)#BLAKE3 Short description of Wikipedia: BLAKE3 is a cryptographic hash function based on Bao and BLAKE2, created by Jack O'Connor, Jean-Philippe Aumasson, Samuel Neves, and Zooko Wilcox-O'Hearn. It was announced on January 9, 2020, at Real World Crypto. BLAKE3 is a single algorithm with many desirable features (parallelism, XOF, KDF, PRF and MAC), in contrast to BLAKE and BLAKE2, which are algorithm families with multiple variants. BLAKE3 has a binary tree structure, so it supports a practically unlimited degree of parallelism (both SIMD and multithreading) given enough input. The official Rust and C implementations are dual-licensed as public domain (CC0) and the Apache License. Along with adding the BLAKE3 hash into the OpenZFS infrastructure a new benchmarking file called chksum_bench was introduced. When read it reports the speed of the available checksum functions. On Linux: cat /proc/spl/kstat/zfs/chksum_bench On FreeBSD: sysctl kstat.zfs.misc.chksum_bench This is an example output of an i3-1005G1 test system with Debian 11: implementation 1k 4k 16k 64k 256k 1m 4m edonr-generic 1196 1602 1761 1749 1762 1759 1751 skein-generic 546 591 608 615 619 612 616 sha256-generic 240 300 316 314 304 285 276 sha512-generic 353 441 467 476 472 467 426 blake3-generic 308 313 313 313 312 313 312 blake3-sse2 402 1289 1423 1446 1432 1458 1413 blake3-sse41 427 1470 1625 1704 1679 1607 1629 blake3-avx2 428 1920 3095 3343 3356 3318 3204 blake3-avx512 473 2687 4905 5836 5844 5643 5374 Output on Debian 5.10.0-10-amd64 system: (Ryzen 7 5800X) implementation 1k 4k 16k 64k 256k 1m 4m edonr-generic 1840 2458 2665 2719 2711 2723 2693 skein-generic 870 966 996 992 1003 1005 1009 sha256-generic 415 442 453 455 457 457 457 sha512-generic 608 690 711 718 719 720 721 blake3-generic 301 313 311 309 309 310 310 blake3-sse2 343 1865 2124 2188 2180 2181 2186 blake3-sse41 364 2091 2396 2509 2463 2482 2488 blake3-avx2 365 2590 4399 4971 4915 4802 4764 Output on Debian 5.10.0-9-powerpc64le system: (POWER 9) implementation 1k 4k 16k 64k 256k 1m 4m edonr-generic 1213 1703 1889 1918 1957 1902 1907 skein-generic 434 492 520 522 511 525 525 sha256-generic 167 183 187 188 188 187 188 sha512-generic 186 216 222 221 225 224 224 blake3-generic 153 152 154 153 151 153 153 blake3-sse2 391 1170 1366 1406 1428 1426 1414 blake3-sse41 352 1049 1212 1174 1262 1258 1259 Output on Debian 5.10.0-11-arm64 system: (Pi400) implementation 1k 4k 16k 64k 256k 1m 4m edonr-generic 487 603 629 639 643 641 641 skein-generic 271 299 303 308 309 309 307 sha256-generic 117 127 128 130 130 129 130 sha512-generic 145 165 170 172 173 174 175 blake3-generic 81 29 71 89 89 89 89 blake3-sse2 112 323 368 379 380 371 374 blake3-sse41 101 315 357 368 369 364 360 Structurally, the new code is mainly split into these parts: - 1x cross platform generic c variant: blake3_generic.c - 4x assembly for X86-64 (SSE2, SSE4.1, AVX2, AVX512) - 2x assembly for ARMv8 (NEON converted from SSE2) - 2x assembly for PPC64-LE (POWER8 converted from SSE2) - one file for switching between the implementations Note the PPC64 assembly requires the VSX instruction set and the kfpu_begin() / kfpu_end() calls on PowerPC were updated accordingly. Reviewed-by: Felix Dörre <[email protected]> Reviewed-by: Ahelenia Ziemiańska <[email protected]> Reviewed-by: Brian Behlendorf <[email protected]> Signed-off-by: Tino Reichardt <[email protected]> Co-authored-by: Rich Ercolani <[email protected]> Closes openzfs#10058 Closes openzfs#12918
1 parent 5027477 commit 2883a19

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

53 files changed

+22804
-52
lines changed

AUTHORS

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -285,6 +285,7 @@ CONTRIBUTORS:
285285
Tim Connors <[email protected]>
286286
Tim Crawford <[email protected]>
287287
Tim Haley <[email protected]>
288+
Tino Reichardt <[email protected]>
288289
Tobin Harding <[email protected]>
289290
Tom Caputi <[email protected]>
290291
Tom Matthews <[email protected]>

cmd/ztest.c

Lines changed: 89 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -121,6 +121,7 @@
121121
#include <sys/zfeature.h>
122122
#include <sys/dsl_userhold.h>
123123
#include <sys/abd.h>
124+
#include <sys/blake3.h>
124125
#include <stdio.h>
125126
#include <stdlib.h>
126127
#include <unistd.h>
@@ -417,6 +418,7 @@ ztest_func_t ztest_device_removal;
417418
ztest_func_t ztest_spa_checkpoint_create_discard;
418419
ztest_func_t ztest_initialize;
419420
ztest_func_t ztest_trim;
421+
ztest_func_t ztest_blake3;
420422
ztest_func_t ztest_fletcher;
421423
ztest_func_t ztest_fletcher_incr;
422424
ztest_func_t ztest_verify_dnode_bt;
@@ -470,6 +472,7 @@ ztest_info_t ztest_info[] = {
470472
ZTI_INIT(ztest_spa_checkpoint_create_discard, 1, &zopt_rarely),
471473
ZTI_INIT(ztest_initialize, 1, &zopt_sometimes),
472474
ZTI_INIT(ztest_trim, 1, &zopt_sometimes),
475+
ZTI_INIT(ztest_blake3, 1, &zopt_rarely),
473476
ZTI_INIT(ztest_fletcher, 1, &zopt_rarely),
474477
ZTI_INIT(ztest_fletcher_incr, 1, &zopt_rarely),
475478
ZTI_INIT(ztest_verify_dnode_bt, 1, &zopt_sometimes),
@@ -6373,6 +6376,92 @@ ztest_reguid(ztest_ds_t *zd, uint64_t id)
63736376
VERIFY3U(load, ==, spa_load_guid(spa));
63746377
}
63756378

6379+
void
6380+
ztest_blake3(ztest_ds_t *zd, uint64_t id)
6381+
{
6382+
(void) zd, (void) id;
6383+
hrtime_t end = gethrtime() + NANOSEC;
6384+
zio_cksum_salt_t salt;
6385+
void *salt_ptr = &salt.zcs_bytes;
6386+
struct abd *abd_data, *abd_meta;
6387+
void *buf, *templ;
6388+
int i, *ptr;
6389+
uint32_t size;
6390+
BLAKE3_CTX ctx;
6391+
6392+
size = ztest_random_blocksize();
6393+
buf = umem_alloc(size, UMEM_NOFAIL);
6394+
abd_data = abd_alloc(size, B_FALSE);
6395+
abd_meta = abd_alloc(size, B_TRUE);
6396+
6397+
for (i = 0, ptr = buf; i < size / sizeof (*ptr); i++, ptr++)
6398+
*ptr = ztest_random(UINT_MAX);
6399+
memset(salt_ptr, 'A', 32);
6400+
6401+
abd_copy_from_buf_off(abd_data, buf, 0, size);
6402+
abd_copy_from_buf_off(abd_meta, buf, 0, size);
6403+
6404+
while (gethrtime() <= end) {
6405+
int run_count = 100;
6406+
zio_cksum_t zc_ref1, zc_ref2;
6407+
zio_cksum_t zc_res1, zc_res2;
6408+
6409+
void *ref1 = &zc_ref1;
6410+
void *ref2 = &zc_ref2;
6411+
void *res1 = &zc_res1;
6412+
void *res2 = &zc_res2;
6413+
6414+
/* BLAKE3_KEY_LEN = 32 */
6415+
VERIFY0(blake3_set_impl_name("generic"));
6416+
templ = abd_checksum_blake3_tmpl_init(&salt);
6417+
Blake3_InitKeyed(&ctx, salt_ptr);
6418+
Blake3_Update(&ctx, buf, size);
6419+
Blake3_Final(&ctx, ref1);
6420+
zc_ref2 = zc_ref1;
6421+
ZIO_CHECKSUM_BSWAP(&zc_ref2);
6422+
abd_checksum_blake3_tmpl_free(templ);
6423+
6424+
VERIFY0(blake3_set_impl_name("cycle"));
6425+
while (run_count-- > 0) {
6426+
6427+
/* Test current implementation */
6428+
Blake3_InitKeyed(&ctx, salt_ptr);
6429+
Blake3_Update(&ctx, buf, size);
6430+
Blake3_Final(&ctx, res1);
6431+
zc_res2 = zc_res1;
6432+
ZIO_CHECKSUM_BSWAP(&zc_res2);
6433+
6434+
VERIFY0(memcmp(ref1, res1, 32));
6435+
VERIFY0(memcmp(ref2, res2, 32));
6436+
6437+
/* Test ABD - data */
6438+
templ = abd_checksum_blake3_tmpl_init(&salt);
6439+
abd_checksum_blake3_native(abd_data, size,
6440+
templ, &zc_res1);
6441+
abd_checksum_blake3_byteswap(abd_data, size,
6442+
templ, &zc_res2);
6443+
6444+
VERIFY0(memcmp(ref1, res1, 32));
6445+
VERIFY0(memcmp(ref2, res2, 32));
6446+
6447+
/* Test ABD - metadata */
6448+
abd_checksum_blake3_native(abd_meta, size,
6449+
templ, &zc_res1);
6450+
abd_checksum_blake3_byteswap(abd_meta, size,
6451+
templ, &zc_res2);
6452+
abd_checksum_blake3_tmpl_free(templ);
6453+
6454+
VERIFY0(memcmp(ref1, res1, 32));
6455+
VERIFY0(memcmp(ref2, res2, 32));
6456+
6457+
}
6458+
}
6459+
6460+
abd_free(abd_data);
6461+
abd_free(abd_meta);
6462+
umem_free(buf, size);
6463+
}
6464+
63766465
void
63776466
ztest_fletcher(ztest_ds_t *zd, uint64_t id)
63786467
{

config/always-arch.m4

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,8 @@ AC_DEFUN([ZFS_AC_CONFIG_ALWAYS_ARCH], [
3030
;;
3131
esac
3232
33+
AM_CONDITIONAL([TARGET_CPU_AARCH64], test $TARGET_CPU = aarch64)
3334
AM_CONDITIONAL([TARGET_CPU_X86_64], test $TARGET_CPU = x86_64)
3435
AM_CONDITIONAL([TARGET_CPU_POWERPC], test $TARGET_CPU = powerpc)
36+
AM_CONDITIONAL([TARGET_CPU_SPARC64], test $TARGET_CPU = sparc64)
3537
])

include/Makefile.am

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,7 @@ COMMON_H = \
2323
sys/avl.h \
2424
sys/avl_impl.h \
2525
sys/bitops.h \
26+
sys/blake3.h \
2627
sys/blkptr.h \
2728
sys/bplist.h \
2829
sys/bpobj.h \
@@ -117,6 +118,7 @@ COMMON_H = \
117118
sys/zfeature.h \
118119
sys/zfs_acl.h \
119120
sys/zfs_bootenv.h \
121+
sys/zfs_chksum.h \
120122
sys/zfs_context.h \
121123
sys/zfs_debug.h \
122124
sys/zfs_delay.h \

include/os/freebsd/spl/sys/ccompile.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -74,10 +74,12 @@ extern "C" {
7474

7575
#ifndef LOCORE
7676
#ifndef HAVE_RPC_TYPES
77+
#ifndef _KERNEL
7778
typedef int bool_t;
7879
typedef int enum_t;
7980
#endif
8081
#endif
82+
#endif
8183

8284
#ifndef __cplusplus
8385
#define __init

include/os/linux/kernel/linux/simd_powerpc.h

Lines changed: 27 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -57,25 +57,45 @@
5757
#include <sys/types.h>
5858
#include <linux/version.h>
5959

60-
#define kfpu_allowed() 1
61-
#define kfpu_begin() \
62-
{ \
63-
preempt_disable(); \
64-
enable_kernel_altivec(); \
65-
}
60+
#define kfpu_allowed() 1
61+
6662
#if LINUX_VERSION_CODE >= KERNEL_VERSION(4, 5, 0)
6763
#define kfpu_end() \
6864
{ \
65+
disable_kernel_vsx(); \
6966
disable_kernel_altivec(); \
7067
preempt_enable(); \
7168
}
69+
#define kfpu_begin() \
70+
{ \
71+
preempt_disable(); \
72+
enable_kernel_altivec(); \
73+
enable_kernel_vsx(); \
74+
}
7275
#else
73-
/* seems that before 4.5 no-one bothered disabling ... */
76+
/* seems that before 4.5 no-one bothered */
77+
#define kfpu_begin()
7478
#define kfpu_end() preempt_enable()
7579
#endif
7680
#define kfpu_init() 0
7781
#define kfpu_fini() ((void) 0)
7882

83+
static inline boolean_t
84+
zfs_vsx_available(void)
85+
{
86+
boolean_t res;
87+
#if defined(__powerpc64__)
88+
u64 msr;
89+
#else
90+
u32 msr;
91+
#endif
92+
kfpu_begin();
93+
__asm volatile("mfmsr %0" : "=r"(msr));
94+
res = (msr & 0x800000) != 0;
95+
kfpu_end();
96+
return (res);
97+
}
98+
7999
/*
80100
* Check if AltiVec instruction set is available
81101
*/

include/sys/blake3.h

Lines changed: 120 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,120 @@
1+
/*
2+
* CDDL HEADER START
3+
*
4+
* The contents of this file are subject to the terms of the
5+
* Common Development and Distribution License (the "License").
6+
* You may not use this file except in compliance with the License.
7+
*
8+
* You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9+
* or http://www.opensolaris.org/os/licensing.
10+
* See the License for the specific language governing permissions
11+
* and limitations under the License.
12+
*
13+
* When distributing Covered Code, include this CDDL HEADER in each
14+
* file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15+
* If applicable, add the following below this CDDL HEADER, with the
16+
* fields enclosed by brackets "[]" replaced with your own identifying
17+
* information: Portions Copyright [yyyy] [name of copyright owner]
18+
*
19+
* CDDL HEADER END
20+
*/
21+
22+
/*
23+
* Based on BLAKE3 v1.3.1, https://github.com/BLAKE3-team/BLAKE3
24+
* Copyright (c) 2019-2020 Samuel Neves and Jack O'Connor
25+
* Copyright (c) 2021 Tino Reichardt <[email protected]>
26+
*/
27+
28+
#ifndef BLAKE3_H
29+
#define BLAKE3_H
30+
31+
#ifdef _KERNEL
32+
#include <sys/types.h>
33+
#else
34+
#include <stdint.h>
35+
#include <stdlib.h>
36+
#endif
37+
38+
#ifdef __cplusplus
39+
extern "C" {
40+
#endif
41+
42+
#define BLAKE3_KEY_LEN 32
43+
#define BLAKE3_OUT_LEN 32
44+
#define BLAKE3_MAX_DEPTH 54
45+
#define BLAKE3_BLOCK_LEN 64
46+
#define BLAKE3_CHUNK_LEN 1024
47+
48+
/*
49+
* This struct is a private implementation detail.
50+
* It has to be here because it's part of BLAKE3_CTX below.
51+
*/
52+
typedef struct {
53+
uint32_t cv[8];
54+
uint64_t chunk_counter;
55+
uint8_t buf[BLAKE3_BLOCK_LEN];
56+
uint8_t buf_len;
57+
uint8_t blocks_compressed;
58+
uint8_t flags;
59+
} blake3_chunk_state_t;
60+
61+
typedef struct {
62+
uint32_t key[8];
63+
blake3_chunk_state_t chunk;
64+
uint8_t cv_stack_len;
65+
66+
/*
67+
* The stack size is MAX_DEPTH + 1 because we do lazy merging. For
68+
* example, with 7 chunks, we have 3 entries in the stack. Adding an
69+
* 8th chunk requires a 4th entry, rather than merging everything down
70+
* to 1, because we don't know whether more input is coming. This is
71+
* different from how the reference implementation does things.
72+
*/
73+
uint8_t cv_stack[(BLAKE3_MAX_DEPTH + 1) * BLAKE3_OUT_LEN];
74+
75+
/* const blake3_impl_ops_t *ops */
76+
const void *ops;
77+
} BLAKE3_CTX;
78+
79+
/* init the context for hash operation */
80+
void Blake3_Init(BLAKE3_CTX *ctx);
81+
82+
/* init the context for a MAC and/or tree hash operation */
83+
void Blake3_InitKeyed(BLAKE3_CTX *ctx, const uint8_t key[BLAKE3_KEY_LEN]);
84+
85+
/* process the input bytes */
86+
void Blake3_Update(BLAKE3_CTX *ctx, const void *input, size_t input_len);
87+
88+
/* finalize the hash computation and output the result */
89+
void Blake3_Final(const BLAKE3_CTX *ctx, uint8_t *out);
90+
91+
/* finalize the hash computation and output the result */
92+
void Blake3_FinalSeek(const BLAKE3_CTX *ctx, uint64_t seek, uint8_t *out,
93+
size_t out_len);
94+
95+
/* return number of supported implementations */
96+
extern int blake3_get_impl_count(void);
97+
98+
/* return id of selected implementation */
99+
extern int blake3_get_impl_id(void);
100+
101+
/* return name of selected implementation */
102+
extern const char *blake3_get_impl_name(void);
103+
104+
/* setup id as fastest implementation */
105+
extern void blake3_set_impl_fastest(uint32_t id);
106+
107+
/* set implementation by id */
108+
extern void blake3_set_impl_id(uint32_t id);
109+
110+
/* set implementation by name */
111+
extern int blake3_set_impl_name(const char *name);
112+
113+
/* set startup implementation */
114+
extern void blake3_setup_impl(void);
115+
116+
#ifdef __cplusplus
117+
}
118+
#endif
119+
120+
#endif /* BLAKE3_H */

include/sys/zfs_chksum.h

Lines changed: 48 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,48 @@
1+
/*
2+
* CDDL HEADER START
3+
*
4+
* The contents of this file are subject to the terms of the
5+
* Common Development and Distribution License (the "License").
6+
* You may not use this file except in compliance with the License.
7+
*
8+
* You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9+
* or http://www.opensolaris.org/os/licensing.
10+
* See the License for the specific language governing permissions
11+
* and limitations under the License.
12+
*
13+
* When distributing Covered Code, include this CDDL HEADER in each
14+
* file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15+
* If applicable, add the following below this CDDL HEADER, with the
16+
* fields enclosed by brackets "[]" replaced with your own identifying
17+
* information: Portions Copyright [yyyy] [name of copyright owner]
18+
*
19+
* CDDL HEADER END
20+
*/
21+
22+
/*
23+
* Copyright (c) 2021 Tino Reichardt <[email protected]>
24+
*/
25+
26+
#ifndef _ZFS_CHKSUM_H
27+
#define _ZFS_CHKSUM_H
28+
29+
#ifdef _KERNEL
30+
#include <sys/types.h>
31+
#else
32+
#include <stdint.h>
33+
#include <stdlib.h>
34+
#endif
35+
36+
#ifdef __cplusplus
37+
extern "C" {
38+
#endif
39+
40+
/* Benchmark the chksums of ZFS when the module is loading */
41+
void chksum_init(void);
42+
void chksum_fini(void);
43+
44+
#ifdef __cplusplus
45+
}
46+
#endif
47+
48+
#endif /* _ZFS_CHKSUM_H */

0 commit comments

Comments
 (0)