]> git.proxmox.com Git - mirror_zfs.git/commitdiff
Add libtpool (thread pools)
authorBrian Behlendorf <behlendorf1@llnl.gov>
Wed, 9 Aug 2017 22:31:08 +0000 (15:31 -0700)
committerGitHub <noreply@github.com>
Wed, 9 Aug 2017 22:31:08 +0000 (15:31 -0700)
OpenZFS provides a library called tpool which implements thread
pools for user space applications.  Porting this library means
the zpool utility no longer needs to borrow the kernel mutex and
taskq interfaces from libzpool.  This code was updated to use
the tpool library which behaves in a very similar fashion.

Porting libtpool was relatively straight forward and minimal
modifications were needed.  The core changes were:

* Fully convert the library to use pthreads.
* Updated signal handling.
* lmalloc/lfree converted to calloc/free
* Implemented portable pthread_attr_clone() function.

Finally, update the build system such that libzpool.so is no
longer linked in to zfs(8), zpool(8), etc.  All that is required
is libzfs to which the zcommon soures were added (which is the way
it always should have been).  Removing the libzpool dependency
resulted in several build issues which needed to be resolved.

* Moved zfeature support to module/zcommon/zfeature_common.c
* Moved ratelimiting to to module/zfs/zfs_ratelimit.c
* Moved get_system_hostid() to lib/libspl/gethostid.c
* Removed use of cmn_err() in zcommon source
* Removed dprintf_setup() call from zpool_main.c and zfs_main.c
* Removed highbit() and lowbit()
* Removed unnecessary library dependencies from Makefiles
* Removed fletcher-4 kstat in user space
* Added sha2 support explicitly to libzfs
* Added highbit64() and lowbit64() to zpool_util.c

Reviewed-by: Tony Hutter <hutter2@llnl.gov>
Signed-off-by: Brian Behlendorf <behlendorf1@llnl.gov>
Closes #6442

47 files changed:
cmd/mount_zfs/Makefile.am
cmd/raidz_test/Makefile.am
cmd/zdb/Makefile.am
cmd/zed/Makefile.am
cmd/zfs/Makefile.am
cmd/zfs/zfs_main.c
cmd/zhack/Makefile.am
cmd/zinject/Makefile.am
cmd/zpool/Makefile.am
cmd/zpool/zpool_iter.c
cmd/zpool/zpool_main.c
cmd/zpool/zpool_util.c
cmd/zpool/zpool_util.h
cmd/zstreamdump/Makefile.am
cmd/ztest/Makefile.am
configure.ac
include/Makefile.am
include/libzfs.h
include/sys/zfs_context.h
include/thread_pool.h [new file with mode: 0644]
lib/Makefile.am
lib/libnvpair/Makefile.am
lib/libspl/Makefile.am
lib/libspl/gethostid.c [new file with mode: 0644]
lib/libspl/include/sys/systeminfo.h
lib/libtpool/Makefile.am [new file with mode: 0644]
lib/libtpool/thread_pool.c [new file with mode: 0644]
lib/libtpool/thread_pool_impl.h [new file with mode: 0644]
lib/libuutil/Makefile.am
lib/libzfs/Makefile.am
lib/libzfs/libzfs_import.c
lib/libzfs/libzfs_pool.c
lib/libzfs/libzfs_status.c
lib/libzpool/Makefile.am
lib/libzpool/kernel.c
module/icp/algs/sha2/sha2.c
module/icp/os/modhash.c
module/zcommon/Makefile.in
module/zcommon/zfeature_common.c [new file with mode: 0644]
module/zcommon/zfs_comutil.c
module/zcommon/zfs_deleg.c
module/zcommon/zfs_fletcher.c
module/zfs/Makefile.in
module/zfs/zfeature_common.c [deleted file]
module/zfs/zfs_ratelimit.c [new file with mode: 0644]
scripts/zfs2zol-patch.sed
tests/zfs-tests/tests/functional/libzfs/Makefile.am

index b1d9389226e278e1be7e52fb5562d0b3f6d8e605..bc9fb4c34bba6c1b816b2dc00452043334d7d662 100644 (file)
@@ -16,7 +16,4 @@ mount_zfs_SOURCES = \
 
 mount_zfs_LDADD = \
        $(top_builddir)/lib/libnvpair/libnvpair.la \
-       $(top_builddir)/lib/libuutil/libuutil.la \
-       $(top_builddir)/lib/libzpool/libzpool.la \
-       $(top_builddir)/lib/libzfs/libzfs.la \
-       $(top_builddir)/lib/libzfs_core/libzfs_core.la
+       $(top_builddir)/lib/libzfs/libzfs.la
index 15edb2b1e1153420d5a98c00b447ab4ca968b1db..02cc746ec9263250a53e5e0c97bd379b49f846fe 100644 (file)
@@ -15,8 +15,6 @@ raidz_test_SOURCES = \
        raidz_bench.c
 
 raidz_test_LDADD = \
-       $(top_builddir)/lib/libnvpair/libnvpair.la \
-       $(top_builddir)/lib/libuutil/libuutil.la \
        $(top_builddir)/lib/libzpool/libzpool.la
 
 raidz_test_LDADD += -lm -ldl
index eb8e6777f5e7a861f856fe35ef6002fcedc5d929..ea6806b2c53c5a2d485080e450de7d5ce1f127e5 100644 (file)
@@ -14,7 +14,5 @@ zdb_SOURCES = \
 
 zdb_LDADD = \
        $(top_builddir)/lib/libnvpair/libnvpair.la \
-       $(top_builddir)/lib/libuutil/libuutil.la \
-       $(top_builddir)/lib/libzpool/libzpool.la \
        $(top_builddir)/lib/libzfs/libzfs.la \
-       $(top_builddir)/lib/libzfs_core/libzfs_core.la
+       $(top_builddir)/lib/libzpool/libzpool.la
index 97733a5125d663b27e1f3861d7096b602e30fbe8..53d5aa71c7d1812690434c8adadb24b2f9d275ca 100644 (file)
@@ -40,15 +40,12 @@ FMA_SRC = \
 zed_SOURCES = $(ZED_SRC) $(FMA_SRC)
 
 zed_LDADD = \
-       $(top_builddir)/lib/libavl/libavl.la \
        $(top_builddir)/lib/libnvpair/libnvpair.la \
-       $(top_builddir)/lib/libspl/libspl.la \
        $(top_builddir)/lib/libuutil/libuutil.la \
-       $(top_builddir)/lib/libzpool/libzpool.la \
-       $(top_builddir)/lib/libzfs/libzfs.la \
-       $(top_builddir)/lib/libzfs_core/libzfs_core.la
+       $(top_builddir)/lib/libzfs/libzfs.la
 
-zed_LDFLAGS = -lrt -pthread
+zed_LDADD += -lrt
+zed_LDFLAGS = -pthread
 
 zedconfdir = $(sysconfdir)/zfs/zed.d
 
index e40909516d576e186bf886b56c2cf8d2cb412262..4e689d1ee5e5b46f8f995d7e4e897ddc274294f5 100644 (file)
@@ -15,8 +15,5 @@ zfs_SOURCES = \
 zfs_LDADD = \
        $(top_builddir)/lib/libnvpair/libnvpair.la \
        $(top_builddir)/lib/libuutil/libuutil.la \
-       $(top_builddir)/lib/libzpool/libzpool.la \
        $(top_builddir)/lib/libzfs/libzfs.la \
        $(top_builddir)/lib/libzfs_core/libzfs_core.la
-
-zfs_LDFLAGS = -pthread
index e8fe6a9fa9bfb60c66a4f956c82b5643f53d1c4c..0d18ca7b6bba5da0bb297806327a6ca5bd5056c7 100644 (file)
@@ -55,6 +55,7 @@
 #include <sys/mount.h>
 #include <sys/stat.h>
 #include <sys/fs/zfs.h>
+#include <sys/systeminfo.h>
 #include <sys/types.h>
 #include <time.h>
 
@@ -7045,8 +7046,6 @@ main(int argc, char **argv)
        (void) setlocale(LC_ALL, "");
        (void) textdomain(TEXT_DOMAIN);
 
-       dprintf_setup(&argc, argv);
-
        opterr = 0;
 
        /*
index a7bce5ddee43d25278767937a1fa2fdec2c7c70f..f720e8286afd4d1ef922b58e78912cc53bbfaed0 100644 (file)
@@ -11,7 +11,5 @@ zhack_SOURCES = \
 
 zhack_LDADD = \
        $(top_builddir)/lib/libnvpair/libnvpair.la \
-       $(top_builddir)/lib/libuutil/libuutil.la \
-       $(top_builddir)/lib/libzpool/libzpool.la \
        $(top_builddir)/lib/libzfs/libzfs.la \
-       $(top_builddir)/lib/libzfs_core/libzfs_core.la
+       $(top_builddir)/lib/libzpool/libzpool.la
index 2500beec2b56ffc51145ffdf724f1a8ee903de30..b709a2f5a2920ffcc787840b65816d5146468e00 100644 (file)
@@ -13,7 +13,5 @@ zinject_SOURCES = \
 
 zinject_LDADD = \
        $(top_builddir)/lib/libnvpair/libnvpair.la \
-       $(top_builddir)/lib/libuutil/libuutil.la \
-       $(top_builddir)/lib/libzpool/libzpool.la \
        $(top_builddir)/lib/libzfs/libzfs.la \
-       $(top_builddir)/lib/libzfs_core/libzfs_core.la
+       $(top_builddir)/lib/libzpool/libzpool.la
index 6eff1d143202824a1155a9ec0f575a5f00e9d7f1..d7e1741c1d051af48693b1b189f617cf8a68645e 100644 (file)
@@ -16,10 +16,9 @@ zpool_SOURCES = \
 zpool_LDADD = \
        $(top_builddir)/lib/libnvpair/libnvpair.la \
        $(top_builddir)/lib/libuutil/libuutil.la \
-       $(top_builddir)/lib/libzpool/libzpool.la \
-       $(top_builddir)/lib/libzfs/libzfs.la \
-       $(top_builddir)/lib/libzfs_core/libzfs_core.la \
-       -lm $(LIBBLKID)
+       $(top_builddir)/lib/libzfs/libzfs.la
+
+zpool_LDADD += -lm $(LIBBLKID)
 
 zpoolconfdir = $(sysconfdir)/zfs/zpool.d
 zpoolexecdir = $(libexecdir)/zfs/zpool.d
index e55c2f10297d93d8ca48f99b36c5ed9623ab0d4d..019f0b136d80455d0f56dce958d61e50634652ca 100644 (file)
@@ -33,6 +33,7 @@
 #include <stdio.h>
 #include <stdlib.h>
 #include <strings.h>
+#include <thread_pool.h>
 
 #include <libzfs.h>
 #include <sys/zfs_context.h>
@@ -668,34 +669,21 @@ all_pools_for_each_vdev_gather_cb(zpool_handle_t *zhp, void *cb_vcdl)
 static void
 all_pools_for_each_vdev_run_vcdl(vdev_cmd_data_list_t *vcdl)
 {
-       taskq_t *t;
-       int i;
-       /* 5 * boot_ncpus selfishly chosen since it works best on LLNL's HW */
-       int max_threads = 5 * boot_ncpus;
-
-       /*
-        * Under Linux we use a taskq to parallelize running a command
-        * on each vdev.  It is therefore necessary to initialize this
-        * functionality for the duration of the threads.
-        */
-       thread_init();
+       tpool_t *t;
 
-       t = taskq_create("z_pool_cmd", max_threads, defclsyspri, max_threads,
-           INT_MAX, 0);
+       t = tpool_create(1, 5 * sysconf(_SC_NPROCESSORS_ONLN), 0, NULL);
        if (t == NULL)
                return;
 
        /* Spawn off the command for each vdev */
-       for (i = 0; i < vcdl->count; i++) {
-               (void) taskq_dispatch(t, vdev_run_cmd_thread,
-                   (void *) &vcdl->data[i], TQ_SLEEP);
+       for (int i = 0; i < vcdl->count; i++) {
+               (void) tpool_dispatch(t, vdev_run_cmd_thread,
+                   (void *) &vcdl->data[i]);
        }
 
        /* Wait for threads to finish */
-       taskq_wait(t);
-       taskq_destroy(t);
-       thread_fini();
-
+       tpool_wait(t);
+       tpool_destroy(t);
 }
 
 /*
index 338b9952cde7ba07470a8bd6b2f4f400d9896360..60713197db5b55a2dd107d360b8cc4d2a6dfa95e 100644 (file)
@@ -50,6 +50,7 @@
 #include <zfs_prop.h>
 #include <sys/fs/zfs.h>
 #include <sys/stat.h>
+#include <sys/systeminfo.h>
 #include <sys/fm/fs/zfs.h>
 #include <sys/fm/util.h>
 #include <sys/fm/protocol.h>
@@ -2645,15 +2646,7 @@ zpool_do_import(int argc, char **argv)
        idata.cachefile = cachefile;
        idata.scan = do_scan;
 
-       /*
-        * Under Linux the zpool_find_import_impl() function leverages the
-        * taskq implementation to parallelize device scanning.  It is
-        * therefore necessary to initialize this functionality for the
-        * duration of the zpool_search_import() function.
-        */
-       thread_init();
        pools = zpool_search_import(g_zfs, &idata);
