diff --git a/lib/libspl/Makefile.am b/lib/libspl/Makefile.am index f8943572bf29..6640ecd582a7 100644 --- a/lib/libspl/Makefile.am +++ b/lib/libspl/Makefile.am @@ -1,52 +1,53 @@ include $(srcdir)/%D%/include/Makefile.am libspl_assert_la_CFLAGS = $(AM_CFLAGS) $(LIBRARY_CFLAGS) $(LIBUNWIND_CFLAGS) libspl_la_CFLAGS = $(libspl_assert_la_CFLAGS) noinst_LTLIBRARIES += libspl_assert.la libspl.la CPPCHECKTARGETS += libspl_assert.la libspl.la libspl_assert_la_SOURCES = \ %D%/assert.c \ %D%/backtrace.c libspl_la_SOURCES = \ %D%/libspl_impl.h \ %D%/atomic.c \ %D%/getexecname.c \ %D%/list.c \ %D%/mkdirp.c \ %D%/page.c \ %D%/strlcat.c \ %D%/strlcpy.c \ %D%/timestamp.c \ + %D%/tunables.c \ %D%/include/sys/list.h \ %D%/include/sys/list_impl.h if BUILD_LINUX libspl_la_SOURCES += \ %D%/os/linux/getexecname.c \ %D%/os/linux/gethostid.c \ %D%/os/linux/getmntany.c \ %D%/os/linux/zone.c endif if BUILD_FREEBSD libspl_la_SOURCES += \ %D%/os/freebsd/getexecname.c \ %D%/os/freebsd/gethostid.c \ %D%/os/freebsd/getmntany.c \ %D%/os/freebsd/mnttab.c \ %D%/os/freebsd/zone.c endif libspl_la_LIBADD = \ libspl_assert.la libspl_la_LIBADD += $(LIBATOMIC_LIBS) $(LIBCLOCK_GETTIME) libspl_assert_la_LIBADD = $(BACKTRACE_LIBS) $(LIBUNWIND_LIBS) if BUILD_FREEBSD libspl_assert_la_LIBADD += -lpthread endif diff --git a/lib/libspl/include/Makefile.am b/lib/libspl/include/Makefile.am index e17119e968ef..21f0c70db9e7 100644 --- a/lib/libspl/include/Makefile.am +++ b/lib/libspl/include/Makefile.am @@ -1,107 +1,108 @@ libspldir = $(includedir)/libspl libspl_HEADERS = \ %D%/assert.h \ %D%/atomic.h \ %D%/libgen.h \ %D%/libshare.h \ %D%/statcommon.h \ %D%/stdlib.h \ %D%/string.h \ %D%/umem.h \ %D%/unistd.h \ %D%/zone.h if BUILD_FREEBSD libspl_HEADERS += \ %D%/os/freebsd/fcntl.h endif libspl_rpcdir = $(libspldir)/rpc libspl_rpc_HEADERS = \ %D%/rpc/xdr.h libspl_sysdir = $(libspldir)/sys libspl_sys_HEADERS = \ %D%/sys/abd_os.h \ %D%/sys/abd_impl_os.h \ %D%/sys/acl.h \ %D%/sys/acl_impl.h \ %D%/sys/asm_linkage.h \ %D%/sys/backtrace.h \ %D%/sys/callb.h \ %D%/sys/cmn_err.h \ %D%/sys/cred.h \ %D%/sys/debug.h \ %D%/sys/dkio.h \ %D%/sys/dklabel.h \ %D%/sys/feature_tests.h \ %D%/sys/inttypes.h \ %D%/sys/isa_defs.h \ %D%/sys/kmem.h \ %D%/sys/kstat.h \ %D%/sys/list.h \ %D%/sys/list_impl.h \ %D%/sys/mhd.h \ %D%/sys/mkdev.h \ %D%/sys/mod.h \ %D%/sys/policy.h \ %D%/sys/poll.h \ %D%/sys/priv.h \ %D%/sys/processor.h \ %D%/sys/simd.h \ %D%/sys/stack.h \ %D%/sys/stdtypes.h \ %D%/sys/string.h \ %D%/sys/sunddi.h \ %D%/sys/systeminfo.h \ %D%/sys/time.h \ %D%/sys/trace_spl.h \ %D%/sys/trace_zfs.h \ + %D%/sys/tunables.h \ %D%/sys/types.h \ %D%/sys/types32.h \ %D%/sys/uio.h \ %D%/sys/vnode.h \ %D%/sys/wmsum.h \ %D%/sys/zone.h libspl_ia32dir = $(libspldir)/sys/ia32 if BUILD_LINUX libspl_sys_HEADERS += \ %D%/os/linux/sys/byteorder.h \ %D%/os/linux/sys/errno.h \ %D%/os/linux/sys/mnttab.h \ %D%/os/linux/sys/mount.h \ %D%/os/linux/sys/param.h \ %D%/os/linux/sys/stat.h \ %D%/os/linux/sys/sysmacros.h \ %D%/os/linux/sys/zfs_context_os.h libspl_ia32_HEADERS = \ %D%/os/linux/sys/ia32/asm_linkage.h endif if BUILD_FREEBSD libspl_sys_HEADERS += \ %D%/os/freebsd/sys/byteorder.h \ %D%/os/freebsd/sys/fcntl.h \ %D%/os/freebsd/sys/file.h \ %D%/os/freebsd/sys/mnttab.h \ %D%/os/freebsd/sys/mount.h \ %D%/os/freebsd/sys/param.h \ %D%/os/freebsd/sys/stat.h \ %D%/os/freebsd/sys/sysmacros.h \ %D%/os/freebsd/sys/vfs.h \ %D%/os/freebsd/sys/zfs_context_os.h libspl_ia32_HEADERS = \ %D%/os/freebsd/sys/ia32/asm_linkage.h endif libspl_sys_dktpdir = $(libspl_sysdir)/dktp libspl_sys_dktp_HEADERS = \ %D%/sys/dktp/fdisk.h diff --git a/lib/libspl/include/sys/mod.h b/lib/libspl/include/sys/mod.h index b1a39e91309e..ad19b6607a42 100644 --- a/lib/libspl/include/sys/mod.h +++ b/lib/libspl/include/sys/mod.h @@ -1,39 +1,56 @@ // SPDX-License-Identifier: CDDL-1.0 /* * 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) 2005, 2010, Oracle and/or its affiliates. All rights reserved. * Copyright 2011 Nexenta Systems, Inc. All rights reserved. * Copyright (c) 2012, 2018 by Delphix. All rights reserved. * Copyright (c) 2012, Joyent, Inc. All rights reserved. + * Copyright (c) 2025, Rob Norris */ #ifndef _SYS_MOD_H #define _SYS_MOD_H -#define ZFS_MODULE_PARAM(scope, prefix, name, type, perm, desc) +#include + +#define ZFS_MODULE_PARAM(scope, prefix, name, type, perm, desc) \ + static const zfs_tunable_t _zfs_tunable_##prefix##name = { \ + .zt_name = #prefix#name, \ + .zt_varp = &prefix##name, \ + .zt_varsz = sizeof (prefix##name), \ + .zt_type = ZFS_TUNABLE_TYPE_##type, \ + .zt_perm = ZFS_TUNABLE_PERM_##perm, \ + .zt_desc = desc \ + }; \ + static const zfs_tunable_t * \ + __zfs_tunable_##prefix##name \ + __attribute__((__section__("zfs_tunables"))) \ + __attribute__((__used__)) \ + = &_zfs_tunable_##prefix##name; + #define ZFS_MODULE_PARAM_ARGS void #define ZFS_MODULE_PARAM_CALL(scope_prefix, name_prefix, name, setfunc, \ getfunc, perm, desc) #define EXPORT_SYMBOL(x) #endif diff --git a/lib/libspl/include/sys/mod.h b/lib/libspl/include/sys/tunables.h similarity index 61% copy from lib/libspl/include/sys/mod.h copy to lib/libspl/include/sys/tunables.h index b1a39e91309e..9c7036791eec 100644 --- a/lib/libspl/include/sys/mod.h +++ b/lib/libspl/include/sys/tunables.h @@ -1,39 +1,52 @@ // SPDX-License-Identifier: CDDL-1.0 /* * 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) 2005, 2010, Oracle and/or its affiliates. All rights reserved. - * Copyright 2011 Nexenta Systems, Inc. All rights reserved. - * Copyright (c) 2012, 2018 by Delphix. All rights reserved. - * Copyright (c) 2012, Joyent, Inc. All rights reserved. + * Copyright (c) 2025, Rob Norris */ -#ifndef _SYS_MOD_H -#define _SYS_MOD_H +#ifndef _SYS_TUNABLES_H +#define _SYS_TUNABLES_H + +typedef enum { + ZFS_TUNABLE_TYPE_INT, + ZFS_TUNABLE_TYPE_UINT, + ZFS_TUNABLE_TYPE_ULONG, + ZFS_TUNABLE_TYPE_U64, + ZFS_TUNABLE_TYPE_STRING, +} zfs_tunable_type_t; -#define ZFS_MODULE_PARAM(scope, prefix, name, type, perm, desc) -#define ZFS_MODULE_PARAM_ARGS void -#define ZFS_MODULE_PARAM_CALL(scope_prefix, name_prefix, name, setfunc, \ - getfunc, perm, desc) +typedef enum { + ZFS_TUNABLE_PERM_ZMOD_RW, + ZFS_TUNABLE_PERM_ZMOD_RD, +} zfs_tunable_perm_t; -#define EXPORT_SYMBOL(x) +typedef struct zfs_tunable { + const char *zt_name; + void *zt_varp; + size_t zt_varsz; + zfs_tunable_type_t zt_type; + zfs_tunable_perm_t zt_perm; + const char *zt_desc; +} zfs_tunable_t; #endif diff --git a/lib/libspl/tunables.c b/lib/libspl/tunables.c new file mode 100644 index 000000000000..8ad74fc95efc --- /dev/null +++ b/lib/libspl/tunables.c @@ -0,0 +1,72 @@ +// SPDX-License-Identifier: CDDL-1.0 +/* + * 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) 2025, Rob Norris + */ + +#include +#include + +/* + * Userspace tunables. + * + * Tunables are external pointers to global variables that are wired up to the + * host environment in some way that allows the operator to directly change + * their values "under the hood". + * + * In userspace, the "host environment" is the program using libzpool.so. So + * that it can manipulate tunables if it wants, we provide an API to access + * them. + * + * Tunables are declared through the ZFS_MODULE_PARAM* macros, which associate + * a global variable with some metadata we can use to describe and access the + * tunable. This is done by creating a uniquely-named zfs_tunable_t. + * + * At runtime, we need a way to discover these zfs_tunable_t items. Since they + * are declared globally, all over the codebase, there's no central place to + * record or list them. So, we take advantage of the compiler's "linker set" + * feature. + * + * In the ZFS_MODULE_PARAM macro, after we create the zfs_tunable_t, we also + * create a zfs_tunable_t* pointing to it. That pointer is forced into the + * "zfs_tunables" ELF section in compiled object. At link time, the linker will + * collect all these pointers into one single big "zfs_tunable" section, and + * will generate two new symbols in the final object: __start_zfs_tunable and + * __stop_zfs_tunable. These point to the first and last item in that section, + * which allows us to access the pointers in that section like an array, and + * through those pointers access the tunable metadata, and from there the + * actual C variable that the tunable describes. + */ + +extern const zfs_tunable_t *__start_zfs_tunables; +extern const zfs_tunable_t *__stop_zfs_tunables; + +/* + * Because there are no tunables in libspl itself, the above symbols will not + * be generated, which will stop libspl being linked at all. To work around + * that, we force a symbol into that section, and then when iterating, skip + * any NULL pointers. + */ +static void *__zfs_tunable__placeholder + __attribute__((__section__("zfs_tunables"))) + __attribute__((__used__)) = NULL;