]> git.proxmox.com Git - mirror_spl-debian.git/commitdiff
Imported Upstream version 0.6.5.2
authorAron Xu <aron@debian.org>
Tue, 13 Oct 2015 14:20:53 +0000 (15:20 +0100)
committerAron Xu <aron@debian.org>
Tue, 13 Oct 2015 14:20:53 +0000 (15:20 +0100)
47 files changed:
META
Makefile.am
Makefile.in
config/rpm.am
config/spl-build.m4
configure
include/linux/rwsem_compat.h
include/sys/Makefile.am
include/sys/Makefile.in
include/sys/condvar.h
include/sys/debug.h
include/sys/rwlock.h
include/sys/sysmacros.h
include/sys/taskq.h
include/sys/uio.h
include/sys/user.h [new file with mode: 0644]
include/sys/vmem.h
include/sys/vmsystm.h
include/sys/vnode.h
include/util/Makefile.am
include/util/Makefile.in
man/man5/spl-module-parameters.5
module/spl/Makefile.in
module/spl/spl-condvar.c
module/spl/spl-kmem-cache.c
module/spl/spl-proc.c
module/spl/spl-taskq.c
module/spl/spl-tsd.c
module/spl/spl-vnode.c
module/splat/Makefile.in
module/splat/splat-atomic.c
module/splat/splat-ctl.c
module/splat/splat-internal.h
module/splat/splat-kmem.c
module/splat/splat-mutex.c
module/splat/splat-rwlock.c
module/splat/splat-taskq.c
module/splat/splat-thread.c
module/splat/splat-vnode.c
rpm/generic/spl-dkms.spec.in
rpm/generic/spl-kmod.spec.in
rpm/generic/spl.spec.in
rpm/redhat/spl-dkms.spec.in
rpm/redhat/spl.spec.in
scripts/Makefile.am
scripts/Makefile.in
spl_config.h.in

diff --git a/META b/META
index 5c3fe29c2d369df7d16acdb98fec340a862f696c..49ac4741f29c2189811f346ec52446976195b5ed 100644 (file)
--- a/META
+++ b/META
@@ -1,7 +1,7 @@
 Meta:         1
 Name:         spl
 Branch:       1.0
-Version:      0.6.4.2
+Version:      0.6.5.2
 Release:      1
 Release-Tags: relext
 License:      GPL
index 89af931ae4fa7f732ef5aa6720473ab87d3b3c74..4977448fda95ca7acf5baf63a031f5b726fb7c35 100644 (file)
@@ -1,9 +1,9 @@
 
 ACLOCAL_AMFLAGS = -I config
 
-include $(top_srcdir)/config/rpm.am
-include $(top_srcdir)/config/deb.am
-include $(top_srcdir)/config/tgz.am
+include config/rpm.am
+include config/deb.am
+include config/tgz.am
 
 SUBDIRS = include rpm
 if CONFIG_USER
@@ -40,11 +40,11 @@ dist-hook:
                $(distdir)/META
 
 ctags:
-       $(RM) $(top_srcdir)/tags
+       $(RM) tags
        find $(top_srcdir) -name .git -prune -o -name '*.[hc]' | xargs ctags
 
 etags:
-       $(RM) $(top_srcdir)/TAGS
+       $(RM) TAGS
        find $(top_srcdir) -name .pc -prune -o -name '*.[hc]' | xargs etags -a
 
 tags: ctags etags
index ed56b225563b2d4996d9e4b4b5dcde9a9cc78f86..c4b29393231c0444816f3bb070ce6be2cb18b5f8 100644 (file)
@@ -73,9 +73,9 @@ host_triplet = @host@
 target_triplet = @target@
 DIST_COMMON = $(am__configure_deps) $(am__extra_HEADERS_DIST) \
        $(srcdir)/Makefile.am $(srcdir)/Makefile.in \
-       $(srcdir)/spl.release.in $(srcdir)/spl_config.h.in \
-       $(top_srcdir)/config/deb.am $(top_srcdir)/config/rpm.am \
-       $(top_srcdir)/config/tgz.am $(top_srcdir)/configure \
+       $(srcdir)/config/deb.am $(srcdir)/config/rpm.am \
+       $(srcdir)/config/tgz.am $(srcdir)/spl.release.in \
+       $(srcdir)/spl_config.h.in $(top_srcdir)/configure \
        $(top_srcdir)/module/Makefile.in \
        $(top_srcdir)/module/spl/Makefile.in \
        $(top_srcdir)/module/splat/Makefile.in AUTHORS COPYING \
@@ -376,7 +376,7 @@ all: spl_config.h
 .SUFFIXES:
 am--refresh: Makefile
        @:
-$(srcdir)/Makefile.in: @MAINTAINER_MODE_TRUE@ $(srcdir)/Makefile.am $(top_srcdir)/config/rpm.am $(top_srcdir)/config/deb.am $(top_srcdir)/config/tgz.am $(am__configure_deps)
+$(srcdir)/Makefile.in: @MAINTAINER_MODE_TRUE@ $(srcdir)/Makefile.am $(srcdir)/config/rpm.am $(srcdir)/config/deb.am $(srcdir)/config/tgz.am $(am__configure_deps)
        @for dep in $?; do \
          case '$(am__configure_deps)' in \
            *$$dep*) \
@@ -399,7 +399,7 @@ Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status
            echo ' cd $(top_builddir) && $(SHELL) ./config.status $@ $(am__depfiles_maybe)'; \
            cd $(top_builddir) && $(SHELL) ./config.status $@ $(am__depfiles_maybe);; \
        esac;
-$(top_srcdir)/config/rpm.am $(top_srcdir)/config/deb.am $(top_srcdir)/config/tgz.am:
+$(srcdir)/config/rpm.am $(srcdir)/config/deb.am $(srcdir)/config/tgz.am:
 
 $(top_builddir)/config.status: $(top_srcdir)/configure $(CONFIG_STATUS_DEPENDENCIES)
        $(SHELL) ./config.status --recheck
@@ -980,7 +980,7 @@ rpm-local:
        mkdir -p $(rpmbuild)/SPECS && \
        cp ${RPM_SPEC_DIR}/$(rpmspec) $(rpmbuild)/SPECS && \
        mkdir -p $(rpmbuild)/SOURCES && \
-       cp scripts/kmodtool $(rpmbuild)/SOURCES && \
+       cp $(top_srcdir)/scripts/kmodtool $(rpmbuild)/SOURCES && \
        cp $(distdir).tar.gz $(rpmbuild)/SOURCES)
 
 srpm-common: dist
@@ -1093,11 +1093,11 @@ dist-hook:
                $(distdir)/META
 
 ctags:
-       $(RM) $(top_srcdir)/tags
+       $(RM) tags
        find $(top_srcdir) -name .git -prune -o -name '*.[hc]' | xargs ctags
 
 etags:
-       $(RM) $(top_srcdir)/TAGS
+       $(RM) TAGS
        find $(top_srcdir) -name .pc -prune -o -name '*.[hc]' | xargs etags -a
 
 tags: ctags etags
index 311c754d429d4dbc00eb35e5fc312dc42abf7db4..51a20b3e6a10d736b3e6422f3faafbb1c93560db 100644 (file)
@@ -51,7 +51,7 @@ rpm-local:
        mkdir -p $(rpmbuild)/SPECS && \
        cp ${RPM_SPEC_DIR}/$(rpmspec) $(rpmbuild)/SPECS && \
        mkdir -p $(rpmbuild)/SOURCES && \
-       cp scripts/kmodtool $(rpmbuild)/SOURCES && \
+       cp $(top_srcdir)/scripts/kmodtool $(rpmbuild)/SOURCES && \
        cp $(distdir).tar.gz $(rpmbuild)/SOURCES)
 
 srpm-common: dist