-       thread_fini();
 
        if (pools != NULL && idata.exists &&
            (argc == 1 || strcmp(argv[0], argv[1]) == 0)) {
@@ -7968,8 +7961,6 @@ main(int argc, char **argv)
        (void) textdomain(TEXT_DOMAIN);
        srand(time(NULL));
 
-       dprintf_setup(&argc, argv);
-
        opterr = 0;
 
        /*
index 43abfa23b0b8212ce686114361ee276210de0d8a..c26c0eb3969b717ba66996cb6b30f96799986604 100644 (file)
@@ -111,3 +111,29 @@ isnumber(char *str)
 
        return (1);
 }
+
+/*
+ * 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));
+}
index aef2cff27d29e0aaa322f3a9ab8acb366ed4e770..3afc82d54b5282e0044500151920acf9b7b553c3 100644 (file)
@@ -43,6 +43,8 @@ void zpool_no_memory(void);
 uint_t num_logs(nvlist_t *nv);
 uint64_t array64_max(uint64_t array[], unsigned int len);
 int isnumber(char *str);
+int highbit64(uint64_t i);
+int lowbit64(uint64_t i);
 
 /*
  * Misc utility functions
index b46958d65af7ace41254db3ae376a837836e7337..f80b5018e04ee67d80c2261ceab74adf15b9229b 100644 (file)
@@ -11,7 +11,4 @@ zstreamdump_SOURCES = \
 
 zstreamdump_LDADD = \
        $(top_builddir)/lib/libnvpair/libnvpair.la \
-       $(top_builddir)/lib/libuutil/libuutil.la \
-       $(top_builddir)/lib/libzpool/libzpool.la \
-       $(top_builddir)/lib/libzfs/libzfs.la \
-       $(top_builddir)/lib/libzfs_core/libzfs_core.la
+       $(top_builddir)/lib/libzfs/libzfs.la
index 5167d0c1d86e7d1dcaa7e5f0d628c2e390aa9a33..930a7ec3a8a76390f2969a8bba5878c5995e1368 100644 (file)
@@ -16,9 +16,8 @@ ztest_SOURCES = \
 
 ztest_LDADD = \
        $(top_builddir)/lib/libnvpair/libnvpair.la \
-       $(top_builddir)/lib/libuutil/libuutil.la \
-       $(top_builddir)/lib/libzpool/libzpool.la \
        $(top_builddir)/lib/libzfs/libzfs.la \
-       $(top_builddir)/lib/libzfs_core/libzfs_core.la
+       $(top_builddir)/lib/libzpool/libzpool.la
 
 ztest_LDADD += -lm
+ztest_LDFLAGS = -pthread
index 0c7977ef80ea23d1a67a56c8245c28bdbb98d9f5..6d0270a7a522faaca54d31f938b1a90e79718e47 100644 (file)
@@ -87,6 +87,7 @@ AC_CONFIG_FILES([
        lib/libefi/Makefile
        lib/libicp/Makefile
        lib/libnvpair/Makefile
+       lib/libtpool/Makefile
        lib/libunicode/Makefile
        lib/libuutil/Makefile
        lib/libzpool/Makefile
index a94cad50da17016b087007e46319731da6034bdf..a5e98bba8ba3d20d9045e2644e33328d4872e280 100644 (file)
@@ -19,7 +19,8 @@ USER_H = \
        $(top_srcdir)/include/libuutil_impl.h \
        $(top_srcdir)/include/libzfs.h \
        $(top_srcdir)/include/libzfs_core.h \
-       $(top_srcdir)/include/libzfs_impl.h
+       $(top_srcdir)/include/libzfs_impl.h \
+       $(top_srcdir)/include/thread_pool.h
 
 EXTRA_DIST = $(COMMON_H) $(KERNEL_H) $(USER_H)
 
index 147589bbfdad3b8b4054d74f5a4c1ed99cf51dc5..d60ebbdbd08f3d86b499c0ffb9ec635a58cd015b 100644 (file)
@@ -368,7 +368,6 @@ typedef enum {
        ZPOOL_STATUS_OK
 } zpool_status_t;
 
-extern unsigned long get_system_hostid(void);
 extern zpool_status_t zpool_get_status(zpool_handle_t *, char **,
     zpool_errata_t *);
 extern zpool_status_t zpool_import_status(nvlist_t *, char **,
index 4fe35342dee78336db8847db59f19f6338659f23..21a9a8481f604dcd2d65460ebe7dd49ca9bd9a03 100644 (file)
@@ -668,15 +668,11 @@ extern uint64_t physmem;
 
 extern int highbit64(uint64_t i);
 extern int lowbit64(uint64_t i);
-extern int highbit(ulong_t i);
-extern int lowbit(ulong_t i);
 extern int random_get_bytes(uint8_t *ptr, size_t len);
 extern int random_get_pseudo_bytes(uint8_t *ptr, size_t len);
 
 extern void kernel_init(int);
 extern void kernel_fini(void);
-extern void thread_init(void);
-extern void thread_fini(void);
 extern void random_init(void);
 extern void random_fini(void);
 
diff --git a/include/thread_pool.h b/include/thread_pool.h
new file mode 100644 (file)
index 0000000..57266f1
--- /dev/null
@@ -0,0 +1,72 @@
+/*
+ * 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://www.opensolaris.org/os/licensing.
+ * 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 2006 Sun Microsystems, Inc.  All rights reserved.
+ * Use is subject to license terms.
+ */
+
+#ifndef        _THREAD_POOL_H_
+#define        _THREAD_POOL_H_
+
+#include <sys/types.h>
+#include <thread.h>
+#include <pthread.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+typedef        struct tpool tpool_t;   /* opaque thread pool descriptor */
+
+#if defined(__STDC__)
+
+extern tpool_t *tpool_create(uint_t min_threads, uint_t max_threads,
+                       uint_t linger, pthread_attr_t *attr);
+extern int     tpool_dispatch(tpool_t *tpool,
+                       void (*func)(void *), void *arg);
+extern void    tpool_destroy(tpool_t *tpool);
+extern void    tpool_abandon(tpool_t *tpool);
+extern void    tpool_wait(tpool_t *tpool);
+extern void    tpool_suspend(tpool_t *tpool);
+extern int     tpool_suspended(tpool_t *tpool);
+extern void    tpool_resume(tpool_t *tpool);
+extern int     tpool_member(tpool_t *tpool);
+
+#else  /* Non ANSI */
+
+extern tpool_t *tpool_create();
+extern int     tpool_dispatch();
+extern void    tpool_destroy();
+extern void    tpool_abandon();
+extern void    tpool_wait();
+extern void    tpool_suspend();
+extern int     tpool_suspended();
+extern void    tpool_resume();
+extern int     tpool_member();
+
+#endif /* __STDC__ */
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* _THREAD_POOL_H_ */
index 3aec922c93ca2312313cd7eb67b215640b5c0abf..e1833b842f949aa5db4c2b8ca3bae64bf5771af5 100644 (file)
@@ -1,6 +1,6 @@
 # NB: GNU Automake Manual, Chapter 8.3.5: Libtool Convenience Libraries
 # These six libraries are intermediary build components.
-SUBDIRS = libspl libavl libefi libshare libunicode libicp
+SUBDIRS = libavl libefi libicp libshare libspl libtpool libunicode
 
 # These four libraries, which are installed as the final build product,
 # incorporate the six convenience libraries given above.
index 2833557a30bf342748081e1d8aab31335c35b222..6da679fd50fc42d08e9424c039ccd670e35b1ea5 100644 (file)
@@ -25,9 +25,7 @@ nodist_libnvpair_la_SOURCES = \
        $(USER_C) \
        $(KERNEL_C)
 
-libnvpair_la_LIBADD = \
-       $(top_builddir)/lib/libuutil/libuutil.la \
-       $(LIBTIRPC)
+libnvpair_la_LIBADD = $(LIBTIRPC)
 libnvpair_la_LDFLAGS = -version-info 1:1:0
 
 EXTRA_DIST = $(USER_C)
index 3c99529f1aae375285ccd68f9a42cec1a04a5636..28ae153519f5c59a4d70fc5f873f28feb10574ec 100644 (file)
@@ -19,6 +19,7 @@ noinst_LTLIBRARIES = libspl.la
 
 USER_C = \
        getexecname.c \
+       gethostid.c \
        gethrtime.c \
        gethrestime.c \
        getmntany.c \
diff --git a/lib/libspl/gethostid.c b/lib/libspl/gethostid.c
new file mode 100644 (file)
index 0000000..1eb93f4
--- /dev/null
@@ -0,0 +1,86 @@
+/*
+ * 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://www.opensolaris.org/os/licensing.
+ * 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) 2017, Lawrence Livermore National Security, LLC.
+ */
+
+#include <fcntl.h>
+#include <stdlib.h>
+#include <stdio.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <sys/systeminfo.h>
+
+static unsigned long
+get_spl_hostid(void)
+{
+       FILE *f;
+       unsigned long hostid;
+       char *env;
+
+       /*
+        * Allow the hostid to be subverted for testing.
+        */
+       env = getenv("ZFS_HOSTID");
+       if (env) {
+               hostid = strtoull(env, NULL, 0);
+               return (hostid & HOSTID_MASK);
+       }
+
+       f = fopen("/sys/module/spl/parameters/spl_hostid", "r");
+       if (!f)
+               return (0);
+
+       if (fscanf(f, "%lu", &hostid) != 1)
+               hostid = 0;
+
+       fclose(f);
+
+       return (hostid & HOSTID_MASK);
+}
+
+unsigned long
+get_system_hostid(void)
+{
+       unsigned long system_hostid = get_spl_hostid();
+       /*
+        * We do not use the library call gethostid() because
+        * it generates a hostid value that the kernel is
+        * unaware of, if the spl_hostid module parameter has not
+        * been set and there is no system hostid file (e.g.
+        * /etc/hostid).  The kernel and userspace must agree.
+        * See comments above hostid_read() in the SPL.
+        */
+       if (system_hostid == 0) {
+               int fd, rc;
+               unsigned long hostid;
+               int hostid_size = 4;  /* 4 bytes regardless of arch */
+
+               fd = open("/etc/hostid", O_RDONLY);
+               if (fd >= 0) {
+                       rc = read(fd, &hostid, hostid_size);
+                       if (rc > 0)
+                               system_hostid = (hostid & HOSTID_MASK);
+                       close(fd);
+               }
+       }
+       return (system_hostid);
+}
index 3f7cef5b95b1367b33d439b74cb1d80a90cfc521..cc6c1793c00e6d5f1a743b29087129a2acd69dcd 100644 (file)
 #ifndef _LIBSPL_SYS_SYSTEMINFO_H
 #define        _LIBSPL_SYS_SYSTEMINFO_H
 
+#define        HOSTID_MASK             0xFFFFFFFF
 #define        HW_INVALID_HOSTID       0xFFFFFFFF      /* an invalid hostid */
 #define        HW_HOSTID_LEN           11              /* minimum buffer size needed */
                                                /* to hold a decimal or hex */
                                                /* hostid string */
 
-#define        sysinfo(cmd, buf, cnt)          (-1)
+unsigned long get_system_hostid(void);
 
 #endif
diff --git a/lib/libtpool/Makefile.am b/lib/libtpool/Makefile.am
new file mode 100644 (file)
index 0000000..adbaee6
--- /dev/null
@@ -0,0 +1,26 @@
+include $(top_srcdir)/config/Rules.am
+
+AM_CFLAGS += $(DEBUG_STACKFLAGS)
+
+DEFAULT_INCLUDES += \
+       -I$(top_srcdir)/include \
+       -I$(top_srcdir)/lib/libspl/include
+
+noinst_LTLIBRARIES = libtpool.la
+
+USER_C = \
+       thread_pool.c \
+       thread_pool_impl.h
+
+KERNEL_C =
+
+nodist_libtpool_la_SOURCES = \
+       $(USER_C) \
+       $(KERNEL_C)
+
+libtpool_la_LIBADD = \
+       $(top_builddir)/lib/libspl/libspl.la
+
+libtpool_la_LDFLAGS = -pthread
+
+EXTRA_DIST = $(USER_C)
diff --git a/lib/libtpool/thread_pool.c b/lib/libtpool/thread_pool.c
new file mode 100644 (file)
index 0000000..166ce3e
--- /dev/null
@@ -0,0 +1,650 @@
+/*
+ * 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://www.opensolaris.org/os/licensing.
+ * 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 2008 Sun Microsystems, Inc.  All rights reserved.
+ * Use is subject to license terms.
+ */
+
+#include <stdlib.h>
+#include <signal.h>
+#include <errno.h>
+#include <assert.h>
+#include "thread_pool_impl.h"
+
+static pthread_mutex_t thread_pool_lock = PTHREAD_MUTEX_INITIALIZER;
+static tpool_t *thread_pools = NULL;
+
+static void
+delete_pool(tpool_t *tpool)
+{
+       tpool_job_t *job;
+
+       ASSERT(tpool->tp_current == 0 && tpool->tp_active == NULL);
+
+       /*
+        * Unlink the pool from the global list of all pools.
+        */
+       (void) pthread_mutex_lock(&thread_pool_lock);
+       if (thread_pools == tpool)
+               thread_pools = tpool->tp_forw;
+       if (thread_pools == tpool)
+               thread_pools = NULL;
+       else {
+               tpool->tp_back->tp_forw = tpool->tp_forw;
+               tpool->tp_forw->tp_back = tpool->tp_back;
+       }
+       pthread_mutex_unlock(&thread_pool_lock);
+
+       /*
+        * There should be no pending jobs, but just in case...
+        */
+       for (job = tpool->tp_head; job != NULL; job = tpool->tp_head) {
+               tpool->tp_head = job->tpj_next;
+               free(job);
+       }
+       (void) pthread_attr_destroy(&tpool->tp_attr);
+       free(tpool);
+}
+
+/*
+ * Worker thread is terminating.
+ */
+static void
+worker_cleanup(void *arg)
+{
+       tpool_t *tpool = (tpool_t *)arg;
+
+       if (--tpool->tp_current == 0 &&
+           (tpool->tp_flags & (TP_DESTROY | TP_ABANDON))) {
+               if (tpool->tp_flags & TP_ABANDON) {
+                       pthread_mutex_unlock(&tpool->tp_mutex);
+                       delete_pool(tpool);
+                       return;
+               }
+               if (tpool->tp_flags & TP_DESTROY)
+                       (void) pthread_cond_broadcast(&tpool->tp_busycv);
+       }
+       pthread_mutex_unlock(&tpool->tp_mutex);
+}
+
+static void
+notify_waiters(tpool_t *tpool)
+{
+       if (tpool->tp_head == NULL && tpool->tp_active == NULL) {
+               tpool->tp_flags &= ~TP_WAIT;
+               (void) pthread_cond_broadcast(&tpool->tp_waitcv);
+       }
+}
+
+/*
+ * Called by a worker thread on return from a tpool_dispatch()d job.
+ */
+static void
+job_cleanup(void *arg)
+{
+       tpool_t *tpool = (tpool_t *)arg;
+
+       pthread_t my_tid = pthread_self();
+       tpool_active_t *activep;
+       tpool_active_t **activepp;
+
+       pthread_mutex_lock(&tpool->tp_mutex);
+       /* CSTYLED */
+       for (activepp = &tpool->tp_active;; activepp = &activep->tpa_next) {
+               activep = *activepp;
+               if (activep->tpa_tid == my_tid) {
+                       *activepp = activep->tpa_next;
+                       break;
+               }
+       }
+       if (tpool->tp_flags & TP_WAIT)
+               notify_waiters(tpool);
+}
+
+static void *
+tpool_worker(void *arg)
+{
+       tpool_t *tpool = (tpool_t *)arg;
+       int elapsed;
+       tpool_job_t *job;
+       void (*func)(void *);
+       tpool_active_t active;
+
+       pthread_mutex_lock(&tpool->tp_mutex);
+       pthread_cleanup_push(worker_cleanup, tpool);
+
+       /*
+        * This is the worker's main loop.
+        * It will only be left if a timeout or an error has occured.
+        */
+       active.tpa_tid = pthread_self();
+       for (;;) {
+               elapsed = 0;
+               tpool->tp_idle++;
+               if (tpool->tp_flags & TP_WAIT)
+                       notify_waiters(tpool);
+               while ((tpool->tp_head == NULL ||
+                   (tpool->tp_flags & TP_SUSPEND)) &&
+                   !(tpool->tp_flags & (TP_DESTROY | TP_ABANDON))) {
+                       if (tpool->tp_current <= tpool->tp_minimum ||
+                           tpool->tp_linger == 0) {
+                               (void) pthread_cond_wait(&tpool->tp_workcv,
+                                   &tpool->tp_mutex);
+                       } else {
+                               struct timespec ts;
+
+                               clock_gettime(CLOCK_REALTIME, &ts);
+                               ts.tv_sec += tpool->tp_linger;
+
+                               if (pthread_cond_timedwait(&tpool->tp_workcv,
+                                   &tpool->tp_mutex, &ts) != 0) {
+                                       elapsed = 1;
+                                       break;
+                               }
+                       }
+               }
+               tpool->tp_idle--;
+               if (tpool->tp_flags & TP_DESTROY)
+                       break;
+               if (tpool->tp_flags & TP_ABANDON) {
+                       /* can't abandon a suspended pool */
+                       if (tpool->tp_flags & TP_SUSPEND) {
+                               tpool->tp_flags &= ~TP_SUSPEND;
+                               (void) pthread_cond_broadcast(
+                                   &tpool->tp_workcv);
+                       }
+                       if (tpool->tp_head == NULL)
+                               break;
+               }
+               if ((job = tpool->tp_head) != NULL &&
+                   !(tpool->tp_flags & TP_SUSPEND)) {
+                       elapsed = 0;
+                       func = job->tpj_func;
+                       arg = job->tpj_arg;
+                       tpool->tp_head = job->tpj_next;
+                       if (job == tpool->tp_tail)
+                               tpool->tp_tail = NULL;
+                       tpool->tp_njobs--;
+                       active.tpa_next = tpool->tp_active;
+                       tpool->tp_active = &active;
+                       pthread_mutex_unlock(&tpool->tp_mutex);
+                       pthread_cleanup_push(job_cleanup, tpool);
+                       free(job);
+
+                       sigset_t maskset;
+                       (void) pthread_sigmask(SIG_SETMASK, NULL, &maskset);
+
+                       /*
+                        * Call the specified function.
+                        */
+                       func(arg);
+                       /*
+                        * We don't know what this thread has been doing,
+                        * so we reset its signal mask and cancellation
+                        * state back to the values prior to calling func().
+                        */
+                       (void) pthread_sigmask(SIG_SETMASK, &maskset, NULL);
+                       (void) pthread_setcanceltype(PTHREAD_CANCEL_DEFERRED,
+                           NULL);
+                       (void) pthread_setcancelstate(PTHREAD_CANCEL_ENABLE,
+                           NULL);
+                       pthread_cleanup_pop(1);
+               }
+               if (elapsed && tpool->tp_current > tpool->tp_minimum) {
+                       /*
+                        * We timed out and there is no work to be done
+                        * and the number of workers exceeds the minimum.
+                        * Exit now to reduce the size of the pool.
+                        */
+                       break;
+               }
+       }
+       pthread_cleanup_pop(1);
+       return (arg);
+}
+
+/*
+ * Create a worker thread, with default signals blocked.
+ */
+static int
+create_worker(tpool_t *tpool)
+{
+       pthread_t thread;
+       sigset_t oset;
+       int error;
+
+       (void) pthread_sigmask(SIG_SETMASK, NULL, &oset);
+       error = pthread_create(&thread, &tpool->tp_attr, tpool_worker, tpool);
+       (void) pthread_sigmask(SIG_SETMASK, &oset, NULL);
+       return (error);
+}
+
+
+/*
+ * pthread_attr_clone: make a copy of a pthread_attr_t.  When old_attr
+ * is NULL initialize the cloned attr using default values.
+ */
+static int
+pthread_attr_clone(pthread_attr_t *attr, const pthread_attr_t *old_attr)
+{
+       int error;
+
+       error = pthread_attr_init(attr);
+       if (error || (old_attr == NULL))
+               return (error);
+
+       cpu_set_t cpuset;
+       size_t cpusetsize = sizeof (cpuset);
+       error = pthread_attr_getaffinity_np(old_attr, cpusetsize, &cpuset);
+       if (error == 0)
+               error = pthread_attr_setaffinity_np(attr, cpusetsize, &cpuset);
+       if (error)
+               goto error;
+
+       int detachstate;
+       error = pthread_attr_getdetachstate(old_attr, &detachstate);
+       if (error == 0)
+               error = pthread_attr_setdetachstate(attr, detachstate);
+       if (error)
+               goto error;
+
+       size_t guardsize;
+       error = pthread_attr_getguardsize(old_attr, &guardsize);
+       if (error == 0)
+               error = pthread_attr_setguardsize(attr, guardsize);
+       if (error)
+               goto error;
+
+       int inheritsched;
+       error = pthread_attr_getinheritsched(old_attr, &inheritsched);
+       if (error == 0)
+               error = pthread_attr_setinheritsched(attr, inheritsched);
+       if (error)
+               goto error;
+
+       struct sched_param param;
+       error = pthread_attr_getschedparam(old_attr, &param);
+       if (error == 0)
+               error = pthread_attr_setschedparam(attr, &param);
+       if (error)
+               goto error;
+
+       int policy;
+       error = pthread_attr_getschedpolicy(old_attr, &policy);
+       if (error == 0)
+               error = pthread_attr_setschedpolicy(attr, policy);
+       if (error)
+               goto error;
+
+       int scope;
+       error = pthread_attr_getscope(old_attr, &scope);
+       if (error == 0)
+               error = pthread_attr_setscope(attr, scope);
+       if (error)
+               goto error;
+
+       void *stackaddr;
+       size_t stacksize;
+       error = pthread_attr_getstack(old_attr, &stackaddr, &stacksize);
+       if (error == 0)
+               error = pthread_attr_setstack(attr, stackaddr, stacksize);
+       if (error)
+               goto error;
+
+       return (0);
+error:
+       pthread_attr_destroy(attr);
+       return (error);
+}
+
+tpool_t        *
+tpool_create(uint_t min_threads, uint_t max_threads, uint_t linger,
+    pthread_attr_t *attr)
+{
+       tpool_t *tpool;
+       void *stackaddr;
+       size_t stacksize;
+       size_t minstack;
+       int error;
+
+       if (min_threads > max_threads || max_threads < 1) {
+               errno = EINVAL;
+               return (NULL);
+       }
+       if (attr != NULL) {
+               if (pthread_attr_getstack(attr, &stackaddr, &stacksize) != 0) {
+                       errno = EINVAL;
+                       return (NULL);
+               }
+               /*
+                * Allow only one thread in the pool with a specified stack.
+                * Require threads to have at least the minimum stack size.
+                */
+               minstack = PTHREAD_STACK_MIN;
+               if (stackaddr != NULL) {
+                       if (stacksize < minstack || max_threads != 1) {
+                               errno = EINVAL;
+                               return (NULL);
+                       }
+               } else if (stacksize != 0 && stacksize < minstack) {
+                       errno = EINVAL;
+                       return (NULL);
+               }
+       }
+
+       tpool = calloc(1, sizeof (*tpool));
+       if (tpool == NULL) {
+               errno = ENOMEM;
+               return (NULL);
+       }
+       (void) pthread_mutex_init(&tpool->tp_mutex, NULL);
+       (void) pthread_cond_init(&tpool->tp_busycv, NULL);
+       (void) pthread_cond_init(&tpool->tp_workcv, NULL);
+       (void) pthread_cond_init(&tpool->tp_waitcv, NULL);
+       tpool->tp_minimum = min_threads;
+       tpool->tp_maximum = max_threads;
+       tpool->tp_linger = linger;
+
+       /*
+        * We cannot just copy the attribute pointer.
+        * We need to initialize a new pthread_attr_t structure
+        * with the values from the user-supplied pthread_attr_t.
+        * If the attribute pointer is NULL, we need to initialize
+        * the new pthread_attr_t structure with default values.
+        */
+       error = pthread_attr_clone(&tpool->tp_attr, attr);
+       if (error) {
+               free(tpool);
+               errno = error;
+               return (NULL);
+       }
+
+       /* make all pool threads be detached daemon threads */
+       (void) pthread_attr_setdetachstate(&tpool->tp_attr,
+           PTHREAD_CREATE_DETACHED);
+
+       /* insert into the global list of all thread pools */
+       pthread_mutex_lock(&thread_pool_lock);
+       if (thread_pools == NULL) {
+               tpool->tp_forw = tpool;
+               tpool->tp_back = tpool;
+               thread_pools = tpool;
+       } else {
+               thread_pools->tp_back->tp_forw = tpool;
+               tpool->tp_forw = thread_pools;
+               tpool->tp_back = thread_pools->tp_back;
+               thread_pools->tp_back = tpool;
+       }
+       pthread_mutex_unlock(&thread_pool_lock);
+
+       return (tpool);
+}
+
+/*
+ * Dispatch a work request to the thread pool.
+ * If there are idle workers, awaken one.
+ * Else, if the maximum number of workers has
+ * not been reached, spawn a new worker thread.
+ * Else just return with the job added to the queue.
+ */
+int
+tpool_dispatch(tpool_t *tpool, void (*func)(void *), void *arg)
+{
+       tpool_job_t *job;
+
+       ASSERT(!(tpool->tp_flags & (TP_DESTROY | TP_ABANDON)));
+
+       if ((job = calloc(1, sizeof (*job))) == NULL)
+               return (-1);
+       job->tpj_next = NULL;
+       job->tpj_func = func;
+       job->tpj_arg = arg;
+
+       pthread_mutex_lock(&tpool->tp_mutex);
+
+       if (tpool->tp_head == NULL)
+               tpool->tp_head = job;
+       else
+               tpool->tp_tail->tpj_next = job;
+       tpool->tp_tail = job;
+       tpool->tp_njobs++;
+
+       if (!(tpool->tp_flags & TP_SUSPEND)) {
+               if (tpool->tp_idle > 0)
+                       (void) pthread_cond_signal(&tpool->tp_workcv);
+               else if (tpool->tp_current < tpool->tp_maximum &&
+                   create_worker(tpool) == 0)
+                       tpool->tp_current++;
+       }
+
+       pthread_mutex_unlock(&tpool->tp_mutex);
+       return (0);
+}
+
+static void
+tpool_cleanup(void *arg)
+{
+       tpool_t *tpool = (tpool_t *)arg;
+
+       pthread_mutex_unlock(&tpool->tp_mutex);
+}
+
+/*
+ * Assumes: by the time tpool_destroy() is called no one will use this
+ * thread pool in any way and no one will try to dispatch entries to it.
+ * Calling tpool_destroy() from a job in the pool will cause deadlock.
+ */
+void
+tpool_destroy(tpool_t *tpool)
+{
+       tpool_active_t *activep;
+
+       ASSERT(!tpool_member(tpool));
+       ASSERT(!(tpool->tp_flags & (TP_DESTROY | TP_ABANDON)));
+
+       pthread_mutex_lock(&tpool->tp_mutex);
+       pthread_cleanup_push(tpool_cleanup, tpool);
+
+       /* mark the pool as being destroyed; wakeup idle workers */
+       tpool->tp_flags |= TP_DESTROY;
+       tpool->tp_flags &= ~TP_SUSPEND;
+       (void) pthread_cond_broadcast(&tpool->tp_workcv);
+
+       /* cancel all active workers */
+       for (activep = tpool->tp_active; activep; activep = activep->tpa_next)
+               (void) pthread_cancel(activep->tpa_tid);
+
+       /* wait for all active workers to finish */
+       while (tpool->tp_active != NULL) {
+               tpool->tp_flags |= TP_WAIT;
+               (void) pthread_cond_wait(&tpool->tp_waitcv, &tpool->tp_mutex);
+       }
+
+       /* the last worker to terminate will wake us up */
+       while (tpool->tp_current != 0)
+               (void) pthread_cond_wait(&tpool->tp_busycv, &tpool->tp_mutex);
+
+       pthread_cleanup_pop(1); /* pthread_mutex_unlock(&tpool->tp_mutex); */
+       delete_pool(tpool);
+}
+
+/*
+ * Like tpool_destroy(), but don't cancel workers or wait for them to finish.
+ * The last worker to terminate will delete the pool.
+ */
+void
+tpool_abandon(tpool_t *tpool)
+{
+       ASSERT(!(tpool->tp_flags & (TP_DESTROY | TP_ABANDON)));
+
+       pthread_mutex_lock(&tpool->tp_mutex);
+       if (tpool->tp_current == 0) {
+               /* no workers, just delete the pool */
+               pthread_mutex_unlock(&tpool->tp_mutex);
+               delete_pool(tpool);
+       } else {
+               /* wake up all workers, last one will delete the pool */
+               tpool->tp_flags |= TP_ABANDON;
+               tpool->tp_flags &= ~TP_SUSPEND;
+               (void) pthread_cond_broadcast(&tpool->tp_workcv);
+               pthread_mutex_unlock(&tpool->tp_mutex);
+       }
+}
+
+/*
+ * Wait for all jobs to complete.
+ * Calling tpool_wait() from a job in the pool will cause deadlock.
+ */
+void
+tpool_wait(tpool_t *tpool)
+{
+       ASSERT(!tpool_member(tpool));
+       ASSERT(!(tpool->tp_flags & (TP_DESTROY | TP_ABANDON)));
+
+       pthread_mutex_lock(&tpool->tp_mutex);
+       pthread_cleanup_push(tpool_cleanup, tpool);
+       while (tpool->tp_head != NULL || tpool->tp_active != NULL) {
+               tpool->tp_flags |= TP_WAIT;
+               (void) pthread_cond_wait(&tpool->tp_waitcv, &tpool->tp_mutex);
+               ASSERT(!(tpool->tp_flags & (TP_DESTROY | TP_ABANDON)));
+       }
+       pthread_cleanup_pop(1); /* pthread_mutex_unlock(&tpool->tp_mutex); */
+}
+
+void
+tpool_suspend(tpool_t *tpool)
+{
+       ASSERT(!(tpool->tp_flags & (TP_DESTROY | TP_ABANDON)));
+
+       pthread_mutex_lock(&tpool->tp_mutex);
+       tpool->tp_flags |= TP_SUSPEND;
+       pthread_mutex_unlock(&tpool->tp_mutex);
+}
+
+int
+tpool_suspended(tpool_t *tpool)
+{
+       int suspended;
+
+       ASSERT(!(tpool->tp_flags & (TP_DESTROY | TP_ABANDON)));
+
+       pthread_mutex_lock(&tpool->tp_mutex);
+       suspended = (tpool->tp_flags & TP_SUSPEND) != 0;
+       pthread_mutex_unlock(&tpool->tp_mutex);
+
+       return (suspended);
+}
+
+void
+tpool_resume(tpool_t *tpool)
+{
+       int excess;
+
+       ASSERT(!(tpool->tp_flags & (TP_DESTROY | TP_ABANDON)));
+
+       pthread_mutex_lock(&tpool->tp_mutex);
+       if (!(tpool->tp_flags & TP_SUSPEND)) {
+               pthread_mutex_unlock(&tpool->tp_mutex);
+               return;
+       }
+       tpool->tp_flags &= ~TP_SUSPEND;
+       (void) pthread_cond_broadcast(&tpool->tp_workcv);
+       excess = tpool->tp_njobs - tpool->tp_idle;
+       while (excess-- > 0 && tpool->tp_current < tpool->tp_maximum) {
+               if (create_worker(tpool) != 0)
+                       break;          /* pthread_create() failed */
+               tpool->tp_current++;
+       }
+       pthread_mutex_unlock(&tpool->tp_mutex);
+}
+
+int
+tpool_member(tpool_t *tpool)
+{
+       pthread_t my_tid = pthread_self();
+       tpool_active_t *activep;
+
+       ASSERT(!(tpool->tp_flags & (TP_DESTROY | TP_ABANDON)));
+
+       pthread_mutex_lock(&tpool->tp_mutex);
+       for (activep = tpool->tp_active; activep; activep = activep->tpa_next) {
+               if (activep->tpa_tid == my_tid) {
+                       pthread_mutex_unlock(&tpool->tp_mutex);
+                       return (1);
+               }
+       }
+       pthread_mutex_unlock(&tpool->tp_mutex);
+       return (0);
+}
+
+void
+postfork1_child_tpool(void)
+{
+       pthread_t my_tid = pthread_self();
+       tpool_t *tpool;
+       tpool_job_t *job;
+
+       /*
+        * All of the thread pool workers are gone, except possibly
+        * for the current thread, if it is a thread pool worker thread.
+        * Retain the thread pools, but make them all empty.  Whatever
+        * jobs were queued or running belong to the parent process.
+        */
+top:
+       if ((tpool = thread_pools) == NULL)
+               return;
+
+       do {
+               tpool_active_t *activep;
+
+               (void) pthread_mutex_init(&tpool->tp_mutex, NULL);
+               (void) pthread_cond_init(&tpool->tp_busycv, NULL);
+               (void) pthread_cond_init(&tpool->tp_workcv, NULL);
+               (void) pthread_cond_init(&tpool->tp_waitcv, NULL);
+               for (job = tpool->tp_head; job; job = tpool->tp_head) {
+                       tpool->tp_head = job->tpj_next;
+                       free(job);
+               }
+               tpool->tp_tail = NULL;
+               tpool->tp_njobs = 0;
+               for (activep = tpool->tp_active; activep;
+                   activep = activep->tpa_next) {
+                       if (activep->tpa_tid == my_tid) {
+                               activep->tpa_next = NULL;
+                               break;
+                       }
+               }
+               tpool->tp_idle = 0;
+               tpool->tp_current = 0;
+               if ((tpool->tp_active = activep) != NULL)
+                       tpool->tp_current = 1;
+               tpool->tp_flags &= ~TP_WAIT;
+               if (tpool->tp_flags & (TP_DESTROY | TP_ABANDON)) {
+                       tpool->tp_flags &= ~TP_DESTROY;
+                       tpool->tp_flags |= TP_ABANDON;
+                       if (tpool->tp_current == 0) {
+                               delete_pool(tpool);
+                               goto top;       /* start over */
+                       }
+               }
+       } while ((tpool = tpool->tp_forw) != thread_pools);
+}
diff --git a/lib/libtpool/thread_pool_impl.h b/lib/libtpool/thread_pool_impl.h
new file mode 100644 (file)
index 0000000..5349c2a
--- /dev/null
@@ -0,0 +1,93 @@
+/*
+ * 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://www.opensolaris.org/os/licensing.
+ * 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 2008 Sun Microsystems, Inc.  All rights reserved.
+ * Use is subject to license terms.
+ */
+
+#ifndef _THREAD_POOL_IMPL_H
+#define        _THREAD_POOL_IMPL_H
+
+#include <thread_pool.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/*
+ * Thread pool implementation definitions.
+ * See <thread_pool.h> for interface declarations.
+ */
+
+/*
+ * FIFO queued job
+ */
+typedef struct tpool_job tpool_job_t;
+struct tpool_job {
+       tpool_job_t     *tpj_next;              /* list of jobs */
+       void            (*tpj_func)(void *);    /* function to call */
+       void            *tpj_arg;               /* its argument */
+};
+
+/*
+ * List of active threads, linked through their stacks.
+ */
+typedef struct tpool_active tpool_active_t;
+struct tpool_active {
+       tpool_active_t  *tpa_next;      /* list of active threads */
+       pthread_t       tpa_tid;        /* active thread id */
+};
+
+/*
+ * The thread pool.
+ */
+struct tpool {
+       tpool_t         *tp_forw;       /* circular list of all thread pools */
+       tpool_t         *tp_back;
+       pthread_mutex_t tp_mutex;       /* protects the pool data */
+       pthread_cond_t  tp_busycv;      /* synchronization in tpool_dispatch */
+       pthread_cond_t  tp_workcv;      /* synchronization with workers */
+       pthread_cond_t  tp_waitcv;      /* synchronization in tpool_wait() */
+       tpool_active_t  *tp_active;     /* threads performing work */
+       tpool_job_t     *tp_head;       /* FIFO job queue */
+       tpool_job_t     *tp_tail;
+       pthread_attr_t  tp_attr;        /* attributes of the workers */
+       int             tp_flags;       /* see below */
+       uint_t          tp_linger;      /* seconds before idle workers exit */
+       int             tp_njobs;       /* number of jobs in job queue */
+       int             tp_minimum;     /* minimum number of worker threads */
+       int             tp_maximum;     /* maximum number of worker threads */
+       int             tp_current;     /* current number of worker threads */
+       int             tp_idle;        /* number of idle workers */
+};
+
+/* tp_flags */
+#define        TP_WAIT         0x01            /* waiting in tpool_wait() */
+#define        TP_SUSPEND      0x02            /* pool is being suspended */
+#define        TP_DESTROY      0x04            /* pool is being destroyed */
+#define        TP_ABANDON      0x08            /* pool is abandoned (auto-destroy) */
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* _THREAD_POOL_IMPL_H */
index 4d54485b735b6a90de86754243782de6c8eb8d31..c2659b6193d955493c66f11b5f41bfb26f888b70 100644 (file)
@@ -28,8 +28,7 @@ nodist_libuutil_la_SOURCES = \
 
 libuutil_la_LIBADD = \
        $(top_builddir)/lib/libavl/libavl.la \
-       $(top_builddir)/lib/libspl/libspl.la \
-       $(top_builddir)/lib/libefi/libefi.la
+       $(top_builddir)/lib/libspl/libspl.la
 
 libuutil_la_LDFLAGS = -pthread -version-info 1:1:0
 
index f1260ea7195dd60903ababd537a2c2ec0f0a5c55..7ab8658e49f930c1c09936e85fe027625638dbf7 100644 (file)
@@ -1,10 +1,16 @@
 include $(top_srcdir)/config/Rules.am
 
+VPATH = \
+       $(top_srcdir)/module/icp \
+       $(top_srcdir)/module/zcommon \
+       $(top_srcdir)/lib/libzfs
+
 libzfs_pcdir = $(datarootdir)/pkgconfig
 libzfs_pc_DATA = libzfs.pc libzfs_core.pc
 
 DEFAULT_INCLUDES += \
        -I$(top_srcdir)/include \
+       -I$(top_srcdir)/module/icp/include \
        -I$(top_srcdir)/lib/libspl/include
 
 lib_LTLIBRARIES = libzfs.la
@@ -23,17 +29,35 @@ USER_C = \
        libzfs_status.c \
        libzfs_util.c
 
-KERNEL_C =
+KERNEL_C = \
+       algs/sha2/sha2.c \
+       zfeature_common.c \
+       zfs_comutil.c \
+       zfs_deleg.c \
+       zfs_fletcher.c \
+       zfs_fletcher_aarch64_neon.c \
+       zfs_fletcher_avx512.c \
+       zfs_fletcher_intel.c \
+       zfs_fletcher_sse.c \
+       zfs_fletcher_superscalar.c \
+       zfs_fletcher_superscalar4.c \
+       zfs_namecheck.c \
+       zfs_prop.c \
+       zfs_uio.c \
+       zpool_prop.c \
+       zprop_common.c
 
 nodist_libzfs_la_SOURCES = \
        $(USER_C) \
        $(KERNEL_C)
 
 libzfs_la_LIBADD = \
-       $(top_builddir)/lib/libzfs_core/libzfs_core.la \
-       $(top_builddir)/lib/libshare/libshare.la \
+        $(top_builddir)/lib/libefi/libefi.la \
        $(top_builddir)/lib/libnvpair/libnvpair.la \
-       $(top_builddir)/lib/libzpool/libzpool.la
+       $(top_builddir)/lib/libshare/libshare.la \
+       $(top_builddir)/lib/libtpool/libtpool.la \
+       $(top_builddir)/lib/libuutil/libuutil.la \
+       $(top_builddir)/lib/libzfs_core/libzfs_core.la
 
 libzfs_la_LIBADD += -lm $(LIBBLKID) $(LIBUDEV)
 libzfs_la_LDFLAGS = -version-info 2:0:0
index f371d925bc59c4223089260bcb482fdc0700035b..8335683560c261d8f5240275dbf0386daff5b5ab 100644 (file)
@@ -60,6 +60,7 @@
 #include <sys/vtoc.h>
 #include <sys/dktp/fdisk.h>
 #include <sys/efi_partition.h>
+#include <thread_pool.h>
 #include <sys/vdev_impl.h>
 #include <blkid/blkid.h>
 #include "libzfs.h"
@@ -1388,7 +1389,7 @@ typedef struct rdsk_node {
        nvlist_t *rn_config;            /* Label config */
        avl_tree_t *rn_avl;
        avl_node_t rn_node;
-       kmutex_t *rn_lock;
+       pthread_mutex_t *rn_lock;
        boolean_t rn_labelpaths;
 } rdsk_node_t;
 
@@ -1603,14 +1604,14 @@ zpool_open_func(void *arg)
                        slice->rn_hdl = hdl;
                        slice->rn_order = IMPORT_ORDER_PREFERRED_1;
                        slice->rn_labelpaths = B_FALSE;
-                       mutex_enter(rn->rn_lock);
+                       pthread_mutex_lock(rn->rn_lock);
                        if (avl_find(rn->rn_avl, slice, &where)) {
-                       mutex_exit(rn->rn_lock);
+                       pthread_mutex_unlock(rn->rn_lock);
                                free(slice->rn_name);
                                free(slice);
                        } else {
                                avl_insert(rn->rn_avl, slice, where);
-                               mutex_exit(rn->rn_lock);
+                               pthread_mutex_unlock(rn->rn_lock);
                                zpool_open_func(slice);
                        }
                }
