From d2f5cb3a50d5eb156eb97c7e9a6ed3ad9cd95af6 Mon Sep 17 00:00:00 2001 From: Tony Hutter Date: Sun, 22 Feb 2026 11:43:51 -0800 Subject: [PATCH] Move range_tree, btree, highbit64 to common code Break out the range_tree, btree, and highbit64/lowbit64 code from kernel space into shared kernel and userspace code. This is needed for the updated `zpool status -vv` error byte range reporting that will be coming in a future commit. That commit needs the range_tree code in kernel and userspace. Reviewed-by: Rob Norris Reviewed-by: Brian Behlendorf Signed-off-by: Tony Hutter Closes #18133 --- cmd/Makefile.am | 4 ++-- cmd/zdb/Makefile.am | 4 +++- cmd/zpool/zpool_util.c | 26 -------------------------- cmd/zpool/zpool_util.h | 2 -- include/sys/btree.h | 9 ++++++--- lib/Makefile.am | 28 +++++++++++++++------------- lib/libbtree/Makefile.am | 6 ++++++ lib/librange_tree/Makefile.am | 9 +++++++++ lib/libspl/include/sys/sysmacros.h | 29 +++++++++++++++++++++++++++-- lib/libzfs/Makefile.am | 9 +++++++++ lib/libzpool/Makefile.am | 11 +++++++++-- lib/libzpool/kernel.c | 28 ---------------------------- module/zfs/btree.c | 17 ++++++++++++++++- module/zfs/range_tree.c | 20 ++++++++++++++------ tests/zfs-tests/cmd/Makefile.am | 3 +-- 15 files changed, 117 insertions(+), 88 deletions(-) create mode 100644 lib/libbtree/Makefile.am create mode 100644 lib/librange_tree/Makefile.am diff --git a/cmd/Makefile.am b/cmd/Makefile.am index ef9fdd31a..6f8d0c4b1 100644 --- a/cmd/Makefile.am +++ b/cmd/Makefile.am @@ -36,8 +36,8 @@ zhack_SOURCES = \ zhack_LDADD = \ libzpool.la \ libzfs_core.la \ - libnvpair.la - + libnvpair.la \ + librange_tree.la ztest_CFLAGS = $(AM_CFLAGS) $(KERNEL_CFLAGS) ztest_CPPFLAGS = $(AM_CPPFLAGS) $(LIBZPOOL_CPPFLAGS) diff --git a/cmd/zdb/Makefile.am b/cmd/zdb/Makefile.am index 4ab982f60..57be1568e 100644 --- a/cmd/zdb/Makefile.am +++ b/cmd/zdb/Makefile.am @@ -14,6 +14,8 @@ zdb_LDADD = \ libzdb.la \ libzpool.la \ libzfs_core.la \ - libnvpair.la + libnvpair.la \ + libbtree.la \ + librange_tree.la zdb_LDADD += $(LIBCRYPTO_LIBS) diff --git a/cmd/zpool/zpool_util.c b/cmd/zpool/zpool_util.c index ff2597ef6..11257f77d 100644 --- a/cmd/zpool/zpool_util.c +++ b/cmd/zpool/zpool_util.c @@ -114,29 +114,3 @@ array64_max(uint64_t array[], unsigned int len) return (max); } - -/* - * Find highest one bit set. - * Returns bit number + 1 of highest bit that is set, otherwise returns 0. - */ -int -highbit64(uint64_t i) -{ - if (i == 0) - return (0); - - return (NBBY * sizeof (uint64_t) - __builtin_clzll(i)); -} - -/* - * Find lowest one bit set. - * Returns bit number + 1 of lowest bit that is set, otherwise returns 0. - */ -int -lowbit64(uint64_t i) -{ - if (i == 0) - return (0); - - return (__builtin_ffsll(i)); -} diff --git a/cmd/zpool/zpool_util.h b/cmd/zpool/zpool_util.h index 3af23c52b..6869f57aa 100644 --- a/cmd/zpool/zpool_util.h +++ b/cmd/zpool/zpool_util.h @@ -45,8 +45,6 @@ void *safe_realloc(void *, size_t); void zpool_no_memory(void); uint_t num_logs(nvlist_t *nv); uint64_t array64_max(uint64_t array[], unsigned int len); -int highbit64(uint64_t i); -int lowbit64(uint64_t i); /* * Misc utility functions diff --git a/include/sys/btree.h b/include/sys/btree.h index 2ac811da0..50125530d 100644 --- a/include/sys/btree.h +++ b/include/sys/btree.h @@ -191,9 +191,11 @@ void zfs_btree_fini(void); * size - the value of sizeof(struct my_type) * lsize - custom leaf size */ -void zfs_btree_create(zfs_btree_t *, int (*) (const void *, const void *), +void zfs_btree_create(zfs_btree_t *, + int (*) (const void *, const void *), bt_find_in_buf_f, size_t); -void zfs_btree_create_custom(zfs_btree_t *, int (*)(const void *, const void *), +void zfs_btree_create_custom(zfs_btree_t *, + int (*)(const void *, const void *), bt_find_in_buf_f, size_t, size_t); /* @@ -213,7 +215,8 @@ void *zfs_btree_find(zfs_btree_t *, const void *, zfs_btree_index_t *); * node - the node to insert * where - position as returned from zfs_btree_find() */ -void zfs_btree_add_idx(zfs_btree_t *, const void *, const zfs_btree_index_t *); +void zfs_btree_add_idx(zfs_btree_t *, const void *, + const zfs_btree_index_t *); /* * Return the first or last valued node in the tree. Will return NULL if the diff --git a/lib/Makefile.am b/lib/Makefile.am index f9ef28177..33db8b9db 100644 --- a/lib/Makefile.am +++ b/lib/Makefile.am @@ -12,19 +12,19 @@ # # CMDS: zhack/ztest/ zfs/zpool/zed/ # raidz_{test,bench} zinject/zstream -# | | -# LIBS: | | libzfsbootenv* -# |--libzdb--zdb | | -# | | | -# libzpool libzfs* ----------------+ -# | | \ / | | | -# libicp --/ | \ / | \ | -# | \ / | \ \ -# libzstd ---/ \ / | \ \-------\ -# \ / \ \ \ -# \ / \ \-------\ \ -# \ / \ \ | -# libzutil libzfs_core* | | +# | \_____ / | +# LIBS: | \ / | libzfsbootenv* +# |--libzdb--zdb \ / | | +# | | | / | | +# libzpool-\ | | //-libzfs* --------------+ +# | | \ \ | | // / | \ \ +# libicp --/ | \ \ | | // / | \ \ +# | \ librange_tree / | \ \ +# libzstd ---/ \ libbtree / | \ \-------- +# \ / \ \ \ +# \ / \ \------ | +# \ / \ \ | +# libzutil libzfs_core* | | # | | | \ | | | | # | | | | | | | | # | | | | | | | | @@ -55,8 +55,10 @@ noinst_LTLIBRARIES = lib_LTLIBRARIES = pkgconfig_DATA = include $(srcdir)/%D%/libavl/Makefile.am +include $(srcdir)/%D%/libbtree/Makefile.am include $(srcdir)/%D%/libicp/Makefile.am include $(srcdir)/%D%/libnvpair/Makefile.am +include $(srcdir)/%D%/librange_tree/Makefile.am include $(srcdir)/%D%/libspl/Makefile.am include $(srcdir)/%D%/libzdb/Makefile.am include $(srcdir)/%D%/libzfs_core/Makefile.am diff --git a/lib/libbtree/Makefile.am b/lib/libbtree/Makefile.am new file mode 100644 index 000000000..1b310cce7 --- /dev/null +++ b/lib/libbtree/Makefile.am @@ -0,0 +1,6 @@ +# SPDX-License-Identifier: CDDL-1.0 +libbtree_la_CFLAGS = $(AM_CFLAGS) $(KERNEL_CFLAGS) $(LIBRARY_CFLAGS) + +noinst_LTLIBRARIES += libbtree.la + +nodist_libbtree_la_SOURCES = module/zfs/btree.c diff --git a/lib/librange_tree/Makefile.am b/lib/librange_tree/Makefile.am new file mode 100644 index 000000000..1c2aa833e --- /dev/null +++ b/lib/librange_tree/Makefile.am @@ -0,0 +1,9 @@ +# SPDX-License-Identifier: CDDL-1.0 +librange_tree_la_CFLAGS = $(AM_CFLAGS) $(KERNEL_CFLAGS) $(LIBRARY_CFLAGS) +librange_tree_la_CFLAGS += -fvisibility=hidden + +noinst_LTLIBRARIES += librange_tree.la + +nodist_librange_tree_la_SOURCES = \ + module/zfs/btree.c \ + module/zfs/range_tree.c diff --git a/lib/libspl/include/sys/sysmacros.h b/lib/libspl/include/sys/sysmacros.h index e33915c8d..12edf0f95 100644 --- a/lib/libspl/include/sys/sysmacros.h +++ b/lib/libspl/include/sys/sysmacros.h @@ -30,6 +30,7 @@ #define _LIBSPL_SYS_SYSMACROS_H #include +#include #ifdef __linux__ /* @@ -120,7 +121,31 @@ #define CPU_SEQID ((uintptr_t)pthread_self() & (max_ncpus - 1)) #define CPU_SEQID_UNSTABLE CPU_SEQID -extern int lowbit64(uint64_t i); -extern int highbit64(uint64_t i); +/* + * Find highest one bit set. + * Returns bit number + 1 of highest bit that is set, otherwise returns 0. + */ +static inline int +highbit64(uint64_t i) +{ + if (i == 0) + return (0); + + return (CHAR_BIT * sizeof (uint64_t) - __builtin_clzll(i)); +} + +/* + * Find lowest one bit set. + * Returns bit number + 1 of lowest bit that is set, otherwise returns 0. + * The __builtin_ffsll() function is supported by both GCC and Clang. + */ +static inline int +lowbit64(uint64_t i) +{ + if (i == 0) + return (0); + + return (__builtin_ffsll(i)); +} #endif /* _SYS_SYSMACROS_H */ diff --git a/lib/libzfs/Makefile.am b/lib/libzfs/Makefile.am index 4b3fc04ff..43b65d4dc 100644 --- a/lib/libzfs/Makefile.am +++ b/lib/libzfs/Makefile.am @@ -59,6 +59,15 @@ nodist_libzfs_la_SOURCES = \ module/zcommon/zpool_prop.c \ module/zcommon/zprop_common.c +# Special case: +# +# We need to include btree.c and range_tree.c as SOURCES rather than +# LIBADD'ing them. This is because LIBADD'ing them will add their symbols to +# the libzfs API, which we do not want at this time. +nodist_libzfs_la_SOURCES += \ + module/zfs/btree.c \ + module/zfs/range_tree.c + libzfs_la_LIBADD = \ libzfs_core.la \ libnvpair.la \ diff --git a/lib/libzpool/Makefile.am b/lib/libzpool/Makefile.am index 6e2028093..f8f128268 100644 --- a/lib/libzpool/Makefile.am +++ b/lib/libzpool/Makefile.am @@ -74,7 +74,6 @@ nodist_libzpool_la_SOURCES = \ module/zfs/bpobj.c \ module/zfs/bptree.c \ module/zfs/bqueue.c \ - module/zfs/btree.c \ module/zfs/brt.c \ module/zfs/dbuf.c \ module/zfs/dbuf_stats.c \ @@ -119,7 +118,6 @@ nodist_libzpool_la_SOURCES = \ module/zfs/multilist.c \ module/zfs/objlist.c \ module/zfs/pathname.c \ - module/zfs/range_tree.c \ module/zfs/refcount.c \ module/zfs/rrwlock.c \ module/zfs/sa.c \ @@ -196,6 +194,15 @@ nodist_libzpool_la_SOURCES = \ module/zfs/zrlock.c \ module/zfs/zthr.c +# Special case: +# +# We need to include btree.c and range_tree.c as SOURCES rather than +# LIBADD'ing them. This is because LIBADD'ing them will add their symbols to +# the libzpool API, which we do not want at this time. +nodist_libzpool_la_SOURCES += \ + module/zfs/btree.c \ + module/zfs/range_tree.c + libzpool_la_LIBADD = \ libicp.la \ libnvpair.la \ diff --git a/lib/libzpool/kernel.c b/lib/libzpool/kernel.c index 7e3ffec3b..197e0d178 100644 --- a/lib/libzpool/kernel.c +++ b/lib/libzpool/kernel.c @@ -315,34 +315,6 @@ delay(clock_t ticks) (void) poll(0, 0, ticks * (1000 / hz)); } -/* - * Find highest one bit set. - * Returns bit number + 1 of highest bit that is set, otherwise returns 0. - * The __builtin_clzll() function is supported by both GCC and Clang. - */ -int -highbit64(uint64_t i) -{ - if (i == 0) - return (0); - - return (NBBY * sizeof (uint64_t) - __builtin_clzll(i)); -} - -/* - * Find lowest one bit set. - * Returns bit number + 1 of lowest bit that is set, otherwise returns 0. - * The __builtin_ffsll() function is supported by both GCC and Clang. - */ -int -lowbit64(uint64_t i) -{ - if (i == 0) - return (0); - - return (__builtin_ffsll(i)); -} - int ddi_strtoull(const char *str, char **nptr, int base, u_longlong_t *result) { diff --git a/module/zfs/btree.c b/module/zfs/btree.c index 725b96a3b..1cc4add4c 100644 --- a/module/zfs/btree.c +++ b/module/zfs/btree.c @@ -21,7 +21,11 @@ #include #include -kmem_cache_t *zfs_btree_leaf_cache; +#ifndef _KERNEL +#define panic(...) PANIC(__VA_ARGS__) +#endif + +kmem_cache_t *zfs_btree_leaf_cache = NULL; /* * Control the extent of the verification that occurs when zfs_btree_verify is @@ -106,6 +110,8 @@ zfs_btree_poison_node(zfs_btree_t *tree, zfs_btree_hdr_t *hdr) tree->bt_leaf_size - offsetof(zfs_btree_leaf_t, btl_elems) - (hdr->bth_first + hdr->bth_count) * size); } +#else + (void) tree; (void) hdr; #endif } @@ -132,6 +138,8 @@ zfs_btree_poison_node_at(zfs_btree_t *tree, zfs_btree_hdr_t *hdr, (void) memset(leaf->btl_elems + (hdr->bth_first + idx) * size, 0x0f, count * size); } +#else + (void) tree; (void) hdr; (void) idx; (void) count; #endif } @@ -158,6 +166,8 @@ zfs_btree_verify_poison_at(zfs_btree_t *tree, zfs_btree_hdr_t *hdr, * size + i], ==, 0x0f); } } +#else + (void) tree; (void) hdr; (void) idx; #endif } @@ -196,6 +206,9 @@ void zfs_btree_create(zfs_btree_t *tree, int (*compar) (const void *, const void *), bt_find_in_buf_f bt_find_in_buf, size_t size) { + /* Verify zfs_btree_init() was called before zfs_btree_create() */ + ASSERT(zfs_btree_leaf_cache != NULL); + zfs_btree_create_custom(tree, compar, bt_find_in_buf, size, BTREE_LEAF_SIZE); } @@ -2185,6 +2198,8 @@ zfs_btree_verify_poison(zfs_btree_t *tree) if (tree->bt_height == -1) return; zfs_btree_verify_poison_helper(tree, tree->bt_root); +#else + (void) tree; #endif } diff --git a/module/zfs/range_tree.c b/module/zfs/range_tree.c index d73195f1a..341b02a03 100644 --- a/module/zfs/range_tree.c +++ b/module/zfs/range_tree.c @@ -34,6 +34,16 @@ #include #include #include +#include + +#ifndef _KERNEL +/* + * Need the extra 'abort()' here since is possible for PANIC() to return, and + * our panic() usage in this file assumes it's NORETURN. + */ +#define panic(...) do {PANIC(__VA_ARGS__); abort(); } while (0); +#define zfs_panic_recover(...) panic(__VA_ARGS__) +#endif /* * Range trees are tree-based data structures that can be used to @@ -116,12 +126,10 @@ zfs_range_tree_stat_verify(zfs_range_tree_t *rt) } for (i = 0; i < ZFS_RANGE_TREE_HISTOGRAM_SIZE; i++) { - if (hist[i] != rt->rt_histogram[i]) { - zfs_dbgmsg("i=%d, hist=%px, hist=%llu, rt_hist=%llu", - i, hist, (u_longlong_t)hist[i], - (u_longlong_t)rt->rt_histogram[i]); - } - VERIFY3U(hist[i], ==, rt->rt_histogram[i]); + VERIFY3UF(hist[i], ==, rt->rt_histogram[i], + "i=%d, hist=%px, hist=%llu, rt_hist=%llu", + i, hist, (u_longlong_t)hist[i], + (u_longlong_t)rt->rt_histogram[i]); } } diff --git a/tests/zfs-tests/cmd/Makefile.am b/tests/zfs-tests/cmd/Makefile.am index 6be5bd550..9683834f8 100644 --- a/tests/zfs-tests/cmd/Makefile.am +++ b/tests/zfs-tests/cmd/Makefile.am @@ -28,8 +28,7 @@ scripts_zfs_tests_bin_PROGRAMS += %D%/btree_test %C%_btree_test_CPPFLAGS = $(AM_CPPFLAGS) $(LIBZPOOL_CPPFLAGS) %C%_btree_test_LDADD = \ libzpool.la \ - libzfs_core.la - + libbtree.la scripts_zfs_tests_bin_PROGRAMS += %D%/crypto_test %C%_crypto_test_SOURCES = %D%/crypto_test.c