diff options
author | Brian Behlendorf <[email protected]> | 2018-02-14 17:01:15 -0800 |
---|---|---|
committer | Brian Behlendorf <[email protected]> | 2018-05-29 14:51:39 -0700 |
commit | a91258913fb597db7f409f3534512cf2249bceb6 (patch) | |
tree | 7c489b0ed42187c10046f52fe8f2e4883f884db1 /module | |
parent | 1149b62d20b7ed9d8ae25d5da7a06213d79b7602 (diff) |
Prepare SPL repo to merge with ZFS repo
This commit removes everything from the repository except the core
SPL implementation for Linux. Those files which remain have been
moved to non-conflicting locations to facilitate the merge.
The README.md and associated files have been updated accordingly.
Signed-off-by: Brian Behlendorf <[email protected]>
Diffstat (limited to 'module')
32 files changed, 430 insertions, 8637 deletions
diff --git a/module/.gitignore b/module/.gitignore deleted file mode 100644 index 907099287..000000000 --- a/module/.gitignore +++ /dev/null @@ -1,13 +0,0 @@ -*.ko -*.ko.unsigned -*.ko.out -*.ko.out.sig -*.mod.c -.*.cmd -modules.order - -/.tmp_versions -/Module.markers -/Module.symvers - -!Makefile.in diff --git a/module/Makefile.in b/module/Makefile.in deleted file mode 100644 index d4e62e152..000000000 --- a/module/Makefile.in +++ /dev/null @@ -1,54 +0,0 @@ -subdir-m += spl -subdir-m += splat - -INSTALL_MOD_DIR ?= extra - -SPL_MODULE_CFLAGS = -I@abs_top_srcdir@/include -SPL_MODULE_CFLAGS += -include @abs_top_builddir@/spl_config.h -export SPL_MODULE_CFLAGS - -modules: - $(MAKE) -C @LINUX_OBJ@ SUBDIRS=`pwd` @KERNELMAKE_PARAMS@ CONFIG_SPL=m $@ - -clean: - @# Only cleanup the kernel build directories when CONFIG_KERNEL - @# is defined. This indicates that kernel modules should be built. -@CONFIG_KERNEL_TRUE@ $(MAKE) -C @LINUX_OBJ@ SUBDIRS=`pwd` @KERNELMAKE_PARAMS@ $@ - - if [ -f @LINUX_SYMBOLS@ ]; then $(RM) @LINUX_SYMBOLS@; fi - if [ -f Module.markers ]; then $(RM) Module.markers; fi - -modules_install: - @# Install the kernel modules - $(MAKE) -C @LINUX_OBJ@ SUBDIRS=`pwd` $@ \ - INSTALL_MOD_PATH=$(DESTDIR)$(INSTALL_MOD_PATH) \ - INSTALL_MOD_DIR=$(INSTALL_MOD_DIR) \ - KERNELRELEASE=@LINUX_VERSION@ - @# Remove extraneous build products when packaging - kmoddir=$(DESTDIR)$(INSTALL_MOD_PATH)/lib/modules/@LINUX_VERSION@; \ - if [ -n "$(DESTDIR)" ]; then \ - find $$kmoddir -name 'modules.*' | xargs $(RM); \ - fi - sysmap=$(DESTDIR)$(INSTALL_MOD_PATH)/boot/System.map-@LINUX_VERSION@; \ - if [ -f $$sysmap ]; then \ - depmod -ae -F $$sysmap @LINUX_VERSION@; \ - fi - -modules_uninstall: - @# Uninstall the kernel modules - kmoddir=$(DESTDIR)$(INSTALL_MOD_PATH)/lib/modules/@LINUX_VERSION@ - list='$(subdir-m)'; for subdir in $$list; do \ - $(RM) -R $$kmoddir/$(INSTALL_MOD_DIR)/$$subdir; \ - done - -distdir: - list='$(subdir-m)'; for subdir in $$list; do \ - (find @top_srcdir@/module/$$subdir -name '*.c' -o -name '*.h' |\ - xargs /bin/cp -t $$distdir/$$subdir); \ - done - -distclean maintainer-clean: clean -install: modules_install -uninstall: modules_uninstall -all: modules -check: diff --git a/module/spl/Makefile.in b/module/spl/Makefile.in deleted file mode 100644 index a1f1ab823..000000000 --- a/module/spl/Makefile.in +++ /dev/null @@ -1,30 +0,0 @@ -# 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 += 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 diff --git a/module/spl/THIRDPARTYLICENSE.gplv2 b/module/spl/THIRDPARTYLICENSE.gplv2 new file mode 100644 index 000000000..d159169d1 --- /dev/null +++ b/module/spl/THIRDPARTYLICENSE.gplv2 @@ -0,0 +1,339 @@ + GNU GENERAL PUBLIC LICENSE + Version 2, June 1991 + + Copyright (C) 1989, 1991 Free Software Foundation, Inc., + 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + Everyone is permitted to copy and distribute verbatim copies + of this license document, but changing it is not allowed. + + Preamble + + The licenses for most software are designed to take away your +freedom to share and change it. By contrast, the GNU General Public +License is intended to guarantee your freedom to share and change free +software--to make sure the software is free for all its users. This +General Public License applies to most of the Free Software +Foundation's software and to any other program whose authors commit to +using it. (Some other Free Software Foundation software is covered by +the GNU Lesser General Public License instead.) You can apply it to +your programs, too. + + When we speak of free software, we are referring to freedom, not +price. Our General Public Licenses are designed to make sure that you +have the freedom to distribute copies of free software (and charge for +this service if you wish), that you receive source code or can get it +if you want it, that you can change the software or use pieces of it +in new free programs; and that you know you can do these things. + + To protect your rights, we need to make restrictions that forbid +anyone to deny you these rights or to ask you to surrender the rights. +These restrictions translate to certain responsibilities for you if you +distribute copies of the software, or if you modify it. + + For example, if you distribute copies of such a program, whether +gratis or for a fee, you must give the recipients all the rights that +you have. You must make sure that they, too, receive or can get the +source code. And you must show them these terms so they know their +rights. + + We protect your rights with two steps: (1) copyright the software, and +(2) offer you this license which gives you legal permission to copy, +distribute and/or modify the software. + + Also, for each author's protection and ours, we want to make certain +that everyone understands that there is no warranty for this free +software. If the software is modified by someone else and passed on, we +want its recipients to know that what they have is not the original, so +that any problems introduced by others will not reflect on the original +authors' reputations. + + Finally, any free program is threatened constantly by software +patents. We wish to avoid the danger that redistributors of a free +program will individually obtain patent licenses, in effect making the +program proprietary. To prevent this, we have made it clear that any +patent must be licensed for everyone's free use or not licensed at all. + + The precise terms and conditions for copying, distribution and +modification follow. + + GNU GENERAL PUBLIC LICENSE + TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION + + 0. This License applies to any program or other work which contains +a notice placed by the copyright holder saying it may be distributed +under the terms of this General Public License. The "Program", below, +refers to any such program or work, and a "work based on the Program" +means either the Program or any derivative work under copyright law: +that is to say, a work containing the Program or a portion of it, +either verbatim or with modifications and/or translated into another +language. (Hereinafter, translation is included without limitation in +the term "modification".) Each licensee is addressed as "you". + +Activities other than copying, distribution and modification are not +covered by this License; they are outside its scope. The act of +running the Program is not restricted, and the output from the Program +is covered only if its contents constitute a work based on the +Program (independent of having been made by running the Program). +Whether that is true depends on what the Program does. + + 1. You may copy and distribute verbatim copies of the Program's +source code as you receive it, in any medium, provided that you +conspicuously and appropriately publish on each copy an appropriate +copyright notice and disclaimer of warranty; keep intact all the +notices that refer to this License and to the absence of any warranty; +and give any other recipients of the Program a copy of this License +along with the Program. + +You may charge a fee for the physical act of transferring a copy, and +you may at your option offer warranty protection in exchange for a fee. + + 2. You may modify your copy or copies of the Program or any portion +of it, thus forming a work based on the Program, and copy and +distribute such modifications or work under the terms of Section 1 +above, provided that you also meet all of these conditions: + + a) You must cause the modified files to carry prominent notices + stating that you changed the files and the date of any change. + + b) You must cause any work that you distribute or publish, that in + whole or in part contains or is derived from the Program or any + part thereof, to be licensed as a whole at no charge to all third + parties under the terms of this License. + + c) If the modified program normally reads commands interactively + when run, you must cause it, when started running for such + interactive use in the most ordinary way, to print or display an + announcement including an appropriate copyright notice and a + notice that there is no warranty (or else, saying that you provide + a warranty) and that users may redistribute the program under + these conditions, and telling the user how to view a copy of this + License. (Exception: if the Program itself is interactive but + does not normally print such an announcement, your work based on + the Program is not required to print an announcement.) + +These requirements apply to the modified work as a whole. If +identifiable sections of that work are not derived from the Program, +and can be reasonably considered independent and separate works in +themselves, then this License, and its terms, do not apply to those +sections when you distribute them as separate works. But when you +distribute the same sections as part of a whole which is a work based +on the Program, the distribution of the whole must be on the terms of +this License, whose permissions for other licensees extend to the +entire whole, and thus to each and every part regardless of who wrote it. + +Thus, it is not the intent of this section to claim rights or contest +your rights to work written entirely by you; rather, the intent is to +exercise the right to control the distribution of derivative or +collective works based on the Program. + +In addition, mere aggregation of another work not based on the Program +with the Program (or with a work based on the Program) on a volume of +a storage or distribution medium does not bring the other work under +the scope of this License. + + 3. You may copy and distribute the Program (or a work based on it, +under Section 2) in object code or executable form under the terms of +Sections 1 and 2 above provided that you also do one of the following: + + a) Accompany it with the complete corresponding machine-readable + source code, which must be distributed under the terms of Sections + 1 and 2 above on a medium customarily used for software interchange; or, + + b) Accompany it with a written offer, valid for at least three + years, to give any third party, for a charge no more than your + cost of physically performing source distribution, a complete + machine-readable copy of the corresponding source code, to be + distributed under the terms of Sections 1 and 2 above on a medium + customarily used for software interchange; or, + + c) Accompany it with the information you received as to the offer + to distribute corresponding source code. (This alternative is + allowed only for noncommercial distribution and only if you + received the program in object code or executable form with such + an offer, in accord with Subsection b above.) + +The source code for a work means the preferred form of the work for +making modifications to it. For an executable work, complete source +code means all the source code for all modules it contains, plus any +associated interface definition files, plus the scripts used to +control compilation and installation of the executable. However, as a +special exception, the source code distributed need not include +anything that is normally distributed (in either source or binary +form) with the major components (compiler, kernel, and so on) of the +operating system on which the executable runs, unless that component +itself accompanies the executable. + +If distribution of executable or object code is made by offering +access to copy from a designated place, then offering equivalent +access to copy the source code from the same place counts as +distribution of the source code, even though third parties are not +compelled to copy the source along with the object code. + + 4. You may not copy, modify, sublicense, or distribute the Program +except as expressly provided under this License. Any attempt +otherwise to copy, modify, sublicense or distribute the Program is +void, and will automatically terminate your rights under this License. +However, parties who have received copies, or rights, from you under +this License will not have their licenses terminated so long as such +parties remain in full compliance. + + 5. You are not required to accept this License, since you have not +signed it. However, nothing else grants you permission to modify or +distribute the Program or its derivative works. These actions are +prohibited by law if you do not accept this License. Therefore, by +modifying or distributing the Program (or any work based on the +Program), you indicate your acceptance of this License to do so, and +all its terms and conditions for copying, distributing or modifying +the Program or works based on it. + + 6. Each time you redistribute the Program (or any work based on the +Program), the recipient automatically receives a license from the +original licensor to copy, distribute or modify the Program subject to +these terms and conditions. You may not impose any further +restrictions on the recipients' exercise of the rights granted herein. +You are not responsible for enforcing compliance by third parties to +this License. + + 7. If, as a consequence of a court judgment or allegation of patent +infringement or for any other reason (not limited to patent issues), +conditions are imposed on you (whether by court order, agreement or +otherwise) that contradict the conditions of this License, they do not +excuse you from the conditions of this License. If you cannot +distribute so as to satisfy simultaneously your obligations under this +License and any other pertinent obligations, then as a consequence you +may not distribute the Program at all. For example, if a patent +license would not permit royalty-free redistribution of the Program by +all those who receive copies directly or indirectly through you, then +the only way you could satisfy both it and this License would be to +refrain entirely from distribution of the Program. + +If any portion of this section is held invalid or unenforceable under +any particular circumstance, the balance of the section is intended to +apply and the section as a whole is intended to apply in other +circumstances. + +It is not the purpose of this section to induce you to infringe any +patents or other property right claims or to contest validity of any +such claims; this section has the sole purpose of protecting the +integrity of the free software distribution system, which is +implemented by public license practices. Many people have made +generous contributions to the wide range of software distributed +through that system in reliance on consistent application of that +system; it is up to the author/donor to decide if he or she is willing +to distribute software through any other system and a licensee cannot +impose that choice. + +This section is intended to make thoroughly clear what is believed to +be a consequence of the rest of this License. + + 8. If the distribution and/or use of the Program is restricted in +certain countries either by patents or by copyrighted interfaces, the +original copyright holder who places the Program under this License +may add an explicit geographical distribution limitation excluding +those countries, so that distribution is permitted only in or among +countries not thus excluded. In such case, this License incorporates +the limitation as if written in the body of this License. + + 9. The Free Software Foundation may publish revised and/or new versions +of the General Public License from time to time. Such new versions will +be similar in spirit to the present version, but may differ in detail to +address new problems or concerns. + +Each version is given a distinguishing version number. If the Program +specifies a version number of this License which applies to it and "any +later version", you have the option of following the terms and conditions +either of that version or of any later version published by the Free +Software Foundation. If the Program does not specify a version number of +this License, you may choose any version ever published by the Free Software +Foundation. + + 10. If you wish to incorporate parts of the Program into other free +programs whose distribution conditions are different, write to the author +to ask for permission. For software which is copyrighted by the Free +Software Foundation, write to the Free Software Foundation; we sometimes +make exceptions for this. Our decision will be guided by the two goals +of preserving the free status of all derivatives of our free software and +of promoting the sharing and reuse of software generally. + + NO WARRANTY + + 11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY +FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN +OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES +PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED +OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF +MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS +TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE +PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING, +REPAIR OR CORRECTION. + + 12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING +WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR +REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, +INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING +OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED +TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY +YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER +PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE +POSSIBILITY OF SUCH DAMAGES. + + END OF TERMS AND CONDITIONS + + How to Apply These Terms to Your New Programs + + If you develop a new program, and you want it to be of the greatest +possible use to the public, the best way to achieve this is to make it +free software which everyone can redistribute and change under these terms. + + To do so, attach the following notices to the program. It is safest +to attach them to the start of each source file to most effectively +convey the exclusion of warranty; and each file should have at least +the "copyright" line and a pointer to where the full notice is found. + + <one line to give the program's name and a brief idea of what it does.> + Copyright (C) <year> <name of author> + + This program 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. + + This program 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 this program; if not, write to the Free Software Foundation, Inc., + 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + +Also add information on how to contact you by electronic and paper mail. + +If the program is interactive, make it output a short notice like this +when it starts in an interactive mode: + + Gnomovision version 69, Copyright (C) year name of author + Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'. + This is free software, and you are welcome to redistribute it + under certain conditions; type `show c' for details. + +The hypothetical commands `show w' and `show c' should show the appropriate +parts of the General Public License. Of course, the commands you use may +be called something other than `show w' and `show c'; they could even be +mouse-clicks or menu items--whatever suits your program. + +You should also get your employer (if you work as a programmer) or your +school, if any, to sign a "copyright disclaimer" for the program, if +necessary. Here is a sample; alter the names: + + Yoyodyne, Inc., hereby disclaims all copyright interest in the program + `Gnomovision' (which makes passes at compilers) written by James Hacker. + + <signature of Ty Coon>, 1 April 1989 + Ty Coon, President of Vice + +This General Public License does not permit incorporating your program into +proprietary programs. If your program is a subroutine library, you may +consider it more useful to permit linking proprietary applications with the +library. If this is what you want to do, use the GNU Lesser General +Public License instead of this License. diff --git a/module/spl/THIRDPARTYLICENSE.gplv2.descrip b/module/spl/THIRDPARTYLICENSE.gplv2.descrip new file mode 100644 index 000000000..78535a8ee --- /dev/null +++ b/module/spl/THIRDPARTYLICENSE.gplv2.descrip @@ -0,0 +1 @@ +COMPATIBILITY LAYER FOR OPENZFS ON LINUX diff --git a/module/spl/spl-generic.c b/module/spl/spl-generic.c index 2a8972691..b38fe254c 100644 --- a/module/spl/spl-generic.c +++ b/module/spl/spl-generic.c @@ -43,9 +43,8 @@ #include <linux/ctype.h> #include <sys/disp.h> #include <sys/random.h> +#include <sys/strings.h> #include <linux/kmod.h> -#include <linux/math64_compat.h> -#include <linux/proc_compat.h> char spl_version[32] = "SPL v" SPL_META_VERSION "-" SPL_META_RELEASE; EXPORT_SYMBOL(spl_version); @@ -260,6 +259,12 @@ __udivdi3(uint64_t u, uint64_t v) } EXPORT_SYMBOL(__udivdi3); +/* BEGIN CSTYLED */ +#ifndef abs64 +#define abs64(x) ({ uint64_t t = (x) >> 63; ((x) ^ t) - t; }) +#endif +/* END CSTYLED */ + /* * Implementation of 64-bit signed division for 32-bit machines. */ diff --git a/module/spl/spl-kmem-cache.c b/module/spl/spl-kmem-cache.c index c73a2fdc2..5492c6a46 100644 --- a/module/spl/spl-kmem-cache.c +++ b/module/spl/spl-kmem-cache.c @@ -24,13 +24,13 @@ #include <sys/kmem.h> #include <sys/kmem_cache.h> +#include <sys/shrinker.h> #include <sys/taskq.h> #include <sys/timer.h> #include <sys/vmem.h> +#include <sys/wait.h> #include <linux/slab.h> #include <linux/swap.h> -#include <linux/mm_compat.h> -#include <linux/wait_compat.h> #include <linux/prefetch.h> /* diff --git a/module/spl/spl-kstat.c b/module/spl/spl-kstat.c index 10e93f318..bcbff94a6 100644 --- a/module/spl/spl-kstat.c +++ b/module/spl/spl-kstat.c @@ -28,6 +28,7 @@ #include <sys/kstat.h> #include <sys/vmem.h> #include <sys/cmn_err.h> +#include <sys/sysmacros.h> #ifndef HAVE_PDE_DATA #define PDE_DATA(x) (PDE(x)->data) diff --git a/module/spl/spl-proc.c b/module/spl/spl-proc.c index 796f69e48..9c52924a4 100644 --- a/module/spl/spl-proc.c +++ b/module/spl/spl-proc.c @@ -30,10 +30,10 @@ #include <sys/kmem_cache.h> #include <sys/vmem.h> #include <sys/taskq.h> +#include <sys/proc.h> #include <linux/ctype.h> #include <linux/kmod.h> #include <linux/seq_file.h> -#include <linux/proc_compat.h> #include <linux/uaccess.h> #include <linux/version.h> diff --git a/module/spl/spl-vmem.c b/module/spl/spl-vmem.c index dd10607dc..e1a84a911 100644 --- a/module/spl/spl-vmem.c +++ b/module/spl/spl-vmem.c @@ -25,7 +25,7 @@ #include <sys/debug.h> #include <sys/vmem.h> #include <sys/kmem_cache.h> -#include <linux/mm_compat.h> +#include <sys/shrinker.h> #include <linux/module.h> vmem_t *heap_arena = NULL; diff --git a/module/spl/spl-vnode.c b/module/spl/spl-vnode.c index a371fb966..28ce21276 100644 --- a/module/spl/spl-vnode.c +++ b/module/spl/spl-vnode.c @@ -28,7 +28,11 @@ #include <sys/vnode.h> #include <sys/kmem_cache.h> #include <linux/falloc.h> -#include <linux/file_compat.h> +#include <linux/fs.h> +#include <linux/uaccess.h> +#ifdef HAVE_FDTABLE_HEADER +#include <linux/fdtable.h> +#endif vnode_t *rootdir = (vnode_t *)0xabcd1234; EXPORT_SYMBOL(rootdir); @@ -39,6 +43,76 @@ static spl_kmem_cache_t *vn_file_cache; static DEFINE_SPINLOCK(vn_file_lock); static LIST_HEAD(vn_file_list); +static int +spl_filp_fallocate(struct file *fp, int mode, loff_t offset, loff_t len) +{ + int error = -EOPNOTSUPP; + +#ifdef HAVE_FILE_FALLOCATE + if (fp->f_op->fallocate) + error = fp->f_op->fallocate(fp, mode, offset, len); +#else +#ifdef HAVE_INODE_FALLOCATE + if (fp->f_dentry && fp->f_dentry->d_inode && + fp->f_dentry->d_inode->i_op->fallocate) + error = fp->f_dentry->d_inode->i_op->fallocate( + fp->f_dentry->d_inode, mode, offset, len); +#endif /* HAVE_INODE_FALLOCATE */ +#endif /* HAVE_FILE_FALLOCATE */ + + return (error); +} + +static int +spl_filp_fsync(struct file *fp, int sync) +{ +#ifdef HAVE_2ARGS_VFS_FSYNC + return (vfs_fsync(fp, sync)); +#else + return (vfs_fsync(fp, (fp)->f_dentry, sync)); +#endif /* HAVE_2ARGS_VFS_FSYNC */ +} + +static ssize_t +spl_kernel_write(struct file *file, const void *buf, size_t count, loff_t *pos) +{ +#if defined(HAVE_KERNEL_WRITE_PPOS) + return (kernel_write(file, buf, count, pos)); +#else + mm_segment_t saved_fs; + ssize_t ret; + + saved_fs = get_fs(); + set_fs(get_ds()); + + ret = vfs_write(file, (__force const char __user *)buf, count, pos); + + set_fs(saved_fs); + + return (ret); +#endif +} + +static ssize_t +spl_kernel_read(struct file *file, void *buf, size_t count, loff_t *pos) +{ +#if defined(HAVE_KERNEL_READ_PPOS) + return (kernel_read(file, buf, count, pos)); +#else + mm_segment_t saved_fs; + ssize_t ret; + + saved_fs = get_fs(); + set_fs(get_ds()); + + ret = vfs_read(file, (void __user *)buf, count, pos); + + set_fs(saved_fs); + + return (ret); +#endif +} + vtype_t vn_mode_to_vtype(mode_t mode) { diff --git a/module/spl/spl-xdr.c b/module/spl/spl-xdr.c index 4055921b4..2cc3e2a03 100644 --- a/module/spl/spl-xdr.c +++ b/module/spl/spl-xdr.c @@ -25,7 +25,7 @@ #include <sys/kmem.h> #include <sys/debug.h> #include <sys/types.h> -#include <rpc/types.h> +#include <sys/sysmacros.h> #include <rpc/xdr.h> /* @@ -131,6 +131,8 @@ static struct xdr_ops xdrmem_encode_ops; static struct xdr_ops xdrmem_decode_ops; +typedef int bool_t; + void xdrmem_create(XDR *xdrs, const caddr_t addr, const uint_t size, const enum xdr_op op) diff --git a/module/spl/spl-zlib.c b/module/spl/spl-zlib.c index 177a626df..229e6a44b 100644 --- a/module/spl/spl-zlib.c +++ b/module/spl/spl-zlib.c @@ -57,7 +57,6 @@ #include <sys/kmem.h> #include <sys/kmem_cache.h> #include <sys/zmod.h> -#include <linux/zlib_compat.h> static spl_kmem_cache_t *zlib_workspace_cache; diff --git a/module/splat/Makefile.in b/module/splat/Makefile.in deleted file mode 100644 index 680f28492..000000000 --- a/module/splat/Makefile.in +++ /dev/null @@ -1,28 +0,0 @@ -# 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 += 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 diff --git a/module/splat/splat-atomic.c b/module/splat/splat-atomic.c deleted file mode 100644 index 8aaa0835d..000000000 --- a/module/splat/splat-atomic.c +++ /dev/null @@ -1,233 +0,0 @@ -/* - * 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). - * Written by Brian Behlendorf <[email protected]>. - * UCRL-CODE-235197 - * - * 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/>. - ***************************************************************************** - * Solaris Porting LAyer Tests (SPLAT) Atomic Tests. - */ - -#include <sys/atomic.h> -#include <sys/thread.h> -#include <sys/mutex.h> -#include <linux/mm_compat.h> -#include <linux/wait_compat.h> -#include <linux/slab.h> -#include "splat-internal.h" - -#define SPLAT_ATOMIC_NAME "atomic" -#define SPLAT_ATOMIC_DESC "Kernel Atomic Tests" - -#define SPLAT_ATOMIC_TEST1_ID 0x0b01 -#define SPLAT_ATOMIC_TEST1_NAME "64-bit" -#define SPLAT_ATOMIC_TEST1_DESC "Validate 64-bit atomic ops" - -#define SPLAT_ATOMIC_TEST_MAGIC 0x43435454UL -#define SPLAT_ATOMIC_INIT_VALUE 10000000UL - -typedef enum { - SPLAT_ATOMIC_INC_64 = 0, - SPLAT_ATOMIC_DEC_64 = 1, - SPLAT_ATOMIC_ADD_64 = 2, - SPLAT_ATOMIC_SUB_64 = 3, - SPLAT_ATOMIC_ADD_64_NV = 4, - SPLAT_ATOMIC_SUB_64_NV = 5, - SPLAT_ATOMIC_COUNT_64 = 6 -} atomic_op_t; - -typedef struct atomic_priv { - unsigned long ap_magic; - struct file *ap_file; - kmutex_t ap_lock; - spl_wait_queue_head_t ap_waitq; - volatile uint64_t ap_atomic; - volatile uint64_t ap_atomic_exited; - atomic_op_t ap_op; - -} atomic_priv_t; - -static void -splat_atomic_work(void *priv) -{ - atomic_priv_t *ap; - atomic_op_t op; - int i; - - ap = (atomic_priv_t *)priv; - ASSERT(ap->ap_magic == SPLAT_ATOMIC_TEST_MAGIC); - - mutex_enter(&ap->ap_lock); - op = ap->ap_op; - wake_up(&ap->ap_waitq); - mutex_exit(&ap->ap_lock); - - splat_vprint(ap->ap_file, SPLAT_ATOMIC_TEST1_NAME, - "Thread %d successfully started: %lu/%lu\n", op, - (long unsigned)ap->ap_atomic, - (long unsigned)ap->ap_atomic_exited); - - for (i = 0; i < SPLAT_ATOMIC_INIT_VALUE / 10; i++) { - - /* Periodically sleep to mix up the ordering */ - if ((i % (SPLAT_ATOMIC_INIT_VALUE / 100)) == 0) { - splat_vprint(ap->ap_file, SPLAT_ATOMIC_TEST1_NAME, - "Thread %d sleeping: %lu/%lu\n", op, - (long unsigned)ap->ap_atomic, - (long unsigned)ap->ap_atomic_exited); - set_current_state(TASK_INTERRUPTIBLE); - schedule_timeout(HZ / 100); - } - - switch (op) { - case SPLAT_ATOMIC_INC_64: - atomic_inc_64(&ap->ap_atomic); - break; - case SPLAT_ATOMIC_DEC_64: - atomic_dec_64(&ap->ap_atomic); - break; - case SPLAT_ATOMIC_ADD_64: - atomic_add_64(&ap->ap_atomic, 3); - break; - case SPLAT_ATOMIC_SUB_64: - atomic_sub_64(&ap->ap_atomic, 3); - break; - case SPLAT_ATOMIC_ADD_64_NV: - atomic_add_64_nv(&ap->ap_atomic, 5); - break; - case SPLAT_ATOMIC_SUB_64_NV: - atomic_sub_64_nv(&ap->ap_atomic, 5); - break; - default: - PANIC("Undefined op %d\n", op); - } - } - - atomic_inc_64(&ap->ap_atomic_exited); - - splat_vprint(ap->ap_file, SPLAT_ATOMIC_TEST1_NAME, - "Thread %d successfully exited: %lu/%lu\n", op, - (long unsigned)ap->ap_atomic, - (long unsigned)ap->ap_atomic_exited); - - wake_up(&ap->ap_waitq); - thread_exit(); -} - -static int -splat_atomic_test1_cond(atomic_priv_t *ap, int started) -{ - return (ap->ap_atomic_exited == started); -} - -static int -splat_atomic_test1(struct file *file, void *arg) -{ - atomic_priv_t ap; - DEFINE_WAIT(wait); - kthread_t *thr; - int i, rc = 0; - - ap.ap_magic = SPLAT_ATOMIC_TEST_MAGIC; - ap.ap_file = file; - mutex_init(&ap.ap_lock, SPLAT_ATOMIC_TEST1_NAME, MUTEX_DEFAULT, NULL); - init_waitqueue_head(&ap.ap_waitq); - ap.ap_atomic = SPLAT_ATOMIC_INIT_VALUE; - ap.ap_atomic_exited = 0; - - for (i = 0; i < SPLAT_ATOMIC_COUNT_64; i++) { - mutex_enter(&ap.ap_lock); - ap.ap_op = i; - - thr = (kthread_t *)thread_create(NULL, 0, splat_atomic_work, - &ap, 0, &p0, TS_RUN, - defclsyspri); - if (thr == NULL) { - rc = -ESRCH; - mutex_exit(&ap.ap_lock); - break; - } - - /* Prepare to wait, the new thread will wake us once it - * has made a copy of the unique private passed data */ - prepare_to_wait(&ap.ap_waitq, &wait, TASK_UNINTERRUPTIBLE); - mutex_exit(&ap.ap_lock); - schedule(); - } - - wait_event(ap.ap_waitq, splat_atomic_test1_cond(&ap, i)); - - if (rc) { - splat_vprint(file, SPLAT_ATOMIC_TEST1_NAME, "Only started " - "%d/%d test threads\n", i, SPLAT_ATOMIC_COUNT_64); - return rc; - } - - if (ap.ap_atomic != SPLAT_ATOMIC_INIT_VALUE) { - splat_vprint(file, SPLAT_ATOMIC_TEST1_NAME, - "Final value %lu does not match initial value %lu\n", - (long unsigned)ap.ap_atomic, SPLAT_ATOMIC_INIT_VALUE); - return -EINVAL; - } - - splat_vprint(file, SPLAT_ATOMIC_TEST1_NAME, - "Success initial and final values match, %lu == %lu\n", - (long unsigned)ap.ap_atomic, SPLAT_ATOMIC_INIT_VALUE); - - mutex_destroy(&ap.ap_lock); - - return 0; -} - -splat_subsystem_t * -splat_atomic_init(void) -{ - splat_subsystem_t *sub; - - sub = kmalloc(sizeof(*sub), GFP_KERNEL); - if (sub == NULL) - return NULL; - - memset(sub, 0, sizeof(*sub)); - strncpy(sub->desc.name, SPLAT_ATOMIC_NAME, SPLAT_NAME_SIZE); - strncpy(sub->desc.desc, SPLAT_ATOMIC_DESC, SPLAT_DESC_SIZE); - INIT_LIST_HEAD(&sub->subsystem_list); - INIT_LIST_HEAD(&sub->test_list); - spin_lock_init(&sub->test_lock); - sub->desc.id = SPLAT_SUBSYSTEM_ATOMIC; - - splat_test_init(sub, SPLAT_ATOMIC_TEST1_NAME, SPLAT_ATOMIC_TEST1_DESC, - SPLAT_ATOMIC_TEST1_ID, splat_atomic_test1); - - return sub; -} - -void -splat_atomic_fini(splat_subsystem_t *sub) -{ - ASSERT(sub); - splat_test_fini(sub, SPLAT_ATOMIC_TEST1_ID); - - kfree(sub); -} - -int -splat_atomic_id(void) { - return SPLAT_SUBSYSTEM_ATOMIC; -} diff --git a/module/splat/splat-condvar.c b/module/splat/splat-condvar.c deleted file mode 100644 index 0804baf50..000000000 --- a/module/splat/splat-condvar.c +++ /dev/null @@ -1,511 +0,0 @@ -/* - * 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). - * Written by Brian Behlendorf <[email protected]>. - * UCRL-CODE-235197 - * - * 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/>. - ***************************************************************************** - * Solaris Porting LAyer Tests (SPLAT) Condition Variable Tests. - */ - -#include <sys/condvar.h> -#include <sys/timer.h> -#include <sys/thread.h> -#include "splat-internal.h" - -#define SPLAT_CONDVAR_NAME "condvar" -#define SPLAT_CONDVAR_DESC "Kernel Condition Variable Tests" - -#define SPLAT_CONDVAR_TEST1_ID 0x0501 -#define SPLAT_CONDVAR_TEST1_NAME "signal1" -#define SPLAT_CONDVAR_TEST1_DESC "Wake a single thread, cv_wait()/cv_signal()" - -#define SPLAT_CONDVAR_TEST2_ID 0x0502 -#define SPLAT_CONDVAR_TEST2_NAME "broadcast1" -#define SPLAT_CONDVAR_TEST2_DESC "Wake all threads, cv_wait()/cv_broadcast()" - -#define SPLAT_CONDVAR_TEST3_ID 0x0503 -#define SPLAT_CONDVAR_TEST3_NAME "signal2" -#define SPLAT_CONDVAR_TEST3_DESC "Wake a single thread, cv_wait_timeout()/cv_signal()" - -#define SPLAT_CONDVAR_TEST4_ID 0x0504 -#define SPLAT_CONDVAR_TEST4_NAME "broadcast2" -#define SPLAT_CONDVAR_TEST4_DESC "Wake all threads, cv_wait_timeout()/cv_broadcast()" - -#define SPLAT_CONDVAR_TEST5_ID 0x0505 -#define SPLAT_CONDVAR_TEST5_NAME "timeout" -#define SPLAT_CONDVAR_TEST5_DESC "Timeout thread, cv_wait_timeout()" - -#define SPLAT_CONDVAR_TEST_MAGIC 0x115599DDUL -#define SPLAT_CONDVAR_TEST_NAME "condvar" -#define SPLAT_CONDVAR_TEST_COUNT 8 - -typedef struct condvar_priv { - unsigned long cv_magic; - struct file *cv_file; - kcondvar_t cv_condvar; - kmutex_t cv_mtx; -} condvar_priv_t; - -typedef struct condvar_thr { - const char *ct_name; - condvar_priv_t *ct_cvp; - struct task_struct *ct_thread; - int ct_rc; -} condvar_thr_t; - -int -splat_condvar_test12_thread(void *arg) -{ - condvar_thr_t *ct = (condvar_thr_t *)arg; - condvar_priv_t *cv = ct->ct_cvp; - - ASSERT(cv->cv_magic == SPLAT_CONDVAR_TEST_MAGIC); - - mutex_enter(&cv->cv_mtx); - splat_vprint(cv->cv_file, ct->ct_name, - "%s thread sleeping with %d waiters\n", - ct->ct_thread->comm, atomic_read(&cv->cv_condvar.cv_waiters)); - cv_wait(&cv->cv_condvar, &cv->cv_mtx); - splat_vprint(cv->cv_file, ct->ct_name, - "%s thread woken %d waiters remain\n", - ct->ct_thread->comm, atomic_read(&cv->cv_condvar.cv_waiters)); - mutex_exit(&cv->cv_mtx); - - /* wait for main thread reap us */ - while (!kthread_should_stop()) - schedule(); - return 0; -} - -static int -splat_condvar_test1(struct file *file, void *arg) -{ - int i, count = 0, rc = 0; - condvar_thr_t ct[SPLAT_CONDVAR_TEST_COUNT]; - condvar_priv_t cv; - - cv.cv_magic = SPLAT_CONDVAR_TEST_MAGIC; - cv.cv_file = file; - mutex_init(&cv.cv_mtx, SPLAT_CONDVAR_TEST_NAME, MUTEX_DEFAULT, NULL); - cv_init(&cv.cv_condvar, NULL, CV_DEFAULT, NULL); - - /* Create some threads, the exact number isn't important just as - * long as we know how many we managed to create and should expect. */ - for (i = 0; i < SPLAT_CONDVAR_TEST_COUNT; i++) { - ct[i].ct_cvp = &cv; - ct[i].ct_name = SPLAT_CONDVAR_TEST1_NAME; - ct[i].ct_rc = 0; - ct[i].ct_thread = spl_kthread_create(splat_condvar_test12_thread, - &ct[i], "%s/%d", SPLAT_CONDVAR_TEST_NAME, i); - - if (!IS_ERR(ct[i].ct_thread)) { - wake_up_process(ct[i].ct_thread); - count++; - } - } - - /* Wait until all threads are waiting on the condition variable */ - while (atomic_read(&cv.cv_condvar.cv_waiters) != count) - schedule(); - - /* Wake a single thread at a time, wait until it exits */ - for (i = 1; i <= count; i++) { - cv_signal(&cv.cv_condvar); - - while (atomic_read(&cv.cv_condvar.cv_waiters) > (count - i)) - schedule(); - - /* Correct behavior 1 thread woken */ - if (atomic_read(&cv.cv_condvar.cv_waiters) == (count - i)) - continue; - - splat_vprint(file, SPLAT_CONDVAR_TEST1_NAME, "Attempted to " - "wake %d thread but work %d threads woke\n", - 1, count - atomic_read(&cv.cv_condvar.cv_waiters)); - rc = -EINVAL; - break; - } - - if (!rc) - splat_vprint(file, SPLAT_CONDVAR_TEST1_NAME, "Correctly woke " - "%d sleeping threads %d at a time\n", count, 1); - - /* Wait until that last nutex is dropped */ - while (mutex_owner(&cv.cv_mtx)) - schedule(); - - /* Wake everything for the failure case */ - cv_broadcast(&cv.cv_condvar); - cv_destroy(&cv.cv_condvar); - - /* wait for threads to exit */ - for (i = 0; i < SPLAT_CONDVAR_TEST_COUNT; i++) { - if (!IS_ERR(ct[i].ct_thread)) - kthread_stop(ct[i].ct_thread); - } - mutex_destroy(&cv.cv_mtx); - - return rc; -} - -static int -splat_condvar_test2(struct file *file, void *arg) -{ - int i, count = 0, rc = 0; - condvar_thr_t ct[SPLAT_CONDVAR_TEST_COUNT]; - condvar_priv_t cv; - - cv.cv_magic = SPLAT_CONDVAR_TEST_MAGIC; - cv.cv_file = file; - mutex_init(&cv.cv_mtx, SPLAT_CONDVAR_TEST_NAME, MUTEX_DEFAULT, NULL); - cv_init(&cv.cv_condvar, NULL, CV_DEFAULT, NULL); - - /* Create some threads, the exact number isn't important just as - * long as we know how many we managed to create and should expect. */ - for (i = 0; i < SPLAT_CONDVAR_TEST_COUNT; i++) { - ct[i].ct_cvp = &cv; - ct[i].ct_name = SPLAT_CONDVAR_TEST2_NAME; - ct[i].ct_rc = 0; - ct[i].ct_thread = spl_kthread_create(splat_condvar_test12_thread, - &ct[i], "%s/%d", SPLAT_CONDVAR_TEST_NAME, i); - - if (!IS_ERR(ct[i].ct_thread)) { - wake_up_process(ct[i].ct_thread); - count++; - } - } - - /* Wait until all threads are waiting on the condition variable */ - while (atomic_read(&cv.cv_condvar.cv_waiters) != count) - schedule(); - - /* Wake all threads waiting on the condition variable */ - cv_broadcast(&cv.cv_condvar); - - /* Wait until all threads have exited */ - while ((atomic_read(&cv.cv_condvar.cv_waiters) > 0) || mutex_owner(&cv.cv_mtx)) - schedule(); - - splat_vprint(file, SPLAT_CONDVAR_TEST2_NAME, "Correctly woke all " - "%d sleeping threads at once\n", count); - - /* Wake everything for the failure case */ - cv_destroy(&cv.cv_condvar); - - /* wait for threads to exit */ - for (i = 0; i < SPLAT_CONDVAR_TEST_COUNT; i++) { - if (!IS_ERR(ct[i].ct_thread)) - kthread_stop(ct[i].ct_thread); - } - mutex_destroy(&cv.cv_mtx); - - return rc; -} - -int -splat_condvar_test34_thread(void *arg) -{ - condvar_thr_t *ct = (condvar_thr_t *)arg; - condvar_priv_t *cv = ct->ct_cvp; - clock_t rc; - - ASSERT(cv->cv_magic == SPLAT_CONDVAR_TEST_MAGIC); - - mutex_enter(&cv->cv_mtx); - splat_vprint(cv->cv_file, ct->ct_name, - "%s thread sleeping with %d waiters\n", - ct->ct_thread->comm, atomic_read(&cv->cv_condvar.cv_waiters)); - - /* Sleep no longer than 3 seconds, for this test we should - * actually never sleep that long without being woken up. */ - rc = cv_timedwait(&cv->cv_condvar, &cv->cv_mtx, lbolt + HZ * 3); - if (rc == -1) { - ct->ct_rc = -ETIMEDOUT; - splat_vprint(cv->cv_file, ct->ct_name, "%s thread timed out, " - "should have been woken\n", ct->ct_thread->comm); - } else { - splat_vprint(cv->cv_file, ct->ct_name, - "%s thread woken %d waiters remain\n", - ct->ct_thread->comm, - atomic_read(&cv->cv_condvar.cv_waiters)); - } - - mutex_exit(&cv->cv_mtx); - - /* wait for main thread reap us */ - while (!kthread_should_stop()) - schedule(); - return 0; -} - -static int -splat_condvar_test3(struct file *file, void *arg) -{ - int i, count = 0, rc = 0; - condvar_thr_t ct[SPLAT_CONDVAR_TEST_COUNT]; - condvar_priv_t cv; - - cv.cv_magic = SPLAT_CONDVAR_TEST_MAGIC; - cv.cv_file = file; - mutex_init(&cv.cv_mtx, SPLAT_CONDVAR_TEST_NAME, MUTEX_DEFAULT, NULL); - cv_init(&cv.cv_condvar, NULL, CV_DEFAULT, NULL); - - /* Create some threads, the exact number isn't important just as - * long as we know how many we managed to create and should expect. */ - for (i = 0; i < SPLAT_CONDVAR_TEST_COUNT; i++) { - ct[i].ct_cvp = &cv; - ct[i].ct_name = SPLAT_CONDVAR_TEST3_NAME; - ct[i].ct_rc = 0; - ct[i].ct_thread = spl_kthread_create(splat_condvar_test34_thread, - &ct[i], "%s/%d", SPLAT_CONDVAR_TEST_NAME, i); - - if (!IS_ERR(ct[i].ct_thread)) { - wake_up_process(ct[i].ct_thread); - count++; - } - } - - /* Wait until all threads are waiting on the condition variable */ - while (atomic_read(&cv.cv_condvar.cv_waiters) != count) - schedule(); - - /* Wake a single thread at a time, wait until it exits */ - for (i = 1; i <= count; i++) { - cv_signal(&cv.cv_condvar); - - while (atomic_read(&cv.cv_condvar.cv_waiters) > (count - i)) - schedule(); - - /* Correct behavior 1 thread woken */ - if (atomic_read(&cv.cv_condvar.cv_waiters) == (count - i)) - continue; - - splat_vprint(file, SPLAT_CONDVAR_TEST3_NAME, "Attempted to " - "wake %d thread but work %d threads woke\n", - 1, count - atomic_read(&cv.cv_condvar.cv_waiters)); - rc = -EINVAL; - break; - } - - /* Validate no waiting thread timed out early */ - for (i = 0; i < count; i++) - if (ct[i].ct_rc) - rc = ct[i].ct_rc; - - if (!rc) - splat_vprint(file, SPLAT_CONDVAR_TEST3_NAME, "Correctly woke " - "%d sleeping threads %d at a time\n", count, 1); - - /* Wait until that last nutex is dropped */ - while (mutex_owner(&cv.cv_mtx)) - schedule(); - - /* Wake everything for the failure case */ - cv_broadcast(&cv.cv_condvar); - cv_destroy(&cv.cv_condvar); - - /* wait for threads to exit */ - for (i = 0; i < SPLAT_CONDVAR_TEST_COUNT; i++) { - if (!IS_ERR(ct[i].ct_thread)) - kthread_stop(ct[i].ct_thread); - } - mutex_destroy(&cv.cv_mtx); - - return rc; -} - -static int -splat_condvar_test4(struct file *file, void *arg) -{ - int i, count = 0, rc = 0; - condvar_thr_t ct[SPLAT_CONDVAR_TEST_COUNT]; - condvar_priv_t cv; - - cv.cv_magic = SPLAT_CONDVAR_TEST_MAGIC; - cv.cv_file = file; - mutex_init(&cv.cv_mtx, SPLAT_CONDVAR_TEST_NAME, MUTEX_DEFAULT, NULL); - cv_init(&cv.cv_condvar, NULL, CV_DEFAULT, NULL); - - /* Create some threads, the exact number isn't important just as - * long as we know how many we managed to create and should expect. */ - for (i = 0; i < SPLAT_CONDVAR_TEST_COUNT; i++) { - ct[i].ct_cvp = &cv; - ct[i].ct_name = SPLAT_CONDVAR_TEST3_NAME; - ct[i].ct_rc = 0; - ct[i].ct_thread = spl_kthread_create(splat_condvar_test34_thread, - &ct[i], "%s/%d", SPLAT_CONDVAR_TEST_NAME, i); - - if (!IS_ERR(ct[i].ct_thread)) { - wake_up_process(ct[i].ct_thread); - count++; - } - } - - /* Wait until all threads are waiting on the condition variable */ - while (atomic_read(&cv.cv_condvar.cv_waiters) != count) - schedule(); - - /* Wake a single thread at a time, wait until it exits */ - for (i = 1; i <= count; i++) { - cv_signal(&cv.cv_condvar); - - while (atomic_read(&cv.cv_condvar.cv_waiters) > (count - i)) - schedule(); - - /* Correct behavior 1 thread woken */ - if (atomic_read(&cv.cv_condvar.cv_waiters) == (count - i)) - continue; - - splat_vprint(file, SPLAT_CONDVAR_TEST3_NAME, "Attempted to " - "wake %d thread but work %d threads woke\n", - 1, count - atomic_read(&cv.cv_condvar.cv_waiters)); - rc = -EINVAL; - break; - } - - /* Validate no waiting thread timed out early */ - for (i = 0; i < count; i++) - if (ct[i].ct_rc) - rc = ct[i].ct_rc; - - if (!rc) - splat_vprint(file, SPLAT_CONDVAR_TEST3_NAME, "Correctly woke " - "%d sleeping threads %d at a time\n", count, 1); - - /* Wait until that last nutex is dropped */ - while (mutex_owner(&cv.cv_mtx)) - schedule(); - - /* Wake everything for the failure case */ - cv_broadcast(&cv.cv_condvar); - cv_destroy(&cv.cv_condvar); - - /* wait for threads to exit */ - for (i = 0; i < SPLAT_CONDVAR_TEST_COUNT; i++) { - if (!IS_ERR(ct[i].ct_thread)) - kthread_stop(ct[i].ct_thread); - } - mutex_destroy(&cv.cv_mtx); - - return rc; -} - -static int -splat_condvar_test5(struct file *file, void *arg) -{ - kcondvar_t condvar; - kmutex_t mtx; - clock_t time_left, time_before, time_after, time_delta; - uint64_t whole_delta; - uint32_t remain_delta; - int rc = 0; - - mutex_init(&mtx, SPLAT_CONDVAR_TEST_NAME, MUTEX_DEFAULT, NULL); - cv_init(&condvar, NULL, CV_DEFAULT, NULL); - - splat_vprint(file, SPLAT_CONDVAR_TEST5_NAME, "Thread going to sleep for " - "%d second and expecting to be woken by timeout\n", 1); - - /* Allow a 1 second timeout, plenty long to validate correctness. */ - time_before = lbolt; - mutex_enter(&mtx); - time_left = cv_timedwait(&condvar, &mtx, lbolt + HZ); - mutex_exit(&mtx); - time_after = lbolt; - time_delta = time_after - time_before; /* XXX - Handle jiffie wrap */ - whole_delta = time_delta; - remain_delta = do_div(whole_delta, HZ); - - if (time_left == -1) { - if (time_delta >= HZ) { - splat_vprint(file, SPLAT_CONDVAR_TEST5_NAME, - "Thread correctly timed out and was asleep " - "for %d.%d seconds (%d second min)\n", - (int)whole_delta, (int)remain_delta, 1); - } else { - splat_vprint(file, SPLAT_CONDVAR_TEST5_NAME, - "Thread correctly timed out but was only " - "asleep for %d.%d seconds (%d second " - "min)\n", (int)whole_delta, - (int)remain_delta, 1); - rc = -ETIMEDOUT; - } - } else { - splat_vprint(file, SPLAT_CONDVAR_TEST5_NAME, - "Thread exited after only %d.%d seconds, it " - "did not hit the %d second timeout\n", - (int)whole_delta, (int)remain_delta, 1); - rc = -ETIMEDOUT; - } - - cv_destroy(&condvar); - mutex_destroy(&mtx); - - return rc; -} - -splat_subsystem_t * -splat_condvar_init(void) -{ - splat_subsystem_t *sub; - - sub = kmalloc(sizeof(*sub), GFP_KERNEL); - if (sub == NULL) - return NULL; - - memset(sub, 0, sizeof(*sub)); - strncpy(sub->desc.name, SPLAT_CONDVAR_NAME, SPLAT_NAME_SIZE); - strncpy(sub->desc.desc, SPLAT_CONDVAR_DESC, SPLAT_DESC_SIZE); - INIT_LIST_HEAD(&sub->subsystem_list); - INIT_LIST_HEAD(&sub->test_list); - spin_lock_init(&sub->test_lock); - sub->desc.id = SPLAT_SUBSYSTEM_CONDVAR; - - splat_test_init(sub, SPLAT_CONDVAR_TEST1_NAME, SPLAT_CONDVAR_TEST1_DESC, - SPLAT_CONDVAR_TEST1_ID, splat_condvar_test1); - splat_test_init(sub, SPLAT_CONDVAR_TEST2_NAME, SPLAT_CONDVAR_TEST2_DESC, - SPLAT_CONDVAR_TEST2_ID, splat_condvar_test2); - splat_test_init(sub, SPLAT_CONDVAR_TEST3_NAME, SPLAT_CONDVAR_TEST3_DESC, - SPLAT_CONDVAR_TEST3_ID, splat_condvar_test3); - splat_test_init(sub, SPLAT_CONDVAR_TEST4_NAME, SPLAT_CONDVAR_TEST4_DESC, - SPLAT_CONDVAR_TEST4_ID, splat_condvar_test4); - splat_test_init(sub, SPLAT_CONDVAR_TEST5_NAME, SPLAT_CONDVAR_TEST5_DESC, - SPLAT_CONDVAR_TEST5_ID, splat_condvar_test5); - - return sub; -} - -void -splat_condvar_fini(splat_subsystem_t *sub) -{ - ASSERT(sub); - splat_test_fini(sub, SPLAT_CONDVAR_TEST5_ID); - splat_test_fini(sub, SPLAT_CONDVAR_TEST4_ID); - splat_test_fini(sub, SPLAT_CONDVAR_TEST3_ID); - splat_test_fini(sub, SPLAT_CONDVAR_TEST2_ID); - splat_test_fini(sub, SPLAT_CONDVAR_TEST1_ID); - - kfree(sub); -} - -int -splat_condvar_id(void) { - return SPLAT_SUBSYSTEM_CONDVAR; -} diff --git a/module/splat/splat-cred.c b/module/splat/splat-cred.c deleted file mode 100644 index f13c0f752..000000000 --- a/module/splat/splat-cred.c +++ /dev/null @@ -1,299 +0,0 @@ -/* - * 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). - * Written by Brian Behlendorf <[email protected]>. - * UCRL-CODE-235197 - * - * 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/>. - ***************************************************************************** - * Solaris Porting LAyer Tests (SPLAT) Credential Tests. - */ - -#include <sys/cred.h> -#include <sys/random.h> -#include "splat-internal.h" - -#define SPLAT_CRED_NAME "cred" -#define SPLAT_CRED_DESC "Kernel Cred Tests" - -#define SPLAT_CRED_TEST1_ID 0x0e01 -#define SPLAT_CRED_TEST1_NAME "cred" -#define SPLAT_CRED_TEST1_DESC "Task Credential Test" - -#define SPLAT_CRED_TEST2_ID 0x0e02 -#define SPLAT_CRED_TEST2_NAME "kcred" -#define SPLAT_CRED_TEST2_DESC "Kernel Credential Test" - -#define SPLAT_CRED_TEST3_ID 0x0e03 -#define SPLAT_CRED_TEST3_NAME "groupmember" -#define SPLAT_CRED_TEST3_DESC "Group Member Test" - -#define GROUP_STR_SIZE 128 -#define GROUP_STR_REDZONE 16 - -static int -splat_cred_test1(struct file *file, void *arg) -{ - char str[GROUP_STR_SIZE]; - uid_t uid, ruid, suid; - gid_t gid, rgid, sgid, *groups; - int ngroups, i, count = 0; - cred_t *cr = CRED(); - - uid = crgetuid(cr); - ruid = crgetruid(cr); - suid = crgetsuid(cr); - - gid = crgetgid(cr); - rgid = crgetrgid(cr); - sgid = crgetsgid(cr); - - ngroups = crgetngroups(cr); - groups = crgetgroups(cr); - - memset(str, 0, GROUP_STR_SIZE); - for (i = 0; i < ngroups; i++) { - count += sprintf(str + count, "%d ", groups[i]); - - if (count > (GROUP_STR_SIZE - GROUP_STR_REDZONE)) { - splat_vprint(file, SPLAT_CRED_TEST1_NAME, - "Failed too many group entries for temp " - "buffer: %d, %s\n", ngroups, str); - return -ENOSPC; - } - } - - splat_vprint(file, SPLAT_CRED_TEST1_NAME, - "uid: %d ruid: %d suid: %d " - "gid: %d rgid: %d sgid: %d\n", - uid, ruid, suid, gid, rgid, sgid); - splat_vprint(file, SPLAT_CRED_TEST1_NAME, - "ngroups: %d groups: %s\n", ngroups, str); - - if (uid || ruid || suid || gid || rgid || sgid) { - splat_vprint(file, SPLAT_CRED_TEST1_NAME, - "Failed expected all uids+gids to be %d\n", 0); - return -EIDRM; - } - - if (ngroups > NGROUPS_MAX) { - splat_vprint(file, SPLAT_CRED_TEST1_NAME, - "Failed ngroups must not exceed NGROUPS_MAX: " - "%d > %d\n", ngroups, NGROUPS_MAX); - return -EIDRM; - } - - splat_vprint(file, SPLAT_CRED_TEST1_NAME, - "Success sane CRED(): %d\n", 0); - - return 0; -} /* splat_cred_test1() */ - -static int -splat_cred_test2(struct file *file, void *arg) -{ - char str[GROUP_STR_SIZE]; - uid_t uid, ruid, suid; - gid_t gid, rgid, sgid, *groups; - int ngroups, i, count = 0; - - crhold(kcred); - - uid = crgetuid(kcred); - ruid = crgetruid(kcred); - suid = crgetsuid(kcred); - - gid = crgetgid(kcred); - rgid = crgetrgid(kcred); - sgid = crgetsgid(kcred); - - ngroups = crgetngroups(kcred); - groups = crgetgroups(kcred); - - memset(str, 0, GROUP_STR_SIZE); - for (i = 0; i < ngroups; i++) { - count += sprintf(str + count, "%d ", groups[i]); - - if (count > (GROUP_STR_SIZE - GROUP_STR_REDZONE)) { - splat_vprint(file, SPLAT_CRED_TEST2_NAME, - "Failed too many group entries for temp " - "buffer: %d, %s\n", ngroups, str); - crfree(kcred); - return -ENOSPC; - } - } - - crfree(kcred); - - splat_vprint(file, SPLAT_CRED_TEST2_NAME, - "uid: %d ruid: %d suid: %d " - "gid: %d rgid: %d sgid: %d\n", - uid, ruid, suid, gid, rgid, sgid); - splat_vprint(file, SPLAT_CRED_TEST2_NAME, - "ngroups: %d groups: %s\n", ngroups, str); - - if (uid || ruid || suid || gid || rgid || sgid) { - splat_vprint(file, SPLAT_CRED_TEST2_NAME, - "Failed expected all uids+gids to be %d\n", 0); - return -EIDRM; - } - - if (ngroups > NGROUPS_MAX) { - splat_vprint(file, SPLAT_CRED_TEST2_NAME, - "Failed ngroups must not exceed NGROUPS_MAX: " - "%d > %d\n", ngroups, NGROUPS_MAX); - return -EIDRM; - } - - splat_vprint(file, SPLAT_CRED_TEST2_NAME, - "Success sane kcred: %d\n", 0); - - return 0; -} /* splat_cred_test2() */ - -#define SPLAT_NGROUPS 32 -/* - * Verify the groupmember() works correctly by constructing an interesting - * CRED() and checking that the expected gids are part of it. - */ -static int -splat_cred_test3(struct file *file, void *arg) -{ - gid_t known_gid, missing_gid, tmp_gid; - unsigned char rnd; - struct group_info *gi; - int i, rc; - - get_random_bytes((void *)&rnd, 1); - known_gid = (rnd > 0) ? rnd : 1; - missing_gid = 0; - - /* - * Create an interesting known set of gids for test purposes. The - * gids are pseudo randomly selected are will be in the range of - * 1:(NGROUPS_MAX-1). Gid 0 is explicitly avoided so we can reliably - * test for its absence in the test cases. - */ - gi = groups_alloc(SPLAT_NGROUPS); - if (gi == NULL) { - splat_vprint(file, SPLAT_CRED_TEST3_NAME, "Failed create " - "group_info for known gids: %d\n", -ENOMEM); - rc = -ENOMEM; - goto show_groups; - } - - for (i = 0, tmp_gid = known_gid; i < SPLAT_NGROUPS; i++) { - splat_vprint(file, SPLAT_CRED_TEST3_NAME, "Adding gid %d " - "to current CRED() (%d/%d)\n", tmp_gid, i, gi->ngroups); -#ifdef HAVE_KUIDGID_T - GROUP_AT(gi, i) = make_kgid(current_user_ns(), tmp_gid); -#else - GROUP_AT(gi, i) = tmp_gid; -#endif /* HAVE_KUIDGID_T */ - tmp_gid = ((tmp_gid * 17) % (NGROUPS_MAX - 1)) + 1; - } - - /* Set the new groups in the CRED() and release our reference. */ - rc = set_current_groups(gi); - put_group_info(gi); - - if (rc) { - splat_vprint(file, SPLAT_CRED_TEST3_NAME, "Failed to add " - "gid %d to current group: %d\n", known_gid, rc); - goto show_groups; - } - - /* Verify groupmember() finds the known_gid in the CRED() */ - rc = groupmember(known_gid, CRED()); - if (!rc) { - splat_vprint(file, SPLAT_CRED_TEST3_NAME, "Failed to find " - "known gid %d in CRED()'s groups.\n", known_gid); - rc = -EIDRM; - goto show_groups; - } - - /* Verify groupmember() does NOT finds the missing gid in the CRED() */ - rc = groupmember(missing_gid, CRED()); - if (rc) { - splat_vprint(file, SPLAT_CRED_TEST3_NAME, "Failed missing " - "gid %d was found in CRED()'s groups.\n", missing_gid); - rc = -EIDRM; - goto show_groups; - } - - splat_vprint(file, SPLAT_CRED_TEST3_NAME, "Success groupmember() " - "correctly detects expected gids in CRED(): %d\n", rc); - -show_groups: - if (rc) { - int i, grps = crgetngroups(CRED()); - - splat_vprint(file, SPLAT_CRED_TEST3_NAME, "%d groups: ", grps); - for (i = 0; i < grps; i++) - splat_print(file, "%d ", crgetgroups(CRED())[i]); - splat_print(file, "%s", "\n"); - } - - - return (rc); -} /* splat_cred_test3() */ - -splat_subsystem_t * -splat_cred_init(void) -{ - splat_subsystem_t *sub; - - sub = kmalloc(sizeof(*sub), GFP_KERNEL); - if (sub == NULL) - return NULL; - - memset(sub, 0, sizeof(*sub)); - strncpy(sub->desc.name, SPLAT_CRED_NAME, SPLAT_NAME_SIZE); - strncpy(sub->desc.desc, SPLAT_CRED_DESC, SPLAT_DESC_SIZE); - INIT_LIST_HEAD(&sub->subsystem_list); - INIT_LIST_HEAD(&sub->test_list); - spin_lock_init(&sub->test_lock); - sub->desc.id = SPLAT_SUBSYSTEM_CRED; - - splat_test_init(sub, SPLAT_CRED_TEST1_NAME, SPLAT_CRED_TEST1_DESC, - SPLAT_CRED_TEST1_ID, splat_cred_test1); - splat_test_init(sub, SPLAT_CRED_TEST2_NAME, SPLAT_CRED_TEST2_DESC, - SPLAT_CRED_TEST2_ID, splat_cred_test2); - splat_test_init(sub, SPLAT_CRED_TEST3_NAME, SPLAT_CRED_TEST3_DESC, - SPLAT_CRED_TEST3_ID, splat_cred_test3); - - return sub; -} /* splat_cred_init() */ - -void -splat_cred_fini(splat_subsystem_t *sub) -{ - ASSERT(sub); - - splat_test_fini(sub, SPLAT_CRED_TEST3_ID); - splat_test_fini(sub, SPLAT_CRED_TEST2_ID); - splat_test_fini(sub, SPLAT_CRED_TEST1_ID); - - kfree(sub); -} /* splat_cred_fini() */ - -int -splat_cred_id(void) -{ - return SPLAT_SUBSYSTEM_CRED; -} /* splat_cred_id() */ diff --git a/module/splat/splat-ctl.c b/module/splat/splat-ctl.c deleted file mode 100644 index cf6850100..000000000 --- a/module/splat/splat-ctl.c +++ /dev/null @@ -1,753 +0,0 @@ -/* - * 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). - * Written by Brian Behlendorf <[email protected]>. - * UCRL-CODE-235197 - * - * 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/>. - ***************************************************************************** - * Solaris Porting LAyer Tests (SPLAT) Test Control Interface. - * - * The 'splat' (Solaris Porting LAyer Tests) module is designed as a - * framework which runs various in kernel regression tests to validate - * the SPL primitives honor the Solaris ABI. - * - * The splat module is constructed of various splat_* source files each - * of which contain regression tests for a particular subsystem. For - * example, the splat_kmem.c file contains all the tests for validating - * the kmem interfaces have been implemented correctly. When the splat - * module is loaded splat_*_init() will be called for each subsystems - * tests. It is the responsibility of splat_*_init() to register all - * the tests for this subsystem using the splat_test_init(). - * Similarly splat_*_fini() is called when the splat module is removed - * and is responsible for unregistering its tests via the splat_test_fini. - * Once a test is registered it can then be run with an ioctl() - * call which specifies the subsystem and test to be run. The provided - * splat command line tool can be used to display all available - * subsystems and tests. It can also be used to run the full suite - * of regression tests or particular tests. - */ - -#include <sys/debug.h> -#include <sys/mutex.h> -#include <sys/types.h> -#include <linux/cdev.h> -#include <linux/fs.h> -#include <linux/miscdevice.h> -#include <linux/module.h> -#include <linux/slab.h> -#include <linux/uaccess.h> -#include <linux/vmalloc.h> -#include "splat-internal.h" - -static struct list_head splat_module_list; -static spinlock_t splat_module_lock; - -static int -splat_open(struct inode *inode, struct file *file) -{ - splat_info_t *info; - - info = (splat_info_t *)kmalloc(sizeof(*info), GFP_KERNEL); - if (info == NULL) - return -ENOMEM; - - mutex_init(&info->info_lock, SPLAT_NAME, MUTEX_DEFAULT, NULL); - info->info_size = SPLAT_INFO_BUFFER_SIZE; - info->info_buffer = (char *)vmalloc(SPLAT_INFO_BUFFER_SIZE); - if (info->info_buffer == NULL) { - kfree(info); - return -ENOMEM; - } - memset(info->info_buffer, 0, info->info_size); - - info->info_head = info->info_buffer; - file->private_data = (void *)info; - - splat_print(file, "%s\n", spl_version); - - return 0; -} - -static int -splat_release(struct inode *inode, struct file *file) -{ - splat_info_t *info = (splat_info_t *)file->private_data; - - ASSERT(info); - ASSERT(info->info_buffer); - - mutex_destroy(&info->info_lock); - vfree(info->info_buffer); - kfree(info); - - return 0; -} - -static int -splat_buffer_clear(struct file *file, splat_cfg_t *kcfg, unsigned long arg) -{ - splat_info_t *info = (splat_info_t *)file->private_data; - - ASSERT(info); - ASSERT(info->info_buffer); - - mutex_enter(&info->info_lock); - memset(info->info_buffer, 0, info->info_size); - info->info_head = info->info_buffer; - mutex_exit(&info->info_lock); - - return 0; -} - -static int -splat_buffer_size(struct file *file, splat_cfg_t *kcfg, unsigned long arg) -{ - splat_info_t *info = (splat_info_t *)file->private_data; - char *buf; - int min, size, rc = 0; - - ASSERT(info); - ASSERT(info->info_buffer); - - mutex_enter(&info->info_lock); - if (kcfg->cfg_arg1 > 0) { - - size = kcfg->cfg_arg1; - buf = (char *)vmalloc(size); - if (buf == NULL) { - rc = -ENOMEM; - goto out; - } - - /* Zero fill and truncate contents when coping buffer */ - min = ((size < info->info_size) ? size : info->info_size); - memset(buf, 0, size); - memcpy(buf, info->info_buffer, min); - vfree(info->info_buffer); - info->info_size = size; - info->info_buffer = buf; - info->info_head = info->info_buffer; - } - - kcfg->cfg_rc1 = info->info_size; - - if (copy_to_user((struct splat_cfg_t __user *)arg, kcfg, sizeof(*kcfg))) - rc = -EFAULT; -out: - mutex_exit(&info->info_lock); - - return rc; -} - - -static splat_subsystem_t * -splat_subsystem_find(int id) { - splat_subsystem_t *sub; - - spin_lock(&splat_module_lock); - list_for_each_entry(sub, &splat_module_list, subsystem_list) { - if (id == sub->desc.id) { - spin_unlock(&splat_module_lock); - return sub; - } - } - spin_unlock(&splat_module_lock); - - return NULL; -} - -static int -splat_subsystem_count(splat_cfg_t *kcfg, unsigned long arg) -{ - splat_subsystem_t *sub; - int i = 0; - - spin_lock(&splat_module_lock); - list_for_each_entry(sub, &splat_module_list, subsystem_list) - i++; - - spin_unlock(&splat_module_lock); - kcfg->cfg_rc1 = i; - - if (copy_to_user((struct splat_cfg_t __user *)arg, kcfg, sizeof(*kcfg))) - return -EFAULT; - - return 0; -} - -static int -splat_subsystem_list(splat_cfg_t *kcfg, unsigned long arg) -{ - splat_subsystem_t *sub; - splat_cfg_t *tmp; - int size, i = 0; - - /* Structure will be sized large enough for N subsystem entries - * which is passed in by the caller. On exit the number of - * entries filled in with valid subsystems will be stored in - * cfg_rc1. If the caller does not provide enough entries - * for all subsystems we will truncate the list to avoid overrun. - */ - size = sizeof(*tmp) + kcfg->cfg_data.splat_subsystems.size * - sizeof(splat_user_t); - tmp = kmalloc(size, GFP_KERNEL); - if (tmp == NULL) - return -ENOMEM; - - /* Local 'tmp' is used as the structure copied back to user space */ - memset(tmp, 0, size); - memcpy(tmp, kcfg, sizeof(*kcfg)); - - spin_lock(&splat_module_lock); - list_for_each_entry(sub, &splat_module_list, subsystem_list) { - strncpy(tmp->cfg_data.splat_subsystems.descs[i].name, - sub->desc.name, SPLAT_NAME_SIZE); - strncpy(tmp->cfg_data.splat_subsystems.descs[i].desc, - sub->desc.desc, SPLAT_DESC_SIZE); - tmp->cfg_data.splat_subsystems.descs[i].id = sub->desc.id; - - /* Truncate list if we are about to overrun alloc'ed memory */ - if ((i++) == kcfg->cfg_data.splat_subsystems.size) - break; - } - spin_unlock(&splat_module_lock); - tmp->cfg_rc1 = i; - - if (copy_to_user((struct splat_cfg_t __user *)arg, tmp, size)) { - kfree(tmp); - return -EFAULT; - } - - kfree(tmp); - return 0; -} - -static int -splat_test_count(splat_cfg_t *kcfg, unsigned long arg) -{ - splat_subsystem_t *sub; - splat_test_t *test; - int i = 0; - - /* Subsystem ID passed as arg1 */ - sub = splat_subsystem_find(kcfg->cfg_arg1); - if (sub == NULL) - return -EINVAL; - - spin_lock(&(sub->test_lock)); - list_for_each_entry(test, &(sub->test_list), test_list) - i++; - - spin_unlock(&(sub->test_lock)); - kcfg->cfg_rc1 = i; - - if (copy_to_user((struct splat_cfg_t __user *)arg, kcfg, sizeof(*kcfg))) - return -EFAULT; - - return 0; -} - -static int -splat_test_list(splat_cfg_t *kcfg, unsigned long arg) -{ - splat_subsystem_t *sub; - splat_test_t *test; - splat_cfg_t *tmp; - int size, i = 0; - - /* Subsystem ID passed as arg1 */ - sub = splat_subsystem_find(kcfg->cfg_arg1); - if (sub == NULL) - return -EINVAL; - - /* Structure will be sized large enough for N test entries - * which is passed in by the caller. On exit the number of - * entries filled in with valid tests will be stored in - * cfg_rc1. If the caller does not provide enough entries - * for all tests we will truncate the list to avoid overrun. - */ - size = sizeof(*tmp)+kcfg->cfg_data.splat_tests.size*sizeof(splat_user_t); - tmp = kmalloc(size, GFP_KERNEL); - if (tmp == NULL) - return -ENOMEM; - - /* Local 'tmp' is used as the structure copied back to user space */ - memset(tmp, 0, size); - memcpy(tmp, kcfg, sizeof(*kcfg)); - - spin_lock(&(sub->test_lock)); - list_for_each_entry(test, &(sub->test_list), test_list) { - strncpy(tmp->cfg_data.splat_tests.descs[i].name, - test->desc.name, SPLAT_NAME_SIZE); - strncpy(tmp->cfg_data.splat_tests.descs[i].desc, - test->desc.desc, SPLAT_DESC_SIZE); - tmp->cfg_data.splat_tests.descs[i].id = test->desc.id; - - /* Truncate list if we are about to overrun alloc'ed memory */ - if ((i++) == kcfg->cfg_data.splat_tests.size) - break; - } - spin_unlock(&(sub->test_lock)); - tmp->cfg_rc1 = i; - - if (copy_to_user((struct splat_cfg_t __user *)arg, tmp, size)) { - kfree(tmp); - return -EFAULT; - } - - kfree(tmp); - return 0; -} - -static int -splat_validate(struct file *file, splat_subsystem_t *sub, int cmd, void *arg) -{ - splat_test_t *test; - - spin_lock(&(sub->test_lock)); - list_for_each_entry(test, &(sub->test_list), test_list) { - if (test->desc.id == cmd) { - spin_unlock(&(sub->test_lock)); - return test->test(file, arg); - } - } - spin_unlock(&(sub->test_lock)); - - return -EINVAL; -} - -static int -splat_ioctl_cfg(struct file *file, unsigned int cmd, unsigned long arg) -{ - splat_cfg_t kcfg; - int rc = 0; - - /* User and kernel space agree about arg size */ - if (_IOC_SIZE(cmd) != sizeof(kcfg)) - return -EBADMSG; - - if (copy_from_user(&kcfg, (splat_cfg_t *)arg, sizeof(kcfg))) - return -EFAULT; - - if (kcfg.cfg_magic != SPLAT_CFG_MAGIC) { - splat_print(file, "Bad config magic 0x%x != 0x%x\n", - kcfg.cfg_magic, SPLAT_CFG_MAGIC); - return -EINVAL; - } - - switch (kcfg.cfg_cmd) { - case SPLAT_CFG_BUFFER_CLEAR: - /* cfg_arg1 - Unused - * cfg_rc1 - Unused - */ - rc = splat_buffer_clear(file, &kcfg, arg); - break; - case SPLAT_CFG_BUFFER_SIZE: - /* cfg_arg1 - 0 - query size; >0 resize - * cfg_rc1 - Set to current buffer size - */ - rc = splat_buffer_size(file, &kcfg, arg); - break; - case SPLAT_CFG_SUBSYSTEM_COUNT: - /* cfg_arg1 - Unused - * cfg_rc1 - Set to number of subsystems - */ - rc = splat_subsystem_count(&kcfg, arg); - break; - case SPLAT_CFG_SUBSYSTEM_LIST: - /* cfg_arg1 - Unused - * cfg_rc1 - Set to number of subsystems - * cfg_data.splat_subsystems - Set with subsystems - */ - rc = splat_subsystem_list(&kcfg, arg); - break; - case SPLAT_CFG_TEST_COUNT: - /* cfg_arg1 - Set to a target subsystem - * cfg_rc1 - Set to number of tests - */ - rc = splat_test_count(&kcfg, arg); - break; - case SPLAT_CFG_TEST_LIST: - /* cfg_arg1 - Set to a target subsystem - * cfg_rc1 - Set to number of tests - * cfg_data.splat_subsystems - Populated with tests - */ - rc = splat_test_list(&kcfg, arg); - break; - default: - splat_print(file, "Bad config command %d\n", - kcfg.cfg_cmd); - rc = -EINVAL; - break; - } - - return rc; -} - -static int -splat_ioctl_cmd(struct file *file, unsigned int cmd, unsigned long arg) -{ - splat_subsystem_t *sub; - splat_cmd_t kcmd; - int rc = -EINVAL; - void *data = NULL; - - /* User and kernel space agree about arg size */ - if (_IOC_SIZE(cmd) != sizeof(kcmd)) - return -EBADMSG; - - if (copy_from_user(&kcmd, (splat_cfg_t *)arg, sizeof(kcmd))) - return -EFAULT; - - if (kcmd.cmd_magic != SPLAT_CMD_MAGIC) { - splat_print(file, "Bad command magic 0x%x != 0x%x\n", - kcmd.cmd_magic, SPLAT_CFG_MAGIC); - return -EINVAL; - } - - /* Allocate memory for any opaque data the caller needed to pass on */ - if (kcmd.cmd_data_size > 0) { - data = (void *)kmalloc(kcmd.cmd_data_size, GFP_KERNEL); - if (data == NULL) - return -ENOMEM; - - if (copy_from_user(data, (void *)(arg + offsetof(splat_cmd_t, - cmd_data_str)), kcmd.cmd_data_size)) { - kfree(data); - return -EFAULT; - } - } - - sub = splat_subsystem_find(kcmd.cmd_subsystem); - if (sub != NULL) - rc = splat_validate(file, sub, kcmd.cmd_test, data); - else - rc = -EINVAL; - - if (data != NULL) - kfree(data); - - return rc; -} - -static long -splat_unlocked_ioctl(struct file *file, unsigned int cmd, unsigned long arg) -{ - int rc = 0; - - /* Ignore tty ioctls */ - if ((cmd & 0xffffff00) == ((int)'T') << 8) - return -ENOTTY; - - switch (cmd) { - case SPLAT_CFG: - rc = splat_ioctl_cfg(file, cmd, arg); - break; - case SPLAT_CMD: - rc = splat_ioctl_cmd(file, cmd, arg); - break; - default: - splat_print(file, "Bad ioctl command %d\n", cmd); - rc = -EINVAL; - break; - } - - return rc; -} - -#ifdef CONFIG_COMPAT -/* Compatibility handler for ioctls from 32-bit ELF binaries */ -static long -splat_compat_ioctl(struct file *file, unsigned int cmd, unsigned long arg) -{ - return splat_unlocked_ioctl(file, cmd, arg); -} -#endif /* CONFIG_COMPAT */ - -/* I'm not sure why you would want to write in to this buffer from - * user space since its principle use is to pass test status info - * back to the user space, but I don't see any reason to prevent it. - */ -static ssize_t splat_write(struct file *file, const char __user *buf, - size_t count, loff_t *ppos) -{ - splat_info_t *info = (splat_info_t *)file->private_data; - int rc = 0; - - ASSERT(info); - ASSERT(info->info_buffer); - - mutex_enter(&info->info_lock); - - /* Write beyond EOF */ - if (*ppos >= info->info_size) { - rc = -EFBIG; - goto out; - } - - /* Resize count if beyond EOF */ - if (*ppos + count > info->info_size) - count = info->info_size - *ppos; - - if (copy_from_user(info->info_buffer, buf, count)) { - rc = -EFAULT; - goto out; - } - - *ppos += count; - rc = count; -out: - mutex_exit(&info->info_lock); - return rc; -} - -static ssize_t splat_read(struct file *file, char __user *buf, - size_t count, loff_t *ppos) -{ - splat_info_t *info = (splat_info_t *)file->private_data; - int rc = 0; - - ASSERT(info); - ASSERT(info->info_buffer); - - mutex_enter(&info->info_lock); - - /* Read beyond EOF */ - if (*ppos >= info->info_size) - goto out; - - /* Resize count if beyond EOF */ - if (*ppos + count > info->info_size) - count = info->info_size - *ppos; - - if (copy_to_user(buf, info->info_buffer + *ppos, count)) { - rc = -EFAULT; - goto out; - } - - *ppos += count; - rc = count; -out: - mutex_exit(&info->info_lock); - return rc; -} - -static loff_t splat_seek(struct file *file, loff_t offset, int origin) -{ - splat_info_t *info = (splat_info_t *)file->private_data; - int rc = -EINVAL; - - ASSERT(info); - ASSERT(info->info_buffer); - - mutex_enter(&info->info_lock); - - switch (origin) { - case 0: /* SEEK_SET - No-op just do it */ - break; - case 1: /* SEEK_CUR - Seek from current */ - offset = file->f_pos + offset; - break; - case 2: /* SEEK_END - Seek from end */ - offset = info->info_size + offset; - break; - } - - if (offset >= 0) { - file->f_pos = offset; - file->f_version = 0; - rc = offset; - } - - mutex_exit(&info->info_lock); - - return rc; -} - -static struct file_operations splat_fops = { - .owner = THIS_MODULE, - .open = splat_open, - .release = splat_release, - .unlocked_ioctl = splat_unlocked_ioctl, -#ifdef CONFIG_COMPAT - .compat_ioctl = splat_compat_ioctl, -#endif - .read = splat_read, - .write = splat_write, - .llseek = splat_seek, -}; - -static struct miscdevice splat_misc = { - .minor = MISC_DYNAMIC_MINOR, - .name = SPLAT_NAME, - .fops = &splat_fops, -}; - -static void splat_subsystem_init(const char *name, - splat_subsystem_t *(*init)(void)) -{ - splat_subsystem_t *sub; - sub = init(); - if (sub == NULL) { - printk(KERN_ERR "splat: Error initializing: %s\n", name); - return; - } - spin_lock(&splat_module_lock); - list_add_tail(&sub->subsystem_list, &splat_module_list); - spin_unlock(&splat_module_lock); -} - -static void splat_subsystem_fini(const char *name, - int (*id_func)(void), void (*fini)(splat_subsystem_t *)) -{ - splat_subsystem_t *sub, *tmp; - int id, flag = 0; - - id = id_func(); - spin_lock(&splat_module_lock); - list_for_each_entry_safe(sub, tmp, &splat_module_list, subsystem_list) { - if (sub->desc.id == id) { - list_del_init(&sub->subsystem_list); - flag = 1; - break; - } - } - spin_unlock(&splat_module_lock); - if (flag == 0) - printk(KERN_ERR "splat: Error finalizing: %s\n", name); - else - fini(sub); -} - -#define SPLAT_SUBSYSTEM_INIT(type) \ - splat_subsystem_init(#type, splat_##type##_init) -#define SPLAT_SUBSYSTEM_FINI(type) \ - splat_subsystem_fini(#type, splat_##type##_id, splat_##type##_fini) - -void splat_test_init(splat_subsystem_t *sub, const char *name, - const char *desc, unsigned int tid, splat_test_func_t func) -{ - splat_test_t *test; - test = kmalloc(sizeof (splat_test_t), GFP_KERNEL); - if (test == NULL) { - printk(KERN_ERR "splat: Error initializing: %s/%u\n", - name, tid); - return; - } - memset(test, 0, sizeof (splat_test_t)); - strncpy(test->desc.name, name, SPLAT_NAME_SIZE-1); - strncpy(test->desc.desc, desc, SPLAT_DESC_SIZE-1); - test->desc.id = tid; - test->test = func; - INIT_LIST_HEAD(&test->test_list); - spin_lock(&sub->test_lock); - list_add_tail(&test->test_list, &sub->test_list); - spin_unlock(&sub->test_lock); -} - -void splat_test_fini(splat_subsystem_t *sub, unsigned int tid) -{ - splat_test_t *test, *tmp; - int flag = 0; - - spin_lock(&sub->test_lock); - list_for_each_entry_safe(test, tmp, &sub->test_list, test_list) { - if (test->desc.id == tid) { - list_del_init(&test->test_list); - kfree(test); - flag = 1; - break; - } - } - spin_unlock(&sub->test_lock); - - if (flag == 0) - printk(KERN_ERR "splat: Error finalizing: %u\n", tid); -} - -static int __init -splat_init(void) -{ - int error; - - spin_lock_init(&splat_module_lock); - INIT_LIST_HEAD(&splat_module_list); - - SPLAT_SUBSYSTEM_INIT(kmem); - SPLAT_SUBSYSTEM_INIT(taskq); - SPLAT_SUBSYSTEM_INIT(krng); - SPLAT_SUBSYSTEM_INIT(mutex); - SPLAT_SUBSYSTEM_INIT(condvar); - SPLAT_SUBSYSTEM_INIT(thread); - SPLAT_SUBSYSTEM_INIT(rwlock); - SPLAT_SUBSYSTEM_INIT(time); - SPLAT_SUBSYSTEM_INIT(vnode); - SPLAT_SUBSYSTEM_INIT(kobj); - SPLAT_SUBSYSTEM_INIT(atomic); - SPLAT_SUBSYSTEM_INIT(list); - SPLAT_SUBSYSTEM_INIT(generic); - SPLAT_SUBSYSTEM_INIT(cred); - SPLAT_SUBSYSTEM_INIT(zlib); - SPLAT_SUBSYSTEM_INIT(linux); - - error = misc_register(&splat_misc); - if (error) { - printk(KERN_INFO "SPLAT: misc_register() failed %d\n", error); - } else { - printk(KERN_INFO "SPLAT: Loaded module v%s-%s%s\n", - SPL_META_VERSION, SPL_META_RELEASE, SPL_DEBUG_STR); - } - - return (error); -} - -static void __exit -splat_fini(void) -{ - misc_deregister(&splat_misc); - - SPLAT_SUBSYSTEM_FINI(linux); - SPLAT_SUBSYSTEM_FINI(zlib); - SPLAT_SUBSYSTEM_FINI(cred); - SPLAT_SUBSYSTEM_FINI(generic); - SPLAT_SUBSYSTEM_FINI(list); - SPLAT_SUBSYSTEM_FINI(atomic); - SPLAT_SUBSYSTEM_FINI(kobj); - SPLAT_SUBSYSTEM_FINI(vnode); - SPLAT_SUBSYSTEM_FINI(time); - SPLAT_SUBSYSTEM_FINI(rwlock); - SPLAT_SUBSYSTEM_FINI(thread); - SPLAT_SUBSYSTEM_FINI(condvar); - SPLAT_SUBSYSTEM_FINI(mutex); - SPLAT_SUBSYSTEM_FINI(krng); - SPLAT_SUBSYSTEM_FINI(taskq); - SPLAT_SUBSYSTEM_FINI(kmem); - - ASSERT(list_empty(&splat_module_list)); - printk(KERN_INFO "SPLAT: Unloaded module v%s-%s%s\n", - SPL_META_VERSION, SPL_META_RELEASE, SPL_DEBUG_STR); -} - -module_init(splat_init); -module_exit(splat_fini); - -MODULE_DESCRIPTION("Solaris Porting LAyer Tests"); -MODULE_AUTHOR(SPL_META_AUTHOR); -MODULE_LICENSE(SPL_META_LICENSE); -MODULE_VERSION(SPL_META_VERSION "-" SPL_META_RELEASE); diff --git a/module/splat/splat-generic.c b/module/splat/splat-generic.c deleted file mode 100644 index e256c83f0..000000000 --- a/module/splat/splat-generic.c +++ /dev/null @@ -1,367 +0,0 @@ -/* - * 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). - * Written by Brian Behlendorf <[email protected]>. - * UCRL-CODE-235197 - * - * 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/>. - ***************************************************************************** - * Solaris Porting LAyer Tests (SPLAT) Generic Tests. - */ - -#include <sys/sunddi.h> -#include <linux/math64_compat.h> -#include "splat-internal.h" - -#define SPLAT_GENERIC_NAME "generic" -#define SPLAT_GENERIC_DESC "Kernel Generic Tests" - -#define SPLAT_GENERIC_TEST1_ID 0x0d01 -#define SPLAT_GENERIC_TEST1_NAME "ddi_strtoul" -#define SPLAT_GENERIC_TEST1_DESC "ddi_strtoul Test" - -#define SPLAT_GENERIC_TEST2_ID 0x0d02 -#define SPLAT_GENERIC_TEST2_NAME "ddi_strtol" -#define SPLAT_GENERIC_TEST2_DESC "ddi_strtol Test" - -#define SPLAT_GENERIC_TEST3_ID 0x0d03 -#define SPLAT_GENERIC_TEST3_NAME "ddi_strtoull" -#define SPLAT_GENERIC_TEST3_DESC "ddi_strtoull Test" - -#define SPLAT_GENERIC_TEST4_ID 0x0d04 -#define SPLAT_GENERIC_TEST4_NAME "ddi_strtoll" -#define SPLAT_GENERIC_TEST4_DESC "ddi_strtoll Test" - -# define SPLAT_GENERIC_TEST5_ID 0x0d05 -# define SPLAT_GENERIC_TEST5_NAME "udivdi3" -# define SPLAT_GENERIC_TEST5_DESC "Unsigned Div-64 Test" - -# define SPLAT_GENERIC_TEST6_ID 0x0d06 -# define SPLAT_GENERIC_TEST6_NAME "divdi3" -# define SPLAT_GENERIC_TEST6_DESC "Signed Div-64 Test" - -#define STR_POS "123456789" -#define STR_NEG "-123456789" -#define STR_BASE "0xabcdef" -#define STR_RANGE_MAX "10000000000000000" -#define STR_RANGE_MIN "-10000000000000000" -#define STR_INVAL1 "12345U" -#define STR_INVAL2 "invald" - -#define VAL_POS 123456789 -#define VAL_NEG -123456789 -#define VAL_BASE 0xabcdef -#define VAL_INVAL1 12345U - -#define define_generic_msg_strtox(type, valtype) \ -static void \ -generic_msg_strto##type(struct file *file, char *msg, int rc, int *err, \ - const char *s, valtype d, char *endptr) \ -{ \ - splat_vprint(file, SPLAT_GENERIC_TEST1_NAME, \ - "%s (%d) %s: %s == %lld, 0x%p\n", \ - rc ? "Fail" : "Pass", *err, msg, s, \ - (unsigned long long)d, endptr); \ - *err = rc; \ -} - -define_generic_msg_strtox(ul, unsigned long); -define_generic_msg_strtox(l, long); -define_generic_msg_strtox(ull, unsigned long long); -define_generic_msg_strtox(ll, long long); - -#define define_splat_generic_test_strtox(type, valtype) \ -static int \ -splat_generic_test_strto##type(struct file *file, void *arg) \ -{ \ - int rc, rc1, rc2, rc3, rc4, rc5, rc6, rc7; \ - char str[20], *endptr; \ - valtype r; \ - \ - /* Positive value: expect success */ \ - r = 0; \ - rc = 1; \ - endptr = NULL; \ - rc1 = ddi_strto##type(STR_POS, &endptr, 10, &r); \ - if (rc1 == 0 && r == VAL_POS && endptr && *endptr == '\0') \ - rc = 0; \ - \ - generic_msg_strto##type(file, "positive", rc , &rc1, \ - STR_POS, r, endptr); \ - \ - /* Negative value: expect success */ \ - r = 0; \ - rc = 1; \ - endptr = NULL; \ - strcpy(str, STR_NEG); \ - rc2 = ddi_strto##type(str, &endptr, 10, &r); \ - if (#type[0] == 'u') { \ - if (rc2 == 0 && r == 0 && endptr == str) \ - rc = 0; \ - } else { \ - if (rc2 == 0 && r == VAL_NEG && \ - endptr && *endptr == '\0') \ - rc = 0; \ - } \ - \ - generic_msg_strto##type(file, "negative", rc, &rc2, \ - STR_NEG, r, endptr); \ - \ - /* Non decimal base: expect sucess */ \ - r = 0; \ - rc = 1; \ - endptr = NULL; \ - rc3 = ddi_strto##type(STR_BASE, &endptr, 0, &r); \ - if (rc3 == 0 && r == VAL_BASE && endptr && *endptr == '\0') \ - rc = 0; \ - \ - generic_msg_strto##type(file, "base", rc, &rc3, \ - STR_BASE, r, endptr); \ - \ - /* Max out of range: failure expected, r unchanged */ \ - r = 0; \ - rc = 1; \ - endptr = NULL; \ - rc4 = ddi_strto##type(STR_RANGE_MAX, &endptr, 16, &r); \ - if (rc4 == ERANGE && r == 0 && endptr == NULL) \ - rc = 0; \ - \ - generic_msg_strto##type(file, "max", rc, &rc4, \ - STR_RANGE_MAX, r, endptr); \ - \ - /* Min out of range: failure expected, r unchanged */ \ - r = 0; \ - rc = 1; \ - endptr = NULL; \ - strcpy(str, STR_RANGE_MIN); \ - rc5 = ddi_strto##type(str, &endptr, 16, &r); \ - if (#type[0] == 'u') { \ - if (rc5 == 0 && r == 0 && endptr == str) \ - rc = 0; \ - } else { \ - if (rc5 == ERANGE && r == 0 && endptr == NULL) \ - rc = 0; \ - } \ - \ - generic_msg_strto##type(file, "min", rc, &rc5, \ - STR_RANGE_MIN, r, endptr); \ - \ - /* Invalid string: success expected, endptr == 'U' */ \ - r = 0; \ - rc = 1; \ - endptr = NULL; \ - rc6 = ddi_strto##type(STR_INVAL1, &endptr, 10, &r); \ - if (rc6 == 0 && r == VAL_INVAL1 && endptr && *endptr == 'U') \ - rc = 0; \ - \ - generic_msg_strto##type(file, "invalid", rc, &rc6, \ - STR_INVAL1, r, endptr); \ - \ - /* Invalid string: failure expected, endptr == str */ \ - r = 0; \ - rc = 1; \ - endptr = NULL; \ - strcpy(str, STR_INVAL2); \ - rc7 = ddi_strto##type(str, &endptr, 10, &r); \ - if (rc7 == 0 && r == 0 && endptr == str) \ - rc = 0; \ - \ - generic_msg_strto##type(file, "invalid", rc, &rc7, \ - STR_INVAL2, r, endptr); \ - \ - return (rc1 || rc2 || rc3 || rc4 || rc5 || rc6 || rc7) ? \ - -EINVAL : 0; \ -} - -define_splat_generic_test_strtox(ul, unsigned long); -define_splat_generic_test_strtox(l, long); -define_splat_generic_test_strtox(ull, unsigned long long); -define_splat_generic_test_strtox(ll, long long); - -/* - * The entries in the table are used in all combinations and the - * return value is checked to ensure it is range. On 32-bit - * systems __udivdi3 will be invoked for the 64-bit division. - * On 64-bit system the native 64-bit divide will be used so - * __udivdi3 isn't used but we might as well stil run the test. - */ -static int -splat_generic_test_udivdi3(struct file *file, void *arg) -{ - const uint64_t tabu[] = { - 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, - 10, 11, 12, 13, 14, 15, 16, 1000, 2003, - 32765, 32766, 32767, 32768, 32769, 32760, - 65533, 65534, 65535, 65536, 65537, 65538, - 0x7ffffffeULL, 0x7fffffffULL, 0x80000000ULL, 0x80000001ULL, - 0x7000000000000000ULL, 0x7000000080000000ULL, 0x7000000080000001ULL, - 0x7fffffffffffffffULL, 0x7fffffff8fffffffULL, 0x7fffffff8ffffff1ULL, - 0x7fffffff00000000ULL, 0x7fffffff80000000ULL, 0x7fffffff00000001ULL, - 0x8000000000000000ULL, 0x8000000080000000ULL, 0x8000000080000001ULL, - 0xc000000000000000ULL, 0xc000000080000000ULL, 0xc000000080000001ULL, - 0xfffffffffffffffdULL, 0xfffffffffffffffeULL, 0xffffffffffffffffULL, - }; - uint64_t uu, vu, qu, ru; - int n, i, j, errors = 0; - - splat_vprint(file, SPLAT_GENERIC_TEST5_NAME, "%s", - "Testing unsigned 64-bit division.\n"); - n = sizeof(tabu) / sizeof(tabu[0]); - for (i = 0; i < n; i++) { - for (j = 1; j < n; j++) { - uu = tabu[i]; - vu = tabu[j]; - qu = uu / vu; /* __udivdi3 */ - ru = uu - qu * vu; - if (qu > uu || ru >= vu) { - splat_vprint(file, SPLAT_GENERIC_TEST5_NAME, - "%016llx/%016llx != %016llx rem %016llx\n", - uu, vu, qu, ru); - errors++; - } - } - } - - if (errors) { - splat_vprint(file, SPLAT_GENERIC_TEST5_NAME, - "Failed %d/%d tests\n", errors, n * (n - 1)); - return -ERANGE; - } - - splat_vprint(file, SPLAT_GENERIC_TEST5_NAME, - "Passed all %d tests\n", n * (n - 1)); - - return 0; -} - -/* - * The entries the table are used in all combinations, with + and - signs - * preceding them. The return value is checked to ensure it is range. - * On 32-bit systems __divdi3 will be invoked for the 64-bit division. - * On 64-bit system the native 64-bit divide will be used so __divdi3 - * isn't used but we might as well stil run the test. - */ -static int -splat_generic_test_divdi3(struct file *file, void *arg) -{ - const int64_t tabs[] = { - 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, - 10, 11, 12, 13, 14, 15, 16, 1000, 2003, - 32765, 32766, 32767, 32768, 32769, 32760, - 65533, 65534, 65535, 65536, 65537, 65538, - 0x7ffffffeLL, 0x7fffffffLL, 0x80000000LL, 0x80000001LL, - 0x7000000000000000LL, 0x7000000080000000LL, 0x7000000080000001LL, - 0x7fffffffffffffffLL, 0x7fffffff8fffffffLL, 0x7fffffff8ffffff1LL, - 0x7fffffff00000000LL, 0x7fffffff80000000LL, 0x7fffffff00000001LL, - 0x0123456789abcdefLL, 0x00000000abcdef01LL, 0x0000000012345678LL, -#if BITS_PER_LONG == 32 - 0x8000000000000000LL, 0x8000000080000000LL, 0x8000000080000001LL, -#endif - }; - int64_t u, v, q, r; - int n, i, j, k, errors = 0; - - splat_vprint(file, SPLAT_GENERIC_TEST6_NAME, "%s", - "Testing signed 64-bit division.\n"); - n = sizeof(tabs) / sizeof(tabs[0]); - for (i = 0; i < n; i++) { - for (j = 1; j < n; j++) { - for (k = 0; k <= 3; k++) { - u = (k & 1) ? -tabs[i] : tabs[i]; - v = (k >= 2) ? -tabs[j] : tabs[j]; - - q = u / v; /* __divdi3 */ - r = u - q * v; - if (abs64(q) > abs64(u) || - abs64(r) >= abs64(v) || - (r != 0 && (r ^ u) < 0)) { - splat_vprint(file, - SPLAT_GENERIC_TEST6_NAME, - "%016llx/%016llx != %016llx " - "rem %016llx\n", u, v, q, r); - errors++; - } - } - } - } - - if (errors) { - splat_vprint(file, SPLAT_GENERIC_TEST6_NAME, - "Failed %d/%d tests\n", errors, n * (n - 1)); - return -ERANGE; - } - - splat_vprint(file, SPLAT_GENERIC_TEST6_NAME, - "Passed all %d tests\n", n * (n - 1)); - - return 0; -} - -splat_subsystem_t * -splat_generic_init(void) -{ - splat_subsystem_t *sub; - - sub = kmalloc(sizeof(*sub), GFP_KERNEL); - if (sub == NULL) - return NULL; - - memset(sub, 0, sizeof(*sub)); - strncpy(sub->desc.name, SPLAT_GENERIC_NAME, SPLAT_NAME_SIZE); - strncpy(sub->desc.desc, SPLAT_GENERIC_DESC, SPLAT_DESC_SIZE); - INIT_LIST_HEAD(&sub->subsystem_list); - INIT_LIST_HEAD(&sub->test_list); - spin_lock_init(&sub->test_lock); - sub->desc.id = SPLAT_SUBSYSTEM_GENERIC; - - splat_test_init(sub, SPLAT_GENERIC_TEST1_NAME, SPLAT_GENERIC_TEST1_DESC, - SPLAT_GENERIC_TEST1_ID, splat_generic_test_strtoul); - splat_test_init(sub, SPLAT_GENERIC_TEST2_NAME, SPLAT_GENERIC_TEST2_DESC, - SPLAT_GENERIC_TEST2_ID, splat_generic_test_strtol); - splat_test_init(sub, SPLAT_GENERIC_TEST3_NAME, SPLAT_GENERIC_TEST3_DESC, - SPLAT_GENERIC_TEST3_ID, splat_generic_test_strtoull); - splat_test_init(sub, SPLAT_GENERIC_TEST4_NAME, SPLAT_GENERIC_TEST4_DESC, - SPLAT_GENERIC_TEST4_ID, splat_generic_test_strtoll); - splat_test_init(sub, SPLAT_GENERIC_TEST5_NAME, SPLAT_GENERIC_TEST5_DESC, - SPLAT_GENERIC_TEST5_ID, splat_generic_test_udivdi3); - splat_test_init(sub, SPLAT_GENERIC_TEST6_NAME, SPLAT_GENERIC_TEST6_DESC, - SPLAT_GENERIC_TEST6_ID, splat_generic_test_divdi3); - - return sub; -} - -void -splat_generic_fini(splat_subsystem_t *sub) -{ - ASSERT(sub); - - splat_test_fini(sub, SPLAT_GENERIC_TEST6_ID); - splat_test_fini(sub, SPLAT_GENERIC_TEST5_ID); - splat_test_fini(sub, SPLAT_GENERIC_TEST4_ID); - splat_test_fini(sub, SPLAT_GENERIC_TEST3_ID); - splat_test_fini(sub, SPLAT_GENERIC_TEST2_ID); - splat_test_fini(sub, SPLAT_GENERIC_TEST1_ID); - - kfree(sub); -} - -int -splat_generic_id(void) -{ - return SPLAT_SUBSYSTEM_GENERIC; -} diff --git a/module/splat/splat-internal.h b/module/splat/splat-internal.h deleted file mode 100644 index 97c10acfd..000000000 --- a/module/splat/splat-internal.h +++ /dev/null @@ -1,150 +0,0 @@ -/* - * 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). - * Written by Brian Behlendorf <[email protected]>. - * UCRL-CODE-235197 - * - * 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 _SPLAT_INTERNAL_H -#define _SPLAT_INTERNAL_H - -#include "splat-ctl.h" -#include <sys/mutex.h> -#include <linux/file_compat.h> -#include <linux/version.h> - -typedef int (*splat_test_func_t)(struct file *, void *); - -typedef struct splat_test { - struct list_head test_list; - splat_user_t desc; - splat_test_func_t test; -} splat_test_t; - -typedef struct splat_subsystem { - struct list_head subsystem_list;/* List had to chain entries */ - splat_user_t desc; - spinlock_t test_lock; - struct list_head test_list; -} splat_subsystem_t; - -void splat_test_init(splat_subsystem_t *sub, const char *name, - const char *desc, unsigned int tid, splat_test_func_t func); -void splat_test_fini(splat_subsystem_t *sub, unsigned int tid); - -#define SPLAT_INFO_BUFFER_SIZE 65536 -#define SPLAT_INFO_BUFFER_REDZONE 256 - -typedef struct splat_info { - kmutex_t info_lock; - int info_size; - char *info_buffer; - char *info_head; /* Internal kernel use only */ -} splat_info_t; - -#define sym2str(sym) (char *)(#sym) - -#define splat_print(file, format, args...) \ -({ splat_info_t *_info_ = (splat_info_t *)file->private_data; \ - int _rc_; \ - \ - ASSERT(_info_); \ - ASSERT(_info_->info_buffer); \ - \ - mutex_enter(&_info_->info_lock); \ - \ - /* Don't allow the kernel to start a write in the red zone */ \ - if ((int)(_info_->info_head - _info_->info_buffer) > \ - (SPLAT_INFO_BUFFER_SIZE - SPLAT_INFO_BUFFER_REDZONE)) { \ - _rc_ = -EOVERFLOW; \ - } else { \ - _rc_ = sprintf(_info_->info_head, format, args); \ - if (_rc_ >= 0) \ - _info_->info_head += _rc_; \ - } \ - \ - mutex_exit(&_info_->info_lock); \ - _rc_; \ -}) - -#define splat_vprint(file, test, format, args...) \ - splat_print(file, "%*s: " format, SPLAT_NAME_SIZE, test, args) - -#define splat_locked_test(lock, test) \ -({ \ - int _rc_; \ - spin_lock(lock); \ - _rc_ = (test) ? 1 : 0; \ - spin_unlock(lock); \ - _rc_; \ -}) - -splat_subsystem_t *splat_condvar_init(void); -splat_subsystem_t *splat_kmem_init(void); -splat_subsystem_t *splat_mutex_init(void); -splat_subsystem_t *splat_krng_init(void); -splat_subsystem_t *splat_rwlock_init(void); -splat_subsystem_t *splat_taskq_init(void); -splat_subsystem_t *splat_thread_init(void); -splat_subsystem_t *splat_time_init(void); -splat_subsystem_t *splat_vnode_init(void); -splat_subsystem_t *splat_kobj_init(void); -splat_subsystem_t *splat_atomic_init(void); -splat_subsystem_t *splat_list_init(void); -splat_subsystem_t *splat_generic_init(void); -splat_subsystem_t *splat_cred_init(void); -splat_subsystem_t *splat_zlib_init(void); -splat_subsystem_t *splat_linux_init(void); - -void splat_condvar_fini(splat_subsystem_t *); -void splat_kmem_fini(splat_subsystem_t *); -void splat_mutex_fini(splat_subsystem_t *); -void splat_krng_fini(splat_subsystem_t *); -void splat_rwlock_fini(splat_subsystem_t *); -void splat_taskq_fini(splat_subsystem_t *); -void splat_thread_fini(splat_subsystem_t *); -void splat_time_fini(splat_subsystem_t *); -void splat_vnode_fini(splat_subsystem_t *); -void splat_kobj_fini(splat_subsystem_t *); -void splat_atomic_fini(splat_subsystem_t *); -void splat_list_fini(splat_subsystem_t *); -void splat_generic_fini(splat_subsystem_t *); -void splat_cred_fini(splat_subsystem_t *); -void splat_zlib_fini(splat_subsystem_t *); -void splat_linux_fini(splat_subsystem_t *); - -int splat_condvar_id(void); -int splat_kmem_id(void); -int splat_mutex_id(void); -int splat_krng_id(void); -int splat_rwlock_id(void); -int splat_taskq_id(void); -int splat_thread_id(void); -int splat_time_id(void); -int splat_vnode_id(void); -int splat_kobj_id(void); -int splat_atomic_id(void); -int splat_list_id(void); -int splat_generic_id(void); -int splat_cred_id(void); -int splat_zlib_id(void); -int splat_linux_id(void); - -#endif /* _SPLAT_INTERNAL_H */ diff --git a/module/splat/splat-kmem.c b/module/splat/splat-kmem.c deleted file mode 100644 index 282f42d77..000000000 --- a/module/splat/splat-kmem.c +++ /dev/null @@ -1,1410 +0,0 @@ -/* - * 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). - * Written by Brian Behlendorf <[email protected]>. - * UCRL-CODE-235197 - * - * 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/>. - ***************************************************************************** - * Solaris Porting LAyer Tests (SPLAT) Kmem Tests. - */ - -#include <sys/kmem.h> -#include <sys/kmem_cache.h> -#include <sys/vmem.h> -#include <sys/random.h> -#include <sys/thread.h> -#include <sys/vmsystm.h> -#include "splat-internal.h" - -#define SPLAT_KMEM_NAME "kmem" -#define SPLAT_KMEM_DESC "Kernel Malloc/Slab Tests" - -#define SPLAT_KMEM_TEST1_ID 0x0101 -#define SPLAT_KMEM_TEST1_NAME "kmem_alloc" -#define SPLAT_KMEM_TEST1_DESC "Memory allocation test (kmem_alloc)" - -#define SPLAT_KMEM_TEST2_ID 0x0102 -#define SPLAT_KMEM_TEST2_NAME "kmem_zalloc" -#define SPLAT_KMEM_TEST2_DESC "Memory allocation test (kmem_zalloc)" - -#define SPLAT_KMEM_TEST3_ID 0x0103 -#define SPLAT_KMEM_TEST3_NAME "vmem_alloc" -#define SPLAT_KMEM_TEST3_DESC "Memory allocation test (vmem_alloc)" - -#define SPLAT_KMEM_TEST4_ID 0x0104 -#define SPLAT_KMEM_TEST4_NAME "vmem_zalloc" -#define SPLAT_KMEM_TEST4_DESC "Memory allocation test (vmem_zalloc)" - -#define SPLAT_KMEM_TEST5_ID 0x0105 -#define SPLAT_KMEM_TEST5_NAME "slab_small" -#define SPLAT_KMEM_TEST5_DESC "Slab ctor/dtor test (small)" - -#define SPLAT_KMEM_TEST6_ID 0x0106 -#define SPLAT_KMEM_TEST6_NAME "slab_large" -#define SPLAT_KMEM_TEST6_DESC "Slab ctor/dtor test (large)" - -#define SPLAT_KMEM_TEST7_ID 0x0107 -#define SPLAT_KMEM_TEST7_NAME "slab_align" -#define SPLAT_KMEM_TEST7_DESC "Slab alignment test" - -#define SPLAT_KMEM_TEST8_ID 0x0108 -#define SPLAT_KMEM_TEST8_NAME "slab_reap" -#define SPLAT_KMEM_TEST8_DESC "Slab reaping test" - -#define SPLAT_KMEM_TEST9_ID 0x0109 -#define SPLAT_KMEM_TEST9_NAME "slab_age" -#define SPLAT_KMEM_TEST9_DESC "Slab aging test" - -#define SPLAT_KMEM_TEST10_ID 0x010a -#define SPLAT_KMEM_TEST10_NAME "slab_lock" -#define SPLAT_KMEM_TEST10_DESC "Slab locking test" - -#if 0 -#define SPLAT_KMEM_TEST11_ID 0x010b -#define SPLAT_KMEM_TEST11_NAME "slab_overcommit" -#define SPLAT_KMEM_TEST11_DESC "Slab memory overcommit test" -#endif - -#define SPLAT_KMEM_TEST13_ID 0x010d -#define SPLAT_KMEM_TEST13_NAME "slab_reclaim" -#define SPLAT_KMEM_TEST13_DESC "Slab direct memory reclaim test" - -#define SPLAT_KMEM_ALLOC_COUNT 10 -#define SPLAT_VMEM_ALLOC_COUNT 10 - - -static int -splat_kmem_test1(struct file *file, void *arg) -{ - void *ptr[SPLAT_KMEM_ALLOC_COUNT]; - int size = PAGE_SIZE; - int i, count, rc = 0; - - while ((!rc) && (size <= spl_kmem_alloc_warn)) { - count = 0; - - for (i = 0; i < SPLAT_KMEM_ALLOC_COUNT; i++) { - ptr[i] = kmem_alloc(size, KM_SLEEP); - if (ptr[i]) - count++; - } - - for (i = 0; i < SPLAT_KMEM_ALLOC_COUNT; i++) - if (ptr[i]) - kmem_free(ptr[i], size); - - splat_vprint(file, SPLAT_KMEM_TEST1_NAME, - "%d byte allocations, %d/%d successful\n", - size, count, SPLAT_KMEM_ALLOC_COUNT); - if (count != SPLAT_KMEM_ALLOC_COUNT) - rc = -ENOMEM; - - size *= 2; - } - - return rc; -} - -static int -splat_kmem_test2(struct file *file, void *arg) -{ - void *ptr[SPLAT_KMEM_ALLOC_COUNT]; - int size = PAGE_SIZE; - int i, j, count, rc = 0; - - while ((!rc) && (size <= spl_kmem_alloc_warn)) { - count = 0; - - for (i = 0; i < SPLAT_KMEM_ALLOC_COUNT; i++) { - ptr[i] = kmem_zalloc(size, KM_SLEEP); - if (ptr[i]) - count++; - } - - /* Ensure buffer has been zero filled */ - for (i = 0; i < SPLAT_KMEM_ALLOC_COUNT; i++) { - for (j = 0; j < size; j++) { - if (((char *)ptr[i])[j] != '\0') { - splat_vprint(file,SPLAT_KMEM_TEST2_NAME, - "%d-byte allocation was " - "not zeroed\n", size); - rc = -EFAULT; - } - } - } - - for (i = 0; i < SPLAT_KMEM_ALLOC_COUNT; i++) - if (ptr[i]) - kmem_free(ptr[i], size); - - splat_vprint(file, SPLAT_KMEM_TEST2_NAME, - "%d byte allocations, %d/%d successful\n", - size, count, SPLAT_KMEM_ALLOC_COUNT); - if (count != SPLAT_KMEM_ALLOC_COUNT) - rc = -ENOMEM; - - size *= 2; - } - - return rc; -} - -static int -splat_kmem_test3(struct file *file, void *arg) -{ - void *ptr[SPLAT_VMEM_ALLOC_COUNT]; - int size = PAGE_SIZE; - int i, count, rc = 0; - - /* - * Test up to 4x the maximum kmem_alloc() size to ensure both - * the kmem_alloc() and vmem_alloc() call paths are used. - */ - while ((!rc) && (size <= (4 * spl_kmem_alloc_max))) { - count = 0; - - for (i = 0; i < SPLAT_VMEM_ALLOC_COUNT; i++) { - ptr[i] = vmem_alloc(size, KM_SLEEP); - if (ptr[i]) - count++; - } - - for (i = 0; i < SPLAT_VMEM_ALLOC_COUNT; i++) - if (ptr[i]) - vmem_free(ptr[i], size); - - splat_vprint(file, SPLAT_KMEM_TEST3_NAME, - "%d byte allocations, %d/%d successful\n", - size, count, SPLAT_VMEM_ALLOC_COUNT); - if (count != SPLAT_VMEM_ALLOC_COUNT) - rc = -ENOMEM; - - size *= 2; - } - - return rc; -} - -static int -splat_kmem_test4(struct file *file, void *arg) -{ - void *ptr[SPLAT_VMEM_ALLOC_COUNT]; - int size = PAGE_SIZE; - int i, j, count, rc = 0; - - /* - * Test up to 4x the maximum kmem_zalloc() size to ensure both - * the kmem_zalloc() and vmem_zalloc() call paths are used. - */ - while ((!rc) && (size <= (4 * spl_kmem_alloc_max))) { - count = 0; - - for (i = 0; i < SPLAT_VMEM_ALLOC_COUNT; i++) { - ptr[i] = vmem_zalloc(size, KM_SLEEP); - if (ptr[i]) - count++; - } - - /* Ensure buffer has been zero filled */ - for (i = 0; i < SPLAT_VMEM_ALLOC_COUNT; i++) { - for (j = 0; j < size; j++) { - if (((char *)ptr[i])[j] != '\0') { - splat_vprint(file, SPLAT_KMEM_TEST4_NAME, - "%d-byte allocation was " - "not zeroed\n", size); - rc = -EFAULT; - } - } - } - - for (i = 0; i < SPLAT_VMEM_ALLOC_COUNT; i++) - if (ptr[i]) - vmem_free(ptr[i], size); - - splat_vprint(file, SPLAT_KMEM_TEST4_NAME, - "%d byte allocations, %d/%d successful\n", - size, count, SPLAT_VMEM_ALLOC_COUNT); - if (count != SPLAT_VMEM_ALLOC_COUNT) - rc = -ENOMEM; - - size *= 2; - } - - return rc; -} - -#define SPLAT_KMEM_TEST_MAGIC 0x004488CCUL -#define SPLAT_KMEM_CACHE_NAME "kmem_test" -#define SPLAT_KMEM_OBJ_COUNT 1024 -#define SPLAT_KMEM_OBJ_RECLAIM 32 /* objects */ -#define SPLAT_KMEM_THREADS 32 - -#define KCP_FLAG_READY 0x01 - -typedef struct kmem_cache_data { - unsigned long kcd_magic; - struct list_head kcd_node; - int kcd_flag; - char kcd_buf[0]; -} kmem_cache_data_t; - -typedef struct kmem_cache_thread { - spinlock_t kct_lock; - int kct_id; - struct list_head kct_list; -} kmem_cache_thread_t; - -typedef struct kmem_cache_priv { - unsigned long kcp_magic; - struct file *kcp_file; - kmem_cache_t *kcp_cache; - spinlock_t kcp_lock; - spl_wait_queue_head_t kcp_ctl_waitq; - spl_wait_queue_head_t kcp_thr_waitq; - int kcp_flags; - int kcp_kct_count; - kmem_cache_thread_t *kcp_kct[SPLAT_KMEM_THREADS]; - int kcp_size; - int kcp_align; - int kcp_count; - int kcp_alloc; - int kcp_rc; -} kmem_cache_priv_t; - -static kmem_cache_priv_t * -splat_kmem_cache_test_kcp_alloc(struct file *file, char *name, - int size, int align, int alloc) -{ - kmem_cache_priv_t *kcp; - - kcp = kmem_zalloc(sizeof(kmem_cache_priv_t), KM_SLEEP); - if (!kcp) - return NULL; - - kcp->kcp_magic = SPLAT_KMEM_TEST_MAGIC; - kcp->kcp_file = file; - kcp->kcp_cache = NULL; - spin_lock_init(&kcp->kcp_lock); - init_waitqueue_head(&kcp->kcp_ctl_waitq); - init_waitqueue_head(&kcp->kcp_thr_waitq); - kcp->kcp_flags = 0; - kcp->kcp_kct_count = -1; - kcp->kcp_size = size; - kcp->kcp_align = align; - kcp->kcp_count = 0; - kcp->kcp_alloc = alloc; - kcp->kcp_rc = 0; - - return kcp; -} - -static void -splat_kmem_cache_test_kcp_free(kmem_cache_priv_t *kcp) -{ - kmem_free(kcp, sizeof(kmem_cache_priv_t)); -} - -static kmem_cache_thread_t * -splat_kmem_cache_test_kct_alloc(kmem_cache_priv_t *kcp, int id) -{ - kmem_cache_thread_t *kct; - - ASSERT3S(id, <, SPLAT_KMEM_THREADS); - ASSERT(kcp->kcp_kct[id] == NULL); - - kct = kmem_zalloc(sizeof(kmem_cache_thread_t), KM_SLEEP); - if (!kct) - return NULL; - - spin_lock_init(&kct->kct_lock); - kct->kct_id = id; - INIT_LIST_HEAD(&kct->kct_list); - - spin_lock(&kcp->kcp_lock); - kcp->kcp_kct[id] = kct; - spin_unlock(&kcp->kcp_lock); - - return kct; -} - -static void -splat_kmem_cache_test_kct_free(kmem_cache_priv_t *kcp, - kmem_cache_thread_t *kct) -{ - spin_lock(&kcp->kcp_lock); - kcp->kcp_kct[kct->kct_id] = NULL; - spin_unlock(&kcp->kcp_lock); - - kmem_free(kct, sizeof(kmem_cache_thread_t)); -} - -static void -splat_kmem_cache_test_kcd_free(kmem_cache_priv_t *kcp, - kmem_cache_thread_t *kct) -{ - kmem_cache_data_t *kcd; - - spin_lock(&kct->kct_lock); - while (!list_empty(&kct->kct_list)) { - kcd = list_entry(kct->kct_list.next, - kmem_cache_data_t, kcd_node); - list_del(&kcd->kcd_node); - spin_unlock(&kct->kct_lock); - - kmem_cache_free(kcp->kcp_cache, kcd); - - spin_lock(&kct->kct_lock); - } - spin_unlock(&kct->kct_lock); -} - -static int -splat_kmem_cache_test_kcd_alloc(kmem_cache_priv_t *kcp, - kmem_cache_thread_t *kct, int count) -{ - kmem_cache_data_t *kcd; - int i; - - for (i = 0; i < count; i++) { - kcd = kmem_cache_alloc(kcp->kcp_cache, KM_SLEEP); - if (kcd == NULL) { - splat_kmem_cache_test_kcd_free(kcp, kct); - return -ENOMEM; - } - - spin_lock(&kct->kct_lock); - list_add_tail(&kcd->kcd_node, &kct->kct_list); - spin_unlock(&kct->kct_lock); - } - - return 0; -} - -static void -splat_kmem_cache_test_debug(struct file *file, char *name, - kmem_cache_priv_t *kcp) -{ - int j; - - splat_vprint(file, name, "%s cache objects %d", - kcp->kcp_cache->skc_name, kcp->kcp_count); - - if (kcp->kcp_cache->skc_flags & (KMC_KMEM | KMC_VMEM)) { - splat_vprint(file, name, ", slabs %u/%u objs %u/%u", - (unsigned)kcp->kcp_cache->skc_slab_alloc, - (unsigned)kcp->kcp_cache->skc_slab_total, - (unsigned)kcp->kcp_cache->skc_obj_alloc, - (unsigned)kcp->kcp_cache->skc_obj_total); - - if (!(kcp->kcp_cache->skc_flags & KMC_NOMAGAZINE)) { - splat_vprint(file, name, "%s", "mags"); - - for_each_online_cpu(j) - splat_print(file, "%u/%u ", - kcp->kcp_cache->skc_mag[j]->skm_avail, - kcp->kcp_cache->skc_mag[j]->skm_size); - } - } - - splat_print(file, "%s\n", ""); -} - -static int -splat_kmem_cache_test_constructor(void *ptr, void *priv, int flags) -{ - kmem_cache_priv_t *kcp = (kmem_cache_priv_t *)priv; - kmem_cache_data_t *kcd = (kmem_cache_data_t *)ptr; - - if (kcd && kcp) { - kcd->kcd_magic = kcp->kcp_magic; - INIT_LIST_HEAD(&kcd->kcd_node); - kcd->kcd_flag = 1; - memset(kcd->kcd_buf, 0xaa, kcp->kcp_size - (sizeof *kcd)); - kcp->kcp_count++; - } - - return 0; -} - -static void -splat_kmem_cache_test_destructor(void *ptr, void *priv) -{ - kmem_cache_priv_t *kcp = (kmem_cache_priv_t *)priv; - kmem_cache_data_t *kcd = (kmem_cache_data_t *)ptr; - - if (kcd && kcp) { - kcd->kcd_magic = 0; - kcd->kcd_flag = 0; - memset(kcd->kcd_buf, 0xbb, kcp->kcp_size - (sizeof *kcd)); - kcp->kcp_count--; - } - - return; -} - -/* - * Generic reclaim function which assumes that all objects may - * be reclaimed at any time. We free a small percentage of the - * objects linked off the kcp or kct[] every time we are called. - */ -static void -splat_kmem_cache_test_reclaim(void *priv) -{ - kmem_cache_priv_t *kcp = (kmem_cache_priv_t *)priv; - kmem_cache_thread_t *kct; - kmem_cache_data_t *kcd; - LIST_HEAD(reclaim); - int i, count; - - ASSERT(kcp->kcp_magic == SPLAT_KMEM_TEST_MAGIC); - - /* For each kct thread reclaim some objects */ - spin_lock(&kcp->kcp_lock); - for (i = 0; i < SPLAT_KMEM_THREADS; i++) { - kct = kcp->kcp_kct[i]; - if (!kct) - continue; - - spin_unlock(&kcp->kcp_lock); - spin_lock(&kct->kct_lock); - - count = SPLAT_KMEM_OBJ_RECLAIM; - while (count > 0 && !list_empty(&kct->kct_list)) { - kcd = list_entry(kct->kct_list.next, - kmem_cache_data_t, kcd_node); - list_del(&kcd->kcd_node); - list_add(&kcd->kcd_node, &reclaim); - count--; - } - - spin_unlock(&kct->kct_lock); - spin_lock(&kcp->kcp_lock); - } - spin_unlock(&kcp->kcp_lock); - - /* Freed outside the spin lock */ - while (!list_empty(&reclaim)) { - kcd = list_entry(reclaim.next, kmem_cache_data_t, kcd_node); - list_del(&kcd->kcd_node); - kmem_cache_free(kcp->kcp_cache, kcd); - } - - return; -} - -static int -splat_kmem_cache_test_threads(kmem_cache_priv_t *kcp, int threads) -{ - int rc; - - spin_lock(&kcp->kcp_lock); - rc = (kcp->kcp_kct_count == threads); - spin_unlock(&kcp->kcp_lock); - - return rc; -} - -static int -splat_kmem_cache_test_flags(kmem_cache_priv_t *kcp, int flags) -{ - int rc; - - spin_lock(&kcp->kcp_lock); - rc = (kcp->kcp_flags & flags); - spin_unlock(&kcp->kcp_lock); - - return rc; -} - -static void -splat_kmem_cache_test_thread(void *arg) -{ - kmem_cache_priv_t *kcp = (kmem_cache_priv_t *)arg; - kmem_cache_thread_t *kct; - int rc = 0, id; - - ASSERT(kcp->kcp_magic == SPLAT_KMEM_TEST_MAGIC); - - /* Assign thread ids */ - spin_lock(&kcp->kcp_lock); - if (kcp->kcp_kct_count == -1) - kcp->kcp_kct_count = 0; - - id = kcp->kcp_kct_count; - kcp->kcp_kct_count++; - spin_unlock(&kcp->kcp_lock); - - kct = splat_kmem_cache_test_kct_alloc(kcp, id); - if (!kct) { - rc = -ENOMEM; - goto out; - } - - /* Wait for all threads to have started and report they are ready */ - if (kcp->kcp_kct_count == SPLAT_KMEM_THREADS) - wake_up(&kcp->kcp_ctl_waitq); - - wait_event(kcp->kcp_thr_waitq, - splat_kmem_cache_test_flags(kcp, KCP_FLAG_READY)); - - /* Create and destroy objects */ - rc = splat_kmem_cache_test_kcd_alloc(kcp, kct, kcp->kcp_alloc); - splat_kmem_cache_test_kcd_free(kcp, kct); -out: - if (kct) - splat_kmem_cache_test_kct_free(kcp, kct); - - spin_lock(&kcp->kcp_lock); - if (!kcp->kcp_rc) - kcp->kcp_rc = rc; - - if ((--kcp->kcp_kct_count) == 0) - wake_up(&kcp->kcp_ctl_waitq); - - spin_unlock(&kcp->kcp_lock); - - thread_exit(); -} - -static int -splat_kmem_cache_test(struct file *file, void *arg, char *name, - int size, int align, int flags) -{ - kmem_cache_priv_t *kcp = NULL; - kmem_cache_data_t **kcd = NULL; - int i, rc = 0, objs = 0; - - /* Limit size for low memory machines (1/128 of memory) */ - size = MIN(size, (physmem * PAGE_SIZE) >> 7); - - splat_vprint(file, name, - "Testing size=%d, align=%d, flags=0x%04x\n", - size, align, flags); - - kcp = splat_kmem_cache_test_kcp_alloc(file, name, size, align, 0); - if (!kcp) { - splat_vprint(file, name, "Unable to create '%s'\n", "kcp"); - return (-ENOMEM); - } - - kcp->kcp_cache = kmem_cache_create(SPLAT_KMEM_CACHE_NAME, - kcp->kcp_size, kcp->kcp_align, - splat_kmem_cache_test_constructor, - splat_kmem_cache_test_destructor, - NULL, kcp, NULL, flags); - if (kcp->kcp_cache == NULL) { - splat_vprint(file, name, "Unable to create " - "name='%s', size=%d, align=%d, flags=0x%x\n", - SPLAT_KMEM_CACHE_NAME, size, align, flags); - rc = -ENOMEM; - goto out_free; - } - - /* - * Allocate several slabs worth of objects to verify functionality. - * However, on 32-bit systems with limited address space constrain - * it to a single slab for the purposes of this test. - */ -#ifdef _LP64 - objs = kcp->kcp_cache->skc_slab_objs * 4; -#else - objs = 1; -#endif - kcd = kmem_zalloc(sizeof (kmem_cache_data_t *) * objs, KM_SLEEP); - if (kcd == NULL) { - splat_vprint(file, name, "Unable to allocate pointers " - "for %d objects\n", objs); - rc = -ENOMEM; - goto out_free; - } - - for (i = 0; i < objs; i++) { - kcd[i] = kmem_cache_alloc(kcp->kcp_cache, KM_SLEEP); - if (kcd[i] == NULL) { - splat_vprint(file, name, "Unable to allocate " - "from '%s'\n", SPLAT_KMEM_CACHE_NAME); - rc = -EINVAL; - goto out_free; - } - - if (!kcd[i]->kcd_flag) { - splat_vprint(file, name, "Failed to run constructor " - "for '%s'\n", SPLAT_KMEM_CACHE_NAME); - rc = -EINVAL; - goto out_free; - } - - if (kcd[i]->kcd_magic != kcp->kcp_magic) { - splat_vprint(file, name, - "Failed to pass private data to constructor " - "for '%s'\n", SPLAT_KMEM_CACHE_NAME); - rc = -EINVAL; - goto out_free; - } - } - - for (i = 0; i < objs; i++) { - kmem_cache_free(kcp->kcp_cache, kcd[i]); - - /* Destructors are run for every kmem_cache_free() */ - if (kcd[i]->kcd_flag) { - splat_vprint(file, name, - "Failed to run destructor for '%s'\n", - SPLAT_KMEM_CACHE_NAME); - rc = -EINVAL; - goto out_free; - } - } - - if (kcp->kcp_count) { - splat_vprint(file, name, - "Failed to run destructor on all slab objects for '%s'\n", - SPLAT_KMEM_CACHE_NAME); - rc = -EINVAL; - } - - kmem_free(kcd, sizeof (kmem_cache_data_t *) * objs); - kmem_cache_destroy(kcp->kcp_cache); - - splat_kmem_cache_test_kcp_free(kcp); - splat_vprint(file, name, - "Success ran alloc'd/free'd %d objects of size %d\n", - objs, size); - - return (rc); - -out_free: - if (kcd) { - for (i = 0; i < objs; i++) { - if (kcd[i] != NULL) - kmem_cache_free(kcp->kcp_cache, kcd[i]); - } - - kmem_free(kcd, sizeof (kmem_cache_data_t *) * objs); - } - - if (kcp->kcp_cache) - kmem_cache_destroy(kcp->kcp_cache); - - splat_kmem_cache_test_kcp_free(kcp); - - return (rc); -} - -static int -splat_kmem_cache_thread_test(struct file *file, void *arg, char *name, - int size, int alloc, int max_time) -{ - kmem_cache_priv_t *kcp; - kthread_t *thr; - struct timespec start, stop, delta; - char cache_name[32]; - int i, rc = 0; - - kcp = splat_kmem_cache_test_kcp_alloc(file, name, size, 0, alloc); - if (!kcp) { - splat_vprint(file, name, "Unable to create '%s'\n", "kcp"); - return -ENOMEM; - } - - (void)snprintf(cache_name, 32, "%s-%d-%d", - SPLAT_KMEM_CACHE_NAME, size, alloc); - kcp->kcp_cache = - kmem_cache_create(cache_name, kcp->kcp_size, 0, - splat_kmem_cache_test_constructor, - splat_kmem_cache_test_destructor, - splat_kmem_cache_test_reclaim, - kcp, NULL, 0); - if (!kcp->kcp_cache) { - splat_vprint(file, name, "Unable to create '%s'\n", cache_name); - rc = -ENOMEM; - goto out_kcp; - } - - getnstimeofday(&start); - - for (i = 0; i < SPLAT_KMEM_THREADS; i++) { - thr = thread_create(NULL, 0, - splat_kmem_cache_test_thread, - kcp, 0, &p0, TS_RUN, defclsyspri); - if (thr == NULL) { - rc = -ESRCH; - goto out_cache; - } - } - - /* Sleep until all threads have started, then set the ready - * flag and wake them all up for maximum concurrency. */ - wait_event(kcp->kcp_ctl_waitq, - splat_kmem_cache_test_threads(kcp, SPLAT_KMEM_THREADS)); - - spin_lock(&kcp->kcp_lock); - kcp->kcp_flags |= KCP_FLAG_READY; - spin_unlock(&kcp->kcp_lock); - wake_up_all(&kcp->kcp_thr_waitq); - - /* Sleep until all thread have finished */ - wait_event(kcp->kcp_ctl_waitq, splat_kmem_cache_test_threads(kcp, 0)); - - getnstimeofday(&stop); - delta = timespec_sub(stop, start); - - splat_vprint(file, name, - "%-22s %2ld.%09ld\t" - "%lu/%lu/%lu\t%lu/%lu/%lu\n", - kcp->kcp_cache->skc_name, - delta.tv_sec, delta.tv_nsec, - (unsigned long)kcp->kcp_cache->skc_slab_total, - (unsigned long)kcp->kcp_cache->skc_slab_max, - (unsigned long)(kcp->kcp_alloc * - SPLAT_KMEM_THREADS / - SPL_KMEM_CACHE_OBJ_PER_SLAB), - (unsigned long)kcp->kcp_cache->skc_obj_total, - (unsigned long)kcp->kcp_cache->skc_obj_max, - (unsigned long)(kcp->kcp_alloc * - SPLAT_KMEM_THREADS)); - - if (delta.tv_sec >= max_time) - rc = -ETIME; - - if (!rc && kcp->kcp_rc) - rc = kcp->kcp_rc; - -out_cache: - kmem_cache_destroy(kcp->kcp_cache); -out_kcp: - splat_kmem_cache_test_kcp_free(kcp); - return rc; -} - -/* Validate small object cache behavior for dynamic/kmem/vmem caches */ -static int -splat_kmem_test5(struct file *file, void *arg) -{ - char *name = SPLAT_KMEM_TEST5_NAME; - int i, rc = 0; - - /* Randomly pick small object sizes and alignments. */ - for (i = 0; i < 100; i++) { - int size, align, flags = 0; - uint32_t rnd; - - /* Evenly distribute tests over all value cache types */ - get_random_bytes((void *)&rnd, sizeof (uint32_t)); - switch (rnd & 0x03) { - default: - case 0x00: - flags = 0; - break; - case 0x01: - flags = KMC_KMEM; - break; - case 0x02: - flags = KMC_VMEM; - break; - case 0x03: - flags = KMC_SLAB; - break; - } - - /* The following flags are set with a 1/10 chance */ - flags |= ((((rnd >> 8) % 10) == 0) ? KMC_OFFSLAB : 0); - flags |= ((((rnd >> 16) % 10) == 0) ? KMC_NOEMERGENCY : 0); - - /* 32b - PAGE_SIZE */ - get_random_bytes((void *)&rnd, sizeof (uint32_t)); - size = MAX(rnd % (PAGE_SIZE + 1), 32); - - /* 2^N where (3 <= N <= PAGE_SHIFT) */ - get_random_bytes((void *)&rnd, sizeof (uint32_t)); - align = (1 << MAX(3, rnd % (PAGE_SHIFT + 1))); - - rc = splat_kmem_cache_test(file, arg, name, size, align, flags); - if (rc) - return (rc); - } - - return (rc); -} - -/* - * Validate large object cache behavior for dynamic/kmem/vmem caches - */ -static int -splat_kmem_test6(struct file *file, void *arg) -{ - char *name = SPLAT_KMEM_TEST6_NAME; - int i, max_size, rc = 0; - - /* Randomly pick large object sizes and alignments. */ - for (i = 0; i < 100; i++) { - int size, align, flags = 0; - uint32_t rnd; - - /* Evenly distribute tests over all value cache types */ - get_random_bytes((void *)&rnd, sizeof (uint32_t)); - switch (rnd & 0x03) { - default: - case 0x00: - flags = 0; - max_size = (SPL_KMEM_CACHE_MAX_SIZE * 1024 * 1024) / 2; - break; - case 0x01: - flags = KMC_KMEM; - max_size = (SPL_MAX_ORDER_NR_PAGES - 2) * PAGE_SIZE; - break; - case 0x02: - flags = KMC_VMEM; - max_size = (SPL_KMEM_CACHE_MAX_SIZE * 1024 * 1024) / 2; - break; - case 0x03: - flags = KMC_SLAB; - max_size = SPL_MAX_KMEM_ORDER_NR_PAGES * PAGE_SIZE; - break; - } - - /* The following flags are set with a 1/10 chance */ - flags |= ((((rnd >> 8) % 10) == 0) ? KMC_OFFSLAB : 0); - flags |= ((((rnd >> 16) % 10) == 0) ? KMC_NOEMERGENCY : 0); - - /* PAGE_SIZE - max_size */ - get_random_bytes((void *)&rnd, sizeof (uint32_t)); - size = MAX(rnd % (max_size + 1), PAGE_SIZE), - - /* 2^N where (3 <= N <= PAGE_SHIFT) */ - get_random_bytes((void *)&rnd, sizeof (uint32_t)); - align = (1 << MAX(3, rnd % (PAGE_SHIFT + 1))); - - rc = splat_kmem_cache_test(file, arg, name, size, align, flags); - if (rc) - return (rc); - } - - return (rc); -} - -/* - * Validate object alignment cache behavior for caches - */ -static int -splat_kmem_test7(struct file *file, void *arg) -{ - char *name = SPLAT_KMEM_TEST7_NAME; - int max_size = (SPL_KMEM_CACHE_MAX_SIZE * 1024 * 1024) / 2; - int i, rc; - - for (i = SPL_KMEM_CACHE_ALIGN; i <= PAGE_SIZE; i *= 2) { - uint32_t size; - - get_random_bytes((void *)&size, sizeof (uint32_t)); - size = MAX(size % (max_size + 1), 32); - - rc = splat_kmem_cache_test(file, arg, name, size, i, 0); - if (rc) - return rc; - - rc = splat_kmem_cache_test(file, arg, name, size, i, - KMC_OFFSLAB); - if (rc) - return rc; - } - - return rc; -} - -/* - * Validate kmem_cache_reap() by requesting the slab cache free any objects - * it can. For a few reasons this may not immediately result in more free - * memory even if objects are freed. First off, due to fragmentation we - * may not be able to reclaim any slabs. Secondly, even if we do we fully - * clear some slabs we will not want to immediately reclaim all of them - * because we may contend with cache allocations and thrash. What we want - * to see is the slab size decrease more gradually as it becomes clear they - * will not be needed. This should be achievable in less than a minute. - * If it takes longer than this something has gone wrong. - */ -static int -splat_kmem_test8(struct file *file, void *arg) -{ - kmem_cache_priv_t *kcp; - kmem_cache_thread_t *kct; - unsigned int spl_kmem_cache_expire_old; - int i, rc = 0; - - /* Enable cache aging just for this test if it is disabled */ - spl_kmem_cache_expire_old = spl_kmem_cache_expire; - spl_kmem_cache_expire = KMC_EXPIRE_AGE; - - kcp = splat_kmem_cache_test_kcp_alloc(file, SPLAT_KMEM_TEST8_NAME, - 256, 0, 0); - if (!kcp) { - splat_vprint(file, SPLAT_KMEM_TEST8_NAME, - "Unable to create '%s'\n", "kcp"); - rc = -ENOMEM; - goto out; - } - - kcp->kcp_cache = - kmem_cache_create(SPLAT_KMEM_CACHE_NAME, kcp->kcp_size, 0, - splat_kmem_cache_test_constructor, - splat_kmem_cache_test_destructor, - splat_kmem_cache_test_reclaim, - kcp, NULL, 0); - if (!kcp->kcp_cache) { - splat_vprint(file, SPLAT_KMEM_TEST8_NAME, - "Unable to create '%s'\n", SPLAT_KMEM_CACHE_NAME); - rc = -ENOMEM; - goto out_kcp; - } - - kct = splat_kmem_cache_test_kct_alloc(kcp, 0); - if (!kct) { - splat_vprint(file, SPLAT_KMEM_TEST8_NAME, - "Unable to create '%s'\n", "kct"); - rc = -ENOMEM; - goto out_cache; - } - - rc = splat_kmem_cache_test_kcd_alloc(kcp, kct, SPLAT_KMEM_OBJ_COUNT); - if (rc) { - splat_vprint(file, SPLAT_KMEM_TEST8_NAME, "Unable to " - "allocate from '%s'\n", SPLAT_KMEM_CACHE_NAME); - goto out_kct; - } - - /* Force reclaim every 1/10 a second for 60 seconds. */ - for (i = 0; i < 600; i++) { - kmem_cache_reap_now(kcp->kcp_cache); - splat_kmem_cache_test_debug(file, SPLAT_KMEM_TEST8_NAME, kcp); - - if (kcp->kcp_count == 0) - break; - - set_current_state(TASK_INTERRUPTIBLE); - schedule_timeout(HZ / 10); - } - - if (kcp->kcp_count == 0) { - splat_vprint(file, SPLAT_KMEM_TEST8_NAME, - "Successfully created %d objects " - "in cache %s and reclaimed them\n", - SPLAT_KMEM_OBJ_COUNT, SPLAT_KMEM_CACHE_NAME); - } else { - splat_vprint(file, SPLAT_KMEM_TEST8_NAME, - "Failed to reclaim %u/%d objects from cache %s\n", - (unsigned)kcp->kcp_count, - SPLAT_KMEM_OBJ_COUNT, SPLAT_KMEM_CACHE_NAME); - rc = -ENOMEM; - } - - /* Cleanup our mess (for failure case of time expiring) */ - splat_kmem_cache_test_kcd_free(kcp, kct); -out_kct: - splat_kmem_cache_test_kct_free(kcp, kct); -out_cache: - kmem_cache_destroy(kcp->kcp_cache); -out_kcp: - splat_kmem_cache_test_kcp_free(kcp); -out: - spl_kmem_cache_expire = spl_kmem_cache_expire_old; - - return rc; -} - -/* Test cache aging, we have allocated a large number of objects thus - * creating a large number of slabs and then free'd them all. However, - * since there should be little memory pressure at the moment those - * slabs have not been freed. What we want to see is the slab size - * decrease gradually as it becomes clear they will not be be needed. - * This should be achievable in less than minute. If it takes longer - * than this something has gone wrong. - */ -static int -splat_kmem_test9(struct file *file, void *arg) -{ - kmem_cache_priv_t *kcp; - kmem_cache_thread_t *kct; - unsigned int spl_kmem_cache_expire_old; - int i, rc = 0, count = SPLAT_KMEM_OBJ_COUNT * 128; - - /* Enable cache aging just for this test if it is disabled */ - spl_kmem_cache_expire_old = spl_kmem_cache_expire; - spl_kmem_cache_expire = KMC_EXPIRE_AGE; - - kcp = splat_kmem_cache_test_kcp_alloc(file, SPLAT_KMEM_TEST9_NAME, - 256, 0, 0); - if (!kcp) { - splat_vprint(file, SPLAT_KMEM_TEST9_NAME, - "Unable to create '%s'\n", "kcp"); - rc = -ENOMEM; - goto out; - } - - kcp->kcp_cache = - kmem_cache_create(SPLAT_KMEM_CACHE_NAME, kcp->kcp_size, 0, - splat_kmem_cache_test_constructor, - splat_kmem_cache_test_destructor, - NULL, kcp, NULL, 0); - if (!kcp->kcp_cache) { - splat_vprint(file, SPLAT_KMEM_TEST9_NAME, - "Unable to create '%s'\n", SPLAT_KMEM_CACHE_NAME); - rc = -ENOMEM; - goto out_kcp; - } - - kct = splat_kmem_cache_test_kct_alloc(kcp, 0); - if (!kct) { - splat_vprint(file, SPLAT_KMEM_TEST8_NAME, - "Unable to create '%s'\n", "kct"); - rc = -ENOMEM; - goto out_cache; - } - - rc = splat_kmem_cache_test_kcd_alloc(kcp, kct, count); - if (rc) { - splat_vprint(file, SPLAT_KMEM_TEST9_NAME, "Unable to " - "allocate from '%s'\n", SPLAT_KMEM_CACHE_NAME); - goto out_kct; - } - - splat_kmem_cache_test_kcd_free(kcp, kct); - - for (i = 0; i < 60; i++) { - splat_kmem_cache_test_debug(file, SPLAT_KMEM_TEST9_NAME, kcp); - - if (kcp->kcp_count == 0) - break; - - set_current_state(TASK_INTERRUPTIBLE); - schedule_timeout(HZ); - } - - if (kcp->kcp_count == 0) { - splat_vprint(file, SPLAT_KMEM_TEST9_NAME, - "Successfully created %d objects " - "in cache %s and reclaimed them\n", - count, SPLAT_KMEM_CACHE_NAME); - } else { - splat_vprint(file, SPLAT_KMEM_TEST9_NAME, - "Failed to reclaim %u/%d objects from cache %s\n", - (unsigned)kcp->kcp_count, count, - SPLAT_KMEM_CACHE_NAME); - rc = -ENOMEM; - } - -out_kct: - splat_kmem_cache_test_kct_free(kcp, kct); -out_cache: - kmem_cache_destroy(kcp->kcp_cache); -out_kcp: - splat_kmem_cache_test_kcp_free(kcp); -out: - spl_kmem_cache_expire = spl_kmem_cache_expire_old; - - return rc; -} - -/* - * This test creates N threads with a shared kmem cache. They then all - * concurrently allocate and free from the cache to stress the locking and - * concurrent cache performance. If any one test takes longer than 5 - * seconds to complete it is treated as a failure and may indicate a - * performance regression. On my test system no one test takes more - * than 1 second to complete so a 5x slowdown likely a problem. - */ -static int -splat_kmem_test10(struct file *file, void *arg) -{ - uint64_t size, alloc, maxsize, limit, rc = 0; - -#if defined(CONFIG_64BIT) - maxsize = (1024 * 1024); -#else - maxsize = (128 * 1024); -#endif - - for (size = 32; size <= maxsize; size *= 2) { - - splat_vprint(file, SPLAT_KMEM_TEST10_NAME, "%-22s %s", "name", - "time (sec)\tslabs \tobjs \thash\n"); - splat_vprint(file, SPLAT_KMEM_TEST10_NAME, "%-22s %s", "", - " \ttot/max/calc\ttot/max/calc\n"); - - for (alloc = 1; alloc <= 1024; alloc *= 2) { - - /* Skip tests which exceed 1/2 of memory. */ - limit = MIN(physmem * PAGE_SIZE, - vmem_size(NULL, VMEM_ALLOC | VMEM_FREE)) / 2; - if (size * alloc * SPLAT_KMEM_THREADS > limit) - continue; - - rc = splat_kmem_cache_thread_test(file, arg, - SPLAT_KMEM_TEST10_NAME, size, alloc, 5); - if (rc) - break; - } - } - - return rc; -} - -#if 0 -/* - * This test creates N threads with a shared kmem cache which overcommits - * memory by 4x. This makes it impossible for the slab to satify the - * thread requirements without having its reclaim hook run which will - * free objects back for use. This behavior is triggered by the linum VM - * detecting a low memory condition on the node and invoking the shrinkers. - * This should allow all the threads to complete while avoiding deadlock - * and for the most part out of memory events. This is very tough on the - * system so it is possible the test app may get oom'ed. This particular - * test has proven troublesome on 32-bit archs with limited virtual - * address space so it only run on 64-bit systems. - */ -static int -splat_kmem_test11(struct file *file, void *arg) -{ - uint64_t size, alloc, rc; - - size = 8 * 1024; - alloc = ((4 * physmem * PAGE_SIZE) / size) / SPLAT_KMEM_THREADS; - - splat_vprint(file, SPLAT_KMEM_TEST11_NAME, "%-22s %s", "name", - "time (sec)\tslabs \tobjs \thash\n"); - splat_vprint(file, SPLAT_KMEM_TEST11_NAME, "%-22s %s", "", - " \ttot/max/calc\ttot/max/calc\n"); - - rc = splat_kmem_cache_thread_test(file, arg, - SPLAT_KMEM_TEST11_NAME, size, alloc, 60); - - return rc; -} -#endif - -typedef struct dummy_page { - struct list_head dp_list; - char dp_pad[PAGE_SIZE - sizeof(struct list_head)]; -} dummy_page_t; - -/* - * This test is designed to verify that direct reclaim is functioning as - * expected. We allocate a large number of objects thus creating a large - * number of slabs. We then apply memory pressure and expect that the - * direct reclaim path can easily recover those slabs. The registered - * reclaim function will free the objects and the slab shrinker will call - * it repeatedly until at least a single slab can be freed. - * - * Note it may not be possible to reclaim every last slab via direct reclaim - * without a failure because the shrinker_rwsem may be contended. For this - * reason, quickly reclaiming 3/4 of the slabs is considered a success. - * - * This should all be possible within 10 seconds. For reference, on a - * system with 2G of memory this test takes roughly 0.2 seconds to run. - * It may take longer on larger memory systems but should still easily - * complete in the alloted 10 seconds. - */ -static int -splat_kmem_test13(struct file *file, void *arg) -{ - kmem_cache_priv_t *kcp; - kmem_cache_thread_t *kct; - dummy_page_t *dp; - struct list_head list; - struct timespec start, stop, delta = { 0, 0 }; - int size, count, slabs, fails = 0; - int i, rc = 0, max_time = 10; - - size = 128 * 1024; - count = MIN(physmem * PAGE_SIZE, vmem_size(NULL, - VMEM_ALLOC | VMEM_FREE)) / 4 / size; - - kcp = splat_kmem_cache_test_kcp_alloc(file, SPLAT_KMEM_TEST13_NAME, - size, 0, 0); - if (!kcp) { - splat_vprint(file, SPLAT_KMEM_TEST13_NAME, - "Unable to create '%s'\n", "kcp"); - rc = -ENOMEM; - goto out; - } - - kcp->kcp_cache = - kmem_cache_create(SPLAT_KMEM_CACHE_NAME, kcp->kcp_size, 0, - splat_kmem_cache_test_constructor, - splat_kmem_cache_test_destructor, - splat_kmem_cache_test_reclaim, - kcp, NULL, 0); - if (!kcp->kcp_cache) { - splat_vprint(file, SPLAT_KMEM_TEST13_NAME, - "Unable to create '%s'\n", SPLAT_KMEM_CACHE_NAME); - rc = -ENOMEM; - goto out_kcp; - } - - kct = splat_kmem_cache_test_kct_alloc(kcp, 0); - if (!kct) { - splat_vprint(file, SPLAT_KMEM_TEST13_NAME, - "Unable to create '%s'\n", "kct"); - rc = -ENOMEM; - goto out_cache; - } - - rc = splat_kmem_cache_test_kcd_alloc(kcp, kct, count); - if (rc) { - splat_vprint(file, SPLAT_KMEM_TEST13_NAME, "Unable to " - "allocate from '%s'\n", SPLAT_KMEM_CACHE_NAME); - goto out_kct; - } - - i = 0; - slabs = kcp->kcp_cache->skc_slab_total; - INIT_LIST_HEAD(&list); - getnstimeofday(&start); - - /* Apply memory pressure */ - while (kcp->kcp_cache->skc_slab_total > (slabs >> 2)) { - - if ((i % 10000) == 0) - splat_kmem_cache_test_debug( - file, SPLAT_KMEM_TEST13_NAME, kcp); - - getnstimeofday(&stop); - delta = timespec_sub(stop, start); - if (delta.tv_sec >= max_time) { - splat_vprint(file, SPLAT_KMEM_TEST13_NAME, - "Failed to reclaim 3/4 of cache in %ds, " - "%u/%u slabs remain\n", max_time, - (unsigned)kcp->kcp_cache->skc_slab_total, - slabs); - rc = -ETIME; - break; - } - - dp = (dummy_page_t *)__get_free_page(GFP_KERNEL); - if (!dp) { - fails++; - splat_vprint(file, SPLAT_KMEM_TEST13_NAME, - "Failed (%d) to allocate page with %u " - "slabs still in the cache\n", fails, - (unsigned)kcp->kcp_cache->skc_slab_total); - continue; - } - - list_add(&dp->dp_list, &list); - i++; - } - - if (rc == 0) - splat_vprint(file, SPLAT_KMEM_TEST13_NAME, - "Successfully created %u slabs and with %d alloc " - "failures reclaimed 3/4 of them in %d.%03ds\n", - slabs, fails, - (int)delta.tv_sec, (int)delta.tv_nsec / 1000000); - - /* Release memory pressure pages */ - while (!list_empty(&list)) { - dp = list_entry(list.next, dummy_page_t, dp_list); - list_del_init(&dp->dp_list); - free_page((unsigned long)dp); - } - - /* Release remaining kmem cache objects */ - splat_kmem_cache_test_kcd_free(kcp, kct); -out_kct: - splat_kmem_cache_test_kct_free(kcp, kct); -out_cache: - kmem_cache_destroy(kcp->kcp_cache); -out_kcp: - splat_kmem_cache_test_kcp_free(kcp); -out: - return rc; -} - -splat_subsystem_t * -splat_kmem_init(void) -{ - splat_subsystem_t *sub; - - sub = kmalloc(sizeof(*sub), GFP_KERNEL); - if (sub == NULL) - return NULL; - - memset(sub, 0, sizeof(*sub)); - strncpy(sub->desc.name, SPLAT_KMEM_NAME, SPLAT_NAME_SIZE); - strncpy(sub->desc.desc, SPLAT_KMEM_DESC, SPLAT_DESC_SIZE); - INIT_LIST_HEAD(&sub->subsystem_list); - INIT_LIST_HEAD(&sub->test_list); - spin_lock_init(&sub->test_lock); - sub->desc.id = SPLAT_SUBSYSTEM_KMEM; - - splat_test_init(sub, SPLAT_KMEM_TEST1_NAME, SPLAT_KMEM_TEST1_DESC, - SPLAT_KMEM_TEST1_ID, splat_kmem_test1); - splat_test_init(sub, SPLAT_KMEM_TEST2_NAME, SPLAT_KMEM_TEST2_DESC, - SPLAT_KMEM_TEST2_ID, splat_kmem_test2); - splat_test_init(sub, SPLAT_KMEM_TEST3_NAME, SPLAT_KMEM_TEST3_DESC, - SPLAT_KMEM_TEST3_ID, splat_kmem_test3); - splat_test_init(sub, SPLAT_KMEM_TEST4_NAME, SPLAT_KMEM_TEST4_DESC, - SPLAT_KMEM_TEST4_ID, splat_kmem_test4); - splat_test_init(sub, SPLAT_KMEM_TEST5_NAME, SPLAT_KMEM_TEST5_DESC, - SPLAT_KMEM_TEST5_ID, splat_kmem_test5); - splat_test_init(sub, SPLAT_KMEM_TEST6_NAME, SPLAT_KMEM_TEST6_DESC, - SPLAT_KMEM_TEST6_ID, splat_kmem_test6); - splat_test_init(sub, SPLAT_KMEM_TEST7_NAME, SPLAT_KMEM_TEST7_DESC, - SPLAT_KMEM_TEST7_ID, splat_kmem_test7); - splat_test_init(sub, SPLAT_KMEM_TEST8_NAME, SPLAT_KMEM_TEST8_DESC, - SPLAT_KMEM_TEST8_ID, splat_kmem_test8); - splat_test_init(sub, SPLAT_KMEM_TEST9_NAME, SPLAT_KMEM_TEST9_DESC, - SPLAT_KMEM_TEST9_ID, splat_kmem_test9); - splat_test_init(sub, SPLAT_KMEM_TEST10_NAME, SPLAT_KMEM_TEST10_DESC, - SPLAT_KMEM_TEST10_ID, splat_kmem_test10); -#if 0 - splat_test_init(sub, SPLAT_KMEM_TEST11_NAME, SPLAT_KMEM_TEST11_DESC, - SPLAT_KMEM_TEST11_ID, splat_kmem_test11); -#endif - splat_test_init(sub, SPLAT_KMEM_TEST13_NAME, SPLAT_KMEM_TEST13_DESC, - SPLAT_KMEM_TEST13_ID, splat_kmem_test13); - - return sub; -} - -void -splat_kmem_fini(splat_subsystem_t *sub) -{ - ASSERT(sub); - splat_test_fini(sub, SPLAT_KMEM_TEST13_ID); -#if 0 - splat_test_fini(sub, SPLAT_KMEM_TEST11_ID); -#endif - splat_test_fini(sub, SPLAT_KMEM_TEST10_ID); - splat_test_fini(sub, SPLAT_KMEM_TEST9_ID); - splat_test_fini(sub, SPLAT_KMEM_TEST8_ID); - splat_test_fini(sub, SPLAT_KMEM_TEST7_ID); - splat_test_fini(sub, SPLAT_KMEM_TEST6_ID); - splat_test_fini(sub, SPLAT_KMEM_TEST5_ID); - splat_test_fini(sub, SPLAT_KMEM_TEST4_ID); - splat_test_fini(sub, SPLAT_KMEM_TEST3_ID); - splat_test_fini(sub, SPLAT_KMEM_TEST2_ID); - splat_test_fini(sub, SPLAT_KMEM_TEST1_ID); - - kfree(sub); -} - -int -splat_kmem_id(void) { - return SPLAT_SUBSYSTEM_KMEM; -} diff --git a/module/splat/splat-kobj.c b/module/splat/splat-kobj.c deleted file mode 100644 index bd44de395..000000000 --- a/module/splat/splat-kobj.c +++ /dev/null @@ -1,166 +0,0 @@ -/* - * 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). - * Written by Brian Behlendorf <[email protected]>. - * UCRL-CODE-235197 - * - * 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/>. - ***************************************************************************** - * Solaris Porting LAyer Tests (SPLAT) Kobj Tests. - */ - -#include <sys/kobj.h> -#include "splat-internal.h" - -#define SPLAT_KOBJ_NAME "kobj" -#define SPLAT_KOBJ_DESC "Kernel Kobj Tests" - -#define SPLAT_KOBJ_TEST1_ID 0x0a01 -#define SPLAT_KOBJ_TEST1_NAME "open" -#define SPLAT_KOBJ_TEST1_DESC "Kobj Open/Close Test" - -#define SPLAT_KOBJ_TEST2_ID 0x0a02 -#define SPLAT_KOBJ_TEST2_NAME "size/read" -#define SPLAT_KOBJ_TEST2_DESC "Kobj Size/Read Test" - -#define SPLAT_KOBJ_TEST_FILE "/etc/fstab" - -static int -splat_kobj_test1(struct file *file, void *arg) -{ - struct _buf *f; - - f = kobj_open_file(SPLAT_KOBJ_TEST_FILE); - if (f == (struct _buf *)-1) { - splat_vprint(file, SPLAT_KOBJ_TEST1_NAME, "Failed to open " - "test file: %s\n", SPLAT_KOBJ_TEST_FILE); - return -ENOENT; - } - - kobj_close_file(f); - splat_vprint(file, SPLAT_KOBJ_TEST1_NAME, "Successfully opened and " - "closed test file: %s\n", SPLAT_KOBJ_TEST_FILE); - - return 0; -} /* splat_kobj_test1() */ - -static int -splat_kobj_test2(struct file *file, void *arg) -{ - struct _buf *f; - char *buf; - uint64_t size; - int rc; - - f = kobj_open_file(SPLAT_KOBJ_TEST_FILE); - if (f == (struct _buf *)-1) { - splat_vprint(file, SPLAT_KOBJ_TEST2_NAME, "Failed to open " - "test file: %s\n", SPLAT_KOBJ_TEST_FILE); - return -ENOENT; - } - - rc = kobj_get_filesize(f, &size); - if (rc) { - splat_vprint(file, SPLAT_KOBJ_TEST2_NAME, "Failed stat of " - "test file: %s (%d)\n", SPLAT_KOBJ_TEST_FILE, rc); - goto out; - } - - buf = kmalloc(size + 1, GFP_KERNEL); - if (!buf) { - rc = -ENOMEM; - splat_vprint(file, SPLAT_KOBJ_TEST2_NAME, "Failed to alloc " - "%lld bytes for tmp buffer (%d)\n", - (long long)size, rc); - goto out; - } - - memset(buf, 0, size + 1); - rc = kobj_read_file(f, buf, size, 0); - if (rc < 0) { - splat_vprint(file, SPLAT_KOBJ_TEST2_NAME, "Failed read of " - "test file: %s (%d)\n", SPLAT_KOBJ_TEST_FILE, rc); - goto out2; - } - - /* Validate we read as many bytes as expected based on the stat. This - * isn't a perfect test since we didn't create the file however it is - * pretty unlikely there are garbage characters in your /etc/fstab */ - if (size != (uint64_t)strlen(buf)) { - rc = -EFBIG; - splat_vprint(file, SPLAT_KOBJ_TEST2_NAME, "Stat'ed size " - "(%lld) does not match number of bytes read " - "(%lld)\n", (long long)size, - (long long)strlen(buf)); - goto out2; - } - - rc = 0; - splat_vprint(file, SPLAT_KOBJ_TEST2_NAME, "\n%s\n", buf); - splat_vprint(file, SPLAT_KOBJ_TEST2_NAME, "Successfully stat'ed " - "and read expected number of bytes (%lld) from test " - "file: %s\n", (long long)size, SPLAT_KOBJ_TEST_FILE); -out2: - kfree(buf); -out: - kobj_close_file(f); - - return rc; -} /* splat_kobj_test2() */ - -splat_subsystem_t * -splat_kobj_init(void) -{ - splat_subsystem_t *sub; - - sub = kmalloc(sizeof(*sub), GFP_KERNEL); - if (sub == NULL) - return NULL; - - memset(sub, 0, sizeof(*sub)); - strncpy(sub->desc.name, SPLAT_KOBJ_NAME, SPLAT_NAME_SIZE); - strncpy(sub->desc.desc, SPLAT_KOBJ_DESC, SPLAT_DESC_SIZE); - INIT_LIST_HEAD(&sub->subsystem_list); - INIT_LIST_HEAD(&sub->test_list); - spin_lock_init(&sub->test_lock); - sub->desc.id = SPLAT_SUBSYSTEM_KOBJ; - - splat_test_init(sub, SPLAT_KOBJ_TEST1_NAME, SPLAT_KOBJ_TEST1_DESC, - SPLAT_KOBJ_TEST1_ID, splat_kobj_test1); - splat_test_init(sub, SPLAT_KOBJ_TEST2_NAME, SPLAT_KOBJ_TEST2_DESC, - SPLAT_KOBJ_TEST2_ID, splat_kobj_test2); - - return sub; -} /* splat_kobj_init() */ - -void -splat_kobj_fini(splat_subsystem_t *sub) -{ - ASSERT(sub); - - splat_test_fini(sub, SPLAT_KOBJ_TEST2_ID); - splat_test_fini(sub, SPLAT_KOBJ_TEST1_ID); - - kfree(sub); -} /* splat_kobj_fini() */ - -int -splat_kobj_id(void) -{ - return SPLAT_SUBSYSTEM_KOBJ; -} /* splat_kobj_id() */ diff --git a/module/splat/splat-linux.c b/module/splat/splat-linux.c deleted file mode 100644 index 1565d74a3..000000000 --- a/module/splat/splat-linux.c +++ /dev/null @@ -1,237 +0,0 @@ -/* - * Copyright (C) 2011 Lawrence Livermore National Security, LLC. - * Produced at Lawrence Livermore National Laboratory (cf, DISCLAIMER). - * Written by Brian Behlendorf <[email protected]>. - * UCRL-CODE-235197 - * - * 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/>. - ***************************************************************************** - * Solaris Porting LAyer Tests (SPLAT) Kernel Compatibility Tests. - */ - -#include <sys/kmem.h> -#include <linux/mm_compat.h> -#include "splat-internal.h" - -#define SPLAT_LINUX_NAME "linux" -#define SPLAT_LINUX_DESC "Kernel Compatibility Tests" - -#define SPLAT_LINUX_TEST1_ID 0x1001 -#define SPLAT_LINUX_TEST1_NAME "shrinker" -#define SPLAT_LINUX_TEST1_DESC "Shrinker test" - -/* - * Wait queue used to eliminate race between dropping of slab - * and execution of the shrinker callback - */ -DECLARE_WAIT_QUEUE_HEAD(shrinker_wait); - -SPL_SHRINKER_CALLBACK_FWD_DECLARE(splat_linux_shrinker_fn); -SPL_SHRINKER_DECLARE(splat_linux_shrinker, splat_linux_shrinker_fn, 1); -static unsigned long splat_linux_shrinker_size = 0; -static struct file *splat_linux_shrinker_file = NULL; - -static spl_shrinker_t -__splat_linux_shrinker_fn(struct shrinker *shrink, struct shrink_control *sc) -{ - static int failsafe = 0; - static unsigned long last_splat_linux_shrinker_size = 0; - unsigned long size; - spl_shrinker_t count; - - /* - * shrinker_size can only decrease or stay the same between callbacks - * in the same run, so Reset failsafe whenever shrinker increases - * as this indicates a new run. - */ - if (last_splat_linux_shrinker_size < splat_linux_shrinker_size) - failsafe = 0; - - last_splat_linux_shrinker_size = splat_linux_shrinker_size; - - if (sc->nr_to_scan) { - size = MIN(sc->nr_to_scan, splat_linux_shrinker_size); - splat_linux_shrinker_size -= size; - - splat_vprint(splat_linux_shrinker_file, SPLAT_LINUX_TEST1_NAME, - "Reclaimed %lu objects, size now %lu\n", - size, splat_linux_shrinker_size); - -#ifdef HAVE_SPLIT_SHRINKER_CALLBACK - count = size; -#else - count = splat_linux_shrinker_size; -#endif /* HAVE_SPLIT_SHRINKER_CALLBACK */ - - } else { - count = splat_linux_shrinker_size; - splat_vprint(splat_linux_shrinker_file, SPLAT_LINUX_TEST1_NAME, - "Cache size is %lu\n", splat_linux_shrinker_size); - } - - /* Far more calls than expected abort drop_slab as a failsafe */ - if (failsafe > 100) { - splat_vprint(splat_linux_shrinker_file, SPLAT_LINUX_TEST1_NAME, - "Far more calls than expected (%d), size now %lu\n", - failsafe, splat_linux_shrinker_size); - return (SHRINK_STOP); - } else { - /* - * We only increment failsafe if it doesn't trigger. This - * makes any failsafe failure persistent until the next test. - */ - failsafe++; - } - - /* Shrinker has run, so signal back to test. */ - wake_up(&shrinker_wait); - - return (count); -} - -SPL_SHRINKER_CALLBACK_WRAPPER(splat_linux_shrinker_fn); - -#define DROP_SLAB_CMD \ - "exec 0</dev/null " \ - " 1>/proc/sys/vm/drop_caches " \ - " 2>/dev/null; " \ - "echo 2" - -static int -splat_linux_drop_slab(struct file *file) -{ - char *argv[] = { "/bin/sh", - "-c", - DROP_SLAB_CMD, - NULL }; - char *envp[] = { "HOME=/", - "TERM=linux", - "PATH=/sbin:/usr/sbin:/bin:/usr/bin", - NULL }; - int rc; - - rc = call_usermodehelper(argv[0], argv, envp, UMH_WAIT_PROC); - if (rc) - splat_vprint(file, SPLAT_LINUX_TEST1_NAME, - "Failed user helper '%s %s %s', rc = %d\n", - argv[0], argv[1], argv[2], rc); - - return rc; -} - -/* - * Verify correct shrinker functionality by registering a shrinker - * with the required compatibility macros. We then use a simulated - * cache and force the systems caches to be dropped. The shrinker - * should be repeatedly called until it reports that the cache is - * empty. It is then cleanly unregistered and correct behavior is - * verified. There are now four slightly different supported shrinker - * API and this test ensures the compatibility code is correct. - */ -static int -splat_linux_test1(struct file *file, void *arg) -{ - int rc = -EINVAL; - - /* - * Globals used by the shrinker, it is not safe to run this - * test concurrently this is a safe assumption for SPLAT tests. - * Regardless we do some minimal checking a bail if concurrent - * use is detected. - */ - if (splat_linux_shrinker_size || splat_linux_shrinker_file) { - splat_vprint(file, SPLAT_LINUX_TEST1_NAME, - "Failed due to concurrent shrinker test, rc = %d\n", rc); - return (rc); - } - - splat_linux_shrinker_size = 1024; - splat_linux_shrinker_file = file; - - spl_register_shrinker(&splat_linux_shrinker); - rc = splat_linux_drop_slab(file); - if (rc) - goto out; - - /* - * By the time we get here, it is possible that the shrinker has not - * yet run. splat_linux_drop_slab sends a signal for it to run, but - * there is no guarantee of when it will actually run. We wait for it - * to run here, terminating when either the shrinker size is now 0 or - * we timeout after 1 second, which should be an eternity (error). - */ - rc = wait_event_timeout(shrinker_wait, !splat_linux_shrinker_size, HZ); - if (!rc) { - splat_vprint(file, SPLAT_LINUX_TEST1_NAME, - "Failed cache shrinking timed out, size now %lu", - splat_linux_shrinker_size); - rc = -ETIMEDOUT; - } else { - rc = 0; - } - - if (!rc && splat_linux_shrinker_size != 0) { - splat_vprint(file, SPLAT_LINUX_TEST1_NAME, - "Failed cache was not shrunk to 0, size now %lu", - splat_linux_shrinker_size); - rc = -EDOM; - } -out: - spl_unregister_shrinker(&splat_linux_shrinker); - - splat_linux_shrinker_size = 0; - splat_linux_shrinker_file = NULL; - - return rc; -} - -splat_subsystem_t * -splat_linux_init(void) -{ - splat_subsystem_t *sub; - - sub = kmalloc(sizeof(*sub), GFP_KERNEL); - if (sub == NULL) - return NULL; - - memset(sub, 0, sizeof(*sub)); - strncpy(sub->desc.name, SPLAT_LINUX_NAME, SPLAT_NAME_SIZE); - strncpy(sub->desc.desc, SPLAT_LINUX_DESC, SPLAT_DESC_SIZE); - INIT_LIST_HEAD(&sub->subsystem_list); - INIT_LIST_HEAD(&sub->test_list); - spin_lock_init(&sub->test_lock); - sub->desc.id = SPLAT_SUBSYSTEM_LINUX; - - splat_test_init(sub, SPLAT_LINUX_TEST1_NAME, SPLAT_LINUX_TEST1_DESC, - SPLAT_LINUX_TEST1_ID, splat_linux_test1); - - return sub; -} - -void -splat_linux_fini(splat_subsystem_t *sub) -{ - ASSERT(sub); - splat_test_fini(sub, SPLAT_LINUX_TEST1_ID); - - kfree(sub); -} - -int -splat_linux_id(void) { - return SPLAT_SUBSYSTEM_LINUX; -} diff --git a/module/splat/splat-list.c b/module/splat/splat-list.c deleted file mode 100644 index 8a5f3c937..000000000 --- a/module/splat/splat-list.c +++ /dev/null @@ -1,475 +0,0 @@ -/* - * 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). - * Written by Brian Behlendorf <[email protected]>. - * UCRL-CODE-235197 - * - * 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/>. - ***************************************************************************** - * Solaris Porting LAyer Tests (SPLAT) List Tests. - */ - -#include <sys/list.h> -#include <sys/kmem.h> -#include "splat-internal.h" - -#define SPLAT_LIST_NAME "list" -#define SPLAT_LIST_DESC "Kernel List Tests" - -#define SPLAT_LIST_TEST1_ID 0x0c01 -#define SPLAT_LIST_TEST1_NAME "create/destroy" -#define SPLAT_LIST_TEST1_DESC "Create/destroy Test" - -#define SPLAT_LIST_TEST2_ID 0x0c02 -#define SPLAT_LIST_TEST2_NAME "ins/rm head" -#define SPLAT_LIST_TEST2_DESC "Insert/remove head Test" - -#define SPLAT_LIST_TEST3_ID 0x0c03 -#define SPLAT_LIST_TEST3_NAME "ins/rm tail" -#define SPLAT_LIST_TEST3_DESC "Insert/remove tail Test" - -#define SPLAT_LIST_TEST4_ID 0x0c04 -#define SPLAT_LIST_TEST4_NAME "insert_after" -#define SPLAT_LIST_TEST4_DESC "Insert_after Test" - -#define SPLAT_LIST_TEST5_ID 0x0c05 -#define SPLAT_LIST_TEST5_NAME "insert_before" -#define SPLAT_LIST_TEST5_DESC "Insert_before Test" - -#define SPLAT_LIST_TEST6_ID 0x0c06 -#define SPLAT_LIST_TEST6_NAME "remove" -#define SPLAT_LIST_TEST6_DESC "Remove Test" - -#define SPLAT_LIST_TEST7_ID 0x0c7 -#define SPLAT_LIST_TEST7_NAME "active" -#define SPLAT_LIST_TEST7_DESC "Active Test" - -/* It is important that li_node is not the first element, this - * ensures the list_d2l/list_object macros are working correctly. */ -typedef struct list_item { - int li_data; - list_node_t li_node; -} list_item_t; - -#define LIST_ORDER_STACK 0 -#define LIST_ORDER_QUEUE 1 - -static int -splat_list_test1(struct file *file, void *arg) -{ - list_t list; - - splat_vprint(file, SPLAT_LIST_TEST1_NAME, "Creating list\n%s", ""); - list_create(&list, sizeof(list_item_t), offsetof(list_item_t, li_node)); - - if (!list_is_empty(&list)) { - splat_vprint(file, SPLAT_LIST_TEST1_NAME, - "New list NOT empty%s\n", ""); - /* list_destroy() intentionally skipped to avoid assert */ - return -EEXIST; - } - - splat_vprint(file, SPLAT_LIST_TEST1_NAME, "Destroying list\n%s", ""); - list_destroy(&list); - - /* Validate the list has been destroyed */ - if (list_link_active(&list.list_head)) { - splat_vprint(file, SPLAT_LIST_TEST1_NAME, - "Destroyed list still active%s", ""); - return -EIO; - } - - return 0; -} - -static int -splat_list_validate(list_t *list, int size, int order, int mult) -{ - list_item_t *li; - int i; - - /* Walk all items in list from head to verify stack or queue - * ordering. We bound the for loop by size+1 to ensure that - * we still terminate if there is list corruption. We also - * intentionally make things a little more complex than they - * need to be by using list_head/list_next for queues, and - * list_tail/list_prev for stacks. This is simply done for - * coverage and to ensure these function are working right. - */ - for (i = 0, li = (order ? list_head(list) : list_tail(list)); - i < size + 1 && li != NULL; - i++, li = (order ? list_next(list, li) : list_prev(list, li))) - if (li->li_data != i * mult) - return -EIDRM; - - if (i != size) - return -E2BIG; - - return 0; -} - -static int -splat_list_test2(struct file *file, void *arg) -{ - list_t list; - list_item_t *li; - int i, list_size = 8, rc = 0; - - splat_vprint(file, SPLAT_LIST_TEST2_NAME, "Creating list\n%s", ""); - list_create(&list, sizeof(list_item_t), offsetof(list_item_t, li_node)); - - /* Insert all items at the list head to form a stack */ - splat_vprint(file, SPLAT_LIST_TEST2_NAME, - "Adding %d items to list head\n", list_size); - for (i = 0; i < list_size; i++) { - li = kmem_alloc(sizeof(list_item_t), KM_SLEEP); - if (li == NULL) { - rc = -ENOMEM; - goto out; - } - - list_link_init(&li->li_node); - li->li_data = i; - list_insert_head(&list, li); - } - - splat_vprint(file, SPLAT_LIST_TEST2_NAME, - "Validating %d item list is a stack\n", list_size); - rc = splat_list_validate(&list, list_size, LIST_ORDER_STACK, 1); - if (rc) - splat_vprint(file, SPLAT_LIST_TEST2_NAME, - "List validation failed, %d\n", rc); -out: - /* Remove all items */ - splat_vprint(file, SPLAT_LIST_TEST2_NAME, - "Removing %d items from list head\n", list_size); - while ((li = list_remove_head(&list))) - kmem_free(li, sizeof(list_item_t)); - - splat_vprint(file, SPLAT_LIST_TEST2_NAME, "Destroying list\n%s", ""); - list_destroy(&list); - - return rc; -} - -static int -splat_list_test3(struct file *file, void *arg) -{ - list_t list; - list_item_t *li; - int i, list_size = 8, rc = 0; - - splat_vprint(file, SPLAT_LIST_TEST3_NAME, "Creating list\n%s", ""); - list_create(&list, sizeof(list_item_t), offsetof(list_item_t, li_node)); - - /* Insert all items at the list tail to form a queue */ - splat_vprint(file, SPLAT_LIST_TEST3_NAME, - "Adding %d items to list tail\n", list_size); - for (i = 0; i < list_size; i++) { - li = kmem_alloc(sizeof(list_item_t), KM_SLEEP); - if (li == NULL) { - rc = -ENOMEM; - goto out; - } - - list_link_init(&li->li_node); - li->li_data = i; - list_insert_tail(&list, li); - } - - splat_vprint(file, SPLAT_LIST_TEST3_NAME, - "Validating %d item list is a queue\n", list_size); - rc = splat_list_validate(&list, list_size, LIST_ORDER_QUEUE, 1); - if (rc) - splat_vprint(file, SPLAT_LIST_TEST3_NAME, - "List validation failed, %d\n", rc); -out: - /* Remove all items */ - splat_vprint(file, SPLAT_LIST_TEST3_NAME, - "Removing %d items from list tail\n", list_size); - while ((li = list_remove_tail(&list))) - kmem_free(li, sizeof(list_item_t)); - - splat_vprint(file, SPLAT_LIST_TEST3_NAME, "Destroying list\n%s", ""); - list_destroy(&list); - - return rc; -} - -static int -splat_list_test4(struct file *file, void *arg) -{ - list_t list; - list_item_t *li_new, *li_last = NULL; - int i, list_size = 8, rc = 0; - - splat_vprint(file, SPLAT_LIST_TEST4_NAME, "Creating list\n%s", ""); - list_create(&list, sizeof(list_item_t), offsetof(list_item_t, li_node)); - - /* Insert all items after the last item to form a queue */ - splat_vprint(file, SPLAT_LIST_TEST4_NAME, - "Adding %d items each after the last item\n", list_size); - for (i = 0; i < list_size; i++) { - li_new = kmem_alloc(sizeof(list_item_t), KM_SLEEP); - if (li_new == NULL) { - rc = -ENOMEM; - goto out; - } - - list_link_init(&li_new->li_node); - li_new->li_data = i; - list_insert_after(&list, li_last, li_new); - li_last = li_new; - } - - splat_vprint(file, SPLAT_LIST_TEST4_NAME, - "Validating %d item list is a queue\n", list_size); - rc = splat_list_validate(&list, list_size, LIST_ORDER_QUEUE, 1); - if (rc) - splat_vprint(file, SPLAT_LIST_TEST4_NAME, - "List validation failed, %d\n", rc); -out: - /* Remove all items */ - splat_vprint(file, SPLAT_LIST_TEST4_NAME, - "Removing %d items from list tail\n", list_size); - while ((li_new = list_remove_head(&list))) - kmem_free(li_new, sizeof(list_item_t)); - - splat_vprint(file, SPLAT_LIST_TEST4_NAME, "Destroying list\n%s", ""); - list_destroy(&list); - - return rc; -} - -static int -splat_list_test5(struct file *file, void *arg) -{ - list_t list; - list_item_t *li_new, *li_last = NULL; - int i, list_size = 8, rc = 0; - - splat_vprint(file, SPLAT_LIST_TEST5_NAME, "Creating list\n%s", ""); - list_create(&list, sizeof(list_item_t), offsetof(list_item_t, li_node)); - - /* Insert all items before the last item to form a stack */ - splat_vprint(file, SPLAT_LIST_TEST5_NAME, - "Adding %d items each before the last item\n", list_size); - for (i = 0; i < list_size; i++) { - li_new = kmem_alloc(sizeof(list_item_t), KM_SLEEP); - if (li_new == NULL) { - rc = -ENOMEM; - goto out; - } - - list_link_init(&li_new->li_node); - li_new->li_data = i; - list_insert_before(&list, li_last, li_new); - li_last = li_new; - } - - splat_vprint(file, SPLAT_LIST_TEST5_NAME, - "Validating %d item list is a queue\n", list_size); - rc = splat_list_validate(&list, list_size, LIST_ORDER_STACK, 1); - if (rc) - splat_vprint(file, SPLAT_LIST_TEST5_NAME, - "List validation failed, %d\n", rc); -out: - /* Remove all items */ - splat_vprint(file, SPLAT_LIST_TEST5_NAME, - "Removing %d items from list tail\n", list_size); - while ((li_new = list_remove_tail(&list))) - kmem_free(li_new, sizeof(list_item_t)); - - splat_vprint(file, SPLAT_LIST_TEST5_NAME, "Destroying list\n%s", ""); - list_destroy(&list); - - return rc; -} - -static int -splat_list_test6(struct file *file, void *arg) -{ - list_t list; - list_item_t *li, *li_prev; - int i, list_size = 8, rc = 0; - - splat_vprint(file, SPLAT_LIST_TEST6_NAME, "Creating list\n%s", ""); - list_create(&list, sizeof(list_item_t), offsetof(list_item_t, li_node)); - - /* Insert all items at the list tail to form a queue */ - splat_vprint(file, SPLAT_LIST_TEST6_NAME, - "Adding %d items to list tail\n", list_size); - for (i = 0; i < list_size; i++) { - li = kmem_alloc(sizeof(list_item_t), KM_SLEEP); - if (li == NULL) { - rc = -ENOMEM; - goto out; - } - - list_link_init(&li->li_node); - li->li_data = i; - list_insert_tail(&list, li); - } - - /* Remove all odd items from the queue */ - splat_vprint(file, SPLAT_LIST_TEST6_NAME, - "Removing %d odd items from the list\n", list_size >> 1); - for (li = list_head(&list); li != NULL; li = list_next(&list, li)) { - if (li->li_data % 2 == 1) { - li_prev = list_prev(&list, li); - list_remove(&list, li); - kmem_free(li, sizeof(list_item_t)); - li = li_prev; - } - } - - splat_vprint(file, SPLAT_LIST_TEST6_NAME, "Validating %d item " - "list is a queue of only even elements\n", list_size / 2); - rc = splat_list_validate(&list, list_size / 2, LIST_ORDER_QUEUE, 2); - if (rc) - splat_vprint(file, SPLAT_LIST_TEST6_NAME, - "List validation failed, %d\n", rc); -out: - /* Remove all items */ - splat_vprint(file, SPLAT_LIST_TEST6_NAME, - "Removing %d items from list tail\n", list_size / 2); - while ((li = list_remove_tail(&list))) - kmem_free(li, sizeof(list_item_t)); - - splat_vprint(file, SPLAT_LIST_TEST6_NAME, "Destroying list\n%s", ""); - list_destroy(&list); - - return rc; -} - -static int -splat_list_test7(struct file *file, void *arg) -{ - list_t list; - list_item_t *li; - int rc = 0; - - splat_vprint(file, SPLAT_LIST_TEST7_NAME, "Creating list\n%s", ""); - list_create(&list, sizeof(list_item_t), offsetof(list_item_t, li_node)); - - li = kmem_alloc(sizeof(list_item_t), KM_SLEEP); - if (li == NULL) { - rc = -ENOMEM; - goto out; - } - - /* Validate newly initialized node is inactive */ - splat_vprint(file, SPLAT_LIST_TEST7_NAME, "Init list node\n%s", ""); - list_link_init(&li->li_node); - if (list_link_active(&li->li_node)) { - splat_vprint(file, SPLAT_LIST_TEST7_NAME, "Newly initialized " - "list node should inactive %p/%p\n", - li->li_node.prev, li->li_node.next); - rc = -EINVAL; - goto out_li; - } - - /* Validate node is active when linked in to a list */ - splat_vprint(file, SPLAT_LIST_TEST7_NAME, "Insert list node\n%s", ""); - list_insert_head(&list, li); - if (!list_link_active(&li->li_node)) { - splat_vprint(file, SPLAT_LIST_TEST7_NAME, "List node " - "inserted in list should be active %p/%p\n", - li->li_node.prev, li->li_node.next); - rc = -EINVAL; - goto out; - } - - /* Validate node is inactive when removed from list */ - splat_vprint(file, SPLAT_LIST_TEST7_NAME, "Remove list node\n%s", ""); - list_remove(&list, li); - if (list_link_active(&li->li_node)) { - splat_vprint(file, SPLAT_LIST_TEST7_NAME, "List node " - "removed from list should be inactive %p/%p\n", - li->li_node.prev, li->li_node.next); - rc = -EINVAL; - } -out_li: - kmem_free(li, sizeof(list_item_t)); -out: - /* Remove all items */ - while ((li = list_remove_head(&list))) - kmem_free(li, sizeof(list_item_t)); - - splat_vprint(file, SPLAT_LIST_TEST7_NAME, "Destroying list\n%s", ""); - list_destroy(&list); - - return rc; -} - -splat_subsystem_t * -splat_list_init(void) -{ - splat_subsystem_t *sub; - - sub = kmalloc(sizeof(*sub), GFP_KERNEL); - if (sub == NULL) - return NULL; - - memset(sub, 0, sizeof(*sub)); - strncpy(sub->desc.name, SPLAT_LIST_NAME, SPLAT_NAME_SIZE); - strncpy(sub->desc.desc, SPLAT_LIST_DESC, SPLAT_DESC_SIZE); - INIT_LIST_HEAD(&sub->subsystem_list); - INIT_LIST_HEAD(&sub->test_list); - spin_lock_init(&sub->test_lock); - sub->desc.id = SPLAT_SUBSYSTEM_LIST; - - splat_test_init(sub, SPLAT_LIST_TEST1_NAME, SPLAT_LIST_TEST1_DESC, - SPLAT_LIST_TEST1_ID, splat_list_test1); - splat_test_init(sub, SPLAT_LIST_TEST2_NAME, SPLAT_LIST_TEST2_DESC, - SPLAT_LIST_TEST2_ID, splat_list_test2); - splat_test_init(sub, SPLAT_LIST_TEST3_NAME, SPLAT_LIST_TEST3_DESC, - SPLAT_LIST_TEST3_ID, splat_list_test3); - splat_test_init(sub, SPLAT_LIST_TEST4_NAME, SPLAT_LIST_TEST4_DESC, - SPLAT_LIST_TEST4_ID, splat_list_test4); - splat_test_init(sub, SPLAT_LIST_TEST5_NAME, SPLAT_LIST_TEST5_DESC, - SPLAT_LIST_TEST5_ID, splat_list_test5); - splat_test_init(sub, SPLAT_LIST_TEST6_NAME, SPLAT_LIST_TEST6_DESC, - SPLAT_LIST_TEST6_ID, splat_list_test6); - splat_test_init(sub, SPLAT_LIST_TEST7_NAME, SPLAT_LIST_TEST7_DESC, - SPLAT_LIST_TEST7_ID, splat_list_test7); - - return sub; -} - -void -splat_list_fini(splat_subsystem_t *sub) -{ - ASSERT(sub); - - splat_test_fini(sub, SPLAT_LIST_TEST7_ID); - splat_test_fini(sub, SPLAT_LIST_TEST6_ID); - splat_test_fini(sub, SPLAT_LIST_TEST5_ID); - splat_test_fini(sub, SPLAT_LIST_TEST4_ID); - splat_test_fini(sub, SPLAT_LIST_TEST3_ID); - splat_test_fini(sub, SPLAT_LIST_TEST2_ID); - splat_test_fini(sub, SPLAT_LIST_TEST1_ID); - - kfree(sub); -} - -int -splat_list_id(void) -{ - return SPLAT_SUBSYSTEM_LIST; -} diff --git a/module/splat/splat-mutex.c b/module/splat/splat-mutex.c deleted file mode 100644 index 202e6c0f6..000000000 --- a/module/splat/splat-mutex.c +++ /dev/null @@ -1,447 +0,0 @@ -/* - * 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). - * Written by Brian Behlendorf <[email protected]>. - * UCRL-CODE-235197 - * - * 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/>. - ***************************************************************************** - * Solaris Porting LAyer Tests (SPLAT) Mutex Tests. - */ - -#include <sys/mutex.h> -#include <sys/taskq.h> -#include <linux/delay.h> -#include <linux/mm_compat.h> -#include "splat-internal.h" - -#define SPLAT_MUTEX_NAME "mutex" -#define SPLAT_MUTEX_DESC "Kernel Mutex Tests" - -#define SPLAT_MUTEX_TEST1_ID 0x0401 -#define SPLAT_MUTEX_TEST1_NAME "tryenter" -#define SPLAT_MUTEX_TEST1_DESC "Validate mutex_tryenter() correctness" - -#define SPLAT_MUTEX_TEST2_ID 0x0402 -#define SPLAT_MUTEX_TEST2_NAME "race" -#define SPLAT_MUTEX_TEST2_DESC "Many threads entering/exiting the mutex" - -#define SPLAT_MUTEX_TEST3_ID 0x0403 -#define SPLAT_MUTEX_TEST3_NAME "owned" -#define SPLAT_MUTEX_TEST3_DESC "Validate mutex_owned() correctness" - -#define SPLAT_MUTEX_TEST4_ID 0x0404 -#define SPLAT_MUTEX_TEST4_NAME "owner" -#define SPLAT_MUTEX_TEST4_DESC "Validate mutex_owner() correctness" - -#define SPLAT_MUTEX_TEST_MAGIC 0x115599DDUL -#define SPLAT_MUTEX_TEST_NAME "mutex_test" -#define SPLAT_MUTEX_TEST_TASKQ "mutex_taskq" -#define SPLAT_MUTEX_TEST_COUNT 128 - -typedef struct mutex_priv { - unsigned long mp_magic; - struct file *mp_file; - kmutex_t mp_mtx; - int mp_rc; - int mp_rc2; -} mutex_priv_t; - -static void -splat_mutex_test1_func(void *arg) -{ - mutex_priv_t *mp = (mutex_priv_t *)arg; - ASSERT(mp->mp_magic == SPLAT_MUTEX_TEST_MAGIC); - - if (mutex_tryenter(&mp->mp_mtx)) { - mp->mp_rc = 0; - mutex_exit(&mp->mp_mtx); - } else { - mp->mp_rc = -EBUSY; - } -} - -static int -splat_mutex_test1(struct file *file, void *arg) -{ - mutex_priv_t *mp; - taskq_t *tq; - taskqid_t id; - int rc = 0; - - mp = (mutex_priv_t *)kmalloc(sizeof(*mp), GFP_KERNEL); - if (mp == NULL) - return -ENOMEM; - - tq = taskq_create(SPLAT_MUTEX_TEST_TASKQ, 1, defclsyspri, - 50, INT_MAX, TASKQ_PREPOPULATE); - if (tq == NULL) { - rc = -ENOMEM; - goto out2; - } - - mp->mp_magic = SPLAT_MUTEX_TEST_MAGIC; - mp->mp_file = file; - mutex_init(&mp->mp_mtx, SPLAT_MUTEX_TEST_NAME, MUTEX_DEFAULT, NULL); - mutex_enter(&mp->mp_mtx); - - /* - * Schedule a task function which will try and acquire the mutex via - * mutex_tryenter() while it's held. This should fail and the task - * function will indicate this status in the passed private data. - */ - mp->mp_rc = -EINVAL; - id = taskq_dispatch(tq, splat_mutex_test1_func, mp, TQ_SLEEP); - if (id == TASKQID_INVALID) { - mutex_exit(&mp->mp_mtx); - splat_vprint(file, SPLAT_MUTEX_TEST1_NAME, "%s", - "taskq_dispatch() failed\n"); - rc = -EINVAL; - goto out; - } - - taskq_wait_id(tq, id); - mutex_exit(&mp->mp_mtx); - - /* Task function successfully acquired mutex, very bad! */ - if (mp->mp_rc != -EBUSY) { - splat_vprint(file, SPLAT_MUTEX_TEST1_NAME, - "mutex_trylock() incorrectly succeeded when " - "the mutex was held, %d/%d\n", (int)id, mp->mp_rc); - rc = -EINVAL; - goto out; - } else { - splat_vprint(file, SPLAT_MUTEX_TEST1_NAME, "%s", - "mutex_trylock() correctly failed when " - "the mutex was held\n"); - } - - /* - * Schedule a task function which will try and acquire the mutex via - * mutex_tryenter() while it is not held. This should succeed and - * can be verified by checking the private data. - */ - mp->mp_rc = -EINVAL; - id = taskq_dispatch(tq, splat_mutex_test1_func, mp, TQ_SLEEP); - if (id == TASKQID_INVALID) { - splat_vprint(file, SPLAT_MUTEX_TEST1_NAME, "%s", - "taskq_dispatch() failed\n"); - rc = -EINVAL; - goto out; - } - - taskq_wait_id(tq, id); - - /* Task function failed to acquire mutex, very bad! */ - if (mp->mp_rc != 0) { - splat_vprint(file, SPLAT_MUTEX_TEST1_NAME, - "mutex_trylock() incorrectly failed when the mutex " - "was not held, %d/%d\n", (int)id, mp->mp_rc); - rc = -EINVAL; - } else { - splat_vprint(file, SPLAT_MUTEX_TEST1_NAME, "%s", - "mutex_trylock() correctly succeeded " - "when the mutex was not held\n"); - } -out: - taskq_destroy(tq); - mutex_destroy(&(mp->mp_mtx)); -out2: - kfree(mp); - return rc; -} - -static void -splat_mutex_test2_func(void *arg) -{ - mutex_priv_t *mp = (mutex_priv_t *)arg; - int rc; - ASSERT(mp->mp_magic == SPLAT_MUTEX_TEST_MAGIC); - - /* Read the value before sleeping and write it after we wake up to - * maximize the chance of a race if mutexs are not working properly */ - mutex_enter(&mp->mp_mtx); - rc = mp->mp_rc; - set_current_state(TASK_INTERRUPTIBLE); - schedule_timeout(HZ / 100); /* 1/100 of a second */ - VERIFY(mp->mp_rc == rc); - mp->mp_rc = rc + 1; - mutex_exit(&mp->mp_mtx); -} - -static int -splat_mutex_test2(struct file *file, void *arg) -{ - mutex_priv_t *mp; - taskq_t *tq; - taskqid_t id; - int i, rc = 0; - - mp = (mutex_priv_t *)kmalloc(sizeof(*mp), GFP_KERNEL); - if (mp == NULL) - return -ENOMEM; - - /* Create several threads allowing tasks to race with each other */ - tq = taskq_create(SPLAT_MUTEX_TEST_TASKQ, num_online_cpus(), - defclsyspri, 50, INT_MAX, TASKQ_PREPOPULATE); - if (tq == NULL) { - rc = -ENOMEM; - goto out; - } - - mp->mp_magic = SPLAT_MUTEX_TEST_MAGIC; - mp->mp_file = file; - mutex_init(&(mp->mp_mtx), SPLAT_MUTEX_TEST_NAME, MUTEX_DEFAULT, NULL); - mp->mp_rc = 0; - - /* - * Schedule N work items to the work queue each of which enters the - * mutex, sleeps briefly, then exits the mutex. On a multiprocessor - * box these work items will be handled by all available CPUs. The - * task function checks to ensure the tracked shared variable is - * always only incremented by one. Additionally, the mutex itself - * is instrumented such that if any two processors are in the - * critical region at the same time the system will panic. If the - * mutex is implemented right this will never happy, that's a pass. - */ - for (i = 0; i < SPLAT_MUTEX_TEST_COUNT; i++) { - id = taskq_dispatch(tq, splat_mutex_test2_func, mp, TQ_SLEEP); - if (id == TASKQID_INVALID) { - splat_vprint(file, SPLAT_MUTEX_TEST2_NAME, - "Failed to queue task %d\n", i); - rc = -EINVAL; - } - } - - taskq_wait(tq); - - if (mp->mp_rc == SPLAT_MUTEX_TEST_COUNT) { - splat_vprint(file, SPLAT_MUTEX_TEST2_NAME, "%d racing threads " - "correctly entered/exited the mutex %d times\n", - num_online_cpus(), mp->mp_rc); - } else { - splat_vprint(file, SPLAT_MUTEX_TEST2_NAME, "%d racing threads " - "only processed %d/%d mutex work items\n", - num_online_cpus(),mp->mp_rc,SPLAT_MUTEX_TEST_COUNT); - rc = -EINVAL; - } - - taskq_destroy(tq); - mutex_destroy(&(mp->mp_mtx)); -out: - kfree(mp); - return rc; -} - -static void -splat_mutex_owned(void *priv) -{ - mutex_priv_t *mp = (mutex_priv_t *)priv; - - ASSERT(mp->mp_magic == SPLAT_MUTEX_TEST_MAGIC); - mp->mp_rc = mutex_owned(&mp->mp_mtx); - mp->mp_rc2 = MUTEX_HELD(&mp->mp_mtx); -} - -static int -splat_mutex_test3(struct file *file, void *arg) -{ - mutex_priv_t mp; - taskq_t *tq; - taskqid_t id; - int rc = 0; - - mp.mp_magic = SPLAT_MUTEX_TEST_MAGIC; - 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, defclsyspri, - 50, INT_MAX, TASKQ_PREPOPULATE)) == NULL) { - splat_vprint(file, SPLAT_MUTEX_TEST3_NAME, "Taskq '%s' " - "create failed\n", SPLAT_MUTEX_TEST3_NAME); - return -EINVAL; - } - - mutex_enter(&mp.mp_mtx); - - /* Mutex should be owned by current */ - if (!mutex_owned(&mp.mp_mtx)) { - splat_vprint(file, SPLAT_MUTEX_TEST3_NAME, "Unowned mutex " - "should be owned by pid %d\n", current->pid); - rc = -EINVAL; - goto out_exit; - } - - id = taskq_dispatch(tq, splat_mutex_owned, &mp, TQ_SLEEP); - if (id == TASKQID_INVALID) { - splat_vprint(file, SPLAT_MUTEX_TEST3_NAME, "Failed to " - "dispatch function '%s' to taskq\n", - sym2str(splat_mutex_owned)); - rc = -EINVAL; - goto out_exit; - } - taskq_wait(tq); - - /* Mutex should not be owned which checked from a different thread */ - if (mp.mp_rc || mp.mp_rc2) { - splat_vprint(file, SPLAT_MUTEX_TEST3_NAME, "Mutex owned by " - "pid %d not by taskq\n", current->pid); - rc = -EINVAL; - goto out_exit; - } - - mutex_exit(&mp.mp_mtx); - - /* Mutex should not be owned by current */ - if (mutex_owned(&mp.mp_mtx)) { - splat_vprint(file, SPLAT_MUTEX_TEST3_NAME, "Mutex owned by " - "pid %d it should be unowned\b", current->pid); - rc = -EINVAL; - goto out; - } - - id = taskq_dispatch(tq, splat_mutex_owned, &mp, TQ_SLEEP); - if (id == TASKQID_INVALID) { - splat_vprint(file, SPLAT_MUTEX_TEST3_NAME, "Failed to " - "dispatch function '%s' to taskq\n", - sym2str(splat_mutex_owned)); - rc = -EINVAL; - goto out; - } - taskq_wait(tq); - - /* Mutex should be owned by no one */ - if (mp.mp_rc || mp.mp_rc2) { - splat_vprint(file, SPLAT_MUTEX_TEST3_NAME, "Mutex owned by " - "no one, %d/%d disagrees\n", mp.mp_rc, mp.mp_rc2); - rc = -EINVAL; - goto out; - } - - splat_vprint(file, SPLAT_MUTEX_TEST3_NAME, "%s", - "Correct mutex_owned() behavior\n"); - goto out; -out_exit: - mutex_exit(&mp.mp_mtx); -out: - mutex_destroy(&mp.mp_mtx); - taskq_destroy(tq); - - return rc; -} - -static int -splat_mutex_test4(struct file *file, void *arg) -{ - kmutex_t mtx; - kthread_t *owner; - int rc = 0; - - mutex_init(&mtx, SPLAT_MUTEX_TEST_NAME, MUTEX_DEFAULT, NULL); - - /* - * Verify mutex owner is cleared after being dropped. Depending - * on how you build your kernel this behavior changes, ensure the - * SPL mutex implementation is properly detecting this. - */ - mutex_enter(&mtx); - msleep(100); - mutex_exit(&mtx); - if (MUTEX_HELD(&mtx)) { - splat_vprint(file, SPLAT_MUTEX_TEST4_NAME, "Mutex should " - "not be held, bit is by %p\n", mutex_owner(&mtx)); - rc = -EINVAL; - goto out; - } - - mutex_enter(&mtx); - - /* Mutex should be owned by current */ - owner = mutex_owner(&mtx); - if (current != owner) { - splat_vprint(file, SPLAT_MUTEX_TEST4_NAME, "Mutex should " - "be owned by pid %d but is owned by pid %d\n", - current->pid, owner ? owner->pid : -1); - rc = -EINVAL; - goto out; - } - - mutex_exit(&mtx); - - /* Mutex should not be owned by any task */ - owner = mutex_owner(&mtx); - if (owner) { - splat_vprint(file, SPLAT_MUTEX_TEST4_NAME, "Mutex should not " - "be owned but is owned by pid %d\n", owner->pid); - rc = -EINVAL; - goto out; - } - - splat_vprint(file, SPLAT_MUTEX_TEST3_NAME, "%s", - "Correct mutex_owner() behavior\n"); -out: - mutex_destroy(&mtx); - - return rc; -} - -splat_subsystem_t * -splat_mutex_init(void) -{ - splat_subsystem_t *sub; - - sub = kmalloc(sizeof(*sub), GFP_KERNEL); - if (sub == NULL) - return NULL; - - memset(sub, 0, sizeof(*sub)); - strncpy(sub->desc.name, SPLAT_MUTEX_NAME, SPLAT_NAME_SIZE); - strncpy(sub->desc.desc, SPLAT_MUTEX_DESC, SPLAT_DESC_SIZE); - INIT_LIST_HEAD(&sub->subsystem_list); - INIT_LIST_HEAD(&sub->test_list); - spin_lock_init(&sub->test_lock); - sub->desc.id = SPLAT_SUBSYSTEM_MUTEX; - - splat_test_init(sub, SPLAT_MUTEX_TEST1_NAME, SPLAT_MUTEX_TEST1_DESC, - SPLAT_MUTEX_TEST1_ID, splat_mutex_test1); - splat_test_init(sub, SPLAT_MUTEX_TEST2_NAME, SPLAT_MUTEX_TEST2_DESC, - SPLAT_MUTEX_TEST2_ID, splat_mutex_test2); - splat_test_init(sub, SPLAT_MUTEX_TEST3_NAME, SPLAT_MUTEX_TEST3_DESC, - SPLAT_MUTEX_TEST3_ID, splat_mutex_test3); - splat_test_init(sub, SPLAT_MUTEX_TEST4_NAME, SPLAT_MUTEX_TEST4_DESC, - SPLAT_MUTEX_TEST4_ID, splat_mutex_test4); - - return sub; -} - -void -splat_mutex_fini(splat_subsystem_t *sub) -{ - ASSERT(sub); - splat_test_fini(sub, SPLAT_MUTEX_TEST4_ID); - splat_test_fini(sub, SPLAT_MUTEX_TEST3_ID); - splat_test_fini(sub, SPLAT_MUTEX_TEST2_ID); - splat_test_fini(sub, SPLAT_MUTEX_TEST1_ID); - - kfree(sub); -} - -int -splat_mutex_id(void) { - return SPLAT_SUBSYSTEM_MUTEX; -} diff --git a/module/splat/splat-random.c b/module/splat/splat-random.c deleted file mode 100644 index 2ddb823fc..000000000 --- a/module/splat/splat-random.c +++ /dev/null @@ -1,130 +0,0 @@ -/* - * 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). - * Written by Brian Behlendorf <[email protected]>. - * UCRL-CODE-235197 - * - * 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/>. - ***************************************************************************** - * Solaris Porting LAyer Tests (SPLAT) Random Number Generator Tests. - */ - -#include <sys/random.h> -#include <sys/kmem.h> -#include "splat-internal.h" - -#define SPLAT_KRNG_NAME "krng" -#define SPLAT_KRNG_DESC "Kernel Random Number Generator Tests" - -#define SPLAT_KRNG_TEST1_ID 0x0301 -#define SPLAT_KRNG_TEST1_NAME "freq" -#define SPLAT_KRNG_TEST1_DESC "Frequency Test" - -#define KRNG_NUM_BITS 1048576 -#define KRNG_NUM_BYTES (KRNG_NUM_BITS >> 3) -#define KRNG_NUM_BITS_DIV2 (KRNG_NUM_BITS >> 1) -#define KRNG_ERROR_RANGE 2097 - -/* Random Number Generator Tests - There can be meny more tests on quality of the - random number generator. For now we are only - testing the frequency of particular bits. - We could also test consecutive sequences, - randomness within a particular block, etc. - but is probably not necessary for our purposes */ - -static int -splat_krng_test1(struct file *file, void *arg) -{ - uint8_t *buf; - int i, j, diff, num = 0, rc = 0; - - buf = kmalloc(sizeof(*buf) * KRNG_NUM_BYTES, GFP_KERNEL); - if (buf == NULL) { - rc = -ENOMEM; - goto out; - } - - memset(buf, 0, sizeof(*buf) * KRNG_NUM_BYTES); - - /* Always succeeds */ - random_get_pseudo_bytes(buf, sizeof(uint8_t) * KRNG_NUM_BYTES); - - for (i = 0; i < KRNG_NUM_BYTES; i++) { - uint8_t tmp = buf[i]; - for (j = 0; j < 8; j++) { - uint8_t tmp2 = ((tmp >> j) & 0x01); - if (tmp2 == 1) { - num++; - } - } - } - - kfree(buf); - - diff = KRNG_NUM_BITS_DIV2 - num; - if (diff < 0) - diff *= -1; - - splat_print(file, "Test 1 Number of ones: %d\n", num); - splat_print(file, "Test 1 Difference from expected: %d Allowed: %d\n", - diff, KRNG_ERROR_RANGE); - - if (diff > KRNG_ERROR_RANGE) - rc = -ERANGE; -out: - return rc; -} - -splat_subsystem_t * -splat_krng_init(void) -{ - splat_subsystem_t *sub; - - sub = kmalloc(sizeof(*sub), GFP_KERNEL); - if (sub == NULL) - return NULL; - - memset(sub, 0, sizeof(*sub)); - strncpy(sub->desc.name, SPLAT_KRNG_NAME, SPLAT_NAME_SIZE); - strncpy(sub->desc.desc, SPLAT_KRNG_DESC, SPLAT_DESC_SIZE); - INIT_LIST_HEAD(&sub->subsystem_list); - INIT_LIST_HEAD(&sub->test_list); - spin_lock_init(&sub->test_lock); - sub->desc.id = SPLAT_SUBSYSTEM_KRNG; - - splat_test_init(sub, SPLAT_KRNG_TEST1_NAME, SPLAT_KRNG_TEST1_DESC, - SPLAT_KRNG_TEST1_ID, splat_krng_test1); - - return sub; -} - -void -splat_krng_fini(splat_subsystem_t *sub) -{ - ASSERT(sub); - - splat_test_fini(sub, SPLAT_KRNG_TEST1_ID); - - kfree(sub); -} - -int -splat_krng_id(void) { - return SPLAT_SUBSYSTEM_KRNG; -} diff --git a/module/splat/splat-rwlock.c b/module/splat/splat-rwlock.c deleted file mode 100644 index 562a5f047..000000000 --- a/module/splat/splat-rwlock.c +++ /dev/null @@ -1,747 +0,0 @@ -/* - * 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). - * Written by Brian Behlendorf <[email protected]>. - * UCRL-CODE-235197 - * - * 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/>. - ***************************************************************************** - * Solaris Porting LAyer Tests (SPLAT) Read/Writer Lock Tests. - */ - -#include <sys/random.h> -#include <sys/rwlock.h> -#include <sys/taskq.h> -#include <linux/delay.h> -#include <linux/mm_compat.h> -#include "splat-internal.h" - -#define SPLAT_RWLOCK_NAME "rwlock" -#define SPLAT_RWLOCK_DESC "Kernel RW Lock Tests" - -#define SPLAT_RWLOCK_TEST1_ID 0x0701 -#define SPLAT_RWLOCK_TEST1_NAME "N-rd/1-wr" -#define SPLAT_RWLOCK_TEST1_DESC "Multiple readers one writer" - -#define SPLAT_RWLOCK_TEST2_ID 0x0702 -#define SPLAT_RWLOCK_TEST2_NAME "0-rd/N-wr" -#define SPLAT_RWLOCK_TEST2_DESC "Multiple writers" - -#define SPLAT_RWLOCK_TEST3_ID 0x0703 -#define SPLAT_RWLOCK_TEST3_NAME "held" -#define SPLAT_RWLOCK_TEST3_DESC "RW_{LOCK|READ|WRITE}_HELD" - -#define SPLAT_RWLOCK_TEST4_ID 0x0704 -#define SPLAT_RWLOCK_TEST4_NAME "tryenter" -#define SPLAT_RWLOCK_TEST4_DESC "Tryenter" - -#define SPLAT_RWLOCK_TEST5_ID 0x0705 -#define SPLAT_RWLOCK_TEST5_NAME "rw_downgrade" -#define SPLAT_RWLOCK_TEST5_DESC "Write downgrade" - -#define SPLAT_RWLOCK_TEST6_ID 0x0706 -#define SPLAT_RWLOCK_TEST6_NAME "rw_tryupgrade-1" -#define SPLAT_RWLOCK_TEST6_DESC "rwsem->count value" - -#define SPLAT_RWLOCK_TEST7_ID 0x0707 -#define SPLAT_RWLOCK_TEST7_NAME "rw_tryupgrade-2" -#define SPLAT_RWLOCK_TEST7_DESC "Read upgrade" - -#define SPLAT_RWLOCK_TEST_MAGIC 0x115599DDUL -#define SPLAT_RWLOCK_TEST_NAME "rwlock_test" -#define SPLAT_RWLOCK_TEST_TASKQ "rwlock_taskq" -#define SPLAT_RWLOCK_TEST_COUNT 8 - -#define SPLAT_RWLOCK_RELEASE_INIT 0 -#define SPLAT_RWLOCK_RELEASE_WR 1 -#define SPLAT_RWLOCK_RELEASE_RD 2 - -typedef struct rw_priv { - unsigned long rw_magic; - struct file *rw_file; - krwlock_t rw_rwlock; - spinlock_t rw_lock; - spl_wait_queue_head_t rw_waitq; - int rw_completed; - int rw_holders; - int rw_waiters; - int rw_release; - int rw_rc; - krw_t rw_type; -} rw_priv_t; - -typedef struct rw_thr { - const char *rwt_name; - rw_priv_t *rwt_rwp; - struct task_struct *rwt_thread; -} rw_thr_t; - -void splat_init_rw_priv(rw_priv_t *rwp, struct file *file) -{ - rwp->rw_magic = SPLAT_RWLOCK_TEST_MAGIC; - rwp->rw_file = file; - rw_init(&rwp->rw_rwlock, SPLAT_RWLOCK_TEST_NAME, RW_DEFAULT, NULL); - spin_lock_init(&rwp->rw_lock); - init_waitqueue_head(&rwp->rw_waitq); - rwp->rw_completed = 0; - rwp->rw_holders = 0; - rwp->rw_waiters = 0; - rwp->rw_release = SPLAT_RWLOCK_RELEASE_INIT; - rwp->rw_rc = 0; - rwp->rw_type = 0; -} - -#if defined(CONFIG_PREEMPT_RT_FULL) -static int -splat_rwlock_test1(struct file *file, void *arg) -{ - /* - * This test will never succeed on PREEMPT_RT_FULL because these - * kernels only allow a single thread to hold the lock. - */ - return 0; -} -#else -static int -splat_rwlock_wr_thr(void *arg) -{ - rw_thr_t *rwt = (rw_thr_t *)arg; - rw_priv_t *rwp = rwt->rwt_rwp; - uint8_t rnd; - - ASSERT(rwp->rw_magic == SPLAT_RWLOCK_TEST_MAGIC); - - get_random_bytes((void *)&rnd, 1); - msleep((unsigned int)rnd); - - splat_vprint(rwp->rw_file, rwt->rwt_name, - "%s trying to acquire rwlock (%d holding/%d waiting)\n", - rwt->rwt_thread->comm, rwp->rw_holders, rwp->rw_waiters); - spin_lock(&rwp->rw_lock); - rwp->rw_waiters++; - spin_unlock(&rwp->rw_lock); - rw_enter(&rwp->rw_rwlock, RW_WRITER); - - spin_lock(&rwp->rw_lock); - rwp->rw_waiters--; - rwp->rw_holders++; - spin_unlock(&rwp->rw_lock); - splat_vprint(rwp->rw_file, rwt->rwt_name, - "%s acquired rwlock (%d holding/%d waiting)\n", - rwt->rwt_thread->comm, rwp->rw_holders, rwp->rw_waiters); - - /* Wait for control thread to signal we can release the write lock */ - wait_event_interruptible(rwp->rw_waitq, splat_locked_test(&rwp->rw_lock, - rwp->rw_release == SPLAT_RWLOCK_RELEASE_WR)); - - spin_lock(&rwp->rw_lock); - rwp->rw_completed++; - rwp->rw_holders--; - spin_unlock(&rwp->rw_lock); - splat_vprint(rwp->rw_file, rwt->rwt_name, - "%s dropped rwlock (%d holding/%d waiting)\n", - rwt->rwt_thread->comm, rwp->rw_holders, rwp->rw_waiters); - - rw_exit(&rwp->rw_rwlock); - - return 0; -} - -static int -splat_rwlock_rd_thr(void *arg) -{ - rw_thr_t *rwt = (rw_thr_t *)arg; - rw_priv_t *rwp = rwt->rwt_rwp; - uint8_t rnd; - - ASSERT(rwp->rw_magic == SPLAT_RWLOCK_TEST_MAGIC); - - get_random_bytes((void *)&rnd, 1); - msleep((unsigned int)rnd); - - /* Don't try and take the semaphore until after someone has it */ - wait_event_interruptible(rwp->rw_waitq, - splat_locked_test(&rwp->rw_lock, rwp->rw_holders > 0)); - - splat_vprint(rwp->rw_file, rwt->rwt_name, - "%s trying to acquire rwlock (%d holding/%d waiting)\n", - rwt->rwt_thread->comm, rwp->rw_holders, rwp->rw_waiters); - spin_lock(&rwp->rw_lock); - rwp->rw_waiters++; - spin_unlock(&rwp->rw_lock); - rw_enter(&rwp->rw_rwlock, RW_READER); - - spin_lock(&rwp->rw_lock); - rwp->rw_waiters--; - rwp->rw_holders++; - spin_unlock(&rwp->rw_lock); - splat_vprint(rwp->rw_file, rwt->rwt_name, - "%s acquired rwlock (%d holding/%d waiting)\n", - rwt->rwt_thread->comm, rwp->rw_holders, rwp->rw_waiters); - - /* Wait for control thread to signal we can release the read lock */ - wait_event_interruptible(rwp->rw_waitq, splat_locked_test(&rwp->rw_lock, - rwp->rw_release == SPLAT_RWLOCK_RELEASE_RD)); - - spin_lock(&rwp->rw_lock); - rwp->rw_completed++; - rwp->rw_holders--; - spin_unlock(&rwp->rw_lock); - splat_vprint(rwp->rw_file, rwt->rwt_name, - "%s dropped rwlock (%d holding/%d waiting)\n", - rwt->rwt_thread->comm, rwp->rw_holders, rwp->rw_waiters); - - rw_exit(&rwp->rw_rwlock); - - return 0; -} - -static int -splat_rwlock_test1(struct file *file, void *arg) -{ - int i, count = 0, rc = 0; - rw_thr_t rwt[SPLAT_RWLOCK_TEST_COUNT]; - rw_priv_t *rwp; - - rwp = (rw_priv_t *)kmalloc(sizeof(*rwp), GFP_KERNEL); - if (rwp == NULL) - return -ENOMEM; - - splat_init_rw_priv(rwp, file); - - /* Create some threads, the exact number isn't important just as - * long as we know how many we managed to create and should expect. */ - for (i = 0; i < SPLAT_RWLOCK_TEST_COUNT; i++) { - rwt[i].rwt_rwp = rwp; - rwt[i].rwt_name = SPLAT_RWLOCK_TEST1_NAME; - - /* The first thread will be the writer */ - if (i == 0) - rwt[i].rwt_thread = spl_kthread_create(splat_rwlock_wr_thr, - &rwt[i], "%s/%d", SPLAT_RWLOCK_TEST_NAME, i); - else - rwt[i].rwt_thread = spl_kthread_create(splat_rwlock_rd_thr, - &rwt[i], "%s/%d", SPLAT_RWLOCK_TEST_NAME, i); - - if (!IS_ERR(rwt[i].rwt_thread)) { - wake_up_process(rwt[i].rwt_thread); - count++; - } - } - - /* Wait for the writer */ - while (splat_locked_test(&rwp->rw_lock, rwp->rw_holders == 0)) { - wake_up_interruptible(&rwp->rw_waitq); - msleep(100); - } - - /* Wait for 'count-1' readers */ - while (splat_locked_test(&rwp->rw_lock, rwp->rw_waiters < count - 1)) { - wake_up_interruptible(&rwp->rw_waitq); - msleep(100); - } - - /* Verify there is only one lock holder */ - if (splat_locked_test(&rwp->rw_lock, rwp->rw_holders) != 1) { - splat_vprint(file, SPLAT_RWLOCK_TEST1_NAME, "Only 1 holder " - "expected for rwlock (%d holding/%d waiting)\n", - rwp->rw_holders, rwp->rw_waiters); - rc = -EINVAL; - } - - /* Verify 'count-1' readers */ - if (splat_locked_test(&rwp->rw_lock, rwp->rw_waiters != count - 1)) { - splat_vprint(file, SPLAT_RWLOCK_TEST1_NAME, "Only %d waiters " - "expected for rwlock (%d holding/%d waiting)\n", - count - 1, rwp->rw_holders, rwp->rw_waiters); - rc = -EINVAL; - } - - /* Signal the writer to release, allows readers to acquire */ - spin_lock(&rwp->rw_lock); - rwp->rw_release = SPLAT_RWLOCK_RELEASE_WR; - wake_up_interruptible(&rwp->rw_waitq); - spin_unlock(&rwp->rw_lock); - - /* Wait for 'count-1' readers to hold the lock */ - while (splat_locked_test(&rwp->rw_lock, rwp->rw_holders < count - 1)) { - wake_up_interruptible(&rwp->rw_waitq); - msleep(100); - } - - /* Verify there are 'count-1' readers */ - if (splat_locked_test(&rwp->rw_lock, rwp->rw_holders != count - 1)) { - splat_vprint(file, SPLAT_RWLOCK_TEST1_NAME, "Only %d holders " - "expected for rwlock (%d holding/%d waiting)\n", - count - 1, rwp->rw_holders, rwp->rw_waiters); - rc = -EINVAL; - } - - /* Release 'count-1' readers */ - spin_lock(&rwp->rw_lock); - rwp->rw_release = SPLAT_RWLOCK_RELEASE_RD; - wake_up_interruptible(&rwp->rw_waitq); - spin_unlock(&rwp->rw_lock); - - /* Wait for the test to complete */ - while (splat_locked_test(&rwp->rw_lock, - rwp->rw_holders>0 || rwp->rw_waiters>0)) - msleep(100); - - rw_destroy(&(rwp->rw_rwlock)); - kfree(rwp); - - return rc; -} -#endif - -static void -splat_rwlock_test2_func(void *arg) -{ - rw_priv_t *rwp = (rw_priv_t *)arg; - int rc; - ASSERT(rwp->rw_magic == SPLAT_RWLOCK_TEST_MAGIC); - - /* Read the value before sleeping and write it after we wake up to - * maximize the chance of a race if rwlocks are not working properly */ - rw_enter(&rwp->rw_rwlock, RW_WRITER); - rc = rwp->rw_rc; - set_current_state(TASK_INTERRUPTIBLE); - schedule_timeout(HZ / 100); /* 1/100 of a second */ - VERIFY(rwp->rw_rc == rc); - rwp->rw_rc = rc + 1; - rw_exit(&rwp->rw_rwlock); -} - -static int -splat_rwlock_test2(struct file *file, void *arg) -{ - rw_priv_t *rwp; - taskq_t *tq; - int i, rc = 0, tq_count = 256; - - rwp = (rw_priv_t *)kmalloc(sizeof(*rwp), GFP_KERNEL); - if (rwp == NULL) - return -ENOMEM; - - splat_init_rw_priv(rwp, file); - - /* Create several threads allowing tasks to race with each other */ - tq = taskq_create(SPLAT_RWLOCK_TEST_TASKQ, num_online_cpus(), - defclsyspri, 50, INT_MAX, TASKQ_PREPOPULATE); - if (tq == NULL) { - rc = -ENOMEM; - goto out; - } - - /* - * Schedule N work items to the work queue each of which enters the - * writer rwlock, sleeps briefly, then exits the writer rwlock. On a - * multiprocessor box these work items will be handled by all available - * CPUs. The task function checks to ensure the tracked shared variable - * is always only incremented by one. Additionally, the rwlock itself - * is instrumented such that if any two processors are in the - * critical region at the same time the system will panic. If the - * rwlock is implemented right this will never happy, that's a pass. - */ - for (i = 0; i < tq_count; i++) { - if (taskq_dispatch(tq, splat_rwlock_test2_func, rwp, - TQ_SLEEP) == TASKQID_INVALID) { - splat_vprint(file, SPLAT_RWLOCK_TEST2_NAME, - "Failed to queue task %d\n", i); - rc = -EINVAL; - } - } - - taskq_wait(tq); - - if (rwp->rw_rc == tq_count) { - splat_vprint(file, SPLAT_RWLOCK_TEST2_NAME, "%d racing threads " - "correctly entered/exited the rwlock %d times\n", - num_online_cpus(), rwp->rw_rc); - } else { - splat_vprint(file, SPLAT_RWLOCK_TEST2_NAME, "%d racing threads " - "only processed %d/%d w rwlock work items\n", - num_online_cpus(), rwp->rw_rc, tq_count); - rc = -EINVAL; - } - - taskq_destroy(tq); - rw_destroy(&(rwp->rw_rwlock)); -out: - kfree(rwp); - return rc; -} - -#define splat_rwlock_test3_helper(rwp,rex1,rex2,wex1,wex2,held_func,rc) \ -do { \ - int result, _rc1_, _rc2_, _rc3_, _rc4_; \ - \ - rc = 0; \ - rw_enter(&(rwp)->rw_rwlock, RW_READER); \ - _rc1_ = ((result = held_func(&(rwp)->rw_rwlock)) != rex1); \ - splat_vprint(file, SPLAT_RWLOCK_TEST3_NAME, "%s" #held_func \ - " returned %d (expected %d) when RW_READER\n", \ - _rc1_ ? "Fail " : "", result, rex1); \ - rw_exit(&(rwp)->rw_rwlock); \ - _rc2_ = ((result = held_func(&(rwp)->rw_rwlock)) != rex2); \ - splat_vprint(file, SPLAT_RWLOCK_TEST3_NAME, "%s" #held_func \ - " returned %d (expected %d) when !RW_READER\n", \ - _rc2_ ? "Fail " : "", result, rex2); \ - \ - rw_enter(&(rwp)->rw_rwlock, RW_WRITER); \ - _rc3_ = ((result = held_func(&(rwp)->rw_rwlock)) != wex1); \ - splat_vprint(file, SPLAT_RWLOCK_TEST3_NAME, "%s" #held_func \ - " returned %d (expected %d) when RW_WRITER\n", \ - _rc3_ ? "Fail " : "", result, wex1); \ - rw_exit(&(rwp)->rw_rwlock); \ - _rc4_ = ((result = held_func(&(rwp)->rw_rwlock)) != wex2); \ - splat_vprint(file, SPLAT_RWLOCK_TEST3_NAME, "%s" #held_func \ - " returned %d (expected %d) when !RW_WRITER\n", \ - _rc4_ ? "Fail " : "", result, wex2); \ - \ - rc = ((_rc1_ || _rc2_ || _rc3_ || _rc4_) ? -EINVAL : 0); \ -} while(0); - -static int -splat_rwlock_test3(struct file *file, void *arg) -{ - rw_priv_t *rwp; - int rc1, rc2, rc3; - - rwp = (rw_priv_t *)kmalloc(sizeof(*rwp), GFP_KERNEL); - if (rwp == NULL) - return -ENOMEM; - - splat_init_rw_priv(rwp, file); - - splat_rwlock_test3_helper(rwp, 1, 0, 1, 0, RW_LOCK_HELD, rc1); - splat_rwlock_test3_helper(rwp, 1, 0, 0, 0, RW_READ_HELD, rc2); - splat_rwlock_test3_helper(rwp, 0, 0, 1, 0, RW_WRITE_HELD, rc3); - - rw_destroy(&rwp->rw_rwlock); - kfree(rwp); - - return ((rc1 || rc2 || rc3) ? -EINVAL : 0); -} - -static void -splat_rwlock_test4_func(void *arg) -{ - rw_priv_t *rwp = (rw_priv_t *)arg; - ASSERT(rwp->rw_magic == SPLAT_RWLOCK_TEST_MAGIC); - - if (rw_tryenter(&rwp->rw_rwlock, rwp->rw_type)) { - rwp->rw_rc = 0; - rw_exit(&rwp->rw_rwlock); - } else { - rwp->rw_rc = -EBUSY; - } -} - -static char * -splat_rwlock_test4_name(krw_t type) -{ - switch (type) { - case RW_NONE: return "RW_NONE"; - case RW_WRITER: return "RW_WRITER"; - case RW_READER: return "RW_READER"; - } - - return NULL; -} - -static int -splat_rwlock_test4_type(taskq_t *tq, rw_priv_t *rwp, int expected_rc, - krw_t holder_type, krw_t try_type) -{ - int id, rc = 0; - - /* Schedule a task function which will try and acquire the rwlock - * using type try_type while the rwlock is being held as holder_type. - * The result must match expected_rc for the test to pass */ - rwp->rw_rc = -EINVAL; - rwp->rw_type = try_type; - - if (holder_type == RW_WRITER || holder_type == RW_READER) - rw_enter(&rwp->rw_rwlock, holder_type); - - id = taskq_dispatch(tq, splat_rwlock_test4_func, rwp, TQ_SLEEP); - if (id == TASKQID_INVALID) { - splat_vprint(rwp->rw_file, SPLAT_RWLOCK_TEST4_NAME, "%s", - "taskq_dispatch() failed\n"); - rc = -EINVAL; - goto out; - } - - taskq_wait_id(tq, id); - - if (rwp->rw_rc != expected_rc) - rc = -EINVAL; - - splat_vprint(rwp->rw_file, SPLAT_RWLOCK_TEST4_NAME, - "%srw_tryenter(%s) returned %d (expected %d) when %s\n", - rc ? "Fail " : "", splat_rwlock_test4_name(try_type), - rwp->rw_rc, expected_rc, - splat_rwlock_test4_name(holder_type)); -out: - if (holder_type == RW_WRITER || holder_type == RW_READER) - rw_exit(&rwp->rw_rwlock); - - return rc; -} - -static int -splat_rwlock_test4(struct file *file, void *arg) -{ - rw_priv_t *rwp; - taskq_t *tq; - int rc = 0, rc1, rc2, rc3, rc4, rc5, rc6; - - rwp = (rw_priv_t *)kmalloc(sizeof(*rwp), GFP_KERNEL); - if (rwp == NULL) - return -ENOMEM; - - tq = taskq_create(SPLAT_RWLOCK_TEST_TASKQ, 1, defclsyspri, - 50, INT_MAX, TASKQ_PREPOPULATE); - if (tq == NULL) { - rc = -ENOMEM; - goto out; - } - - splat_init_rw_priv(rwp, file); - - /* - * Validate all combinations of rw_tryenter() contention. - * - * The concurrent reader test is modified for PREEMPT_RT_FULL - * kernels which do not permit concurrent read locks to be taken - * from different threads. The same thread is allowed to take - * the read lock multiple times. - */ - rc1 = splat_rwlock_test4_type(tq, rwp, -EBUSY, RW_WRITER, RW_WRITER); - rc2 = splat_rwlock_test4_type(tq, rwp, -EBUSY, RW_WRITER, RW_READER); - rc3 = splat_rwlock_test4_type(tq, rwp, -EBUSY, RW_READER, RW_WRITER); -#if defined(CONFIG_PREEMPT_RT_FULL) - rc4 = splat_rwlock_test4_type(tq, rwp, -EBUSY, RW_READER, RW_READER); -#else - rc4 = splat_rwlock_test4_type(tq, rwp, 0, RW_READER, RW_READER); -#endif - rc5 = splat_rwlock_test4_type(tq, rwp, 0, RW_NONE, RW_WRITER); - rc6 = splat_rwlock_test4_type(tq, rwp, 0, RW_NONE, RW_READER); - - if (rc1 || rc2 || rc3 || rc4 || rc5 || rc6) - rc = -EINVAL; - - taskq_destroy(tq); -out: - rw_destroy(&(rwp->rw_rwlock)); - kfree(rwp); - - return rc; -} - -static int -splat_rwlock_test5(struct file *file, void *arg) -{ - rw_priv_t *rwp; - int rc = -EINVAL; - - rwp = (rw_priv_t *)kmalloc(sizeof(*rwp), GFP_KERNEL); - if (rwp == NULL) - return -ENOMEM; - - splat_init_rw_priv(rwp, file); - - rw_enter(&rwp->rw_rwlock, RW_WRITER); - if (!RW_WRITE_HELD(&rwp->rw_rwlock)) { - splat_vprint(file, SPLAT_RWLOCK_TEST5_NAME, - "rwlock should be write lock: %d\n", - RW_WRITE_HELD(&rwp->rw_rwlock)); - goto out; - } - - rw_downgrade(&rwp->rw_rwlock); - if (!RW_READ_HELD(&rwp->rw_rwlock)) { - splat_vprint(file, SPLAT_RWLOCK_TEST5_NAME, - "rwlock should be read lock: %d\n", - RW_READ_HELD(&rwp->rw_rwlock)); - goto out; - } - - rc = 0; - splat_vprint(file, SPLAT_RWLOCK_TEST5_NAME, "%s", - "rwlock properly downgraded\n"); -out: - rw_exit(&rwp->rw_rwlock); - rw_destroy(&rwp->rw_rwlock); - kfree(rwp); - - return rc; -} - -static int -splat_rwlock_test6(struct file *file, void *arg) -{ - rw_priv_t *rwp; - int rc; - - rwp = (rw_priv_t *)kmalloc(sizeof(*rwp), GFP_KERNEL); - if (rwp == NULL) - return -ENOMEM; - - splat_init_rw_priv(rwp, file); - - rw_enter(&rwp->rw_rwlock, RW_READER); - if (RWSEM_COUNT(SEM(&rwp->rw_rwlock)) != - SPL_RWSEM_SINGLE_READER_VALUE) { - splat_vprint(file, SPLAT_RWLOCK_TEST6_NAME, - "We assumed single reader rwsem->count " - "should be %ld, but is %ld\n", - (long int)SPL_RWSEM_SINGLE_READER_VALUE, - (long int)RWSEM_COUNT(SEM(&rwp->rw_rwlock))); - rc = -ENOLCK; - goto out; - } - rw_exit(&rwp->rw_rwlock); - - rw_enter(&rwp->rw_rwlock, RW_WRITER); - if (RWSEM_COUNT(SEM(&rwp->rw_rwlock)) != - SPL_RWSEM_SINGLE_WRITER_VALUE) { - splat_vprint(file, SPLAT_RWLOCK_TEST6_NAME, - "We assumed single writer rwsem->count " - "should be %ld, but is %ld\n", - (long int)SPL_RWSEM_SINGLE_WRITER_VALUE, - (long int)RWSEM_COUNT(SEM(&rwp->rw_rwlock))); - rc = -ENOLCK; - goto out; - } - rc = 0; - splat_vprint(file, SPLAT_RWLOCK_TEST6_NAME, "%s", - "rwsem->count same as we assumed\n"); -out: - rw_exit(&rwp->rw_rwlock); - rw_destroy(&rwp->rw_rwlock); - kfree(rwp); - - return rc; -} - -static int -splat_rwlock_test7(struct file *file, void *arg) -{ - rw_priv_t *rwp; - int rc; - - rwp = (rw_priv_t *)kmalloc(sizeof(*rwp), GFP_KERNEL); - if (rwp == NULL) - return -ENOMEM; - - splat_init_rw_priv(rwp, file); - - rw_enter(&rwp->rw_rwlock, RW_READER); - if (!RW_READ_HELD(&rwp->rw_rwlock)) { - splat_vprint(file, SPLAT_RWLOCK_TEST7_NAME, - "rwlock should be read lock: %d\n", - RW_READ_HELD(&rwp->rw_rwlock)); - rc = -ENOLCK; - goto out; - } - - /* With one reader upgrade should never fail. */ - rc = rw_tryupgrade(&rwp->rw_rwlock); - if (!rc) { - splat_vprint(file, SPLAT_RWLOCK_TEST7_NAME, - "rwlock failed upgrade from reader: %d\n", - RW_READ_HELD(&rwp->rw_rwlock)); - rc = -ENOLCK; - goto out; - } - - if (RW_READ_HELD(&rwp->rw_rwlock) || !RW_WRITE_HELD(&rwp->rw_rwlock)) { - splat_vprint(file, SPLAT_RWLOCK_TEST7_NAME, "rwlock should " - "have 0 (not %d) reader and 1 (not %d) writer\n", - RW_READ_HELD(&rwp->rw_rwlock), - RW_WRITE_HELD(&rwp->rw_rwlock)); - goto out; - } - - rc = 0; - splat_vprint(file, SPLAT_RWLOCK_TEST7_NAME, "%s", - "rwlock properly upgraded\n"); -out: - rw_exit(&rwp->rw_rwlock); - rw_destroy(&rwp->rw_rwlock); - kfree(rwp); - - return rc; -} - -splat_subsystem_t * -splat_rwlock_init(void) -{ - splat_subsystem_t *sub; - - sub = kmalloc(sizeof(*sub), GFP_KERNEL); - if (sub == NULL) - return NULL; - - memset(sub, 0, sizeof(*sub)); - strncpy(sub->desc.name, SPLAT_RWLOCK_NAME, SPLAT_NAME_SIZE); - strncpy(sub->desc.desc, SPLAT_RWLOCK_DESC, SPLAT_DESC_SIZE); - INIT_LIST_HEAD(&sub->subsystem_list); - INIT_LIST_HEAD(&sub->test_list); - spin_lock_init(&sub->test_lock); - sub->desc.id = SPLAT_SUBSYSTEM_RWLOCK; - - splat_test_init(sub, SPLAT_RWLOCK_TEST1_NAME, SPLAT_RWLOCK_TEST1_DESC, - SPLAT_RWLOCK_TEST1_ID, splat_rwlock_test1); - splat_test_init(sub, SPLAT_RWLOCK_TEST2_NAME, SPLAT_RWLOCK_TEST2_DESC, - SPLAT_RWLOCK_TEST2_ID, splat_rwlock_test2); - splat_test_init(sub, SPLAT_RWLOCK_TEST3_NAME, SPLAT_RWLOCK_TEST3_DESC, - SPLAT_RWLOCK_TEST3_ID, splat_rwlock_test3); - splat_test_init(sub, SPLAT_RWLOCK_TEST4_NAME, SPLAT_RWLOCK_TEST4_DESC, - SPLAT_RWLOCK_TEST4_ID, splat_rwlock_test4); - splat_test_init(sub, SPLAT_RWLOCK_TEST5_NAME, SPLAT_RWLOCK_TEST5_DESC, - SPLAT_RWLOCK_TEST5_ID, splat_rwlock_test5); - splat_test_init(sub, SPLAT_RWLOCK_TEST6_NAME, SPLAT_RWLOCK_TEST6_DESC, - SPLAT_RWLOCK_TEST6_ID, splat_rwlock_test6); - splat_test_init(sub, SPLAT_RWLOCK_TEST7_NAME, SPLAT_RWLOCK_TEST7_DESC, - SPLAT_RWLOCK_TEST7_ID, splat_rwlock_test7); - - return sub; -} - -void -splat_rwlock_fini(splat_subsystem_t *sub) -{ - ASSERT(sub); - splat_test_fini(sub, SPLAT_RWLOCK_TEST7_ID); - splat_test_fini(sub, SPLAT_RWLOCK_TEST6_ID); - splat_test_fini(sub, SPLAT_RWLOCK_TEST5_ID); - splat_test_fini(sub, SPLAT_RWLOCK_TEST4_ID); - splat_test_fini(sub, SPLAT_RWLOCK_TEST3_ID); - splat_test_fini(sub, SPLAT_RWLOCK_TEST2_ID); - splat_test_fini(sub, SPLAT_RWLOCK_TEST1_ID); - kfree(sub); -} - -int -splat_rwlock_id(void) { - return SPLAT_SUBSYSTEM_RWLOCK; -} diff --git a/module/splat/splat-taskq.c b/module/splat/splat-taskq.c deleted file mode 100644 index ff73e103a..000000000 --- a/module/splat/splat-taskq.c +++ /dev/null @@ -1,1548 +0,0 @@ -/* - * 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). - * Written by Brian Behlendorf <[email protected]>. - * UCRL-CODE-235197 - * - * 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/>. - ***************************************************************************** - * Solaris Porting LAyer Tests (SPLAT) Task Queue Tests. - */ - -#include <sys/kmem.h> -#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_NAME "taskq" -#define SPLAT_TASKQ_DESC "Kernel Task Queue Tests" - -#define SPLAT_TASKQ_TEST1_ID 0x0201 -#define SPLAT_TASKQ_TEST1_NAME "single" -#define SPLAT_TASKQ_TEST1_DESC "Single task queue, single task" - -#define SPLAT_TASKQ_TEST2_ID 0x0202 -#define SPLAT_TASKQ_TEST2_NAME "multiple" -#define SPLAT_TASKQ_TEST2_DESC "Multiple task queues, multiple tasks" - -#define SPLAT_TASKQ_TEST3_ID 0x0203 -#define SPLAT_TASKQ_TEST3_NAME "system" -#define SPLAT_TASKQ_TEST3_DESC "System task queue, multiple tasks" - -#define SPLAT_TASKQ_TEST4_ID 0x0204 -#define SPLAT_TASKQ_TEST4_NAME "wait" -#define SPLAT_TASKQ_TEST4_DESC "Multiple task waiting" - -#define SPLAT_TASKQ_TEST5_ID 0x0205 -#define SPLAT_TASKQ_TEST5_NAME "order" -#define SPLAT_TASKQ_TEST5_DESC "Correct task ordering" - -#define SPLAT_TASKQ_TEST6_ID 0x0206 -#define SPLAT_TASKQ_TEST6_NAME "front" -#define SPLAT_TASKQ_TEST6_DESC "Correct ordering with TQ_FRONT flag" - -#define SPLAT_TASKQ_TEST7_ID 0x0207 -#define SPLAT_TASKQ_TEST7_NAME "recurse" -#define SPLAT_TASKQ_TEST7_DESC "Single task queue, recursive dispatch" - -#define SPLAT_TASKQ_TEST8_ID 0x0208 -#define SPLAT_TASKQ_TEST8_NAME "contention" -#define SPLAT_TASKQ_TEST8_DESC "1 queue, 100 threads, 131072 tasks" - -#define SPLAT_TASKQ_TEST9_ID 0x0209 -#define SPLAT_TASKQ_TEST9_NAME "delay" -#define SPLAT_TASKQ_TEST9_DESC "Delayed task execution" - -#define SPLAT_TASKQ_TEST10_ID 0x020a -#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 - - -typedef struct splat_taskq_arg { - int flag; - int id; - atomic_t *count; - int order[SPLAT_TASKQ_ORDER_MAX]; - unsigned int depth; - clock_t expire; - taskq_t *tq; - taskq_ent_t *tqe; - spinlock_t lock; - struct file *file; - const char *name; -} splat_taskq_arg_t; - -typedef struct splat_taskq_id { - int id; - splat_taskq_arg_t *arg; -} splat_taskq_id_t; - -/* - * Create a taskq, queue a task, wait until task completes, ensure - * task ran properly, cleanup taskq. - */ -static void -splat_taskq_test13_func(void *arg) -{ - splat_taskq_arg_t *tq_arg = (splat_taskq_arg_t *)arg; - - ASSERT(tq_arg); - splat_vprint(tq_arg->file, SPLAT_TASKQ_TEST1_NAME, - "Taskq '%s' function '%s' setting flag\n", - tq_arg->name, sym2str(splat_taskq_test13_func)); - tq_arg->flag = 1; -} - -static int -splat_taskq_test1_impl(struct file *file, void *arg, boolean_t prealloc) -{ - taskq_t *tq; - taskqid_t id; - splat_taskq_arg_t tq_arg; - taskq_ent_t *tqe; - - tqe = kmem_alloc(sizeof (taskq_ent_t), KM_SLEEP); - taskq_init_ent(tqe); - - splat_vprint(file, SPLAT_TASKQ_TEST1_NAME, - "Taskq '%s' creating (%s dispatch)\n", - SPLAT_TASKQ_TEST1_NAME, - prealloc ? "prealloc" : "dynamic"); - 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", - SPLAT_TASKQ_TEST1_NAME); - kmem_free(tqe, sizeof (taskq_ent_t)); - return -EINVAL; - } - - tq_arg.flag = 0; - tq_arg.id = 0; - tq_arg.file = file; - tq_arg.name = SPLAT_TASKQ_TEST1_NAME; - - splat_vprint(file, SPLAT_TASKQ_TEST1_NAME, - "Taskq '%s' function '%s' dispatching\n", - tq_arg.name, sym2str(splat_taskq_test13_func)); - if (prealloc) { - taskq_dispatch_ent(tq, splat_taskq_test13_func, - &tq_arg, TQ_SLEEP, tqe); - id = tqe->tqent_id; - } else { - id = taskq_dispatch(tq, splat_taskq_test13_func, - &tq_arg, TQ_SLEEP); - } - - if (id == TASKQID_INVALID) { - splat_vprint(file, SPLAT_TASKQ_TEST1_NAME, - "Taskq '%s' function '%s' dispatch failed\n", - tq_arg.name, sym2str(splat_taskq_test13_func)); - kmem_free(tqe, sizeof (taskq_ent_t)); - taskq_destroy(tq); - return -EINVAL; - } - - splat_vprint(file, SPLAT_TASKQ_TEST1_NAME, "Taskq '%s' waiting\n", - tq_arg.name); - taskq_wait(tq); - splat_vprint(file, SPLAT_TASKQ_TEST1_NAME, "Taskq '%s' destroying\n", - tq_arg.name); - - kmem_free(tqe, sizeof (taskq_ent_t)); - taskq_destroy(tq); - - return (tq_arg.flag) ? 0 : -EINVAL; -} - -static int -splat_taskq_test1(struct file *file, void *arg) -{ - int rc; - - rc = splat_taskq_test1_impl(file, arg, B_FALSE); - if (rc) - return rc; - - rc = splat_taskq_test1_impl(file, arg, B_TRUE); - - return rc; -} - -/* - * Create multiple taskq's, each with multiple tasks, wait until - * all tasks complete, ensure all tasks ran properly and in the - * correct order. Run order must be the same as the order submitted - * because we only have 1 thread per taskq. Finally cleanup the taskq. - */ -static void -splat_taskq_test2_func1(void *arg) -{ - splat_taskq_arg_t *tq_arg = (splat_taskq_arg_t *)arg; - - ASSERT(tq_arg); - splat_vprint(tq_arg->file, SPLAT_TASKQ_TEST2_NAME, - "Taskq '%s/%d' function '%s' flag = %d = %d * 2\n", - tq_arg->name, tq_arg->id, - sym2str(splat_taskq_test2_func1), - tq_arg->flag * 2, tq_arg->flag); - tq_arg->flag *= 2; -} - -static void -splat_taskq_test2_func2(void *arg) -{ - splat_taskq_arg_t *tq_arg = (splat_taskq_arg_t *)arg; - - ASSERT(tq_arg); - splat_vprint(tq_arg->file, SPLAT_TASKQ_TEST2_NAME, - "Taskq '%s/%d' function '%s' flag = %d = %d + 1\n", - tq_arg->name, tq_arg->id, - sym2str(splat_taskq_test2_func2), - tq_arg->flag + 1, tq_arg->flag); - tq_arg->flag += 1; -} - -#define TEST2_TASKQS 8 -#define TEST2_THREADS_PER_TASKQ 1 - -static int -splat_taskq_test2_impl(struct file *file, void *arg, boolean_t prealloc) { - taskq_t *tq[TEST2_TASKQS] = { NULL }; - taskqid_t id; - splat_taskq_arg_t *tq_args[TEST2_TASKQS] = { NULL }; - taskq_ent_t *func1_tqes = NULL; - taskq_ent_t *func2_tqes = NULL; - int i, rc = 0; - - func1_tqes = kmalloc(sizeof(*func1_tqes) * TEST2_TASKQS, GFP_KERNEL); - if (func1_tqes == NULL) { - rc = -ENOMEM; - goto out; - } - - func2_tqes = kmalloc(sizeof(*func2_tqes) * TEST2_TASKQS, GFP_KERNEL); - if (func2_tqes == NULL) { - rc = -ENOMEM; - goto out; - } - - for (i = 0; i < TEST2_TASKQS; i++) { - taskq_init_ent(&func1_tqes[i]); - taskq_init_ent(&func2_tqes[i]); - - tq_args[i] = kmalloc(sizeof (splat_taskq_arg_t), GFP_KERNEL); - if (tq_args[i] == NULL) { - rc = -ENOMEM; - break; - } - - splat_vprint(file, SPLAT_TASKQ_TEST2_NAME, - "Taskq '%s/%d' creating (%s dispatch)\n", - SPLAT_TASKQ_TEST2_NAME, i, - prealloc ? "prealloc" : "dynamic"); - if ((tq[i] = taskq_create(SPLAT_TASKQ_TEST2_NAME, - TEST2_THREADS_PER_TASKQ, - defclsyspri, 50, INT_MAX, - TASKQ_PREPOPULATE)) == NULL) { - splat_vprint(file, SPLAT_TASKQ_TEST2_NAME, - "Taskq '%s/%d' create failed\n", - SPLAT_TASKQ_TEST2_NAME, i); - rc = -EINVAL; - break; - } - - tq_args[i]->flag = i; - tq_args[i]->id = i; - tq_args[i]->file = file; - tq_args[i]->name = SPLAT_TASKQ_TEST2_NAME; - - splat_vprint(file, SPLAT_TASKQ_TEST2_NAME, - "Taskq '%s/%d' function '%s' dispatching\n", - tq_args[i]->name, tq_args[i]->id, - sym2str(splat_taskq_test2_func1)); - if (prealloc) { - taskq_dispatch_ent(tq[i], splat_taskq_test2_func1, - tq_args[i], TQ_SLEEP, &func1_tqes[i]); - id = func1_tqes[i].tqent_id; - } else { - id = taskq_dispatch(tq[i], splat_taskq_test2_func1, - tq_args[i], TQ_SLEEP); - } - - if (id == TASKQID_INVALID) { - splat_vprint(file, SPLAT_TASKQ_TEST2_NAME, - "Taskq '%s/%d' function '%s' dispatch " - "failed\n", tq_args[i]->name, tq_args[i]->id, - sym2str(splat_taskq_test2_func1)); - rc = -EINVAL; - break; - } - - splat_vprint(file, SPLAT_TASKQ_TEST2_NAME, - "Taskq '%s/%d' function '%s' dispatching\n", - tq_args[i]->name, tq_args[i]->id, - sym2str(splat_taskq_test2_func2)); - if (prealloc) { - taskq_dispatch_ent(tq[i], splat_taskq_test2_func2, - tq_args[i], TQ_SLEEP, &func2_tqes[i]); - id = func2_tqes[i].tqent_id; - } else { - id = taskq_dispatch(tq[i], splat_taskq_test2_func2, - tq_args[i], TQ_SLEEP); - } - - if (id == TASKQID_INVALID) { - splat_vprint(file, SPLAT_TASKQ_TEST2_NAME, "Taskq " - "'%s/%d' function '%s' dispatch failed\n", - tq_args[i]->name, tq_args[i]->id, - sym2str(splat_taskq_test2_func2)); - rc = -EINVAL; - break; - } - } - - /* When rc is set we're effectively just doing cleanup here, so - * ignore new errors in that case. They just cause noise. */ - for (i = 0; i < TEST2_TASKQS; i++) { - if (tq_args[i] == NULL) - continue; - - if (tq[i] != NULL) { - splat_vprint(file, SPLAT_TASKQ_TEST2_NAME, - "Taskq '%s/%d' waiting\n", - tq_args[i]->name, tq_args[i]->id); - taskq_wait(tq[i]); - splat_vprint(file, SPLAT_TASKQ_TEST2_NAME, - "Taskq '%s/%d; destroying\n", - tq_args[i]->name, tq_args[i]->id); - - taskq_destroy(tq[i]); - - if (!rc && tq_args[i]->flag != ((i * 2) + 1)) { - splat_vprint(file, SPLAT_TASKQ_TEST2_NAME, - "Taskq '%s/%d' processed tasks " - "out of order; %d != %d\n", - tq_args[i]->name, tq_args[i]->id, - tq_args[i]->flag, i * 2 + 1); - rc = -EINVAL; - } else { - splat_vprint(file, SPLAT_TASKQ_TEST2_NAME, - "Taskq '%s/%d' processed tasks " - "in the correct order; %d == %d\n", - tq_args[i]->name, tq_args[i]->id, - tq_args[i]->flag, i * 2 + 1); - } - - kfree(tq_args[i]); - } - } -out: - if (func1_tqes) - kfree(func1_tqes); - - if (func2_tqes) - kfree(func2_tqes); - - return rc; -} - -static int -splat_taskq_test2(struct file *file, void *arg) { - int rc; - - rc = splat_taskq_test2_impl(file, arg, B_FALSE); - if (rc) - return rc; - - rc = splat_taskq_test2_impl(file, arg, B_TRUE); - - return rc; -} - -/* - * Use the global system task queue with a single task, wait until task - * completes, ensure task ran properly. - */ -static int -splat_taskq_test3_impl(struct file *file, void *arg, boolean_t prealloc) -{ - taskqid_t id; - splat_taskq_arg_t *tq_arg; - taskq_ent_t *tqe; - int error; - - tq_arg = kmem_alloc(sizeof (splat_taskq_arg_t), KM_SLEEP); - tqe = kmem_alloc(sizeof (taskq_ent_t), KM_SLEEP); - taskq_init_ent(tqe); - - tq_arg->flag = 0; - tq_arg->id = 0; - tq_arg->file = file; - tq_arg->name = SPLAT_TASKQ_TEST3_NAME; - - splat_vprint(file, SPLAT_TASKQ_TEST3_NAME, - "Taskq '%s' function '%s' %s dispatch\n", - tq_arg->name, sym2str(splat_taskq_test13_func), - prealloc ? "prealloc" : "dynamic"); - if (prealloc) { - taskq_dispatch_ent(system_taskq, splat_taskq_test13_func, - tq_arg, TQ_SLEEP, tqe); - id = tqe->tqent_id; - } else { - id = taskq_dispatch(system_taskq, splat_taskq_test13_func, - tq_arg, TQ_SLEEP); - } - - if (id == TASKQID_INVALID) { - splat_vprint(file, SPLAT_TASKQ_TEST3_NAME, - "Taskq '%s' function '%s' dispatch failed\n", - tq_arg->name, sym2str(splat_taskq_test13_func)); - kmem_free(tqe, sizeof (taskq_ent_t)); - kmem_free(tq_arg, sizeof (splat_taskq_arg_t)); - return -EINVAL; - } - - splat_vprint(file, SPLAT_TASKQ_TEST3_NAME, "Taskq '%s' waiting\n", - tq_arg->name); - taskq_wait(system_taskq); - - error = (tq_arg->flag) ? 0 : -EINVAL; - - kmem_free(tqe, sizeof (taskq_ent_t)); - kmem_free(tq_arg, sizeof (splat_taskq_arg_t)); - - return (error); -} - -static int -splat_taskq_test3(struct file *file, void *arg) -{ - int rc; - - rc = splat_taskq_test3_impl(file, arg, B_FALSE); - if (rc) - return rc; - - rc = splat_taskq_test3_impl(file, arg, B_TRUE); - - return rc; -} - -/* - * Create a taskq and dispatch a large number of tasks to the queue. - * Then use taskq_wait() to block until all the tasks complete, then - * cross check that all the tasks ran by checking the shared atomic - * counter which is incremented in the task function. - * - * First we try with a large 'maxalloc' value, then we try with a small one. - * We should not drop tasks when TQ_SLEEP is used in taskq_dispatch(), even - * if the number of pending tasks is above maxalloc. - */ -static void -splat_taskq_test4_func(void *arg) -{ - splat_taskq_arg_t *tq_arg = (splat_taskq_arg_t *)arg; - ASSERT(tq_arg); - - atomic_inc(tq_arg->count); -} - -static int -splat_taskq_test4_common(struct file *file, void *arg, int minalloc, - int maxalloc, int nr_tasks, boolean_t prealloc) -{ - taskq_t *tq; - taskqid_t id; - splat_taskq_arg_t tq_arg; - taskq_ent_t *tqes; - atomic_t count; - int i, j, rc = 0; - - tqes = kmalloc(sizeof(*tqes) * nr_tasks, GFP_KERNEL); - if (tqes == NULL) - return -ENOMEM; - - splat_vprint(file, SPLAT_TASKQ_TEST4_NAME, - "Taskq '%s' creating (%s dispatch) (%d/%d/%d)\n", - SPLAT_TASKQ_TEST4_NAME, - prealloc ? "prealloc" : "dynamic", - minalloc, maxalloc, nr_tasks); - 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", - SPLAT_TASKQ_TEST4_NAME); - rc = -EINVAL; - goto out_free; - } - - tq_arg.file = file; - tq_arg.name = SPLAT_TASKQ_TEST4_NAME; - tq_arg.count = &count; - - for (i = 1; i <= nr_tasks; i *= 2) { - atomic_set(tq_arg.count, 0); - splat_vprint(file, SPLAT_TASKQ_TEST4_NAME, - "Taskq '%s' function '%s' dispatched %d times\n", - tq_arg.name, sym2str(splat_taskq_test4_func), i); - - for (j = 0; j < i; j++) { - taskq_init_ent(&tqes[j]); - - if (prealloc) { - taskq_dispatch_ent(tq, splat_taskq_test4_func, - &tq_arg, TQ_SLEEP, &tqes[j]); - id = tqes[j].tqent_id; - } else { - id = taskq_dispatch(tq, splat_taskq_test4_func, - &tq_arg, TQ_SLEEP); - } - - if (id == TASKQID_INVALID) { - splat_vprint(file, SPLAT_TASKQ_TEST4_NAME, - "Taskq '%s' function '%s' dispatch " - "%d failed\n", tq_arg.name, - sym2str(splat_taskq_test4_func), j); - rc = -EINVAL; - goto out; - } - } - - splat_vprint(file, SPLAT_TASKQ_TEST4_NAME, "Taskq '%s' " - "waiting for %d dispatches\n", tq_arg.name, i); - taskq_wait(tq); - splat_vprint(file, SPLAT_TASKQ_TEST4_NAME, "Taskq '%s' " - "%d/%d dispatches finished\n", tq_arg.name, - atomic_read(&count), i); - if (atomic_read(&count) != i) { - rc = -ERANGE; - goto out; - - } - } -out: - splat_vprint(file, SPLAT_TASKQ_TEST4_NAME, "Taskq '%s' destroying\n", - tq_arg.name); - taskq_destroy(tq); - -out_free: - kfree(tqes); - - return rc; -} - -static int -splat_taskq_test4_impl(struct file *file, void *arg, boolean_t prealloc) -{ - int rc; - - rc = splat_taskq_test4_common(file, arg, 50, INT_MAX, 1024, prealloc); - if (rc) - return rc; - - rc = splat_taskq_test4_common(file, arg, 1, 1, 32, prealloc); - - return rc; -} - -static int -splat_taskq_test4(struct file *file, void *arg) -{ - int rc; - - rc = splat_taskq_test4_impl(file, arg, B_FALSE); - if (rc) - return rc; - - rc = splat_taskq_test4_impl(file, arg, B_TRUE); - - return rc; -} - -/* - * Create a taskq and dispatch a specific sequence of tasks carefully - * crafted to validate the order in which tasks are processed. When - * there are multiple worker threads each thread will process the - * 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 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_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: - * - * 1) Task ids larger than the waited for task id can run and - * complete as long as there is an available worker thread. - * 2) All task ids lower than the waited one must complete before - * unblocking even if the waited task id itself has completed. - * - * 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_outstanding() - * must unblock for a specific id are identified as well as the - * task ids which must have completed and their order. - * - * +-----+ <--- taskq_wait_outstanding(tq, 8) unblocks - * | | Required Completion Order: 1,2,4,5,3,8,6,7 - * +-----+ | - * | | | - * | | +-----+ - * | | | 8 | - * | | +-----+ <--- taskq_wait_outstanding(tq, 3) unblocks - * | | 7 | | Required Completion Order: 1,2,4,5,3 - * | +-----+ | - * | 6 | | | - * +-----+ | | - * | | 5 | | - * | +-----+ | - * | 4 | | | - * +-----+ | | - * | 1 | 2 | 3 | - * +-----+-----+-----+ - * - */ -static void -splat_taskq_test5_func(void *arg) -{ - splat_taskq_id_t *tq_id = (splat_taskq_id_t *)arg; - splat_taskq_arg_t *tq_arg = tq_id->arg; - int factor; - - /* Delays determined by above table */ - switch (tq_id->id) { - default: factor = 0; break; - case 1: case 8: factor = 1; break; - case 2: case 4: case 5: factor = 2; break; - case 6: case 7: factor = 4; break; - case 3: factor = 5; break; - } - - msleep(factor * 100); - splat_vprint(tq_arg->file, tq_arg->name, - "Taskqid %d complete for taskq '%s'\n", - tq_id->id, tq_arg->name); - - spin_lock(&tq_arg->lock); - tq_arg->order[tq_arg->flag] = tq_id->id; - tq_arg->flag++; - spin_unlock(&tq_arg->lock); -} - -static int -splat_taskq_test_order(splat_taskq_arg_t *tq_arg, int *order) -{ - int i, j; - - for (i = 0; i < SPLAT_TASKQ_ORDER_MAX; i++) { - if (tq_arg->order[i] != order[i]) { - splat_vprint(tq_arg->file, tq_arg->name, - "Taskq '%s' incorrect completion " - "order\n", tq_arg->name); - splat_vprint(tq_arg->file, tq_arg->name, - "%s", "Expected { "); - - for (j = 0; j < SPLAT_TASKQ_ORDER_MAX; j++) - splat_print(tq_arg->file, "%d ", order[j]); - - splat_print(tq_arg->file, "%s", "}\n"); - splat_vprint(tq_arg->file, tq_arg->name, - "%s", "Got { "); - - for (j = 0; j < SPLAT_TASKQ_ORDER_MAX; j++) - splat_print(tq_arg->file, "%d ", - tq_arg->order[j]); - - splat_print(tq_arg->file, "%s", "}\n"); - return -EILSEQ; - } - } - - splat_vprint(tq_arg->file, tq_arg->name, - "Taskq '%s' validated correct completion order\n", - tq_arg->name); - - return 0; -} - -static int -splat_taskq_test5_impl(struct file *file, void *arg, boolean_t prealloc) -{ - taskq_t *tq; - taskqid_t id; - splat_taskq_id_t tq_id[SPLAT_TASKQ_ORDER_MAX]; - splat_taskq_arg_t tq_arg; - int order1[SPLAT_TASKQ_ORDER_MAX] = { 1,2,4,5,3,0,0,0 }; - int order2[SPLAT_TASKQ_ORDER_MAX] = { 1,2,4,5,3,8,6,7 }; - taskq_ent_t *tqes; - int i, rc = 0; - - tqes = kmem_alloc(sizeof(*tqes) * SPLAT_TASKQ_ORDER_MAX, KM_SLEEP); - memset(tqes, 0, sizeof(*tqes) * SPLAT_TASKQ_ORDER_MAX); - - splat_vprint(file, SPLAT_TASKQ_TEST5_NAME, - "Taskq '%s' creating (%s dispatch)\n", - SPLAT_TASKQ_TEST5_NAME, - prealloc ? "prealloc" : "dynamic"); - 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", - SPLAT_TASKQ_TEST5_NAME); - return -EINVAL; - } - - tq_arg.flag = 0; - memset(&tq_arg.order, 0, sizeof(int) * SPLAT_TASKQ_ORDER_MAX); - spin_lock_init(&tq_arg.lock); - tq_arg.file = file; - tq_arg.name = SPLAT_TASKQ_TEST5_NAME; - - for (i = 0; i < SPLAT_TASKQ_ORDER_MAX; i++) { - taskq_init_ent(&tqes[i]); - - tq_id[i].id = i + 1; - tq_id[i].arg = &tq_arg; - - if (prealloc) { - taskq_dispatch_ent(tq, splat_taskq_test5_func, - &tq_id[i], TQ_SLEEP, &tqes[i]); - id = tqes[i].tqent_id; - } else { - id = taskq_dispatch(tq, splat_taskq_test5_func, - &tq_id[i], TQ_SLEEP); - } - - if (id == TASKQID_INVALID) { - splat_vprint(file, SPLAT_TASKQ_TEST5_NAME, - "Taskq '%s' function '%s' dispatch failed\n", - tq_arg.name, sym2str(splat_taskq_test5_func)); - rc = -EINVAL; - goto out; - } - - if (tq_id[i].id != id) { - splat_vprint(file, SPLAT_TASKQ_TEST5_NAME, - "Taskq '%s' expected taskqid %d got %d\n", - tq_arg.name, (int)tq_id[i].id, (int)id); - rc = -EINVAL; - goto out; - } - } - - splat_vprint(file, SPLAT_TASKQ_TEST5_NAME, "Taskq '%s' " - "waiting for taskqid %d completion\n", tq_arg.name, 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_outstanding(tq, 8); - rc = splat_taskq_test_order(&tq_arg, order2); - -out: - splat_vprint(file, SPLAT_TASKQ_TEST5_NAME, - "Taskq '%s' destroying\n", tq_arg.name); - taskq_destroy(tq); - - kmem_free(tqes, sizeof(*tqes) * SPLAT_TASKQ_ORDER_MAX); - - return rc; -} - -static int -splat_taskq_test5(struct file *file, void *arg) -{ - int rc; - - rc = splat_taskq_test5_impl(file, arg, B_FALSE); - if (rc) - return rc; - - rc = splat_taskq_test5_impl(file, arg, B_TRUE); - - return rc; -} - -/* - * Create a single task queue with three threads. Dispatch 8 tasks, - * setting TQ_FRONT on only the last three. Sleep after - * dispatching tasks 1-3 to ensure they will run and hold the threads - * busy while we dispatch the remaining tasks. Verify that tasks 6-8 - * run before task 4-5. - * - * 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. - * - * NB: The Horizontal Line is the LAST Time unit consumed by the Task, - * and must be included in the factor calculation. - * T - * 17-> +-----+ - * 16 | T6 | - * 15-> +-----+ | - * 14 | T6 | | - * 13-> | | 5 +-----+ - * 12 | | | T6 | - * 11-> | +-----| | - * 10 | 4 | T6 | | - * 9-> +-----+ | 8 | - * 8 | T5 | | | - * 7-> | | 7 +-----+ - * 6 | | | T7 | - * 5-> | +-----+ | - * 4 | 6 | T5 | | - * 3-> +-----+ | | - * 2 | T3 | | | - * 1 | 1 | 2 | 3 | - * 0 +-----+-----+-----+ - * - */ -static void -splat_taskq_test6_func(void *arg) -{ - /* Delays determined by above table */ - static const int factor[SPLAT_TASKQ_ORDER_MAX+1] = {0,3,5,7,6,6,5,6,6}; - - splat_taskq_id_t *tq_id = (splat_taskq_id_t *)arg; - splat_taskq_arg_t *tq_arg = tq_id->arg; - - splat_vprint(tq_arg->file, tq_arg->name, - "Taskqid %d starting for taskq '%s'\n", - tq_id->id, tq_arg->name); - - if (tq_id->id < SPLAT_TASKQ_ORDER_MAX+1) { - msleep(factor[tq_id->id] * 50); - } - - spin_lock(&tq_arg->lock); - tq_arg->order[tq_arg->flag] = tq_id->id; - tq_arg->flag++; - spin_unlock(&tq_arg->lock); - - splat_vprint(tq_arg->file, tq_arg->name, - "Taskqid %d complete for taskq '%s'\n", - tq_id->id, tq_arg->name); -} - -static int -splat_taskq_test6_impl(struct file *file, void *arg, boolean_t prealloc) -{ - taskq_t *tq; - taskqid_t id; - splat_taskq_id_t tq_id[SPLAT_TASKQ_ORDER_MAX]; - splat_taskq_arg_t tq_arg; - int order[SPLAT_TASKQ_ORDER_MAX] = { 1,2,3,6,7,8,4,5 }; - taskq_ent_t *tqes; - int i, rc = 0; - uint_t tflags; - - tqes = kmem_alloc(sizeof(*tqes) * SPLAT_TASKQ_ORDER_MAX, KM_SLEEP); - memset(tqes, 0, sizeof(*tqes) * SPLAT_TASKQ_ORDER_MAX); - - splat_vprint(file, SPLAT_TASKQ_TEST6_NAME, - "Taskq '%s' creating (%s dispatch)\n", - SPLAT_TASKQ_TEST6_NAME, - prealloc ? "prealloc" : "dynamic"); - 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", - SPLAT_TASKQ_TEST6_NAME); - return -EINVAL; - } - - tq_arg.flag = 0; - memset(&tq_arg.order, 0, sizeof(int) * SPLAT_TASKQ_ORDER_MAX); - spin_lock_init(&tq_arg.lock); - tq_arg.file = file; - tq_arg.name = SPLAT_TASKQ_TEST6_NAME; - - for (i = 0; i < SPLAT_TASKQ_ORDER_MAX; i++) { - taskq_init_ent(&tqes[i]); - - tq_id[i].id = i + 1; - tq_id[i].arg = &tq_arg; - tflags = TQ_SLEEP; - if (i > 4) - tflags |= TQ_FRONT; - - if (prealloc) { - taskq_dispatch_ent(tq, splat_taskq_test6_func, - &tq_id[i], tflags, &tqes[i]); - id = tqes[i].tqent_id; - } else { - id = taskq_dispatch(tq, splat_taskq_test6_func, - &tq_id[i], tflags); - } - - if (id == TASKQID_INVALID) { - splat_vprint(file, SPLAT_TASKQ_TEST6_NAME, - "Taskq '%s' function '%s' dispatch failed\n", - tq_arg.name, sym2str(splat_taskq_test6_func)); - rc = -EINVAL; - goto out; - } - - if (tq_id[i].id != id) { - splat_vprint(file, SPLAT_TASKQ_TEST6_NAME, - "Taskq '%s' expected taskqid %d got %d\n", - tq_arg.name, (int)tq_id[i].id, (int)id); - rc = -EINVAL; - goto out; - } - /* Sleep to let tasks 1-3 start executing. */ - if ( i == 2 ) - msleep(100); - } - - splat_vprint(file, SPLAT_TASKQ_TEST6_NAME, "Taskq '%s' " - "waiting for taskqid %d completion\n", tq_arg.name, - SPLAT_TASKQ_ORDER_MAX); - taskq_wait_outstanding(tq, SPLAT_TASKQ_ORDER_MAX); - rc = splat_taskq_test_order(&tq_arg, order); - -out: - splat_vprint(file, SPLAT_TASKQ_TEST6_NAME, - "Taskq '%s' destroying\n", tq_arg.name); - taskq_destroy(tq); - - kmem_free(tqes, sizeof(*tqes) * SPLAT_TASKQ_ORDER_MAX); - - return rc; -} - -static int -splat_taskq_test6(struct file *file, void *arg) -{ - int rc; - - rc = splat_taskq_test6_impl(file, arg, B_FALSE); - if (rc) - return rc; - - rc = splat_taskq_test6_impl(file, arg, B_TRUE); - - return rc; -} - -static void -splat_taskq_test7_func(void *arg) -{ - splat_taskq_arg_t *tq_arg = (splat_taskq_arg_t *)arg; - taskqid_t id; - - ASSERT(tq_arg); - - if (tq_arg->depth >= SPLAT_TASKQ_DEPTH_MAX) - return; - - tq_arg->depth++; - - splat_vprint(tq_arg->file, SPLAT_TASKQ_TEST7_NAME, - "Taskq '%s' function '%s' dispatching (depth = %u)\n", - tq_arg->name, sym2str(splat_taskq_test7_func), - tq_arg->depth); - - if (tq_arg->tqe) { - VERIFY(taskq_empty_ent(tq_arg->tqe)); - taskq_dispatch_ent(tq_arg->tq, splat_taskq_test7_func, - tq_arg, TQ_SLEEP, tq_arg->tqe); - id = tq_arg->tqe->tqent_id; - } else { - id = taskq_dispatch(tq_arg->tq, splat_taskq_test7_func, - tq_arg, TQ_SLEEP); - } - - if (id == TASKQID_INVALID) { - splat_vprint(tq_arg->file, SPLAT_TASKQ_TEST7_NAME, - "Taskq '%s' function '%s' dispatch failed " - "(depth = %u)\n", tq_arg->name, - sym2str(splat_taskq_test7_func), tq_arg->depth); - tq_arg->flag = -EINVAL; - return; - } -} - -static int -splat_taskq_test7_impl(struct file *file, void *arg, boolean_t prealloc) -{ - taskq_t *tq; - splat_taskq_arg_t *tq_arg; - taskq_ent_t *tqe; - int error; - - splat_vprint(file, SPLAT_TASKQ_TEST7_NAME, - "Taskq '%s' creating (%s dispatch)\n", - SPLAT_TASKQ_TEST7_NAME, - prealloc ? "prealloc" : "dynamic"); - 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", - SPLAT_TASKQ_TEST7_NAME); - return -EINVAL; - } - - tq_arg = kmem_alloc(sizeof (splat_taskq_arg_t), KM_SLEEP); - tqe = kmem_alloc(sizeof (taskq_ent_t), KM_SLEEP); - - tq_arg->depth = 0; - tq_arg->flag = 0; - tq_arg->id = 0; - tq_arg->file = file; - tq_arg->name = SPLAT_TASKQ_TEST7_NAME; - tq_arg->tq = tq; - - if (prealloc) { - taskq_init_ent(tqe); - tq_arg->tqe = tqe; - } else { - tq_arg->tqe = NULL; - } - - splat_taskq_test7_func(tq_arg); - - if (tq_arg->flag == 0) { - splat_vprint(file, SPLAT_TASKQ_TEST7_NAME, - "Taskq '%s' waiting\n", tq_arg->name); - taskq_wait_outstanding(tq, SPLAT_TASKQ_DEPTH_MAX); - } - - error = (tq_arg->depth == SPLAT_TASKQ_DEPTH_MAX ? 0 : -EINVAL); - - splat_vprint(file, SPLAT_TASKQ_TEST7_NAME, - "Taskq '%s' destroying\n", tq_arg->name); - - kmem_free(tqe, sizeof (taskq_ent_t)); - kmem_free(tq_arg, sizeof (splat_taskq_arg_t)); - - taskq_destroy(tq); - - return (error); -} - -static int -splat_taskq_test7(struct file *file, void *arg) -{ - int rc; - - rc = splat_taskq_test7_impl(file, arg, B_FALSE); - if (rc) - return (rc); - - rc = splat_taskq_test7_impl(file, arg, B_TRUE); - - return (rc); -} - -static void -splat_taskq_throughput_func(void *arg) -{ - splat_taskq_arg_t *tq_arg = (splat_taskq_arg_t *)arg; - ASSERT(tq_arg); - - atomic_inc(tq_arg->count); -} - -static int -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) * tasks); - if (tqes == NULL) - 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 = name; - tq_arg.count = &count; - atomic_set(tq_arg.count, 0); - - 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_throughput_func, - &tq_arg, TQ_SLEEP, tqes[i]); - id = tqes[i]->tqent_id; - - if (id == TASKQID_INVALID) { - 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, name, "Taskq '%s' waiting for %d dispatches\n", - tq_arg.name, tasks); - - taskq_wait(tq); - - 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, name, "Taskq '%s' destroying\n", tq_arg.name); - taskq_destroy(tq); -out_free: - for (j = 0; j < tasks && tqes[j] != NULL; j++) - kfree(tqes[j]); - - vfree(tqes); - - 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) -{ - return (splat_taskq_throughput(file, arg, - SPLAT_TASKQ_TEST8_NAME, TEST8_THREADS_PER_TASKQ, - 1, INT_MAX, TASKQ_PREPOPULATE, TEST8_NUM_TASKS, NULL)); -} - -/* - * Create a taskq and dispatch a number of delayed tasks to the queue. - * For each task verify that it was run no early than requested. - */ -static void -splat_taskq_test9_func(void *arg) -{ - splat_taskq_arg_t *tq_arg = (splat_taskq_arg_t *)arg; - ASSERT(tq_arg); - - if (ddi_time_after_eq(ddi_get_lbolt(), tq_arg->expire)) - atomic_inc(tq_arg->count); - - kmem_free(tq_arg, sizeof(splat_taskq_arg_t)); -} - -static int -splat_taskq_test9(struct file *file, void *arg) -{ - taskq_t *tq; - atomic_t count; - int i, rc = 0; - int minalloc = 1; - int maxalloc = 10; - int nr_tasks = 100; - - 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, defclsyspri, - minalloc, maxalloc, TASKQ_PREPOPULATE)) == NULL) { - splat_vprint(file, SPLAT_TASKQ_TEST9_NAME, - "Taskq '%s' create failed\n", SPLAT_TASKQ_TEST9_NAME); - return -EINVAL; - } - - atomic_set(&count, 0); - - for (i = 1; i <= nr_tasks; i++) { - splat_taskq_arg_t *tq_arg; - taskqid_t id; - uint32_t rnd; - - /* A random timeout in jiffies of at most 5 seconds */ - get_random_bytes((void *)&rnd, 4); - rnd = rnd % (5 * HZ); - - tq_arg = kmem_alloc(sizeof(splat_taskq_arg_t), KM_SLEEP); - tq_arg->file = file; - tq_arg->name = SPLAT_TASKQ_TEST9_NAME; - tq_arg->expire = ddi_get_lbolt() + rnd; - tq_arg->count = &count; - - splat_vprint(file, SPLAT_TASKQ_TEST9_NAME, - "Taskq '%s' delay dispatch %u jiffies\n", - SPLAT_TASKQ_TEST9_NAME, rnd); - - id = taskq_dispatch_delay(tq, splat_taskq_test9_func, - tq_arg, TQ_SLEEP, ddi_get_lbolt() + rnd); - - if (id == TASKQID_INVALID) { - splat_vprint(file, SPLAT_TASKQ_TEST9_NAME, - "Taskq '%s' delay dispatch failed\n", - SPLAT_TASKQ_TEST9_NAME); - kmem_free(tq_arg, sizeof(splat_taskq_arg_t)); - taskq_wait(tq); - rc = -EINVAL; - goto out; - } - } - - splat_vprint(file, SPLAT_TASKQ_TEST9_NAME, "Taskq '%s' waiting for " - "%d delay dispatches\n", SPLAT_TASKQ_TEST9_NAME, nr_tasks); - - taskq_wait(tq); - if (atomic_read(&count) != nr_tasks) - rc = -ERANGE; - - splat_vprint(file, SPLAT_TASKQ_TEST9_NAME, "Taskq '%s' %d/%d delay " - "dispatches finished on time\n", SPLAT_TASKQ_TEST9_NAME, - atomic_read(&count), nr_tasks); - splat_vprint(file, SPLAT_TASKQ_TEST9_NAME, "Taskq '%s' destroying\n", - SPLAT_TASKQ_TEST9_NAME); -out: - taskq_destroy(tq); - - return rc; -} - -/* - * Create a taskq and dispatch then cancel tasks in the queue. - */ -static void -splat_taskq_test10_func(void *arg) -{ - splat_taskq_arg_t *tq_arg = (splat_taskq_arg_t *)arg; - uint8_t rnd; - - if (ddi_time_after_eq(ddi_get_lbolt(), tq_arg->expire)) - atomic_inc(tq_arg->count); - - /* Randomly sleep to further perturb the system */ - get_random_bytes((void *)&rnd, 1); - msleep(1 + (rnd % 9)); -} - -static int -splat_taskq_test10(struct file *file, void *arg) -{ - taskq_t *tq; - splat_taskq_arg_t **tqas; - atomic_t count; - int i, j, rc = 0; - int minalloc = 1; - int maxalloc = 10; - int nr_tasks = 100; - int canceled = 0; - int completed = 0; - int blocked = 0; - clock_t start, cancel; - - tqas = vmalloc(sizeof(*tqas) * nr_tasks); - if (tqas == NULL) - return -ENOMEM; - memset(tqas, 0, sizeof(*tqas) * nr_tasks); - - 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, defclsyspri, - minalloc, maxalloc, TASKQ_PREPOPULATE)) == NULL) { - splat_vprint(file, SPLAT_TASKQ_TEST10_NAME, - "Taskq '%s' create failed\n", SPLAT_TASKQ_TEST10_NAME); - rc = -EINVAL; - goto out_free; - } - - atomic_set(&count, 0); - - for (i = 0; i < nr_tasks; i++) { - splat_taskq_arg_t *tq_arg; - uint32_t rnd; - - /* A random timeout in jiffies of at most 5 seconds */ - get_random_bytes((void *)&rnd, 4); - rnd = rnd % (5 * HZ); - - tq_arg = kmem_alloc(sizeof(splat_taskq_arg_t), KM_SLEEP); - tq_arg->file = file; - tq_arg->name = SPLAT_TASKQ_TEST10_NAME; - tq_arg->count = &count; - tqas[i] = tq_arg; - - /* - * Dispatch every 1/3 one immediately to mix it up, the cancel - * code is inherently racy and we want to try and provoke any - * subtle concurrently issues. - */ - if ((i % 3) == 0) { - tq_arg->expire = ddi_get_lbolt(); - tq_arg->id = taskq_dispatch(tq, splat_taskq_test10_func, - tq_arg, TQ_SLEEP); - } else { - tq_arg->expire = ddi_get_lbolt() + rnd; - tq_arg->id = taskq_dispatch_delay(tq, - splat_taskq_test10_func, - tq_arg, TQ_SLEEP, ddi_get_lbolt() + rnd); - } - - if (tq_arg->id == TASKQID_INVALID) { - splat_vprint(file, SPLAT_TASKQ_TEST10_NAME, - "Taskq '%s' dispatch failed\n", - SPLAT_TASKQ_TEST10_NAME); - kmem_free(tq_arg, sizeof(splat_taskq_arg_t)); - taskq_wait(tq); - rc = -EINVAL; - goto out; - } else { - splat_vprint(file, SPLAT_TASKQ_TEST10_NAME, - "Taskq '%s' dispatch %lu in %lu jiffies\n", - SPLAT_TASKQ_TEST10_NAME, (unsigned long)tq_arg->id, - !(i % 3) ? 0 : tq_arg->expire - ddi_get_lbolt()); - } - } - - /* - * Start randomly canceling tasks for the duration of the test. We - * happen to know the valid task id's will be in the range 1..nr_tasks - * because the taskq is private and was just created. However, we - * have no idea of a particular task has already executed or not. - */ - splat_vprint(file, SPLAT_TASKQ_TEST10_NAME, "Taskq '%s' randomly " - "canceling task ids\n", SPLAT_TASKQ_TEST10_NAME); - - start = ddi_get_lbolt(); - i = 0; - - while (ddi_time_before(ddi_get_lbolt(), start + 5 * HZ)) { - taskqid_t id; - uint32_t rnd; - - i++; - cancel = ddi_get_lbolt(); - get_random_bytes((void *)&rnd, 4); - id = 1 + (rnd % nr_tasks); - rc = taskq_cancel_id(tq, id); - - /* - * Keep track of the results of the random cancels. - */ - if (rc == 0) { - canceled++; - } else if (rc == ENOENT) { - completed++; - } else if (rc == EBUSY) { - blocked++; - } else { - rc = -EINVAL; - break; - } - - /* - * Verify we never get blocked to long in taskq_cancel_id(). - * The worst case is 10ms if we happen to cancel the task - * which is currently executing. We allow a factor of 2x. - */ - if (ddi_get_lbolt() - cancel > HZ / 50) { - splat_vprint(file, SPLAT_TASKQ_TEST10_NAME, - "Taskq '%s' cancel for %lu took %lu\n", - SPLAT_TASKQ_TEST10_NAME, (unsigned long)id, - ddi_get_lbolt() - cancel); - rc = -ETIMEDOUT; - break; - } - - get_random_bytes((void *)&rnd, 4); - msleep(1 + (rnd % 100)); - rc = 0; - } - - taskq_wait(tq); - - /* - * Cross check the results of taskq_cancel_id() with the number of - * times the dispatched function actually ran successfully. - */ - if ((rc == 0) && (nr_tasks - canceled != atomic_read(&count))) - rc = -EDOM; - - splat_vprint(file, SPLAT_TASKQ_TEST10_NAME, "Taskq '%s' %d attempts, " - "%d canceled, %d completed, %d blocked, %d/%d tasks run\n", - SPLAT_TASKQ_TEST10_NAME, i, canceled, completed, blocked, - atomic_read(&count), nr_tasks); - splat_vprint(file, SPLAT_TASKQ_TEST10_NAME, "Taskq '%s' destroying %d\n", - SPLAT_TASKQ_TEST10_NAME, rc); -out: - taskq_destroy(tq); -out_free: - for (j = 0; j < nr_tasks && tqas[j] != NULL; j++) - kmem_free(tqas[j], sizeof(splat_taskq_arg_t)); - vfree(tqas); - - 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 (((int64_t)dynamic.tv_sec * NANOSEC + (int64_t)dynamic.tv_nsec) > - (((int64_t)normal.tv_sec * NANOSEC + (int64_t)normal.tv_nsec) * 10)) - error = -ETIME; - - return (error); -} - -splat_subsystem_t * -splat_taskq_init(void) -{ - splat_subsystem_t *sub; - - sub = kmalloc(sizeof(*sub), GFP_KERNEL); - if (sub == NULL) - return NULL; - - memset(sub, 0, sizeof(*sub)); - strncpy(sub->desc.name, SPLAT_TASKQ_NAME, SPLAT_NAME_SIZE); - strncpy(sub->desc.desc, SPLAT_TASKQ_DESC, SPLAT_DESC_SIZE); - INIT_LIST_HEAD(&sub->subsystem_list); - INIT_LIST_HEAD(&sub->test_list); - spin_lock_init(&sub->test_lock); - sub->desc.id = SPLAT_SUBSYSTEM_TASKQ; - - splat_test_init(sub, SPLAT_TASKQ_TEST1_NAME, SPLAT_TASKQ_TEST1_DESC, - SPLAT_TASKQ_TEST1_ID, splat_taskq_test1); - splat_test_init(sub, SPLAT_TASKQ_TEST2_NAME, SPLAT_TASKQ_TEST2_DESC, - SPLAT_TASKQ_TEST2_ID, splat_taskq_test2); - splat_test_init(sub, SPLAT_TASKQ_TEST3_NAME, SPLAT_TASKQ_TEST3_DESC, - SPLAT_TASKQ_TEST3_ID, splat_taskq_test3); - splat_test_init(sub, SPLAT_TASKQ_TEST4_NAME, SPLAT_TASKQ_TEST4_DESC, - SPLAT_TASKQ_TEST4_ID, splat_taskq_test4); - splat_test_init(sub, SPLAT_TASKQ_TEST5_NAME, SPLAT_TASKQ_TEST5_DESC, - SPLAT_TASKQ_TEST5_ID, splat_taskq_test5); - splat_test_init(sub, SPLAT_TASKQ_TEST6_NAME, SPLAT_TASKQ_TEST6_DESC, - SPLAT_TASKQ_TEST6_ID, splat_taskq_test6); - splat_test_init(sub, SPLAT_TASKQ_TEST7_NAME, SPLAT_TASKQ_TEST7_DESC, - SPLAT_TASKQ_TEST7_ID, splat_taskq_test7); - splat_test_init(sub, SPLAT_TASKQ_TEST8_NAME, SPLAT_TASKQ_TEST8_DESC, - SPLAT_TASKQ_TEST8_ID, splat_taskq_test8); - splat_test_init(sub, SPLAT_TASKQ_TEST9_NAME, SPLAT_TASKQ_TEST9_DESC, - 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; -} - -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); - splat_test_fini(sub, SPLAT_TASKQ_TEST7_ID); - splat_test_fini(sub, SPLAT_TASKQ_TEST6_ID); - splat_test_fini(sub, SPLAT_TASKQ_TEST5_ID); - splat_test_fini(sub, SPLAT_TASKQ_TEST4_ID); - splat_test_fini(sub, SPLAT_TASKQ_TEST3_ID); - splat_test_fini(sub, SPLAT_TASKQ_TEST2_ID); - splat_test_fini(sub, SPLAT_TASKQ_TEST1_ID); - - kfree(sub); -} - -int -splat_taskq_id(void) { - return SPLAT_SUBSYSTEM_TASKQ; -} diff --git a/module/splat/splat-thread.c b/module/splat/splat-thread.c deleted file mode 100644 index f2e6bf15e..000000000 --- a/module/splat/splat-thread.c +++ /dev/null @@ -1,390 +0,0 @@ -/* - * 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). - * Written by Brian Behlendorf <[email protected]>. - * UCRL-CODE-235197 - * - * 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/>. - ***************************************************************************** - * Solaris Porting LAyer Tests (SPLAT) Thread Tests. - */ - -#include <sys/thread.h> -#include <sys/random.h> -#include <linux/delay.h> -#include <linux/mm_compat.h> -#include <linux/wait_compat.h> -#include <linux/slab.h> -#include "splat-internal.h" - -#define SPLAT_THREAD_NAME "thread" -#define SPLAT_THREAD_DESC "Kernel Thread Tests" - -#define SPLAT_THREAD_TEST1_ID 0x0601 -#define SPLAT_THREAD_TEST1_NAME "create" -#define SPLAT_THREAD_TEST1_DESC "Validate thread creation" - -#define SPLAT_THREAD_TEST2_ID 0x0602 -#define SPLAT_THREAD_TEST2_NAME "exit" -#define SPLAT_THREAD_TEST2_DESC "Validate thread exit" - -#define SPLAT_THREAD_TEST3_ID 0x6003 -#define SPLAT_THREAD_TEST3_NAME "tsd" -#define SPLAT_THREAD_TEST3_DESC "Validate thread specific data" - -#define SPLAT_THREAD_TEST_MAGIC 0x4488CC00UL -#define SPLAT_THREAD_TEST_KEYS 32 -#define SPLAT_THREAD_TEST_THREADS 16 - -typedef struct thread_priv { - unsigned long tp_magic; - struct file *tp_file; - spinlock_t tp_lock; - spl_wait_queue_head_t tp_waitq; - uint_t tp_keys[SPLAT_THREAD_TEST_KEYS]; - int tp_rc; - int tp_count; - int tp_dtor_count; -} thread_priv_t; - -static int -splat_thread_rc(thread_priv_t *tp, int rc) -{ - int ret; - - spin_lock(&tp->tp_lock); - ret = (tp->tp_rc == rc); - spin_unlock(&tp->tp_lock); - - return ret; -} - -static int -splat_thread_count(thread_priv_t *tp, int count) -{ - int ret; - - spin_lock(&tp->tp_lock); - ret = (tp->tp_count == count); - spin_unlock(&tp->tp_lock); - - return ret; -} - -static void -splat_thread_work1(void *priv) -{ - thread_priv_t *tp = (thread_priv_t *)priv; - - spin_lock(&tp->tp_lock); - ASSERT(tp->tp_magic == SPLAT_THREAD_TEST_MAGIC); - tp->tp_rc = 1; - wake_up(&tp->tp_waitq); - spin_unlock(&tp->tp_lock); - - thread_exit(); -} - -static int -splat_thread_test1(struct file *file, void *arg) -{ - thread_priv_t tp; - kthread_t *thr; - - tp.tp_magic = SPLAT_THREAD_TEST_MAGIC; - tp.tp_file = file; - spin_lock_init(&tp.tp_lock); - init_waitqueue_head(&tp.tp_waitq); - tp.tp_rc = 0; - - thr = (kthread_t *)thread_create(NULL, 0, splat_thread_work1, &tp, 0, - &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) - return -ESRCH; - - /* Sleep until the thread sets tp.tp_rc == 1 */ - wait_event(tp.tp_waitq, splat_thread_rc(&tp, 1)); - - splat_vprint(file, SPLAT_THREAD_TEST1_NAME, "%s", - "Thread successfully started properly\n"); - return 0; -} - -static void -splat_thread_work2(void *priv) -{ - thread_priv_t *tp = (thread_priv_t *)priv; - - spin_lock(&tp->tp_lock); - ASSERT(tp->tp_magic == SPLAT_THREAD_TEST_MAGIC); - tp->tp_rc = 1; - wake_up(&tp->tp_waitq); - spin_unlock(&tp->tp_lock); - - thread_exit(); - - /* The following code is unreachable when thread_exit() is - * working properly, which is exactly what we're testing */ - spin_lock(&tp->tp_lock); - tp->tp_rc = 2; - wake_up(&tp->tp_waitq); - spin_unlock(&tp->tp_lock); -} - -static int -splat_thread_test2(struct file *file, void *arg) -{ - thread_priv_t tp; - kthread_t *thr; - int rc = 0; - - tp.tp_magic = SPLAT_THREAD_TEST_MAGIC; - tp.tp_file = file; - spin_lock_init(&tp.tp_lock); - init_waitqueue_head(&tp.tp_waitq); - tp.tp_rc = 0; - - thr = (kthread_t *)thread_create(NULL, 0, splat_thread_work2, &tp, 0, - &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) - return -ESRCH; - - /* Sleep until the thread sets tp.tp_rc == 1 */ - wait_event(tp.tp_waitq, splat_thread_rc(&tp, 1)); - - /* Sleep until the thread sets tp.tp_rc == 2, or until we hit - * the timeout. If thread exit is working properly we should - * hit the timeout and never see to.tp_rc == 2. */ - rc = wait_event_timeout(tp.tp_waitq, splat_thread_rc(&tp, 2), HZ / 10); - if (rc > 0) { - rc = -EINVAL; - splat_vprint(file, SPLAT_THREAD_TEST2_NAME, "%s", - "Thread did not exit properly at thread_exit()\n"); - } else { - splat_vprint(file, SPLAT_THREAD_TEST2_NAME, "%s", - "Thread successfully exited at thread_exit()\n"); - } - - return rc; -} - -static void -splat_thread_work3_common(thread_priv_t *tp) -{ - ulong_t rnd; - int i, rc = 0; - - /* set a unique value for each key using a random value */ - get_random_bytes((void *)&rnd, 4); - for (i = 0; i < SPLAT_THREAD_TEST_KEYS; i++) - tsd_set(tp->tp_keys[i], (void *)(i + rnd)); - - /* verify the unique value for each key */ - for (i = 0; i < SPLAT_THREAD_TEST_KEYS; i++) - if (tsd_get(tp->tp_keys[i]) != (void *)(i + rnd)) - rc = -EINVAL; - - /* set the value to thread_priv_t for use by the destructor */ - for (i = 0; i < SPLAT_THREAD_TEST_KEYS; i++) - tsd_set(tp->tp_keys[i], (void *)tp); - - spin_lock(&tp->tp_lock); - if (rc && !tp->tp_rc) - tp->tp_rc = rc; - - tp->tp_count++; - wake_up_all(&tp->tp_waitq); - spin_unlock(&tp->tp_lock); -} - -static void -splat_thread_work3_wait(void *priv) -{ - thread_priv_t *tp = (thread_priv_t *)priv; - - ASSERT(tp->tp_magic == SPLAT_THREAD_TEST_MAGIC); - splat_thread_work3_common(tp); - wait_event(tp->tp_waitq, splat_thread_count(tp, 0)); - thread_exit(); -} - -static void -splat_thread_work3_exit(void *priv) -{ - thread_priv_t *tp = (thread_priv_t *)priv; - - ASSERT(tp->tp_magic == SPLAT_THREAD_TEST_MAGIC); - splat_thread_work3_common(tp); - thread_exit(); -} - -static void -splat_thread_dtor3(void *priv) -{ - thread_priv_t *tp = (thread_priv_t *)priv; - - ASSERT(tp->tp_magic == SPLAT_THREAD_TEST_MAGIC); - spin_lock(&tp->tp_lock); - tp->tp_dtor_count++; - spin_unlock(&tp->tp_lock); -} - -/* - * Create threads which set and verify SPLAT_THREAD_TEST_KEYS number of - * keys. These threads may then exit by calling thread_exit() which calls - * tsd_exit() resulting in all their thread specific data being reclaimed. - * Alternately, the thread may block in which case the thread specific - * data will be reclaimed as part of tsd_destroy(). In either case all - * thread specific data must be reclaimed, this is verified by ensuring - * the registered destructor is called the correct number of times. - */ -static int -splat_thread_test3(struct file *file, void *arg) -{ - int i, rc = 0, expected, wait_count = 0, exit_count = 0; - thread_priv_t tp; - - tp.tp_magic = SPLAT_THREAD_TEST_MAGIC; - tp.tp_file = file; - spin_lock_init(&tp.tp_lock); - init_waitqueue_head(&tp.tp_waitq); - tp.tp_rc = 0; - tp.tp_count = 0; - tp.tp_dtor_count = 0; - - for (i = 0; i < SPLAT_THREAD_TEST_KEYS; i++) { - tp.tp_keys[i] = 0; - tsd_create(&tp.tp_keys[i], splat_thread_dtor3); - } - - /* 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, defclsyspri)) - wait_count++; - } - - /* All wait threads have setup their tsd and are blocking. */ - wait_event(tp.tp_waitq, splat_thread_count(&tp, wait_count)); - - if (tp.tp_dtor_count != 0) { - splat_vprint(file, SPLAT_THREAD_TEST3_NAME, - "Prematurely ran %d tsd destructors\n", tp.tp_dtor_count); - if (!rc) - rc = -ERANGE; - } - - /* 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, defclsyspri)) - exit_count++; - } - - /* All exit threads verified tsd and are in the process of exiting */ - wait_event(tp.tp_waitq,splat_thread_count(&tp, wait_count+exit_count)); - msleep(500); - - expected = (SPLAT_THREAD_TEST_KEYS * exit_count); - if (tp.tp_dtor_count != expected) { - splat_vprint(file, SPLAT_THREAD_TEST3_NAME, - "Expected %d exit tsd destructors but saw %d\n", - expected, tp.tp_dtor_count); - if (!rc) - rc = -ERANGE; - } - - /* Destroy all keys and associated tsd in blocked threads */ - for (i = 0; i < SPLAT_THREAD_TEST_KEYS; i++) - tsd_destroy(&tp.tp_keys[i]); - - expected = (SPLAT_THREAD_TEST_KEYS * (exit_count + wait_count)); - if (tp.tp_dtor_count != expected) { - splat_vprint(file, SPLAT_THREAD_TEST3_NAME, - "Expected %d wait+exit tsd destructors but saw %d\n", - expected, tp.tp_dtor_count); - if (!rc) - rc = -ERANGE; - } - - /* Release the remaining wait threads, sleep briefly while they exit */ - spin_lock(&tp.tp_lock); - tp.tp_count = 0; - wake_up_all(&tp.tp_waitq); - spin_unlock(&tp.tp_lock); - msleep(500); - - if (tp.tp_rc) { - splat_vprint(file, SPLAT_THREAD_TEST3_NAME, - "Thread tsd_get()/tsd_set() error %d\n", tp.tp_rc); - if (!rc) - rc = tp.tp_rc; - } else if (!rc) { - splat_vprint(file, SPLAT_THREAD_TEST3_NAME, "%s", - "Thread specific data verified\n"); - } - - return rc; -} - -splat_subsystem_t * -splat_thread_init(void) -{ - splat_subsystem_t *sub; - - sub = kmalloc(sizeof(*sub), GFP_KERNEL); - if (sub == NULL) - return NULL; - - memset(sub, 0, sizeof(*sub)); - strncpy(sub->desc.name, SPLAT_THREAD_NAME, SPLAT_NAME_SIZE); - strncpy(sub->desc.desc, SPLAT_THREAD_DESC, SPLAT_DESC_SIZE); - INIT_LIST_HEAD(&sub->subsystem_list); - INIT_LIST_HEAD(&sub->test_list); - spin_lock_init(&sub->test_lock); - sub->desc.id = SPLAT_SUBSYSTEM_THREAD; - - splat_test_init(sub, SPLAT_THREAD_TEST1_NAME, SPLAT_THREAD_TEST1_DESC, - SPLAT_THREAD_TEST1_ID, splat_thread_test1); - splat_test_init(sub, SPLAT_THREAD_TEST2_NAME, SPLAT_THREAD_TEST2_DESC, - SPLAT_THREAD_TEST2_ID, splat_thread_test2); - splat_test_init(sub, SPLAT_THREAD_TEST3_NAME, SPLAT_THREAD_TEST3_DESC, - SPLAT_THREAD_TEST3_ID, splat_thread_test3); - - return sub; -} - -void -splat_thread_fini(splat_subsystem_t *sub) -{ - ASSERT(sub); - splat_test_fini(sub, SPLAT_THREAD_TEST3_ID); - splat_test_fini(sub, SPLAT_THREAD_TEST2_ID); - splat_test_fini(sub, SPLAT_THREAD_TEST1_ID); - - kfree(sub); -} - -int -splat_thread_id(void) { - return SPLAT_SUBSYSTEM_THREAD; -} diff --git a/module/splat/splat-time.c b/module/splat/splat-time.c deleted file mode 100644 index a0e261956..000000000 --- a/module/splat/splat-time.c +++ /dev/null @@ -1,119 +0,0 @@ -/* - * 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). - * Written by Brian Behlendorf <[email protected]>. - * UCRL-CODE-235197 - * - * 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/>. - ***************************************************************************** - * Solaris Porting LAyer Tests (SPLAT) Time Tests. - */ - -#include <sys/time.h> -#include <linux/mm_compat.h> -#include <linux/slab.h> -#include "splat-internal.h" - -#define SPLAT_TIME_NAME "time" -#define SPLAT_TIME_DESC "Kernel Time Tests" - -#define SPLAT_TIME_TEST1_ID 0x0801 -#define SPLAT_TIME_TEST1_NAME "time1" -#define SPLAT_TIME_TEST1_DESC "HZ Test" - -#define SPLAT_TIME_TEST2_ID 0x0802 -#define SPLAT_TIME_TEST2_NAME "time2" -#define SPLAT_TIME_TEST2_DESC "Monotonic Test" - -static int -splat_time_test1(struct file *file, void *arg) -{ - int myhz = hz; - splat_vprint(file, SPLAT_TIME_TEST1_NAME, "hz is %d\n", myhz); - return 0; -} - -static int -splat_time_test2(struct file *file, void *arg) -{ - hrtime_t tm1, tm2; - int i; - - tm1 = gethrtime(); - splat_vprint(file, SPLAT_TIME_TEST2_NAME, "time is %lld\n", tm1); - - for(i = 0; i < 100; i++) { - tm2 = gethrtime(); - splat_vprint(file, SPLAT_TIME_TEST2_NAME, "time is %lld\n", tm2); - - if(tm1 > tm2) { - splat_print(file, "%s: gethrtime() is not giving " - "monotonically increasing values\n", - SPLAT_TIME_TEST2_NAME); - return 1; - } - tm1 = tm2; - - set_current_state(TASK_INTERRUPTIBLE); - schedule_timeout(10); - } - - return 0; -} - -splat_subsystem_t * -splat_time_init(void) -{ - splat_subsystem_t *sub; - - sub = kmalloc(sizeof(*sub), GFP_KERNEL); - if (sub == NULL) - return NULL; - - memset(sub, 0, sizeof(*sub)); - strncpy(sub->desc.name, SPLAT_TIME_NAME, SPLAT_NAME_SIZE); - strncpy(sub->desc.desc, SPLAT_TIME_DESC, SPLAT_DESC_SIZE); - INIT_LIST_HEAD(&sub->subsystem_list); - INIT_LIST_HEAD(&sub->test_list); - spin_lock_init(&sub->test_lock); - sub->desc.id = SPLAT_SUBSYSTEM_TIME; - - splat_test_init(sub, SPLAT_TIME_TEST1_NAME, SPLAT_TIME_TEST1_DESC, - SPLAT_TIME_TEST1_ID, splat_time_test1); - splat_test_init(sub, SPLAT_TIME_TEST2_NAME, SPLAT_TIME_TEST2_DESC, - SPLAT_TIME_TEST2_ID, splat_time_test2); - - return sub; -} - -void -splat_time_fini(splat_subsystem_t *sub) -{ - ASSERT(sub); - - splat_test_fini(sub, SPLAT_TIME_TEST2_ID); - splat_test_fini(sub, SPLAT_TIME_TEST1_ID); - - kfree(sub); -} - -int -splat_time_id(void) -{ - return SPLAT_SUBSYSTEM_TIME; -} diff --git a/module/splat/splat-vnode.c b/module/splat/splat-vnode.c deleted file mode 100644 index 4ccf24f1e..000000000 --- a/module/splat/splat-vnode.c +++ /dev/null @@ -1,355 +0,0 @@ -/* - * 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). - * Written by Brian Behlendorf <[email protected]>. - * UCRL-CODE-235197 - * - * 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/>. - ***************************************************************************** - * Solaris Porting LAyer Tests (SPLAT) Vnode Tests. - */ - -#include <sys/vnode.h> -#include "splat-internal.h" - -#define SPLAT_VNODE_NAME "vnode" -#define SPLAT_VNODE_DESC "Kernel Vnode Tests" - -#define SPLAT_VNODE_TEST1_ID 0x0901 -#define SPLAT_VNODE_TEST1_NAME "vn_open" -#define SPLAT_VNODE_TEST1_DESC "Vn_open Test" - -#define SPLAT_VNODE_TEST2_ID 0x0902 -#define SPLAT_VNODE_TEST2_NAME "vn_openat" -#define SPLAT_VNODE_TEST2_DESC "Vn_openat Test" - -#define SPLAT_VNODE_TEST3_ID 0x0903 -#define SPLAT_VNODE_TEST3_NAME "vn_rdwr" -#define SPLAT_VNODE_TEST3_DESC "Vn_rdwrt Test" - -#define SPLAT_VNODE_TEST5_ID 0x0905 -#define SPLAT_VNODE_TEST5_NAME "vn_getattr" -#define SPLAT_VNODE_TEST5_DESC "Vn_getattr Test" - -#define SPLAT_VNODE_TEST6_ID 0x0906 -#define SPLAT_VNODE_TEST6_NAME "vn_sync" -#define SPLAT_VNODE_TEST6_DESC "Vn_sync Test" - -#define SPLAT_VNODE_TEST_FILE "/etc/fstab" -#define SPLAT_VNODE_TEST_FILE_AT "etc/fstab" -#define SPLAT_VNODE_TEST_FILE_RW "/tmp/spl.vnode.tmp" -#define SPLAT_VNODE_TEST_FILE_RW1 "/tmp/spl.vnode.tmp.1" -#define SPLAT_VNODE_TEST_FILE_RW2 "/tmp/spl.vnode.tmp.2" - -static int -splat_vnode_user_cmd(struct file *file, void *arg, - char *name, char *cmd) -{ - char sh_path[] = "/bin/sh"; - char *argv[] = { sh_path, - "-c", - cmd, - NULL }; - char *envp[] = { "HOME=/", - "TERM=linux", - "PATH=/sbin:/usr/sbin:/bin:/usr/bin", - NULL }; - int rc; - - rc = call_usermodehelper(sh_path, argv, envp, UMH_WAIT_PROC); - if (rc) { - splat_vprint(file, name, - "Failed command: %s %s %s (%d)\n", - argv[0], argv[1], cmd, rc); - return -EPERM; - } - - return 0; -} - -static int -splat_vnode_unlink_all(struct file *file, void *arg, char *name) -{ - char *cmds[] = { "rm -f " SPLAT_VNODE_TEST_FILE_RW, - "rm -f " SPLAT_VNODE_TEST_FILE_RW1, - "rm -f " SPLAT_VNODE_TEST_FILE_RW2, - NULL }; - int i = 0, rc = 0; - - while (cmds[i] != NULL) { - if ((rc = splat_vnode_user_cmd(file, arg, name, cmds[i]))) - return rc; - - i++; - } - - return rc; -} - -static int -splat_vnode_test1(struct file *file, void *arg) -{ - vnode_t *vp; - int rc; - - if ((rc = vn_open(SPLAT_VNODE_TEST_FILE, UIO_SYSSPACE, - FREAD, 0644, &vp, 0, 0))) { - splat_vprint(file, SPLAT_VNODE_TEST1_NAME, - "Failed to vn_open test file: %s (%d)\n", - SPLAT_VNODE_TEST_FILE, rc); - return -rc; - } - - rc = VOP_CLOSE(vp, 0, 0, 0, 0, 0); - - if (rc) { - splat_vprint(file, SPLAT_VNODE_TEST1_NAME, - "Failed to vn_close test file: %s (%d)\n", - SPLAT_VNODE_TEST_FILE, rc); - return -rc; - } - - splat_vprint(file, SPLAT_VNODE_TEST1_NAME, "Successfully vn_open'ed " - "and vn_closed test file: %s\n", SPLAT_VNODE_TEST_FILE); - - return -rc; -} /* splat_vnode_test1() */ - -static int -splat_vnode_test2(struct file *file, void *arg) -{ - vnode_t *vp; - int rc; - - if ((rc = vn_openat(SPLAT_VNODE_TEST_FILE_AT, UIO_SYSSPACE, - FREAD, 0644, &vp, 0, 0, rootdir, 0))) { - splat_vprint(file, SPLAT_VNODE_TEST2_NAME, - "Failed to vn_openat test file: %s (%d)\n", - SPLAT_VNODE_TEST_FILE, rc); - return -rc; - } - - rc = VOP_CLOSE(vp, 0, 0, 0, 0, 0); - - if (rc) { - splat_vprint(file, SPLAT_VNODE_TEST2_NAME, - "Failed to vn_close test file: %s (%d)\n", - SPLAT_VNODE_TEST_FILE, rc); - return -rc; - } - - splat_vprint(file, SPLAT_VNODE_TEST2_NAME, "Successfully vn_openat'ed " - "and vn_closed test file: %s\n", SPLAT_VNODE_TEST_FILE); - - return -rc; -} /* splat_vnode_test2() */ - -static int -splat_vnode_test3(struct file *file, void *arg) -{ - vnode_t *vp; - char buf1[32] = "SPL VNode Interface Test File\n"; - char buf2[32] = ""; - int rc; - - if ((rc = splat_vnode_unlink_all(file, arg, SPLAT_VNODE_TEST3_NAME))) - return rc; - - if ((rc = vn_open(SPLAT_VNODE_TEST_FILE_RW, UIO_SYSSPACE, - FWRITE | FREAD | FCREAT | FEXCL, - 0644, &vp, 0, 0))) { - splat_vprint(file, SPLAT_VNODE_TEST3_NAME, - "Failed to vn_open test file: %s (%d)\n", - SPLAT_VNODE_TEST_FILE_RW, rc); - return -rc; - } - - rc = vn_rdwr(UIO_WRITE, vp, buf1, strlen(buf1), 0, - UIO_SYSSPACE, 0, RLIM64_INFINITY, 0, NULL); - if (rc) { - splat_vprint(file, SPLAT_VNODE_TEST3_NAME, - "Failed vn_rdwr write of test file: %s (%d)\n", - SPLAT_VNODE_TEST_FILE_RW, rc); - goto out; - } - - rc = vn_rdwr(UIO_READ, vp, buf2, strlen(buf1), 0, - UIO_SYSSPACE, 0, RLIM64_INFINITY, 0, NULL); - if (rc) { - splat_vprint(file, SPLAT_VNODE_TEST3_NAME, - "Failed vn_rdwr read of test file: %s (%d)\n", - SPLAT_VNODE_TEST_FILE_RW, rc); - goto out; - } - - if (strncmp(buf1, buf2, strlen(buf1))) { - rc = EINVAL; - splat_vprint(file, SPLAT_VNODE_TEST3_NAME, - "Failed strncmp data written does not match " - "data read\nWrote: %sRead: %s\n", buf1, buf2); - goto out; - } - - rc = 0; - splat_vprint(file, SPLAT_VNODE_TEST3_NAME, "Wrote: %s", buf1); - splat_vprint(file, SPLAT_VNODE_TEST3_NAME, "Read: %s", buf2); - splat_vprint(file, SPLAT_VNODE_TEST3_NAME, "Successfully wrote and " - "read expected data pattern to test file: %s\n", - SPLAT_VNODE_TEST_FILE_RW); - -out: - VOP_CLOSE(vp, 0, 0, 0, 0, 0); - - return -rc; -} /* splat_vnode_test3() */ - -static int -splat_vnode_test5(struct file *file, void *arg) -{ - vnode_t *vp; - vattr_t vap; - int rc; - - if ((rc = vn_open(SPLAT_VNODE_TEST_FILE, UIO_SYSSPACE, - FREAD, 0644, &vp, 0, 0))) { - splat_vprint(file, SPLAT_VNODE_TEST5_NAME, - "Failed to vn_open test file: %s (%d)\n", - SPLAT_VNODE_TEST_FILE, rc); - return -rc; - } - - rc = VOP_GETATTR(vp, &vap, 0, 0, NULL); - if (rc) { - splat_vprint(file, SPLAT_VNODE_TEST5_NAME, - "Failed to vn_getattr test file: %s (%d)\n", - SPLAT_VNODE_TEST_FILE, rc); - goto out; - } - - if (vap.va_type != VREG) { - rc = EINVAL; - splat_vprint(file, SPLAT_VNODE_TEST5_NAME, - "Failed expected regular file type " - "(%d != VREG): %s (%d)\n", vap.va_type, - SPLAT_VNODE_TEST_FILE, rc); - goto out; - } - - splat_vprint(file, SPLAT_VNODE_TEST1_NAME, "Successfully " - "vn_getattr'ed test file: %s\n", SPLAT_VNODE_TEST_FILE); - -out: - VOP_CLOSE(vp, 0, 0, 0, 0, 0); - - return -rc; -} /* splat_vnode_test5() */ - -static int -splat_vnode_test6(struct file *file, void *arg) -{ - vnode_t *vp; - char buf[32] = "SPL VNode Interface Test File\n"; - int rc; - - if ((rc = splat_vnode_unlink_all(file, arg, SPLAT_VNODE_TEST6_NAME))) - return rc; - - if ((rc = vn_open(SPLAT_VNODE_TEST_FILE_RW, UIO_SYSSPACE, - FWRITE | FCREAT | FEXCL, 0644, &vp, 0, 0))) { - splat_vprint(file, SPLAT_VNODE_TEST6_NAME, - "Failed to vn_open test file: %s (%d)\n", - SPLAT_VNODE_TEST_FILE_RW, rc); - return -rc; - } - - rc = vn_rdwr(UIO_WRITE, vp, buf, strlen(buf), 0, - UIO_SYSSPACE, 0, RLIM64_INFINITY, 0, NULL); - if (rc) { - splat_vprint(file, SPLAT_VNODE_TEST6_NAME, - "Failed vn_rdwr write of test file: %s (%d)\n", - SPLAT_VNODE_TEST_FILE_RW, rc); - goto out; - } - - rc = vn_fsync(vp, 0, 0, 0); - if (rc) { - splat_vprint(file, SPLAT_VNODE_TEST6_NAME, - "Failed vn_fsync of test file: %s (%d)\n", - SPLAT_VNODE_TEST_FILE_RW, rc); - goto out; - } - - rc = 0; - splat_vprint(file, SPLAT_VNODE_TEST6_NAME, "Successfully " - "fsync'ed test file %s\n", SPLAT_VNODE_TEST_FILE_RW); -out: - VOP_CLOSE(vp, 0, 0, 0, 0, 0); - - return -rc; -} /* splat_vnode_test6() */ - -splat_subsystem_t * -splat_vnode_init(void) -{ - splat_subsystem_t *sub; - - sub = kmalloc(sizeof(*sub), GFP_KERNEL); - if (sub == NULL) - return NULL; - - memset(sub, 0, sizeof(*sub)); - strncpy(sub->desc.name, SPLAT_VNODE_NAME, SPLAT_NAME_SIZE); - strncpy(sub->desc.desc, SPLAT_VNODE_DESC, SPLAT_DESC_SIZE); - INIT_LIST_HEAD(&sub->subsystem_list); - INIT_LIST_HEAD(&sub->test_list); - spin_lock_init(&sub->test_lock); - sub->desc.id = SPLAT_SUBSYSTEM_VNODE; - - splat_test_init(sub, SPLAT_VNODE_TEST1_NAME, SPLAT_VNODE_TEST1_DESC, - SPLAT_VNODE_TEST1_ID, splat_vnode_test1); - splat_test_init(sub, SPLAT_VNODE_TEST2_NAME, SPLAT_VNODE_TEST2_DESC, - 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); - 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, - SPLAT_VNODE_TEST6_ID, splat_vnode_test6); - - return sub; -} /* splat_vnode_init() */ - -void -splat_vnode_fini(splat_subsystem_t *sub) -{ - ASSERT(sub); - - splat_test_fini(sub, SPLAT_VNODE_TEST6_ID); - splat_test_fini(sub, SPLAT_VNODE_TEST5_ID); - splat_test_fini(sub, SPLAT_VNODE_TEST3_ID); - splat_test_fini(sub, SPLAT_VNODE_TEST2_ID); - splat_test_fini(sub, SPLAT_VNODE_TEST1_ID); - - kfree(sub); -} /* splat_vnode_fini() */ - -int -splat_vnode_id(void) -{ - return SPLAT_SUBSYSTEM_VNODE; -} /* splat_vnode_id() */ diff --git a/module/splat/splat-zlib.c b/module/splat/splat-zlib.c deleted file mode 100644 index 28e521c82..000000000 --- a/module/splat/splat-zlib.c +++ /dev/null @@ -1,166 +0,0 @@ -/* - * 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). - * Written by Brian Behlendorf <[email protected]>. - * UCRL-CODE-235197 - * - * 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/>. - ***************************************************************************** - * Solaris Porting LAyer Tests (SPLAT) Zlib Compression Tests. - */ - -#include <sys/zmod.h> -#include <sys/random.h> -#include <sys/kmem.h> -#include <sys/vmem.h> -#include "splat-internal.h" - -#define SPLAT_ZLIB_NAME "zlib" -#define SPLAT_ZLIB_DESC "Zlib Compression Tests" - -#define SPLAT_ZLIB_TEST1_ID 0x0f01 -#define SPLAT_ZLIB_TEST1_NAME "compress/uncompress" -#define SPLAT_ZLIB_TEST1_DESC "Compress/Uncompress Test" - -#define BUFFER_SIZE (128 * 1024) - -static int -splat_zlib_test1_check(struct file *file, void *src, void *dst, void *chk, - int level) -{ - size_t dst_len = BUFFER_SIZE; - size_t chk_len = BUFFER_SIZE; - int rc; - - memset(dst, 0, BUFFER_SIZE); - memset(chk, 0, BUFFER_SIZE); - - rc = z_compress_level(dst, &dst_len, src, BUFFER_SIZE, level); - if (rc != Z_OK) { - splat_vprint(file, SPLAT_ZLIB_TEST1_NAME, - "Failed level %d z_compress_level(), %d\n", level, rc); - return -EINVAL; - } - - rc = z_uncompress(chk, &chk_len, dst, dst_len); - if (rc != Z_OK) { - splat_vprint(file, SPLAT_ZLIB_TEST1_NAME, - "Failed level %d z_uncompress(), %d\n", level, rc); - return -EINVAL; - } - - rc = memcmp(src, chk, BUFFER_SIZE); - if (rc) { - splat_vprint(file, SPLAT_ZLIB_TEST1_NAME, - "Failed level %d memcmp()), %d\n", level, rc); - return -EINVAL; - } - - splat_vprint(file, SPLAT_ZLIB_TEST1_NAME, - "Passed level %d, compressed %d bytes to %d bytes\n", - level, BUFFER_SIZE, (int)dst_len); - - return 0; -} - -/* - * Compress a buffer, uncompress the newly compressed buffer, then - * compare it to the original. Do this for all 9 compression levels. - */ -static int -splat_zlib_test1(struct file *file, void *arg) -{ - void *src = NULL, *dst = NULL, *chk = NULL; - int i, rc, level; - - src = vmalloc(BUFFER_SIZE); - if (src == NULL) { - rc = -ENOMEM; - goto out; - } - - dst = vmalloc(BUFFER_SIZE); - if (dst == NULL) { - rc = -ENOMEM; - goto out; - } - - chk = vmalloc(BUFFER_SIZE); - if (chk == NULL) { - rc = -ENOMEM; - goto out; - } - - /* Source buffer is a repeating 1024 byte random pattern. */ - random_get_pseudo_bytes(src, sizeof(uint8_t) * 1024); - for (i = 1; i < 128; i++) - memcpy(src + (i * 1024), src, 1024); - - for (level = 1; level <= 9; level++) - if ((rc = splat_zlib_test1_check(file, src, dst, chk, level))) - break; -out: - if (src) - vfree(src); - - if (dst) - vfree(dst); - - if (chk) - vfree(chk); - - return rc; -} - -splat_subsystem_t * -splat_zlib_init(void) -{ - splat_subsystem_t *sub; - - sub = kmalloc(sizeof(*sub), GFP_KERNEL); - if (sub == NULL) - return NULL; - - memset(sub, 0, sizeof(*sub)); - strncpy(sub->desc.name, SPLAT_ZLIB_NAME, SPLAT_NAME_SIZE); - strncpy(sub->desc.desc, SPLAT_ZLIB_DESC, SPLAT_DESC_SIZE); - INIT_LIST_HEAD(&sub->subsystem_list); - INIT_LIST_HEAD(&sub->test_list); - spin_lock_init(&sub->test_lock); - sub->desc.id = SPLAT_SUBSYSTEM_ZLIB; - - splat_test_init(sub, SPLAT_ZLIB_TEST1_NAME, SPLAT_ZLIB_TEST1_DESC, - SPLAT_ZLIB_TEST1_ID, splat_zlib_test1); - - return sub; -} - -void -splat_zlib_fini(splat_subsystem_t *sub) -{ - ASSERT(sub); - - splat_test_fini(sub, SPLAT_ZLIB_TEST1_ID); - - kfree(sub); -} - -int -splat_zlib_id(void) { - return SPLAT_SUBSYSTEM_ZLIB; -} |