@@ -1629,14 +1630,14 @@ zpool_open_func(void *arg)
                        slice->rn_hdl = hdl;
                        slice->rn_order = IMPORT_ORDER_PREFERRED_2;
                        slice->rn_labelpaths = B_FALSE;
-                       mutex_enter(rn->rn_lock);
+                       pthread_mutex_lock(rn->rn_lock);
                        if (avl_find(rn->rn_avl, slice, &where)) {
-                               mutex_exit(rn->rn_lock);
+                               pthread_mutex_unlock(rn->rn_lock);
                                free(slice->rn_name);
                                free(slice);
                        } else {
                                avl_insert(rn->rn_avl, slice, where);
-                               mutex_exit(rn->rn_lock);
+                               pthread_mutex_unlock(rn->rn_lock);
                                zpool_open_func(slice);
                        }
                }
@@ -1679,7 +1680,7 @@ zpool_clear_label(int fd)
  * Scan a list of directories for zfs devices.
  */
 static int
-zpool_find_import_scan(libzfs_handle_t *hdl, kmutex_t *lock,
+zpool_find_import_scan(libzfs_handle_t *hdl, pthread_mutex_t *lock,
     avl_tree_t **slice_cache, char **dir, int dirs)
 {
        avl_tree_t *cache;
@@ -1735,9 +1736,9 @@ zpool_find_import_scan(libzfs_handle_t *hdl, kmutex_t *lock,
                        slice->rn_hdl = hdl;
                        slice->rn_order = i + IMPORT_ORDER_SCAN_OFFSET;
                        slice->rn_labelpaths = B_FALSE;
-                       mutex_enter(lock);
+                       pthread_mutex_lock(lock);
                        avl_add(cache, slice);
-                       mutex_exit(lock);
+                       pthread_mutex_unlock(lock);
                }
 
                (void) closedir(dirp);
@@ -1761,7 +1762,7 @@ error:
  * Use libblkid to quickly enumerate all known zfs devices.
  */
 static int
-zpool_find_import_blkid(libzfs_handle_t *hdl, kmutex_t *lock,
+zpool_find_import_blkid(libzfs_handle_t *hdl, pthread_mutex_t *lock,
     avl_tree_t **slice_cache)
 {
        rdsk_node_t *slice;
@@ -1815,14 +1816,14 @@ zpool_find_import_blkid(libzfs_handle_t *hdl, kmutex_t *lock,
                else
                        slice->rn_order = IMPORT_ORDER_DEFAULT;
 
-               mutex_enter(lock);
+               pthread_mutex_lock(lock);
                if (avl_find(*slice_cache, slice, &where)) {
                        free(slice->rn_name);
                        free(slice);
                } else {
                        avl_insert(*slice_cache, slice, where);
                }
-               mutex_exit(lock);
+               pthread_mutex_unlock(lock);
        }
 
        blkid_dev_iterate_end(iter);
@@ -1860,14 +1861,14 @@ zpool_find_import_impl(libzfs_handle_t *hdl, importargs_t *iarg)
        vdev_entry_t *ve, *venext;
        config_entry_t *ce, *cenext;
        name_entry_t *ne, *nenext;
-       kmutex_t lock;
+       pthread_mutex_t lock;
        avl_tree_t *cache;
        rdsk_node_t *slice;
        void *cookie;
-       taskq_t *t;
+       tpool_t *t;
 
        verify(iarg->poolname == NULL || iarg->guid == 0);
-       mutex_init(&lock, NULL, MUTEX_DEFAULT, NULL);
+       pthread_mutex_init(&lock, NULL);
 
        /*
         * Locate pool member vdevs using libblkid or by directory scanning.
@@ -1896,15 +1897,13 @@ zpool_find_import_impl(libzfs_handle_t *hdl, importargs_t *iarg)
         * validating labels, a large number of threads can be used due to
         * minimal contention.
         */
-       t = taskq_create("z_import", 2 * boot_ncpus, defclsyspri,
-           2 * boot_ncpus, INT_MAX, TASKQ_PREPOPULATE);
-
+       t = tpool_create(1, 2 * sysconf(_SC_NPROCESSORS_ONLN), 0, NULL);
        for (slice = avl_first(cache); slice;
            (slice = avl_walk(cache, slice, AVL_AFTER)))
-               (void) taskq_dispatch(t, zpool_open_func, slice, TQ_SLEEP);
+               (void) tpool_dispatch(t, zpool_open_func, slice);
 
-       taskq_wait(t);
-       taskq_destroy(t);
+       tpool_wait(t);
+       tpool_destroy(t);
 
        /*
         * Process the cache filtering out any entries which are not
@@ -1974,7 +1973,7 @@ zpool_find_import_impl(libzfs_handle_t *hdl, importargs_t *iarg)
        }
        avl_destroy(cache);
        free(cache);
-       mutex_destroy(&lock);
+       pthread_mutex_destroy(&lock);
 
        ret = get_configs(hdl, &pools, iarg->can_be_active);
 
index 73af75f9d3d8c2b27dd4b71c3bcfe87bee3a2cfb..d3363809d2b179ef54fc07557563972e821da07c 100644 (file)
@@ -40,6 +40,7 @@
 #include <zone.h>
 #include <sys/stat.h>
 #include <sys/efi_partition.h>
+#include <sys/systeminfo.h>
 #include <sys/vtoc.h>
 #include <sys/zfs_ioctl.h>
 #include <dlfcn.h>
index 05a9afce8a8ab6b7f86121b556533759422d5ac2..ccc472153cb110bc627efc9597dd398f6132e98e 100644 (file)
@@ -44,6 +44,7 @@
 #include <libzfs.h>
 #include <string.h>
 #include <unistd.h>
+#include <sys/systeminfo.h>
 #include "libzfs_impl.h"
 #include "zfeature_common.h"
 
index a8c72c98de3f4f9c2e6c100e0bac148d0e81bdbf..aed8868ae06e96f2cd68a4a5aa94873a731e2f37 100644 (file)
@@ -19,13 +19,14 @@ USER_C = \
        util.c
 
 KERNEL_C = \
+       zfeature_common.c \
        zfs_comutil.c \
        zfs_deleg.c \
        zfs_fletcher.c \
+       zfs_fletcher_aarch64_neon.c \
+       zfs_fletcher_avx512.c \
        zfs_fletcher_intel.c \
        zfs_fletcher_sse.c \
-       zfs_fletcher_avx512.c \
-       zfs_fletcher_aarch64_neon.c \
        zfs_fletcher_superscalar.c \
        zfs_fletcher_superscalar4.c \
        zfs_namecheck.c \
@@ -115,13 +116,13 @@ KERNEL_C = \
        zap_leaf.c \
        zap_micro.c \
        zfeature.c \
-       zfeature_common.c \
        zfs_byteswap.c \
        zfs_debug.c \
        zfs_fm.c \
        zfs_fuid.c \
        zfs_sa.c \
        zfs_znode.c \
+       zfs_ratelimit.c \
        zfs_rlock.c \
        zil.c \
        zio.c \
@@ -136,12 +137,13 @@ nodist_libzpool_la_SOURCES = \
        $(KERNEL_C)
 
 libzpool_la_LIBADD = \
-       $(top_builddir)/lib/libunicode/libunicode.la \
-       $(top_builddir)/lib/libuutil/libuutil.la \
+       $(top_builddir)/lib/libavl/libavl.la \
+       $(top_builddir)/lib/libicp/libicp.la \
        $(top_builddir)/lib/libnvpair/libnvpair.la \
-       $(top_builddir)/lib/libicp/libicp.la
+       $(top_builddir)/lib/libspl/libspl.la \
+       $(top_builddir)/lib/libunicode/libunicode.la
 
 libzpool_la_LIBADD += $(ZLIB) -ldl
-libzpool_la_LDFLAGS = -version-info 2:0:0
+libzpool_la_LDFLAGS = -pthread -version-info 2:0:0
 
 EXTRA_DIST = $(USER_C)
index e67d13c9265270dffc6fe41507b3c0d42df7ea37..3fc7337e8eca8b52937ee482bf43b85a5e3017b6 100644 (file)
@@ -71,7 +71,7 @@ pthread_mutex_t kthread_lock = PTHREAD_MUTEX_INITIALIZER;
 pthread_key_t kthread_key;
 int kthread_nr = 0;
 
-void
+static void
 thread_init(void)
 {
        kthread_t *kt;
@@ -90,7 +90,7 @@ thread_init(void)
        kthread_nr = 1;
 }
 
-void
+static void
 thread_fini(void)
 {
        kthread_t *kt = curthread;
@@ -1051,149 +1051,30 @@ delay(clock_t ticks)
 
 /*
  * Find highest one bit set.
- *     Returns bit number + 1 of highest bit that is set, otherwise returns 0.
- * High order bit is 31 (or 63 in _LP64 kernel).
+ * 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)
 {
-       register int h = 1;
-
        if (i == 0)
-               return (0);
-       if (i & 0xffffffff00000000ULL) {
-               h += 32; i >>= 32;
-       }
-       if (i & 0xffff0000) {
-               h += 16; i >>= 16;
-       }
-       if (i & 0xff00) {
-               h += 8; i >>= 8;
-       }
-       if (i & 0xf0) {
-               h += 4; i >>= 4;
-       }
-       if (i & 0xc) {
-               h += 2; i >>= 2;
-       }
-       if (i & 0x2) {
-               h += 1;
-       }
-       return (h);
+       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.
- * This is basically a reimplementation of ffsll(), which is GNU specific.
+ * The __builtin_ffsll() function is supported by both GCC and Clang.
  */
 int
 lowbit64(uint64_t i)
 {
-       register int h = 64;
        if (i == 0)
                return (0);
 
-       if (i & 0x00000000ffffffffULL)
-               h -= 32;
-       else
-               i >>= 32;
-
-       if (i & 0x0000ffff)
-               h -= 16;
-       else
-               i >>= 16;
-
-       if (i & 0x00ff)
-               h -= 8;
-       else
-               i >>= 8;
-
-       if (i & 0x0f)
-               h -= 4;
-       else
-               i >>= 4;
-
-       if (i & 0x3)
-               h -= 2;
-       else
-               i >>= 2;
-
-       if (i & 0x1)
-               h -= 1;
-
-       return (h);
-}
-
-/*
- * Find highest one bit set.
- * Returns bit number + 1 of highest bit that is set, otherwise returns 0.
- * High order bit is 31 (or 63 in _LP64 kernel).
- */
-int
-highbit(ulong_t i)
-{
-register int h = 1;
-
-       if (i == 0)
-               return (0);
-#ifdef _LP64
-       if (i & 0xffffffff00000000ul) {
-               h += 32; i >>= 32;
-       }
-#endif
-       if (i & 0xffff0000) {
-               h += 16; i >>= 16;
-       }
-       if (i & 0xff00) {
-               h += 8; i >>= 8;
-       }
-       if (i & 0xf0) {
-               h += 4; i >>= 4;
-       }
-       if (i & 0xc) {
-               h += 2; i >>= 2;
-       }
-       if (i & 0x2) {
-               h += 1;
-       }
-       return (h);
-}
-
-/*
- * Find lowest one bit set.
- *     Returns bit number + 1 of lowest bit that is set, otherwise returns 0.
- * Low order bit is 0.
- */
-int
-lowbit(ulong_t i)
-{
-       register int h = 1;
-
-       if (i == 0)
-               return (0);
-
-#ifdef _LP64
-       if (!(i & 0xffffffff)) {
-               h += 32; i >>= 32;
-       }
-#endif
-       if (!(i & 0xffff)) {
-               h += 16; i >>= 16;
-       }
-       if (!(i & 0xff)) {
-               h += 8; i >>= 8;
-       }
-       if (!(i & 0xf)) {
-               h += 4; i >>= 4;
-       }
-       if (!(i & 0x3)) {
-               h += 2; i >>= 2;
-       }
-       if (!(i & 0x1)) {
-               h += 1;
-       }
-       return (h);
+       return (__builtin_ffsll(i));
 }
 
 static int random_fd = -1, urandom_fd = -1;
@@ -1288,64 +1169,6 @@ umem_out_of_memory(void)
        return (0);
 }
 
-#define        HOSTID_MASK 0xffffffff
-
-static unsigned long
-get_spl_hostid(void)
-{
-       FILE *f;
-       unsigned long hostid;
-       char *env;
-
-       /*
-        * Allow the hostid to be subverted for testing.
-        */
-       env = getenv("ZFS_HOSTID");
-       if (env) {
-               hostid = strtoull(env, NULL, 0);
-               return (hostid & HOSTID_MASK);
-       }
-
-       f = fopen("/sys/module/spl/parameters/spl_hostid", "r");
-       if (!f)
-               return (0);
-
-       if (fscanf(f, "%lu", &hostid) != 1)
-               hostid = 0;
-
-       fclose(f);
-
-       return (hostid & HOSTID_MASK);
-}
-
-unsigned long
-get_system_hostid(void)
-{
-       unsigned long system_hostid = get_spl_hostid();
-       /*
-        * We do not use the library call gethostid() because
-        * it generates a hostid value that the kernel is
-        * unaware of, if the spl_hostid module parameter has not
-        * been set and there is no system hostid file (e.g.
-        * /etc/hostid).  The kernel and userspace must agree.
-        * See comments above hostid_read() in the SPL.
-        */
-       if (system_hostid == 0) {
-               int fd, rc;
-               unsigned long hostid;
-               int hostid_size = 4;  /* 4 bytes regardless of arch */
-
-               fd = open("/etc/hostid", O_RDONLY);
-               if (fd >= 0) {
-                       rc = read(fd, &hostid, hostid_size);
-                       if (rc > 0)
-                               system_hostid = (hostid & HOSTID_MASK);
-                       close(fd);
-               }
-       }
-       return (system_hostid);
-}
-
 void
 kernel_init(int mode)
 {
index dbe008190688f4966b70945a593906f9e2d4321b..c585993f13214d705182c1c3ee731cfbd2a3bc64 100644 (file)
@@ -52,7 +52,7 @@
 static void Encode(uint8_t *, uint32_t *, size_t);
 static void Encode64(uint8_t *, uint64_t *, size_t);
 
-#if    defined(__amd64)
+#if    defined(__amd64) && defined(_KERNEL)
 #define        SHA512Transform(ctx, in) SHA512TransformBlocks((ctx), (in), 1)
 #define        SHA256Transform(ctx, in) SHA256TransformBlocks((ctx), (in), 1)
 
@@ -62,7 +62,7 @@ void SHA256TransformBlocks(SHA2_CTX *ctx, const void *in, size_t num);
 #else
 static void SHA256Transform(SHA2_CTX *, const uint8_t *);
 static void SHA512Transform(SHA2_CTX *, const uint8_t *);
-#endif /* __amd64 */
+#endif /* __amd64 && _KERNEL */
 
 static uint8_t PADDING[128] = { 0x80, /* all zeros */ };
 
@@ -142,7 +142,7 @@ static uint8_t PADDING[128] = { 0x80, /* all zeros */ };
 #endif /* _BIG_ENDIAN */
 
 
-#if    !defined(__amd64)
+#if    !defined(__amd64) || !defined(_KERNEL)
 /* SHA256 Transform */
 
 static void
@@ -600,7 +600,7 @@ SHA512Transform(SHA2_CTX *ctx, const uint8_t *blk)
        ctx->state.s64[7] += h;
 
 }
-#endif /* !__amd64 */
+#endif /* !__amd64 || !_KERNEL */
 
 
 /*
@@ -783,10 +783,6 @@ SHA2Update(SHA2_CTX *ctx, const void *inptr, size_t input_len)
        uint32_t        i, buf_index, buf_len, buf_limit;
        const uint8_t   *input = inptr;
        uint32_t        algotype = ctx->algotype;
-#if defined(__amd64)
-       uint32_t        block_count;
-#endif /* !__amd64 */
-
 
        /* check for noop */
        if (input_len == 0)
@@ -842,7 +838,7 @@ SHA2Update(SHA2_CTX *ctx, const void *inptr, size_t input_len)
                        i = buf_len;
                }
 
-#if !defined(__amd64)
+#if !defined(__amd64) || !defined(_KERNEL)
                if (algotype <= SHA256_HMAC_GEN_MECH_INFO_TYPE) {
                        for (; i + buf_limit - 1 < input_len; i += buf_limit) {
                                SHA256Transform(ctx, &input[i]);
@@ -854,6 +850,7 @@ SHA2Update(SHA2_CTX *ctx, const void *inptr, size_t input_len)
                }
 
 #else
+               uint32_t block_count;
                if (algotype <= SHA256_HMAC_GEN_MECH_INFO_TYPE) {
                        block_count = (input_len - i) >> 6;
                        if (block_count > 0) {
@@ -869,7 +866,7 @@ SHA2Update(SHA2_CTX *ctx, const void *inptr, size_t input_len)
                                i += block_count << 7;
                        }
                }
-#endif /* !__amd64 */
+#endif /* !__amd64 || !_KERNEL */
 
                /*
                 * general optimization:
@@ -951,8 +948,6 @@ SHA2Final(void *digest, SHA2_CTX *ctx)
        bzero(ctx, sizeof (*ctx));
 }
 
-
-
 #ifdef _KERNEL
 EXPORT_SYMBOL(SHA2Init);
 EXPORT_SYMBOL(SHA2Update);
index 1ff782afc0ce063e90e326c1496a5da120feab61..497e8439666570755464e9627be45923753eb56e 100644 (file)
@@ -312,7 +312,7 @@ mod_hash_create_ptrhash(char *name, size_t nchains,
         * The high bits, which are also unused, will get taken out when
         * mod_hash takes hashkey % nchains.
         */
-       rshift = highbit(key_elem_size);
+       rshift = highbit64(key_elem_size);
 
        return mod_hash_create_extended(name, nchains, mod_hash_null_keydtor,
            val_dtor, mod_hash_byptr, (void *)rshift, mod_hash_ptrkey_cmp,
index 74bb4378eabbd9accb7f1ae890e5b2b5ed0bd3f3..86eb8ad3922eb731dc1d65a09362103f515e2145 100644 (file)
@@ -7,16 +7,17 @@ EXTRA_CFLAGS = $(ZFS_MODULE_CFLAGS) @KERNELCPPFLAGS@
 
 obj-$(CONFIG_ZFS) := $(MODULE).o
 
-$(MODULE)-objs += zfs_deleg.o
-$(MODULE)-objs += zfs_prop.o
-$(MODULE)-objs += zprop_common.o
-$(MODULE)-objs += zfs_namecheck.o
+$(MODULE)-objs += zfeature_common.o
 $(MODULE)-objs += zfs_comutil.o
+$(MODULE)-objs += zfs_deleg.o
 $(MODULE)-objs += zfs_fletcher.o
-$(MODULE)-objs += zfs_uio.o
-$(MODULE)-objs += zpool_prop.o
 $(MODULE)-objs += zfs_fletcher_superscalar.o
 $(MODULE)-objs += zfs_fletcher_superscalar4.o
+$(MODULE)-objs += zfs_namecheck.o
+$(MODULE)-objs += zfs_prop.o
+$(MODULE)-objs += zfs_uio.o
+$(MODULE)-objs += zpool_prop.o
+$(MODULE)-objs += zprop_common.o
 
 $(MODULE)-$(CONFIG_X86) += zfs_fletcher_intel.o
 $(MODULE)-$(CONFIG_X86) += zfs_fletcher_sse.o
diff --git a/module/zcommon/zfeature_common.c b/module/zcommon/zfeature_common.c
new file mode 100644 (file)
index 0000000..321ee04
--- /dev/null
@@ -0,0 +1,330 @@
+/*
+ * 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://www.opensolaris.org/os/licensing.
+ * 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) 2011, 2015 by Delphix. All rights reserved.
+ * Copyright (c) 2013 by Saso Kiselkov. All rights reserved.
+ * Copyright (c) 2013, Joyent, Inc. All rights reserved.
+ * Copyright (c) 2014, Nexenta Systems, Inc. All rights reserved.
+ */
+
+#ifdef _KERNEL
+#include <sys/systm.h>
+#else
+#include <errno.h>
+#include <string.h>
+#endif
+#include <sys/debug.h>
+#include <sys/fs/zfs.h>
+#include <sys/inttypes.h>
+#include <sys/types.h>
+#include "zfeature_common.h"
+
+/*
+ * Set to disable all feature checks while opening pools, allowing pools with
+ * unsupported features to be opened. Set for testing only.
+ */
+boolean_t zfeature_checks_disable = B_FALSE;
+
+zfeature_info_t spa_feature_table[SPA_FEATURES];
+
+/*
+ * Valid characters for feature guids. This list is mainly for aesthetic
+ * purposes and could be expanded in the future. There are different allowed
+ * characters in the guids reverse dns portion (before the colon) and its
+ * short name (after the colon).
+ */
+static int
+valid_char(char c, boolean_t after_colon)
+{
+       return ((c >= 'a' && c <= 'z') ||
+           (c >= '0' && c <= '9') ||
+           (after_colon && c == '_') ||
+           (!after_colon && (c == '.' || c == '-')));
+}
+
+/*
+ * Every feature guid must contain exactly one colon which separates a reverse
+ * dns organization name from the feature's "short" name (e.g.
+ * "com.company:feature_name").
+ */
+boolean_t
+zfeature_is_valid_guid(const char *name)
+{
+       int i;
+       boolean_t has_colon = B_FALSE;
+
+       i = 0;
+       while (name[i] != '\0') {
+               char c = name[i++];
+               if (c == ':') {
+                       if (has_colon)
+                               return (B_FALSE);
+                       has_colon = B_TRUE;
+                       continue;
+               }
+               if (!valid_char(c, has_colon))
+                       return (B_FALSE);
+       }
+
+       return (has_colon);
+}
+
+boolean_t
+zfeature_is_supported(const char *guid)
+{
+       spa_feature_t i;
+
+       if (zfeature_checks_disable)
+               return (B_TRUE);
+
+       for (i = 0; i < SPA_FEATURES; i++) {
+               zfeature_info_t *feature = &spa_feature_table[i];
+               if (strcmp(guid, feature->fi_guid) == 0)
+                       return (B_TRUE);
+       }
+
+       return (B_FALSE);
+}
+
+int
+zfeature_lookup_name(const char *name, spa_feature_t *res)
+{
+       spa_feature_t i;
+
+       for (i = 0; i < SPA_FEATURES; i++) {
+               zfeature_info_t *feature = &spa_feature_table[i];
+               if (strcmp(name, feature->fi_uname) == 0) {
+                       if (res != NULL)
+                               *res = i;
+                       return (0);
+               }
+       }
+
+       return (ENOENT);
+}
+
+boolean_t
+zfeature_depends_on(spa_feature_t fid, spa_feature_t check)
+{
+       zfeature_info_t *feature = &spa_feature_table[fid];
+       int i;
+
+       for (i = 0; feature->fi_depends[i] != SPA_FEATURE_NONE; i++) {
+               if (feature->fi_depends[i] == check)
+                       return (B_TRUE);
+       }
+       return (B_FALSE);
+}
+
+static boolean_t
+deps_contains_feature(const spa_feature_t *deps, const spa_feature_t feature)
+{
+       int i;
+
+       for (i = 0; deps[i] != SPA_FEATURE_NONE; i++)
+               if (deps[i] == feature)
+                       return (B_TRUE);
+
+       return (B_FALSE);
+}
+
+static void
+zfeature_register(spa_feature_t fid, const char *guid, const char *name,
+    const char *desc, zfeature_flags_t flags, const spa_feature_t *deps)
+{
+       zfeature_info_t *feature = &spa_feature_table[fid];
+       static spa_feature_t nodeps[] = { SPA_FEATURE_NONE };
+
+       ASSERT(name != NULL);
+       ASSERT(desc != NULL);
+       ASSERT((flags & ZFEATURE_FLAG_READONLY_COMPAT) == 0 ||
+           (flags & ZFEATURE_FLAG_MOS) == 0);
+       ASSERT3U(fid, <, SPA_FEATURES);
+       ASSERT(zfeature_is_valid_guid(guid));
+
+       if (deps == NULL)
+               deps = nodeps;
+
+       VERIFY(((flags & ZFEATURE_FLAG_PER_DATASET) == 0) ||
+           (deps_contains_feature(deps, SPA_FEATURE_EXTENSIBLE_DATASET)));
+
+       feature->fi_feature = fid;
+       feature->fi_guid = guid;
+       feature->fi_uname = name;
+       feature->fi_desc = desc;
+       feature->fi_flags = flags;
+       feature->fi_depends = deps;
+}
+
+void
+zpool_feature_init(void)
+{
+       zfeature_register(SPA_FEATURE_ASYNC_DESTROY,
+           "com.delphix:async_destroy", "async_destroy",
+           "Destroy filesystems asynchronously.",
+           ZFEATURE_FLAG_READONLY_COMPAT, NULL);
+
+       zfeature_register(SPA_FEATURE_EMPTY_BPOBJ,
+           "com.delphix:empty_bpobj", "empty_bpobj",
+           "Snapshots use less space.",
+           ZFEATURE_FLAG_READONLY_COMPAT, NULL);
+
+       zfeature_register(SPA_FEATURE_LZ4_COMPRESS,
+           "org.illumos:lz4_compress", "lz4_compress",
+           "LZ4 compression algorithm support.",
+           ZFEATURE_FLAG_ACTIVATE_ON_ENABLE, NULL);
+
+       zfeature_register(SPA_FEATURE_MULTI_VDEV_CRASH_DUMP,
+           "com.joyent:multi_vdev_crash_dump", "multi_vdev_crash_dump",
+           "Crash dumps to multiple vdev pools.",
+           0, NULL);
+
+       zfeature_register(SPA_FEATURE_SPACEMAP_HISTOGRAM,
+           "com.delphix:spacemap_histogram", "spacemap_histogram",
+           "Spacemaps maintain space histograms.",
+           ZFEATURE_FLAG_READONLY_COMPAT, NULL);
+
+       zfeature_register(SPA_FEATURE_ENABLED_TXG,
+           "com.delphix:enabled_txg", "enabled_txg",
+           "Record txg at which a feature is enabled",
+           ZFEATURE_FLAG_READONLY_COMPAT, NULL);
+
+       {
+       static const spa_feature_t hole_birth_deps[] = {
+               SPA_FEATURE_ENABLED_TXG,
+               SPA_FEATURE_NONE
+       };
+       zfeature_register(SPA_FEATURE_HOLE_BIRTH,
+           "com.delphix:hole_birth", "hole_birth",
+           "Retain hole birth txg for more precise zfs send",
+           ZFEATURE_FLAG_MOS | ZFEATURE_FLAG_ACTIVATE_ON_ENABLE,
+           hole_birth_deps);
+       }
+
+       zfeature_register(SPA_FEATURE_EXTENSIBLE_DATASET,
+           "com.delphix:extensible_dataset", "extensible_dataset",
+           "Enhanced dataset functionality, used by other features.",
+           0, NULL);
+
+       {
+       static const spa_feature_t bookmarks_deps[] = {
+               SPA_FEATURE_EXTENSIBLE_DATASET,
+               SPA_FEATURE_NONE
+       };
+
+       zfeature_register(SPA_FEATURE_BOOKMARKS,
+           "com.delphix:bookmarks", "bookmarks",
+           "\"zfs bookmark\" command",
+           ZFEATURE_FLAG_READONLY_COMPAT, bookmarks_deps);
+       }
+
+       {
+       static const spa_feature_t filesystem_limits_deps[] = {
+               SPA_FEATURE_EXTENSIBLE_DATASET,
+               SPA_FEATURE_NONE
+       };
+       zfeature_register(SPA_FEATURE_FS_SS_LIMIT,
+           "com.joyent:filesystem_limits", "filesystem_limits",
+           "Filesystem and snapshot limits.",
+           ZFEATURE_FLAG_READONLY_COMPAT, filesystem_limits_deps);
+       }
+
+       zfeature_register(SPA_FEATURE_EMBEDDED_DATA,
+           "com.delphix:embedded_data", "embedded_data",
+           "Blocks which compress very well use even less space.",
+           ZFEATURE_FLAG_MOS | ZFEATURE_FLAG_ACTIVATE_ON_ENABLE,
+           NULL);
+
+       {
+       static const spa_feature_t large_blocks_deps[] = {
+               SPA_FEATURE_EXTENSIBLE_DATASET,
+               SPA_FEATURE_NONE
+       };
+       zfeature_register(SPA_FEATURE_LARGE_BLOCKS,
+           "org.open-zfs:large_blocks", "large_blocks",
+           "Support for blocks larger than 128KB.",
+           ZFEATURE_FLAG_PER_DATASET, large_blocks_deps);
+       }
+
+       {
+       static const spa_feature_t large_dnode_deps[] = {
+               SPA_FEATURE_EXTENSIBLE_DATASET,
+               SPA_FEATURE_NONE
+       };
+       zfeature_register(SPA_FEATURE_LARGE_DNODE,
+           "org.zfsonlinux:large_dnode", "large_dnode",
+           "Variable on-disk size of dnodes.",
+           ZFEATURE_FLAG_PER_DATASET, large_dnode_deps);
+       }
+
+       {
+       static const spa_feature_t sha512_deps[] = {
+               SPA_FEATURE_EXTENSIBLE_DATASET,
+               SPA_FEATURE_NONE
+       };
+       zfeature_register(SPA_FEATURE_SHA512,
+           "org.illumos:sha512", "sha512",
+           "SHA-512/256 hash algorithm.",
+           ZFEATURE_FLAG_PER_DATASET, sha512_deps);
+       }
+       {
+       static const spa_feature_t skein_deps[] = {
+               SPA_FEATURE_EXTENSIBLE_DATASET,
+               SPA_FEATURE_NONE
+       };
+       zfeature_register(SPA_FEATURE_SKEIN,
+           "org.illumos:skein", "skein",
+           "Skein hash algorithm.",
+           ZFEATURE_FLAG_PER_DATASET, skein_deps);
+       }
+
+       {
+       static const spa_feature_t edonr_deps[] = {
+               SPA_FEATURE_EXTENSIBLE_DATASET,
+               SPA_FEATURE_NONE
+       };
+       zfeature_register(SPA_FEATURE_EDONR,
+           "org.illumos:edonr", "edonr",
+           "Edon-R hash algorithm.",
+           ZFEATURE_FLAG_PER_DATASET, edonr_deps);
+       }
+       {
+       static const spa_feature_t userobj_accounting_deps[] = {
+               SPA_FEATURE_EXTENSIBLE_DATASET,
+               SPA_FEATURE_NONE
+       };
+       zfeature_register(SPA_FEATURE_USEROBJ_ACCOUNTING,
+           "org.zfsonlinux:userobj_accounting", "userobj_accounting",
+           "User/Group object accounting.",
+           ZFEATURE_FLAG_READONLY_COMPAT | ZFEATURE_FLAG_PER_DATASET,
+           userobj_accounting_deps);
+       }
+}
+
+#if defined(_KERNEL) && defined(HAVE_SPL)
+EXPORT_SYMBOL(zfeature_lookup_name);
+EXPORT_SYMBOL(zfeature_is_supported);
+EXPORT_SYMBOL(zfeature_is_valid_guid);
+EXPORT_SYMBOL(zfeature_depends_on);
+EXPORT_SYMBOL(zpool_feature_init);
+EXPORT_SYMBOL(spa_feature_table);
+#endif
index 52cb7e36555906183295358db9770cad17caa734..685a20c448ea4506c3847125c465a3659c3dff7d 100644 (file)
@@ -207,85 +207,10 @@ const char *zfs_history_event_names[ZFS_NUM_LEGACY_HISTORY_EVENTS] = {
        "pool split",
 };
 
-/*
- * Initialize rate limit struct
- *
- * rl:         zfs_ratelimit_t struct
- * burst:      Number to allow in an interval before rate limiting
- * interval:   Interval time in seconds
- */
-void
-zfs_ratelimit_init(zfs_ratelimit_t *rl, unsigned int burst,
-    unsigned int interval)
-{
-       rl->count = 0;
-       rl->start = 0;
-       rl->interval = interval;
-       rl->burst = burst;
-       mutex_init(&rl->lock, NULL, MUTEX_DEFAULT, NULL);
-}
-
-/*
- * Finalize rate limit struct
- *
- * rl:         zfs_ratelimit_t struct
- */
-void
-zfs_ratelimit_fini(zfs_ratelimit_t *rl)
-{
-       mutex_destroy(&rl->lock);
-}
-
-/*
- * Re-implementation of the kernel's __ratelimit() function
- *
- * We had to write our own rate limiter because the kernel's __ratelimit()
- * function annoyingly prints out how many times it rate limited to the kernel
- * logs (and there's no way to turn it off):
- *
- *     __ratelimit: 59 callbacks suppressed
- *
- * If the kernel ever allows us to disable these prints, we should go back to
- * using __ratelimit() instead.
- *
- * Return values are the same as __ratelimit():
- *
- * 0: If we're rate limiting
- * 1: If we're not rate limiting.
- */
-int
-zfs_ratelimit(zfs_ratelimit_t *rl)
-{
-       hrtime_t now;
-       hrtime_t elapsed;
-       int rc = 1;
-
-       mutex_enter(&rl->lock);
-
-       now = gethrtime();
-       elapsed = now - rl->start;
-
-       rl->count++;
-       if (NSEC2SEC(elapsed) >= rl->interval) {
-               rl->start = now;
-               rl->count = 0;
-       } else {
-               if (rl->count >= rl->burst) {
-                       rc = 0; /* We're ratelimiting */
-               }
-       }
-       mutex_exit(&rl->lock);
-
-       return (rc);
-}
-
 #if defined(_KERNEL) && defined(HAVE_SPL)
 EXPORT_SYMBOL(zfs_allocatable_devs);
 EXPORT_SYMBOL(zpool_get_rewind_policy);
 EXPORT_SYMBOL(zfs_zpl_version_map);
 EXPORT_SYMBOL(zfs_spa_version_map);
 EXPORT_SYMBOL(zfs_history_event_names);
-EXPORT_SYMBOL(zfs_ratelimit_init);
-EXPORT_SYMBOL(zfs_ratelimit_fini);
-EXPORT_SYMBOL(zfs_ratelimit);
 #endif
index ce659d7f5cc8ed506408100bc35e9627f86fe9b3..90e9048b1c1a03067a4bee51fa54ae836701eb96 100644 (file)
@@ -233,7 +233,7 @@ zfs_deleg_whokey(char *attr, zfs_deleg_who_type_t type,
                    ZFS_DELEG_FIELD_SEP_CHR);
                break;
        default:
-               cmn_err(CE_PANIC, "bad zfs_deleg_who_type_t %d", type);
+               ASSERT(!"bad zfs_deleg_who_type_t");
        }
 }
 
index 9cdf36d440772f8161cc56ebb31568d06dfba9b0..0cd992979cefd772a6ad198c08517682f2bfad7f 100644 (file)
@@ -212,7 +212,9 @@ static struct fletcher_4_impl_selector {
        { "scalar",     IMPL_SCALAR }
 };
 
+#if defined(_KERNEL)
 static kstat_t *fletcher_4_kstat;
+#endif
 
 static struct fletcher_4_kstat {
        uint64_t native;
@@ -589,7 +591,7 @@ fletcher_4_incremental_byteswap(void *buf, size_t size, void *data)
        return (0);
 }
 
-
+#if defined(_KERNEL)
 /* Fletcher 4 kstats */
 
 static int
@@ -642,6 +644,7 @@ fletcher_4_kstat_addr(kstat_t *ksp, loff_t n)
 
        return (ksp->ks_private);
 }
+#endif
 
 #define        FLETCHER_4_FASTEST_FN_COPY(type, src)                             \
 {                                                                        \
@@ -753,6 +756,7 @@ fletcher_4_init(void)
 
        vmem_free(databuf, data_size);
 
+#if defined(_KERNEL)
        /* install kstats for all implementations */
        fletcher_4_kstat = kstat_create("zfs", 0, "fletcher_4_bench", "misc",
            KSTAT_TYPE_RAW, 0, KSTAT_FLAG_VIRTUAL);
@@ -765,6 +769,7 @@ fletcher_4_init(void)
                    fletcher_4_kstat_addr);
                kstat_install(fletcher_4_kstat);
        }