index 3bfc1e2325e25242d28d0ac43c6b96db8b2da513..daa9eb714897d090efb6492ed2311b243d151b19 100644 (file)
@@ -33,7 +33,6 @@ AC_DEFUN([SPL_AC_CONFIG_KERNEL], [
        SPL_AC_FS_STRUCT_SPINLOCK
        SPL_AC_KUIDGID_T
        SPL_AC_PUT_TASK_STRUCT
-       SPL_AC_EXPORTED_RWSEM_IS_LOCKED
        SPL_AC_KERNEL_FALLOCATE
        SPL_AC_CONFIG_ZLIB_INFLATE
        SPL_AC_CONFIG_ZLIB_DEFLATE
@@ -453,15 +452,14 @@ dnl #
 dnl # Enabled by default it provides a minimal level of memory tracking.
 dnl # A total count of bytes allocated is kept for each alloc and free.
 dnl # Then at module unload time a report to the console will be printed
-dnl # if memory was leaked.  Additionally, /proc/spl/kmem/slab will exist
-dnl # and provide an easy way to inspect the kmem based slab.
+dnl # if memory was leaked.
 dnl #
 AC_DEFUN([SPL_AC_DEBUG_KMEM], [
        AC_ARG_ENABLE([debug-kmem],
                [AS_HELP_STRING([--enable-debug-kmem],
-               [Enable basic kmem accounting @<:@default=yes@:>@])],
+               [Enable basic kmem accounting @<:@default=no@:>@])],
                [],
-               [enable_debug_kmem=yes])
+               [enable_debug_kmem=no])
 
        AS_IF([test "x$enable_debug_kmem" = xyes],
        [
@@ -1201,27 +1199,6 @@ AC_DEFUN([SPL_AC_KERNEL_FALLOCATE], [
        SPL_AC_PAX_KERNEL_FILE_FALLOCATE
 ])
 
-dnl #
-dnl # 2.6.33 API change. Also backported in RHEL5 as of 2.6.18-190.el5.
-dnl # Earlier versions of rwsem_is_locked() were inline and had a race
-dnl # condition.  The fixed version is exported as a symbol.  The race
-dnl # condition is fixed by acquiring sem->wait_lock, so we must not
-dnl # call that version while holding sem->wait_lock.
-dnl #
-AC_DEFUN([SPL_AC_EXPORTED_RWSEM_IS_LOCKED],
-       [AC_MSG_CHECKING([whether rwsem_is_locked() acquires sem->wait_lock])
-       SPL_LINUX_TRY_COMPILE_SYMBOL([
-               #include <linux/rwsem.h>
-               int rwsem_is_locked(struct rw_semaphore *sem) { return 0; }
-       ], [], [rwsem_is_locked], [lib/rwsem-spinlock.c], [
-               AC_MSG_RESULT(yes)
-               AC_DEFINE(RWSEM_IS_LOCKED_TAKES_WAIT_LOCK, 1,
-                         [rwsem_is_locked() acquires sem->wait_lock])
-       ], [
-               AC_MSG_RESULT(no)
-       ])
-])
-
 dnl #
 dnl # zlib inflate compat,
 dnl # Verify the kernel has CONFIG_ZLIB_INFLATE support enabled.
index a6878b322508e0dda148246d3e8758f861c1520e..193dadedadee2f18fa8475785e13f9467a51ca75 100755 (executable)
--- a/configure
+++ b/configure
@@ -1,6 +1,6 @@
 #! /bin/sh
 # Guess values for system-dependent variables and create Makefiles.
-# Generated by GNU Autoconf 2.68 for spl 0.6.4.2.
+# Generated by GNU Autoconf 2.68 for spl 0.6.5.2.
 #
 #
 # Copyright (C) 1992, 1993, 1994, 1995, 1996, 1998, 1999, 2000, 2001,
@@ -567,8 +567,8 @@ MAKEFLAGS=
 # Identity of this package.
 PACKAGE_NAME='spl'
 PACKAGE_TARNAME='spl'
-PACKAGE_VERSION='0.6.4.2'
-PACKAGE_STRING='spl 0.6.4.2'
+PACKAGE_VERSION='0.6.5.2'
+PACKAGE_STRING='spl 0.6.5.2'
 PACKAGE_BUGREPORT=''
 PACKAGE_URL=''
 
@@ -1357,7 +1357,7 @@ if test "$ac_init_help" = "long"; then
   # Omit some internal or obsolete options to make the list less imposing.
   # This message is too long to be a string in the A/UX 3.1 sh.
   cat <<_ACEOF
-\`configure' configures spl 0.6.4.2 to adapt to many kinds of systems.
+\`configure' configures spl 0.6.5.2 to adapt to many kinds of systems.
 
 Usage: $0 [OPTION]... [VAR=VALUE]...
 
@@ -1428,7 +1428,7 @@ fi
 
 if test -n "$ac_init_help"; then
   case $ac_init_help in
-     short | recursive ) echo "Configuration of spl 0.6.4.2:";;
+     short | recursive ) echo "Configuration of spl 0.6.5.2:";;
    esac
   cat <<\_ACEOF
 
@@ -1450,7 +1450,7 @@ Optional Features:
   --enable-linux-builtin  Configure for builtin in-tree kernel modules
                           [default=no]
   --enable-debug          Enable generic debug support [default=no]
-  --enable-debug-kmem     Enable basic kmem accounting [default=yes]
+  --enable-debug-kmem     Enable basic kmem accounting [default=no]
   --enable-debug-kmem-tracking
                           Enable detailed kmem tracking [default=no]
   --enable-atomic-spinlocks
@@ -1545,7 +1545,7 @@ fi
 test -n "$ac_init_help" && exit $ac_status
 if $ac_init_version; then
   cat <<\_ACEOF
-spl configure 0.6.4.2
+spl configure 0.6.5.2
 generated by GNU Autoconf 2.68
 
 Copyright (C) 2010 Free Software Foundation, Inc.
@@ -1823,7 +1823,7 @@ cat >config.log <<_ACEOF
 This file contains any messages produced by compilers while
 running configure, to aid debugging if configure makes a mistake.
 
-It was created by spl $as_me 0.6.4.2, which was
+It was created by spl $as_me 0.6.5.2, which was
 generated by GNU Autoconf 2.68.  Invocation command line was
 
   $ $0 $@
@@ -2947,7 +2947,7 @@ fi
 
 # Define the identity of the package.
  PACKAGE='spl'
- VERSION='0.6.4.2'
+ VERSION='0.6.5.2'
 
 
 cat >>confdefs.h <<_ACEOF
@@ -11922,7 +11922,7 @@ $as_echo "$enable_debug" >&6; }
 if test "${enable_debug_kmem+set}" = set; then :
   enableval=$enable_debug_kmem;
 else
-  enable_debug_kmem=yes
+  enable_debug_kmem=no
 fi
 
 
@@ -13404,103 +13404,6 @@ $as_echo "#define HAVE_PUT_TASK_STRUCT 1" >>confdefs.h
        fi
 
 
-       { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether rwsem_is_locked() acquires sem->wait_lock" >&5
-$as_echo_n "checking whether rwsem_is_locked() acquires sem->wait_lock... " >&6; }
-
-
-
-cat confdefs.h - <<_ACEOF >conftest.c
-
-
-               #include <linux/rwsem.h>
-               int rwsem_is_locked(struct rw_semaphore *sem) { return 0; }
-
-int
-main (void)
-{
-
-  ;
-  return 0;
-}
-
-_ACEOF
-
-
-       rm -Rf build && mkdir -p build && touch build/conftest.mod.c
-       echo "obj-m := conftest.o" >build/Makefile
-       modpost_flag=''
-       test "x$enable_linux_builtin" = xyes && modpost_flag='modpost=true' # fake modpost stage
-       if { ac_try='cp conftest.c build && make modules -C $LINUX_OBJ EXTRA_CFLAGS="-Werror-implicit-function-declaration $EXTRA_KCFLAGS" $ARCH_UM M=$PWD/build $modpost_flag'
-  { { eval echo "\"\$as_me\":${as_lineno-$LINENO}: \"$ac_try\""; } >&5
-  (eval $ac_try) 2>&5
-  ac_status=$?
-  $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
-  test $ac_status = 0; }; } >/dev/null && { ac_try='test -s build/conftest.o'
-  { { eval echo "\"\$as_me\":${as_lineno-$LINENO}: \"$ac_try\""; } >&5
-  (eval $ac_try) 2>&5
-  ac_status=$?
-  $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
-  test $ac_status = 0; }; }; then :
-  rc=0
-else
-  $as_echo "$as_me: failed program was:" >&5
-sed 's/^/| /' conftest.$ac_ext >&5
- rc=1
-
-
-fi
-       rm -Rf build
-
-
-       if test $rc -ne 0; then :
-
-               { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
-$as_echo "no" >&6; }
-
-       else
-               if test "x$enable_linux_builtin" != xyes; then
-
-       grep -q -E '[[:space:]]rwsem_is_locked[[:space:]]' \
-               $LINUX_OBJ/Module*.symvers 2>/dev/null
-       rc=$?
-       if test $rc -ne 0; then
-               export=0
-               for file in lib/rwsem-spinlock.c; do
-                       grep -q -E "EXPORT_SYMBOL.*(rwsem_is_locked)" \
-                               "$LINUX_OBJ/$file" 2>/dev/null
-                       rc=$?
-                       if test $rc -eq 0; then
-                               export=1
-                               break;
-                       fi
-               done
-               if test $export -eq 0; then :
-                       rc=1
-               else :
-                       rc=0
-               fi
-       else :
-               rc=0
-       fi
-
-               fi
-               if test $rc -ne 0; then :
-
-               { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
-$as_echo "no" >&6; }
-
-               else :
-
-               { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5
-$as_echo "yes" >&6; }
-
-$as_echo "#define RWSEM_IS_LOCKED_TAKES_WAIT_LOCK 1" >>confdefs.h
-
-
-               fi
-       fi
-
-
 
 
        { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether fops->fallocate() exists" >&5
@@ -14589,7 +14492,7 @@ $as_echo "$enable_debug" >&6; }
 if test "${enable_debug_kmem+set}" = set; then :
   enableval=$enable_debug_kmem;
 else
-  enable_debug_kmem=yes
+  enable_debug_kmem=no
 fi
 
 
@@ -16071,103 +15974,6 @@ $as_echo "#define HAVE_PUT_TASK_STRUCT 1" >>confdefs.h
        fi
 
 
-       { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether rwsem_is_locked() acquires sem->wait_lock" >&5
-$as_echo_n "checking whether rwsem_is_locked() acquires sem->wait_lock... " >&6; }
-
-
-
-cat confdefs.h - <<_ACEOF >conftest.c
-
-
-               #include <linux/rwsem.h>
-               int rwsem_is_locked(struct rw_semaphore *sem) { return 0; }
-
-int
-main (void)
-{
-
-  ;
-  return 0;
-}
-
-_ACEOF
-
-
-       rm -Rf build && mkdir -p build && touch build/conftest.mod.c
-       echo "obj-m := conftest.o" >build/Makefile
-       modpost_flag=''
-       test "x$enable_linux_builtin" = xyes && modpost_flag='modpost=true' # fake modpost stage
-       if { ac_try='cp conftest.c build && make modules -C $LINUX_OBJ EXTRA_CFLAGS="-Werror-implicit-function-declaration $EXTRA_KCFLAGS" $ARCH_UM M=$PWD/build $modpost_flag'
-  { { eval echo "\"\$as_me\":${as_lineno-$LINENO}: \"$ac_try\""; } >&5
-  (eval $ac_try) 2>&5
-  ac_status=$?
-  $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
-  test $ac_status = 0; }; } >/dev/null && { ac_try='test -s build/conftest.o'
-  { { eval echo "\"\$as_me\":${as_lineno-$LINENO}: \"$ac_try\""; } >&5
-  (eval $ac_try) 2>&5
-  ac_status=$?
-  $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
-  test $ac_status = 0; }; }; then :
-  rc=0
-else
-  $as_echo "$as_me: failed program was:" >&5
-sed 's/^/| /' conftest.$ac_ext >&5
- rc=1
-
-
-fi
-       rm -Rf build
-
-
-       if test $rc -ne 0; then :
-
-               { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
-$as_echo "no" >&6; }
-
-       else
-               if test "x$enable_linux_builtin" != xyes; then
-
-       grep -q -E '[[:space:]]rwsem_is_locked[[:space:]]' \
-               $LINUX_OBJ/Module*.symvers 2>/dev/null
-       rc=$?
-       if test $rc -ne 0; then
-               export=0
-               for file in lib/rwsem-spinlock.c; do
-                       grep -q -E "EXPORT_SYMBOL.*(rwsem_is_locked)" \
-                               "$LINUX_OBJ/$file" 2>/dev/null
-                       rc=$?
-                       if test $rc -eq 0; then
-                               export=1
-                               break;
-                       fi
-               done
-               if test $export -eq 0; then :
-                       rc=1
-               else :
-                       rc=0
-               fi
-       else :
-               rc=0
-       fi
-
-               fi
-               if test $rc -ne 0; then :
-
-               { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
-$as_echo "no" >&6; }
-
-               else :
-
-               { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5
-$as_echo "yes" >&6; }
-
-$as_echo "#define RWSEM_IS_LOCKED_TAKES_WAIT_LOCK 1" >>confdefs.h
-
-
-               fi
-       fi
-
-
 
 
        { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether fops->fallocate() exists" >&5
@@ -17646,7 +17452,7 @@ cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1
 # report actual input values of CONFIG_FILES etc. instead of their
 # values after options handling.
 ac_log="
-This file was extended by spl $as_me 0.6.4.2, which was
+This file was extended by spl $as_me 0.6.5.2, which was
 generated by GNU Autoconf 2.68.  Invocation command line was
 
   CONFIG_FILES    = $CONFIG_FILES
@@ -17712,7 +17518,7 @@ _ACEOF
 cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1
 ac_cs_config="`$as_echo "$ac_configure_args" | sed 's/^ //; s/[\\""\`\$]/\\\\&/g'`"
 ac_cs_version="\\
-spl config.status 0.6.4.2
+spl config.status 0.6.5.2
 configured by $0, generated by GNU Autoconf 2.68,
   with options \\"\$ac_cs_config\\"
 
index 80f348e4c25abbe6556970090fc38975376275b8..5841d7c286978011df049ecbc2520edb249bdf7a 100644 (file)
 #define spl_rwsem_trylock_irqsave(lk, fl)    spin_trylock_irqsave(lk, fl)
 #endif /* RWSEM_SPINLOCK_IS_RAW */
 
-/*
- * Prior to Linux 2.6.33 there existed a race condition in rwsem_is_locked().
- * The semaphore's activity was checked outside of the wait_lock which
- * could result in some readers getting the incorrect activity value.
- *
- * When a kernel without this fix is detected the SPL takes responsibility
- * for acquiring the wait_lock to avoid this race.
- */
-#if defined(RWSEM_IS_LOCKED_TAKES_WAIT_LOCK)
 #define spl_rwsem_is_locked(rwsem)           rwsem_is_locked(rwsem)
-#else
-static inline int
-spl_rwsem_is_locked(struct rw_semaphore *rwsem)
-{
-       unsigned long flags;
-       int rc = 1;
-
-       if (spl_rwsem_trylock_irqsave(&rwsem->wait_lock, flags)) {
-               rc = rwsem_is_locked(rwsem);
-               spl_rwsem_unlock_irqrestore(&rwsem->wait_lock, flags);
-       }
-
-       return (rc);
-}
-#endif /* RWSEM_IS_LOCKED_TAKES_WAIT_LOCK */
 
 #endif /* _SPL_RWSEM_COMPAT_H */
index f9e883fd41ab31e9a57e981ce078a32a0ef12775..73c4a84217829d204bb0b42d4fb9a21d21a28f1d 100644 (file)
@@ -91,6 +91,7 @@ KERNEL_H = \
        $(top_srcdir)/include/sys/u8_textprep.h \
        $(top_srcdir)/include/sys/uio.h \
        $(top_srcdir)/include/sys/unistd.h \
+       $(top_srcdir)/include/sys/user.h \
        $(top_srcdir)/include/sys/va_list.h \
        $(top_srcdir)/include/sys/varargs.h \
        $(top_srcdir)/include/sys/vfs.h \
index fa8818e4819f9af691f6a07a8fb17cef3e67e991..8b185ed20410d745c99c34653798d2d1cfe6cfaa 100644 (file)
@@ -155,6 +155,7 @@ am__kernel_HEADERS_DIST = $(top_srcdir)/include/sys/acl.h \
        $(top_srcdir)/include/sys/u8_textprep.h \
        $(top_srcdir)/include/sys/uio.h \
        $(top_srcdir)/include/sys/unistd.h \
+       $(top_srcdir)/include/sys/user.h \
        $(top_srcdir)/include/sys/va_list.h \
        $(top_srcdir)/include/sys/varargs.h \
        $(top_srcdir)/include/sys/vfs.h \
@@ -485,6 +486,7 @@ KERNEL_H = \
        $(top_srcdir)/include/sys/u8_textprep.h \
        $(top_srcdir)/include/sys/uio.h \
        $(top_srcdir)/include/sys/unistd.h \
+       $(top_srcdir)/include/sys/user.h \
        $(top_srcdir)/include/sys/va_list.h \
        $(top_srcdir)/include/sys/varargs.h \
        $(top_srcdir)/include/sys/vfs.h \
index c9f2bea12ceeb2bc92e0a5c3c0b692fdbe23c218..efcf0dda2769b2c903636932bc0ca0f9b4da0c7d 100644 (file)
@@ -1,4 +1,4 @@
-/*****************************************************************************\
+/*
  *  Copyright (C) 2007-2010 Lawrence Livermore National Security, LLC.
  *  Copyright (C) 2007 The Regents of the University of California.
  *  Produced at Lawrence Livermore National Laboratory (cf, DISCLAIMER).
  *
  *  You should have received a copy of the GNU General Public License along
  *  with the SPL.  If not, see <http://www.gnu.org/licenses/>.
-\*****************************************************************************/
+ */
 
 #ifndef _SPL_CONDVAR_H
-#define _SPL_CONDVAR_H
+#define        _SPL_CONDVAR_H
 
 #include <linux/module.h>
 #include <linux/wait.h>
@@ -36,8 +36,8 @@
  * The kcondvar_t struct is protected by mutex taken externally before
  * calling any of the wait/signal funs, and passed into the wait funs.
  */
-#define CV_MAGIC                       0x346545f4
-#define CV_DESTROY                     0x346545f5
+#define        CV_MAGIC                        0x346545f4
+#define        CV_DESTROY                      0x346545f5
 
 typedef struct {
        int cv_magic;
@@ -48,30 +48,30 @@ typedef struct {
        kmutex_t *cv_mutex;
 } kcondvar_t;
 
-typedef enum { CV_DEFAULT=0, CV_DRIVER } kcv_type_t;
+typedef enum { CV_DEFAULT = 0, CV_DRIVER } kcv_type_t;
 
-extern void __cv_init(kcondvar_t *cvp, char *name, kcv_type_t type, void *arg);
-extern void __cv_destroy(kcondvar_t *cvp);
-extern void __cv_wait(kcondvar_t *cvp, kmutex_t *mp);
-extern void __cv_wait_io(kcondvar_t *cvp, kmutex_t *mp);
-extern void __cv_wait_interruptible(kcondvar_t *cvp, kmutex_t *mp);
-extern clock_t __cv_timedwait(kcondvar_t *cvp, kmutex_t *mp, clock_t exp_time);
-extern clock_t __cv_timedwait_interruptible(kcondvar_t *cvp, kmutex_t *mp,
-       clock_t exp_time);
-extern clock_t cv_timedwait_hires(kcondvar_t *cvp, kmutex_t *mp,
-       hrtime_t tim, hrtime_t res, int flag);
-extern void __cv_signal(kcondvar_t *cvp);
-extern void __cv_broadcast(kcondvar_t *cvp);
+extern void __cv_init(kcondvar_t *, char *, kcv_type_t, void *);
+extern void __cv_destroy(kcondvar_t *);
+extern void __cv_wait(kcondvar_t *, kmutex_t *);
+extern void __cv_wait_io(kcondvar_t *, kmutex_t *);
+extern void __cv_wait_sig(kcondvar_t *, kmutex_t *);
+extern clock_t __cv_timedwait(kcondvar_t *, kmutex_t *, clock_t);
+extern clock_t __cv_timedwait_sig(kcondvar_t *, kmutex_t *, clock_t);
+extern clock_t cv_timedwait_hires(kcondvar_t *, kmutex_t *, hrtime_t,
+    hrtime_t res, int flag);
+extern void __cv_signal(kcondvar_t *);
+extern void __cv_broadcast(kcondvar_t *c);
 
-#define cv_init(cvp, name, type, arg)          __cv_init(cvp, name, type, arg)
-#define cv_destroy(cvp)                                __cv_destroy(cvp)
-#define cv_wait(cvp, mp)                       __cv_wait(cvp, mp)
-#define cv_wait_io(cvp, mp)                    __cv_wait_io(cvp, mp)
-#define cv_wait_interruptible(cvp, mp)         __cv_wait_interruptible(cvp,mp)
-#define cv_timedwait(cvp, mp, t)               __cv_timedwait(cvp, mp, t)
-#define cv_timedwait_interruptible(cvp, mp, t)                                \
-       __cv_timedwait_interruptible(cvp, mp, t)
-#define cv_signal(cvp)                         __cv_signal(cvp)
-#define cv_broadcast(cvp)                      __cv_broadcast(cvp)
+#define        cv_init(cvp, name, type, arg)           __cv_init(cvp, name, type, arg)
+#define        cv_destroy(cvp)                         __cv_destroy(cvp)
+#define        cv_wait(cvp, mp)                        __cv_wait(cvp, mp)
+#define        cv_wait_io(cvp, mp)                     __cv_wait_io(cvp, mp)
+#define        cv_wait_sig(cvp, mp)                    __cv_wait_sig(cvp, mp)
+#define        cv_wait_interruptible(cvp, mp)          cv_wait_sig(cvp, mp)
+#define        cv_timedwait(cvp, mp, t)                __cv_timedwait(cvp, mp, t)
+#define        cv_timedwait_sig(cvp, mp, t)            __cv_timedwait_sig(cvp, mp, t)
+#define        cv_timedwait_interruptible(cvp, mp, t)  cv_timedwait_sig(cvp, mp, t)
+#define        cv_signal(cvp)                          __cv_signal(cvp)
+#define        cv_broadcast(cvp)                       __cv_broadcast(cvp)
 
 #endif /* _SPL_CONDVAR_H */
index cae2d49e44c41b52a007b410cb1494e50c7809f3..a37740036446a26776e08f679c60cb5f945e36db 100644 (file)
@@ -92,6 +92,8 @@ void spl_dumpstack(void);
 #define        ASSERT3U(x,y,z)         ((void)0)
 #define        ASSERT3P(x,y,z)         ((void)0)
 #define        ASSERT0(x)              ((void)0)
+#define        IMPLY(A, B)             ((void)0)
+#define        EQUIV(A, B)             ((void)0)
 
 /*
  * Debugging enabled (--enable-debug)
@@ -105,6 +107,14 @@ void spl_dumpstack(void);
 #define        ASSERT3U(x,y,z)         VERIFY3U(x, y, z)
 #define        ASSERT3P(x,y,z)         VERIFY3P(x, y, z)
 #define        ASSERT0(x)              VERIFY0(x)
+#define        IMPLY(A, B) \
+       ((void)(((!(A)) || (B)) || \
+           spl_panic(__FILE__, __FUNCTION__, __LINE__, \
+           "(" #A ") implies (" #B ")")))
+#define        EQUIV(A, B) \
+       ((void)((!!(A) == !!(B)) || \
+           spl_panic(__FILE__, __FUNCTION__, __LINE__, \
+           "(" #A ") is equivalent to (" #B ")")))
 
 #endif /* NDEBUG */
 
index 9dfbfe5451a50d07db46200bd8b05478f79e2afb..7064e8f1f2018a162ceae6097bf7b80a49948fdd 100644 (file)
@@ -83,15 +83,13 @@ rw_owner(krwlock_t *rwp)
 static inline int
 RW_READ_HELD(krwlock_t *rwp)
 {
-       return (spl_rwsem_is_locked(SEM(rwp)) &&
-               rw_owner(rwp) == NULL);
+       return (spl_rwsem_is_locked(SEM(rwp)) && rw_owner(rwp) == NULL);
 }
 
 static inline int
 RW_WRITE_HELD(krwlock_t *rwp)
 {
-       return (spl_rwsem_is_locked(SEM(rwp)) &&
-               rw_owner(rwp) == current);
+       return (spl_rwsem_is_locked(SEM(rwp)) && rw_owner(rwp) == current);
 }
 
 static inline int
index c56d7e12a6203051abf79213ac88e49d14f55cac..4dc7cd8585619a77d4405ab15724bb30769e3ce6 100644 (file)
@@ -78,6 +78,7 @@
 #define proc_pageout                   NULL
 #define curproc                                current
 #define max_ncpus                      num_possible_cpus()
+#define boot_ncpus                     num_online_cpus()
 #define CPU_SEQID                      smp_processor_id()
 #define _NOTE(x)
 #define is_system_labeled()            0
@@ -92,8 +93,9 @@
  *
  * Treat shim tasks as SCHED_NORMAL tasks
  */
-#define minclsyspri                    (MAX_RT_PRIO)
-#define maxclsyspri                    (MAX_PRIO-1)
+#define minclsyspri                    (MAX_PRIO-1)
+#define maxclsyspri                    (MAX_RT_PRIO)
+#define defclsyspri                    (DEFAULT_PRIO)
 
 #ifndef NICE_TO_PRIO
 #define NICE_TO_PRIO(nice)             (MAX_RT_PRIO + (nice) + 20)
index 7b44e8b8ae42a675514bfc71a7c6879940f14d01..a43a86da651470d42ffc7858164a620e7d516146 100644 (file)
@@ -40,6 +40,7 @@
 #define TASKQ_DYNAMIC          0x00000004
 #define TASKQ_THREADS_CPU_PCT  0x00000008
 #define TASKQ_DC_BATCH         0x00000010
+#define TASKQ_ACTIVE           0x80000000
 
 /*
  * Flags for taskq_dispatch. TQ_SLEEP/TQ_NOSLEEP should be same as
@@ -53,7 +54,6 @@
 #define TQ_NOALLOC             0x02000000
 #define TQ_NEW                 0x04000000
 #define TQ_FRONT               0x08000000
-#define TQ_ACTIVE              0x80000000
 
 typedef unsigned long taskqid_t;
 typedef void (task_func_t)(void *);
@@ -61,11 +61,13 @@ typedef void (task_func_t)(void *);
 typedef struct taskq {
        spinlock_t              tq_lock;       /* protects taskq_t */
        unsigned long           tq_lock_flags; /* interrupt state */
-       const char              *tq_name;      /* taskq name */
+       char                    *tq_name;      /* taskq name */
        struct list_head        tq_thread_list;/* list of all threads */
        struct list_head        tq_active_list;/* list of active threads */
        int                     tq_nactive;    /* # of active threads */
-       int                     tq_nthreads;   /* # of total threads */
+       int                     tq_nthreads;   /* # of existing threads */
+       int                     tq_nspawn;     /* # of threads being spawned */
+       int                     tq_maxthreads; /* # of threads maximum */
        int                     tq_pri;        /* priority */
        int                     tq_minalloc;   /* min task_t pool size */
        int                     tq_maxalloc;   /* max task_t pool size */
@@ -119,7 +121,7 @@ extern void taskq_init_ent(taskq_ent_t *);
 extern taskq_t *taskq_create(const char *, int, pri_t, int, int, uint_t);
 extern void taskq_destroy(taskq_t *);
 extern void taskq_wait_id(taskq_t *, taskqid_t);
-extern void taskq_wait_all(taskq_t *, taskqid_t);
+extern void taskq_wait_outstanding(taskq_t *, taskqid_t);
 extern void taskq_wait(taskq_t *);
 extern int taskq_cancel_id(taskq_t *, taskqid_t);
 extern int taskq_member(taskq_t *, void *);
index 25c5f4a01807bc72406d004305a9e8c7bb094066..404c03774aea46698653dc2b5d1783b91a67238d 100644 (file)
@@ -1,6 +1,7 @@
 /*****************************************************************************\
  *  Copyright (C) 2007-2010 Lawrence Livermore National Security, LLC.
  *  Copyright (C) 2007 The Regents of the University of California.
+ *  Copyright (c) 2015 by Chunwei Chen. All rights reserved.
  *  Produced at Lawrence Livermore National Laboratory (cf, DISCLAIMER).
  *  Written by Brian Behlendorf <behlendorf1@llnl.gov>.
  *  UCRL-CODE-235197
@@ -26,6 +27,7 @@
 #define _SPL_UIO_H
 
 #include <linux/uio.h>
+#include <linux/blkdev.h>
 #include <asm/uaccess.h>
 #include <sys/types.h>
 
@@ -40,10 +42,14 @@ typedef enum uio_seg {
        UIO_USERSPACE = 0,
        UIO_SYSSPACE =  1,
        UIO_USERISPACE= 2,
+       UIO_BVEC =      3,
 } uio_seg_t;
 
 typedef struct uio {
-       struct iovec    *uio_iov;
+       union {
+               const struct iovec      *uio_iov;
+               const struct bio_vec    *uio_bvec;
+       };
        int             uio_iovcnt;
        offset_t        uio_loffset;
        uio_seg_t       uio_segflg;
@@ -51,6 +57,7 @@ typedef struct uio {
        uint16_t        uio_extflg;
        offset_t        uio_limit;
        ssize_t         uio_resid;
+       size_t          uio_skip;
 } uio_t;
 
 typedef struct aio_req {
diff --git a/include/sys/user.h b/include/sys/user.h
new file mode 100644 (file)
index 0000000..ebbe8f6
--- /dev/null
@@ -0,0 +1,42 @@
+/*****************************************************************************\
+ *  Copyright (C) 2015 Cluster Inc.
+ *  Produced at ClusterHQ Inc (cf, DISCLAIMER).
+ *  Written by Richard Yao <richard.yao@clusterhq.com>.
+ *
+ *  This file is part of the SPL, Solaris Porting Layer.
+ *  For details, see <http://zfsonlinux.org/>.
+ *
+ *  The SPL is free software; you can redistribute it and/or modify it
+ *  under the terms of the GNU General Public License as published by the
+ *  Free Software Foundation; either version 2 of the License, or (at your
+ *  option) any later version.
+ *
+ *  The SPL is distributed in the hope that it will be useful, but WITHOUT
+ *  ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ *  FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ *  for more details.
+ *
+ *  You should have received a copy of the GNU General Public License along
+ *  with the SPL.  If not, see <http://www.gnu.org/licenses/>.
+\*****************************************************************************/
+
+#ifndef _SPL_USER_H
+#define _SPL_USER_H
+
+/*
+ * We have uf_info_t for areleasef(). We implement areleasef() using a global
+ * linked list of all open file descriptors with the task structs referenced,
+ * so accessing the correct descriptor from areleasef() only requires knowing
+ * about the Linux task_struct. Since this is internal to our compatibility
+ * layer, we make it an opaque type.
+ *
+ * XXX: If the descriptor changes under us, we would get an incorrect
+ * reference.
+ */
+
+struct uf_info;
+typedef struct uf_info uf_info_t;
+
+#define P_FINFO(x) ((uf_info_t *)x)
+
+#endif /* SPL_USER_H */
index 8aadc9d03b300e8f611261ab8f798b8c276af986..eb482805206190de4fb2c041c92720c82e10479e 100644 (file)
@@ -98,6 +98,7 @@ extern void *spl_vmalloc(unsigned long size, gfp_t lflags, pgprot_t prot);
 #define        vmem_alloc(sz, fl)      spl_vmem_alloc((sz), (fl), __func__, __LINE__)
 #define        vmem_zalloc(sz, fl)     spl_vmem_zalloc((sz), (fl), __func__, __LINE__)
 #define        vmem_free(ptr, sz)      spl_vmem_free((ptr), (sz))
+#define        vmem_qcache_reap(ptr)   ((void)0)
 
 extern void *spl_vmem_alloc(size_t sz, int fl, const char *func, int line);
 extern void *spl_vmem_zalloc(size_t sz, int fl, const char *func, int line);
index 2fa169523ddfd0efa6a2768301bd707108681240..9d334fe0a16e7bcf04bbdb61be80eaedf596f651 100644 (file)
 
 #define        membar_producer()               smp_wmb()
 #define        physmem                         totalram_pages
-#define        freemem                         nr_free_pages()
+#define        freemem                 (nr_free_pages() + \
+                               global_page_state(NR_INACTIVE_FILE) + \
+                               global_page_state(NR_INACTIVE_ANON) + \
+                               global_page_state(NR_SLAB_RECLAIMABLE))
 
 #define        xcopyin(from, to, size)         copy_from_user(to, from, size)
 #define        xcopyout(from, to, size)        copy_to_user(to, from, size)
index 07a34493837b4356f5f847b7606c2753a0e06e8e..0b857d384ba572a540263e59b830c4d8d96fa754 100644 (file)
@@ -40,6 +40,7 @@
 #include <sys/types.h>
 #include <sys/time.h>
 #include <sys/uio.h>
+#include <sys/user.h>
 #include <sys/sunldi.h>
 
 /*
@@ -184,6 +185,7 @@ extern int vn_space(vnode_t *vp, int cmd, struct flock *bfp, int flag,
     offset_t offset, void *x6, void *x7);
 extern file_t *vn_getf(int fd);
 extern void vn_releasef(int fd);
+extern void vn_areleasef(int fd, uf_info_t *fip);
 extern int vn_set_pwd(const char *filename);
 
 int spl_vn_init(void);
@@ -198,6 +200,7 @@ void spl_vn_fini(void);
 #define vn_is_readonly(vp)                     0
 #define getf                                   vn_getf
 #define releasef                               vn_releasef
+#define areleasef                              vn_areleasef
 
 extern vnode_t *rootdir;
 
index b721b5099cf7eb86b777a108ae3bfb8050491787..e2bf09fb10d356c98d6b29eab6509c4a5538990b 100644 (file)
@@ -2,7 +2,7 @@ COMMON_H =
 
 KERNEL_H = \
        $(top_srcdir)/include/util/qsort.h \
-        $(top_srcdir)/include/util/sscanf.h
+       $(top_srcdir)/include/util/sscanf.h
 
 USER_H =
 
index c442f296752f4fd6f0fb89ad4fc8b4545ee9e13f..1d4d7f718c813da053a0dcf47b783034601defd8 100644 (file)
@@ -264,7 +264,7 @@ top_srcdir = @top_srcdir@
 COMMON_H = 
 KERNEL_H = \
        $(top_srcdir)/include/util/qsort.h \
-        $(top_srcdir)/include/util/sscanf.h
+       $(top_srcdir)/include/util/sscanf.h
 
 USER_H = 
 EXTRA_DIST = $(COMMON_H) $(KERNEL_H) $(USER_H)
index 3e7e877fbbbc86becc7221499702cb658b6911c0..acdd5b658ff84486bcdb3a63bb83f126d7f342ad 100644 (file)
@@ -249,3 +249,52 @@ where a thread should run.
 .sp
 Default value: \fB0\fR
 .RE
+
+.sp
+.ne 2
+.na
+\fBspl_taskq_thread_dynamic\fR (int)
+.ad
+.RS 12n
+Allow dynamic taskqs.  When enabled taskqs which set the TASKQ_DYNAMIC flag
+will by default create only a single thread.  New threads will be created on
+demand up to a maximum allowed number to facilitate the completion of
+outstanding tasks.  Threads which are no longer needed will be promptly
+destroyed.  By default this behavior is enabled but it can be disabled to
+aid performance analysis or troubleshooting.
+.sp
+Default value: \fB1\fR
+.RE
+
+.sp
+.ne 2
+.na
+\fBspl_taskq_thread_priority\fR (int)
+.ad
+.RS 12n
+Allow newly created taskq threads to set a non-default scheduler priority.
+When enabled the priority specified when a taskq is created will be applied
+to all threads created by that taskq.  When disabled all threads will use
+the default Linux kernel thread priority.  By default, this behavior is
+enabled.
+.sp
+Default value: \fB1\fR
+.RE
+
+.sp
+.ne 2
+.na
+\fBspl_taskq_thread_sequential\fR (int)
+.ad
+.RS 12n
+The number of items a taskq worker thread must handle without interruption
+before requesting a new worker thread be spawned.  This is used to control
+how quickly taskqs ramp up the number of threads processing the queue.
+Because Linux thread creation and destruction are relatively inexpensive a
+small default value has been selected.  This means that normally threads will
+be created aggressively which is desirable.  Increasing this value will
+result in a slower thread creation rate which may be preferable for some
+configurations.
+.sp
+Default value: \fB4\fR
+.RE
index d1742448deb82e2ad9a92ccf1204b422969eea49..a1f1ab82385c94f3a4087bf3f478b8862e73c7a8 100644 (file)
@@ -1,27 +1,30 @@
 # Makefile.in for spl kernel module
 
+src = @abs_top_srcdir@/module/spl
+obj = @abs_builddir@
+
 MODULE := spl
 EXTRA_CFLAGS = $(SPL_MODULE_CFLAGS) @KERNELCPPFLAGS@
 
 # Solaris porting layer module
 obj-$(CONFIG_SPL) := $(MODULE).o
 
-$(MODULE)-objs += @top_srcdir@/module/spl/spl-proc.o
-$(MODULE)-objs += @top_srcdir@/module/spl/spl-kmem.o
-$(MODULE)-objs += @top_srcdir@/module/spl/spl-kmem-cache.o
-$(MODULE)-objs += @top_srcdir@/module/spl/spl-vmem.o
-$(MODULE)-objs += @top_srcdir@/module/spl/spl-thread.o
-$(MODULE)-objs += @top_srcdir@/module/spl/spl-taskq.o
-$(MODULE)-objs += @top_srcdir@/module/spl/spl-rwlock.o
-$(MODULE)-objs += @top_srcdir@/module/spl/spl-vnode.o
-$(MODULE)-objs += @top_srcdir@/module/spl/spl-err.o
-$(MODULE)-objs += @top_srcdir@/module/spl/spl-kobj.o
-$(MODULE)-objs += @top_srcdir@/module/spl/spl-generic.o
-$(MODULE)-objs += @top_srcdir@/module/spl/spl-atomic.o
-$(MODULE)-objs += @top_srcdir@/module/spl/spl-mutex.o
-$(MODULE)-objs += @top_srcdir@/module/spl/spl-kstat.o
-$(MODULE)-objs += @top_srcdir@/module/spl/spl-condvar.o
-$(MODULE)-objs += @top_srcdir@/module/spl/spl-xdr.o
-$(MODULE)-objs += @top_srcdir@/module/spl/spl-cred.o
-$(MODULE)-objs += @top_srcdir@/module/spl/spl-tsd.o
-$(MODULE)-objs += @top_srcdir@/module/spl/spl-zlib.o
+$(MODULE)-objs += spl-proc.o
+$(MODULE)-objs += spl-kmem.o
+$(MODULE)-objs += spl-kmem-cache.o
+$(MODULE)-objs += spl-vmem.o
+$(MODULE)-objs += spl-thread.o
+$(MODULE)-objs += spl-taskq.o
+$(MODULE)-objs += spl-rwlock.o
+$(MODULE)-objs += spl-vnode.o
+$(MODULE)-objs += spl-err.o
+$(MODULE)-objs += spl-kobj.o
+$(MODULE)-objs += spl-generic.o
+$(MODULE)-objs += spl-atomic.o
+$(MODULE)-objs += spl-mutex.o
+$(MODULE)-objs += spl-kstat.o
+$(MODULE)-objs += spl-condvar.o
+$(MODULE)-objs += spl-xdr.o
+$(MODULE)-objs += spl-cred.o
+$(MODULE)-objs += spl-tsd.o
+$(MODULE)-objs += spl-zlib.o
index cebb8f2b10e88eca23179ad495b6cae4a23bfd93..c3467a56e6ae2ceff81f8b10aff9f41e61c50656 100644 (file)
@@ -1,4 +1,4 @@
-/*****************************************************************************\
+/*
  *  Copyright (C) 2007-2010 Lawrence Livermore National Security, LLC.
  *  Copyright (C) 2007 The Regents of the University of California.
  *  Produced at Lawrence Livermore National Laboratory (cf, DISCLAIMER).
@@ -20,9 +20,9 @@
  *
  *  You should have received a copy of the GNU General Public License along
  *  with the SPL.  If not, see <http://www.gnu.org/licenses/>.
- *****************************************************************************
+ *
  *  Solaris Porting Layer (SPL) Credential Implementation.
-\*****************************************************************************/
+ */
 
 #include <sys/condvar.h>
 #include <sys/time.h>
@@ -50,10 +50,10 @@ cv_destroy_wakeup(kcondvar_t *cvp)
        if (!atomic_read(&cvp->cv_waiters) && !atomic_read(&cvp->cv_refs)) {
                ASSERT(cvp->cv_mutex == NULL);
                ASSERT(!waitqueue_active(&cvp->cv_event));
-               return 1;
+               return (1);
        }
 
-       return 0;
+       return (0);
 }
 
 void
@@ -82,7 +82,7 @@ cv_wait_common(kcondvar_t *cvp, kmutex_t *mp, int state, int io)
        DEFINE_WAIT(wait);
 
        ASSERT(cvp);
-        ASSERT(mp);
+       ASSERT(mp);
        ASSERT(cvp->cv_magic == CV_MAGIC);
        ASSERT(mutex_owned(mp));
        atomic_inc(&cvp->cv_refs);
@@ -96,9 +96,11 @@ cv_wait_common(kcondvar_t *cvp, kmutex_t *mp, int state, int io)
        prepare_to_wait_exclusive(&cvp->cv_event, &wait, state);
        atomic_inc(&cvp->cv_waiters);
 
-       /* Mutex should be dropped after prepare_to_wait() this
+       /*
+        * Mutex should be dropped after prepare_to_wait() this
         * ensures we're linked in to the waiters list and avoids the
-        * race where 'cvp->cv_waiters > 0' but the list is empty. */
+        * race where 'cvp->cv_waiters > 0' but the list is empty.
+        */
        mutex_exit(mp);
        if (io)
                io_schedule();
@@ -124,11 +126,11 @@ __cv_wait(kcondvar_t *cvp, kmutex_t *mp)
 EXPORT_SYMBOL(__cv_wait);
 
 void
-__cv_wait_interruptible(kcondvar_t *cvp, kmutex_t *mp)
+__cv_wait_sig(kcondvar_t *cvp, kmutex_t *mp)
 {
        cv_wait_common(cvp, mp, TASK_INTERRUPTIBLE, 0);
 }
-EXPORT_SYMBOL(__cv_wait_interruptible);
+EXPORT_SYMBOL(__cv_wait_sig);
 
 void
 __cv_wait_io(kcondvar_t *cvp, kmutex_t *mp)
@@ -137,18 +139,19 @@ __cv_wait_io(kcondvar_t *cvp, kmutex_t *mp)
 }
 EXPORT_SYMBOL(__cv_wait_io);
 
-/* 'expire_time' argument is an absolute wall clock time in jiffies.
+/*
+ * 'expire_time' argument is an absolute wall clock time in jiffies.
  * Return value is time left (expire_time - now) or -1 if timeout occurred.
  */
 static clock_t
-__cv_timedwait_common(kcondvar_t *cvp, kmutex_t *mp,
-                     clock_t expire_time, int state)
+__cv_timedwait_common(kcondvar_t *cvp, kmutex_t *mp, clock_t expire_time,
+    int state)
 {
        DEFINE_WAIT(wait);
        clock_t time_left;
 
        ASSERT(cvp);
-        ASSERT(mp);
+       ASSERT(mp);
        ASSERT(cvp->cv_magic == CV_MAGIC);
        ASSERT(mutex_owned(mp));
        atomic_inc(&cvp->cv_refs);
@@ -169,9 +172,11 @@ __cv_timedwait_common(kcondvar_t *cvp, kmutex_t *mp,
        prepare_to_wait_exclusive(&cvp->cv_event, &wait, state);
        atomic_inc(&cvp->cv_waiters);
 
-       /* Mutex should be dropped after prepare_to_wait() this
+       /*
+        * Mutex should be dropped after prepare_to_wait() this
         * ensures we're linked in to the waiters list and avoids the
-        * race where 'cvp->cv_waiters > 0' but the list is empty. */
+        * race where 'cvp->cv_waiters > 0' but the list is empty.
+        */
        mutex_exit(mp);
        time_left = schedule_timeout(time_left);
        mutex_enter(mp);
@@ -191,24 +196,24 @@ __cv_timedwait_common(kcondvar_t *cvp, kmutex_t *mp,
 clock_t
 __cv_timedwait(kcondvar_t *cvp, kmutex_t *mp, clock_t exp_time)
 {
-       return __cv_timedwait_common(cvp, mp, exp_time, TASK_UNINTERRUPTIBLE);
+       return (__cv_timedwait_common(cvp, mp, exp_time, TASK_UNINTERRUPTIBLE));
 }
 EXPORT_SYMBOL(__cv_timedwait);
 
 clock_t
-__cv_timedwait_interruptible(kcondvar_t *cvp, kmutex_t *mp, clock_t exp_time)
+__cv_timedwait_sig(kcondvar_t *cvp, kmutex_t *mp, clock_t exp_time)
 {
-       return __cv_timedwait_common(cvp, mp, exp_time, TASK_INTERRUPTIBLE);
+       return (__cv_timedwait_common(cvp, mp, exp_time, TASK_INTERRUPTIBLE));
 }
-EXPORT_SYMBOL(__cv_timedwait_interruptible);
+EXPORT_SYMBOL(__cv_timedwait_sig);
 
 /*
- *'expire_time' argument is an absolute clock time in nanoseconds.
+ * 'expire_time' argument is an absolute clock time in nanoseconds.
  * Return value is time left (expire_time - now) or -1 if timeout occurred.
  */
 static clock_t
-__cv_timedwait_hires(kcondvar_t *cvp, kmutex_t *mp,
-                    hrtime_t expire_time, int state)
+__cv_timedwait_hires(kcondvar_t *cvp, kmutex_t *mp, hrtime_t expire_time,
+    int state)
 {
        DEFINE_WAIT(wait);
        hrtime_t time_left, now;
@@ -237,12 +242,16 @@ __cv_timedwait_hires(kcondvar_t *cvp, kmutex_t *mp,
        prepare_to_wait_exclusive(&cvp->cv_event, &wait, state);
        atomic_inc(&cvp->cv_waiters);
 
-       /* Mutex should be dropped after prepare_to_wait() this
+       /*
+        * Mutex should be dropped after prepare_to_wait() this
         * ensures we're linked in to the waiters list and avoids the
-        * race where 'cvp->cv_waiters > 0' but the list is empty. */
+        * race where 'cvp->cv_waiters > 0' but the list is empty.
+        */
        mutex_exit(mp);
-       /* Allow a 100 us range to give kernel an opportunity to coalesce
-        * interrupts */
+       /*
+        * Allow a 100 us range to give kernel an opportunity to coalesce
+        * interrupts
+        */
        usleep_range(time_left_us, time_left_us + 100);
        mutex_enter(mp);
 
@@ -263,8 +272,8 @@ __cv_timedwait_hires(kcondvar_t *cvp, kmutex_t *mp,
  * Compatibility wrapper for the cv_timedwait_hires() Illumos interface.
  */
 clock_t
-cv_timedwait_hires(kcondvar_t *cvp, kmutex_t *mp, hrtime_t tim,
-                  hrtime_t res, int flag)
+cv_timedwait_hires(kcondvar_t *cvp, kmutex_t *mp, hrtime_t tim, hrtime_t res,
+    int flag)
 {
        if (res > 1) {
                /*
@@ -278,7 +287,7 @@ cv_timedwait_hires(kcondvar_t *cvp, kmutex_t *mp, hrtime_t tim,
        if (!(flag & CALLOUT_FLAG_ABSOLUTE))
                tim += gethrtime();
 
-       return __cv_timedwait_hires(cvp, mp, tim, TASK_UNINTERRUPTIBLE);
+       return (__cv_timedwait_hires(cvp, mp, tim, TASK_UNINTERRUPTIBLE));
 }
 EXPORT_SYMBOL(cv_timedwait_hires);
 
@@ -289,10 +298,12 @@ __cv_signal(kcondvar_t *cvp)
        ASSERT(cvp->cv_magic == CV_MAGIC);
        atomic_inc(&cvp->cv_refs);
 
-       /* All waiters are added with WQ_FLAG_EXCLUSIVE so only one
+       /*
+        * All waiters are added with WQ_FLAG_EXCLUSIVE so only one
         * waiter will be set runable with each call to wake_up().
         * Additionally wake_up() holds a spin_lock assoicated with
-        * the wait queue to ensure we don't race waking up processes. */
+        * the wait queue to ensure we don't race waking up processes.
+        */
        if (atomic_read(&cvp->cv_waiters) > 0)
                wake_up(&cvp->cv_event);
 
@@ -307,8 +318,10 @@ __cv_broadcast(kcondvar_t *cvp)
        ASSERT(cvp->cv_magic == CV_MAGIC);
        atomic_inc(&cvp->cv_refs);
 
-       /* Wake_up_all() will wake up all waiters even those which
-        * have the WQ_FLAG_EXCLUSIVE flag set. */
+       /*
+        * Wake_up_all() will wake up all waiters even those which
+        * have the WQ_FLAG_EXCLUSIVE flag set.
+        */
        if (atomic_read(&cvp->cv_waiters) > 0)
                wake_up_all(&cvp->cv_event);
 
index cd3e543ba08ebed0e3d75c13f38d9d558b9fe8f3..a7f9ca3a5d9931f171a440783dde9c441c4c1d20 100644 (file)
@@ -986,13 +986,23 @@ spl_kmem_cache_create(char *name, size_t size, size_t align,
                if (rc)
                        goto out;
        } else {
+               unsigned long slabflags = 0;
+
                if (size > (SPL_MAX_KMEM_ORDER_NR_PAGES * PAGE_SIZE)) {
                        rc = EINVAL;
                        goto out;
                }
 
+#if defined(SLAB_USERCOPY)
+               /*
+                * Required for PAX-enabled kernels if the slab is to be
+                * used for coping between user and kernel space.
+                */
+               slabflags |= SLAB_USERCOPY;
+#endif
+
                skc->skc_linux_cache = kmem_cache_create(
-                   skc->skc_name, size, align, 0, NULL);
+                   skc->skc_name, size, align, slabflags, NULL);
                if (skc->skc_linux_cache == NULL) {
                        rc = ENOMEM;
                        goto out;
@@ -1403,8 +1413,6 @@ spl_kmem_cache_alloc(spl_kmem_cache_t *skc, int flags)
        ASSERT(skc->skc_magic == SKC_MAGIC);
        ASSERT(!test_bit(KMC_BIT_DESTROY, &skc->skc_flags));
 
-       atomic_inc(&skc->skc_ref);
-
        /*
         * Allocate directly from a Linux slab.  All optimizations are left
         * to the underlying cache we only need to guarantee that KM_SLEEP
@@ -1457,8 +1465,6 @@ ret:
                        prefetchw(obj);
        }
 
-       atomic_dec(&skc->skc_ref);
-
        return (obj);
 }
 EXPORT_SYMBOL(spl_kmem_cache_alloc);
@@ -1479,7 +1485,6 @@ spl_kmem_cache_free(spl_kmem_cache_t *skc, void *obj)
 
        ASSERT(skc->skc_magic == SKC_MAGIC);
        ASSERT(!test_bit(KMC_BIT_DESTROY, &skc->skc_flags));
-       atomic_inc(&skc->skc_ref);
 
        /*
         * Run the destructor
@@ -1492,7 +1497,7 @@ spl_kmem_cache_free(spl_kmem_cache_t *skc, void *obj)
         */
        if (skc->skc_flags & KMC_SLAB) {
                kmem_cache_free(skc->skc_linux_cache, obj);
-               goto out;
+               return;
        }
 
        /*
@@ -1507,7 +1512,7 @@ spl_kmem_cache_free(spl_kmem_cache_t *skc, void *obj)
                spin_unlock(&skc->skc_lock);
 
                if (do_emergency && (spl_emergency_free(skc, obj) == 0))
-                       goto out;
+                       return;
        }
 
        local_irq_save(flags);
@@ -1538,8 +1543,6 @@ spl_kmem_cache_free(spl_kmem_cache_t *skc, void *obj)
 
        if (do_reclaim)
                spl_slab_reclaim(skc);
-out:
-       atomic_dec(&skc->skc_ref);
 }
 EXPORT_SYMBOL(spl_kmem_cache_free);
 
@@ -1725,7 +1728,9 @@ spl_kmem_cache_init(void)
        init_rwsem(&spl_kmem_cache_sem);
        INIT_LIST_HEAD(&spl_kmem_cache_list);
        spl_kmem_cache_taskq = taskq_create("spl_kmem_cache",
-           spl_kmem_cache_kmem_threads, maxclsyspri, 1, 32, TASKQ_PREPOPULATE);
+           spl_kmem_cache_kmem_threads, maxclsyspri,
+           spl_kmem_cache_kmem_threads * 8, INT_MAX,
+           TASKQ_PREPOPULATE | TASKQ_DYNAMIC);
        spl_register_shrinker(&spl_kmem_cache_shrinker);
 
        return (0);
index a434ef54fd34f12c08984629e751c9b56c5eaef6..eb00505d6ee8240205276ac63a843a50d8c4db8e 100644 (file)
@@ -42,17 +42,13 @@ typedef struct ctl_table __no_const spl_ctl_table;
 typedef struct ctl_table spl_ctl_table;
 #endif
 
-#ifdef DEBUG_KMEM
 static unsigned long table_min = 0;
 static unsigned long table_max = ~0;
-#endif
 
 static struct ctl_table_header *spl_header = NULL;
 static struct proc_dir_entry *proc_spl = NULL;
-#ifdef DEBUG_KMEM
 static struct proc_dir_entry *proc_spl_kmem = NULL;
 static struct proc_dir_entry *proc_spl_kmem_slab = NULL;
-#endif /* DEBUG_KMEM */
 struct proc_dir_entry *proc_spl_kstat = NULL;
 
 static int
@@ -135,6 +131,7 @@ proc_domemused(struct ctl_table *table, int write,
 
         return (rc);
 }
+#endif /* DEBUG_KMEM */
 
 static int
 proc_doslab(struct ctl_table *table, int write,
@@ -182,7 +179,6 @@ proc_doslab(struct ctl_table *table, int write,
 
         return (rc);
 }
-#endif /* DEBUG_KMEM */
 
 static int
 proc_dohostid(struct ctl_table *table, int write,
@@ -219,7 +215,6 @@ proc_dohostid(struct ctl_table *table, int write,
         return (rc);
 }
 
-#ifdef DEBUG_KMEM
 static void
 slab_seq_show_headers(struct seq_file *f)
 {
@@ -329,10 +324,9 @@ static struct file_operations proc_slab_operations = {
         .llseek         = seq_lseek,
         .release        = seq_release,
 };
-#endif /* DEBUG_KMEM */
 
-#ifdef DEBUG_KMEM
 static struct ctl_table spl_kmem_table[] = {
+#ifdef DEBUG_KMEM
         {
                 .procname = "kmem_used",
                 .data     = &kmem_alloc_used,
@@ -353,6 +347,7 @@ static struct ctl_table spl_kmem_table[] = {
                 .mode     = 0444,
                 .proc_handler = &proc_doulongvec_minmax,
         },
+#endif /* DEBUG_KMEM */
         {
                 .procname = "slab_kmem_total",
                .data     = (void *)(KMC_KMEM | KMC_TOTAL),
@@ -409,7 +404,6 @@ static struct ctl_table spl_kmem_table[] = {
         },
        {0},
 };
-#endif /* DEBUG_KMEM */
 
 static struct ctl_table spl_kstat_table[] = {
        {0},
@@ -433,13 +427,11 @@ static struct ctl_table spl_table[] = {
                 .mode     = 0644,
                 .proc_handler = &proc_dohostid,
         },
-#ifdef DEBUG_KMEM
        {
                .procname = "kmem",
                .mode     = 0555,
                .child    = spl_kmem_table,
        },
-#endif
        {
                .procname = "kstat",
                .mode     = 0555,
@@ -484,7 +476,6 @@ spl_proc_init(void)
                goto out;
        }
 
-#ifdef DEBUG_KMEM
         proc_spl_kmem = proc_mkdir("kmem", proc_spl);
         if (proc_spl_kmem == NULL) {
                 rc = -EUNATCH;
@@ -498,8 +489,6 @@ spl_proc_init(void)
                goto out;
        }
 
-#endif /* DEBUG_KMEM */
-
         proc_spl_kstat = proc_mkdir("kstat", proc_spl);
         if (proc_spl_kstat == NULL) {
                 rc = -EUNATCH;
@@ -508,10 +497,8 @@ spl_proc_init(void)
 out:
        if (rc) {
                remove_proc_entry("kstat", proc_spl);
-#ifdef DEBUG_KMEM
                remove_proc_entry("slab", proc_spl_kmem);
                remove_proc_entry("kmem", proc_spl);
-#endif
                remove_proc_entry("spl", NULL);
                unregister_sysctl_table(spl_header);
        }
@@ -523,10 +510,8 @@ void
 spl_proc_fini(void)
 {
        remove_proc_entry("kstat", proc_spl);
-#ifdef DEBUG_KMEM
         remove_proc_entry("slab", proc_spl_kmem);
        remove_proc_entry("kmem", proc_spl);
-#endif
        remove_proc_entry("spl", NULL);
 
         ASSERT(spl_header != NULL);
index 951298d9fa7fc74f7bbff0a7742b7174ed77ed2f..f6ef56251c63f38ea8575dcc1ffaad938cc70a8d 100644 (file)
@@ -31,10 +31,29 @@ int spl_taskq_thread_bind = 0;
 module_param(spl_taskq_thread_bind, int, 0644);
 MODULE_PARM_DESC(spl_taskq_thread_bind, "Bind taskq thread to CPU by default");
 
+
+int spl_taskq_thread_dynamic = 1;
+module_param(spl_taskq_thread_dynamic, int, 0644);
+MODULE_PARM_DESC(spl_taskq_thread_dynamic, "Allow dynamic taskq threads");
+
+int spl_taskq_thread_priority = 1;
+module_param(spl_taskq_thread_priority, int, 0644);
+MODULE_PARM_DESC(spl_taskq_thread_priority,
+    "Allow non-default priority for taskq threads");
+
+int spl_taskq_thread_sequential = 4;
+module_param(spl_taskq_thread_sequential, int, 0644);
+MODULE_PARM_DESC(spl_taskq_thread_sequential,
+    "Create new taskq threads after N sequential tasks");
+
 /* Global system-wide dynamic task queue available for all consumers */
 taskq_t *system_taskq;
 EXPORT_SYMBOL(system_taskq);
 
+/* Private dedicated taskq for creating new taskq threads on demand. */
+static taskq_t *dynamic_taskq;
+static taskq_thread_t *taskq_thread_create(taskq_t *);
+
 static int
 task_km_flags(uint_t flags)
 {
@@ -327,6 +346,33 @@ taskq_find(taskq_t *tq, taskqid_t id, int *active)
        return (NULL);
 }
 
+/*
+ * Theory for the taskq_wait_id(), taskq_wait_outstanding(), and
+ * taskq_wait() functions below.
+ *
+ * Taskq waiting is accomplished by tracking the lowest outstanding task
+ * id and the next available task id.  As tasks are dispatched they are
+ * added to the tail of the pending, priority, or delay lists.  As worker
+ * threads become available the tasks are removed from the heads of these
+ * lists and linked to the worker threads.  This ensures the lists are
+ * kept sorted by lowest to highest task id.
+ *
+ * Therefore the lowest outstanding task id can be quickly determined by
+ * checking the head item from all of these lists.  This value is stored
+ * with the taskq as the lowest id.  It only needs to be recalculated when
+ * either the task with the current lowest id completes or is canceled.
+ *
+ * By blocking until the lowest task id exceeds the passed task id the
+ * taskq_wait_outstanding() function can be easily implemented.  Similarly,
+ * by blocking until the lowest task id matches the next task id taskq_wait()
+ * can be implemented.
+ *
+ * Callers should be aware that when there are multiple worked threads it
+ * is possible for larger task ids to complete before smaller ones.  Also
+ * when the taskq contains delay tasks with small task ids callers may
+ * block for a considerable length of time waiting for them to expire and
+ * execute.
+ */
 static int
 taskq_wait_id_check(taskq_t *tq, taskqid_t id)
 {
@@ -351,34 +397,8 @@ taskq_wait_id(taskq_t *tq, taskqid_t id)
 }
 EXPORT_SYMBOL(taskq_wait_id);
 
-/*
- * The taskq_wait() function will block until all previously submitted
- * tasks have been completed.  A previously submitted task is defined as
- * a task with a lower task id than the current task queue id.  Note that
- * all task id's are assigned monotonically at dispatch time.
- *
- * Waiting for all previous tasks to complete is accomplished by tracking
- * the lowest outstanding task id.  As tasks are dispatched they are added
- * added to the tail of the pending, priority, or delay lists.  And as
- * worker threads become available the tasks are removed from the heads
- * of these lists and linked to the worker threads.  This ensures the
- * lists are kept in lowest to highest task id order.
- *
- * Therefore the lowest outstanding task id can be quickly determined by
- * checking the head item from all of these lists.  This value is stored
- * with the task queue as the lowest id.  It only needs to be recalculated
- * when either the task with the current lowest id completes or is canceled.
- *
- * By blocking until the lowest task id exceeds the current task id when
- * the function was called we ensure all previous tasks have completed.
- *
- * NOTE: When there are multiple worked threads it is possible for larger
- * task ids to complete before smaller ones.  Conversely when the task
- * queue contains delay tasks with small task ids, you may block for a
- * considerable length of time waiting for them to expire and execute.
- */
 static int
-taskq_wait_check(taskq_t *tq, taskqid_t id)
+taskq_wait_outstanding_check(taskq_t *tq, taskqid_t id)
 {
        int rc;
 
@@ -389,45 +409,76 @@ taskq_wait_check(taskq_t *tq, taskqid_t id)
        return (rc);
 }
 
+/*
+ * The taskq_wait_outstanding() function will block until all tasks with a
+ * lower taskqid than the passed 'id' have been completed.  Note that all
+ * task id's are assigned monotonically at dispatch time.  Zero may be
+ * passed for the id to indicate all tasks dispatch up to this point,
+ * but not after, should be waited for.
+ */
 void
-taskq_wait_all(taskq_t *tq, taskqid_t id)
+taskq_wait_outstanding(taskq_t *tq, taskqid_t id)
 {
-       wait_event(tq->tq_wait_waitq, taskq_wait_check(tq, id));
+       wait_event(tq->tq_wait_waitq,
+           taskq_wait_outstanding_check(tq, id ? id : tq->tq_next_id - 1));
 }
-EXPORT_SYMBOL(taskq_wait_all);
+EXPORT_SYMBOL(taskq_wait_outstanding);
 
-void
-taskq_wait(taskq_t *tq)
+static int
+taskq_wait_check(taskq_t *tq)
 {
-       taskqid_t id;
-
-       ASSERT(tq);
+       int rc;
 
-       /* Wait for the largest outstanding taskqid */
        spin_lock_irqsave(&tq->tq_lock, tq->tq_lock_flags);
-       id = tq->tq_next_id - 1;
+       rc = (tq->tq_lowest_id == tq->tq_next_id);
        spin_unlock_irqrestore(&tq->tq_lock, tq->tq_lock_flags);
 
-       taskq_wait_all(tq, id);
+       return (rc);
+}
+
+/*
+ * The taskq_wait() function will block until the taskq is empty.
+ * This means that if a taskq re-dispatches work to itself taskq_wait()
+ * callers will block indefinitely.
+ */
+void
+taskq_wait(taskq_t *tq)
+{
+       wait_event(tq->tq_wait_waitq, taskq_wait_check(tq));
 }
 EXPORT_SYMBOL(taskq_wait);
 
-int
-taskq_member(taskq_t *tq, void *t)
+static int
+taskq_member_impl(taskq_t *tq, void *t)
 {
        struct list_head *l;
        taskq_thread_t *tqt;
+       int found = 0;
 
        ASSERT(tq);
        ASSERT(t);
+       ASSERT(spin_is_locked(&tq->tq_lock));
 
        list_for_each(l, &tq->tq_thread_list) {
                tqt = list_entry(l, taskq_thread_t, tqt_thread_list);
-               if (tqt->tqt_thread == (struct task_struct *)t)
-                       return (1);
+               if (tqt->tqt_thread == (struct task_struct *)t) {
+                       found = 1;
+                       break;
+               }
        }
+       return (found);
+}
 
-       return (0);
+int
+taskq_member(taskq_t *tq, void *t)
+{
+       int found;
+
+       spin_lock_irqsave(&tq->tq_lock, tq->tq_lock_flags);
+       found = taskq_member_impl(tq, t);
+       spin_unlock_irqrestore(&tq->tq_lock, tq->tq_lock_flags);
+
+       return (found);
 }
 EXPORT_SYMBOL(taskq_member);
 
@@ -487,6 +538,8 @@ taskq_cancel_id(taskq_t *tq, taskqid_t id)
 }
 EXPORT_SYMBOL(taskq_cancel_id);
 
+static int taskq_thread_spawn(taskq_t *tq, int seq_tasks);
+
 taskqid_t
 taskq_dispatch(taskq_t *tq, task_func_t func, void *arg, uint_t flags)
 {
@@ -499,7 +552,7 @@ taskq_dispatch(taskq_t *tq, task_func_t func, void *arg, uint_t flags)
        spin_lock_irqsave(&tq->tq_lock, tq->tq_lock_flags);
 
        /* Taskq being destroyed and all tasks drained */
-       if (!(tq->tq_flags & TQ_ACTIVE))
+       if (!(tq->tq_flags & TASKQ_ACTIVE))
                goto out;
 
        /* Do not queue the task unless there is idle thread for it */
@@ -533,6 +586,11 @@ taskq_dispatch(taskq_t *tq, task_func_t func, void *arg, uint_t flags)
 
        wake_up(&tq->tq_work_waitq);
 out:
+       /* Spawn additional taskq threads if required. */
+       if (tq->tq_nactive == tq->tq_nthreads &&
+           taskq_member_impl(tq, current))
+               (void) taskq_thread_spawn(tq, spl_taskq_thread_sequential + 1);
+
        spin_unlock_irqrestore(&tq->tq_lock, tq->tq_lock_flags);
        return (rc);
 }
@@ -551,7 +609,7 @@ taskq_dispatch_delay(taskq_t *tq, task_func_t func, void *arg,
        spin_lock_irqsave(&tq->tq_lock, tq->tq_lock_flags);
 
        /* Taskq being destroyed and all tasks drained */
-       if (!(tq->tq_flags & TQ_ACTIVE))
+       if (!(tq->tq_flags & TASKQ_ACTIVE))
                goto out;
 
        if ((t = task_alloc(tq, flags)) == NULL)
@@ -576,6 +634,10 @@ taskq_dispatch_delay(taskq_t *tq, task_func_t func, void *arg,
 
        spin_unlock(&t->tqent_lock);
 out:
+       /* Spawn additional taskq threads if required. */
+       if (tq->tq_nactive == tq->tq_nthreads &&
+           taskq_member_impl(tq, current))
+               (void) taskq_thread_spawn(tq, spl_taskq_thread_sequential + 1);
        spin_unlock_irqrestore(&tq->tq_lock, tq->tq_lock_flags);
        return (rc);
 }
@@ -587,12 +649,11 @@ taskq_dispatch_ent(taskq_t *tq, task_func_t func, void *arg, uint_t flags,
 {
        ASSERT(tq);
        ASSERT(func);
-       ASSERT(!(tq->tq_flags & TASKQ_DYNAMIC));
 
        spin_lock_irqsave(&tq->tq_lock, tq->tq_lock_flags);
 
        /* Taskq being destroyed and all tasks drained */
-       if (!(tq->tq_flags & TQ_ACTIVE)) {
+       if (!(tq->tq_flags & TASKQ_ACTIVE)) {
                t->tqent_id = 0;
                goto out;
        }
@@ -621,6 +682,10 @@ taskq_dispatch_ent(taskq_t *tq, task_func_t func, void *arg, uint_t flags,
 
        wake_up(&tq->tq_work_waitq);
 out:
+       /* Spawn additional taskq threads if required. */
+       if (tq->tq_nactive == tq->tq_nthreads &&
+           taskq_member_impl(tq, current))
+               (void) taskq_thread_spawn(tq, spl_taskq_thread_sequential + 1);
        spin_unlock_irqrestore(&tq->tq_lock, tq->tq_lock_flags);
 }
 EXPORT_SYMBOL(taskq_dispatch_ent);
@@ -647,6 +712,97 @@ taskq_init_ent(taskq_ent_t *t)
 }
 EXPORT_SYMBOL(taskq_init_ent);
 
+/*
+ * Return the next pending task, preference is given to tasks on the
+ * priority list which were dispatched with TQ_FRONT.
+ */
+static taskq_ent_t *
+taskq_next_ent(taskq_t *tq)
+{
+       struct list_head *list;
+
+       ASSERT(spin_is_locked(&tq->tq_lock));
+
+       if (!list_empty(&tq->tq_prio_list))
+               list = &tq->tq_prio_list;
+       else if (!list_empty(&tq->tq_pend_list))
+               list = &tq->tq_pend_list;
+       else
+               return (NULL);
+
+       return (list_entry(list->next, taskq_ent_t, tqent_list));
+}
+
+/*
+ * Spawns a new thread for the specified taskq.
+ */
+static void
+taskq_thread_spawn_task(void *arg)
+{
+       taskq_t *tq = (taskq_t *)arg;
+
+       (void) taskq_thread_create(tq);
+
+       spin_lock_irqsave(&tq->tq_lock, tq->tq_lock_flags);
+       tq->tq_nspawn--;
+       spin_unlock_irqrestore(&tq->tq_lock, tq->tq_lock_flags);
+}
+
+/*
+ * Spawn addition threads for dynamic taskqs (TASKQ_DYNMAIC) the current
+ * number of threads is insufficient to handle the pending tasks.  These
+ * new threads must be created by the dedicated dynamic_taskq to avoid
+ * deadlocks between thread creation and memory reclaim.  The system_taskq
+ * which is also a dynamic taskq cannot be safely used for this.
+ */
+static int
+taskq_thread_spawn(taskq_t *tq, int seq_tasks)
+{
+       int spawning = 0;
+
+       if (!(tq->tq_flags & TASKQ_DYNAMIC))
+               return (0);
+
+       if ((seq_tasks > spl_taskq_thread_sequential) &&
+           (tq->tq_nthreads + tq->tq_nspawn < tq->tq_maxthreads) &&
+           (tq->tq_flags & TASKQ_ACTIVE)) {
+               spawning = (++tq->tq_nspawn);
+               taskq_dispatch(dynamic_taskq, taskq_thread_spawn_task,
+                   tq, TQ_NOSLEEP);
+       }
+
+       return (spawning);
+}
+
+/*
+ * Threads in a dynamic taskq should only exit once it has been completely
+ * drained and no other threads are actively servicing tasks.  This prevents
+ * threads from being created and destroyed more than is required.
+ *
+ * The first thread is the thread list is treated as the primary thread.
+ * There is nothing special about the primary thread but in order to avoid
+ * all the taskq pids from changing we opt to make it long running.
+ */
+static int
+taskq_thread_should_stop(taskq_t *tq, taskq_thread_t *tqt)
+{
+       ASSERT(spin_is_locked(&tq->tq_lock));
+
+       if (!(tq->tq_flags & TASKQ_DYNAMIC))
+               return (0);
+
+       if (list_first_entry(&(tq->tq_thread_list), taskq_thread_t,
+           tqt_thread_list) == tqt)
+               return (0);
+
+       return
+           ((tq->tq_nspawn == 0) &&    /* No threads are being spawned */
+           (tq->tq_nactive == 0) &&    /* No threads are handling tasks */
+           (tq->tq_nthreads > 1) &&    /* More than 1 thread is running */
+           (!taskq_next_ent(tq)) &&    /* There are no pending tasks */
+           (spl_taskq_thread_dynamic));/* Dynamic taskqs are allowed */
+}
+
 static int
 taskq_thread(void *args)
 {
@@ -655,18 +811,28 @@ taskq_thread(void *args)
        taskq_thread_t *tqt = args;
        taskq_t *tq;
        taskq_ent_t *t;
-       struct list_head *pend_list;
+       int seq_tasks = 0;
 
        ASSERT(tqt);
        tq = tqt->tqt_tq;
        current->flags |= PF_NOFREEZE;
 
+       #if defined(PF_MEMALLOC_NOIO)
+       (void) memalloc_noio_save();
+       #endif
+
        sigfillset(&blocked);
        sigprocmask(SIG_BLOCK, &blocked, NULL);
        flush_signals(current);
 
        spin_lock_irqsave(&tq->tq_lock, tq->tq_lock_flags);
+
+       /* Immediately exit if more threads than allowed were created. */
+       if (tq->tq_nthreads >= tq->tq_maxthreads)
+               goto error;
+
        tq->tq_nthreads++;
+       list_add_tail(&tqt->tqt_thread_list, &tq->tq_thread_list);
        wake_up(&tq->tq_wait_waitq);
        set_current_state(TASK_INTERRUPTIBLE);
 
@@ -674,25 +840,25 @@ taskq_thread(void *args)
 
                if (list_empty(&tq->tq_pend_list) &&
                    list_empty(&tq->tq_prio_list)) {
+
+                       if (taskq_thread_should_stop(tq, tqt)) {
+                               wake_up_all(&tq->tq_wait_waitq);
+                               break;
+                       }
+
                        add_wait_queue_exclusive(&tq->tq_work_waitq, &wait);
                        spin_unlock_irqrestore(&tq->tq_lock, tq->tq_lock_flags);
+
                        schedule();
+                       seq_tasks = 0;
+
                        spin_lock_irqsave(&tq->tq_lock, tq->tq_lock_flags);
                        remove_wait_queue(&tq->tq_work_waitq, &wait);
                } else {
                        __set_current_state(TASK_RUNNING);
                }
 
-
-               if (!list_empty(&tq->tq_prio_list))
-                       pend_list = &tq->tq_prio_list;
-               else if (!list_empty(&tq->tq_pend_list))
-                       pend_list = &tq->tq_pend_list;
-               else
-                       pend_list = NULL;
-
-               if (pend_list) {
-                       t = list_entry(pend_list->next,taskq_ent_t,tqent_list);
+               if ((t = taskq_next_ent(tq)) != NULL) {
                        list_del_init(&t->tqent_list);
 
                        /* In order to support recursively dispatching a
@@ -721,8 +887,7 @@ taskq_thread(void *args)
                        tqt->tqt_task = NULL;
 
                        /* For prealloc'd tasks, we don't free anything. */
-                       if ((tq->tq_flags & TASKQ_DYNAMIC) ||
-                           !(tqt->tqt_flags & TQENT_FLAG_PREALLOC))
+                       if (!(tqt->tqt_flags & TQENT_FLAG_PREALLOC))
                                task_done(tq, t);
 
                        /* When the current lowest outstanding taskqid is
@@ -732,9 +897,16 @@ taskq_thread(void *args)
                                ASSERT3S(tq->tq_lowest_id, >, tqt->tqt_id);
                        }
 
+                       /* Spawn additional taskq threads if required. */
+                       if (taskq_thread_spawn(tq, ++seq_tasks))
+                               seq_tasks = 0;
+
                        tqt->tqt_id = 0;
                        tqt->tqt_flags = 0;
                        wake_up_all(&tq->tq_wait_waitq);
+               } else {
+                       if (taskq_thread_should_stop(tq, tqt))
+                               break;
                }
 
                set_current_state(TASK_INTERRUPTIBLE);
@@ -744,27 +916,57 @@ taskq_thread(void *args)
        __set_current_state(TASK_RUNNING);
        tq->tq_nthreads--;
        list_del_init(&tqt->tqt_thread_list);
-       kmem_free(tqt, sizeof(taskq_thread_t));
-
+error:
+       kmem_free(tqt, sizeof (taskq_thread_t));
        spin_unlock_irqrestore(&tq->tq_lock, tq->tq_lock_flags);
 
        return (0);
 }
 
+static taskq_thread_t *
+taskq_thread_create(taskq_t *tq)
+{
+       static int last_used_cpu = 0;
+       taskq_thread_t *tqt;
+
+       tqt = kmem_alloc(sizeof (*tqt), KM_PUSHPAGE);
+       INIT_LIST_HEAD(&tqt->tqt_thread_list);
+       INIT_LIST_HEAD(&tqt->tqt_active_list);
+       tqt->tqt_tq = tq;
+       tqt->tqt_id = 0;
+
+       tqt->tqt_thread = spl_kthread_create(taskq_thread, tqt,
+           "%s", tq->tq_name);
+       if (tqt->tqt_thread == NULL) {
+               kmem_free(tqt, sizeof (taskq_thread_t));
+               return (NULL);
+       }
+
+       if (spl_taskq_thread_bind) {
+               last_used_cpu = (last_used_cpu + 1) % num_online_cpus();
+               kthread_bind(tqt->tqt_thread, last_used_cpu);
+       }
+
+       if (spl_taskq_thread_priority)
+               set_user_nice(tqt->tqt_thread, PRIO_TO_NICE(tq->tq_pri));
+
+       wake_up_process(tqt->tqt_thread);
+
+       return (tqt);
+}
+
 taskq_t *
 taskq_create(const char *name, int nthreads, pri_t pri,
     int minalloc, int maxalloc, uint_t flags)
 {
-       static int last_used_cpu = 0;
        taskq_t *tq;
        taskq_thread_t *tqt;
-       int rc = 0, i, j = 0;
+       int count = 0, rc = 0, i;
 
        ASSERT(name != NULL);
-       ASSERT(pri <= maxclsyspri);
        ASSERT(minalloc >= 0);
        ASSERT(maxalloc <= INT_MAX);
-       ASSERT(!(flags & (TASKQ_CPR_SAFE | TASKQ_DYNAMIC))); /* Unsupported */
+       ASSERT(!(flags & (TASKQ_CPR_SAFE))); /* Unsupported */
 
        /* Scale the number of threads using nthreads as a percentage */
        if (flags & TASKQ_THREADS_CPU_PCT) {
@@ -775,24 +977,25 @@ taskq_create(const char *name, int nthreads, pri_t pri,
                nthreads = MAX((num_online_cpus() * nthreads) / 100, 1);
        }
 
-       tq = kmem_alloc(sizeof(*tq), KM_PUSHPAGE);
+       tq = kmem_alloc(sizeof (*tq), KM_PUSHPAGE);
        if (tq == NULL)
                return (NULL);
 
        spin_lock_init(&tq->tq_lock);
-       spin_lock_irqsave(&tq->tq_lock, tq->tq_lock_flags);
        INIT_LIST_HEAD(&tq->tq_thread_list);
        INIT_LIST_HEAD(&tq->tq_active_list);
-       tq->tq_name      = name;
-       tq->tq_nactive   = 0;
-       tq->tq_nthreads  = 0;
-       tq->tq_pri       = pri;
-       tq->tq_minalloc  = minalloc;
-       tq->tq_maxalloc  = maxalloc;
-       tq->tq_nalloc    = 0;
-       tq->tq_flags     = (flags | TQ_ACTIVE);
-       tq->tq_next_id   = 1;
-       tq->tq_lowest_id = 1;
+       tq->tq_name       = strdup(name);
+       tq->tq_nactive    = 0;
+       tq->tq_nthreads   = 0;
+       tq->tq_nspawn     = 0;
+       tq->tq_maxthreads = nthreads;
+       tq->tq_pri        = pri;
+       tq->tq_minalloc   = minalloc;
+       tq->tq_maxalloc   = maxalloc;
+       tq->tq_nalloc     = 0;
+       tq->tq_flags      = (flags | TASKQ_ACTIVE);
+       tq->tq_next_id    = 1;
+       tq->tq_lowest_id  = 1;
        INIT_LIST_HEAD(&tq->tq_free_list);
        INIT_LIST_HEAD(&tq->tq_pend_list);
        INIT_LIST_HEAD(&tq->tq_prio_list);
@@ -800,38 +1003,28 @@ taskq_create(const char *name, int nthreads, pri_t pri,
        init_waitqueue_head(&tq->tq_work_waitq);
        init_waitqueue_head(&tq->tq_wait_waitq);
 
-       if (flags & TASKQ_PREPOPULATE)
+       if (flags & TASKQ_PREPOPULATE) {
+               spin_lock_irqsave(&tq->tq_lock, tq->tq_lock_flags);
+
                for (i = 0; i < minalloc; i++)
                        task_done(tq, task_alloc(tq, TQ_PUSHPAGE | TQ_NEW));
 
-       spin_unlock_irqrestore(&tq->tq_lock, tq->tq_lock_flags);
+               spin_unlock_irqrestore(&tq->tq_lock, tq->tq_lock_flags);
+       }
+
+       if ((flags & TASKQ_DYNAMIC) && spl_taskq_thread_dynamic)
+               nthreads = 1;
 
        for (i = 0; i < nthreads; i++) {
-               tqt = kmem_alloc(sizeof(*tqt), KM_PUSHPAGE);
-               INIT_LIST_HEAD(&tqt->tqt_thread_list);
-               INIT_LIST_HEAD(&tqt->tqt_active_list);
-               tqt->tqt_tq = tq;
-               tqt->tqt_id = 0;
-
-               tqt->tqt_thread = spl_kthread_create(taskq_thread, tqt,
-                   "%s/%d", name, i);
-               if (tqt->tqt_thread) {
-                       list_add(&tqt->tqt_thread_list, &tq->tq_thread_list);
-                       if (spl_taskq_thread_bind) {
-                               last_used_cpu = (last_used_cpu + 1) % num_online_cpus();
-                               kthread_bind(tqt->tqt_thread, last_used_cpu);
-                       }
-                       set_user_nice(tqt->tqt_thread, PRIO_TO_NICE(pri));
-                       wake_up_process(tqt->tqt_thread);
-                       j++;
-               } else {
-                       kmem_free(tqt, sizeof(taskq_thread_t));
+               tqt = taskq_thread_create(tq);
+               if (tqt == NULL)
                        rc = 1;
-               }
+               else
+                       count++;
        }
 
        /* Wait for all threads to be started before potential destroy */
-       wait_event(tq->tq_wait_waitq, tq->tq_nthreads == j);
+       wait_event(tq->tq_wait_waitq, tq->tq_nthreads == count);
 
        if (rc) {
                taskq_destroy(tq);
@@ -851,10 +1044,16 @@ taskq_destroy(taskq_t *tq)
 
        ASSERT(tq);
        spin_lock_irqsave(&tq->tq_lock, tq->tq_lock_flags);
-       tq->tq_flags &= ~TQ_ACTIVE;
+       tq->tq_flags &= ~TASKQ_ACTIVE;
        spin_unlock_irqrestore(&tq->tq_lock, tq->tq_lock_flags);
 
-       /* TQ_ACTIVE cleared prevents new tasks being added to pending */
+       /*
+        * When TASKQ_ACTIVE is clear new tasks may not be added nor may
+        * new worker threads be spawned for dynamic taskq.
+        */
+       if (dynamic_taskq != NULL)
+               taskq_wait_outstanding(dynamic_taskq, 0);
+
        taskq_wait(tq);
 
        spin_lock_irqsave(&tq->tq_lock, tq->tq_lock_flags);
@@ -867,7 +1066,7 @@ taskq_destroy(taskq_t *tq)
         */
        while (!list_empty(&tq->tq_thread_list)) {
                tqt = list_entry(tq->tq_thread_list.next,
-                                taskq_thread_t, tqt_thread_list);
+                   taskq_thread_t, tqt_thread_list);
                thread = tqt->tqt_thread;
                spin_unlock_irqrestore(&tq->tq_lock, tq->tq_lock_flags);
 
@@ -885,8 +1084,9 @@ taskq_destroy(taskq_t *tq)
                task_free(tq, t);
        }
 
-       ASSERT(tq->tq_nthreads == 0);
-       ASSERT(tq->tq_nalloc == 0);
+       ASSERT0(tq->tq_nthreads);
+       ASSERT0(tq->tq_nalloc);
+       ASSERT0(tq->tq_nspawn);
        ASSERT(list_empty(&tq->tq_thread_list));
        ASSERT(list_empty(&tq->tq_active_list));
        ASSERT(list_empty(&tq->tq_free_list));
@@ -896,25 +1096,35 @@ taskq_destroy(taskq_t *tq)
 
        spin_unlock_irqrestore(&tq->tq_lock, tq->tq_lock_flags);
 
-       kmem_free(tq, sizeof(taskq_t));
+       strfree(tq->tq_name);
+       kmem_free(tq, sizeof (taskq_t));
 }
 EXPORT_SYMBOL(taskq_destroy);
 
 int
 spl_taskq_init(void)
 {
-       /* Solaris creates a dynamic taskq of up to 64 threads, however in
-        * a Linux environment 1 thread per-core is usually about right */
-       system_taskq = taskq_create("spl_system_taskq", num_online_cpus(),
-                                   minclsyspri, 4, 512, TASKQ_PREPOPULATE);
+       system_taskq = taskq_create("spl_system_taskq", MAX(boot_ncpus, 64),
+           maxclsyspri, boot_ncpus, INT_MAX, TASKQ_PREPOPULATE|TASKQ_DYNAMIC);
        if (system_taskq == NULL)
                return (1);
 
+       dynamic_taskq = taskq_create("spl_dynamic_taskq", 1,
+           maxclsyspri, boot_ncpus, INT_MAX, TASKQ_PREPOPULATE);
+       if (dynamic_taskq == NULL) {
+               taskq_destroy(system_taskq);
+               return (1);
+       }
+
        return (0);
 }
 
 void
 spl_taskq_fini(void)
 {
+       taskq_destroy(dynamic_taskq);
+       dynamic_taskq = NULL;
+
        taskq_destroy(system_taskq);
+       system_taskq = NULL;
 }
index 9a0987527b2705d9bd5a1b0f9be2a8add67ffda6..4d0800e5a11f5d4b570c79d46dd33ccb3f3de1cf 100644 (file)
@@ -1,4 +1,4 @@
-/*****************************************************************************\
+/*
  *  Copyright (C) 2010 Lawrence Livermore National Security, LLC.
  *  Produced at Lawrence Livermore National Laboratory (cf, DISCLAIMER).
  *  Written by Brian Behlendorf <behlendorf1@llnl.gov>.
@@ -19,7 +19,8 @@
  *
  *  You should have received a copy of the GNU General Public License along
  *  with the SPL.  If not, see <http://www.gnu.org/licenses/>.
- *****************************************************************************
+ *
+ *
  *  Solaris Porting Layer (SPL) Thread Specific Data Implementation.
  *
  *  Thread specific data has implemented using a hash table, this avoids
@@ -56,7 +57,7 @@
  *  so if your using the Solaris thread API you should not need to call
  *  tsd_exit() directly.
  *
-\*****************************************************************************/
+ */
 
 #include <sys/kmem.h>
 #include <sys/thread.h>
@@ -136,7 +137,7 @@ tsd_hash_dtor(struct hlist_head *work)
                if (entry->he_dtor && entry->he_pid != DTOR_PID)
                        entry->he_dtor(entry->he_value);
 
-               kmem_free(entry, sizeof(tsd_hash_entry_t));
+               kmem_free(entry, sizeof (tsd_hash_entry_t));
        }
 }
 
@@ -163,7 +164,7 @@ tsd_hash_add(tsd_hash_table_t *table, uint_t key, pid_t pid, void *value)
        ASSERT3P(tsd_hash_search(table, key, pid), ==, NULL);
 
        /* New entry allocate structure, set value, and add to hash */
-       entry = kmem_alloc(sizeof(tsd_hash_entry_t), KM_PUSHPAGE);
+       entry = kmem_alloc(sizeof (tsd_hash_entry_t), KM_PUSHPAGE);
        if (entry == NULL)
                return (ENOMEM);
 
@@ -222,7 +223,7 @@ tsd_hash_add_key(tsd_hash_table_t *table, uint_t *keyp, dtor_func_t dtor)
        ASSERT3P(table, !=, NULL);
 
        /* Allocate entry to be used as a destructor for this key */
-       entry = kmem_alloc(sizeof(tsd_hash_entry_t), KM_PUSHPAGE);
+       entry = kmem_alloc(sizeof (tsd_hash_entry_t), KM_PUSHPAGE);
        if (entry == NULL)
                return (ENOMEM);
 
@@ -280,7 +281,7 @@ tsd_hash_add_pid(tsd_hash_table_t *table, pid_t pid)
        ulong_t hash;
 
        /* Allocate entry to be used as the process reference */
-       entry = kmem_alloc(sizeof(tsd_hash_entry_t), KM_PUSHPAGE);
+       entry = kmem_alloc(sizeof (tsd_hash_entry_t), KM_PUSHPAGE);
        if (entry == NULL)
                return (ENOMEM);
 
@@ -333,13 +334,13 @@ tsd_hash_table_init(uint_t bits)
        tsd_hash_table_t *table;
        int hash, size = (1 << bits);
 
-       table = kmem_zalloc(sizeof(tsd_hash_table_t), KM_SLEEP);
+       table = kmem_zalloc(sizeof (tsd_hash_table_t), KM_SLEEP);
        if (table == NULL)
                return (NULL);
 
-       table->ht_bins = kmem_zalloc(sizeof(tsd_hash_bin_t) * size, KM_SLEEP);
+       table->ht_bins = kmem_zalloc(sizeof (tsd_hash_bin_t) * size, KM_SLEEP);
        if (table->ht_bins == NULL) {
-               kmem_free(table, sizeof(tsd_hash_table_t));
+               kmem_free(table, sizeof (tsd_hash_table_t));
                return (NULL);
        }
 
@@ -376,9 +377,9 @@ tsd_hash_table_fini(tsd_hash_table_t *table)
        for (i = 0, size = (1 << table->ht_bits); i < size; i++) {
                bin = &table->ht_bins[i];
                spin_lock(&bin->hb_lock);
-               while (!hlist_empty(&bin->hb_head)) {
+               while (!hlist_empty(&bin->hb_head)) {
                        entry = hlist_entry(bin->hb_head.first,
-                                           tsd_hash_entry_t, he_list);
+                           tsd_hash_entry_t, he_list);
                        tsd_hash_del(table, entry);
                        hlist_add_head(&entry->he_list, &work);
                }
@@ -387,8 +388,62 @@ tsd_hash_table_fini(tsd_hash_table_t *table)
        spin_unlock(&table->ht_lock);
 
        tsd_hash_dtor(&work);
-       kmem_free(table->ht_bins, sizeof(tsd_hash_bin_t)*(1<<table->ht_bits));
-       kmem_free(table, sizeof(tsd_hash_table_t));
+       kmem_free(table->ht_bins, sizeof (tsd_hash_bin_t)*(1<<table->ht_bits));
+       kmem_free(table, sizeof (tsd_hash_table_t));
+}
+
+/*
+ * tsd_remove_entry - remove a tsd entry for this thread
+ * @entry: entry to remove
+ *
+ * Remove the thread specific data @entry for this thread.
+ * If this is the last entry for this thread, also remove the PID entry.
+ */
+static void
+tsd_remove_entry(tsd_hash_entry_t *entry)
+{
+       HLIST_HEAD(work);
+       tsd_hash_table_t *table;
+       tsd_hash_entry_t *pid_entry;
+       tsd_hash_bin_t *pid_entry_bin, *entry_bin;
+       ulong_t hash;
+
+       table = tsd_hash_table;
+       ASSERT3P(table, !=, NULL);
+       ASSERT3P(entry, !=, NULL);
+
+       spin_lock(&table->ht_lock);
+
+       hash = hash_long((ulong_t)entry->he_key *
+           (ulong_t)entry->he_pid, table->ht_bits);
+       entry_bin = &table->ht_bins[hash];
+
+       /* save the possible pid_entry */
+       pid_entry = list_entry(entry->he_pid_list.next, tsd_hash_entry_t,
+           he_pid_list);
+
+       /* remove entry */
+       spin_lock(&entry_bin->hb_lock);
+       tsd_hash_del(table, entry);
+       hlist_add_head(&entry->he_list, &work);
+       spin_unlock(&entry_bin->hb_lock);
+
+       /* if pid_entry is indeed pid_entry, then remove it if it's empty */
+       if (pid_entry->he_key == PID_KEY &&
+           list_empty(&pid_entry->he_pid_list)) {
+               hash = hash_long((ulong_t)pid_entry->he_key *
+                   (ulong_t)pid_entry->he_pid, table->ht_bits);
+               pid_entry_bin = &table->ht_bins[hash];
+
+               spin_lock(&pid_entry_bin->hb_lock);
+               tsd_hash_del(table, pid_entry);
+               hlist_add_head(&pid_entry->he_list, &work);
+               spin_unlock(&pid_entry_bin->hb_lock);
+       }
+
+       spin_unlock(&table->ht_lock);
+
+       tsd_hash_dtor(&work);
 }
 
 /*
@@ -409,6 +464,8 @@ tsd_set(uint_t key, void *value)
        tsd_hash_entry_t *entry;
        pid_t pid;
        int rc;
+       /* mark remove if value is NULL */
+       boolean_t remove = (value == NULL);
 
        table = tsd_hash_table;
        pid = curthread->pid;
@@ -421,9 +478,16 @@ tsd_set(uint_t key, void *value)
        entry = tsd_hash_search(table, key, pid);
        if (entry) {
                entry->he_value = value;
+               /* remove the entry */
+               if (remove)
+                       tsd_remove_entry(entry);
                return (0);
        }
 
+       /* don't create entry if value is NULL */
+       if (remove)
+               return (0);
+
        /* Add a process entry to the hash if not yet exists */
        entry = tsd_hash_search(table, PID_KEY, pid);
        if (entry == NULL) {
@@ -482,7 +546,7 @@ tsd_create(uint_t *keyp, dtor_func_t dtor)
        if (*keyp)
                return;
 
-       (void)tsd_hash_add_key(tsd_hash_table, keyp, dtor);
+       (void) tsd_hash_add_key(tsd_hash_table, keyp, dtor);
 }
 EXPORT_SYMBOL(tsd_create);
 
@@ -519,14 +583,14 @@ tsd_destroy(uint_t *keyp)
         * DTOR_PID entry.  They are removed from the hash table and
         * linked in to a private working list to be destroyed.
         */
-        while (!list_empty(&dtor_entry->he_key_list)) {
+       while (!list_empty(&dtor_entry->he_key_list)) {
                entry = list_entry(dtor_entry->he_key_list.next,
-                                  tsd_hash_entry_t, he_key_list);
+                   tsd_hash_entry_t, he_key_list);
                ASSERT3U(dtor_entry->he_key, ==, entry->he_key);
                ASSERT3P(dtor_entry->he_dtor, ==, entry->he_dtor);
 
                hash = hash_long((ulong_t)entry->he_key *
-                    (ulong_t)entry->he_pid, table->ht_bits);
+                   (ulong_t)entry->he_pid, table->ht_bits);
                entry_bin = &table->ht_bins[hash];
 
                spin_lock(&entry_bin->hb_lock);
@@ -583,9 +647,9 @@ tsd_exit(void)
         * linked in to a private working list to be destroyed.
         */
 
-        while (!list_empty(&pid_entry->he_pid_list)) {
+       while (!list_empty(&pid_entry->he_pid_list)) {
                entry = list_entry(pid_entry->he_pid_list.next,
-                                  tsd_hash_entry_t, he_pid_list);
+                   tsd_hash_entry_t, he_pid_list);
                ASSERT3U(pid_entry->he_pid, ==, entry->he_pid);
 
                hash = hash_long((ulong_t)entry->he_key *
index 1e26b8e29a89e736f82e26a2a87e5606326bc889..ab9830d1867a04ea6577d534110d6f41a229b85c 100644 (file)
@@ -623,14 +623,14 @@ EXPORT_SYMBOL(vn_space);
 
 /* Function must be called while holding the vn_file_lock */
 static file_t *
-file_find(int fd)
+file_find(int fd, struct task_struct *task)
 {
         file_t *fp;
 
        ASSERT(spin_is_locked(&vn_file_lock));
 
         list_for_each_entry(fp, &vn_file_list,  f_list) {
-               if (fd == fp->f_fd && fp->f_task == current) {
+               if (fd == fp->f_fd && fp->f_task == task) {
                        ASSERT(atomic_read(&fp->f_ref) != 0);
                         return fp;
                }
@@ -648,10 +648,13 @@ vn_getf(int fd)
        vnode_t *vp;
        int rc = 0;
 
+       if (fd < 0)
+               return (NULL);
+
        /* Already open just take an extra reference */
        spin_lock(&vn_file_lock);
 
-       fp = file_find(fd);
+       fp = file_find(fd, current);
        if (fp) {
                atomic_inc(&fp->f_ref);
                spin_unlock(&vn_file_lock);
@@ -730,11 +733,22 @@ static void releasef_locked(file_t *fp)
 
 void
 vn_releasef(int fd)
+{
+       areleasef(fd, P_FINFO(current));
+}
+EXPORT_SYMBOL(releasef);
+
+void
+vn_areleasef(int fd, uf_info_t *fip)
 {
        file_t *fp;
+       struct task_struct *task = (struct task_struct *)fip;
+
+       if (fd < 0)
+               return;
 
        spin_lock(&vn_file_lock);
-       fp = file_find(fd);
+       fp = file_find(fd, task);
        if (fp) {
                atomic_dec(&fp->f_ref);
                if (atomic_read(&fp->f_ref) > 0) {
@@ -749,7 +763,8 @@ vn_releasef(int fd)
 
        return;
 } /* releasef() */
-EXPORT_SYMBOL(releasef);
+EXPORT_SYMBOL(areleasef);
+
 
 static void
 #ifdef HAVE_SET_FS_PWD_WITH_CONST
index f4065196b64e337f11a6403e107f554308c4b88d..680f28492b46b75fce8e2cecdc93c192cb609016 100644 (file)
@@ -1,25 +1,28 @@
 # Makefile.in for splat kernel module
 
+src = @abs_top_srcdir@/module/splat
+obj = @abs_builddir@
+
 MODULE := splat
 EXTRA_CFLAGS = $(SPL_MODULE_CFLAGS) @KERNELCPPFLAGS@
 
 # Solaris Porting LAyer Tests
 obj-$(CONFIG_SPL) := $(MODULE).o
 
-$(MODULE)-objs += @top_srcdir@/module/splat/splat-ctl.o
-$(MODULE)-objs += @top_srcdir@/module/splat/splat-kmem.o
-$(MODULE)-objs += @top_srcdir@/module/splat/splat-taskq.o
-$(MODULE)-objs += @top_srcdir@/module/splat/splat-random.o
-$(MODULE)-objs += @top_srcdir@/module/splat/splat-mutex.o
-$(MODULE)-objs += @top_srcdir@/module/splat/splat-condvar.o
-$(MODULE)-objs += @top_srcdir@/module/splat/splat-thread.o
-$(MODULE)-objs += @top_srcdir@/module/splat/splat-rwlock.o
-$(MODULE)-objs += @top_srcdir@/module/splat/splat-time.o
-$(MODULE)-objs += @top_srcdir@/module/splat/splat-vnode.o
-$(MODULE)-objs += @top_srcdir@/module/splat/splat-kobj.o
-$(MODULE)-objs += @top_srcdir@/module/splat/splat-atomic.o
-$(MODULE)-objs += @top_srcdir@/module/splat/splat-list.o
-$(MODULE)-objs += @top_srcdir@/module/splat/splat-generic.o
-$(MODULE)-objs += @top_srcdir@/module/splat/splat-cred.o
-$(MODULE)-objs += @top_srcdir@/module/splat/splat-zlib.o
-$(MODULE)-objs += @top_srcdir@/module/splat/splat-linux.o
+$(MODULE)-objs += splat-ctl.o
+$(MODULE)-objs += splat-kmem.o
+$(MODULE)-objs += splat-taskq.o
+$(MODULE)-objs += splat-random.o
+$(MODULE)-objs += splat-mutex.o
+$(MODULE)-objs += splat-condvar.o
+$(MODULE)-objs += splat-thread.o
+$(MODULE)-objs += splat-rwlock.o
+$(MODULE)-objs += splat-time.o
+$(MODULE)-objs += splat-vnode.o
+$(MODULE)-objs += splat-kobj.o
+$(MODULE)-objs += splat-atomic.o
+$(MODULE)-objs += splat-list.o
+$(MODULE)-objs += splat-generic.o
+$(MODULE)-objs += splat-cred.o
+$(MODULE)-objs += splat-zlib.o
+$(MODULE)-objs += splat-linux.o
index e94f42f00b15da2ea1cf7799aa6e3fd294ab1510..999f4f0587676429107c56f1d7aff1ad042a8eca 100644 (file)
@@ -156,7 +156,7 @@ splat_atomic_test1(struct file *file, void *arg)
 
                thr = (kthread_t *)thread_create(NULL, 0, splat_atomic_work,
                                                 &ap, 0, &p0, TS_RUN,
-                                                minclsyspri);
+                                                defclsyspri);
                if (thr == NULL) {
                        rc = -ESRCH;
                        mutex_exit(&ap.ap_lock);
index 4b9bcb3f068d746e0bf8f0cba1ce817fc8273786..4d4148d427f21d90e4afc58d7470243c309918ed 100644 (file)
@@ -638,11 +638,7 @@ splat_init(void)
 static void __exit
 splat_fini(void)
 {
-       int error;
-
-       error = misc_deregister(&splat_misc);
-       if (error)
-               printk(KERN_INFO "SPLAT: misc_deregister() failed %d\n", error);
+       misc_deregister(&splat_misc);
 
        SPLAT_SUBSYSTEM_FINI(linux);
        SPLAT_SUBSYSTEM_FINI(zlib);
index 832132696d885d7f48a8a11f9708db521b442ce3..d00af90fa748d69f5d93cc06ac249ef6ccf29d59 100644 (file)
@@ -28,6 +28,7 @@
 #include "splat-ctl.h"
 #include <sys/mutex.h>
 #include <linux/file_compat.h>
+#include <linux/version.h>
 
 #define SPLAT_SUBSYSTEM_INIT(type)                                      \
 ({      splat_subsystem_t *_sub_;                                       \
index cd0000bae67138c3031d645bd155962238d62bf2..b3fd1a84dc871a4d95deaafcf9c88dfd6986860d 100644 (file)
@@ -739,7 +739,7 @@ splat_kmem_cache_thread_test(struct file *file, void *arg, char *name,
        for (i = 0; i < SPLAT_KMEM_THREADS; i++) {
                thr = thread_create(NULL, 0,
                                    splat_kmem_cache_test_thread,
-                                   kcp, 0, &p0, TS_RUN, minclsyspri);
+                                   kcp, 0, &p0, TS_RUN, defclsyspri);
                if (thr == NULL) {
                        rc = -ESRCH;
                        goto out_cache;
index 909d730cb014453e1bdca80d041ceabc6f3e5896..86bef8ee31be6a2cb2dd26166a6a7a4e08a4cf52 100644 (file)
@@ -87,7 +87,7 @@ splat_mutex_test1(struct file *file, void *arg)
         if (mp == NULL)
                 return -ENOMEM;
 
-        tq = taskq_create(SPLAT_MUTEX_TEST_TASKQ, 1, maxclsyspri,
+        tq = taskq_create(SPLAT_MUTEX_TEST_TASKQ, 1, defclsyspri,
                           50, INT_MAX, TASKQ_PREPOPULATE);
         if (tq == NULL) {
                 rc = -ENOMEM;
@@ -196,7 +196,7 @@ splat_mutex_test2(struct file *file, void *arg)
 
         /* Create several threads allowing tasks to race with each other */
         tq = taskq_create(SPLAT_MUTEX_TEST_TASKQ, num_online_cpus(),
-                          maxclsyspri, 50, INT_MAX, TASKQ_PREPOPULATE);
+                          defclsyspri, 50, INT_MAX, TASKQ_PREPOPULATE);
         if (tq == NULL) {
                 rc = -ENOMEM;
                 goto out;
@@ -266,7 +266,7 @@ splat_mutex_test3(struct file *file, void *arg)
         mp.mp_file = file;
         mutex_init(&mp.mp_mtx, SPLAT_MUTEX_TEST_NAME, MUTEX_DEFAULT, NULL);
 
-        if ((tq = taskq_create(SPLAT_MUTEX_TEST_NAME, 1, maxclsyspri,
+        if ((tq = taskq_create(SPLAT_MUTEX_TEST_NAME, 1, defclsyspri,
                                50, INT_MAX, TASKQ_PREPOPULATE)) == NULL) {
                 splat_vprint(file, SPLAT_MUTEX_TEST3_NAME, "Taskq '%s' "
                              "create failed\n", SPLAT_MUTEX_TEST3_NAME);
index 6c623792e645eedb420be3416adcd7382825f388..284f77370d37dc245dd2982ac947e362bce12347 100644 (file)
@@ -327,7 +327,7 @@ splat_rwlock_test2(struct file *file, void *arg)
 
        /* Create several threads allowing tasks to race with each other */
        tq = taskq_create(SPLAT_RWLOCK_TEST_TASKQ, num_online_cpus(),
-                         maxclsyspri, 50, INT_MAX, TASKQ_PREPOPULATE);
+                         defclsyspri, 50, INT_MAX, TASKQ_PREPOPULATE);
        if (tq == NULL) {
                rc = -ENOMEM;
                goto out;
@@ -500,7 +500,7 @@ splat_rwlock_test4(struct file *file, void *arg)
        if (rwp == NULL)
                return -ENOMEM;
 
-       tq = taskq_create(SPLAT_RWLOCK_TEST_TASKQ, 1, maxclsyspri,
+       tq = taskq_create(SPLAT_RWLOCK_TEST_TASKQ, 1, defclsyspri,
                          50, INT_MAX, TASKQ_PREPOPULATE);
        if (tq == NULL) {
                rc = -ENOMEM;
index 2787bf401b0748c6eefa1d64334eceb86ef4c0d1..8f06f413d5bc95d60cc9fc906a86ff193218713e 100644 (file)
@@ -28,6 +28,7 @@
 #include <sys/vmem.h>
 #include <sys/random.h>
 #include <sys/taskq.h>
+#include <sys/time.h>
 #include <sys/timer.h>
 #include <linux/delay.h>
 #include "splat-internal.h"
 #define SPLAT_TASKQ_TEST10_NAME                "cancel"
 #define SPLAT_TASKQ_TEST10_DESC                "Cancel task execution"
 
+#define SPLAT_TASKQ_TEST11_ID          0x020b
+#define SPLAT_TASKQ_TEST11_NAME                "dynamic"
+#define SPLAT_TASKQ_TEST11_DESC                "Dynamic task queue thread creation"
+
 #define SPLAT_TASKQ_ORDER_MAX          8
 #define SPLAT_TASKQ_DEPTH_MAX          16
 
@@ -129,7 +134,7 @@ splat_taskq_test1_impl(struct file *file, void *arg, boolean_t prealloc)
                     "Taskq '%s' creating (%s dispatch)\n",
                     SPLAT_TASKQ_TEST1_NAME,
                     prealloc ? "prealloc" : "dynamic");
-       if ((tq = taskq_create(SPLAT_TASKQ_TEST1_NAME, 1, maxclsyspri,
+       if ((tq = taskq_create(SPLAT_TASKQ_TEST1_NAME, 1, defclsyspri,
                               50, INT_MAX, TASKQ_PREPOPULATE)) == NULL) {
                splat_vprint(file, SPLAT_TASKQ_TEST1_NAME,
                           "Taskq '%s' create failed\n",
@@ -264,7 +269,7 @@ splat_taskq_test2_impl(struct file *file, void *arg, boolean_t prealloc) {
                             prealloc ? "prealloc" : "dynamic");
                if ((tq[i] = taskq_create(SPLAT_TASKQ_TEST2_NAME,
                                          TEST2_THREADS_PER_TASKQ,
-                                         maxclsyspri, 50, INT_MAX,
+                                         defclsyspri, 50, INT_MAX,
                                          TASKQ_PREPOPULATE)) == NULL) {
                        splat_vprint(file, SPLAT_TASKQ_TEST2_NAME,
                                   "Taskq '%s/%d' create failed\n",
@@ -489,7 +494,7 @@ splat_taskq_test4_common(struct file *file, void *arg, int minalloc,
                     SPLAT_TASKQ_TEST4_NAME,
                     prealloc ? "prealloc" : "dynamic",
                     minalloc, maxalloc, nr_tasks);
-       if ((tq = taskq_create(SPLAT_TASKQ_TEST4_NAME, 1, maxclsyspri,
+       if ((tq = taskq_create(SPLAT_TASKQ_TEST4_NAME, 1, defclsyspri,
                               minalloc, maxalloc, TASKQ_PREPOPULATE)) == NULL) {
                splat_vprint(file, SPLAT_TASKQ_TEST4_NAME,
                             "Taskq '%s' create failed\n",
@@ -588,10 +593,10 @@ splat_taskq_test4(struct file *file, void *arg)
  * next pending task as soon as it completes its current task.  This
  * means that tasks do not strictly complete in order in which they
  * were dispatched (increasing task id).  This is fine but we need to
- * verify that taskq_wait_all() blocks until the passed task id and all
- * lower task ids complete.  We do this by dispatching the following
+ * verify taskq_wait_outstanding() blocks until the passed task id and
+ * all lower task ids complete.  We do this by dispatching the following
  * specific sequence of tasks each of which block for N time units.
- * We then use taskq_wait_all() to unblock at specific task id and
+ * We then use taskq_wait_outstanding() to unblock at specific task id and
  * verify the only the expected task ids have completed and in the
  * correct order.  The two cases of interest are:
  *
@@ -602,17 +607,17 @@ splat_taskq_test4(struct file *file, void *arg)
  *
  * The following table shows each task id and how they will be
  * scheduled.  Each rows represent one time unit and each column
- * one of the three worker threads.  The places taskq_wait_all()
+ * one of the three worker threads.  The places taskq_wait_outstanding()
  * must unblock for a specific id are identified as well as the
  * task ids which must have completed and their order.
  *
- *       +-----+       <--- taskq_wait_all(tq, 8) unblocks
+ *       +-----+       <--- taskq_wait_outstanding(tq, 8) unblocks
  *       |     |            Required Completion Order: 1,2,4,5,3,8,6,7
  * +-----+     |
  * |     |     |
  * |     |     +-----+
  * |     |     |  8  |
- * |     |     +-----+ <--- taskq_wait_all(tq, 3) unblocks
+ * |     |     +-----+ <--- taskq_wait_outstanding(tq, 3) unblocks
  * |     |  7  |     |      Required Completion Order: 1,2,4,5,3
  * |     +-----+     |
  * |  6  |     |     |
@@ -707,7 +712,7 @@ splat_taskq_test5_impl(struct file *file, void *arg, boolean_t prealloc)
                     "Taskq '%s' creating (%s dispatch)\n",
                     SPLAT_TASKQ_TEST5_NAME,
                     prealloc ? "prealloc" : "dynamic");
-       if ((tq = taskq_create(SPLAT_TASKQ_TEST5_NAME, 3, maxclsyspri,
+       if ((tq = taskq_create(SPLAT_TASKQ_TEST5_NAME, 3, defclsyspri,
                               50, INT_MAX, TASKQ_PREPOPULATE)) == NULL) {
                splat_vprint(file, SPLAT_TASKQ_TEST5_NAME,
                             "Taskq '%s' create failed\n",
@@ -755,13 +760,13 @@ splat_taskq_test5_impl(struct file *file, void *arg, boolean_t prealloc)
 
        splat_vprint(file, SPLAT_TASKQ_TEST5_NAME, "Taskq '%s' "
                     "waiting for taskqid %d completion\n", tq_arg.name, 3);
-       taskq_wait_all(tq, 3);
+       taskq_wait_outstanding(tq, 3);
        if ((rc = splat_taskq_test_order(&tq_arg, order1)))
                goto out;
 
        splat_vprint(file, SPLAT_TASKQ_TEST5_NAME, "Taskq '%s' "
                     "waiting for taskqid %d completion\n", tq_arg.name, 8);
-       taskq_wait_all(tq, 8);
+       taskq_wait_outstanding(tq, 8);
        rc = splat_taskq_test_order(&tq_arg, order2);
 
 out:
@@ -868,7 +873,7 @@ splat_taskq_test6_impl(struct file *file, void *arg, boolean_t prealloc)
                     "Taskq '%s' creating (%s dispatch)\n",
                     SPLAT_TASKQ_TEST6_NAME,
                     prealloc ? "prealloc" : "dynamic");
-       if ((tq = taskq_create(SPLAT_TASKQ_TEST6_NAME, 3, maxclsyspri,
+       if ((tq = taskq_create(SPLAT_TASKQ_TEST6_NAME, 3, defclsyspri,
                               50, INT_MAX, TASKQ_PREPOPULATE)) == NULL) {
                splat_vprint(file, SPLAT_TASKQ_TEST6_NAME,
                             "Taskq '%s' create failed\n",
@@ -923,7 +928,7 @@ splat_taskq_test6_impl(struct file *file, void *arg, boolean_t prealloc)
        splat_vprint(file, SPLAT_TASKQ_TEST6_NAME, "Taskq '%s' "
                     "waiting for taskqid %d completion\n", tq_arg.name,
                     SPLAT_TASKQ_ORDER_MAX);
-       taskq_wait_all(tq, SPLAT_TASKQ_ORDER_MAX);
+       taskq_wait_outstanding(tq, SPLAT_TASKQ_ORDER_MAX);
        rc = splat_taskq_test_order(&tq_arg, order);
 
 out:
@@ -1000,7 +1005,7 @@ splat_taskq_test7_impl(struct file *file, void *arg, boolean_t prealloc)
                     "Taskq '%s' creating (%s dispatch)\n",
                     SPLAT_TASKQ_TEST7_NAME,
                     prealloc ? "prealloc" :  "dynamic");
-       if ((tq = taskq_create(SPLAT_TASKQ_TEST7_NAME, 1, maxclsyspri,
+       if ((tq = taskq_create(SPLAT_TASKQ_TEST7_NAME, 1, defclsyspri,
                               50, INT_MAX, TASKQ_PREPOPULATE)) == NULL) {
                splat_vprint(file, SPLAT_TASKQ_TEST7_NAME,
                             "Taskq '%s' create failed\n",
@@ -1030,7 +1035,7 @@ splat_taskq_test7_impl(struct file *file, void *arg, boolean_t prealloc)
        if (tq_arg->flag == 0) {
                splat_vprint(file, SPLAT_TASKQ_TEST7_NAME,
                             "Taskq '%s' waiting\n", tq_arg->name);
-               taskq_wait_all(tq, SPLAT_TASKQ_DEPTH_MAX);
+               taskq_wait_outstanding(tq, SPLAT_TASKQ_DEPTH_MAX);
        }
 
        error = (tq_arg->depth == SPLAT_TASKQ_DEPTH_MAX ? 0 : -EINVAL);
@@ -1052,21 +1057,15 @@ splat_taskq_test7(struct file *file, void *arg)
 
        rc = splat_taskq_test7_impl(file, arg, B_FALSE);
        if (rc)
-               return rc;
+               return (rc);
 
        rc = splat_taskq_test7_impl(file, arg, B_TRUE);
 
-       return rc;
+       return (rc);
 }
 
-/*
- * Create a taskq with 100 threads and dispatch a huge number of trivial
- * tasks to generate contention on tq->tq_lock.  This test should always
- * pass.  The purpose is to provide a benchmark for measuring the
- * effectiveness of taskq optimizations.
- */
 static void
-splat_taskq_test8_func(void *arg)
+splat_taskq_throughput_func(void *arg)
 {
        splat_taskq_arg_t *tq_arg = (splat_taskq_arg_t *)arg;
        ASSERT(tq_arg);
@@ -1074,98 +1073,105 @@ splat_taskq_test8_func(void *arg)
        atomic_inc(tq_arg->count);
 }
 
-#define TEST8_NUM_TASKS                        0x20000
-#define TEST8_THREADS_PER_TASKQ                100
-
 static int
-splat_taskq_test8_common(struct file *file, void *arg, int minalloc,
-                         int maxalloc)
+splat_taskq_throughput(struct file *file, void *arg, const char *name,
+    int nthreads, int minalloc, int maxalloc, int flags, int tasks,
+    struct timespec *delta)
 {
        taskq_t *tq;
        taskqid_t id;
        splat_taskq_arg_t tq_arg;
        taskq_ent_t **tqes;
        atomic_t count;
+       struct timespec start, stop;
        int i, j, rc = 0;
 
-       tqes = vmalloc(sizeof(*tqes) * TEST8_NUM_TASKS);
+       tqes = vmalloc(sizeof (*tqes) * tasks);
        if (tqes == NULL)
-               return -ENOMEM;
-       memset(tqes, 0, sizeof(*tqes) * TEST8_NUM_TASKS);
-
-       splat_vprint(file, SPLAT_TASKQ_TEST8_NAME,
-                    "Taskq '%s' creating (%d/%d/%d)\n",
-                    SPLAT_TASKQ_TEST8_NAME,
-                    minalloc, maxalloc, TEST8_NUM_TASKS);
-       if ((tq = taskq_create(SPLAT_TASKQ_TEST8_NAME, TEST8_THREADS_PER_TASKQ,
-                              maxclsyspri, minalloc, maxalloc,
-                              TASKQ_PREPOPULATE)) == NULL) {
-               splat_vprint(file, SPLAT_TASKQ_TEST8_NAME,
-                            "Taskq '%s' create failed\n",
-                            SPLAT_TASKQ_TEST8_NAME);
+               return (-ENOMEM);
+
+       memset(tqes, 0, sizeof (*tqes) * tasks);
+
+       splat_vprint(file, name, "Taskq '%s' creating (%d/%d/%d/%d)\n",
+           name, nthreads, minalloc, maxalloc, tasks);
+       if ((tq = taskq_create(name, nthreads, defclsyspri,
+           minalloc, maxalloc, flags)) == NULL) {
+               splat_vprint(file, name, "Taskq '%s' create failed\n", name);
                rc = -EINVAL;
                goto out_free;
        }
 
        tq_arg.file = file;
-       tq_arg.name = SPLAT_TASKQ_TEST8_NAME;
+       tq_arg.name = name;
        tq_arg.count = &count;
        atomic_set(tq_arg.count, 0);
 
-       for (i = 0; i < TEST8_NUM_TASKS; i++) {
-               tqes[i] = kmalloc(sizeof(taskq_ent_t), GFP_KERNEL);
+       getnstimeofday(&start);
+
+       for (i = 0; i < tasks; i++) {
+               tqes[i] = kmalloc(sizeof (taskq_ent_t), GFP_KERNEL);
                if (tqes[i] == NULL) {
                        rc = -ENOMEM;
                        goto out;
                }
-               taskq_init_ent(tqes[i]);
-
-               taskq_dispatch_ent(tq, splat_taskq_test8_func,
-                                  &tq_arg, TQ_SLEEP, tqes[i]);
 
+               taskq_init_ent(tqes[i]);
+               taskq_dispatch_ent(tq, splat_taskq_throughput_func,
+                   &tq_arg, TQ_SLEEP, tqes[i]);
                id = tqes[i]->tqent_id;
 
                if (id == 0) {
-                       splat_vprint(file, SPLAT_TASKQ_TEST8_NAME,
-                               "Taskq '%s' function '%s' dispatch "
-                               "%d failed\n", tq_arg.name,
-                               sym2str(splat_taskq_test8_func), i);
-                               rc = -EINVAL;
-                               goto out;
+                       splat_vprint(file, name, "Taskq '%s' function '%s' "
+                           "dispatch %d failed\n", tq_arg.name,
+                           sym2str(splat_taskq_throughput_func), i);
+                       rc = -EINVAL;
+                       goto out;
                }
        }
 
-       splat_vprint(file, SPLAT_TASKQ_TEST8_NAME, "Taskq '%s' "
-                    "waiting for %d dispatches\n", tq_arg.name,
-                    TEST8_NUM_TASKS);
+       splat_vprint(file, name, "Taskq '%s' waiting for %d dispatches\n",
+           tq_arg.name, tasks);
+
        taskq_wait(tq);
-       splat_vprint(file, SPLAT_TASKQ_TEST8_NAME, "Taskq '%s' "
-                    "%d/%d dispatches finished\n", tq_arg.name,
-                    atomic_read(tq_arg.count), TEST8_NUM_TASKS);
 
-       if (atomic_read(tq_arg.count) != TEST8_NUM_TASKS)
+       if (delta != NULL) {
+               getnstimeofday(&stop);
+               *delta = timespec_sub(stop, start);
+       }
+
+       splat_vprint(file, name, "Taskq '%s' %d/%d dispatches finished\n",
+           tq_arg.name, atomic_read(tq_arg.count), tasks);
+
+       if (atomic_read(tq_arg.count) != tasks)
                rc = -ERANGE;
 
 out:
-       splat_vprint(file, SPLAT_TASKQ_TEST8_NAME, "Taskq '%s' destroying\n",
-                  tq_arg.name);
+       splat_vprint(file, name, "Taskq '%s' destroying\n", tq_arg.name);
        taskq_destroy(tq);
 out_free:
-       for (j = 0; j < TEST8_NUM_TASKS && tqes[j] != NULL; j++)
+       for (j = 0; j < tasks && tqes[j] != NULL; j++)
                kfree(tqes[j]);
+
        vfree(tqes);
 
-       return rc;
+       return (rc);
 }
 
+/*
+ * Create a taskq with 100 threads and dispatch a huge number of trivial
+ * tasks to generate contention on tq->tq_lock.  This test should always
+ * pass.  The purpose is to provide a benchmark for measuring the
+ * effectiveness of taskq optimizations.
+ */
+#define        TEST8_NUM_TASKS                 0x20000
+#define        TEST8_THREADS_PER_TASKQ         100
+
 static int
 splat_taskq_test8(struct file *file, void *arg)
 {
-       int rc;
-
-       rc = splat_taskq_test8_common(file, arg, 1, 100);
-
-       return rc;
+       return (splat_taskq_throughput(file, arg,
+           SPLAT_TASKQ_TEST8_NAME, TEST8_THREADS_PER_TASKQ,
+           1, INT_MAX, TASKQ_PREPOPULATE, TEST8_NUM_TASKS, NULL));
 }
 
 /*
@@ -1197,7 +1203,7 @@ splat_taskq_test9(struct file *file, void *arg)
        splat_vprint(file, SPLAT_TASKQ_TEST9_NAME,
            "Taskq '%s' creating (%s dispatch) (%d/%d/%d)\n",
            SPLAT_TASKQ_TEST9_NAME, "delay", minalloc, maxalloc, nr_tasks);
-       if ((tq = taskq_create(SPLAT_TASKQ_TEST9_NAME, 3, maxclsyspri,
+       if ((tq = taskq_create(SPLAT_TASKQ_TEST9_NAME, 3, defclsyspri,
            minalloc, maxalloc, TASKQ_PREPOPULATE)) == NULL) {
                splat_vprint(file, SPLAT_TASKQ_TEST9_NAME,
                    "Taskq '%s' create failed\n", SPLAT_TASKQ_TEST9_NAME);
@@ -1297,7 +1303,7 @@ splat_taskq_test10(struct file *file, void *arg)
        splat_vprint(file, SPLAT_TASKQ_TEST10_NAME,
            "Taskq '%s' creating (%s dispatch) (%d/%d/%d)\n",
            SPLAT_TASKQ_TEST10_NAME, "delay", minalloc, maxalloc, nr_tasks);
-       if ((tq = taskq_create(SPLAT_TASKQ_TEST10_NAME, 3, maxclsyspri,
+       if ((tq = taskq_create(SPLAT_TASKQ_TEST10_NAME, 3, defclsyspri,
            minalloc, maxalloc, TASKQ_PREPOPULATE)) == NULL) {
                splat_vprint(file, SPLAT_TASKQ_TEST10_NAME,
                    "Taskq '%s' create failed\n", SPLAT_TASKQ_TEST10_NAME);
@@ -1433,6 +1439,46 @@ out_free:
        return rc;
 }
 
+/*
+ * Create a dynamic taskq with 100 threads and dispatch a huge number of
+ * trivial tasks.  This will cause the taskq to grow quickly to its max
+ * thread count.  This test should always pass.  The purpose is to provide
+ * a benchmark for measuring the performance of dynamic taskqs.
+ */
+#define        TEST11_NUM_TASKS                        100000
+#define        TEST11_THREADS_PER_TASKQ                100
+
+static int
+splat_taskq_test11(struct file *file, void *arg)
+{
+       struct timespec normal, dynamic;
+       int error;
+
+       error = splat_taskq_throughput(file, arg, SPLAT_TASKQ_TEST11_NAME,
+           TEST11_THREADS_PER_TASKQ, 1, INT_MAX,
+           TASKQ_PREPOPULATE, TEST11_NUM_TASKS, &normal);
+       if (error)
+               return (error);
+
+       error = splat_taskq_throughput(file, arg, SPLAT_TASKQ_TEST11_NAME,
+           TEST11_THREADS_PER_TASKQ, 1, INT_MAX,
+           TASKQ_PREPOPULATE | TASKQ_DYNAMIC, TEST11_NUM_TASKS, &dynamic);
+       if (error)
+               return (error);
+
+       splat_vprint(file, SPLAT_TASKQ_TEST11_NAME,
+           "Timing taskq_wait(): normal=%ld.%09lds, dynamic=%ld.%09lds\n",
+           normal.tv_sec, normal.tv_nsec,
+           dynamic.tv_sec, dynamic.tv_nsec);
+
+       /* A 10x increase in runtime is used to indicate a core problem. */
+       if ((dynamic.tv_sec * NANOSEC + dynamic.tv_nsec) >
+           ((normal.tv_sec * NANOSEC + normal.tv_nsec) * 10))
+               error = -ETIME;
+
+       return (error);
+}
+
 splat_subsystem_t *
 splat_taskq_init(void)
 {
@@ -1470,6 +1516,8 @@ splat_taskq_init(void)
                      SPLAT_TASKQ_TEST9_ID, splat_taskq_test9);
        SPLAT_TEST_INIT(sub, SPLAT_TASKQ_TEST10_NAME, SPLAT_TASKQ_TEST10_DESC,
                      SPLAT_TASKQ_TEST10_ID, splat_taskq_test10);
+       SPLAT_TEST_INIT(sub, SPLAT_TASKQ_TEST11_NAME, SPLAT_TASKQ_TEST11_DESC,
+                     SPLAT_TASKQ_TEST11_ID, splat_taskq_test11);
 
         return sub;
 }
@@ -1478,6 +1526,7 @@ void
 splat_taskq_fini(splat_subsystem_t *sub)
 {
         ASSERT(sub);
+       SPLAT_TEST_FINI(sub, SPLAT_TASKQ_TEST11_ID);
        SPLAT_TEST_FINI(sub, SPLAT_TASKQ_TEST10_ID);
        SPLAT_TEST_FINI(sub, SPLAT_TASKQ_TEST9_ID);
        SPLAT_TEST_FINI(sub, SPLAT_TASKQ_TEST8_ID);
index 3255e37e5b8d515ba2dd607dcbd0c8615baf8dcc..8a44714078d4d5eae7461835703ea97fe1c1e636 100644 (file)
@@ -112,7 +112,7 @@ splat_thread_test1(struct file *file, void *arg)
        tp.tp_rc = 0;
 
        thr = (kthread_t *)thread_create(NULL, 0, splat_thread_work1, &tp, 0,
-                                        &p0, TS_RUN, minclsyspri);
+                                        &p0, TS_RUN, defclsyspri);
        /* Must never fail under Solaris, but we check anyway since this
         * can happen in the linux SPL, we may want to change this behavior */
        if (thr == NULL)
@@ -161,7 +161,7 @@ splat_thread_test2(struct file *file, void *arg)
        tp.tp_rc = 0;
 
        thr = (kthread_t *)thread_create(NULL, 0, splat_thread_work2, &tp, 0,
-                                        &p0, TS_RUN, minclsyspri);
+                                        &p0, TS_RUN, defclsyspri);
        /* Must never fail under Solaris, but we check anyway since this
         * can happen in the linux SPL, we may want to change this behavior */
        if (thr == NULL)
@@ -278,7 +278,7 @@ splat_thread_test3(struct file *file, void *arg)
        /* Start tsd wait threads */
        for (i = 0; i < SPLAT_THREAD_TEST_THREADS; i++) {
                if (thread_create(NULL, 0, splat_thread_work3_wait,
-                                 &tp, 0, &p0, TS_RUN, minclsyspri))
+                                 &tp, 0, &p0, TS_RUN, defclsyspri))
                        wait_count++;
        }
 
@@ -295,7 +295,7 @@ splat_thread_test3(struct file *file, void *arg)
        /* Start tsd exit threads */
        for (i = 0; i < SPLAT_THREAD_TEST_THREADS; i++) {
                if (thread_create(NULL, 0, splat_thread_work3_exit,
-                                 &tp, 0, &p0, TS_RUN, minclsyspri))
+                                 &tp, 0, &p0, TS_RUN, defclsyspri))
                        exit_count++;
        }
 
index f3f17ec9256677c2adf12c0a250a7d2516ac5885..bffcf492ff5dae3c607f7cb9a2c37f0feb30f406 100644 (file)
@@ -223,6 +223,7 @@ out:
         return -rc;
 } /* splat_vnode_test3() */
 
+#if LINUX_VERSION_CODE <= KERNEL_VERSION(4,1,0)
 static int
 splat_vnode_test4(struct file *file, void *arg)
 {
@@ -303,6 +304,7 @@ out:
 
         return -rc;
 } /* splat_vnode_test4() */
+#endif
 
 static int
 splat_vnode_test5(struct file *file, void *arg)
@@ -413,8 +415,10 @@ splat_vnode_init(void)
                        SPLAT_VNODE_TEST2_ID, splat_vnode_test2);
         SPLAT_TEST_INIT(sub, SPLAT_VNODE_TEST3_NAME, SPLAT_VNODE_TEST3_DESC,
                        SPLAT_VNODE_TEST3_ID, splat_vnode_test3);
+#if LINUX_VERSION_CODE <= KERNEL_VERSION(4,1,0)
         SPLAT_TEST_INIT(sub, SPLAT_VNODE_TEST4_NAME, SPLAT_VNODE_TEST4_DESC,
                        SPLAT_VNODE_TEST4_ID, splat_vnode_test4);
+#endif
         SPLAT_TEST_INIT(sub, SPLAT_VNODE_TEST5_NAME, SPLAT_VNODE_TEST5_DESC,
                        SPLAT_VNODE_TEST5_ID, splat_vnode_test5);
         SPLAT_TEST_INIT(sub, SPLAT_VNODE_TEST6_NAME, SPLAT_VNODE_TEST6_DESC,
@@ -430,7 +434,9 @@ splat_vnode_fini(splat_subsystem_t *sub)
 
         SPLAT_TEST_FINI(sub, SPLAT_VNODE_TEST6_ID);
         SPLAT_TEST_FINI(sub, SPLAT_VNODE_TEST5_ID);
+#if LINUX_VERSION_CODE <= KERNEL_VERSION(4,1,0)
         SPLAT_TEST_FINI(sub, SPLAT_VNODE_TEST4_ID);
+#endif
         SPLAT_TEST_FINI(sub, SPLAT_VNODE_TEST3_ID);
         SPLAT_TEST_FINI(sub, SPLAT_VNODE_TEST2_ID);
         SPLAT_TEST_FINI(sub, SPLAT_VNODE_TEST1_ID);
index 6d8e058cb01acb3244c0700baf05bed2df683bfd..949660ebc024d171b5eaa545381412442728ef5b 100644 (file)
@@ -62,14 +62,8 @@ echo -e "support or upgrade DKMS to a more current version."
 exit 1
 
 %preun
-# Only remove the modules if they are for this %{version}-%{release}.  A
-# package upgrade can replace them if only the %{release} is changed.
-RELEASE="/var/lib/dkms/%{module}/%{version}/build/%{module}.release"
-if [ -f $RELEASE ] && [ `cat $RELEASE`%{?dist} = "%{version}-%{release}" ]; then
-    echo -e
-    echo -e "Uninstall of %{module} module (version %{version}) beginning:"
-    dkms remove -m %{module} -v %{version} --all --rpm_safe_upgrade
-fi
+echo -e "Uninstall of %{module} module (version %{version}) beginning:"
+dkms remove -m %{module} -v %{version} --all --rpm_safe_upgrade
 exit 0
 
 %changelog
index d95e2df58d579a70ea0a7df9c3e99380706a1361..8a28e0822f41b62727be88e536586d66b694e986 100644 (file)
@@ -160,9 +160,15 @@ chmod u+x ${RPM_BUILD_ROOT}%{kmodinstdir_prefix}/*/extra/*/*/*
 rm -rf $RPM_BUILD_ROOT
 
 %changelog
-* Wed Jun  24 2015 Ned Bass <bass6@llnl.gov> - 0.6.4.2-1
-- No changes from 0.6.4-1
-- Bump version to match ZFS release
+* Tue Sep 29 2015 Ned Bass <bass6@llnl.gov> - 0.6.5.2-1
+- Released 0.6.5.2-1
+- Fix PAX Patch/Grsec SLAB_USERCOPY panic zfsonlinux/zfs#3796
+- Always remove during dkms uninstall/update zfsonlinux/spl#476
+* Thu Sep 19 2015 Ned Bass <bass6@llnl.gov> - 0.6.5.1-1
+- Released 0.6.5.1-1, no changes from spl-0.6.5
+* Thu Sep 10 2015 Brian Behlendorf <behlendorf1@llnl.gov> - 0.6.5-1
+- Released 0.6.5-1, detailed release notes are available at:
+- https://github.com/zfsonlinux/zfs/releases/tag/zfs-0.6.5
 * Wed Apr  8 2015 Brian Behlendorf <behlendorf1@llnl.gov> - 0.6.4-1
 - Released 0.6.4-1
 * Thu Jun 12 2014 Brian Behlendorf <behlendorf1@llnl.gov> - 0.6.3-1
index 1faeba965e52b368f32d50ca8023a2a38c334e95..89e7e59c5db8f68651e13226b7db98d63303c311 100644 (file)
@@ -38,9 +38,15 @@ make install DESTDIR=%{?buildroot}
 %{_mandir}/man5/*
 
 %changelog
-* Wed Jun  24 2015 Ned Bass <bass6@llnl.gov> - 0.6.4.2-1
-- No changes from 0.6.4-1
-- Bump version to match ZFS release
+* Tue Sep 29 2015 Ned Bass <bass6@llnl.gov> - 0.6.5.2-1
+- Released 0.6.5.2-1
+- Fix PAX Patch/Grsec SLAB_USERCOPY panic zfsonlinux/zfs#3796
+- Always remove during dkms uninstall/update zfsonlinux/spl#476
+* Thu Sep 19 2015 Ned Bass <bass6@llnl.gov> - 0.6.5.1-1
+- Released 0.6.5.1-1, no changes from spl-0.6.5
+* Thu Sep 10 2015 Brian Behlendorf <behlendorf1@llnl.gov> - 0.6.5-1
+- Released 0.6.5-1, detailed release notes are available at:
+- https://github.com/zfsonlinux/zfs/releases/tag/zfs-0.6.5
 * Wed Apr  8 2015 Brian Behlendorf <behlendorf1@llnl.gov> - 0.6.4-1
 - Released 0.6.4-1
 * Thu Jun 12 2014 Brian Behlendorf <behlendorf1@llnl.gov> - 0.6.3-1
index 6d8e058cb01acb3244c0700baf05bed2df683bfd..949660ebc024d171b5eaa545381412442728ef5b 100644 (file)
@@ -62,14 +62,8 @@ echo -e "support or upgrade DKMS to a more current version."
 exit 1
 
 %preun
-# Only remove the modules if they are for this %{version}-%{release}.  A
-# package upgrade can replace them if only the %{release} is changed.
-RELEASE="/var/lib/dkms/%{module}/%{version}/build/%{module}.release"
-if [ -f $RELEASE ] && [ `cat $RELEASE`%{?dist} = "%{version}-%{release}" ]; then
-    echo -e
-    echo -e "Uninstall of %{module} module (version %{version}) beginning:"
-    dkms remove -m %{module} -v %{version} --all --rpm_safe_upgrade
-fi
+echo -e "Uninstall of %{module} module (version %{version}) beginning:"
+dkms remove -m %{module} -v %{version} --all --rpm_safe_upgrade
 exit 0
 
 %changelog
index 1faeba965e52b368f32d50ca8023a2a38c334e95..89e7e59c5db8f68651e13226b7db98d63303c311 100644 (file)
@@ -38,9 +38,15 @@ make install DESTDIR=%{?buildroot}
 %{_mandir}/man5/*
 
 %changelog
-* Wed Jun  24 2015 Ned Bass <bass6@llnl.gov> - 0.6.4.2-1
-- No changes from 0.6.4-1
-- Bump version to match ZFS release
+* Tue Sep 29 2015 Ned Bass <bass6@llnl.gov> - 0.6.5.2-1
+- Released 0.6.5.2-1
+- Fix PAX Patch/Grsec SLAB_USERCOPY panic zfsonlinux/zfs#3796
+- Always remove during dkms uninstall/update zfsonlinux/spl#476
+* Thu Sep 19 2015 Ned Bass <bass6@llnl.gov> - 0.6.5.1-1
+- Released 0.6.5.1-1, no changes from spl-0.6.5
+* Thu Sep 10 2015 Brian Behlendorf <behlendorf1@llnl.gov> - 0.6.5-1
+- Released 0.6.5-1, detailed release notes are available at:
+- https://github.com/zfsonlinux/zfs/releases/tag/zfs-0.6.5
 * Wed Apr  8 2015 Brian Behlendorf <behlendorf1@llnl.gov> - 0.6.4-1
 - Released 0.6.4-1
 * Thu Jun 12 2014 Brian Behlendorf <behlendorf1@llnl.gov> - 0.6.3-1
index f146ec6e674a4cf76f3bd038edc42a1b26938e2b..a718c4b1abf97e5b0478dc79152c7219b1449d74 100644 (file)
@@ -1,4 +1,4 @@
 EXTRA_DIST = check.sh dkms.mkconf dkms.postbuild kmodtool
 
 check:
-       $(top_srcdir)/scripts/check.sh
+       scripts/check.sh
index 4890832b7b496da618dd3c52ecfec4c683d4b437..8222867f253e937c16d2ec00fc661cfc198962d1 100644 (file)
@@ -418,7 +418,7 @@ uninstall-am:
 
 
 check:
-       $(top_srcdir)/scripts/check.sh
+       scripts/check.sh
 
 # Tell versions [3.59,3.63) of GNU make to not export all variables.
 # Otherwise a system limit (for SysV at least) may be exceeded.
index 858636c5998e2279b1a84785ed59570f7a846164..cfd94db79c4496b79a0b3f5fbc6114ec3340fd7f 100644 (file)
 /* Define to the version of this package. */
 #undef PACKAGE_VERSION
 
-/* rwsem_is_locked() acquires sem->wait_lock */
-#undef RWSEM_IS_LOCKED_TAKES_WAIT_LOCK
-
 /* struct rw_semaphore member wait_lock is raw_spinlock_t */
 #undef RWSEM_SPINLOCK_IS_RAW