mirror_zfs/module/icp/algs/blake3/blake3_impl.c
Richard Yao 303678350a
Convert some sprintf() calls to kmem_scnprintf()
These `sprintf()` calls are used repeatedly to write to a buffer. There
is no protection against overflow other than reviewers explicitly
checking to see if the buffers are big enough. However, such issues are
easily missed during review and when they are missed, we would rather
stop printing rather than have a buffer overflow, so we convert these
functions to use `kmem_scnprintf()`. The Linux kernel provides an entire
page for module parameters, so we are safe to write up to PAGE_SIZE.

Removing `sprintf()` from these functions removes the last instances of
`sprintf()` usage in our platform-independent kernel code. This improves
XNU kernel compatibility because the XNU kernel does not support
(removed support for?) `sprintf()`.

Reviewed-by: Brian Behlendorf <behlendorf1@llnl.gov>
Reviewed-by: Jorgen Lundman <lundman@lundman.net>
Signed-off-by: Richard Yao <richard.yao@alumni.stonybrook.edu>
Closes #14209
2022-11-28 13:49:58 -08:00

362 lines
8.3 KiB
C

/*
* 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 https://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) 2021-2022 Tino Reichardt <milky-zfs@mcmilk.de>
*/
#include <sys/zfs_context.h>
#include <sys/zio_checksum.h>
#include "blake3_impl.h"
static const blake3_ops_t *const blake3_impls[] = {
&blake3_generic_impl,
#if defined(__aarch64__) || \
(defined(__x86_64) && defined(HAVE_SSE2)) || \
(defined(__PPC64__) && defined(__LITTLE_ENDIAN__))
&blake3_sse2_impl,
#endif
#if defined(__aarch64__) || \
(defined(__x86_64) && defined(HAVE_SSE4_1)) || \
(defined(__PPC64__) && defined(__LITTLE_ENDIAN__))
&blake3_sse41_impl,
#endif
#if defined(__x86_64) && defined(HAVE_SSE4_1) && defined(HAVE_AVX2)
&blake3_avx2_impl,
#endif
#if defined(__x86_64) && defined(HAVE_AVX512F) && defined(HAVE_AVX512VL)
&blake3_avx512_impl,
#endif
};
/* Select BLAKE3 implementation */
#define IMPL_FASTEST (UINT32_MAX)
#define IMPL_CYCLE (UINT32_MAX - 1)
#define IMPL_READ(i) (*(volatile uint32_t *) &(i))
/* Indicate that benchmark has been done */
static boolean_t blake3_initialized = B_FALSE;
/* Implementation that contains the fastest methods */
static blake3_ops_t blake3_fastest_impl = {
.name = "fastest"
};
/* Hold all supported implementations */
static const blake3_ops_t *blake3_supp_impls[ARRAY_SIZE(blake3_impls)];
static uint32_t blake3_supp_impls_cnt = 0;
/* Currently selected implementation */
static uint32_t blake3_impl_chosen = IMPL_FASTEST;
static struct blake3_impl_selector {
const char *name;
uint32_t sel;
} blake3_impl_selectors[] = {
{ "cycle", IMPL_CYCLE },
{ "fastest", IMPL_FASTEST }
};
/* check the supported implementations */
static void blake3_impl_init(void)
{
int i, c;
/* init only once */
if (likely(blake3_initialized))
return;
/* move supported implementations into blake3_supp_impls */
for (i = 0, c = 0; i < ARRAY_SIZE(blake3_impls); i++) {
const blake3_ops_t *impl = blake3_impls[i];
if (impl->is_supported && impl->is_supported())
blake3_supp_impls[c++] = impl;
}
blake3_supp_impls_cnt = c;
/* first init generic impl, may be changed via set_fastest() */
memcpy(&blake3_fastest_impl, blake3_impls[0],
sizeof (blake3_fastest_impl));
blake3_initialized = B_TRUE;
}
/* get number of supported implementations */
uint32_t
blake3_impl_getcnt(void)
{
blake3_impl_init();
return (blake3_supp_impls_cnt);
}
/* get id of selected implementation */
uint32_t
blake3_impl_getid(void)
{
return (IMPL_READ(blake3_impl_chosen));
}
/* get name of selected implementation */
const char *
blake3_impl_getname(void)
{
uint32_t impl = IMPL_READ(blake3_impl_chosen);
blake3_impl_init();
switch (impl) {
case IMPL_FASTEST:
return ("fastest");
case IMPL_CYCLE:
return ("cycle");
default:
return (blake3_supp_impls[impl]->name);
}
}
/* setup id as fastest implementation */
void
blake3_impl_set_fastest(uint32_t id)
{
/* setup fastest impl */
memcpy(&blake3_fastest_impl, blake3_supp_impls[id],
sizeof (blake3_fastest_impl));
}
/* set implementation by id */
void
blake3_impl_setid(uint32_t id)
{
blake3_impl_init();
switch (id) {
case IMPL_FASTEST:
atomic_swap_32(&blake3_impl_chosen, IMPL_FASTEST);
break;
case IMPL_CYCLE:
atomic_swap_32(&blake3_impl_chosen, IMPL_CYCLE);
break;
default:
ASSERT3U(id, <, blake3_supp_impls_cnt);
atomic_swap_32(&blake3_impl_chosen, id);
break;
}
}
/* set implementation by name */
int
blake3_impl_setname(const char *val)
{
uint32_t impl = IMPL_READ(blake3_impl_chosen);
size_t val_len;
int i, err = -EINVAL;
blake3_impl_init();
val_len = strlen(val);
while ((val_len > 0) && !!isspace(val[val_len-1])) /* trim '\n' */
val_len--;
/* check mandatory implementations */
for (i = 0; i < ARRAY_SIZE(blake3_impl_selectors); i++) {
const char *name = blake3_impl_selectors[i].name;
if (val_len == strlen(name) &&
strncmp(val, name, val_len) == 0) {
impl = blake3_impl_selectors[i].sel;
err = 0;
break;
}
}
if (err != 0 && blake3_initialized) {
/* check all supported implementations */
for (i = 0; i < blake3_supp_impls_cnt; i++) {
const char *name = blake3_supp_impls[i]->name;
if (val_len == strlen(name) &&
strncmp(val, name, val_len) == 0) {
impl = i;
err = 0;
break;
}
}
}
if (err == 0) {
atomic_swap_32(&blake3_impl_chosen, impl);
}
return (err);
}
const blake3_ops_t *
blake3_impl_get_ops(void)
{
const blake3_ops_t *ops = NULL;
uint32_t impl = IMPL_READ(blake3_impl_chosen);
blake3_impl_init();
switch (impl) {
case IMPL_FASTEST:
ASSERT(blake3_initialized);
ops = &blake3_fastest_impl;
break;
case IMPL_CYCLE:
/* Cycle through supported implementations */
ASSERT(blake3_initialized);
ASSERT3U(blake3_supp_impls_cnt, >, 0);
static uint32_t cycle_count = 0;
uint32_t idx = (++cycle_count) % blake3_supp_impls_cnt;
ops = blake3_supp_impls[idx];
break;
default:
ASSERT3U(blake3_supp_impls_cnt, >, 0);
ASSERT3U(impl, <, blake3_supp_impls_cnt);
ops = blake3_supp_impls[impl];
break;
}
ASSERT3P(ops, !=, NULL);
return (ops);
}
#if defined(_KERNEL)
void **blake3_per_cpu_ctx;
void
blake3_per_cpu_ctx_init(void)
{
/*
* Create "The Godfather" ptr to hold all blake3 ctx
*/
blake3_per_cpu_ctx = kmem_alloc(max_ncpus * sizeof (void *), KM_SLEEP);
for (int i = 0; i < max_ncpus; i++) {
blake3_per_cpu_ctx[i] = kmem_alloc(sizeof (BLAKE3_CTX),
KM_SLEEP);
}
/* init once in kernel mode */
blake3_impl_init();
}
void
blake3_per_cpu_ctx_fini(void)
{
for (int i = 0; i < max_ncpus; i++) {
memset(blake3_per_cpu_ctx[i], 0, sizeof (BLAKE3_CTX));
kmem_free(blake3_per_cpu_ctx[i], sizeof (BLAKE3_CTX));
}
memset(blake3_per_cpu_ctx, 0, max_ncpus * sizeof (void *));
kmem_free(blake3_per_cpu_ctx, max_ncpus * sizeof (void *));
}
#define IMPL_FMT(impl, i) (((impl) == (i)) ? "[%s] " : "%s ")
#if defined(__linux__)
static int
blake3_param_get(char *buffer, zfs_kernel_param_t *unused)
{
const uint32_t impl = IMPL_READ(blake3_impl_chosen);
char *fmt;
int cnt = 0;
/* cycling */
fmt = IMPL_FMT(impl, IMPL_CYCLE);
cnt += kmem_scnprintf(buffer + cnt, PAGE_SIZE - cnt, fmt, "cycle");
/* list fastest */
fmt = IMPL_FMT(impl, IMPL_FASTEST);
cnt += kmem_scnprintf(buffer + cnt, PAGE_SIZE - cnt, fmt, "fastest");
/* list all supported implementations */
for (uint32_t i = 0; i < blake3_supp_impls_cnt; ++i) {
fmt = IMPL_FMT(impl, i);
cnt += kmem_scnprintf(buffer + cnt, PAGE_SIZE - cnt, fmt,
blake3_supp_impls[i]->name);
}
return (cnt);
}
static int
blake3_param_set(const char *val, zfs_kernel_param_t *unused)
{
(void) unused;
return (blake3_impl_setname(val));
}
#elif defined(__FreeBSD__)
#include <sys/sbuf.h>
static int
blake3_param(ZFS_MODULE_PARAM_ARGS)
{
int err;
if (req->newptr == NULL) {
const uint32_t impl = IMPL_READ(blake3_impl_chosen);
const int init_buflen = 64;
const char *fmt;
struct sbuf *s;
s = sbuf_new_for_sysctl(NULL, NULL, init_buflen, req);
/* cycling */
fmt = IMPL_FMT(impl, IMPL_CYCLE);
(void) sbuf_printf(s, fmt, "cycle");
/* list fastest */
fmt = IMPL_FMT(impl, IMPL_FASTEST);
(void) sbuf_printf(s, fmt, "fastest");
/* list all supported implementations */
for (uint32_t i = 0; i < blake3_supp_impls_cnt; ++i) {
fmt = IMPL_FMT(impl, i);
(void) sbuf_printf(s, fmt, blake3_supp_impls[i]->name);
}
err = sbuf_finish(s);
sbuf_delete(s);
return (err);
}
char buf[16];
err = sysctl_handle_string(oidp, buf, sizeof (buf), req);
if (err) {
return (err);
}
return (-blake3_impl_setname(buf));
}
#endif
#undef IMPL_FMT
ZFS_MODULE_VIRTUAL_PARAM_CALL(zfs, zfs_, blake3_impl,
blake3_param_set, blake3_param_get, ZMOD_RW, \
"Select BLAKE3 implementation.");
#endif