+#endif
 
        /* Finish initialization */
        fletcher_4_initialized = B_TRUE;
@@ -773,10 +778,12 @@ fletcher_4_init(void)
 void
 fletcher_4_fini(void)
 {
+#if defined(_KERNEL)
        if (fletcher_4_kstat != NULL) {
                kstat_delete(fletcher_4_kstat);
                fletcher_4_kstat = NULL;
        }
+#endif
 }
 
 /* ABD adapters */
index d6336f3142ca200c933055f9530b64a834bdff1c..b849d901072f4201c72d443bd9db265157f7edd2 100644 (file)
@@ -82,7 +82,6 @@ $(MODULE)-objs += zap.o
 $(MODULE)-objs += zap_leaf.o
 $(MODULE)-objs += zap_micro.o
 $(MODULE)-objs += zfeature.o
-$(MODULE)-objs += zfeature_common.o
 $(MODULE)-objs += zfs_acl.o
 $(MODULE)-objs += zfs_byteswap.o
 $(MODULE)-objs += zfs_ctldir.o
@@ -93,6 +92,7 @@ $(MODULE)-objs += zfs_fuid.o
 $(MODULE)-objs += zfs_ioctl.o
 $(MODULE)-objs += zfs_log.o
 $(MODULE)-objs += zfs_onexit.o
+$(MODULE)-objs += zfs_ratelimit.o
 $(MODULE)-objs += zfs_replay.o
 $(MODULE)-objs += zfs_rlock.o
 $(MODULE)-objs += zfs_sa.o
diff --git a/module/zfs/zfeature_common.c b/module/zfs/zfeature_common.c
deleted file mode 100644 (file)
index 73abcb2..0000000
+++ /dev/null
@@ -1,321 +0,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 http://www.opensolaris.org/os/licensing.
- * 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) 2011, 2015 by Delphix. All rights reserved.
- * Copyright (c) 2013 by Saso Kiselkov. All rights reserved.
- * Copyright (c) 2013, Joyent, Inc. All rights reserved.
- * Copyright (c) 2014, Nexenta Systems, Inc. All rights reserved.
- */
-
-#ifdef _KERNEL
-#include <sys/systm.h>
-#else
-#include <errno.h>
-#include <string.h>
-#endif
-#include <sys/debug.h>
-#include <sys/fs/zfs.h>
-#include <sys/inttypes.h>
-#include <sys/types.h>
-#include "zfeature_common.h"
-
-/*
- * Set to disable all feature checks while opening pools, allowing pools with
- * unsupported features to be opened. Set for testing only.
- */
-boolean_t zfeature_checks_disable = B_FALSE;
-
-zfeature_info_t spa_feature_table[SPA_FEATURES];
-
-/*
- * Valid characters for feature guids. This list is mainly for aesthetic
- * purposes and could be expanded in the future. There are different allowed
- * characters in the guids reverse dns portion (before the colon) and its
- * short name (after the colon).
- */
-static int
-valid_char(char c, boolean_t after_colon)
-{
-       return ((c >= 'a' && c <= 'z') ||
-           (c >= '0' && c <= '9') ||
-           (after_colon && c == '_') ||
-           (!after_colon && (c == '.' || c == '-')));
-}
-
-/*
- * Every feature guid must contain exactly one colon which separates a reverse
- * dns organization name from the feature's "short" name (e.g.
- * "com.company:feature_name").
- */
-boolean_t
-zfeature_is_valid_guid(const char *name)
-{
-       int i;
-       boolean_t has_colon = B_FALSE;
-
-       i = 0;
-       while (name[i] != '\0') {
-               char c = name[i++];
-               if (c == ':') {
-                       if (has_colon)
-                               return (B_FALSE);
-                       has_colon = B_TRUE;
-                       continue;
-               }
-               if (!valid_char(c, has_colon))
-                       return (B_FALSE);
-       }
-
-       return (has_colon);
-}
-
-boolean_t
-zfeature_is_supported(const char *guid)
-{
-       spa_feature_t i;
-
-       if (zfeature_checks_disable)
-               return (B_TRUE);
-
-       for (i = 0; i < SPA_FEATURES; i++) {
-               zfeature_info_t *feature = &spa_feature_table[i];
-               if (strcmp(guid, feature->fi_guid) == 0)
-                       return (B_TRUE);
-       }
-
-       return (B_FALSE);
-}
-
-int
-zfeature_lookup_name(const char *name, spa_feature_t *res)
-{
-       spa_feature_t i;
-
-       for (i = 0; i < SPA_FEATURES; i++) {
-               zfeature_info_t *feature = &spa_feature_table[i];
-               if (strcmp(name, feature->fi_uname) == 0) {
-                       if (res != NULL)
-                               *res = i;
-                       return (0);
-               }
-       }
-
-       return (ENOENT);
-}
-
-boolean_t
-zfeature_depends_on(spa_feature_t fid, spa_feature_t check)
-{
-       zfeature_info_t *feature = &spa_feature_table[fid];
-       int i;
-
-       for (i = 0; feature->fi_depends[i] != SPA_FEATURE_NONE; i++) {
-               if (feature->fi_depends[i] == check)
-                       return (B_TRUE);
-       }
-       return (B_FALSE);
-}
-
-static boolean_t
-deps_contains_feature(const spa_feature_t *deps, const spa_feature_t feature)
-{
-       int i;
-
-       for (i = 0; deps[i] != SPA_FEATURE_NONE; i++)
-               if (deps[i] == feature)
-                       return (B_TRUE);
-
-       return (B_FALSE);
-}
-
-static void
-zfeature_register(spa_feature_t fid, const char *guid, const char *name,
-    const char *desc, zfeature_flags_t flags, const spa_feature_t *deps)
-{
-       zfeature_info_t *feature = &spa_feature_table[fid];
-       static spa_feature_t nodeps[] = { SPA_FEATURE_NONE };
-
-       ASSERT(name != NULL);
-       ASSERT(desc != NULL);
-       ASSERT((flags & ZFEATURE_FLAG_READONLY_COMPAT) == 0 ||
-           (flags & ZFEATURE_FLAG_MOS) == 0);
-       ASSERT3U(fid, <, SPA_FEATURES);
-       ASSERT(zfeature_is_valid_guid(guid));
-
-       if (deps == NULL)
-               deps = nodeps;
-
-       VERIFY(((flags & ZFEATURE_FLAG_PER_DATASET) == 0) ||
-           (deps_contains_feature(deps, SPA_FEATURE_EXTENSIBLE_DATASET)));
-
-       feature->fi_feature = fid;
-       feature->fi_guid = guid;
-       feature->fi_uname = name;
-       feature->fi_desc = desc;
-       feature->fi_flags = flags;
-       feature->fi_depends = deps;
-}
-
-void
-zpool_feature_init(void)
-{
-       zfeature_register(SPA_FEATURE_ASYNC_DESTROY,
-           "com.delphix:async_destroy", "async_destroy",
-           "Destroy filesystems asynchronously.",
-           ZFEATURE_FLAG_READONLY_COMPAT, NULL);
-
-       zfeature_register(SPA_FEATURE_EMPTY_BPOBJ,
-           "com.delphix:empty_bpobj", "empty_bpobj",
-           "Snapshots use less space.",
-           ZFEATURE_FLAG_READONLY_COMPAT, NULL);
-
-       zfeature_register(SPA_FEATURE_LZ4_COMPRESS,
-           "org.illumos:lz4_compress", "lz4_compress",
-           "LZ4 compression algorithm support.",
-           ZFEATURE_FLAG_ACTIVATE_ON_ENABLE, NULL);
-
-       zfeature_register(SPA_FEATURE_MULTI_VDEV_CRASH_DUMP,
-           "com.joyent:multi_vdev_crash_dump", "multi_vdev_crash_dump",
-           "Crash dumps to multiple vdev pools.",
-           0, NULL);
-
-       zfeature_register(SPA_FEATURE_SPACEMAP_HISTOGRAM,
-           "com.delphix:spacemap_histogram", "spacemap_histogram",
-           "Spacemaps maintain space histograms.",
-           ZFEATURE_FLAG_READONLY_COMPAT, NULL);
-
-       zfeature_register(SPA_FEATURE_ENABLED_TXG,
-           "com.delphix:enabled_txg", "enabled_txg",
-           "Record txg at which a feature is enabled",
-           ZFEATURE_FLAG_READONLY_COMPAT, NULL);
-
-       {
-       static const spa_feature_t hole_birth_deps[] = {
-               SPA_FEATURE_ENABLED_TXG,
-               SPA_FEATURE_NONE
-       };
-       zfeature_register(SPA_FEATURE_HOLE_BIRTH,
-           "com.delphix:hole_birth", "hole_birth",
-           "Retain hole birth txg for more precise zfs send",
-           ZFEATURE_FLAG_MOS | ZFEATURE_FLAG_ACTIVATE_ON_ENABLE,
-           hole_birth_deps);
-       }
-
-       zfeature_register(SPA_FEATURE_EXTENSIBLE_DATASET,
-           "com.delphix:extensible_dataset", "extensible_dataset",
-           "Enhanced dataset functionality, used by other features.",
-           0, NULL);
-
-       {
-       static const spa_feature_t bookmarks_deps[] = {
-               SPA_FEATURE_EXTENSIBLE_DATASET,
-               SPA_FEATURE_NONE
-       };
-
-       zfeature_register(SPA_FEATURE_BOOKMARKS,
-           "com.delphix:bookmarks", "bookmarks",
-           "\"zfs bookmark\" command",
-           ZFEATURE_FLAG_READONLY_COMPAT, bookmarks_deps);
-       }
-
-       {
-       static const spa_feature_t filesystem_limits_deps[] = {
-               SPA_FEATURE_EXTENSIBLE_DATASET,
-               SPA_FEATURE_NONE
-       };
-       zfeature_register(SPA_FEATURE_FS_SS_LIMIT,
-           "com.joyent:filesystem_limits", "filesystem_limits",
-           "Filesystem and snapshot limits.",
-           ZFEATURE_FLAG_READONLY_COMPAT, filesystem_limits_deps);
-       }
-
-       zfeature_register(SPA_FEATURE_EMBEDDED_DATA,
-           "com.delphix:embedded_data", "embedded_data",
-           "Blocks which compress very well use even less space.",
-           ZFEATURE_FLAG_MOS | ZFEATURE_FLAG_ACTIVATE_ON_ENABLE,
-           NULL);
-
-       {
-       static const spa_feature_t large_blocks_deps[] = {
-               SPA_FEATURE_EXTENSIBLE_DATASET,
-               SPA_FEATURE_NONE
-       };
-       zfeature_register(SPA_FEATURE_LARGE_BLOCKS,
-           "org.open-zfs:large_blocks", "large_blocks",
-           "Support for blocks larger than 128KB.",
-           ZFEATURE_FLAG_PER_DATASET, large_blocks_deps);
-       }
-
-       {
-       static const spa_feature_t large_dnode_deps[] = {
-               SPA_FEATURE_EXTENSIBLE_DATASET,
-               SPA_FEATURE_NONE
-       };
-       zfeature_register(SPA_FEATURE_LARGE_DNODE,
-           "org.zfsonlinux:large_dnode", "large_dnode",
-           "Variable on-disk size of dnodes.",
-           ZFEATURE_FLAG_PER_DATASET, large_dnode_deps);
-       }
-
-       {
-       static const spa_feature_t sha512_deps[] = {
-               SPA_FEATURE_EXTENSIBLE_DATASET,
-               SPA_FEATURE_NONE
-       };
-       zfeature_register(SPA_FEATURE_SHA512,
-           "org.illumos:sha512", "sha512",
-           "SHA-512/256 hash algorithm.",
-           ZFEATURE_FLAG_PER_DATASET, sha512_deps);
-       }
-       {
-       static const spa_feature_t skein_deps[] = {
-               SPA_FEATURE_EXTENSIBLE_DATASET,
-               SPA_FEATURE_NONE
-       };
-       zfeature_register(SPA_FEATURE_SKEIN,
-           "org.illumos:skein", "skein",
-           "Skein hash algorithm.",
-           ZFEATURE_FLAG_PER_DATASET, skein_deps);
-       }
-
-       {
-       static const spa_feature_t edonr_deps[] = {
-               SPA_FEATURE_EXTENSIBLE_DATASET,
-               SPA_FEATURE_NONE
-       };
-       zfeature_register(SPA_FEATURE_EDONR,
-           "org.illumos:edonr", "edonr",
-           "Edon-R hash algorithm.",
-           ZFEATURE_FLAG_PER_DATASET, edonr_deps);
-       }
-       {
-       static const spa_feature_t userobj_accounting_deps[] = {
-               SPA_FEATURE_EXTENSIBLE_DATASET,
-               SPA_FEATURE_NONE
-       };
-       zfeature_register(SPA_FEATURE_USEROBJ_ACCOUNTING,
-           "org.zfsonlinux:userobj_accounting", "userobj_accounting",
-           "User/Group object accounting.",
-           ZFEATURE_FLAG_READONLY_COMPAT | ZFEATURE_FLAG_PER_DATASET,
-           userobj_accounting_deps);
-       }
-}
diff --git a/module/zfs/zfs_ratelimit.c b/module/zfs/zfs_ratelimit.c
new file mode 100644 (file)
index 0000000..d4a7d52
--- /dev/null
@@ -0,0 +1,99 @@
+/*
+ * 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://www.opensolaris.org/os/licensing.
+ * 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) 2017, Lawrence Livermore National Security, LLC.
+ */
+
+#include <sys/zfs_ratelimit.h>
+
+/*
+ * Initialize rate limit struct
+ *
+ * rl:         zfs_ratelimit_t struct
+ * burst:      Number to allow in an interval before rate limiting
+ * interval:   Interval time in seconds
+ */
+void
+zfs_ratelimit_init(zfs_ratelimit_t *rl, unsigned int burst,
+    unsigned int interval)
+{
+       rl->count = 0;
+       rl->start = 0;
+       rl->interval = interval;
+       rl->burst = burst;
+       mutex_init(&rl->lock, NULL, MUTEX_DEFAULT, NULL);
+}
+
+/*
+ * Finalize rate limit struct
+ *
+ * rl:         zfs_ratelimit_t struct
+ */
+void
+zfs_ratelimit_fini(zfs_ratelimit_t *rl)
+{
+       mutex_destroy(&rl->lock);
+}
+
+/*
+ * Re-implementation of the kernel's __ratelimit() function
+ *
+ * We had to write our own rate limiter because the kernel's __ratelimit()
+ * function annoyingly prints out how many times it rate limited to the kernel
+ * logs (and there's no way to turn it off):
+ *
+ *     __ratelimit: 59 callbacks suppressed
+ *
+ * If the kernel ever allows us to disable these prints, we should go back to
+ * using __ratelimit() instead.
+ *
+ * Return values are the same as __ratelimit():
+ *
+ * 0: If we're rate limiting
+ * 1: If we're not rate limiting.
+ */
+int
+zfs_ratelimit(zfs_ratelimit_t *rl)
+{
+       hrtime_t now;
+
+       hrtime_t elapsed;
+       int error = 1;
+
+       mutex_enter(&rl->lock);
+
+       now = gethrtime();
+       elapsed = now - rl->start;
+
+       rl->count++;
+       if (NSEC2SEC(elapsed) >= rl->interval) {
+               rl->start = now;
+               rl->count = 0;
+       } else {
+               if (rl->count >= rl->burst) {
+                       error = 0; /* We're ratelimiting */
+               }
+       }
+       mutex_exit(&rl->lock);
+
+       return (error);
+}
index d4def4429a833cc043929fd08ed407a8eb59439e..99824d6dd4afbb2c44e57e43d1aaecc8f2efcbce 100755 (executable)
@@ -19,14 +19,6 @@ s:usr/src/test/zfs-tests/runfiles:tests/runfiles:g
 s:usr/src/test/zfs-tests/tests/functional:tests/zfs-tests/tests/functional:g
 s:usr/src/test/zfs-tests/tests/perf:tests/zfs-tests/tests/perf:g
 s:usr/src/test/test-runner/cmd/run.py:tests/test-runner/cmd/test-runner.py:g
-
-#
-# The usr/src/common/zfs/ files go in a couple different dirs.
-# usr/src/common/zfs/zfeature_common.c goes in module/zfs
-#
-s:usr/src/common/zfs/zfeature_common.c:module/zfs/zfeature_common.c:g
-
-# ...but most of the rest of the C files go in module/zcommon
 s/usr\/src\/common\/zfs\/\(.*\)\.c/module\/zcommon\/\1.c/g
 
 # crypto framework
index 811f09452e5a2024dd9af2628ce228b46cd51f80..d885bc1ab6804e0bea542e379613265dce67bffd 100644 (file)
@@ -13,11 +13,7 @@ DEFAULT_INCLUDES += \
        -I$(top_srcdir)/lib/libspl/include
 
 many_fds_LDADD = \
-       $(top_builddir)/lib/libnvpair/libnvpair.la \
-       $(top_builddir)/lib/libuutil/libuutil.la \
-       $(top_builddir)/lib/libzpool/libzpool.la \
-       $(top_builddir)/lib/libzfs/libzfs.la \
-       $(top_builddir)/lib/libzfs_core/libzfs_core.la
+       $(top_builddir)/lib/libzfs/libzfs.la
 
 pkgexec_PROGRAMS = many_fds
 many_fds_SOURCES = many_fds.c