diff --git a/.travis.yml b/.travis.yml
new file mode 100644
index 0000000000000000000000000000000000000000..916369adbc0393fa6f00a0e341cbac565de1579b
--- /dev/null
+++ b/.travis.yml
@@ -0,0 +1,9 @@
+language: c
+compiler:
+  - clang
+  - gcc
+before_install:
+  - sudo apt-get update -qq
+  - sudo apt-get install -y uuid-dev valgrind
+  - cp src/test/testconfig.sh.example src/test/testconfig.sh
+script: make && make test && make check
diff --git a/LICENSE b/LICENSE
index 0c6a355680d69d2c2c5c88e3508ae0b5bbc68aba..18f3bf75c12a4b14f7280d6719ecd54cb6375b33 100644
--- a/LICENSE
+++ b/LICENSE
@@ -34,3 +34,5 @@ with the following exceptions:
 
 * src/jemalloc has its own (somewhat similar) license contained in
   src/jemalloc/COPYING.
+
+* utils/cstyle (used only during development) licensed under CDDL.
diff --git a/Makefile b/Makefile
new file mode 100644
index 0000000000000000000000000000000000000000..8b613a3606b906e195ecd70080d35309cdd3bd03
--- /dev/null
+++ b/Makefile
@@ -0,0 +1,78 @@
+#
+# Copyright (c) 2014, Intel Corporation
+#
+# Redistribution and use in source and binary forms, with or without
+# modification, are permitted provided that the following conditions
+# are met:
+#
+#     * Redistributions of source code must retain the above copyright
+#       notice, this list of conditions and the following disclaimer.
+#
+#     * Redistributions in binary form must reproduce the above copyright
+#       notice, this list of conditions and the following disclaimer in
+#       the documentation and/or other materials provided with the
+#       distribution.
+#
+#     * Neither the name of Intel Corporation nor the names of its
+#       contributors may be used to endorse or promote products derived
+#       from this software without specific prior written permission.
+#
+# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+#
+# Makefile -- top-level Makefile for NVM Library
+#
+# Use "make" to build the library.
+#
+# Use "make test" to build unit tests.
+#
+# Use "make check" to run unit tests.
+#
+# Use "make clean" to delete all intermediate files (*.o, etc).
+#
+# Use "make clobber" to delete everything re-buildable (binaries, etc.).
+#
+# Use "make cstyle" to run cstyle on all C source files
+#
+# Use "make source DESTDIR=path_to_dir" to copy source files
+# from HEAD to 'path_to_dir/nvml' directory.
+#
+# As root, use "make install" to install the library in the usual
+# locations (/usr/lib, /usr/include, and /usr/share/man).
+# You can provide custom directory prefix for installation using
+# DESTDIR variable e.g.: "make install DESTDIR=/opt"
+
+all clean clobber:
+	$(MAKE) -C src $@
+	$(MAKE) -C examples $@
+	$(MAKE) -C doc $@
+
+test check:
+	$(MAKE) -C src $@
+
+cstyle:
+	$(MAKE) -C src $@
+	$(MAKE) -C examples $@
+
+source:
+	$(if $(shell git rev-parse 2>&1), $(error Not a git repository))
+	$(if $(shell git status --porcelain), $(error Working directory is dirty))
+	$(if $(DESTDIR), , $(error Please provide DESTDIR variable))
+	mkdir -p $(DESTDIR)/nvml
+	git archive HEAD | tar -x -C $(DESTDIR)/nvml
+
+install:
+	$(MAKE) -C src $@
+	$(MAKE) -C doc $@
+
+.PHONY: all clean clobber test check cstyle install source $(SUBDIRS)
diff --git a/README.md b/README.md
index 9648da68163320fa948d0fe481b09fc58740565d..e6bce55501b7f6e6318ca21620feaff912952cbf 100644
--- a/README.md
+++ b/README.md
@@ -1,7 +1,56 @@
-nvml
-====
+nvml: Linux NVM Library
+=======================
 
-NVM Library
+[![Build Status](https://travis-ci.org/pmem/nvml.svg)](https://travis-ci.org/pmem/nvml)
 
+This is the top-level README.md the Linux NVM Library.
+For more information, see http://pmem.io.
 
-**Coming Soon...**
+Please see the file LICENSE for information on how this library is licensed.
+
+This tree contains libaries for using Non-Volatile Memory (NVM).
+Here you'll find:
+
+* **doc** -- man pages describing each library contained here
+* **examples** -- brief example programs using these libraries
+* **src** -- the source for the libraries
+* **utils** -- utilities used during build & test
+* **CONTRIBUTING.md** -- instructions for people wishing to contribute
+
+To build this library, you may need to install some required packages on
+the build system.  See the **before_install:** rules in the
+[.travis.yml](https://github.com/pmem/nvml/blob/master/.travis.yml)
+file at the top level of the repository to get an idea what packages
+were required to build on the _travis-ci_ (Ubuntu-based) systems.
+
+Once the build system is setup, the NVM Library is built using
+this command at the top level:
+```
+	$ make
+```
+
+To build and run the unit tests:
+```
+	$ make check
+```
+
+To install this library into the standard locations
+(/usr/lib, /usr/include, /usr/share/man), become root and:
+```
+	$ make install
+```
+
+To install this library into other locations, you can use
+DESTDIR variable, e.g.:
+```
+	$ make install DESTDIR=/tmp
+```
+This will install files to /tmp/lib, /tmp/include /tmp/usr/share/man.
+
+To install a complete copy of the source tree to $(DESTDIR)/nvml:
+```
+	$ make source DESTDIR=some_path
+```
+
+For more information on this library,
+contact Andy Rudoff (andy.rudoff@intel.com).
diff --git a/benchmarks/.gitignore b/benchmarks/.gitignore
new file mode 100644
index 0000000000000000000000000000000000000000..f47cb2045f130d56b12a40b1ab207bd492281c17
--- /dev/null
+++ b/benchmarks/.gitignore
@@ -0,0 +1 @@
+*.out
diff --git a/benchmarks/Makefile b/benchmarks/Makefile
new file mode 100644
index 0000000000000000000000000000000000000000..72fc6be84ec1f9cf65ffa80a2cccce5af9a458ac
--- /dev/null
+++ b/benchmarks/Makefile
@@ -0,0 +1,48 @@
+#
+# Copyright (c) 2014, Intel Corporation
+#
+# Redistribution and use in source and binary forms, with or without
+# modification, are permitted provided that the following conditions
+# are met:
+#
+#     * Redistributions of source code must retain the above copyright
+#       notice, this list of conditions and the following disclaimer.
+#
+#     * Redistributions in binary form must reproduce the above copyright
+#       notice, this list of conditions and the following disclaimer in
+#       the documentation and/or other materials provided with the
+#       distribution.
+#
+#     * Neither the name of Intel Corporation nor the names of its
+#       contributors may be used to endorse or promote products derived
+#       from this software without specific prior written permission.
+#
+# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+#
+
+#
+# Makefile -- build all benchmarks
+#
+BENCHMARK = mt
+
+all     : TARGET = all
+clean   : TARGET = clean
+clobber : TARGET = clobber
+cstyle  : TARGET = cstyle
+
+all clean clobber cstyle: $(BENCHMARK)
+
+$(BENCHMARK):
+	$(MAKE) -C $@ $(TARGET)
+
+.PHONY: all clean clobber cstyle $(BENCHMARK)
diff --git a/benchmarks/Makefile.inc b/benchmarks/Makefile.inc
new file mode 100644
index 0000000000000000000000000000000000000000..760341ba3472f3a34df9b8824b2fd220606ea692
--- /dev/null
+++ b/benchmarks/Makefile.inc
@@ -0,0 +1,59 @@
+#
+# Copyright (c) 2014, Intel Corporation
+#
+# Redistribution and use in source and binary forms, with or without
+# modification, are permitted provided that the following conditions
+# are met:
+#
+#     * Redistributions of source code must retain the above copyright
+#       notice, this list of conditions and the following disclaimer.
+#
+#     * Redistributions in binary form must reproduce the above copyright
+#       notice, this list of conditions and the following disclaimer in
+#       the documentation and/or other materials provided with the
+#       distribution.
+#
+#     * Neither the name of Intel Corporation nor the names of its
+#       contributors may be used to endorse or promote products derived
+#       from this software without specific prior written permission.
+#
+# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+#
+
+#
+# src/test/Makefile.inc -- common Makefile defs for benchmarks
+#
+
+LIBS =
+INCS =
+DEFS =
+CFLAGS = -ggdb -Wall -Werror -std=gnu99
+
+all: $(TARGET)
+
+$(TARGET): $(OBJS)
+	$(CC) -o $@ $(OBJS) $(LIBS)
+
+%.o: %.c
+	$(CC) -c $(CFLAGS) $(INCS) $(DEFS) $< -o $@
+
+clean:
+	$(RM) *.o */*.o *.out *.png
+
+clobber: clean
+	$(RM) $(TARGET) $(ADD_TARGETS)
+
+cstyle:
+	../../utils/cstyle -pP *.c
+
+.PHONY: all clean clobber cstyle
diff --git a/benchmarks/README b/benchmarks/README
new file mode 100644
index 0000000000000000000000000000000000000000..07d733614a831e6c9a8786d03f22df649e3db7b2
--- /dev/null
+++ b/benchmarks/README
@@ -0,0 +1,12 @@
+Linux NVM Library
+
+This is benchmarks/README.
+
+This directory contains benchmarks for NVM Library.
+
+Benchmarks may be built and run from this directory using:
+	$ make
+	$ make run
+
+The subdirectories here contain benchmarks, which each subdirectory
+containing one benchmark and corresponding scripts.
diff --git a/benchmarks/mt/.gitignore b/benchmarks/mt/.gitignore
new file mode 100644
index 0000000000000000000000000000000000000000..d0ff685ba0f093041501a210eb5da7a97fb4ca1f
--- /dev/null
+++ b/benchmarks/mt/.gitignore
@@ -0,0 +1,3 @@
+benchmark_mt
+benchmark_pool_mt
+*.png
diff --git a/benchmarks/mt/Makefile b/benchmarks/mt/Makefile
new file mode 100644
index 0000000000000000000000000000000000000000..f717084b5dcf237b5a6a62984ec5ff97777d144c
--- /dev/null
+++ b/benchmarks/mt/Makefile
@@ -0,0 +1,47 @@
+#
+# Copyright (c) 2014, Intel Corporation
+#
+# Redistribution and use in source and binary forms, with or without
+# modification, are permitted provided that the following conditions
+# are met:
+#
+#     * Redistributions of source code must retain the above copyright
+#       notice, this list of conditions and the following disclaimer.
+#
+#     * Redistributions in binary form must reproduce the above copyright
+#       notice, this list of conditions and the following disclaimer in
+#       the documentation and/or other materials provided with the
+#       distribution.
+#
+#     * Neither the name of Intel Corporation nor the names of its
+#       contributors may be used to endorse or promote products derived
+#       from this software without specific prior written permission.
+#
+# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+#
+
+#
+# benchmarks/mt/Makefile -- build multi-threading scaling benchmark
+#
+TARGET = benchmark_mt
+VMEM_PATH=../../src/nondebug/
+
+OBJS = mt.o tasks.o
+
+include ../Makefile.inc
+
+LIBS := -Wl,-rpath,$(VMEM_PATH) -L$(VMEM_PATH) -lvmem -lpthread
+INCS := -I../../src/include/ -I.
+
+mt.o: mt.c
+tasks.o: tasks.c tasks.h
diff --git a/benchmarks/mt/README b/benchmarks/mt/README
new file mode 100644
index 0000000000000000000000000000000000000000..00ae12e25db70dcc96549c0f3bfc042e7b3eef53
--- /dev/null
+++ b/benchmarks/mt/README
@@ -0,0 +1,40 @@
+Linux NVM Library
+
+This is benchmarks/mt/README.
+
+This directory contains the multithreaded allocations benchmark.
+
+mt benchmark serves as a comparison tool between any malloc library and libvmem,
+it measures the number of malloc and free operations per second.
+
+Benchmark run can be configured to use certain number of threads to allocate
+given amount of memory.
+
+By default, the makefile builds the application without linking to any
+non-standard malloc libraries.
+
+The application itself requires two arguments: thread count and
+operations count. First, the benchmark performs mallocs in threads, then frees
+the allocated memory. Time spent doing these operations is measured separately.
+By default libvmem is used, to choose different allocator use '-e' option.
+For more informations about the application usage invoke --help ('-?').
+
+In order to compare libvmem against other allocators,
+set LD_PRELOAD environment variable before running the benchmark.
+
+For example, running this command before the benchmark:
+export LD_PRELOAD=$LD_PRELOAD:/path/to/jemalloc/libjemalloc.so
+will allow you to measure the performance of jemalloc.
+
+For convenience, there is a simple RUN.sh script provided that will compare
+libvmem with provided library and generate results charts. To use it simply do:
+./RUN.sh [malloc_library.so]
+
+The results of the benchmark are printed to standard output, use provided
+gnuplot scripts (gnuplot_mt_free.p, gnuplot_mt_malloc.p) to visualize them.
+
+Output format:
+total malloc operations time;malloc operations per second;
+total free operations time;free operations per second;
+
+See the top-level README for instructions on building the entire library.
diff --git a/benchmarks/mt/RUN.sh b/benchmarks/mt/RUN.sh
new file mode 100755
index 0000000000000000000000000000000000000000..a94b2651431827adb332c8bb0bb4221d0bad77f8
--- /dev/null
+++ b/benchmarks/mt/RUN.sh
@@ -0,0 +1,22 @@
+#! /bin/bash
+
+LIB=$1
+MALLOCS_COUNT=10000000
+MAX_THREADS=32
+RUNS=`seq $MAX_THREADS`
+SMALL=512
+VMEM_OUT=benchmark_mt_vmem.out
+MALLOC_OUT=benchmark_mt.out
+
+rm $VMEM_OUT
+for i in $RUNS ; do
+	./benchmark_mt -e vmem -s $SMALL $i $MALLOCS_COUNT >> $VMEM_OUT;
+done
+
+export LD_PRELOAD=$LD_PRELOAD:$LIB
+rm $MALLOC_OUT
+for i in $RUNS ; do
+        ./benchmark_mt -e malloc -s $SMALL $i $MALLOCS_COUNT >> $MALLOC_OUT;
+done
+
+gnuplot *.p
diff --git a/benchmarks/mt/gnuplot_mt_free.p b/benchmarks/mt/gnuplot_mt_free.p
new file mode 100644
index 0000000000000000000000000000000000000000..690ccef074c0a7cadb2740e972246e2626facf6b
--- /dev/null
+++ b/benchmarks/mt/gnuplot_mt_free.p
@@ -0,0 +1,16 @@
+set terminal png size 1000,500
+set output "benchmark_free.png"
+set autoscale
+set datafile separator ';'
+unset log
+unset label
+set grid
+set xtic auto
+set size ratio 0.5
+set ytic auto
+set title "jemalloc library thread scaling"
+set xlabel "Threads"
+set ylabel "Operations per second"
+set key inside right bottom
+plot "benchmark_mt_vmem.out" using ($0+1):4 title "vmem" with linespoints, \
+"benchmark_mt.out" using ($0+1):4 title "free" with linespoints
diff --git a/benchmarks/mt/gnuplot_mt_malloc.p b/benchmarks/mt/gnuplot_mt_malloc.p
new file mode 100644
index 0000000000000000000000000000000000000000..00c0a8265d792c80908f2a0aa31f3e478624661a
--- /dev/null
+++ b/benchmarks/mt/gnuplot_mt_malloc.p
@@ -0,0 +1,16 @@
+set terminal png size 1000,500
+set output "benchmark_malloc.png"
+set autoscale
+set datafile separator ';'
+unset log
+unset label
+set grid
+set xtic auto
+set size ratio 0.5
+set ytic auto
+set title "jemalloc library thread scaling"
+set xlabel "Threads"
+set ylabel "Operations per second"
+set key inside right bottom
+plot "benchmark_mt_vmem.out" using ($0+1):2 title "vmem" with linespoints, \
+"benchmark_mt.out" using ($0+1):2 title "malloc" with linespoints
diff --git a/benchmarks/mt/mt.c b/benchmarks/mt/mt.c
new file mode 100644
index 0000000000000000000000000000000000000000..fff66a104ff3aed04a9af2345ef99460df4f9221
--- /dev/null
+++ b/benchmarks/mt/mt.c
@@ -0,0 +1,301 @@
+/*
+ * Copyright (c) 2014, Intel Corporation
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ *     * Redistributions of source code must retain the above copyright
+ *       notice, this list of conditions and the following disclaimer.
+ *
+ *     * Redistributions in binary form must reproduce the above copyright
+ *       notice, this list of conditions and the following disclaimer in
+ *       the documentation and/or other materials provided with the
+ *       distribution.
+ *
+ *     * Neither the name of Intel Corporation nor the names of its
+ *       contributors may be used to endorse or promote products derived
+ *       from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY LOG OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+/*
+ * mt.c -- multi-threaded malloc benchmark
+ */
+
+#include <stdio.h>
+#include <stdint.h>
+#include <ctype.h>
+#include <string.h>
+#include <argp.h>
+#include "tasks.h"
+
+#define	MAX_THREADS 8
+#define	DEF_ALLOC 512
+#define	KB 1024
+#define	MB 1024 * KB
+
+void **allocated_mem;
+
+const char *argp_program_version = "mt_benchmark 1.2";
+static char doc[] = "Multithreaded allocator benchmark";
+static char args_doc[] = "THREAD_COUNT OPS_COUNT";
+
+static struct argp_option options[] = {
+	{"pool-per-thread",	'p', 0,	0,
+		"Create a pool for each worker thread"},
+	{"seed",		'r', "SEED", 0,
+		"Seed for random size allocator"},
+	{"size",		's', "SIZE", 0,	"Allocation size in bytes "
+		"(default: 512b); single number for static allocator;"
+		" comma separated min and max allocation size for ranged"},
+	{"allocator",		'e', "NAME", 0, "Allocator to benchmark\n"
+		"Valid arguments: vmem (default), malloc"},
+	{ 0 }
+};
+
+#define	ALLOCATOR_NAME_MAX_LEN	10
+static const char *allocator_names[] = {"vmem", "malloc"};
+
+task_f tasks[MAX_TASK] = {
+	task_malloc,
+	task_free
+};
+
+/*
+ * parse_range -- parses allocation size provided by user and sets apropriate
+ * fields in arguments_t structure
+ *
+ * Syntax of input:
+ * - ALLOCATION_STATIC: <number>
+ * - ALLOCATION_RANGE:  <number,number>
+ */
+int
+parse_range(arguments_t *arguments, char *allocation_size)
+{
+	char *endptr;
+
+	int size_param;
+
+	char *size = strtok(allocation_size, ",");
+	if (size == NULL)
+		return FAILURE;
+
+	size_param = strtol(size, &endptr, 10);
+	if (*endptr != 0) {
+		return FAILURE;
+	}
+
+	size = strtok(NULL, ",");
+	if (size == NULL) {
+		arguments->allocation_size_max = size_param;
+		arguments->allocation_type = ALLOCATION_STATIC;
+	} else {
+		arguments->allocation_size = size_param;
+		arguments->allocation_type = ALLOCATION_RANGE;
+
+		arguments->allocation_size_max = strtol(size, &endptr, 10);
+		size_param = strtol(size, &endptr, 10);
+		if (*endptr != 0) {
+			return FAILURE;
+		}
+
+		if (size_param < arguments->allocation_size) {
+			fprintf(stderr,
+				"Range param: min > max!\n");
+			return FAILURE;
+		} else {
+			arguments->allocation_size_max = size_param;
+		}
+	}
+
+	return SUCCESS;
+}
+
+char *allocation_size_str = NULL;
+
+/*
+ * parse_opt -- argp parsing function
+ */
+static error_t
+parse_opt(int key, char *arg, struct argp_state *state)
+{
+	arguments_t *arguments = state->input;
+	char *endptr;
+	int i;
+
+	switch (key) {
+	case 'p':
+		arguments->pool_per_thread = 1;
+		break;
+	case 's':
+		allocation_size_str = arg;
+		break;
+	case 'r':
+		arguments->seed = strtol(arg, &endptr, 10);
+		if (*endptr != 0) {
+			fprintf(stderr,
+				"Invalid seed count: %s\n",
+				endptr);
+			argp_usage(state);
+			return EXIT_FAILURE;
+		}
+		break;
+	case 'e':
+		for (i = 0; i < MAX_ALLOCATOR; ++i) {
+			if (strncmp(arg, allocator_names[i],
+				ALLOCATOR_NAME_MAX_LEN) == 0) {
+				arguments->allocator = i;
+				break;
+			}
+		}
+		allocator = arguments->allocator;
+		if (i == MAX_ALLOCATOR) {
+			fprintf(stderr,
+				"Unknown allocator %s, using default\n",
+				arg);
+		}
+		break;
+	case ARGP_KEY_ARG:
+		switch (state->arg_num) {
+		case 0:
+			arguments->thread_count = strtol(arg, &endptr, 10);
+			if (*endptr != 0) {
+				fprintf(stderr,
+					"Invalid thread count: %s\n",
+					endptr);
+				argp_usage(state);
+				return EXIT_FAILURE;
+			}
+			break;
+		case 1:
+			arguments->ops_count = strtol(arg, &endptr, 10);
+			if (*endptr != 0) {
+				fprintf(stderr,
+					"Invalid operation count: %s\n",
+					endptr);
+				argp_usage(state);
+				return EXIT_FAILURE;
+			}
+			break;
+		default:
+			argp_usage(state);
+			return ARGP_ERR_UNKNOWN;
+		}
+		break;
+	case ARGP_KEY_END:
+		if (state->arg_num < 2)
+			argp_usage(state);
+
+			if (allocation_size_str == NULL ||
+				parse_range(arguments, allocation_size_str)
+				== FAILURE) {
+				arguments->allocation_size_max = DEF_ALLOC;
+				arguments->allocation_type = ALLOCATION_STATIC;
+			}
+		break;
+	default:
+		return ARGP_ERR_UNKNOWN;
+	}
+
+	return 0;
+}
+
+static struct argp argp = { options, parse_opt, args_doc, doc };
+
+/*
+ * main -- entry point, initializes allocated_mem and runs the tasks
+ */
+int
+main(int argc, char *argv[])
+{
+	int i, fails = 0;
+	double task_duration;
+	void **arg = NULL;
+	uint64_t pool_size;
+	arguments_t arguments;
+	int per_thread_args = 0;
+	arguments.pool_per_thread = 0;
+	arguments.allocator = ALLOCATOR_VMEM;
+	argp_parse(&argp, argc, argv, 0, 0, &arguments);
+	int pools_count = arguments.pool_per_thread ?
+			arguments.thread_count : 1;
+	VMEM *pools[pools_count];
+	void *pools_data[pools_count];
+	allocated_mem = calloc(arguments.ops_count, sizeof (void*));
+
+	if (arguments.allocator == ALLOCATOR_VMEM) {
+		if (arguments.pool_per_thread &&
+			arguments.thread_count > MAX_THREADS) {
+			fprintf(stderr, "Maximum allowed thread count"
+				" with pool per thread option enabled is %u\n",
+				MAX_THREADS);
+			return EXIT_FAILURE;
+		}
+
+		pools_count = arguments.pool_per_thread ?
+			arguments.thread_count : 1;
+		per_thread_args = arguments.pool_per_thread;
+		pool_size = arguments.ops_count *
+			arguments.allocation_size_max * 2u;
+
+		pool_size /= pools_count;
+
+		if (pool_size < 160 * MB) {
+			pool_size = 160 * MB;
+		}
+
+		for (i = 0; i < pools_count; ++i) {
+			pools_data[i] = malloc(pool_size);
+			if (pools_data[i] == NULL) {
+				free(allocated_mem);
+				fprintf(stderr,
+					"Cannot allocate memory for pool\n");
+				return EXIT_FAILURE;
+			}
+			pools[i] = vmem_pool_create_in_region(pools_data[i],
+					pool_size);
+			if (pools[i] == NULL) {
+				fprintf(stderr, "Cannot create vmem pool\n");
+			}
+		}
+		arg = (void **)pools;
+	}
+
+	/* Cache warmup. */
+	for (i = 0; i < MAX_TASK; ++i) {
+		fails += run_threads(&arguments, tasks[i],
+			per_thread_args, arg, &task_duration);
+	}
+
+	for (i = 0; i < MAX_TASK; ++i) {
+		fails += run_threads(&arguments, tasks[i],
+			per_thread_args, arg, &task_duration);
+		printf("%f;%f;",
+			task_duration, arguments.ops_count/task_duration);
+	}
+
+	printf("\n");
+
+	if (arguments.allocator == ALLOCATOR_VMEM) {
+		for (i = 0; i < pools_count; ++i) {
+			vmem_pool_delete(pools[i]);
+			free(pools_data[i]);
+		}
+	}
+
+	free(allocated_mem);
+
+	return (fails == 0) ? EXIT_SUCCESS : EXIT_FAILURE;
+}
diff --git a/benchmarks/mt/tasks.c b/benchmarks/mt/tasks.c
new file mode 100644
index 0000000000000000000000000000000000000000..c73846f899cf291a8d766cef01016e67cf6b42a5
--- /dev/null
+++ b/benchmarks/mt/tasks.c
@@ -0,0 +1,157 @@
+#include <tasks.h>
+#include <pthread.h>
+#include <sys/time.h>
+
+#define	USEC_IN_SEC 1000000.0
+
+struct task_def {
+	int start;
+	int end;
+	task_f task;
+	int result;
+	void *arg;
+	struct random_data *rand_state;
+};
+
+static allocation_type_t allocation_type;
+static int allocation_min;
+static int allocation_max;
+allocator_t allocator;
+
+/*
+ * do_task -- thread start routine,
+ * performs task_f on values between start and end.
+ */
+void *
+do_task(void *arg)
+{
+	struct task_def *t_def = arg;
+	int i;
+
+	for (i = t_def->start; i < t_def->end; ++i) {
+		t_def->result = t_def->task(i, t_def->arg, t_def->rand_state);
+	}
+
+	return NULL;
+}
+
+/*
+ * run_threads -- performs runs number of tasks on threads
+ */
+int
+run_threads(arguments_t *arguments, task_f task, int per_thread_arg, void **arg,
+	double *elapsed)
+{
+	int i, n, ret = 0;
+	pthread_t threads[arguments->thread_count];
+	struct task_def t_def[arguments->thread_count];
+	char *random_statebuf;
+	struct timeval task_start, task_stop;
+
+	allocation_type = arguments->allocation_type;
+	allocation_min = arguments->allocation_size;
+	allocation_max = arguments->allocation_size_max;
+
+	random_statebuf = (char *)calloc(arguments->thread_count, 32);
+
+	n = arguments->ops_count / arguments->thread_count;
+	gettimeofday(&task_start, NULL);
+
+	for (i = 0; i < arguments->thread_count; ++i) {
+		t_def[i].start = i * n;
+		t_def[i].end = n + i * n;
+		t_def[i].task = task;
+		t_def[i].rand_state =
+			(struct random_data *)
+			calloc(1, sizeof (struct random_data));
+
+		initstate_r(arguments->seed,
+			&random_statebuf[i], 32, t_def[i].rand_state);
+
+		if (per_thread_arg) {
+			t_def[i].arg = arg == NULL ? NULL : arg[i];
+		} else {
+			t_def[i].arg = arg == NULL ? NULL : arg[0];
+		}
+		if (pthread_create(&threads[i], NULL, do_task, &t_def[i]) < 0) {
+			return FAILURE;
+		}
+	}
+
+	for (i = 0; i < arguments->thread_count; ++i) {
+		pthread_join(threads[i], NULL);
+		if (t_def[i].result == FAILURE) {
+			ret++;
+		}
+	}
+
+	gettimeofday(&task_stop, NULL);
+
+	free(random_statebuf);
+	for (i = 0; i < arguments->thread_count; ++i) {
+		free(t_def[i].rand_state);
+	}
+
+	if (elapsed != NULL) {
+		*elapsed = (task_stop.tv_sec - task_start.tv_sec) +
+				((task_stop.tv_usec - task_start.tv_usec) /
+				USEC_IN_SEC);
+	}
+
+	return ret;
+}
+
+/*
+ * task_malloc -- allocates MALLOC_SIZE memory in allocated_mem array
+ */
+int
+task_malloc(int i, void *arg, struct random_data *rand_state)
+{
+	int size_to_alloc;
+	int random_number;
+
+	switch (allocation_type) {
+	case ALLOCATION_STATIC:
+		size_to_alloc = allocation_max;
+		break;
+
+	case ALLOCATION_RANGE:
+		random_r(rand_state, &random_number);
+		size_to_alloc =  random_number %
+			(allocation_max - allocation_min)
+			+ allocation_min;
+		break;
+
+	case ALLOCATION_UNKNOWN:
+		break;
+	}
+
+	if (allocator == ALLOCATOR_VMEM) {
+		VMEM *pool = arg;
+		allocated_mem[i] = vmem_malloc(pool, size_to_alloc);
+	} else {
+		allocated_mem[i] = malloc(size_to_alloc);
+	}
+
+	if (allocated_mem[i] == NULL) {
+		return FAILURE;
+	}
+	return SUCCESS;
+}
+
+/*
+ * task_free -- frees memory located in allocated_mem
+ */
+int
+task_free(int i, void *arg, struct random_data *rand_state)
+{
+	if (allocated_mem[i] != NULL) {
+		if (allocator == ALLOCATOR_VMEM) {
+			VMEM *pool = arg;
+			vmem_free(pool, allocated_mem[i]);
+		} else {
+			free(allocated_mem[i]);
+		}
+	}
+	return SUCCESS;
+}
diff --git a/benchmarks/mt/tasks.h b/benchmarks/mt/tasks.h
new file mode 100644
index 0000000000000000000000000000000000000000..2ae3fe379394fbf4dfe9364c4a495c602045f25e
--- /dev/null
+++ b/benchmarks/mt/tasks.h
@@ -0,0 +1,59 @@
+#ifndef TASKS_H
+#define TASKS_H
+
+#include <stdlib.h>
+#include <inttypes.h>
+#include <libvmem.h>
+
+#define	SUCCESS 0
+#define	FAILURE -1
+
+typedef enum allocator_e {
+	ALLOCATOR_VMEM,
+	ALLOCATOR_MALLOC,
+	MAX_ALLOCATOR
+} allocator_t;
+
+typedef enum allocation_type_e {
+	ALLOCATION_UNKNOWN,
+	ALLOCATION_STATIC,
+	ALLOCATION_RANGE
+} allocation_type_t;
+
+typedef struct arguments_s
+{
+	int thread_count;
+	int pool_per_thread;
+	uint64_t ops_count;
+	uint seed;
+	uint allocation_size;
+	uint allocation_size_max;
+	allocation_type_t allocation_type;
+	allocator_t allocator;
+} arguments_t;
+
+typedef int (*task_f)(int, void *arg, struct random_data* rand_state);
+
+enum {
+	TASK_MALLOC,
+	TASK_FREE,
+	MAX_TASK
+};
+
+int task_malloc(int i, void *arg, struct random_data* rand_state);
+int task_free(int i, void *arg, struct random_data* rand_state);
+
+extern task_f tasks[MAX_TASK];
+
+extern int allocation_range_min;
+extern int allocation_range_max;
+extern allocator_t allocator;
+
+extern void **allocated_mem;
+
+extern const int allocation_sizes[];
+
+int run_threads(arguments_t *arguments, task_f task,
+	int per_thread_arg, void **arg, double *elapsed);
+
+#endif // TASKS_H
diff --git a/doc/.gitignore b/doc/.gitignore
new file mode 100644
index 0000000000000000000000000000000000000000..76eaea317ef0b3778a09cb131de3bf9550b4f476
--- /dev/null
+++ b/doc/.gitignore
@@ -0,0 +1,3 @@
+*.txt
+*.html
+*.gz
diff --git a/doc/Makefile b/doc/Makefile
new file mode 100644
index 0000000000000000000000000000000000000000..39ecdd61514564c03e277393b919c3d8d4146647
--- /dev/null
+++ b/doc/Makefile
@@ -0,0 +1,66 @@
+#
+# Copyright (c) 2014, Intel Corporation
+#
+# Redistribution and use in source and binary forms, with or without
+# modification, are permitted provided that the following conditions
+# are met:
+#
+#     * Redistributions of source code must retain the above copyright
+#       notice, this list of conditions and the following disclaimer.
+#
+#     * Redistributions in binary form must reproduce the above copyright
+#       notice, this list of conditions and the following disclaimer in
+#       the documentation and/or other materials provided with the
+#       distribution.
+#
+#     * Neither the name of Intel Corporation nor the names of its
+#       contributors may be used to endorse or promote products derived
+#       from this software without specific prior written permission.
+#
+# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+#
+
+#
+# doc/Makefile -- Makefile for NVM library man pages
+#
+MANPAGES = libpmem.3 libvmem.3
+TXTFILES = $(MANPAGES:=.txt)
+HTMLFILES = $(MANPAGES:=.html)
+GZFILES = $(MANPAGES:=.gz)
+MANPAGES_DESTDIR = $(DESTDIR)/usr/share/man/man3
+
+all: $(TXTFILES)
+
+%.3.txt: %.3
+	man ./$< > $@
+
+html: $(HTMLFILES)
+
+%.3.html: %.3
+	groff -mandoc -Thtml ./$< > $@
+
+compress: $(GZFILES)
+
+%.3.gz: %.3
+	gzip -c ./$< > $@
+
+clean:
+
+clobber: clean
+	$(RM) -f $(TXTFILES) $(HTMLFILES) $(GZFILES)
+
+install: compress
+	install -d $(MANPAGES_DESTDIR)
+	install -p -m 0644 $(GZFILES) $(MANPAGES_DESTDIR)
+
+.PHONY: all html clean compress clobber cstyle install
diff --git a/doc/README b/doc/README
new file mode 100644
index 0000000000000000000000000000000000000000..b345c5ce72173068bb3303a25ccf4fc94bd1d0ad
--- /dev/null
+++ b/doc/README
@@ -0,0 +1,20 @@
+Linux NVM Library
+
+This is doc/README.
+
+This directory contains the man pages for the NVM Library:
+
+libpmem.3 -- libpmem(3) - persistent memory library
+libvmem.3 -- libvmem(3) - volatile memory allocation library
+
+These man pages provide the API specification for the corresponding
+libraries in this source tree, so any updates to one should be tested,
+reviewed, and committed with changes to the other.
+
+To create more readable text files from the source, use:
+	$ make
+An even more convenient way to read these is to use the "man"
+command to format them (includes bold, underline, etc. when
+run in a terminal window):
+	$ man -l libpmem.3
+	$ man -l libvmem.3
diff --git a/doc/libpmem.3 b/doc/libpmem.3
new file mode 100644
index 0000000000000000000000000000000000000000..667fd769af128db090fa264ba32cb9fdddaa5a67
--- /dev/null
+++ b/doc/libpmem.3
@@ -0,0 +1,1216 @@
+.\"
+.\" Copyright (c) 2014, Intel Corporation
+.\"
+.\" Redistribution and use in source and binary forms, with or without
+.\" modification, are permitted provided that the following conditions
+.\" are met:
+.\"
+.\"     * Redistributions of source code must retain the above copyright
+.\"       notice, this list of conditions and the following disclaimer.
+.\"
+.\"     * Redistributions in binary form must reproduce the above copyright
+.\"       notice, this list of conditions and the following disclaimer in
+.\"       the documentation and/or other materials provided with the
+.\"       distribution.
+.\"
+.\"     * Neither the name of Intel Corporation nor the names of its
+.\"       contributors may be used to endorse or promote products derived
+.\"       from this software without specific prior written permission.
+.\"
+.\" THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+.\" "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+.\" LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+.\" A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+.\" OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+.\" SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+.\" LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+.\" DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+.\" THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+.\" (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+.\" OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+.\"
+.\"
+.\" libpmem.3 -- man page for libpmem
+.\"
+.\" Format this man page with:
+.\"	man -l libpmem.3
+.\" or
+.\"	groff -man -Tascii libpmem.3
+.\"
+.TH libpmem 3 "pmem API version 0.48" "NVM Library"
+.SH NAME
+libpmem \- persistent memory library
+.SH SYNOPSIS
+.nf
+.B #include <libpmem.h>
+.sp
+.B cc ... -lpmem
+.sp
+.B Flush-to-persistence support:
+.sp
+.BI "int pmem_is_pmem(void *" addr ", size_t " len );
+.BI "void pmem_persist(void *" addr ", size_t " len ", int " flags );
+.BI "void pmem_flush(void *" addr ", size_t " len ", int " flags );
+.BI "void pmem_fence(void);"
+.BI "void pmem_drain(void);"
+.sp
+.B Support for Persistent Memory Transactions:
+.sp
+.BI "PMEMtrn *pmemtrn_map(int " fd );
+.BI "void pmemtrn_unmap(PMEMtrn *" ptp );
+.B XXX REST OF TRANSACTION SECTION NOT READY FOR REVIEW
+.sp
+.B Support for Atomic Arrays:
+.sp
+.BI "PMEMblk *pmemblk_map(int " fd ", size_t " bsize );
+.BI "void pmemblk_unmap(PMEMblk *" pbp );
+.BI "size_t pmemblk_nblock(PMEMblk *" pbp );
+.BI "int pmemblk_read(PMEMblk *" pbp ", void *" buf ", off_t " blockno );
+.BI "int pmemblk_write(PMEMblk *" pbp ", const void *" buf ", off_t " blockno );
+.BI "int pmemblk_set_zero(PMEMblk *" pbp ", off_t " blockno );
+.BI "int pmemblk_set_error(PMEMblk *" pbp ", off_t " blockno );
+.sp
+.B Support for Persistent Memory Logs:
+.sp
+.BI "PMEMlog *pmemlog_map(int " fd );
+.BI "void pmemlog_unmap(PMEMlog *" plp );
+.BI "size_t pmemlog_nbyte(PMEMlog *" plp );
+.BI "int pmemlog_append(PMEMlog *" plp ", const void *" buf ", size_t " count );
+.BI "int pmemlog_appendv(PMEMlog *" plp ", const struct iovec *" iov ", int " iovcnt );
+.BI "off_t pmemlog_tell(PMEMlog *" plp );
+.BI "void pmemlog_rewind(PMEMlog *" plp );
+.BI "void pmemlog_walk(PMEMlog *" plp ", size_t " chunksize ,
+.BI "           int (*" process_chunk ")(const void *" buf ", size_t " len ", void *" arg ),
+.BI "           void *" arg );
+.sp
+.B Managing overall library behavior:
+.sp
+.BI "const char *pmem_check_version("
+.BI "           unsigned " major_required ,
+.BI "           unsigned " minor_required );
+.BI "void pmem_set_funcs("
+.BI "           void *(*" malloc_func ")(size_t " size ),
+.BI "           void (*" free_func ")(void *" ptr ),
+.BI "           void *(*" realloc_func ")(void *" ptr ", size_t " size ),
+.BI "           char *(*" strdup_func ")(const char *" s ),
+.BI "           void (*" print_func ")(const char *" s ),
+.BI "           void (*" persist_func ")(void *" addr ", size_t " len" , int " flags ));
+.BI "int pmemtrn_check(const char *" path );
+.BI "int pmemblk_check(const char *" path );
+.BI "int pmemlog_check(const char *" path );
+.fi
+.sp
+.SH DESCRIPTION
+.PP
+.B libpmem
+provides several
+interfaces to persistent memory pools built on memory-mapped files.
+The interfaces are divided into categories, each described in a section
+below.
+All the interfaces may be used concurrently, however memory from
+different memory pools must not be mixed.  For example, memory allocated
+from a transactional memory pool created with
+.BR pmemtrn_map ()
+must not be freed to any other memory pool.
+.PP
+.B libpmem
+uses the
+.BR mmap (2)
+system call to access memory pools.  The library
+is most useful when used with
+.I Direct Access
+storage (DAX), which is memory-addressable persistent storage
+that supports load/store access without being paged via the system page cache.
+A Persistent Memory-aware file system is typically used to provide this
+type of access.  Memory-mapping a file from a Persistent
+Memory-aware file system provides the raw memory pools, and this library
+supplies additional semantics like
+.I transactions
+on top of those pools.
+.PP
+Under normal usage,
+.B libpmem
+will never print messages or intentionally cause the process to exit.
+The only exception to this is the debugging information, when enabled, as
+described under
+.B DEBUGGING
+below.
+The library uses
+.BR pthreads (7)
+to be fully MT-safe, but never creates or destroys threads itself.
+The library does not make use of any signals, networking, and
+never calls
+.BR select ()
+or
+.BR poll ().
+The system memory allocation routines like
+.BR malloc ()
+and
+.BR free ()
+are used by
+.B libpmem
+for managing a small amount of run-time state, but applications
+are allowed to override these calls if necessary (see the description
+of
+.BR pmem_set_funcs ()
+below).
+.SH FLUSH-TO-PERSISTENCE
+.PP
+These interfaces are meant for fairly raw access to persistent
+memory, where a persistent memory file has been memory mapped (see
+.BR mmap (2))
+and the application takes on full responsibility to storing data to
+the mapped area and flushing those stores to make them persistent.
+Traditionally, forcing memory mapped changes to persistence is done
+using
+.BR msync (2),
+and that will work as expected with Persistent Memory as well.
+However, platforms may have more optimal ways to flush changes
+in a range of memory.  These functions are provided
+for the case where a range is known to be true Persistent Memory
+(not paged from storage).
+.PP
+.BI "int pmem_is_pmem(void *" addr ", size_t " len );
+.IP
+The
+.BR pmem_is_pmem ()
+function returns true only if the entire range
+.IR "" [ addr ", " addr + len )
+consists entirely of Persistent Memory.  A true return from
+.BR pmem_is_pmem ()
+means it is safe to use
+.BR pmem_persist ()
+and the related functions below to make changes durable for that
+memory range.
+.IP
+The implementation of
+.BR pmem_is_pmem ()
+requires a non-trivial amount of work to determine if the given range
+is entirely Persistent Memory.  For this reason, it is better to call
+.BR pmem_is_pmem ()
+once when a range of memory is first encountered, save the result, and
+use the saved result to determine whether
+.BR pmem_persist ()
+or
+.BR msync (2)
+is called when flushing changes to persistence.  Calling
+.BR pmem_is_pmem ()
+each time changes are flushed to persistence will not perform well.
+.IP
+WARNING: Using
+.BR pmem_persist ()
+on a range where
+.BR pmem_is_pmem ()
+returns false may not do anything useful -- use
+.BR msync (2)
+instead.
+.PP
+.BI "void pmem_persist(void *" addr ", size_t " len ", int " flags );
+.IP
+Force any changes in the range
+.IR "" [ addr ", " addr + len )
+to be stored
+durably in Persistent Memory.  This is equivalent to calling
+.BR msync (2)
+as described above, but may be more optimal and will
+avoid calling into the kernel if possible.
+There are no alignment restrictions on
+the range described by
+.I addr
+and
+.IR len ,
+but
+.BR pmem_persist ()
+may expand the range as necessary
+to meet platform alignment requirements.
+Zero should be passed in for
+.I flags
+since no flags have been defined for this call yet.
+.IP
+WARNING: Like
+.BR msync (2),
+there is nothing
+atomic or transactional about this call.  Any
+unwritten stores in the given range will be written,
+but some stores may have already been written by
+virtue of normal cache eviction/replacement policies.
+Correctly written code must not depend on stores
+waiting until
+.BR pmem_persist ()
+is called to become
+persistent -- they can become persistent at any time
+before
+.BR pmem_persist ()
+is called.
+.PP
+.nf
+.BI "void pmem_flush(void *" addr ", size_t " len ", int " flags );
+.BI "void pmem_fence(void);"
+.BI "void pmem_drain(void);"
+.fi
+.IP
+These three functions provide partial versions of the
+.BR pmem_persist ()
+function described above.
+.BR pmem_persist ()
+can be thought of as this:
+.IP
+.nf
+void pmem_persist(void *addr, size_t len, int flags)
+{
+    /* flush the processor caches */
+    pmem_flush(addr, len, flags);
+
+    /* Persistent Memory store barrier */
+    pmem_fence();
+
+    /* wait for any PM stores to drain from HW buffers */
+    pmem_drain();
+}
+.fi
+.IP
+These functions allow advanced programs to create their
+own variations of
+.BR pmem_persist ().
+For example, a program
+that needs to flush several discontiguous ranges can call
+.BR pmem_flush ()
+for each range and then follow up by
+calling the
+.BR pmem_fence ()
+and
+.BR pmem_drain ()
+once.
+.SH PERSISTENT MEMORY TRANSACTIONS
+.PP
+To use the transactions supplied by
+.BR libpmem ,
+a
+.I memory pool
+is first created.  This is done with the
+.BR pmemtrn_map ()
+function described in this section.
+The other functions
+described in this section then operate on the transaction-based
+memory pool.
+.PP
+Once created, the memory pool is represented by an opaque handle,
+of type
+.IR "PMEMtrn *" ,
+which is passed to most of the other functions in this section.
+Internally,
+.B libpmem
+will use either
+.B pmem_persist ()
+or
+.B msync (2)
+when it needs to flush changes, depending on whether
+the memory pool appears to be Persistent Memory or a regular file
+(see
+.BR pmem_is_pmem ()
+above for more information).
+There is no need for applications to flush changes directly
+when using the transactional memory API described in this section.
+.PP
+.BI "PMEMtrn *pmemtrn_map(int " fd );
+.IP
+The
+.BR pmemtrn_map ()
+function maps a transactional memory pool into memory, creating
+a new pool in the file referenced by
+.I fd
+if an existing pool is not found.
+.BR pmemtrn_map ()
+returns a memory
+pool handle used with most of the functions in this section.
+.I fd
+must be a file descriptor for a file opened for both reading and writing,
+and the file size must already be set appropriately
+(for example, by calling
+.BR posix_fallocate ()
+the first time the file is used).
+.BR pmemtrn_map ()
+will map the file using
+.BR mmap (2),
+and detect if the file already contains a
+.B libpmem
+memory pool from an earlier use of the file with
+.BR pmemtrn_map ().
+If a memory pool is not found, a new pool is created,
+overwriting any data contained in the file.
+The minimum
+file size allowed by the library for a transactional memory
+pool is defined in
+.B <libpmem.h>
+as
+.BR PMEMTRN_MIN_POOL .
+After
+.BR pmemtrn_map ()
+returns the memory pool handle, the file descriptor
+.I fd
+may be closed by the caller without impacting the use
+of
+.B libpmem
+on the memory pool.
+.BR pmemtrn_map ()
+returns NULL on error, setting errno appropriately.
+It is an error to use
+.BR pmemtrn_map ()
+on a file with a different type of memory pool in it.  The library
+will return EINVAL for this case.  To switch the type of memory pool
+in a file, it is best to delete the file and recreate it.
+.IP
+Each time a transactional memory pool is mapped using
+.BR pmemtrn_map (),
+a brief consistency check is performed, similar to the check done by
+.BR pmemtrn_check ()
+described below, but less extensive.  If a consistency issue is
+discovered, the severity of the pool corruption is evaluated to
+determine if read-only access is still viable.  If so,
+.BR pmemtrn_map ()
+succeeds but any subsequent calls to change the pool will
+return the error EROFS.  If the memory pool is not viable
+for read-only access,
+.BR pmemtrn_map ()
+will return the error EINVAL.  In either case, see
+.BR pmemtrn_check ()
+below for a description of how to determine the details of the
+memory pool corruption.
+.PP
+.BI "void pmemtrn_unmap(PMEMtrn *" ptp );
+.IP
+The
+.BR pmemtrn_unmap ()
+function unmaps the memory pool indicated by
+.I ptp
+and deletes the memory pool handle.  The transactional memory pool
+itself lives on in the file that contains it and may be re-opened
+at a later time using
+.BR pmemtrn_map ()
+as described above.
+Any in-progress (incomplete) transactions in outstanding at the time
+.BR pmemtrn_unmap ()
+is called are discarded in the same manner as if the program had terminated
+before completed those transactions.
+.PP
+.B XXX REST OF TRANSACTION SECTION NOT READY FOR REVIEW
+.SH ATOMIC ARRAYS
+.PP
+To use the atomic block arrays supplied by
+.BR libpmem ,
+a
+.I memory pool
+is first created.  This is done with the
+.BR pmemblk_map ()
+function described in this section.
+The other functions
+described in this section then operate on the resulting block
+memory pool.
+.PP
+Once created, the memory pool is represented by an opaque handle,
+of type
+.IR "PMEMblk *" ,
+which is passed to most of the other functions in this section.
+Internally,
+.B libpmem
+will use either
+.B pmem_persist ()
+or
+.B msync (2)
+when it needs to flush changes, depending on whether
+the memory pool appears to be Persistent Memory or a regular file
+(see
+.BR pmem_is_pmem ()
+above for more information).
+There is no need for applications to flush changes directly
+when using the block memory API described in this section.
+.PP
+.BI "PMEMblk *pmemblk_map(int " fd ", size_t " bsize );
+.IP
+The
+.B pmemblk_map ()
+function maps a block memory pool into memory (an array of
+blocks that support atomic update at the block level), returning a memory
+pool handle used with most of the functions in this section.
+.I fd
+must be a file descriptor for a file opened for both reading and writing,
+and the file size must already be set appropriately
+(for example, by calling
+.BR posix_fallocate ()
+the first time the file is used).
+.I bsize
+is the block size of each element in the pool.
+.B pmemblk_map ()
+will map the file using
+.BR mmap (2),
+and detect if the file already contains a
+.B libpmem
+memory pool from an earlier use of the file with
+.BR pmemblk_map ().
+If a memory pool is not found, a new pool is created,
+overwriting any data contained in the file.
+.BR pmemblk_map ()
+will fit as many blocks as possible in the given file, but some
+space will be used by the library for metadata.  See
+.BR pmemblk_nblock ()
+below for a way to determine the resulting number of usable blocks.
+The minimum
+file size allowed by the library for a block pool is defined in
+.B <libpmem.h>
+as
+.BR PMEMBLK_MIN_POOL .
+There are no restrictions on the block size
+.IR bsize ,
+however
+.B libpmem
+will silently round up the given size to
+.BR PMEMBLK_MIN_BLK ,
+as defined in
+.BR <libpmem.h> .
+After
+.BR pmemblk_map ()
+returns the memory pool handle, the file descriptor
+.I fd
+may be closed by the caller without impacting the use
+of
+.B libpmem
+on the memory pool.
+.BR pmemblk_map ()
+returns NULL on error, setting errno appropriately.
+It is an error to use
+.BR pmemblk_map ()
+on a file with a different type of memory pool in it.  The library
+will return EINVAL for this case.  To switch the type of memory pool
+in a file, it is best to delete the file and recreate it.
+.IP
+Each time a block memory pool is mapped using
+.BR pmemblk_map (),
+a brief consistency check is performed, similar to the check done by
+.BR pmemblk_check ()
+described below, but less extensive.  If a consistency issue is
+discovered, the severity of the pool corruption is evaluated to
+determine if read-only access is still viable.  If so,
+.BR pmemblk_map ()
+succeeds but any subsequent calls to change the pool will
+return the error EROFS.  If the memory pool is not viable
+for read-only access,
+.BR pmemblk_map ()
+will return the error EINVAL.  In either case, see
+.BR pmemblk_check ()
+below for a description of how to determine the details of the
+memory pool corruption.
+.PP
+.BI "void pmemblk_unmap(PMEMblk *" pbp );
+.IP
+The
+.BR pmemblk_unmap ()
+function unmaps the memory pool indicated by
+.I pbp
+and deletes the memory pool handle.  The block memory pool
+itself lives on in the file that contains it and may be re-opened
+at a later time using
+.BR pmemblk_map ()
+as described above.
+.PP
+.BI "size_t pmemblk_nblock(PMEMblk *" pbp );
+.IP
+The
+.BR pmemblk_nblock ()
+function returns the usable space in the block memory pool,
+expressed as the number of blocks available.
+.I pbp
+must be a block memory pool as returned by
+.BR pmemblk_map ().
+.PP
+.BI "int pmemblk_read(PMEMblk *" pbp ", void *" buf ", off_t " blockno );
+.IP
+The
+.BR pmemblk_read ()
+function reads a block from memory pool
+.IR pbp ,
+block number
+.IR blockno ,
+into the buffer
+.IR buf .
+On success, zero is returned.  On error, -1 is returned and errno is set.
+Reading a block that has never been written by
+.BR pmemblk_write ()
+since the creation of block memory pool will return a block of zeroes, as
+that is the initial state of all blocks when the memory pool is created.
+.PP
+.BI "int pmemblk_write(PMEMblk *" pbp ", const void *" buf ", off_t " blockno );
+.IP
+The
+.BR pmemblk_write ()
+function writes a block from
+.I buf
+to block number
+.I blockno
+in the memory pool
+.IR pbp .
+The write is atomic with respect to other reads and writes.  In addition,
+the write cannot be torn by program failure or system crashes; on recovery
+the block is guaranteed to contain either the old data or the new data,
+never a mixture of both.
+On success, zero is returned.  On error, -1 is returned and errno is set.
+.PP
+.BI "int pmemblk_set_zero(PMEMblk *" pbp ", off_t " blockno );
+.IP
+The
+.BR pmemblk_set_zero ()
+function writes zeros to block number
+.I blockno
+in memory pool
+.IR pbp .
+Using this function is faster than actually writing a block of zeros
+since
+.B libpmem
+uses metadata to indicate the block should read back as zero.
+On success, zero is returned.  On error, -1 is returned and errno is set.
+.PP
+.BI "int pmemblk_set_error(PMEMblk *" pbp ", off_t " blockno );
+.IP
+The
+.BR pmemblk_set_error ()
+function sets the error state for block number
+.I blockno
+in memory pool
+.IR pbp .
+A block in the error state returns errno EIO when read.  Writing the
+block clears the error state and returns the block to normal use.
+On success, zero is returned.  On error, -1 is returned and errno is set.
+.SH PERSISTENT MEMORY LOGS
+.PP
+To use the persistent memory logs supplied by
+.BR libpmem ,
+a
+.I memory pool
+is first created.  This is done with the
+.BR pmemlog_map ()
+function described in this section.
+The other functions
+described in this section then operate on the resulting log
+memory pool.
+.PP
+Once created, the memory pool is represented by an opaque handle,
+of type
+.IR "PMEMlog *" ,
+which is passed to most of the other functions in this section.
+Internally,
+.B libpmem
+will use either
+.B pmem_persist ()
+or
+.B msync (2)
+when it needs to flush changes, depending on whether
+the memory pool appears to be Persistent Memory or a regular file
+(see
+.BR pmem_is_pmem ()
+above for more information).
+There is no need for applications to flush changes directly
+when using the log memory API described in this section.
+.PP
+.BI "PMEMlog *pmemlog_map(int " fd );
+.IP
+The
+.B pmemlog_map ()
+function maps a log memory pool into memory (a persistent memory
+resident log file), returning a memory
+pool handle used with most of the functions in this section.
+.I fd
+must be a file descriptor for a file opened for both reading and writing,
+and the file size must already be set appropriately
+(for example, by calling
+.BR posix_fallocate ()
+the first time the file is used).
+.B pmemlog_map ()
+will map the file using
+.BR mmap (2),
+and detect if the file already contains a
+.B libpmem
+memory pool from an earlier use of the file with
+.BR pmemlog_map ().
+If a memory pool is not found, a new pool is created,
+overwriting any data contained in the file.
+.BR pmemlog_map ()
+will create as large a log as possible in the given file, but some
+space will be used by the library for metadata.  See
+.BR pmemlog_nbyte ()
+below for a way to determine the resulting usable space.
+The minimum
+file size allowed by the library for a log memory pool is defined in
+.B <libpmem.h>
+as
+.BR PMEMLOG_MIN_POOL .
+After
+.BR pmemlog_map ()
+returns the memory pool handle, the file descriptor
+.I fd
+may be closed by the caller without impacting the use
+of
+.B libpmem
+on the memory pool.
+.BR pmemlog_map ()
+returns NULL on error, setting errno appropriately.
+It is an error to use
+.BR pmemlog_map ()
+on a file with a different type of memory pool in it.  The library
+will return EINVAL for this case.  To switch the type of memory pool
+in a file, it is best to delete the file and recreate it.
+.IP
+Each time a log memory pool is mapped using
+.BR pmemlog_map (),
+a brief consistency check is performed, similar to the check done by
+.BR pmemlog_check ()
+described below, but less extensive.  If a consistency issue is
+discovered, the severity of the pool corruption is evaluated to
+determine if read-only access is still viable.  If so,
+.BR pmemlog_map ()
+succeeds but any subsequent calls to change the pool will
+return the error EROFS.  If the memory pool is not viable
+for read-only access,
+.BR pmemlog_map ()
+will return the error EINVAL.  In either case, see
+.BR pmemlog_check ()
+below for a description of how to determine the details of the
+memory pool corruption.
+.PP
+.BI "void pmemlog_unmap(PMEMlog *" plp );
+.IP
+The
+.BR pmemlog_unmap ()
+function unmaps the memory pool indicated by
+.I plp
+and deletes the memory pool handle.  The log memory pool
+itself lives on in the file that contains it and may be re-opened
+at a later time using
+.BR pmemlog_map ()
+as described above.
+.PP
+.BI "size_t pmemlog_nbyte(PMEMlog *" plp );
+.IP
+The
+.BR pmemlog_nbyte ()
+function returns the
+amount of usable space in the log
+.IR plp .
+This function may be used on a log to determine how much
+usable space is available after
+.B libpmem
+has added its metadata to the memory pool.
+.PP
+.BI "int pmemlog_append(PMEMlog *" plp ", const void *" buf ", size_t " count );
+.IP
+The
+.BR pmemlog_append ()
+function appends
+.I count
+bytes from
+.I buf
+to the current write offset in the log memory pool
+.IR plp .
+Calling this function is analogous to appending to a file.  The append
+is atomic and cannot be torn by a program failure or system crash.
+On success, zero is returned.  On error, -1 is returned and errno is set.
+.PP
+.BI "int pmemlog_appendv(PMEMlog *" plp ", const struct iovec *" iov ", int " iovcnt );
+.IP
+The
+.BR pmemlog_appendv ()
+function appends to the log
+.I plp
+just like
+.BR pmemlog_append ()
+above, but this function takes a scatter/gather list in a manner
+similar to
+.BR writev (2).
+In this case, the entire list of buffers is appended atomically.
+On success, zero is returned.  On error, -1 is returned and errno is set.
+.PP
+.BI "off_t pmemlog_tell(PMEMlog *" plp );
+.IP
+The
+.BR pmemlog_tell ()
+function returns the current write point for the log, expressed as a byte
+offset into the usable log space in the memory pool.  This offset starts
+off as zero on a newly-created log, and is incremented by each successful
+append operation.  This function can be used to determine how much data
+is currently in the log.
+.PP
+.BI "void pmemlog_rewind(PMEMlog *" plp );
+.IP
+The
+.BR pmemlog_rewind ()
+function resets the current write point for the log to zero.  After this
+call, the next append adds to the beginning of the log.
+.PP
+.nf
+.BI "void pmemlog_walk(PMEMlog *" plp ", size_t chunksize ,
+.BI "           int (*" process_chunk ")(const void *" buf ", size_t " len ", void *" arg ),
+.BI "           void *" arg );
+.fi
+.IP
+The
+.BR pmemlog_walk ()
+function walks through the log
+.IR plp ,
+from beginning to end, calling the callback function
+.I process_chunk
+for each
+.I chunksize
+block of data found.
+The argument
+.I arg
+is also passed to the callback to help avoid the need for global state.
+The
+.I chunksize
+argument is useful for logs with fixed-length records and may be specified
+as 0 to cause a single call to the callback with the entire log contents
+passed as the
+.I buf
+argument.  The
+.I len
+argument tells the
+.I process_chunk
+function how much data buf is holding.
+The callback function should return true if
+.BR pmemlog_walk ()
+should continue walking through the log, or false to
+terminate the walk.
+The callback function is called while holding
+.B libpmem
+internal locks that make calls atomic, so the callback function
+must not try to append to the log itself or deadlock will occur.
+.SH MANAGING LIBRARY BEHAVIOR
+.PP
+The library entry points described in this section are less
+commonly used than the previous section.
+These entry points expose library information or alter
+the default library behavior.
+.PP
+.nf
+.BI "const char *pmem_check_version("
+.BI "           unsigned " major_required ,
+.BI "           unsigned " minor_required );
+.fi
+.IP
+The
+.BR pmem_check_version ()
+function is used to see if the installed
+.B libpmem
+supports the version of the library API required by an application.
+The easiest way to do this is for the application to supply the
+compile-time version information, supplied by defines in
+.BR <libpmem.h> ,
+like this:
+.IP
+.nf
+reason = pmem_check_version(PMEM_MAJOR_VERSION,
+                            PMEM_MINOR_VERSION);
+if (reason != NULL {
+	/*  version check failed, reason string tells you why */
+}
+.fi
+.IP
+Any mismatch in the major version number is considered a failure,
+but a library with a newer minor version number will pass this
+check since increasing minor versions imply backwards compatibility.
+.IP
+An application can also check specifically for the existence of
+an interface by checking for the version where that interface was
+introduced.  These versions are documented in this man page as follows:
+unless otherwise specified, all interfaces described here are available
+in version 1.0 of the library.  Interfaces added after version 1.0
+will contain the text
+.I introduced in version x.y
+in the section of this manual describing the feature.
+.IP
+When the version check performed by
+.BR pmem_check_version ()
+is successful, the return value is NULL.  Otherwise the return value
+is a static string describing the reason for failing the version check.
+The string returned by
+.BR pmem_check_version ()
+must not be modified or freed.
+.PP
+.nf
+.BI "void pmem_set_funcs("
+.BI "           void *(*" malloc_func ")(size_t " size ),
+.BI "           void (*" free_func ")(void *" ptr ),
+.BI "           void *(*" realloc_func ")(void *" ptr ", size_t " size ),
+.BI "           char *(*" strdup_func ")(const char *" s ),
+.BI "           void (*" print_func ")(const char *" s ),
+.BI "           void (*" persist_func ")(void *" addr ", size_t " len ", int " flags ));
+.fi
+.IP
+The
+.BR pmem_set_funcs ()
+function allows an application to override some
+interfaces used internally by
+.BR libpmem .
+Passing in NULL for any of the handlers will cause the
+.B libpmem
+default function to be used.
+The library does not make heavy use of the system malloc functions, but
+it does allocate approximately 4-8 kilobytes for each memory pool in use.
+The only functions in the malloc family used by the library are represented
+by the first four arguments to
+.BR pmem_set_funcs ().
+The
+.I print_func
+function is called by
+.B libpmem
+when additional tracing is enabled
+in the debug version of the library as described in the
+.B DEBUGGING
+section below.
+The default
+.I print_func
+used by the library prints to
+the file specified by the
+.B PMEM_LOG_FILE
+environment variable, or to
+.B stderr
+if that variable is not set.
+The
+.I persist_func
+is called by
+.B libpmem
+to make changes to Persistent Memory persistent.  The default
+.I persist_func
+used by the library is
+.BR pmem_persist (),
+described in this manual.
+.PP
+.nf
+.BI "int pmemtrn_check(const char *" path );
+.BI "int pmemblk_check(const char *" path );
+.BI "int pmemlog_check(const char *" path );
+.fi
+.IP
+These functions perform a consistency check of the file
+indicated by
+.IR path .
+They return true if the memory pool is found to be consistent.  In
+the event of inconsistencies, continued use of the file
+with
+.B libpmem
+will result in undefined behavior.  The debug version of
+.B libpmem
+will provide additional details on inconsistencies when
+.B PMEM_LOG_LEVEL
+is at least 1, as described in the
+.B DEBUGGING
+section below.
+These functions open the given
+.I path
+read-only so they never make any changes to the file.
+Although these functions are mostly used during the development of
+.B libpmem
+itself, they are potentially useful for determining the type of
+memory pool contained in a file (only the appropriate check function
+will return true).
+.SH DEBUGGING
+.PP
+Two versions of
+.B libpmem
+are typically available on a development system.
+The normal version, accessed when a program is
+linked using the
+.B -lpmem
+option, is optimized for performance.  That version skips checks
+that impact performance and never logs any trace information or performs
+any run-time assertions.  A second version, accessed when a program
+uses the libraries under
+.BR /usr/lib/nvml_debug ,
+contains run-time assertions and trace points.
+The typical way to access the debug version is to set the environment variable
+.B LD_LIBRARY_PATH
+to
+.BR /usr/lib/nvml_debug
+or
+.BR /usr/lib64/nvml_debug
+depending on where the debug libraries are installed on the system.
+The trace points in the debug version of the library
+are enabled using the environment variable
+.BR PMEM_LOG_LEVEL ,
+which can be set to the following values:
+.IP 0
+This is the default level when
+.B PMEM_LOG_LEVEL
+is not set.  No log messages are emitted at this level.
+.IP 1
+Additional details on any errors detected are logged (in addition
+to returning the errno-based errors as usual).
+.IP 2
+A trace of basic operations including allocations and deallocations
+is logged.
+.IP 3
+This level enables a very verbose amount of function call tracing
+in the library.
+.IP 4
+This level enables voluminous and fairly obscure tracing information
+that is likely only useful to the
+.B libpmem
+developers.
+.PP
+The environment variable
+.B PMEM_LOG_FILE
+specifies a file name where
+all logging information should be written, and if
+.B PMEM_LOG_FILE
+is not set, output goes to stderr.
+All prints are done using the
+.I print_func
+function in
+.B libpmem
+(see
+.BR pmem_set_funcs ()
+above for details on how to override that function).
+.PP
+Setting the environment variable
+.B PMEM_LOG_LEVEL
+has no effect on the non-debug version of
+.BR libpmem .
+.SH BASIC PERSISTENT MEMORY EXAMPLE
+.PP
+The follow example uses
+.B libpmem
+to flush changes made to raw, memory-mapped persistent memory.
+.IP
+.\" run source through expand -4 before inserting...
+.nf
+#include <sys/mman.h>
+#include <fcntl.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <string.h>
+#include <libpmem.h>
+
+int
+main(int argc, char *argv[])
+{
+    int fd;
+    char *pmaddr;
+
+    /* memory map some persistent memory */
+    if ((fd = open("/my/pmem-aware/fs/myfile", O_RDWR)) < 0) {
+        perror("open");
+        exit(1);
+    }
+
+    /* just map 4k for this example */
+    if ((pmaddr = mmap(NULL, 4096, PROT_READ|PROT_WRITE,
+                MAP_SHARED, fd, 0)) == MAP_FAILED) {
+        perror("mmap");
+        exit(1);
+    }
+    close(fd);
+
+    /* store a string to the persistent memory */
+    strcpy(pmaddr, "hello, persistent memory");
+
+    /*
+     * The above stores may or may not be sitting in cache at
+     * this point, depending on other system activity causing
+     * cache pressure.  Now force the change to be durable
+     * (flushed all the say to the persistent memory).  If
+     * unsure whether the file is really persistent memory,
+     * use pmem_is_pmem() to decide whether pmem_persist() can
+     * be used, or whether msync() must be used.
+     */
+    if (pmem_is_pmem(pmaddr, 4096))
+        pmem_persist(pmaddr, 4096, 0);
+    else
+        msync(pmaddr, 4096, MS_SYNC);
+}
+.fi
+.SH ATOMIC ARRAYS EXAMPLE
+.PP
+The follow example shows how the
+.I pmemblk
+entry points to
+.B libpmem
+are used to provide atomic arrays.
+.IP
+.\" run source through expand -4 before inserting...
+.nf
+#include <stdio.h>
+#include <fcntl.h>
+#include <errno.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <string.h>
+#include <libpmem.h>
+
+/* size of each element in the PMEM pool (bytes) */
+#define ELEMENT_SIZE ((size_t)1024)
+
+int
+main(int argc, char *argv[])
+{
+    int fd;
+    PMEMblk *pbp;
+    size_t nelements;
+    char buf[ELEMENT_SIZE];
+
+    /* create file on PMEM-aware file system */
+    if ((fd = open("/my/pmem-aware/fs/myfile",
+                    O_CREAT|O_RDWR, 0666)) < 0) {
+        perror("open");
+        exit(1);
+    }
+
+    /* pre-allocate 2GB of persistent memory */
+    if ((errno = posix_fallocate(fd, (off_t)0,
+                    (size_t)1024 * 1024 * 1024 * 2)) != 0) {
+        perror("posix_fallocate");
+        exit(1);
+    }
+
+    /* create an array of atomically writable elements */
+    if ((pbp = pmemblk_map(fd, ELEMENT_SIZE)) == NULL) {
+        perror("pmemblk_map");
+        exit(1);
+    }
+
+    /* how many elements fit into the PMEM pool? */
+    nelements = pmemblk_nblock(pbp);
+    printf("file holds %zu elements\n", nelements);
+
+    /* store a block at index 5 */
+    strcpy(buf, "hello, world");
+    if (pmemblk_write(pbp, buf, 5) < 0) {
+        perror("pmemblk_write");
+        exit(1);
+    }
+
+    /* read the block at index 10 (reads as zeros initially) */
+    if (pmemblk_read(pbp, buf, 10) < 0) {
+        perror("pmemblk_write");
+        exit(1);
+    }
+
+    /* zero out the block at index 5 */
+    if (pmemblk_set_zero(pbp, 5) < 0) {
+        perror("pmemblk_set_zero");
+        exit(1);
+    }
+
+    /* ... */
+
+    pmemblk_unmap(pbp);
+    close(fd);
+}
+.fi
+.SH PERSISTENT MEMORY LOG EXAMPLE
+.PP
+The follow example shows how the
+.I pmemlog
+entry points to
+.B libpmem
+are used to provide a persistent memory resident log file.
+.IP
+.\" run source through expand -4 before inserting...
+.nf
+#include <stdio.h>
+#include <fcntl.h>
+#include <errno.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <string.h>
+#include <libpmem.h>
+
+/* log processing callback for use with pmemlog_walk() */
+int
+printit(const void *buf, size_t len, void *arg)
+{
+    fwrite(buf, len, 1, stdout);
+    return 0;
+}
+
+int
+main(int argc, char *argv[])
+{
+    int fd;
+    PMEMlog *plp;
+    size_t nbyte;
+    char *str;
+
+    /* create file on PMEM-aware file system */
+    if ((fd = open("/my/pmem-aware/fs/myfile",
+                    O_CREAT|O_RDWR, 0666)) < 0) {
+        perror("open");
+        exit(1);
+    }
+
+    /* pre-allocate 2GB of persistent memory */
+    if ((errno = posix_fallocate(fd, (off_t)0,
+                    (size_t)1024 * 1024 * 1024 * 2)) != 0) {
+        perror("posix_fallocate");
+        exit(1);
+    }
+
+    /* create a persistent memory resident log */
+    if ((plp = pmemlog_map(fd)) == NULL) {
+        perror("pmemlog_map");
+        exit(1);
+    }
+
+    /* how many bytes does the log hold? */
+    nbyte = pmemlog_nbyte(plp);
+    printf("log holds %zu bytes\n", nbyte);
+
+    /* append to the log... */
+    str = "This is the first string appended\n";
+    if (pmemlog_append(plp, str, strlen(str)) < 0) {
+        perror("pmemlog_append");
+        exit(1);
+    }
+    str = "This is the second string appended\n";
+    if (pmemlog_append(plp, str, strlen(str)) < 0) {
+        perror("pmemlog_append");
+        exit(1);
+    }
+
+    /* print the log contents */
+    printf("log contains:\n");
+    pmemlog_walk(plp, 0, printit, NULL);
+
+    pmemlog_unmap(plp);
+    close(fd);
+}
+.fi
+.SH BUGS
+XXX
+.SH ACKNOWLEDGEMENTS
+.B libpmem
+leverages persistent memory research from the
+community and especially from these notable academic works:
+.IP
+J. Coburn, et al.:
+.IR "NV-Heaps: Making Persistent Objects Fast and Safe with Next Generation, Non-Volatile Memories" ,
+The 16th ACM Conference
+on Architectural Support for Programming Languages and Operating
+Systems (ASPLOS 2011), March 2011, Newport Beach, Ca.
+.IP
+Haris Volos, Andres Jaan Tack, Michael M. Swift:
+.IR "Mnemosyne: Lightweight Persistent Memory" ,
+The 16th ACM Conference on
+Architectural Support for Programming Languages and Operating
+Systems (ASPLOS 2011), March 2011, Newport Beach, California.
+http://research.cs.wisc.edu/sonar/projects/mnemosyne/
+.PP
+.B libpmem
+builds on the persistent memory programming model
+recommended by the SNIA NVM Programming Technical Work Group:
+.IP
+http://snia.org/nvmp
+.SH "SEE ALSO"
+.BR malloc (3),
+.BR posix_memalign (3),
+.BR strdup (3),
+.BR mmap (2),
+.BR msync (2),
+.BR libvmem (3).
diff --git a/doc/libvmem.3 b/doc/libvmem.3
new file mode 100644
index 0000000000000000000000000000000000000000..ad4e458fb129593e15cdbfb873e5a871c2242e02
--- /dev/null
+++ b/doc/libvmem.3
@@ -0,0 +1,734 @@
+.\"
+.\" Copyright (c) 2014, Intel Corporation
+.\"
+.\" Redistribution and use in source and binary forms, with or without
+.\" modification, are permitted provided that the following conditions
+.\" are met:
+.\"
+.\"     * Redistributions of source code must retain the above copyright
+.\"       notice, this list of conditions and the following disclaimer.
+.\"
+.\"     * Redistributions in binary form must reproduce the above copyright
+.\"       notice, this list of conditions and the following disclaimer in
+.\"       the documentation and/or other materials provided with the
+.\"       distribution.
+.\"
+.\"     * Neither the name of Intel Corporation nor the names of its
+.\"       contributors may be used to endorse or promote products derived
+.\"       from this software without specific prior written permission.
+.\"
+.\" THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+.\" "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+.\" LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+.\" A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+.\" OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+.\" SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+.\" LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+.\" DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+.\" THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+.\" (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+.\" OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+.\"
+.\"
+.\" libvmem.3 -- man page for libvmem
+.\"
+.\" Format this man page with:
+.\"	man -l libvmem.3
+.\" or
+.\"	groff -man -Tascii libvmem.3
+.\"
+.TH libvmem 3 "vmem API version 0.53" "NVM Library"
+.SH NAME
+libvmem \- volatile memory allocation library
+.SH SYNOPSIS
+.nf
+.B #include <libvmem.h>
+.sp
+.B cc ... -lvmem
+.sp
+.B Memory pool management:
+.sp
+.BI "VMEM *vmem_pool_create(const char *" dir ", size_t " size );
+.BI "VMEM *vmem_pool_create_in_region(void *" addr ", size_t " size );
+.BI "void vmem_pool_delete(VMEM *" vmp );
+.BI "int vmem_pool_check(VMEM *" vmp );
+.BI "int vmem_pool_freespace(VMEM *" vmp );
+.BI "void vmem_pool_stats_print(VMEM *" vmp ", const char *" opts );
+.sp
+.B Memory allocation related functions:
+.sp
+.BI "void *vmem_malloc(VMEM *" vmp ", size_t " size );
+.BI "void vmem_free(VMEM *" vmp ", void *" ptr );
+.BI "void *vmem_calloc(VMEM *" vmp ", size_t " nmemb ", size_t " size );
+.BI "void *vmem_realloc(VMEM *" vmp ", void *" ptr ", size_t " size );
+.BI "void *vmem_aligned_alloc(VMEM *" vmp ", size_t " alignment ", size_t " size );
+.BI "char *vmem_strdup(VMEM *" vmp ", const char *" s );
+.sp
+.B Managing overall library behavior:
+.sp
+.BI "const char *vmem_check_version("
+.BI "           unsigned " major_required ,
+.BI "           unsigned " minor_required );
+.BI "void vmem_set_funcs("
+.BI "           void *(*" malloc_func ")(size_t " size ),
+.BI "           void (*" free_func ")(void *" ptr ),
+.BI "           void *(*" realloc_func ")(void *" ptr ", size_t " size ),
+.BI "           char *(*" strdup_func ")(const char *" s ),
+.BI "           void (*" print_func ")(const char *" s ));
+.fi
+.sp
+.SH DESCRIPTION
+.PP
+.B libvmem
+provides common
+.I malloc-like
+interfaces to memory pools built on memory-mapped files.
+These interfaces are for traditional
+.B volatile
+memory allocation but, unlike the functions described in
+.BR malloc (3),
+the memory managed by
+.B libvmem
+may have different attributes, depending on the file system
+containing the memory-mapped files.  In particular,
+.B libvmem
+is part of the
+.I Non-Volatile Memory Library
+because it is sometimes useful to use non-volatile memory as a volatile
+memory pool, leveraging its capacity, cost, or performance characteristics.
+.PP
+.B libvmem
+uses the
+.BR mmap (2)
+system call to create a pool of volatile memory.  The library
+is most useful when used with
+.I Direct Access
+storage (DAX), which is memory-addressable persistent storage
+that supports load/store access without being paged via the system page cache.
+A Persistent Memory-aware file system is typically used to provide this
+type of access.  Memory-mapping a file from a Persistent
+Memory-aware file system provides the raw memory pools, and this library
+supplies the more familiar
+.I malloc-like
+interfaces on top of those pools.
+.PP
+Under normal usage,
+.B libvmem
+will never print messages or intentionally cause the process to exit.
+Exceptions to this are prints caused by calls to
+.BR vmem_pool_stats_print (),
+or by enabling debugging as described under
+.B DEBUGGING
+below.
+The library uses
+.BR pthreads (7)
+to be fully MT-safe, but never creates or destroys threads itself.
+The library does not make use of any signals, networking, and
+never calls
+.BR select ()
+or
+.BR poll ().
+The system memory allocation routines like
+.BR malloc ()
+and
+.BR free ()
+are used by
+.B libvmem
+for managing a small amount of run-time state, but applications
+are allowed to override these calls if necessary (see the description
+of
+.BR vmem_set_funcs ()
+below).
+.PP
+.B libvmem
+interfaces are grouped into three categories: those that manage
+memory pools, those providing the basic
+memory allocation functions, and those interfaces
+less commonly used for managing
+the overall library behavior.  These groups of interfaces are
+described in the following three sections.
+.SH MANAGING MEMORY POOLS
+.PP
+To use
+.BR libvmem ,
+a
+.I memory pool
+is first created.  This is most commonly done with the
+.BR vmem_pool_create ()
+function described in this section.
+The other functions
+described in this section are for less common cases, where
+applications have special needs for creating pools or examining
+library state.
+.PP
+Once created, a memory pool is represented by an opaque pool handle,
+of type
+.IR "VMEM *" ,
+which is passed to the functions for memory allocation described in
+the next section.
+.PP
+.BI "VMEM *vmem_pool_create(const char *" dir ", size_t " size );
+.IP
+The
+.BR vmem_pool_create ()
+function creates a memory pool.  The resulting pool is then used with
+functions like
+.BR vmem_malloc ()
+and
+.BR vmem_free ()
+to provide the familiar
+.I malloc-like
+programming model for the memory pool.
+.BR vmem_pool_create ()
+creates the pool by allocating a
+temporary file in the given directory
+.IR dir .
+The file is created in a fashion similar to
+.BR tmpfile (3),
+so that the file name does not appear when the directory is listed and
+the space is automatically freed when the program terminates.
+.I size
+bytes are allocated
+and the resulting space is memory-mapped.
+The minimum
+.I size
+value allowed by the library is defined in
+.B <libvmem.h>
+as
+.BR VMEM_MIN_POOL .
+Calling
+.BR vmem_pool_create ()
+with a size smaller than that will return an error.
+The maximum allowed size is not limited by
+.BR libvmem ,
+but by the file system specified by the
+.I dir
+argument.
+The
+.I size
+passed in is the raw size of the memory pool and
+.B libvmem
+will use some of that space for its own metadata.
+.BR vmem_pool_create ()
+returns an opaque memory pool handle or NULL if an error occurred
+(in which case
+.I errno
+is set appropriately).  The opaque memory pool handle
+is then used with the other functions
+described in this man page that operate on a specific memory pool.
+.PP
+.BI "VMEM *vmem_pool_create_in_region(void *" addr ", size_t " size );
+.IP
+The
+.BR vmem_pool_create_in_region ()
+is an alternate
+.B libvmem
+entry point for creating a memory pool.
+It is for the rare case where an application needs to create
+a memory pool from an already memory-mapped region.
+Instead of allocating space from a given file system,
+.BR vmem_pool_create_in_region ()
+is given the memory region explicitly via the
+.I addr
+and
+.I size
+arguments.
+Any data in the region is lost by calling
+.BR vmem_pool_create_in_region (),
+which will immediately store its own data structures for managing
+the pool there.
+Like
+.BR vmem_pool_create ()
+above, the minimum
+.I size
+allowed is defined as
+.BR VMEM_MIN_POOL .
+.BR vmem_pool_create_in_region ()
+returns an opaque memory pool handle or NULL if an error occurred
+(in which case
+.I errno
+is set appropriately).
+.PP
+.BI "void vmem_pool_delete(VMEM *" vmp );
+.IP
+The
+.BR vmem_pool_delete ()
+function releases the memory pool
+.IR vmp .
+If the memory pool was created using
+.BR vmem_create_pool (),
+deleting it allows the space to be reclaimed.
+.PP
+.BI "int vmem_pool_check(VMEM *" vmp );
+.IP
+The
+.BR vmem_pool_check ()
+function
+performs an exhaustive consistency check of all
+.B libvmem
+internal data structures in memory pool
+.IR vmp .
+A return value of zero from
+.BR vmem_pool_check ()
+means that no errors were found, otherwise -1 is returned and errno
+is set to
+.BR EINVAL .
+Since an error return indicates memory pool corruption, applications
+should not continue to use a pool in this state.
+Additional details about errors found are logged when the log level
+is at least 1 (see
+.B DEBUGGING
+below).
+During the consistency check performed by
+.BR vmem_pool_check (),
+other operations on the same memory pool are locked out.
+The checks are all read-only;
+.BR vmem_pool_check ()
+never modifies the memory pool.
+This function is mostly useful for
+.B libvmem
+developers during testing/debugging.
+.PP
+.BI "int vmem_pool_freespace(VMEM *" vmp );
+.IP
+The
+.BR vmem_pool_freespace ()
+function returns the amount of unallocated space available
+in the memory pool
+.IR vmp .
+This return value is in bytes, and should be considered
+an approximation since different allocation patterns will require
+.B libvmem
+to use up different amounts of space for internal metadata.
+.PP
+.BI "void vmem_pool_stats_print(VMEM *" vmp ", const char *" opts );
+.IP
+The
+.BR vmem_pool_stats_print ()
+function produces messages containing statistics about the
+given memory pool.
+The output is printed using
+.BR libvmem 's
+internal
+.I print_func
+function (see
+.BR vmem_set_funcs ()
+below).  That means the output typically appears on
+.B stderr
+unless the caller supplies a replacement
+.I print_func
+or sets the environment variable
+.B VMEM_LOG_FILE
+to direct output elsewhere.
+The
+.I opts
+string can either be NULL or it can contain a list of options
+that change the stats printed.
+General information that never changes during execution can be
+omitted by specifying "g" as a character within the opts string.
+The characters “m” and “a” can be specified to omit merged arena
+and per arena statistics, respectively; “b” and “l” can be specified
+to omit per size class statistics for bins and large objects, respectively.
+Unrecognized characters are silently ignored.
+Note that thread caching may prevent some statistics from being
+completely up to date.
+See
+.BR jemalloc (3)
+for more detail (the description of the available
+.I opts
+above was taken from that man page).
+.SH MEMORY ALLOCATION
+.PP
+This section describes the
+.I malloc-like
+API provided by
+.BR libvmem .
+These functions provide the same semantics as their libc namesakes,
+but operate on the memory pools specified by their first arguments.
+.PP
+.BI "void *vmem_malloc(VMEM *" vmp ", size_t " size );
+.IP
+The
+.BR vmem_malloc ()
+function provides the same semantics as
+.BR malloc (3),
+but operates on the memory pool
+.I vmp
+instead of the process heap supplied by the system.
+It allocates
+.I size
+bytes and returns a pointer to the allocated memory.
+.IR "The memory is not initialized" .
+If
+.I size
+is 0, then
+.BR vmem_malloc ()
+returns either NULL,
+or a unique pointer value that can later be successfully passed to
+.BR vmem_free ().
+If
+.BR vmem_malloc ()
+is unable to satisfy the allocation request, a NULL pointer is
+returned and errno is set appropriately.
+.PP
+.BI "void vmem_free(VMEM *" vmp ", void *" ptr );
+.IP
+The
+.BR vmem_free ()
+function provides the same semantics as
+.BR free (3),
+but operates on the memory pool
+.I vmp
+instead of the process heap supplied by the system.
+It frees the memory space pointed to by
+.IR ptr ,
+which must have been returned by a previous call to
+.BR vmem_malloc (),
+.BR vmem_calloc ()
+or
+.BR vmem_realloc ()
+for
+.IR "the same pool of memory" .
+Undefined behavior occurs if frees do not correspond to allocated
+memory from the same memory pool.
+If
+.I ptr
+is NULL, no operation is performed.
+.PP
+.BI "void *vmem_calloc(VMEM *" vmp ", size_t " nmemb ", size_t " size );
+.IP
+The
+.BR vmem_calloc ()
+function provides the same semantics as
+.BR calloc (3),
+but operates on the memory pool
+.I vmp
+instead of the process heap supplied by the system.
+It allocates memory for an array of
+.I nmemb
+elements of
+.I size
+bytes each and returns a pointer to the allocated memory.
+The memory is set to zero.
+If
+.I nmemb
+or
+.I size
+is 0, then
+.BR vmem_calloc ()
+returns either NULL,
+or a unique pointer value that can later be successfully passed to
+.BR vmem_free ().
+If
+.BR vmem_calloc ()
+is unable to satisfy the allocation request, a NULL pointer is
+returned and errno is set appropriately.
+.PP
+.BI "void *vmem_realloc(VMEM *" vmp ", void *" ptr ", size_t " size );
+.IP
+The
+.BR vmem_realloc ()
+function provides the same semantics as
+.BR realloc (3),
+but operates on the memory pool
+.I vmp
+instead of the process heap supplied by the system.
+It changes the size of the memory block pointed to by
+.I ptr
+to
+.I size
+bytes.
+The contents will be unchanged in the range from the start of the region
+up to the minimum of the old and new sizes.
+If the new size is larger than the old size, the added memory will
+.I not
+be initialized.
+If
+.I ptr
+is NULL, then the call is equivalent to
+.IR "vmem_malloc(vmp, size)" ,
+for all values of
+.IR size ;
+if
+.I size
+is equal to zero,
+and
+.I ptr
+is not NULL, then the call is equivalent to
+.IR "vmem_free(vmp, ptr)" .
+Unless
+.I ptr
+is NULL, it must have been returned by an earlier call to
+.BR vmem_malloc (),
+.BR vmem_calloc ()
+or
+.BR vmem_realloc ().
+If the area pointed to was moved, a
+.I vmem_free(vmp, ptr)
+is done.
+If
+.BR vmem_realloc ()
+is unable to satisfy the allocation request, a NULL pointer is
+returned and errno is set appropriately.
+.PP
+.BI "void *vmem_aligned_alloc(VMEM *" vmp ", size_t " alignment ", size_t " size );
+.IP
+The
+.BR vmem_aligned_alloc ()
+function provides the same semantics as
+.BR aligned_alloc (3),
+but operates on the memory pool
+.I vmp
+instead of the process heap supplied by the system.
+It allocates
+.I size
+bytes from the memory pool and returns a pointer
+to the allocated memory.
+The memory address will be a multiple of
+.IR alignment ,
+which must be a power of two.
+If
+.BR vmem_aligned_alloc ()
+is unable to satisfy the allocation request, a NULL pointer is
+returned and errno is set appropriately.
+.PP
+.BI "char *vmem_strdup(VMEM *" vmp ", const char *" s );
+.IP
+The
+.BR vmem_strdup ()
+function provides the same semantics as
+.BR strdup (3),
+but operates on the memory pool
+.I vmp
+instead of the process heap supplied by the system.
+It returns a pointer to a new string which is a
+duplicate of the string
+.IR s .
+Memory for the new string is obtained
+with
+.BR vmem_malloc (),
+on the given memory pool, and can be freed with
+.BR vmem_free ()
+on the same memory pool.
+If
+.BR vmem_strdup ()
+is unable to satisfy the allocation request, a NULL pointer is
+returned and errno is set appropriately.
+.SH MANAGING LIBRARY BEHAVIOR
+.PP
+The library entry points described in this section are less
+commonly used than the previous section.
+These entry points expose library information or alter
+the default library behavior.
+.PP
+.nf
+.BI "const char *vmem_check_version("
+.BI "           unsigned " major_required ,
+.BI "           unsigned " minor_required );
+.fi
+.IP
+The
+.BR vmem_check_version ()
+function is used to see if the installed
+.B libvmem
+supports the version of the library API required by an application.
+The easiest way to do this is for the application to supply the
+compile-time version information, supplied by defines in
+.BR <libvmem.h> ,
+like this:
+.IP
+.nf
+reason = vmem_check_version(VMEM_MAJOR_VERSION,
+                            VMEM_MINOR_VERSION);
+if (reason != NULL {
+	/*  version check failed, reason string tells you why */
+}
+.fi
+.IP
+Any mismatch in the major version number is considered a failure,
+but a library with a newer minor version number will pass this
+check since increasing minor versions imply backwards compatibility.
+.IP
+An application can also check specifically for the existence of
+an interface by checking for the version where that interface was
+introduced.  These versions are documented in this man page as follows:
+unless otherwise specified, all interfaces described here are available
+in version 1.0 of the library.  Interfaces added after version 1.0
+will contain the text
+.I introduced in version x.y
+in the section of this manual describing the feature.
+.IP
+When the version check performed by
+.BR vmem_check_version ()
+is successful, the return value is NULL.  Otherwise the return value
+is a static string describing the reason for failing the version check.
+The string returned by
+.BR vmem_check_version ()
+must not be modified or freed.
+.PP
+.nf
+.BI "void vmem_set_funcs("
+.BI "           void *(*" malloc_func ")(size_t " size ),
+.BI "           void (*" free_func ")(void *" ptr ),
+.BI "           void *(*" realloc_func ")(void *" ptr ", size_t " size ),
+.BI "           char *(*" strdup_func ")(const char *" s ),
+.BI "           void (*" print_func ")(const char *" s ));
+.fi
+.IP
+The
+.BR vmem_set_funcs ()
+function allows an application to override some
+interfaces used internally by
+.BR libvmem .
+Passing in NULL for any of the handlers will cause the
+.B libvmem
+default function to be used.
+The library does not make heavy use of the system malloc functions, but
+it does allocate approximately 4-8 kilobytes for each memory pool in use.
+The only functions in the malloc family used by the library are represented
+by the first four arguments to
+.BR vmem_set_funcs ().
+The
+.I print_func
+function is called by
+.B libvmem
+when the
+.BR vmem_pool_stats_print ()
+entry point is used, or when additional tracing is enabled
+in the debug version of the library as described in the
+.B DEBUGGING
+section below.
+The default
+.I print_func
+used by the library prints to
+the file specified by the
+.B VMEM_LOG_FILE
+environment variable, or to
+.B stderr
+if that variable is not set.
+.SH DEBUGGING
+.PP
+Two versions of
+.B libvmem
+are typically available on a development system.
+The normal version, accessed when a program is
+linked using the
+.B -lvmem
+option, is optimized for performance.  That version skips checks
+that impact performance and never logs any trace information or performs
+any run-time assertions.  A second version, accessed when a program
+uses the libraries under
+.BR /usr/lib/nvml_debug ,
+contains run-time assertions and trace points.
+The typical way to access the debug version is to set the environment variable
+.B LD_LIBRARY_PATH
+to
+.BR /usr/lib/nvml_debug
+or
+.BR /usr/lib64/nvml_debug
+depending on where the debug libraries are installed on the system.
+The trace points in the debug version of the library
+are enabled using the environment variable
+.BR VMEM_LOG_LEVEL ,
+which can be set to the following values:
+.IP 0
+This is the default level when
+.B VMEM_LOG_LEVEL
+is not set.
+Only statistics are logged, and then only in response to a call to
+.BR vmem_pool_stats_print ().
+.IP 1
+Additional details on any errors detected are logged (in addition
+to returning the errno-based errors as usual).
+.IP 2
+A trace of basic operations including allocations and deallocations
+is logged.
+.IP 3
+This level enables a very verbose amount of function call tracing
+in the library.
+.IP 4
+This level enables voluminous and fairly obscure tracing information
+that is likely only useful to the
+.B libvmem
+developers.
+.PP
+The environment variable
+.B VMEM_LOG_FILE
+specifies a file name where
+all logging information should be written, and if
+.B VMEM_LOG_FILE
+is not set, output goes to stderr.
+All prints are done using the
+.I print_func
+function in
+.B libvmem
+(see
+.BR vmem_set_funcs ()
+above for details on how to override that function).
+.PP
+Setting the environment variable
+.B VMEM_LOG_LEVEL
+has no effect on the non-debug version of
+.BR libvmem .
+.SH EXAMPLE
+.PP
+The follow example creates a memory pool, allocates some memory to contain
+the string "hello, world", and then frees that memory.
+.IP
+.nf
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <libvmem.h>
+
+main()
+{
+    VMEM *vmp;
+    char *ptr;
+
+    /* create minimum size pool of memory */
+    if ((vmp = vmem_pool_create("/my/pmem-aware/fs",
+                                VMEM_MIN_POOL)) == NULL) {
+        perror("vmem_pool_create");
+        exit(1);
+    }
+
+    if ((ptr = vmem_malloc(vmp, 100)) == NULL) {
+        perror("vmem_malloc");
+        exit(1);
+    }
+
+    strcpy(ptr, "hello, world");
+
+    /* give the memory back */
+    vmem_free(vmp, ptr);
+
+    /* ... */
+}
+.fi
+.SH BUGS
+Unlike the normal
+.BR malloc (),
+which asks the system for additional memory when it runs out,
+.B libvmem
+allocates the size it is told to and never attempts to grow or shrink
+that memory pool.
+.SH ACKNOWLEDGEMENTS
+.B libvmem
+depends on jemalloc, written by Jason Evans, to do the heavy lifting
+of managing dynamic memory allocation.  See:
+.IP
+http://www.canonware.com/jemalloc/
+.PP
+.B libvmem
+builds on the persistent memory programming model
+recommended by the SNIA NVM Programming Technical Work Group:
+.IP
+http://snia.org/nvmp
+.SH "SEE ALSO"
+.BR malloc (3),
+.BR posix_memalign (3),
+.BR strdup (3),
+.BR mmap (2),
+.BR jemalloc (3),
+.BR libpmem (3).
diff --git a/examples/.gitignore b/examples/.gitignore
new file mode 100644
index 0000000000000000000000000000000000000000..e85d8524c4a17e5029e19c983307277da586db9b
--- /dev/null
+++ b/examples/.gitignore
@@ -0,0 +1,5 @@
+*.o
+pmem_example
+pmemblk_example
+pmemlog_example
+vmem_example
diff --git a/examples/Makefile b/examples/Makefile
new file mode 100644
index 0000000000000000000000000000000000000000..b470a269cc0760743763680069e0bc40fc6a7010
--- /dev/null
+++ b/examples/Makefile
@@ -0,0 +1,77 @@
+#
+# Copyright (c) 2014, Intel Corporation
+#
+# Redistribution and use in source and binary forms, with or without
+# modification, are permitted provided that the following conditions
+# are met:
+#
+#     * Redistributions of source code must retain the above copyright
+#       notice, this list of conditions and the following disclaimer.
+#
+#     * Redistributions in binary form must reproduce the above copyright
+#       notice, this list of conditions and the following disclaimer in
+#       the documentation and/or other materials provided with the
+#       distribution.
+#
+#     * Neither the name of Intel Corporation nor the names of its
+#       contributors may be used to endorse or promote products derived
+#       from this software without specific prior written permission.
+#
+# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+#
+
+#
+# examples/Makefile -- build the NVM Library examples
+#
+TARGETS = pmem_example pmemblk_example pmemlog_example vmem_example
+INCS = -I../src/include
+CFLAGS = -std=gnu99 -ggdb -Wall -Werror
+LIBS = -L../src/debug -pthread
+
+vmem_example: LIBS += -lvmem
+pmem_example pmemblk_example pmemlog_example: LIBS += -lpmem
+
+all: $(TARGETS)
+	$(MAKE) -C logfile $@
+	$(MAKE) -C assetdb $@
+
+clean:
+	$(RM) *.o core a.out
+	$(MAKE) -C logfile $@
+	$(MAKE) -C assetdb $@
+
+clobber: clean
+	$(RM) $(TARGETS)
+	$(MAKE) -C logfile $@
+	$(MAKE) -C assetdb $@
+
+cstyle:
+	../utils/cstyle -pP *.[ch]
+	$(MAKE) -C logfile $@
+	$(MAKE) -C assetdb $@
+
+.c.o:
+	$(CC) -c -o $@ $(CFLAGS) $(INCS) $<
+
+$(TARGETS):
+	$(CC) -o $@ $< $(LIBS)
+
+pmem_example: pmem_example.o
+
+pmemblk_example: pmemblk_example.o
+
+pmemlog_example: pmemlog_example.o
+
+vmem_example: vmem_example.o
+
+.PHONY: all clean clobber cstyle
diff --git a/examples/README b/examples/README
new file mode 100644
index 0000000000000000000000000000000000000000..4f5755a446ebf98c692629a76bc9b63915b9f03e
--- /dev/null
+++ b/examples/README
@@ -0,0 +1,8 @@
+Linux NVM Library
+
+This is examples/README.
+
+This directory contains brief educational examples illustrating the use
+of the NVM libraries.  For many of these examples, the Makefile rules
+are here just to check that the example compiles, loads against the
+appropriate library, and passes cstyle.
diff --git a/examples/assetdb/.gitignore b/examples/assetdb/.gitignore
new file mode 100644
index 0000000000000000000000000000000000000000..e17d8d8d4fc67f946de4a6803384971e601808b8
--- /dev/null
+++ b/examples/assetdb/.gitignore
@@ -0,0 +1,4 @@
+asset_load
+asset_list
+asset_checkout
+asset_checkin
diff --git a/examples/assetdb/Makefile b/examples/assetdb/Makefile
new file mode 100644
index 0000000000000000000000000000000000000000..844334df6c150b341e1305bd29418bb47881e726
--- /dev/null
+++ b/examples/assetdb/Makefile
@@ -0,0 +1,68 @@
+#
+# Copyright (c) 2014, Intel Corporation
+#
+# Redistribution and use in source and binary forms, with or without
+# modification, are permitted provided that the following conditions
+# are met:
+#
+#     * Redistributions of source code must retain the above copyright
+#       notice, this list of conditions and the following disclaimer.
+#
+#     * Redistributions in binary form must reproduce the above copyright
+#       notice, this list of conditions and the following disclaimer in
+#       the documentation and/or other materials provided with the
+#       distribution.
+#
+#     * Neither the name of Intel Corporation nor the names of its
+#       contributors may be used to endorse or promote products derived
+#       from this software without specific prior written permission.
+#
+# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+#
+
+#
+# examples/asset/Makefile -- build the NVM Library examples
+#
+TARGETS = asset_load asset_list asset_checkout asset_checkin
+INCS = -I../../src/include
+CFLAGS = -std=gnu99 -ggdb -Wall -Werror
+LIBS = -L../../src/debug -lpmem -pthread
+
+all: $(TARGETS)
+
+clean:
+	$(RM) *.o core a.out
+
+clobber: clean
+	$(RM) $(TARGETS)
+
+cstyle:
+	../../utils/cstyle -pP *.[ch]
+
+.c.o:
+	$(CC) -c -o $@ $(CFLAGS) $(INCS) $<
+
+$(TARGETS):
+	$(CC) -o $@ $< $(LIBS)
+
+asset_load: asset_load.o
+
+asset_list: asset_list.o
+
+asset_checkout: asset_checkout.o
+
+asset_checkin: asset_checkin.o
+
+asset_load.o asset_list.o asset_checkout.o asset_checkin.o: asset.h
+
+.PHONY: all clean clobber cstyle
diff --git a/examples/assetdb/README b/examples/assetdb/README
new file mode 100644
index 0000000000000000000000000000000000000000..efe64c3baf33b4c3caa66cee43e0d923f8b8e3fc
--- /dev/null
+++ b/examples/assetdb/README
@@ -0,0 +1,47 @@
+Linux NVM Library
+
+This is examples/asset/README.
+
+This example illustrates how a very simple database can be built using the
+atomic arrays provided by libpmem (pmemblk).  An array of records is created to
+track a list of assets (like books or computers for example).  Each asset is
+represented by a fixed-length record in the asset database.  Since updates to a
+single record are atomic, the file remains consistent even if interrupted
+during an update.  To run this example, follow these steps:
+
+0. Build the example with "make".  libpmem must be built first (i.e.
+   by running "make" in ../../src).  To allow the example to find
+   libpmem, you can set the environment variable:
+   	$ export LD_LIBRARY_PATH=../../src/debug
+
+1. Create the assetdb file.  This can be anywhere but the point is it
+   will be a much faster database file if it is created on a PMEM-aware
+   file system.  For example, if /pmem is the mount point for a
+   PMEM-aware file system:
+
+   	$ truncate -s 1G /pmem/assetdb
+
+2. Load up the assets from a list of assets, which is just a simple text
+   file containing asset description strings, one per line:
+
+	$ asset_load /pmem/assetdb assetlist
+
+3. Print the assets any time using:
+
+	$ asset_list /pmem/assetdb
+
+4. To mark an asset as checked out to someone:
+
+	$ asset_checkout /pmem/assetdb asset-ID name
+
+	The asset-ID is the ID printed by asset_list.  The name may require
+	quotes if it contains any whitespace or special characters.
+
+5. To mark an asset as no longer checked out:
+
+	$ asset_checkin /pmem/assetdb asset-ID
+
+As this is just an example to illustrate how pmemblk works, it may take
+some trial-and-error to find the best size for the assetdb -- the file
+must be large enough to hold about 512 bytes for each asset record, plus
+about 1% overhead used by libpmem to provide the atomicity.
diff --git a/examples/assetdb/asset.h b/examples/assetdb/asset.h
new file mode 100644
index 0000000000000000000000000000000000000000..7c98533d6022a25345cfe605ef199c6c42221bee
--- /dev/null
+++ b/examples/assetdb/asset.h
@@ -0,0 +1,43 @@
+/*
+ * Copyright (c) 2014, Intel Corporation
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ *     * Redistributions of source code must retain the above copyright
+ *       notice, this list of conditions and the following disclaimer.
+ *
+ *     * Redistributions in binary form must reproduce the above copyright
+ *       notice, this list of conditions and the following disclaimer in
+ *       the documentation and/or other materials provided with the
+ *       distribution.
+ *
+ *     * Neither the name of Intel Corporation nor the names of its
+ *       contributors may be used to endorse or promote products derived
+ *       from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY LOG OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#define	ASSET_NAME_MAX 256
+#define	ASSET_USER_NAME_MAX 64
+#define	ASSET_CHECKED_OUT 2
+#define	ASSET_FREE 1
+
+struct asset {
+	char name[ASSET_NAME_MAX];
+	char user[ASSET_USER_NAME_MAX];
+	time_t time;
+	int state;
+};
diff --git a/examples/assetdb/asset_checkin.c b/examples/assetdb/asset_checkin.c
new file mode 100644
index 0000000000000000000000000000000000000000..214a0b29bc5073d8c3635a2e47ccdf97d23fa28e
--- /dev/null
+++ b/examples/assetdb/asset_checkin.c
@@ -0,0 +1,102 @@
+/*
+ * Copyright (c) 2014, Intel Corporation
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ *     * Redistributions of source code must retain the above copyright
+ *       notice, this list of conditions and the following disclaimer.
+ *
+ *     * Redistributions in binary form must reproduce the above copyright
+ *       notice, this list of conditions and the following disclaimer in
+ *       the documentation and/or other materials provided with the
+ *       distribution.
+ *
+ *     * Neither the name of Intel Corporation nor the names of its
+ *       contributors may be used to endorse or promote products derived
+ *       from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY LOG OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+/*
+ * asset_checkin -- mark an asset as no longer checked out
+ *
+ * Usage:
+ *	asset_checkin /path/to/pm-aware/file asset-ID
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <fcntl.h>
+#include <string.h>
+#include <time.h>
+#include <libpmem.h>
+
+#include "asset.h"
+
+int
+main(int argc, char *argv[])
+{
+	int fd;
+	PMEMblk *pbp;
+	struct asset asset;
+	int assetid;
+
+	if (argc < 3) {
+		fprintf(stderr, "usage: %s assetdb asset-ID\n", argv[0]);
+		exit(1);
+	}
+
+	assetid = atoi(argv[2]);
+
+	if ((fd = open(argv[1], O_RDWR)) == -1) {
+		perror(argv[1]);
+		exit(1);
+	}
+
+	/* open an array of atomically writable elements */
+	if ((pbp = pmemblk_map(fd, sizeof (struct asset))) == NULL) {
+		perror("pmemblk_map");
+		exit(1);
+	}
+
+	close(fd);
+
+	/* read a required element in */
+	if (pmemblk_read(pbp, &asset, (off_t)assetid) < 0) {
+		perror("pmemblk_read");
+		exit(1);
+	}
+
+	/* check if it contains any data */
+	if ((asset.state != ASSET_FREE) &&
+		(asset.state != ASSET_CHECKED_OUT)) {
+		fprintf(stderr, "Asset ID %d not found", assetid);
+		exit(1);
+	}
+
+	/* change state to free, clear user name and timestamp */
+	asset.state = ASSET_FREE;
+	asset.user[0] = '\0';
+	asset.time = 0;
+
+	if (pmemblk_write(pbp, &asset, (off_t)assetid) < 0) {
+		perror("pmemblk_write");
+		exit(1);
+	}
+
+	pmemblk_unmap(pbp);
+}
diff --git a/examples/assetdb/asset_checkout.c b/examples/assetdb/asset_checkout.c
new file mode 100644
index 0000000000000000000000000000000000000000..cee3e834cfdc43ddca5f40973cca04072532b498
--- /dev/null
+++ b/examples/assetdb/asset_checkout.c
@@ -0,0 +1,109 @@
+/*
+ * Copyright (c) 2014, Intel Corporation
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ *     * Redistributions of source code must retain the above copyright
+ *       notice, this list of conditions and the following disclaimer.
+ *
+ *     * Redistributions in binary form must reproduce the above copyright
+ *       notice, this list of conditions and the following disclaimer in
+ *       the documentation and/or other materials provided with the
+ *       distribution.
+ *
+ *     * Neither the name of Intel Corporation nor the names of its
+ *       contributors may be used to endorse or promote products derived
+ *       from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY LOG OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+/*
+ * asset_checkout -- mark an asset as checked out to someone
+ *
+ * Usage:
+ *	asset_checkin /path/to/pm-aware/file asset-ID name
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <fcntl.h>
+#include <string.h>
+#include <time.h>
+#include <libpmem.h>
+
+#include "asset.h"
+
+int
+main(int argc, char *argv[])
+{
+	int fd;
+	PMEMblk *pbp;
+	struct asset asset;
+	int assetid;
+
+	if (argc < 4) {
+		fprintf(stderr, "usage: %s assetdb asset-ID name\n", argv[0]);
+		exit(1);
+	}
+
+	assetid = atoi(argv[2]);
+
+	if ((fd = open(argv[1], O_RDWR)) == -1) {
+		perror(argv[1]);
+		exit(1);
+	}
+
+	/* open an array of atomically writable elements */
+	if ((pbp = pmemblk_map(fd, sizeof (struct asset))) == NULL) {
+		perror("pmemblk_map");
+		exit(1);
+	}
+
+	close(fd);
+
+	/* read a required element in */
+	if (pmemblk_read(pbp, &asset, (off_t)assetid) < 0) {
+		perror("pmemblk_read");
+		exit(1);
+	}
+
+	/* check if it contains any data */
+	if ((asset.state != ASSET_FREE) &&
+		(asset.state != ASSET_CHECKED_OUT)) {
+		fprintf(stderr, "Asset ID %d not found", assetid);
+		exit(1);
+	}
+
+	if (asset.state == ASSET_CHECKED_OUT) {
+		fprintf(stderr, "Asset ID %d already checked out\n", assetid);
+		exit(1);
+	}
+
+	/* update user name, set checked out state, and take timestamp */
+	strncpy(asset.user, argv[3], ASSET_USER_NAME_MAX - 1);
+	asset.user[ASSET_USER_NAME_MAX - 1] = '\0';
+	asset.state = ASSET_CHECKED_OUT;
+	time(&asset.time);
+
+	/* put it back in the block */
+	if (pmemblk_write(pbp, &asset, assetid) < 0) {
+		perror("pmemblk_write");
+		exit(1);
+	}
+
+	pmemblk_unmap(pbp);
+}
diff --git a/examples/assetdb/asset_list.c b/examples/assetdb/asset_list.c
new file mode 100644
index 0000000000000000000000000000000000000000..13d7b3aba5946dd760245d1bb0657f1d0fd602de
--- /dev/null
+++ b/examples/assetdb/asset_list.c
@@ -0,0 +1,104 @@
+/*
+ * Copyright (c) 2014, Intel Corporation
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ *     * Redistributions of source code must retain the above copyright
+ *       notice, this list of conditions and the following disclaimer.
+ *
+ *     * Redistributions in binary form must reproduce the above copyright
+ *       notice, this list of conditions and the following disclaimer in
+ *       the documentation and/or other materials provided with the
+ *       distribution.
+ *
+ *     * Neither the name of Intel Corporation nor the names of its
+ *       contributors may be used to endorse or promote products derived
+ *       from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY LOG OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+/*
+ * asset_list -- list all assets in an assetdb file
+ *
+ * Usage:
+ *	asset_list /path/to/pm-aware/file
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <fcntl.h>
+#include <string.h>
+#include <time.h>
+#include <libpmem.h>
+
+#include "asset.h"
+
+int
+main(int argc, char *argv[])
+{
+	int fd;
+	PMEMblk *pbp;
+	int assetid;
+	size_t nelements;
+	struct asset asset;
+
+	if (argc < 2) {
+		fprintf(stderr, "usage: %s assetdb\n", argv[0]);
+		exit(1);
+	}
+
+	if ((fd = open(argv[1], O_RDWR)) == -1) {
+		perror(argv[1]);
+		exit(1);
+	}
+
+	/* open an array of atomically writable elements */
+	if ((pbp = pmemblk_map(fd, sizeof (struct asset))) == NULL) {
+		perror("pmemblk_map");
+		exit(1);
+	}
+
+	close(fd);
+
+	/* how many elements do we have? */
+	nelements = pmemblk_nblock(pbp);
+
+	/* print out all the elements that contain assets data */
+	for (assetid = 0; assetid < nelements; ++assetid) {
+		if (pmemblk_read(pbp, &asset, (off_t)assetid) < 0) {
+			perror("pmemblk_read");
+			exit(1);
+		}
+
+		if ((asset.state != ASSET_FREE) &&
+			(asset.state != ASSET_CHECKED_OUT)) {
+			break;
+		}
+
+		printf("Asset ID: %d\n", (int)assetid);
+		if (asset.state == ASSET_FREE)
+			printf("   State: Free\n");
+		else {
+			printf("   State: Checked out\n");
+			printf("    User: %s\n", asset.user);
+			printf("    Time: %s", ctime(&asset.time));
+		}
+		printf("    Name: %s\n", asset.name);
+	}
+
+	pmemblk_unmap(pbp);
+}
diff --git a/examples/assetdb/asset_load.c b/examples/assetdb/asset_load.c
new file mode 100644
index 0000000000000000000000000000000000000000..b4a205de87d0d8f1740a31111bb901ad56700989
--- /dev/null
+++ b/examples/assetdb/asset_load.c
@@ -0,0 +1,119 @@
+/*
+ * Copyright (c) 2014, Intel Corporation
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ *     * Redistributions of source code must retain the above copyright
+ *       notice, this list of conditions and the following disclaimer.
+ *
+ *     * Redistributions in binary form must reproduce the above copyright
+ *       notice, this list of conditions and the following disclaimer in
+ *       the documentation and/or other materials provided with the
+ *       distribution.
+ *
+ *     * Neither the name of Intel Corporation nor the names of its
+ *       contributors may be used to endorse or promote products derived
+ *       from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY LOG OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+/*
+ * asset_load -- given an assetdb file, an asset list file, load up the assets
+ *
+ * Usage:
+ *	truncate -s 1G /path/to/pm-aware/file	# before first use
+ *
+ *	asset_load /path/to/pm-aware/file assetlist
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <fcntl.h>
+#include <string.h>
+#include <time.h>
+#include <libpmem.h>
+
+#include "asset.h"
+
+int
+main(int argc, char *argv[])
+{
+	int fd;
+	FILE *fp;
+	size_t len;
+	PMEMblk *pbp;
+	int assetid = 0;
+	size_t nelements;
+	char *line = NULL;
+
+	if (argc < 3) {
+		fprintf(stderr, "usage: %s assetdb assetlist\n", argv[0]);
+		exit(1);
+	}
+
+	if ((fd = open(argv[1], O_RDWR)) < 0) {
+		perror(argv[1]);
+		exit(1);
+	}
+
+	/* create an array of atomically writable elements */
+	if ((pbp = pmemblk_map(fd, sizeof (struct asset))) == NULL) {
+		perror("pmemblk_map");
+		exit(1);
+	}
+	close(fd);
+
+	nelements = pmemblk_nblock(pbp);
+
+	if ((fp = fopen(argv[2], "r")) == NULL) {
+		perror(argv[2]);
+		exit(1);
+	}
+
+	/*
+	 * Read in all the assets from the assetfile and put them in the
+	 * array, if a name of the asset is longer than ASSET_NAME_SIZE_MAX,
+	 * truncate it.
+	 */
+	while (getline(&line, &len, fp) != -1) {
+		struct asset asset;
+
+		if (assetid >= nelements) {
+			fprintf(stderr, "%s: too many assets to fit in %s "
+					"(only %d assets loaded)\n",
+					argv[2], argv[1], assetid);
+			exit(1);
+		}
+
+		memset(&asset, '\0', sizeof (asset));
+		asset.state = ASSET_FREE;
+		strncpy(asset.name, line, ASSET_NAME_MAX - 1);
+		asset.name[ASSET_NAME_MAX - 1] = '\0';
+
+		if (pmemblk_write(pbp, &asset, (off_t)assetid) < 0) {
+			perror("pmemblk_write");
+			exit(1);
+		}
+
+		assetid++;
+	}
+
+	free(line);
+	fclose(fp);
+
+	pmemblk_unmap(pbp);
+}
diff --git a/examples/logfile/.gitignore b/examples/logfile/.gitignore
new file mode 100644
index 0000000000000000000000000000000000000000..3b2f05823afb853d05ad3be91bbe2b7fce239db2
--- /dev/null
+++ b/examples/logfile/.gitignore
@@ -0,0 +1,2 @@
+addlog
+printlog
diff --git a/examples/logfile/Makefile b/examples/logfile/Makefile
new file mode 100644
index 0000000000000000000000000000000000000000..457640325506bfb088088197537d2de1667b9691
--- /dev/null
+++ b/examples/logfile/Makefile
@@ -0,0 +1,66 @@
+#
+# Copyright (c) 2014, Intel Corporation
+#
+# Redistribution and use in source and binary forms, with or without
+# modification, are permitted provided that the following conditions
+# are met:
+#
+#     * Redistributions of source code must retain the above copyright
+#       notice, this list of conditions and the following disclaimer.
+#
+#     * Redistributions in binary form must reproduce the above copyright
+#       notice, this list of conditions and the following disclaimer in
+#       the documentation and/or other materials provided with the
+#       distribution.
+#
+#     * Neither the name of Intel Corporation nor the names of its
+#       contributors may be used to endorse or promote products derived
+#       from this software without specific prior written permission.
+#
+# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+#
+
+#
+# examples/logfile/Makefile -- build the NVM Library examples
+#
+TARGETS = addlog printlog
+INCS = -I../../src/include
+CFLAGS = -std=gnu99 -ggdb -Wall -Werror
+LIBS = -L../../src/debug -pthread
+
+addlog printlog: LIBS += -lpmem
+
+all: $(TARGETS)
+
+clean:
+	$(RM) *.o core a.out
+
+clobber: clean
+	$(RM) $(TARGETS)
+
+cstyle:
+	../../utils/cstyle -pP *.[ch]
+
+.c.o:
+	$(CC) -c -o $@ $(CFLAGS) $(INCS) $<
+
+$(TARGETS):
+	$(CC) -o $@ $< $(LIBS)
+
+addlog: addlog.o
+
+printlog: printlog.o
+
+addlog.o printlog.o: logentry.h
+
+.PHONY: all clean clobber cstyle
diff --git a/examples/logfile/README b/examples/logfile/README
new file mode 100644
index 0000000000000000000000000000000000000000..82024b8f18a87da084dcdaeb079828d81913b296
--- /dev/null
+++ b/examples/logfile/README
@@ -0,0 +1,34 @@
+Linux NVM Library
+
+This is examples/logfile/README.
+
+The example in this directory uses persistent memory to implement a
+simple log file using the libpmem "pmemlog" functions.  To run this
+example, follow these steps:
+
+0. Build the example with "make".  libpmem must be built first (i.e.
+   by running "make" in ../../src).  To allow the example to find
+   libpmem, you can set the environment variable:
+   	$ export LD_LIBRARY_PATH=../../src/debug
+
+1. Create the log file.  This can be anywhere but the point is it
+   will be a much faster log file if it is created on a PMEM-aware
+   file system.  For example, if /pmem is the mount point for a
+   PMEM-aware file system:
+
+   	$ truncate -s 1G /pmem/logfile
+
+2. Append to the log file as many times as you like:
+
+	$ addlog /pmem/logfile "Hello there."
+	$ addlog /pmem/logfile "First line." "Second line."
+	...
+
+3. Print the contents of the log any time using:
+
+	$ printlog /pmem/logfile
+
+4. The printlog command will throw away the current log file contents
+   aftert printing it if given the -t argument:
+
+   	$ printlog -t /pmem/logfile
diff --git a/examples/logfile/addlog.c b/examples/logfile/addlog.c
new file mode 100644
index 0000000000000000000000000000000000000000..972cd0fcc12fd4ee3f4de3f3eca9026629b456c1
--- /dev/null
+++ b/examples/logfile/addlog.c
@@ -0,0 +1,130 @@
+/*
+ * Copyright (c) 2014, Intel Corporation
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ *     * Redistributions of source code must retain the above copyright
+ *       notice, this list of conditions and the following disclaimer.
+ *
+ *     * Redistributions in binary form must reproduce the above copyright
+ *       notice, this list of conditions and the following disclaimer in
+ *       the documentation and/or other materials provided with the
+ *       distribution.
+ *
+ *     * Neither the name of Intel Corporation nor the names of its
+ *       contributors may be used to endorse or promote products derived
+ *       from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY LOG OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+/*
+ * addlog -- given a log file, append a log entry
+ *
+ * Usage:
+ *	truncate -s 1G /path/to/pm-aware/file	# before first use
+ *
+ *	addlog /path/to/pm-aware/file "first line of entry" "second line"
+ *
+ *	addlog ...		# appends to the log
+ *
+ *	addlog ...		# appends to the log
+ */
+
+#include <stdio.h>
+#include <fcntl.h>
+#include <time.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+#include <libpmem.h>
+
+#include "logentry.h"
+
+int
+main(int argc, char *argv[])
+{
+	int fd;
+	PMEMlog *plp;
+	struct logentry header;
+	struct iovec *iovp;
+	struct iovec *next_iovp;
+	int iovcnt;
+
+	if (argc < 3) {
+		fprintf(stderr, "usage: %s filename lines...\n", argv[0]);
+		exit(1);
+	}
+
+	if ((fd = open(argv[1], O_RDWR)) < 0) {
+		perror(argv[1]);
+		exit(1);
+	}
+
+	if ((plp = pmemlog_map(fd)) == NULL) {
+		perror("pmemlog_map");
+		exit(1);
+	}
+
+	/* fill in the header */
+	time(&header.timestamp);
+	header.pid = getpid();
+
+	/*
+	 * Create an iov for pmemlog_appendv().  For each argument given,
+	 * allocate two entries (one for the string, one for the newline
+	 * appended to the string).  Allocate 1 additional entry for the
+	 * header that gets prepended to the entry.
+	 */
+	iovcnt = (argc - 2) * 2 + 1;
+	if ((iovp = malloc(sizeof (*iovp) * iovcnt)) == NULL) {
+		perror("malloc");
+		exit(1);
+	}
+	next_iovp = iovp;
+
+	/* put the header into iov first */
+	next_iovp->iov_base = &header;
+	next_iovp->iov_len = sizeof (header);
+	next_iovp++;
+
+	/*
+	 * Now put each arg in, following it with the string "\n".
+	 * Calculate a total character count in header.len along the way.
+	 */
+	header.len = 0;
+	for (int arg = 2; arg < argc; arg++) {
+		/* add the string given */
+		next_iovp->iov_base = argv[arg];
+		next_iovp->iov_len = strlen(argv[arg]);
+		header.len += next_iovp->iov_len;
+		next_iovp++;
+
+		/* add the newline */
+		next_iovp->iov_base = "\n";
+		next_iovp->iov_len = 1;
+		header.len += 1;
+		next_iovp++;
+	}
+
+	/* atomically add it all to the log */
+	if (pmemlog_appendv(plp, iovp, iovcnt) < 0) {
+		perror("pmemlog_appendv");
+		exit(1);
+	}
+
+	pmemlog_unmap(plp);
+	close(fd);
+}
diff --git a/examples/logfile/logentry.h b/examples/logfile/logentry.h
new file mode 100644
index 0000000000000000000000000000000000000000..3403e8fc213960bd2b6e198e9d6b0c60ecae056d
--- /dev/null
+++ b/examples/logfile/logentry.h
@@ -0,0 +1,45 @@
+/*
+ * Copyright (c) 2014, Intel Corporation
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ *     * Redistributions of source code must retain the above copyright
+ *       notice, this list of conditions and the following disclaimer.
+ *
+ *     * Redistributions in binary form must reproduce the above copyright
+ *       notice, this list of conditions and the following disclaimer in
+ *       the documentation and/or other materials provided with the
+ *       distribution.
+ *
+ *     * Neither the name of Intel Corporation nor the names of its
+ *       contributors may be used to endorse or promote products derived
+ *       from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY LOG OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef LOGENTRY_H_
+#define	LOGENTRY_H_
+
+/*
+ * info prepended to each log entry...
+ */
+struct logentry {
+	size_t len;		/* length of the rest of the log entry */
+	time_t timestamp;
+	pid_t pid;
+};
+
+#endif /* LOGENTRY_H_ */
diff --git a/examples/logfile/printlog.c b/examples/logfile/printlog.c
new file mode 100644
index 0000000000000000000000000000000000000000..12d22ddb02b3080a84404eb6a3a55fa66074e8c5
--- /dev/null
+++ b/examples/logfile/printlog.c
@@ -0,0 +1,120 @@
+/*
+ * Copyright (c) 2014, Intel Corporation
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ *     * Redistributions of source code must retain the above copyright
+ *       notice, this list of conditions and the following disclaimer.
+ *
+ *     * Redistributions in binary form must reproduce the above copyright
+ *       notice, this list of conditions and the following disclaimer in
+ *       the documentation and/or other materials provided with the
+ *       distribution.
+ *
+ *     * Neither the name of Intel Corporation nor the names of its
+ *       contributors may be used to endorse or promote products derived
+ *       from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY LOG OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+/*
+ * printlog -- given a log file, print the entries
+ *
+ * Usage:
+ *	printlog [-t] /path/to/pm-aware/file
+ *
+ * -t option means truncate the file after printing it.
+ */
+
+#include <stdio.h>
+#include <fcntl.h>
+#include <time.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+#include <libpmem.h>
+
+#include "logentry.h"
+
+/*
+ * printlog -- callback function called when walking the log
+ */
+int
+printlog(const void *buf, size_t len, void *arg)
+{
+	const void *endp = buf + len;	/* first byte after log contents */
+
+	/* for each entry in the log... */
+	while (buf < endp) {
+		struct logentry *headerp = (struct logentry *)buf;
+		buf += sizeof (struct logentry);
+
+		/* print the header */
+		printf("Entry from pid: %ld\n", (long)headerp->pid);
+		printf("       Created: %s", ctime(&headerp->timestamp));
+		printf("      Contents:\n");
+
+		/* print the log data itself */
+		fwrite(buf, headerp->len, 1, stdout);
+		buf += headerp->len;
+	}
+
+	return 0;
+}
+
+int
+main(int argc, char *argv[])
+{
+	int opt;
+	int tflag = 0;
+	int fd;
+	PMEMlog *plp;
+
+	while ((opt = getopt(argc, argv, "t")) != -1)
+		switch (opt) {
+		case 't':
+			tflag = 1;
+			break;
+
+		default:
+			fprintf(stderr, "usage: %s [-t] file\n", argv[0]);
+			exit(1);
+		}
+
+	if (optind >= argc) {
+		fprintf(stderr, "usage: %s [-t] file\n", argv[0]);
+		exit(1);
+	}
+
+	if ((fd = open(argv[optind], O_RDWR)) < 0) {
+		perror(argv[optind]);
+		exit(1);
+	}
+
+	if ((plp = pmemlog_map(fd)) == NULL) {
+		perror("pmemlog_map");
+		exit(1);
+	}
+
+	/* the rest of the work happens in printlog() above */
+	pmemlog_walk(plp, 0, printlog, NULL);
+
+	if (tflag)
+		pmemlog_rewind(plp);
+
+	pmemlog_unmap(plp);
+	close(fd);
+}
diff --git a/examples/pmem_example.c b/examples/pmem_example.c
new file mode 100644
index 0000000000000000000000000000000000000000..bbd2dd25036ffeca91b13f9e36bfad1868e70386
--- /dev/null
+++ b/examples/pmem_example.c
@@ -0,0 +1,45 @@
+#include <sys/mman.h>
+#include <fcntl.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <string.h>
+#include <libpmem.h>
+
+int
+main(int argc, char *argv[])
+{
+	int fd;
+	char *pmaddr;
+
+	/* memory map some persistent memory */
+	if ((fd = open("/my/pmem-aware/fs/myfile", O_RDWR)) < 0) {
+		perror("open");
+		exit(1);
+	}
+
+	/* just map 4k for this example */
+	if ((pmaddr = mmap(NULL, 4096, PROT_READ|PROT_WRITE,
+				MAP_SHARED, fd, 0)) == MAP_FAILED) {
+		perror("mmap");
+		exit(1);
+	}
+	close(fd);
+
+	/* store a string to the persistent memory */
+	strcpy(pmaddr, "hello, persistent memory");
+
+	/*
+	 * The above stores may or may not be sitting in cache at
+	 * this point, depending on other system activity causing
+	 * cache pressure.  Now force the change to be durable
+	 * (flushed all the say to the persistent memory).  If
+	 * unsure whether the file is really persistent memory,
+	 * use pmem_is_pmem() to decide whether pmem_persist() can
+	 * be used, or whether msync() must be used.
+	 */
+	if (pmem_is_pmem(pmaddr, 4096))
+		pmem_persist(pmaddr, 4096, 0);
+	else
+		msync(pmaddr, 4096, MS_SYNC);
+}
diff --git a/examples/pmemblk_example.c b/examples/pmemblk_example.c
new file mode 100644
index 0000000000000000000000000000000000000000..a937760bd29e045e78b102ba4f35843db136d42a
--- /dev/null
+++ b/examples/pmemblk_example.c
@@ -0,0 +1,67 @@
+#include <stdio.h>
+#include <fcntl.h>
+#include <errno.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <string.h>
+#include <libpmem.h>
+
+/* size of each element in the PMEM pool (bytes) */
+#define	ELEMENT_SIZE ((size_t)1024)
+
+int
+main(int argc, char *argv[])
+{
+	int fd;
+	PMEMblk *pbp;
+	size_t nelements;
+	char buf[ELEMENT_SIZE];
+
+	/* create file on PMEM-aware file system */
+	if ((fd = open("/my/pmem-aware/fs/myfile",
+					O_CREAT|O_RDWR, 0666)) < 0) {
+		perror("open");
+		exit(1);
+	}
+
+	/* pre-allocate 2GB of persistent memory */
+	if ((errno = posix_fallocate(fd, (off_t)0,
+					(size_t)1024 * 1024 * 1024 * 2)) != 0) {
+		perror("posix_fallocate");
+		exit(1);
+	}
+
+	/* create an array of atomically writable elements */
+	if ((pbp = pmemblk_map(fd, ELEMENT_SIZE)) == NULL) {
+		perror("pmemblk_map");
+		exit(1);
+	}
+
+	/* how many elements fit into the PMEM pool? */
+	nelements = pmemblk_nblock(pbp);
+	printf("file holds %zu elements\n", nelements);
+
+	/* store a block at index 5 */
+	strcpy(buf, "hello, world");
+	if (pmemblk_write(pbp, buf, 5) < 0) {
+		perror("pmemblk_write");
+		exit(1);
+	}
+
+	/* read the block at index 10 (reads as zeros initially) */
+	if (pmemblk_read(pbp, buf, 10) < 0) {
+		perror("pmemblk_write");
+		exit(1);
+	}
+
+	/* zero out the block at index 5 */
+	if (pmemblk_set_zero(pbp, 5) < 0) {
+		perror("pmemblk_set_zero");
+		exit(1);
+	}
+
+	/* ... */
+
+	pmemblk_unmap(pbp);
+	close(fd);
+}
diff --git a/examples/pmemlog_example.c b/examples/pmemlog_example.c
new file mode 100644
index 0000000000000000000000000000000000000000..9ca08a0d224bdd8aef22caac671aa8c40f60086a
--- /dev/null
+++ b/examples/pmemlog_example.c
@@ -0,0 +1,67 @@
+#include <stdio.h>
+#include <fcntl.h>
+#include <errno.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <string.h>
+#include <libpmem.h>
+
+/* log processing callback for use with pmemlog_walk() */
+int
+printit(const void *buf, size_t len, void *arg)
+{
+	fwrite(buf, len, 1, stdout);
+	return 0;
+}
+
+int
+main(int argc, char *argv[])
+{
+	int fd;
+	PMEMlog *plp;
+	size_t nbyte;
+	char *str;
+
+	/* create file on PMEM-aware file system */
+	if ((fd = open("/my/pmem-aware/fs/myfile",
+					O_CREAT|O_RDWR, 0666)) < 0) {
+		perror("open");
+		exit(1);
+	}
+
+	/* pre-allocate 2GB of persistent memory */
+	if ((errno = posix_fallocate(fd, (off_t)0,
+					(size_t)1024 * 1024 * 1024 * 2)) != 0) {
+		perror("posix_fallocate");
+		exit(1);
+	}
+
+	/* create a persistent memory resident log */
+	if ((plp = pmemlog_map(fd)) == NULL) {
+		perror("pmemlog_map");
+		exit(1);
+	}
+
+	/* how many bytes does the log hold? */
+	nbyte = pmemlog_nbyte(plp);
+	printf("log holds %zu bytes\n", nbyte);
+
+	/* append to the log... */
+	str = "This is the first string appended\n";
+	if (pmemlog_append(plp, str, strlen(str)) < 0) {
+		perror("pmemlog_append");
+		exit(1);
+	}
+	str = "This is the second string appended\n";
+	if (pmemlog_append(plp, str, strlen(str)) < 0) {
+		perror("pmemlog_append");
+		exit(1);
+	}
+
+	/* print the log contents */
+	printf("log contains:\n");
+	pmemlog_walk(plp, 0, printit, NULL);
+
+	pmemlog_unmap(plp);
+	close(fd);
+}
diff --git a/examples/vmem_example.c b/examples/vmem_example.c
new file mode 100644
index 0000000000000000000000000000000000000000..a6e5f01f4693502b24b8a9e5cd3af7a1998454c3
--- /dev/null
+++ b/examples/vmem_example.c
@@ -0,0 +1,30 @@
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <libvmem.h>
+
+int
+main(int argc, char *argv[])
+{
+	VMEM *vmp;
+	char *ptr;
+
+	/* create minimum size pool of memory */
+	if ((vmp = vmem_pool_create("/my/pmem-aware/fs",
+					VMEM_MIN_POOL)) == NULL) {
+		perror("vmem_pool_create");
+		exit(1);
+	}
+
+	if ((ptr = vmem_malloc(vmp, 100)) == NULL) {
+		perror("vmem_malloc");
+		exit(1);
+	}
+
+	strcpy(ptr, "hello, world");
+
+	/* give the memory back */
+	vmem_free(vmp, ptr);
+
+	/* ... */
+}
diff --git a/src/.gitignore b/src/.gitignore
new file mode 100644
index 0000000000000000000000000000000000000000..2e2c8c7deeff768b9d7894be565f7e4f806beb47
--- /dev/null
+++ b/src/.gitignore
@@ -0,0 +1,8 @@
+*.so
+*.so.*
+*.a
+tags
+TAGS
+cscope.in.out
+cscope.out
+cscope.po.out
diff --git a/src/Makefile b/src/Makefile
new file mode 100644
index 0000000000000000000000000000000000000000..efc116970c0efcd1a372a5e521975ecc65452304
--- /dev/null
+++ b/src/Makefile
@@ -0,0 +1,87 @@
+#
+# Copyright (c) 2014, Intel Corporation
+#
+# Redistribution and use in source and binary forms, with or without
+# modification, are permitted provided that the following conditions
+# are met:
+#
+#     * Redistributions of source code must retain the above copyright
+#       notice, this list of conditions and the following disclaimer.
+#
+#     * Redistributions in binary form must reproduce the above copyright
+#       notice, this list of conditions and the following disclaimer in
+#       the documentation and/or other materials provided with the
+#       distribution.
+#
+#     * Neither the name of Intel Corporation nor the names of its
+#       contributors may be used to endorse or promote products derived
+#       from this software without specific prior written permission.
+#
+# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+#
+
+#
+# src/Makefile -- build the NVM Library
+#
+VARIANTS = debug nondebug
+
+JEMALLOC_DIR = $(CURDIR)/jemalloc
+export JEMALLOC_DIR
+
+HEADERS_DESTDIR = $(DESTDIR)/usr/include
+HEADERS_INSTALL = include/libpmem.h include/libvmem.h
+
+SCOPEFILES = *.[ch] include/*.[ch] jemalloc/src/*.[ch]\
+	     $(JEMALLOC_DIR)/include/jemalloc/*.h\
+	     $(JEMALLOC_DIR)/include/jemalloc/internal/*.h
+
+all     : TARGET = all
+clean   : TARGET = clean
+clobber : TARGET = clobber
+jeconfig: TARGET = jeconfig
+jemalloc: TARGET = jemalloc
+install : TARGET = install
+
+all jeconfig jemalloc clean clobber install: $(VARIANTS)
+
+$(VARIANTS):
+	$(MAKE) -C $@ $(TARGET)
+
+clean:
+	$(MAKE) -C test clean
+	$(RM) tags cscope.in.out cscope.out cscope.po.out
+
+clobber:
+	$(MAKE) -C test clobber
+
+test: $(VARIANTS)
+	$(MAKE) -C test all
+	$(MAKE) -C $(JEMALLOC_DIR) tests
+
+check: test
+	cd test && ./RUNTESTS
+	$(MAKE) -C $(JEMALLOC_DIR) check
+
+cscope:
+	cscope -q -b $(SCOPEFILES)
+	ctags -e $(SCOPEFILES)
+
+cstyle:
+	../utils/cstyle -pP *.[ch] include/*.[ch]
+	$(MAKE) -C test cstyle
+
+install:
+	install -d $(HEADERS_DESTDIR)
+	install -p -m 0644 $(HEADERS_INSTALL) $(HEADERS_DESTDIR)
+
+.PHONY: all jeconfig jemalloc clean clobber test check cscope cstyle install $(VARIANTS)
diff --git a/src/Makefile.inc b/src/Makefile.inc
new file mode 100644
index 0000000000000000000000000000000000000000..e27358fa1b93a7a352590529749849f0f9432812
--- /dev/null
+++ b/src/Makefile.inc
@@ -0,0 +1,155 @@
+# Copyright (c) 2014, Intel Corporation
+#
+# Redistribution and use in source and binary forms, with or without
+# modification, are permitted provided that the following conditions
+# are met:
+#
+#     * Redistributions of source code must retain the above copyright
+#       notice, this list of conditions and the following disclaimer.
+#
+#     * Redistributions in binary form must reproduce the above copyright
+#       notice, this list of conditions and the following disclaimer in
+#       the documentation and/or other materials provided with the
+#       distribution.
+#
+#     * Neither the name of Intel Corporation nor the names of its
+#       contributors may be used to endorse or promote products derived
+#       from this software without specific prior written permission.
+#
+# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+#
+# src/Makefile.inc -- common Makefile rules for NVM library
+#
+
+JEMALLOC_MAKE_NAME ?= Makefile
+JEMALLOC_OBJROOT ?=
+JEMALLOC_MAKE = $(JEMALLOC_DIR)/$(JEMALLOC_MAKE_NAME)
+JEMALLOC_CFG = $(JEMALLOC_DIR)/configure
+JEMALLOC_CFG_AC = $(JEMALLOC_DIR)/configure.ac
+JEMALLOC_LIB_NAME = libjemalloc_pic.a
+JEMALLOC_LIB = $(JEMALLOC_DIR)/$(JEMALLOC_OBJROOT)lib/$(JEMALLOC_LIB_NAME)
+
+JECONFIG_FILE = ../jemalloc.cfg
+JECONFIG = $(shell cat $(JECONFIG_FILE))
+
+MACHINE := $(shell uname -m)
+
+ifeq ($(MACHINE), x86_64)
+ifneq ($(wildcard /usr/lib64),)
+LIBDIR = usr/lib64
+else
+LIBDIR = usr/lib
+endif
+else
+LIBDIR = usr/lib
+endif
+
+LIBS_DESTDIR = $(DESTDIR)/$(LIBDIR)/$(VARIANT_DESTDIR)
+
+vpath %.c ..
+vpath %.h .. ../include
+INCS = -I.. -I../include
+
+CFLAGS = -std=gnu99 -ggdb -Wall -Werror
+LN = ln
+TARGETS = libpmem.a libpmem.so libvmem.a libvmem.so
+libpmem.a libpmem.so: LIBS += -luuid
+COMMONOBJS = out.o util.o
+PMEMOBJS = libpmem.o blk.o btt.o log.o pmem.o trn.o $(COMMONOBJS)
+VMEMOBJS = libvmem.o vmem.o $(COMMONOBJS)
+PMEMMAPFILE = ../libpmem.map
+VMEMMAPFILE = ../libvmem.map
+PMEMSOVERSION = 1
+VMEMSOVERSION = 1
+EXTRA_JECONFIG =
+INSTALL_LINKS = libpmem.so.$(PMEMSOVERSION) libvmem.so.$(VMEMSOVERSION)
+
+SRCVERSION := $(shell git describe --tags)
+out.o: CFLAGS += -DSRCVERSION=\"$(SRCVERSION)\"
+
+all: $(TARGETS)
+
+jemalloc: $(JEMALLOC_LIB)
+
+jeconfig $(JEMALLOC_MAKE): $(JEMALLOC_CFG) $(JECONFIG_FILE)
+	cd $(JEMALLOC_DIR) && \
+	    ./configure $(JECONFIG) $(EXTRA_JECONFIG)
+	-mv -f $(JEMALLOC_DIR)/Makefile $(JEMALLOC_MAKE)
+
+$(JEMALLOC_CFG): $(JEMALLOC_CFG_AC)
+	cd $(JEMALLOC_DIR) && \
+	    autoconf
+
+$(VMEMOBJS): $(JEMALLOC_LIB)
+
+$(JEMALLOC_LIB): $(JEMALLOC_MAKE)
+	make objroot=$(JEMALLOC_OBJROOT) -f $(JEMALLOC_MAKE_NAME) -C $(JEMALLOC_DIR) all
+
+libpmem.a: $(PMEMOBJS)
+	$(LD) -o $*_unscoped.o -r $(PMEMOBJS)
+	objcopy --localize-hidden `sed -n 's/^	*\([a-zA-Z0-9_]*\);$$/-G \1/p' $(PMEMMAPFILE)` $*_unscoped.o $*_all.o
+	$(AR) rv $@ $*_all.o
+
+libpmem.so: $(PMEMOBJS)
+	$(CC) -shared -Wl,--version-script=$(PMEMMAPFILE),-soname,$@.$(PMEMSOVERSION) -o $@ $(PMEMOBJS) $(LIBS)
+	$(RM) $@.$(PMEMSOVERSION)
+	$(LN) -s $@ $@.$(PMEMSOVERSION)
+
+
+libvmem.a libvmem.so: INCS += -I$(JEMALLOC_DIR)/include/jemalloc
+
+libvmem.a: $(VMEMOBJS) $(JEMALLOC_LIB)
+	$(LD) -o $*_unscoped.o -r $(VMEMOBJS) $(JEMALLOC_LIB)
+	objcopy --localize-hidden `sed -n 's/^	*\([a-zA-Z0-9_]*\);$$/-G \1/p' $(VMEMMAPFILE)` $*_unscoped.o $*_all.o
+	$(AR) rv $@ $*_all.o
+
+libvmem.so: $(VMEMOBJS) $(JEMALLOC_LIB)
+	$(CC) -shared -Wl,--version-script=$(VMEMMAPFILE),-soname,$@.$(VMEMSOVERSION) -o $@ $(VMEMOBJS) $(JEMALLOC_LIB)
+	$(RM) $@.$(VMEMSOVERSION)
+	$(LN) -s $@ $@.$(VMEMSOVERSION)
+
+.c.o:
+	$(CC) -c -o $@ $(CFLAGS) $(INCS) -fPIC $<
+
+clean:
+	$(RM) *.o core a.out
+	@if [ -f $(JEMALLOC_MAKE) ];\
+	then\
+		make objroot=$(JEMALLOC_OBJROOT) -f $(JEMALLOC_MAKE_NAME) -C $(JEMALLOC_DIR) clean;\
+	fi
+
+clobber: clean
+	$(RM) $(TARGETS) *.so.[0-9]*
+	-make cfgoutputs_out+=$(JEMALLOC_MAKE) objroot=$(JEMALLOC_OBJROOT) -f $(JEMALLOC_MAKE_NAME) -C $(JEMALLOC_DIR) distclean
+	rm -rf $(JEMALLOC_CFG)
+
+install: $(TARGETS) $(INSTALL_LINKS)
+	install -d $(LIBS_DESTDIR)
+	install -p -m 0755 $(TARGETS) $(LIBS_DESTDIR)
+	cp -d $(INSTALL_LINKS) $(LIBS_DESTDIR)
+
+.PHONY: all clean clobber jeconfig jemalloc install
+
+libpmem.o: libpmem.c libpmem.h pmem.h util.h out.h
+blk.o: blk.c libpmem.h pmem.h blk.h util.h out.h
+btt.o: btt.c util.h btt.h btt_layout.h
+log.o: log.c libpmem.h pmem.h log.h util.h out.h
+pmem.o: pmem.c libpmem.h pmem.h out.h
+trn.o: trn.c libpmem.h pmem.h trn.h util.h out.h
+
+libvmem.o: libvmem.c libvmem.h vmem.h util.h out.h
+vmem.o: vmem.c libvmem.h util.h out.h
+
+out.o: out.c out.h
+util.o: util.c util.h out.h
diff --git a/src/README b/src/README
new file mode 100644
index 0000000000000000000000000000000000000000..dbc33077df6b86a57996fd5135bbcd95a602c2b8
--- /dev/null
+++ b/src/README
@@ -0,0 +1,20 @@
+Linux NVM Library
+
+This is src/README.
+
+This directory contains the source for the NVM Library.
+
+libvmem is largely just a wrapper around a modified jemalloc
+library.  See the "jemalloc" subdirectory and the git change
+log for those files for details.
+
+The subdirectory "include" contains header files that get delivered
+along with the libraries.  Everything else is internal to the libraries
+and lives in this directory.
+
+Two versions of the libraries are built, a debug version and a nondebug
+version.  The object files and the libraries themselves end up in the
+subdirectories "debug" and "nondebug".
+
+See the top-level README for build, test, and installation instructions.
+The basic "make" and "make test" targets also work from this directory.
diff --git a/src/blk.c b/src/blk.c
new file mode 100644
index 0000000000000000000000000000000000000000..2d2e08502a46bd92fa8651f28b6cd83d98883969
--- /dev/null
+++ b/src/blk.c
@@ -0,0 +1,572 @@
+/*
+ * Copyright (c) 2014, Intel Corporation
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ *     * Redistributions of source code must retain the above copyright
+ *       notice, this list of conditions and the following disclaimer.
+ *
+ *     * Redistributions in binary form must reproduce the above copyright
+ *       notice, this list of conditions and the following disclaimer in
+ *       the documentation and/or other materials provided with the
+ *       distribution.
+ *
+ *     * Neither the name of Intel Corporation nor the names of its
+ *       contributors may be used to endorse or promote products derived
+ *       from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY LOG OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+/*
+ * blk.c -- block memory pool entry points for libpmem
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <sys/types.h>
+#include <sys/param.h>
+#include <sys/stat.h>
+#include <signal.h>
+#include <fcntl.h>
+#include <unistd.h>
+#include <errno.h>
+#include <time.h>
+#include <stdint.h>
+#include <uuid/uuid.h>
+#include <pthread.h>
+#include <endian.h>
+#include <libpmem.h>
+
+#include "pmem.h"
+#include "util.h"
+#include "out.h"
+#include "btt.h"
+#include "blk.h"
+
+/*
+ * blk_init -- (internal) load-time initialization for blk
+ *
+ * Called automatically by the run-time loader.
+ */
+__attribute__((constructor))
+static void
+blk_init(void)
+{
+	out_init(LOG_PREFIX, LOG_LEVEL_VAR, LOG_FILE_VAR);
+	LOG(3, NULL);
+	util_init();
+}
+
+/*
+ * lane_enter -- (internal) acquire a unique lane number
+ */
+static int
+lane_enter(PMEMblk *pbp)
+{
+	int mylane;
+
+	mylane = __sync_fetch_and_add(&pbp->next_lane, 1) % pbp->nlane;
+
+	/* lane selected, grab the per-lane lock */
+	if (pthread_mutex_lock(&pbp->locks[mylane]) < 0) {
+		LOG(1, "!pthread_mutex_lock");
+		return -1;
+	}
+
+	return mylane;
+}
+
+/*
+ * lane_exit -- (internal) drop lane lock
+ */
+static int
+lane_exit(PMEMblk *pbp, int mylane)
+{
+	if (pthread_mutex_unlock(&pbp->locks[mylane]) < 0) {
+		LOG(1, "!pthread_mutex_unlock");
+		return -1;
+	}
+
+	return 0;
+}
+
+/*
+ * nsread -- (internal) read data from the namespace encapsulating the BTT
+ *
+ * This routine is provided to btt_init() to allow the btt module to
+ * do I/O on the memory pool containing the BTT layout.
+ */
+static int
+nsread(void *ns, int lane, void *buf, size_t count, off_t off)
+{
+	struct pmemblk *pbp = (struct pmemblk *)ns;
+
+	LOG(13, "pbp %p lane %d count %zu off %zu", pbp, lane, count, off);
+
+	if (off + count >= pbp->datasize) {
+		LOG(1, "offset + count (%zu) past end of data area (%zu)",
+				off + count, pbp->datasize - 1);
+		errno = EINVAL;
+		return -1;
+	}
+
+	memcpy(buf, pbp->data + off, count);
+
+	return 0;
+}
+
+/*
+ * nswrite -- (internal) write data to the namespace encapsulating the BTT
+ *
+ * This routine is provided to btt_init() to allow the btt module to
+ * do I/O on the memory pool containing the BTT layout.
+ */
+static int
+nswrite(void *ns, int lane, const void *buf, size_t count, off_t off)
+{
+	struct pmemblk *pbp = (struct pmemblk *)ns;
+
+	LOG(13, "pbp %p lane %d count %zu off %zu", pbp, lane, count, off);
+
+	if (off + count >= pbp->datasize) {
+		LOG(1, "offset + count (%zu) past end of data area (%zu)",
+				off + count, pbp->datasize - 1);
+		errno = EINVAL;
+		return -1;
+	}
+
+	void *dest = pbp->data + off;
+	memcpy(dest, buf, count);
+	libpmem_persist(pbp->is_pmem, dest, count);
+
+	return 0;
+}
+
+/*
+ * nsmap -- (internal) allow direct access to a range of a namespace
+ *
+ * The caller requests a range to be "mapped" but the return value
+ * may indicate a smaller amount (in which case the caller is expected
+ * to call back later for another mapping).
+ *
+ * This routine is provided to btt_init() to allow the btt module to
+ * do I/O on the memory pool containing the BTT layout.
+ */
+static int
+nsmap(void *ns, int lane, void **addrp, size_t len, off_t off)
+{
+	struct pmemblk *pbp = (struct pmemblk *)ns;
+
+	LOG(12, "pbp %p lane %d len %zu off %zu", pbp, lane, len, off);
+
+	if (off + len >= pbp->datasize) {
+		LOG(1, "offset + len (%zu) past end of data area (%zu)",
+				off + len, pbp->datasize - 1);
+		errno = EINVAL;
+		return -1;
+	}
+
+	/*
+	 * Since the entire file is memory-mapped, this callback
+	 * can always provide the entire length requested.
+	 */
+	*addrp = pbp->data + off;
+
+	LOG(12, "returning addr %p", *addrp);
+
+	return len;
+}
+
+/*
+ * nssync -- (internal) flush changes made to a namespace range
+ *
+ * This is used in conjunction with the addresses handed out by
+ * nsmap() above.  There's no need to sync things written via
+ * nswrite() since those changes are flushed each time nswrite()
+ * is called.
+ *
+ * This routine is provided to btt_init() to allow the btt module to
+ * do I/O on the memory pool containing the BTT layout.
+ */
+static void
+nssync(void *ns, int lane, void *addr, size_t len)
+{
+	struct pmemblk *pbp = (struct pmemblk *)ns;
+
+	LOG(12, "pbp %p lane %d addr %p len %zu", pbp, lane, addr, len);
+
+	libpmem_persist(pbp->is_pmem, addr, len);
+}
+
+/* callbacks for btt_init() */
+static const struct ns_callback ns_cb = {
+	nsread,
+	nswrite,
+	nsmap,
+	nssync
+};
+
+/*
+ * pmemblk_map_common -- (internal) map a block memory pool
+ *
+ * This routine does all the work, but takes a rdonly flag so internal
+ * calls can map a read-only pool if required.
+ *
+ * Passing in bsize == 0 means a valid pool header must exist (which
+ * will supply the block size).
+ */
+static PMEMblk *
+pmemblk_map_common(int fd, size_t bsize, int rdonly)
+{
+	LOG(3, "fd %d bsize %zu rdonly %d", fd, bsize, rdonly);
+
+	/* things free by "goto err" if not NULL */
+	void *addr = NULL;
+	struct btt *bttp = NULL;
+	pthread_mutex_t *locks = NULL;
+
+	struct stat stbuf;
+	if (fstat(fd, &stbuf) < 0) {
+		LOG(1, "!fstat");
+		return NULL;
+	}
+
+	if (stbuf.st_size < PMEMBLK_MIN_POOL) {
+		LOG(1, "size %zu smaller than %zu",
+				stbuf.st_size, PMEMBLK_MIN_POOL);
+		errno = EINVAL;
+		return NULL;
+	}
+
+	if ((addr = util_map(fd, stbuf.st_size, rdonly)) == NULL)
+		return NULL;	/* util_map() set errno, called LOG */
+
+	/* check if the mapped region is located in persistent memory */
+	int is_pmem = pmem_is_pmem(addr, stbuf.st_size);
+
+	/* opaque info lives at the beginning of mapped memory pool */
+	struct pmemblk *pbp = addr;
+
+	struct pool_hdr hdr;
+	memcpy(&hdr, &pbp->hdr, sizeof (hdr));
+
+	if (util_convert_hdr(&hdr)) {
+		/*
+		 * valid header found
+		 */
+		if (strncmp(hdr.signature, BLK_HDR_SIG, POOL_HDR_SIG_LEN)) {
+			LOG(1, "wrong pool type: \"%s\"", hdr.signature);
+
+			errno = EINVAL;
+			goto err;
+		}
+
+		if (hdr.major != BLK_FORMAT_MAJOR) {
+			LOG(1, "blk pool version %d (library expects %d)",
+				hdr.major, BLK_FORMAT_MAJOR);
+
+			errno = EINVAL;
+			goto err;
+		}
+
+		size_t hdr_bsize = le32toh(pbp->bsize);
+		if (bsize && bsize != hdr_bsize) {
+			LOG(1, "wrong bsize (%zu), pool created with bsize %zu",
+					bsize, hdr_bsize);
+			errno = EINVAL;
+			goto err;
+		}
+		bsize = hdr_bsize;
+		LOG(3, "using block size from header: %zu", bsize);
+
+		int retval = util_feature_check(&hdr, BLK_FORMAT_INCOMPAT,
+							BLK_FORMAT_RO_COMPAT,
+							BLK_FORMAT_COMPAT);
+		if (retval < 0)
+		    goto err;
+		else if (retval == 0)
+		    rdonly = 1;
+	} else {
+		/*
+		 * no valid header was found
+		 */
+		if (rdonly) {
+			LOG(1, "read-only and no header found");
+			errno = EROFS;
+			goto err;
+		}
+		LOG(3, "creating new blk memory pool");
+
+		struct pool_hdr *hdrp = &pbp->hdr;
+
+		memset(hdrp, '\0', sizeof (*hdrp));
+		strncpy(hdrp->signature, BLK_HDR_SIG, POOL_HDR_SIG_LEN);
+		hdrp->major = htole32(BLK_FORMAT_MAJOR);
+		hdrp->compat_features = htole32(BLK_FORMAT_COMPAT);
+		hdrp->incompat_features = htole32(BLK_FORMAT_INCOMPAT);
+		hdrp->ro_compat_features = htole32(BLK_FORMAT_RO_COMPAT);
+		uuid_generate(hdrp->uuid);
+		hdrp->crtime = htole64((uint64_t)time(NULL));
+		util_checksum(hdrp, sizeof (*hdrp), &hdrp->checksum, 1);
+		hdrp->checksum = htole64(hdrp->checksum);
+
+		/* store pool's header */
+		libpmem_persist(is_pmem, hdrp, sizeof (*hdrp));
+
+		/* create rest of required metadata */
+		pbp->bsize = htole32(bsize);
+		libpmem_persist(is_pmem, &pbp->bsize, sizeof (bsize));
+	}
+
+	/*
+	 * Use some of the memory pool area for run-time info.  This
+	 * run-time state is never loaded from the file, it is always
+	 * created here, so no need to worry about byte-order.
+	 */
+	pbp->addr = addr;
+	pbp->size = stbuf.st_size;
+	pbp->rdonly = rdonly;
+	pbp->is_pmem = is_pmem;
+	pbp->data = addr + roundup(sizeof (*pbp), BLK_FORMAT_DATA_ALIGN);
+	pbp->datasize = (pbp->addr + pbp->size) - pbp->data;
+
+	LOG(4, "data area %p data size %zu bsize %zu",
+		pbp->data, pbp->datasize, bsize);
+
+	int ncpus = sysconf(_SC_NPROCESSORS_ONLN);
+	if (ncpus < 1)
+		ncpus = 1;
+
+	bttp = btt_init(pbp->datasize, (uint32_t)bsize, pbp->hdr.uuid,
+			ncpus, pbp, &ns_cb);
+
+	if (bttp == NULL)
+		goto err;	/* btt_init set errno, called LOG */
+
+	pbp->bttp = bttp;
+
+	pbp->nlane = btt_nlane(pbp->bttp);
+	pbp->next_lane = 0;
+	if ((locks = Malloc(pbp->nlane * sizeof (*locks))) == NULL) {
+		LOG(1, "!Malloc for lane locks");
+		goto err;
+	}
+
+	for (int i = 0; i < pbp->nlane; i++)
+		if (pthread_mutex_init(&locks[i], NULL) < 0) {
+			LOG(1, "!pthread_mutex_init");
+			goto err;
+		}
+
+	pbp->locks = locks;
+
+	/*
+	 * If possible, turn off all permissions on the pool header page.
+	 *
+	 * The prototype PMFS doesn't allow this when large pages are in
+	 * use not it is not considered an error if this fails.
+	 */
+	util_range_none(addr, sizeof (struct pool_hdr));
+
+#ifdef	notdef
+	/* XXX not ready to protect the pool just yet */
+	/* the rest should be kept read-only for debug version */
+	RANGE_RO(addr + sizeof (struct pool_hdr),
+			stbuf.st_size - sizeof (struct pool_hdr));
+#endif	/* notdef */
+
+	LOG(3, "pbp %p", pbp);
+	return pbp;
+
+err:
+	LOG(4, "error clean up");
+	int oerrno = errno;
+	if (locks)
+		Free((void *)locks);
+	if (bttp)
+		btt_fini(bttp);
+	util_unmap(addr, stbuf.st_size);
+	errno = oerrno;
+	return NULL;
+}
+
+/*
+ * pmemblk_map -- map a block memory pool
+ */
+PMEMblk *
+pmemblk_map(int fd, size_t bsize)
+{
+	LOG(3, "fd %d bsize %zu", fd, bsize);
+
+	return pmemblk_map_common(fd, bsize, 0);
+}
+
+/*
+ * pmemblk_unmap -- unmap a block memory pool
+ */
+void
+pmemblk_unmap(PMEMblk *pbp)
+{
+	LOG(3, "pbp %p", pbp);
+
+	btt_fini(pbp->bttp);
+	if (pbp->locks) {
+		for (int i = 0; i < pbp->nlane; i++)
+			pthread_mutex_destroy(&pbp->locks[i]);
+		Free((void *)pbp->locks);
+	}
+	util_unmap(pbp->addr, pbp->size);
+}
+
+/*
+ * pmemblk_nblock -- return number of usable blocks in a block memory pool
+ */
+size_t
+pmemblk_nblock(PMEMblk *pbp)
+{
+	LOG(3, "pbp %p", pbp);
+
+	return btt_nlba(pbp->bttp);
+}
+
+/*
+ * pmemblk_read -- read a block in a block memory pool
+ */
+int
+pmemblk_read(PMEMblk *pbp, void *buf, off_t blockno)
+{
+	LOG(3, "pbp %p buf %p blockno %zu", pbp, buf, blockno);
+
+	int lane = lane_enter(pbp);
+
+	if (lane < 0)
+		return -1;
+
+	int err = btt_read(pbp->bttp, lane, blockno, buf);
+
+	lane_exit(pbp, lane);
+
+	return err;
+}
+
+/*
+ * pmemblk_write -- write a block (atomically) in a block memory pool
+ */
+int
+pmemblk_write(PMEMblk *pbp, const void *buf, off_t blockno)
+{
+	LOG(3, "pbp %p buf %p blockno %zu", pbp, buf, blockno);
+
+	if (pbp->rdonly) {
+		LOG(1, "EROFS (pool is read-only)");
+		errno = EROFS;
+		return -1;
+	}
+
+	int lane = lane_enter(pbp);
+
+	if (lane < 0)
+		return -1;
+
+	int err = btt_write(pbp->bttp, lane, blockno, buf);
+
+	lane_exit(pbp, lane);
+
+	return err;
+}
+
+/*
+ * pmemblk_set_zero -- zero a block in a block memory pool
+ */
+int
+pmemblk_set_zero(PMEMblk *pbp, off_t blockno)
+{
+	LOG(3, "pbp %p blockno %zu", pbp, blockno);
+
+	if (pbp->rdonly) {
+		LOG(1, "EROFS (pool is read-only)");
+		errno = EROFS;
+		return -1;
+	}
+
+	int lane = lane_enter(pbp);
+
+	if (lane < 0)
+		return -1;
+
+	int err = btt_set_zero(pbp->bttp, lane, blockno);
+
+	lane_exit(pbp, lane);
+
+	return err;
+}
+
+/*
+ * pmemblk_set_error -- set the error state on a block in a block memory pool
+ */
+int
+pmemblk_set_error(PMEMblk *pbp, off_t blockno)
+{
+	LOG(3, "pbp %p blockno %zu", pbp, blockno);
+
+	if (pbp->rdonly) {
+		LOG(1, "EROFS (pool is read-only)");
+		errno = EROFS;
+		return -1;
+	}
+
+	int lane = lane_enter(pbp);
+
+	if (lane < 0)
+		return -1;
+
+	int err = btt_set_error(pbp->bttp, lane, blockno);
+
+	lane_exit(pbp, lane);
+
+	return err;
+}
+
+/*
+ * pmemblk_check -- block memory pool consistency check
+ */
+int
+pmemblk_check(const char *path)
+{
+	LOG(3, "path \"%s\"", path);
+
+	int fd = open(path, O_RDWR);
+
+	if (fd < 0) {
+		LOG(1, "!open");
+		return -1;
+	}
+
+	/* open the pool read-only */
+	PMEMblk *pbp = pmemblk_map_common(fd, 0, 1);
+	close(fd);
+
+	if (pbp == NULL)
+		return -1;	/* errno set by pmemblk_map_common() */
+
+	int retval = btt_check(pbp->bttp);
+	int oerrno = errno;
+	pmemblk_unmap(pbp);
+	errno = oerrno;
+
+	return retval;
+}
diff --git a/src/blk.h b/src/blk.h
new file mode 100644
index 0000000000000000000000000000000000000000..5dfaf752b8a612300fef34c5c7099ea48d61369b
--- /dev/null
+++ b/src/blk.h
@@ -0,0 +1,66 @@
+/*
+ * Copyright (c) 2014, Intel Corporation
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ *     * Redistributions of source code must retain the above copyright
+ *       notice, this list of conditions and the following disclaimer.
+ *
+ *     * Redistributions in binary form must reproduce the above copyright
+ *       notice, this list of conditions and the following disclaimer in
+ *       the documentation and/or other materials provided with the
+ *       distribution.
+ *
+ *     * Neither the name of Intel Corporation nor the names of its
+ *       contributors may be used to endorse or promote products derived
+ *       from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+/*
+ * blk.h -- internal definitions for libpmem blk module
+ */
+
+/* attributes of the blk memory pool format for the pool header */
+#define	BLK_HDR_SIG "PMEMBLK"	/* must be 8 bytes including '\0' */
+#define	BLK_FORMAT_MAJOR 1
+#define	BLK_FORMAT_COMPAT 0x0000
+#define	BLK_FORMAT_INCOMPAT 0x0000
+#define	BLK_FORMAT_RO_COMPAT 0x0000
+
+struct pmemblk {
+	struct pool_hdr hdr;	/* memory pool header */
+
+	/* root info for on-media format... */
+	uint32_t bsize;			/* block size */
+
+	/* some run-time state, allocated out of memory pool... */
+	void *addr;			/* mapped region */
+	size_t size;			/* size of mapped region */
+	int is_pmem;			/* true if pool is PMEM */
+	int rdonly;			/* true if pool is opened read-only */
+	void *data;			/* post-header data area */
+	size_t datasize;		/* size of data area */
+	size_t nlba;			/* number of LBAs in pool */
+	struct btt *bttp;		/* btt handle */
+	struct ns_callback *ns_cbp;	/* callbacks for btt_init() */
+	int nlane;			/* number of lanes */
+	unsigned next_lane;		/* used to rotate through lanes */
+	pthread_mutex_t *locks;		/* one per lane */
+};
+
+/* data area starts at this alignement after the struct pmemblk above */
+#define	BLK_FORMAT_DATA_ALIGN 4096
diff --git a/src/btt.c b/src/btt.c
new file mode 100644
index 0000000000000000000000000000000000000000..c642aae529af829199f16952eea3855a1b4606f8
--- /dev/null
+++ b/src/btt.c
@@ -0,0 +1,1676 @@
+/*
+ * Copyright (c) 2014, Intel Corporation
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ *     * Redistributions of source code must retain the above copyright
+ *       notice, this list of conditions and the following disclaimer.
+ *
+ *     * Redistributions in binary form must reproduce the above copyright
+ *       notice, this list of conditions and the following disclaimer in
+ *       the documentation and/or other materials provided with the
+ *       distribution.
+ *
+ *     * Neither the name of Intel Corporation nor the names of its
+ *       contributors may be used to endorse or promote products derived
+ *       from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+/*
+ * btt.c -- block translation table providing atomic block updates
+ *
+ * This is a user-space implementation of the BTT mechanism providing
+ * single block powerfail write atomicity, as described by:
+ * 	The NVDIMM Namespace Specification
+ *
+ * To use this module, the caller must provide three routines for
+ * accessing the namespace containing the data (in this context,
+ * "namespace" refers to the storage containing the BTT layout, such
+ * as a file).  All namespace I/O is done by these three calls:
+ *
+ * 	nsread	Read count bytes from namespace at offset off
+ * 	nswrite	Write count bytes to namespace at offset off
+ * 	nsmap	Return direct access to a range of a namespace
+ * 	nssync	Flush changes made to an nsmap'd range
+ *
+ * Data written by the nswrite callback is flushed out to the media
+ * (made durable) when the call returns.  Data written directly via
+ * the nsmap callback must be flushed explicitly using nssync.
+ *
+ * The caller passes these callbacks, along with information such as
+ * namespace size and UUID to btt_init() and gets back an opaque handle
+ * which is then used with the rest of the entry points.
+ *
+ * Here is a brief list of the entry points to this module:
+ *
+ *	btt_nlane	Returns number of concurrent threads allowed
+ *
+ *	btt_nlba	Returns the usable size, as a count of LBAs
+ *
+ *	btt_read	Reads a single block at a given LBA
+ *
+ *	btt_write	Writes a single block (atomically) at a given LBA
+ *
+ *	btt_set_zero	Sets a block to read back as zeros
+ *
+ *	btt_set_error	Sets a block to return error on read
+ *
+ *	btt_check	Checks the BTT metadata for consistency
+ *
+ *	btt_fini	Frees run-time state, done using namespace
+ *
+ * If the caller is multi-threaded, it must only allow btt_nlane() threads
+ * to enter this module at a time, each assigned a unique "lane" number
+ * between 0 and btt_nlane() - 1.
+ *
+ * There are a number of static routines defined in this module.  Here's
+ * a brief overview of the most important routines:
+ *
+ *	read_layout	Checks for valid BTT layout and builds run-time state.
+ *			A number of helper functions are used by read_layout
+ *			to handle various parts of the metadata:
+ *				read_info
+ *				read_arenas
+ *				read_arena
+ *				read_flogs
+ *				read_flog_pair
+ *
+ * 	write_layout	Generates a new BTT layout when one doesn't exist.
+ * 			Once a new layout is written, write_layout uses
+ * 			the same helper functions above to construct the
+ * 			run-time state.
+ *
+ * 	invalid_lba	Range check done by each entry point that takes
+ * 			an LBA.
+ *
+ *	lba_to_arena_lba
+ *			Find the arena and LBA in that arena for a given
+ *			external LBA.  This is the heart of the arena
+ *			range matching logic.
+ *
+ *	flog_update	Update the BTT free list/log combined data structure
+ *			(known as the "flog").  This is the heart of the
+ *			logic that makes writes powerfail atomic.
+ *
+ *	map_lock	These routines provide atomic access to the BTT map
+ *	map_unlock	data structure in an area.
+ *	map_abort
+ *
+ *	map_entry_setf	Common code for btt_set_zero() and btt_set_error().
+ *
+ *	zero_block	Generate a block of all zeros (instead of actually
+ *			doing a read), when the metadata indicates the
+ *			block should read as zeros.
+ *
+ *	build_rtt	These routines construct the run-time tracking
+ *	build_map_locks	data structures used during I/O.
+ */
+
+#include <stdio.h>
+#include <sys/param.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <errno.h>
+#include <string.h>
+#include <stdarg.h>
+#include <stdint.h>
+#include <pthread.h>
+#include <endian.h>
+
+#include "out.h"
+#include "util.h"
+#include "btt.h"
+#include "btt_layout.h"
+
+/*
+ * The opaque btt handle containing state tracked by this module
+ * for the btt namespace.  This is created by btt_init(), handed to
+ * all the other btt_* entry points, and deleted by btt_fini().
+ */
+struct btt {
+	int nlane;	/* number of concurrent threads allowed per btt */
+
+	/*
+	 * The laidout flag indicates whether the namespace contains valid BTT
+	 * metadata.  It is initialized by read_layout() and if no valid layout
+	 * is found, all reads return zeros and the first write will write the
+	 * BTT layout.  The layout_write_mutex protects the laidout flag so
+	 * only one write threads ends up writing the initial metadata by
+	 * calling write_layout().
+	 */
+	pthread_mutex_t layout_write_mutex;
+	int laidout;
+
+	/*
+	 * UUID of the containing namespace, used to validate BTT metadata.
+	 */
+	uint8_t parent_uuid[BTTINFO_UUID_LEN];
+
+	/*
+	 * Parameters controlling/describing the BTT layout.
+	 */
+	uint64_t rawsize;		/* size of containing namespace */
+	uint32_t lbasize;		/* external LBA size */
+	uint32_t nfree;			/* available flog entries */
+	uint64_t nlba;			/* total number of external LBAs */
+	int narena;			/* number of arenas */
+
+	/* run-time state kept for each arena */
+	struct arena {
+		uint32_t flags;		/* arena flags (btt_info) */
+		uint64_t external_nlba;	/* LBAs that live in this arena */
+		uint32_t internal_lbasize;
+		uint32_t internal_nlba;
+
+		/*
+		 * The following offsets are relative to the beginning of
+		 * the encapsulating namespace.  This is different from
+		 * how these offsets are stored on-media, where they are
+		 * relative to the start of the arena.  The offset are
+		 * converted by read_layout() to make them more convenient
+		 * for run-time use.
+		 */
+		uint64_t startoff;	/* offset to start of arena */
+		uint64_t dataoff;	/* offset to arena data area */
+		uint64_t mapoff;	/* offset to area map */
+		uint64_t flogoff;	/* offset to area flog */
+		uint64_t nextoff;	/* offset to next arena */
+
+		/*
+		 * Run-time flog state.  Indexed by lane.
+		 *
+		 * The write path uses the flog to find the free block
+		 * it writes to before atomically making it the new
+		 * active block for an external LBA.
+		 *
+		 * The read path doesn't use the flog at all.
+		 */
+		struct flog_runtime {
+			struct btt_flog flog;	/* current info */
+			off_t entries[2];	/* offsets for flog pair */
+			int next;		/* next write (0 or 1) */
+		} *flogs;
+
+		/*
+		 * Read tracking table.  Indexed by lane.
+		 *
+		 * Before using a free block found in the flog, the write path
+		 * scans the rtt to see if there are any outstanding reads on
+		 * that block (reads that started before the block was freed by
+		 * a concurrent write).  Unused slots in the rtt are indicated
+		 * by setting the error bit, BTT_MAP_ENTRY_ERROR, so that the
+		 * entry won't match any post-map LBA when checked.
+		 */
+		uint32_t volatile *rtt;
+
+		/*
+		 * Map locking.  Indexed by pre-map LBA modulo nlane.
+		 */
+		pthread_spinlock_t *map_locks;
+	} *arenas;
+
+	/*
+	 * Callbacks for doing I/O to namespace.  These are provided by
+	 * the code calling the BTT module, which passes them in to
+	 * btt_init().  All namespace I/O is done using these.
+	 *
+	 * The opaque namespace handle "ns" was provided by the code calling
+	 * the BTT module and is passed to each callback to identify the
+	 * namespace being accessed.
+	 */
+	void *ns;
+	const struct ns_callback *ns_cbp;
+};
+
+/*
+ * Signature for arena info blocks.  Total size is 16 bytes, including
+ * the '\0' added to the string by the declaration (the last two bytes
+ * of the string are '\0').
+ */
+static const char Sig[] = "BTT_ARENA_INFO\0";
+
+/*
+ * Zeroed out flog entry, used when initializing the flog.
+ */
+static const struct btt_flog Zflog;
+
+/*
+ * Lookup table and macro for looking up sequence numbers.  These are
+ * the 2-bit numbers that cycle between 01, 10, and 11.
+ *
+ * To advance a sequence number to the next number, use something like:
+ * 	seq = NSEQ(seq);
+ */
+static const unsigned Nseq[] = { 0, 2, 3, 1 };
+#define	NSEQ(seq) (Nseq[(seq) & 3])
+
+/*
+ * invalid_lba -- (internal) set errno and return true if lba is invalid
+ *
+ * This function is used at the top of the entry points where an external
+ * LBA is provided, like this:
+ *
+ *	if (invalid_lba(bttp, lba))
+ *		return -1;
+ */
+static int
+invalid_lba(struct btt *bttp, uint64_t lba)
+{
+	LOG(3, "bttp %p lba %zu", bttp, lba);
+
+	if (lba >= bttp->nlba) {
+		LOG(1, "lba out of range (nlba %zu)", bttp->nlba);
+		errno = EINVAL;
+		return 1;
+	}
+
+	return 0;
+}
+
+/*
+ * read_info -- (internal) convert btt_info to host byte order & validate
+ *
+ * Returns true if info block is valid, and all the integer fields are
+ * converted to host byte order.  If the info block is not valid, this
+ * routine returns false and the info block passed in is left in an
+ * unknown state.
+ */
+static int
+read_info(struct btt_info *infop)
+{
+	LOG(3, "infop %p", infop);
+
+	if (memcmp(infop->sig, Sig, BTTINFO_SIG_LEN)) {
+		LOG(3, "signature invalid");
+		return 0;
+	}
+
+	/* to be valid, info block must have a major version of at least 1 */
+	if ((infop->major = le16toh(infop->major)) == 0) {
+		LOG(3, "invalid major version (0)");
+		return 0;
+	}
+
+	infop->flags = le32toh(infop->flags);
+	infop->minor = le16toh(infop->minor);
+	infop->external_lbasize = le32toh(infop->external_lbasize);
+	infop->external_nlba = le32toh(infop->external_nlba);
+	infop->internal_lbasize = le32toh(infop->internal_lbasize);
+	infop->internal_nlba = le32toh(infop->internal_nlba);
+	infop->nfree = le32toh(infop->nfree);
+	infop->infosize = le32toh(infop->infosize);
+	infop->nextoff = le64toh(infop->nextoff);
+	infop->dataoff = le64toh(infop->dataoff);
+	infop->mapoff = le64toh(infop->mapoff);
+	infop->flogoff = le64toh(infop->flogoff);
+	infop->infooff = le64toh(infop->infooff);
+	infop->checksum = le64toh(infop->checksum);
+
+	/* and to be valid, the fields must checksum correctly */
+	if (!util_checksum(infop, sizeof (*infop), &infop->checksum, 0)) {
+		LOG(3, "invalid checksum");
+		return 0;
+	}
+
+	return 1;
+}
+
+/*
+ * read_flog_pair -- (internal) load up a single flog pair
+ *
+ * Zero is returned on success, otherwise -1/errno.
+ *
+ * XXX lots of byzantine checks could be added, like range checking lbas
+ */
+static int
+read_flog_pair(struct btt *bttp, int lane, struct arena *arenap,
+	off_t flog_off, struct flog_runtime *flog_runtimep, int flognum)
+{
+	LOG(5, "bttp %p lane %d arenap %p flog_off %zu runtimep %p flognum %d",
+			bttp, lane, arenap, flog_off, flog_runtimep, flognum);
+
+	flog_runtimep->entries[0] = flog_off;
+	flog_runtimep->entries[1] = flog_off + sizeof (struct btt_flog);
+
+	struct btt_flog flog_pair[2];
+	if ((*bttp->ns_cbp->nsread)(bttp->ns, lane, flog_pair,
+				sizeof (flog_pair), flog_off) < 0)
+		return -1;
+
+	flog_pair[0].lba = le32toh(flog_pair[0].lba);
+	flog_pair[0].old_map = le32toh(flog_pair[0].old_map);
+	flog_pair[0].new_map = le32toh(flog_pair[0].new_map);
+	flog_pair[0].seq = le32toh(flog_pair[0].seq);
+
+	flog_pair[1].lba = le32toh(flog_pair[1].lba);
+	flog_pair[1].old_map = le32toh(flog_pair[1].old_map);
+	flog_pair[1].new_map = le32toh(flog_pair[1].new_map);
+	flog_pair[1].seq = le32toh(flog_pair[1].seq);
+
+	LOG(6, "flog_pair[0] flog_off %zu old_map %u new_map %u seq %u",
+			flog_off, flog_pair[0].old_map,
+			flog_pair[0].new_map, flog_pair[0].seq);
+	LOG(6, "flog_pair[1] old_map %u new_map %u seq %u",
+			flog_pair[1].old_map, flog_pair[1].new_map,
+			flog_pair[1].seq);
+
+	/*
+	 * Interesting cases:
+	 * 	- no valid seq numbers:  layout consistency error
+	 * 	- one valid seq number:  that's the current entry
+	 * 	- two valid seq numbers: higher number is current entry
+	 * 	- identical seq numbers: layout consistency error
+	 */
+	struct btt_flog *currentp;
+	if (flog_pair[0].seq == flog_pair[1].seq) {
+		LOG(1, "flog layout error: bad seq numbers %d %d",
+				flog_pair[0].seq, flog_pair[1].seq);
+		arenap->flags |= BTTINFO_FLAG_ERROR;
+		return 0;
+	} else if (flog_pair[0].seq == 0) {
+		/* singleton valid flog at flog_pair[1] */
+		currentp = &flog_pair[1];
+		flog_runtimep->next = 0;
+	} else if (flog_pair[1].seq == 0) {
+		/* singleton valid flog at flog_pair[0] */
+		currentp = &flog_pair[0];
+		flog_runtimep->next = 1;
+	} else if (NSEQ(flog_pair[0].seq) == flog_pair[1].seq) {
+		/* flog_pair[1] has the later sequence number */
+		currentp = &flog_pair[1];
+		flog_runtimep->next = 0;
+	} else {
+		/* flog_pair[0] has the later sequence number */
+		currentp = &flog_pair[0];
+		flog_runtimep->next = 1;
+	}
+
+	LOG(6, "run-time flog next is %d", flog_runtimep->next);
+
+	/* copy current flog into run-time flog state */
+	flog_runtimep->flog = *currentp;
+
+	LOG(9, "read flog[%d]: lba %u old %u%s%s new %u%s%s", flognum,
+		currentp->lba,
+		currentp->old_map & BTT_MAP_ENTRY_LBA_MASK,
+		(currentp->old_map & BTT_MAP_ENTRY_ERROR) ? " ERROR" : "",
+		(currentp->old_map & BTT_MAP_ENTRY_ZERO) ? " ZERO" : "",
+		currentp->new_map & BTT_MAP_ENTRY_LBA_MASK,
+		(currentp->new_map & BTT_MAP_ENTRY_ERROR) ? " ERROR" : "",
+		(currentp->new_map & BTT_MAP_ENTRY_ZERO) ? " ZERO" : "");
+
+	/*
+	 * Decide if the current flog info represents a completed
+	 * operation or an incomplete operation.  If completed, the
+	 * old_map field will contain the free block to be used for
+	 * the next write.  But if the operation didn't complete (indicated
+	 * by the map entry not being updated), then new_map is the free
+	 * block since it never became active according to the map.
+	 *
+	 * A special case, used by flog entries when first created, is
+	 * when old_map == new_map.  This counts as a complete entry
+	 * and doesn't require reading the map to see if recovery is
+	 * required.
+	 */
+	if (currentp->old_map == currentp->new_map) {
+		LOG(9, "flog[%d] entry complete (initial state)", flognum);
+		return 0;
+	}
+
+	/* convert pre-map LBA into an offset into the map */
+	off_t map_entry_off = arenap->mapoff +
+				BTT_MAP_ENTRY_SIZE * currentp->lba;
+
+	/* read current map entry */
+	uint32_t entry;
+	if ((*bttp->ns_cbp->nsread)(bttp->ns, lane, &entry,
+				sizeof (entry), map_entry_off) < 0)
+		return -1;
+
+	entry = le32toh(entry);
+	if (currentp->new_map != entry && currentp->old_map == entry) {
+		/* last update didn't complete */
+		LOG(9, "recover flog[%d]: map[%u]: %u",
+				flognum, currentp->lba, currentp->new_map);
+
+		/*
+		 * Recovery step is to complete the transaction by
+		 * updating the map entry.
+		 */
+		entry = htole32(currentp->new_map);
+		if ((*bttp->ns_cbp->nswrite)(bttp->ns, lane, &entry,
+					sizeof (uint32_t), map_entry_off) < 0)
+			return -1;
+	}
+
+	return 0;
+}
+
+/*
+ * flog_update -- (internal) write out an updated flog entry
+ *
+ * The flog entries are not checksummed.  Instead, increasing sequence
+ * numbers are used to atomically switch the active flog entry between
+ * the first and second struct btt_flog in each slot.  In order for this
+ * to work, the sequence number must be updated only after all the other
+ * fields in the flog are updated.  So the writes to the flog are broken
+ * into two writes, one for the first three fields (lba, old_map, new_map)
+ * and, only after those fields are known to be written durably, the
+ * second write for the seq field is done.
+ *
+ * Returns 0 on success, otherwise -1/errno.
+ */
+static int
+flog_update(struct btt *bttp, int lane, struct arena *arenap,
+		uint32_t lba, uint32_t old_map, uint32_t new_map)
+{
+	LOG(3, "bttp %p lane %d arenap %p lba %u old_map %u new_map %u",
+			bttp, lane, arenap, lba, old_map, new_map);
+
+	/* construct new flog entry in little-endian byte order */
+	struct btt_flog new_flog;
+	new_flog.lba = htole32(lba);
+	new_flog.old_map = htole32(old_map);
+	new_flog.new_map = htole32(new_map);
+	new_flog.seq = htole32(NSEQ(arenap->flogs[lane].flog.seq));
+
+	off_t new_flog_off =
+		arenap->flogs[lane].entries[arenap->flogs[lane].next];
+
+	/* write out first three fields first */
+	/* XXX writing two fields and two fields will be faster */
+	if ((*bttp->ns_cbp->nswrite)(bttp->ns, lane, &new_flog,
+				sizeof (uint32_t) * 3, new_flog_off) < 0)
+		return -1;
+	new_flog_off += sizeof (uint32_t) * 3;
+
+	/* write out seq field to make it active */
+	if ((*bttp->ns_cbp->nswrite)(bttp->ns, lane, &new_flog.seq,
+				sizeof (uint32_t), new_flog_off) < 0)
+		return -1;
+
+	/* flog entry written successfully, update run-time state */
+	arenap->flogs[lane].next = 1 - arenap->flogs[lane].next;
+	arenap->flogs[lane].flog.lba = lba;
+	arenap->flogs[lane].flog.old_map = old_map;
+	arenap->flogs[lane].flog.new_map = new_map;
+	arenap->flogs[lane].flog.seq = NSEQ(arenap->flogs[lane].flog.seq);
+
+	LOG(9, "update flog[%d]: lba %u old %u%s%s new %u%s%s", lane, lba,
+			old_map & BTT_MAP_ENTRY_LBA_MASK,
+			(old_map & BTT_MAP_ENTRY_ERROR) ? " ERROR" : "",
+			(old_map & BTT_MAP_ENTRY_ZERO) ? " ZERO" : "",
+			new_map & BTT_MAP_ENTRY_LBA_MASK,
+			(new_map & BTT_MAP_ENTRY_ERROR) ? " ERROR" : "",
+			(new_map & BTT_MAP_ENTRY_ZERO) ? " ZERO" : "");
+
+	return 0;
+}
+
+/*
+ * read_flogs -- (internal) load up all the flog entries for an arena
+ *
+ * Zero is returned on success, otherwise -1/errno.
+ */
+static int
+read_flogs(struct btt *bttp, int lane, struct arena *arenap)
+{
+	if ((arenap->flogs = Malloc(bttp->nfree *
+			sizeof (struct flog_runtime))) == NULL) {
+		LOG(1, "!Malloc for %d flog entries", bttp->nfree);
+		return -1;
+	}
+	memset(arenap->flogs, '\0', bttp->nfree * sizeof (struct flog_runtime));
+
+	/*
+	 * Load up the flog state.  read_flog_pair() will determine if
+	 * any recovery steps are required take them on the in-memory
+	 * data structures it creates.
+	 */
+	off_t flog_off = arenap->flogoff;
+	struct flog_runtime *flog_runtimep = arenap->flogs;
+	for (int i = 0; i < bttp->nfree; i++) {
+		if (read_flog_pair(bttp, lane, arenap, flog_off,
+						flog_runtimep, i) < 0)
+			return -1;
+
+		/* prepare for next time around the loop */
+		flog_off += 2 * sizeof (struct btt_flog);
+		flog_runtimep++;
+	}
+
+	return 0;
+}
+
+/*
+ * build_rtt -- (internal) construct a read tracking table for an arena
+ *
+ * Zero is returned on success, otherwise -1/errno.
+ *
+ * The rtt is big enough to hold an entry for each free block (nfree)
+ * since nlane can't be bigger than nfree.  nlane may end up smaller,
+ * in which case some of the high rtt entries will be unused.
+ */
+static int
+build_rtt(struct btt *bttp, struct arena *arenap)
+{
+	if ((arenap->rtt = Malloc(bttp->nfree * sizeof (uint32_t)))
+							== NULL) {
+		LOG(1, "!Malloc for %d rtt entries", bttp->nfree);
+		return -1;
+	}
+	for (int lane = 0; lane < bttp->nfree; lane++)
+		arenap->rtt[lane] = BTT_MAP_ENTRY_ERROR;
+	__sync_synchronize();
+
+	return 0;
+}
+
+/*
+ * build_map_locks -- (internal) construct map locks
+ *
+ * Zero is returned on success, otherwise -1/errno.
+ */
+static int
+build_map_locks(struct btt *bttp, struct arena *arenap)
+{
+	if ((arenap->map_locks =
+			Malloc(bttp->nfree * sizeof (*arenap->map_locks)))
+							== NULL) {
+		LOG(1, "!Malloc for %d map_lock entries", bttp->nfree);
+		return -1;
+	}
+	for (int lane = 0; lane < bttp->nfree; lane++)
+		pthread_spin_init(&arenap->map_locks[lane],
+					PTHREAD_PROCESS_PRIVATE);
+
+	return 0;
+}
+
+/*
+ * read_arena -- (internal) load up an arena and build run-time state
+ *
+ * Zero is returned on success, otherwise -1/errno.
+ */
+static int
+read_arena(struct btt *bttp, int lane, off_t arena_off, struct arena *arenap)
+{
+	LOG(3, "bttp %p lane %d arena_off %zu arenap %p",
+			bttp, lane, arena_off, arenap);
+
+	struct btt_info info;
+	if ((*bttp->ns_cbp->nsread)(bttp->ns, lane, &info, sizeof (info),
+							arena_off) < 0)
+		return -1;
+
+	arenap->flags = le32toh(info.flags);
+	arenap->external_nlba = le64toh(info.external_nlba);
+	arenap->internal_lbasize = le32toh(info.internal_lbasize);
+	arenap->internal_nlba = le32toh(info.internal_nlba);
+
+	arenap->startoff = arena_off;
+	arenap->dataoff = arena_off + le64toh(info.dataoff);
+	arenap->mapoff = arena_off + le64toh(info.mapoff);
+	arenap->flogoff = arena_off + le64toh(info.flogoff);
+	arenap->nextoff = arena_off + le64toh(info.nextoff);
+
+	if (read_flogs(bttp, lane, arenap) < 0)
+		return -1;
+
+	if (build_rtt(bttp, arenap) < 0)
+		return -1;
+
+	if (build_map_locks(bttp, arenap) < 0)
+		return -1;
+
+	return 0;
+}
+
+/*
+ * read_arenas -- (internal) load up all arenas and build run-time state
+ *
+ * On entry, layout must be known to be valid, and the number of arenas
+ * must be known.  Zero is returned on success, otherwise -1/errno.
+ */
+static int
+read_arenas(struct btt *bttp, int lane, int narena)
+{
+	LOG(3, "bttp %p lane %d narena %d", bttp, lane, narena);
+
+	if ((bttp->arenas = Malloc(narena * sizeof (*bttp->arenas))) == NULL) {
+		LOG(1, "!Malloc for %d arenas", narena);
+		goto err;
+	}
+	memset(bttp->arenas, '\0', narena * sizeof (*bttp->arenas));
+
+	off_t arena_off = 0;
+	struct arena *arenap = bttp->arenas;
+	for (int i = 0; i < narena; i++) {
+
+		if (read_arena(bttp, lane, arena_off, arenap) < 0)
+			goto err;
+
+		/* prepare for next time around the loop */
+		arena_off = arenap->nextoff;
+		arenap++;
+	}
+
+	bttp->laidout = 1;
+
+	return 0;
+
+err:
+	LOG(4, "error clean up");
+	int oerrno = errno;
+	if (bttp->arenas) {
+		for (int i = 0; i < bttp->narena; i++) {
+			if (bttp->arenas[i].flogs)
+				Free(bttp->arenas[i].flogs);
+			if (bttp->arenas[i].rtt)
+				Free((void *)bttp->arenas[i].rtt);
+			if (bttp->arenas[i].map_locks)
+				Free((void *)bttp->arenas[i].map_locks);
+		}
+		Free(bttp->arenas);
+		bttp->arenas = NULL;
+	}
+	errno = oerrno;
+	return -1;
+}
+
+/*
+ * write_layout -- (internal) write out the initial btt metadata layout
+ *
+ * Called with write == 1 only once in the life time of a btt namespace, when
+ * the first write happens.  The caller of this routine is responsible for
+ * locking out multiple threads.  This routine doesn't read anything -- by the
+ * time it is called, it is known there's no layout in the namespace and a new
+ * layout should be written.
+ *
+ * Calling with write == 0 tells this routine to do the calculations for
+ * bttp->narena and bttp->nlba, but don't write out any metadata.
+ *
+ * If successful, sets bttp->layout to 1 and returns 0.  Otherwise -1
+ * is returned and errno is set, and bttp->layout remains 0 so that
+ * later attempts to write will try again to create the layout.
+ */
+static int
+write_layout(struct btt *bttp, int lane, int write)
+{
+	LOG(3, "bttp %p lane %d write %d", bttp, lane, write);
+
+	ASSERT(bttp->rawsize >= BTT_MIN_SIZE);
+	ASSERT(bttp->nfree);
+
+	/*
+	 * The number of arenas is the number of full arena of
+	 * size BTT_MAX_ARENA that fit into rawsize and then, if
+	 * the remainder is at least BTT_MIN_SIZE in size, then
+	 * that adds one more arena.
+	 */
+	bttp->narena = bttp->rawsize / BTT_MAX_ARENA;
+	if (bttp->rawsize % BTT_MAX_ARENA >= BTT_MIN_SIZE)
+		bttp->narena++;
+	LOG(4, "narena %u", bttp->narena);
+
+	int flog_size = bttp->nfree * 2 * sizeof (struct btt_flog);
+	flog_size = roundup(flog_size, BTT_ALIGNMENT);
+
+	uint32_t internal_lbasize = bttp->lbasize;
+	if (internal_lbasize < BTT_MIN_LBA)
+		internal_lbasize = BTT_MIN_LBA;
+	internal_lbasize =
+		roundup(internal_lbasize, BTT_INTERNAL_LBA_ALIGNMENT);
+	LOG(4, "adjusted internal_lbasize %u", internal_lbasize);
+
+	uint64_t total_nlba = 0;
+	uint64_t rawsize = bttp->rawsize;
+	int arena_num = 0;
+	off_t arena_off = 0;
+
+	/*
+	 * for each arena...
+	 */
+	while (rawsize >= BTT_MIN_SIZE) {
+		LOG(4, "layout arena %u", arena_num);
+
+		uint64_t arena_rawsize = rawsize;
+		if (arena_rawsize > BTT_MAX_ARENA) {
+			arena_rawsize = BTT_MAX_ARENA;
+		}
+		rawsize -= arena_rawsize;
+		arena_num++;
+
+		uint64_t arena_datasize = arena_rawsize;
+		arena_datasize -= 2 * sizeof (struct btt_info);
+		arena_datasize -= flog_size;
+
+		/* allow for map alignment padding */
+		uint64_t internal_nlba = (arena_datasize - BTT_ALIGNMENT) /
+			(internal_lbasize + BTT_MAP_ENTRY_SIZE);
+		uint64_t external_nlba = internal_nlba - bttp->nfree;
+
+		LOG(4, "internal_nlba %zu external_nlba %zu",
+				internal_nlba, external_nlba);
+
+		total_nlba += external_nlba;
+
+		/*
+		 * The rest of the loop body calculates metadata structures
+		 * and lays it out for this arena.  So only continue if
+		 * the write flag is set.
+		 */
+		if (!write)
+			continue;
+
+		uint64_t mapsize = roundup(external_nlba * BTT_MAP_ENTRY_SIZE,
+							BTT_ALIGNMENT);
+		arena_datasize -= mapsize;
+
+		ASSERT(arena_datasize / internal_lbasize >= internal_nlba);
+
+		/*
+		 * Calculate offsets for the BTT info block.  These are
+		 * all relative to the beginning of the arena.
+		 */
+		uint64_t nextoff;
+		if (rawsize)
+			nextoff = arena_rawsize;
+		else
+			nextoff = 0;
+		uint64_t infooff = arena_rawsize - sizeof (struct btt_info);
+		uint64_t flogoff = infooff - flog_size;
+		uint64_t mapoff = flogoff - mapsize;
+		uint64_t dataoff = sizeof (struct btt_info);
+
+		LOG(4, "nextoff 0x%016lx", nextoff);
+		LOG(4, "dataoff 0x%016lx", dataoff);
+		LOG(4, "mapoff  0x%016lx", mapoff);
+		LOG(4, "flogoff 0x%016lx", flogoff);
+		LOG(4, "infooff 0x%016lx", infooff);
+
+		ASSERTeq(arena_datasize, mapoff - dataoff);
+
+		/* write out the initial map, identity style */
+		off_t map_entry_off = arena_off + mapoff;
+		uint32_t *mapp = NULL;
+		int mlen = 0;
+		int next_index = 0;
+		int remaining = 0;
+		for (int i = 0; i < external_nlba; i++) {
+			if (remaining == 0) {
+				/* flush previous mapped area */
+				if (mapp != NULL)
+					(*bttp->ns_cbp->nssync)(bttp->ns,
+						lane, mapp, mlen);
+				/* request a mapping of remaining map area */
+				mlen = (*bttp->ns_cbp->nsmap)(bttp->ns,
+					lane, (void **)&mapp,
+					(external_nlba - i) * sizeof (uint32_t),
+					map_entry_off);
+
+				if (mlen < 0)
+					return -1;
+
+				remaining = mlen;
+				next_index = 0;
+			}
+			mapp[next_index++] = htole32(i | BTT_MAP_ENTRY_ZERO);
+			remaining -= sizeof (uint32_t);
+		}
+		/* flush previous mapped area */
+		if (mapp != NULL)
+			(*bttp->ns_cbp->nssync)(bttp->ns, lane, mapp, mlen);
+
+		/* write out the initial flog */
+		off_t flog_entry_off = arena_off + flogoff;
+		uint32_t next_free_lba = external_nlba;
+		for (int i = 0; i < bttp->nfree; i++) {
+			struct btt_flog flog;
+			flog.lba = 0;
+			flog.old_map = flog.new_map =
+				htole32(next_free_lba | BTT_MAP_ENTRY_ZERO);
+			flog.seq = htole32(1);
+
+			/*
+			 * Write both btt_flog structs in the pair, writing
+			 * the second one as all zeros.
+			 */
+			LOG(6, "flog[%d] entry off %zu initial %u + zero = %u",
+					i, flog_entry_off, next_free_lba,
+					next_free_lba | BTT_MAP_ENTRY_ZERO);
+			if ((*bttp->ns_cbp->nswrite)(bttp->ns, lane, &flog,
+					sizeof (flog), flog_entry_off) < 0)
+				return -1;
+			flog_entry_off += sizeof (flog);
+
+			LOG(6, "flog[%d] entry off %zu zeros",
+					i, flog_entry_off);
+			if ((*bttp->ns_cbp->nswrite)(bttp->ns, lane, &Zflog,
+					sizeof (Zflog), flog_entry_off) < 0)
+				return -1;
+			flog_entry_off += sizeof (flog);
+
+			next_free_lba++;
+		}
+
+		/*
+		 * Construct the BTT info block and write it out
+		 * at both the beginning and end of the arena.
+		 */
+		struct btt_info info;
+		memset(&info, '\0', sizeof (info));
+		memcpy(info.sig, Sig, BTTINFO_SIG_LEN);
+		memcpy(info.parent_uuid, bttp->parent_uuid, BTTINFO_UUID_LEN);
+		info.major = htole16(BTTINFO_MAJOR_VERSION);
+		info.minor = htole16(BTTINFO_MINOR_VERSION);
+		info.external_lbasize = htole32(bttp->lbasize);
+		info.external_nlba = htole32(external_nlba);
+		info.internal_lbasize = htole32(internal_lbasize);
+		info.internal_nlba = htole32(internal_nlba);
+		info.nfree = htole32(bttp->nfree);
+		info.infosize = htole32(sizeof (info));
+		info.nextoff = htole64(nextoff);
+		info.dataoff = htole64(dataoff);
+		info.mapoff = htole64(mapoff);
+		info.flogoff = htole64(flogoff);
+		info.infooff = htole64(infooff);
+
+		util_checksum(&info, sizeof (info), &info.checksum, 1);
+
+		if ((*bttp->ns_cbp->nswrite)(bttp->ns, lane, &info,
+					sizeof (info), arena_off) < 0)
+			return -1;
+		if ((*bttp->ns_cbp->nswrite)(bttp->ns, lane, &info,
+					sizeof (info), arena_off + nextoff) < 0)
+			return -1;
+
+		arena_off += nextoff;
+	}
+
+	ASSERTeq(bttp->narena, arena_num);
+
+	bttp->nlba = total_nlba;
+
+	if (write) {
+		/*
+		 * The layout is written now, so load up the arenas.
+		 */
+		return read_arenas(bttp, lane, bttp->narena);
+	}
+
+	return 0;
+}
+
+/*
+ * read_layout -- (internal) load up layout info from btt namespace
+ *
+ * Called once when the btt namespace is opened for use.
+ * Sets bttp->layout to 0 if no valid layout is found, 1 otherwise.
+ *
+ * Any recovery actions required (as indicated by the flog state) are
+ * performed by this routine.
+ *
+ * Any quick checks for layout consistency are performed by this routine
+ * (quick enough to be done each time a BTT area is opened for use, not
+ * like the slow consistency checks done by btt_check()).
+ *
+ * Returns 0 if no errors are encountered accessing the namespace (in this
+ * context, detecting there's no layout is not an error if the nsread function
+ * didn't have any problems doing the reads).  Otherwise, -1 is returned
+ * and errno is set (by nsread).
+ */
+static int
+read_layout(struct btt *bttp, int lane)
+{
+	LOG(3, "bttp %p", bttp);
+
+	ASSERT(bttp->rawsize >= BTT_MIN_SIZE);
+
+	int narena = 0;
+	uint32_t smallest_nfree = UINT32_MAX;
+	uint64_t rawsize = bttp->rawsize;
+	uint64_t total_nlba = 0;
+	off_t arena_off = 0;
+
+	bttp->nfree = BTT_DEFAULT_NFREE;
+
+	/*
+	 * For each arena, see if there's a valid info block
+	 */
+	while (rawsize >= BTT_MIN_SIZE) {
+		narena++;
+
+		struct btt_info info;
+		if ((*bttp->ns_cbp->nsread)(bttp->ns, lane, &info,
+					sizeof (info), arena_off) < 0)
+			return -1;
+
+		if (!read_info(&info)) {
+			/*
+			 * Failed to find complete BTT metadata.  Just
+			 * calculate the narena and nlba values that will
+			 * result when write_layout() gets called.  This
+			 * allows checks against nlba to work correctly
+			 * even before the layout is written.
+			 */
+			return write_layout(bttp, lane, 0);
+		}
+
+		if (info.nfree < smallest_nfree)
+			smallest_nfree = info.nfree;
+
+		total_nlba += info.external_nlba;
+		arena_off += info.nextoff;
+		if (info.nextoff == 0)
+			break;
+		rawsize -= info.nextoff;
+	}
+
+	ASSERT(narena);
+
+	bttp->narena = narena;
+	bttp->nlba = total_nlba;
+
+	/*
+	 * All arenas were valid.  nfree should be the smallest value found.
+	 */
+	if (smallest_nfree < bttp->nfree)
+		bttp->nfree = smallest_nfree;
+
+	/*
+	 * Load up arenas.
+	 */
+	return read_arenas(bttp, lane, narena);
+}
+
+/*
+ * zero_block -- (internal) satisfy a read with a block of zeros
+ *
+ * Returns 0 on success, otherwise -1/errno.
+ */
+static int
+zero_block(struct btt *bttp, void *buf)
+{
+	LOG(3, "bttp %p", bttp);
+
+	memset(buf, '\0', bttp->lbasize);
+	return 0;
+}
+
+/*
+ * lba_to_arena_lba -- (internal) calculate the arena & pre-map LBA
+ *
+ * This routine takes the external LBA and matches it to the
+ * appropriate arena, adjusting the lba for use within that arena.
+ *
+ * If successful, zero is returned, *arenapp is a pointer to the appropriate
+ * arena struct in the run-time state, and *premap_lbap is the LBA adjusted
+ * to an arena-internal LBA (also known as the pre-map LBA).  Otherwise
+ * -1/errno.
+ */
+static int
+lba_to_arena_lba(struct btt *bttp, uint64_t lba,
+		struct arena **arenapp, uint32_t *premap_lbap)
+{
+	LOG(3, "bttp %p lba %zu", bttp, lba);
+
+	ASSERT(bttp->laidout);
+
+	int arena;
+	for (arena = 0; arena < bttp->narena; arena++)
+		if (lba < bttp->arenas[arena].external_nlba)
+			break;
+		else
+			lba -= bttp->arenas[arena].external_nlba;
+
+	ASSERT(arena < bttp->narena);
+
+	*arenapp = &bttp->arenas[arena];
+	*premap_lbap = lba;
+
+	LOG(3, "arenap %p pre-map LBA %u", *arenapp, *premap_lbap);
+	return 0;
+}
+
+/*
+ * btt_init -- prepare a btt namespace for use, returning an opaque handle
+ *
+ * Returns handle on success, otherwise NULL/errno.
+ *
+ * XXX handle case where lbasize doesn't match lbasize found in valid arenas.
+ * XXX check rawsize against size from valid arenas.
+ * XXX what if write_layout produces something read_layout says is invalid?
+ * XXX what if arenas have different nfree?
+ */
+struct btt *
+btt_init(uint64_t rawsize, uint32_t lbasize, uint8_t parent_uuid[],
+		int maxlane, void *ns, const struct ns_callback *ns_cbp)
+{
+	LOG(3, "rawsize %zu lbasize %u", rawsize, lbasize);
+
+	if (rawsize < BTT_MIN_SIZE) {
+		LOG(1, "rawsize smaller than BTT_MIN_SIZE %zu", BTT_MIN_SIZE);
+		errno = EINVAL;
+		return NULL;
+	}
+
+	struct btt *bttp = Malloc(sizeof (*bttp));
+
+	if (bttp == NULL) {
+		LOG(1, "!Malloc %zu bytes", sizeof (*bttp));
+		return NULL;
+	}
+
+	memset(bttp, '\0', sizeof (*bttp));
+
+	pthread_mutex_init(&bttp->layout_write_mutex, NULL);
+	memcpy(bttp->parent_uuid, parent_uuid, BTTINFO_UUID_LEN);
+	bttp->rawsize = rawsize;
+	bttp->lbasize = lbasize;
+	bttp->ns = ns;
+	bttp->ns_cbp = ns_cbp;
+
+	/*
+	 * Load up layout, if it exists.
+	 *
+	 * Whether read_layout() finds a valid layout or not, it finishes
+	 * updating these layout-related fields:
+	 * 	bttp->nfree
+	 * 	bttp->nlba
+	 * 	bttp->narena
+	 * since these fields are used even before a valid layout it written.
+	 */
+	if (read_layout(bttp, 0) < 0) {
+		btt_fini(bttp);		/* free up any allocations */
+		return NULL;
+	}
+
+	bttp->nlane = bttp->nfree;
+
+	/* maxlane, if provided, is an upper bound on nlane */
+	if (maxlane && bttp->nlane > maxlane)
+		bttp->nlane = maxlane;
+
+	LOG(3, "success, bttp %p nlane %d", bttp, bttp->nlane);
+	return bttp;
+}
+
+/*
+ * btt_nlane -- return the number of "lanes" for this btt namespace
+ *
+ * The number of lanes is the number of threads allowed in this module
+ * concurrently for a given btt.  Each thread executing this code must
+ * have a unique "lane" number assigned to it between 0 and btt_nlane() - 1.
+ */
+int
+btt_nlane(struct btt *bttp)
+{
+	LOG(3, "bttp %p", bttp);
+
+	return bttp->nlane;
+}
+
+/*
+ * btt_nlba -- return the number of usable blocks in a btt namespace
+ *
+ * Valid LBAs to pass to btt_read() and btt_write() are 0 through
+ * btt_nlba() - 1.
+ */
+size_t
+btt_nlba(struct btt *bttp)
+{
+	LOG(3, "bttp %p", bttp);
+
+	return bttp->nlba;
+}
+
+/*
+ * btt_read -- read a block from a btt namespace
+ *
+ * Returns 0 on success, otherwise -1/errno.
+ */
+int
+btt_read(struct btt *bttp, int lane, uint64_t lba, void *buf)
+{
+	LOG(3, "bttp %p lane %u lba %zu", bttp, lane, lba);
+
+	if (invalid_lba(bttp, lba))
+		return -1;
+
+	/* if there's no layout written yet, all reads come back as zeros */
+	if (!bttp->laidout)
+		return zero_block(bttp, buf);
+
+	/* find which arena LBA lives in, and the offset to the map entry */
+	struct arena *arenap;
+	uint32_t premap_lba;
+	off_t map_entry_off;
+	if (lba_to_arena_lba(bttp, lba, &arenap, &premap_lba) < 0)
+		return -1;
+
+	/* convert pre-map LBA into an offset into the map */
+	map_entry_off = arenap->mapoff + BTT_MAP_ENTRY_SIZE * premap_lba;
+
+	/*
+	 * Read the current map entry to get the post-map LBA for the data
+	 * block read.
+	 */
+	uint32_t entry;
+
+	if ((*bttp->ns_cbp->nsread)(bttp->ns, lane, &entry,
+				sizeof (entry), map_entry_off) < 0)
+		return -1;
+
+	entry = le32toh(entry);
+
+	/*
+	 * Retries come back to the top of this loop (for a rare case where
+	 * the map is changed by another thread doing writes to the same LBA).
+	 */
+	while (1) {
+		if (entry & BTT_MAP_ENTRY_ERROR) {
+			LOG(1, "EIO due to map entry error flag");
+			errno = EIO;
+			return -1;
+		}
+
+		if (entry & BTT_MAP_ENTRY_ZERO)
+			return zero_block(bttp, buf);
+
+		/*
+		 * Record the post-map LBA in the read tracking table during
+		 * the read.  The write will check entries in the read tracking
+		 * table before allocating a block for a write, waiting for
+		 * outstanding reads on that block to complete.
+		 *
+		 * No need to mask off ERROR and ZERO bits since the above
+		 * checks make sure they are clear at this point.
+		 */
+		arenap->rtt[lane] = entry;
+		__sync_synchronize();
+
+		/*
+		 * In case this thread was preempted between reading entry and
+		 * storing it in the rtt, check to see if the map changed.  If
+		 * it changed, the block about to be read is at least free now
+		 * (in the flog, but that's okay since the data will still be
+		 * undisturbed) and potentially allocated and being used for
+		 * another write (data disturbed, so not okay to continue).
+		 */
+		uint32_t latest_entry;
+		if ((*bttp->ns_cbp->nsread)(bttp->ns, lane, &latest_entry,
+				sizeof (latest_entry), map_entry_off) < 0) {
+			arenap->rtt[lane] = BTT_MAP_ENTRY_ERROR;
+			return -1;
+		}
+
+		latest_entry = le32toh(latest_entry);
+
+		if (entry == latest_entry)
+			break;			/* map stayed the same */
+		else
+			entry = latest_entry;	/* try again */
+	}
+
+	/*
+	 * It is safe to read the block now, since the rtt protects the
+	 * block from getting re-allocated to something else by a write.
+	 */
+	off_t data_block_off =
+		arenap->dataoff + entry * arenap->internal_lbasize;
+	int readret = (*bttp->ns_cbp->nsread)(bttp->ns, lane, buf,
+					bttp->lbasize, data_block_off);
+
+	/* done with read, so clear out rtt entry */
+	arenap->rtt[lane] = BTT_MAP_ENTRY_ERROR;
+
+	return readret;
+}
+
+/*
+ * map_lock -- (internal) grab the map_lock and read a map entry
+ */
+static int
+map_lock(struct btt *bttp, int lane, struct arena *arenap,
+		uint32_t *entryp, uint32_t premap_lba)
+{
+	LOG(3, "bttp %p lane %u arenap %p premap_lba %u",
+			bttp, lane, arenap, premap_lba);
+
+	off_t map_entry_off = arenap->mapoff + BTT_MAP_ENTRY_SIZE * premap_lba;
+	int map_lock_num = premap_lba % bttp->nfree;
+
+	pthread_spin_lock(&arenap->map_locks[map_lock_num]);
+
+	/* read the old map entry */
+	if ((*bttp->ns_cbp->nsread)(bttp->ns, lane, entryp,
+				sizeof (uint32_t), map_entry_off) < 0) {
+		pthread_spin_unlock(&arenap->map_locks[map_lock_num]);
+		return -1;
+	}
+
+	LOG(9, "locked map[%d]: %u%s%s", premap_lba,
+			*entryp & BTT_MAP_ENTRY_LBA_MASK,
+			(*entryp & BTT_MAP_ENTRY_ERROR) ? " ERROR" : "",
+			(*entryp & BTT_MAP_ENTRY_ZERO) ? " ZERO" : "");
+
+	return 0;
+}
+
+/*
+ * map_abort -- (internal) drop the map_lock without updating the entry
+ */
+void
+map_abort(struct btt *bttp, int lane, struct arena *arenap, uint32_t premap_lba)
+{
+	LOG(3, "bttp %p lane %u arenap %p premap_lba %u",
+			bttp, lane, arenap, premap_lba);
+
+	int map_lock_num = premap_lba % bttp->nfree;
+	pthread_spin_unlock(&arenap->map_locks[map_lock_num]);
+}
+
+/*
+ * map_unlock -- (internal) update the map and drop the map_lock
+ */
+static int
+map_unlock(struct btt *bttp, int lane, struct arena *arenap,
+		uint32_t entry, uint32_t premap_lba)
+{
+	LOG(3, "bttp %p lane %u arenap %p entry %u premap_lba %u",
+			bttp, lane, arenap, entry, premap_lba);
+
+	off_t map_entry_off = arenap->mapoff + BTT_MAP_ENTRY_SIZE * premap_lba;
+	int map_lock_num = premap_lba % bttp->nfree;
+
+	/* write the new map entry */
+	int err = (*bttp->ns_cbp->nswrite)(bttp->ns, lane, &entry,
+				sizeof (uint32_t), map_entry_off);
+
+	pthread_spin_unlock(&arenap->map_locks[map_lock_num]);
+
+	LOG(9, "unlocked map[%d]: %u%s%s", premap_lba,
+			entry & BTT_MAP_ENTRY_LBA_MASK,
+			(entry & BTT_MAP_ENTRY_ERROR) ? " ERROR" : "",
+			(entry & BTT_MAP_ENTRY_ZERO) ? " ZERO" : "");
+
+	return err;
+}
+
+/*
+ * btt_write -- write a block to a btt namespace
+ *
+ * Returns 0 on success, otherwise -1/errno.
+ */
+int
+btt_write(struct btt *bttp, int lane, uint64_t lba, const void *buf)
+{
+	LOG(3, "bttp %p lane %u lba %zu", bttp, lane, lba);
+
+	if (invalid_lba(bttp, lba))
+		return -1;
+
+	/* first write through here will initialize the metadata layout */
+	if (!bttp->laidout) {
+		int err = 0;
+
+		pthread_mutex_lock(&bttp->layout_write_mutex);
+		if (!bttp->laidout)
+			err = write_layout(bttp, lane, 1);
+		pthread_mutex_unlock(&bttp->layout_write_mutex);
+
+		if (err < 0)
+			return err;
+	}
+
+	/* find which arena LBA lives in, and the offset to the map entry */
+	struct arena *arenap;
+	uint32_t premap_lba;
+	if (lba_to_arena_lba(bttp, lba, &arenap, &premap_lba) < 0)
+		return -1;
+
+	/* if the arena is in an error state, writing is not allowed */
+	if (arenap->flags & BTTINFO_FLAG_ERROR_MASK) {
+		LOG(1, "EIO due to btt_info error flags 0x%x",
+			arenap->flags & BTTINFO_FLAG_ERROR_MASK);
+		errno = EIO;
+		return -1;
+	}
+
+	/*
+	 * This routine was passed a unique "lane" which is an index
+	 * into the flog.  That means the free block held by flog[lane]
+	 * is assigned to this thread and to no other threads (no additional
+	 * locking required).  So start by performing the write to the
+	 * free block.  It is only safe to write to a free block if it
+	 * doesn't appear in the read tracking table, so scan that first
+	 * and if found, wait for the thread reading from it to finish.
+	 */
+	uint32_t free_entry =
+		arenap->flogs[lane].flog.old_map & BTT_MAP_ENTRY_LBA_MASK;
+
+	LOG(3, "free_entry %u (before mask %u)", free_entry,
+				arenap->flogs[lane].flog.old_map);
+
+	/* wait for other threads to finish any reads on free block */
+	for (int i = 0; i < bttp->nlane; i++)
+		while (arenap->rtt[i] == free_entry)
+			;
+
+	/* it is now safe to perform write to the free block */
+	off_t data_block_off =
+			arenap->dataoff + free_entry * arenap->internal_lbasize;
+	if ((*bttp->ns_cbp->nswrite)(bttp->ns, lane, buf,
+				bttp->lbasize, data_block_off) < 0)
+		return -1;
+
+	/*
+	 * Make the new block active atomically by updating the on-media flog
+	 * and then updating the map.
+	 */
+	uint32_t old_entry;
+	if (map_lock(bttp, lane, arenap, &old_entry, premap_lba) < 0)
+		return -1;
+
+	old_entry = le32toh(old_entry);
+
+	/* update the flog */
+	if (flog_update(bttp, lane, arenap, premap_lba,
+					old_entry, free_entry) < 0) {
+		map_abort(bttp, lane, arenap, premap_lba);
+		return -1;
+	}
+
+	if (map_unlock(bttp, lane, arenap, htole32(free_entry),
+					premap_lba) < 0) {
+		/* XXX retry? revert the flog? */
+		return -1;
+	}
+
+	return 0;
+}
+
+/*
+ * map_entry_setf -- (internal) set a given flag on a map entry
+ *
+ * Returns 0 on success, otherwise -1/errno.
+ */
+static int
+map_entry_setf(struct btt *bttp, int lane, uint64_t lba, uint32_t setf)
+{
+	LOG(3, "bttp %p lane %u lba %zu setf 0x%x", bttp, lane, lba, setf);
+
+	if (invalid_lba(bttp, lba))
+		return -1;
+
+	if (!bttp->laidout) {
+		/*
+		 * No layout is written yet.  If the flag being set
+		 * is the zero flag, it is superfluous since all blocks
+		 * read as zero at this point.
+		 */
+		if (setf == BTT_MAP_ENTRY_ZERO)
+			return 0;
+
+		/*
+		 * Treat this like the first write and write out
+		 * the metadata layout at this point.
+		 */
+		int err = 0;
+		pthread_mutex_lock(&bttp->layout_write_mutex);
+		if (!bttp->laidout)
+			err = write_layout(bttp, lane, 1);
+		pthread_mutex_unlock(&bttp->layout_write_mutex);
+
+		if (err < 0)
+			return err;
+	}
+
+	/* find which arena LBA lives in, and the offset to the map entry */
+	struct arena *arenap;
+	uint32_t premap_lba;
+	if (lba_to_arena_lba(bttp, lba, &arenap, &premap_lba) < 0)
+		return -1;
+
+	/* if the arena is in an error state, writing is not allowed */
+	if (arenap->flags & BTTINFO_FLAG_ERROR_MASK) {
+		LOG(1, "EIO due to btt_info error flags 0x%x",
+			arenap->flags & BTTINFO_FLAG_ERROR_MASK);
+		errno = EIO;
+		return -1;
+	}
+
+	/*
+	 * Set the flags in the map entry.  To do this, read the
+	 * current map entry, set the flags, and write out the update.
+	 */
+	uint32_t old_entry;
+	uint32_t new_entry;
+
+	if (map_lock(bttp, lane, arenap, &old_entry, premap_lba) < 0)
+		return -1;
+
+	old_entry = le32toh(old_entry);
+
+	if (setf == BTT_MAP_ENTRY_ZERO && (old_entry & BTT_MAP_ENTRY_ZERO)) {
+		map_abort(bttp, lane, arenap, premap_lba);
+		return 0;	/* block already zero, nothing to do */
+	}
+
+	/* create the new map entry */
+	new_entry = old_entry | setf;
+
+	if (map_unlock(bttp, lane, arenap, htole32(new_entry), premap_lba) < 0)
+		return -1;
+
+	return 0;
+}
+
+/*
+ * btt_set_zero -- mark a block as zeroed in a btt namespace
+ *
+ * Returns 0 on success, otherwise -1/errno.
+ */
+int
+btt_set_zero(struct btt *bttp, int lane, uint64_t lba)
+{
+	LOG(3, "bttp %p lane %u lba %zu", bttp, lane, lba);
+
+	return map_entry_setf(bttp, lane, lba, BTT_MAP_ENTRY_ZERO);
+}
+
+/*
+ * btt_set_error -- mark a block as in an error state in a btt namespace
+ *
+ * Returns 0 on success, otherwise -1/errno.
+ */
+int
+btt_set_error(struct btt *bttp, int lane, uint64_t lba)
+{
+	LOG(3, "bttp %p lane %u lba %zu", bttp, lane, lba);
+
+	return map_entry_setf(bttp, lane, lba, BTT_MAP_ENTRY_ERROR);
+}
+
+/*
+ * check_arena -- (internal) perform a consistency check on an arena
+ */
+static int
+check_arena(struct btt *bttp, struct arena *arenap)
+{
+	LOG(3, "bttp %p arenap %p", bttp, arenap);
+
+	int consistent = 1;
+
+	off_t map_entry_off = arenap->mapoff;
+	int bitmapsize = howmany(arenap->internal_nlba, 8);
+	char *bitmap = Malloc(bitmapsize);
+	if (bitmap == NULL) {
+		LOG(1, "!Malloc for bitmap");
+		return -1;
+	}
+	memset(bitmap, '\0', bitmapsize);
+
+	/*
+	 * Go through every post-map LBA mentioned in the map and make sure
+	 * there are no duplicates.  bitmap is used to track which LBAs have
+	 * been seen so far.
+	 */
+	uint32_t *mapp = NULL;
+	int mlen;
+	int next_index = 0;
+	int remaining = 0;
+	for (int i = 0; i < arenap->external_nlba; i++) {
+		uint32_t entry;
+
+		if (remaining == 0) {
+			/* request a mapping of remaining map area */
+			mlen = (*bttp->ns_cbp->nsmap)(bttp->ns,
+				0, (void **)&mapp,
+				(arenap->external_nlba - i) * sizeof (uint32_t),
+				map_entry_off);
+
+			if (mlen < 0)
+				return -1;
+
+			remaining = mlen;
+			next_index = 0;
+		}
+		entry = le32toh(mapp[next_index]);
+
+		/* for debug, dump non-zero map entries at log level 11 */
+		if ((entry & BTT_MAP_ENTRY_ZERO) == 0)
+			LOG(11, "map[%d]: %u%s%s", i,
+				entry & BTT_MAP_ENTRY_LBA_MASK,
+				(entry & BTT_MAP_ENTRY_ERROR) ? " ERROR" : "",
+				(entry & BTT_MAP_ENTRY_ZERO) ? " ZERO" : "");
+
+		entry &= BTT_MAP_ENTRY_LBA_MASK;
+
+		if (isset(bitmap, entry)) {
+			LOG(1, "map[%d] duplicate entry: %u", i, entry);
+			consistent = 0;
+		} else
+			setbit(bitmap, entry);
+
+		map_entry_off += sizeof (uint32_t);
+		next_index++;
+		remaining -= sizeof (uint32_t);
+	}
+
+	/*
+	 * Go through the free blocks in the flog, adding them to bitmap
+	 * and checking for duplications.  It is sufficient to read the
+	 * run-time flog here, avoiding more calls to nsread.
+	 */
+	for (int i = 0; i < bttp->nfree; i++) {
+		uint32_t entry = arenap->flogs[i].flog.old_map;
+		entry &= BTT_MAP_ENTRY_LBA_MASK;
+
+		if (isset(bitmap, entry)) {
+			LOG(1, "flog[%d] duplicate entry: %u", i, entry);
+			consistent = 0;
+		} else
+			setbit(bitmap, entry);
+	}
+
+	/*
+	 * Make sure every possible post-map LBA was accounted for
+	 * in the two loops above.
+	 */
+	for (int i = 0; i < arenap->internal_nlba; i++)
+		if (isclr(bitmap, i)) {
+			LOG(1, "unreferenced lba: %u", i);
+			consistent = 0;
+		}
+
+
+	Free(bitmap);
+
+	return consistent;
+}
+
+/*
+ * btt_check -- perform a consistency check on a btt namespace
+ *
+ * This routine contains a fairly high-impact set of consistency checks.
+ * It may use a good amount of dynamic memory and CPU time performing
+ * the checks.  Any lightweight, quick consistency checks are included
+ * in read_layout() so they happen every time the BTT area is opened
+ * for use.
+ *
+ * Returns true if consistent, zero if inconsistent, -1/error if checking
+ * cannot happen due to other errors.
+ *
+ * No lane number required here because only one thread is allowed -- all
+ * other threads must be locked out of all btt routines for this btt
+ * namespace while this is running.
+ */
+int
+btt_check(struct btt *bttp)
+{
+	LOG(3, "bttp %p", bttp);
+
+	int consistent = 1;
+
+	if (!bttp->laidout) {
+		/* consistent by definition */
+		LOG(3, "no layout yet");
+		return consistent;
+	}
+
+	/* XXX report issues found during read_layout (from flags) */
+
+	/* for each arena... */
+	struct arena *arenap = bttp->arenas;
+	for (int i = 0; i < bttp->narena; i++) {
+		/*
+		 * Perform the consistency checks for the arena.
+		 */
+		int retval = check_arena(bttp, arenap);
+		if (retval < 0)
+			return retval;
+		else if (retval == 0)
+			consistent = 0;
+	}
+
+	/* XXX stub */
+	return consistent;
+}
+
+/*
+ * btt_fini -- delete opaque btt info, done using btt namespace
+ */
+void
+btt_fini(struct btt *bttp)
+{
+	LOG(3, "bttp %p", bttp);
+
+	if (bttp->arenas) {
+		for (int i = 0; i < bttp->narena; i++) {
+			if (bttp->arenas[i].flogs)
+				Free(bttp->arenas[i].flogs);
+			if (bttp->arenas[i].rtt)
+				Free((void *)bttp->arenas[i].rtt);
+			if (bttp->arenas[i].rtt)
+				Free((void *)bttp->arenas[i].map_locks);
+		}
+		Free(bttp->arenas);
+	}
+	Free(bttp);
+}
diff --git a/src/btt.h b/src/btt.h
new file mode 100644
index 0000000000000000000000000000000000000000..89d5b2feede311893329f8bb769880b5ddf1f34c
--- /dev/null
+++ b/src/btt.h
@@ -0,0 +1,56 @@
+/*
+ * Copyright (c) 2014, Intel Corporation
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ *     * Redistributions of source code must retain the above copyright
+ *       notice, this list of conditions and the following disclaimer.
+ *
+ *     * Redistributions in binary form must reproduce the above copyright
+ *       notice, this list of conditions and the following disclaimer in
+ *       the documentation and/or other materials provided with the
+ *       distribution.
+ *
+ *     * Neither the name of Intel Corporation nor the names of its
+ *       contributors may be used to endorse or promote products derived
+ *       from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+/*
+ * btt.h -- btt module definitions
+ */
+
+/* callback functions passed to btt_init() */
+struct ns_callback {
+	int (*nsread)(void *ns, int lane,
+		void *buf, size_t count, off_t off);
+	int (*nswrite)(void *ns, int lane,
+		const void *buf, size_t count, off_t off);
+	int (*nsmap)(void *ns, int lane, void **addrp, size_t len, off_t off);
+	void (*nssync)(void *ns, int lane, void *addr, size_t len);
+};
+
+struct btt *btt_init(uint64_t rawsize, uint32_t lbasize, uint8_t parent_uuid[],
+		int maxlane, void *ns, const struct ns_callback *ns_cbp);
+int btt_nlane(struct btt *bttp);
+size_t btt_nlba(struct btt *bttp);
+int btt_read(struct btt *bttp, int lane, uint64_t lba, void *buf);
+int btt_write(struct btt *bttp, int lane, uint64_t lba, const void *buf);
+int btt_set_zero(struct btt *bttp, int lane, uint64_t lba);
+int btt_set_error(struct btt *bttp, int lane, uint64_t lba);
+int btt_check(struct btt *bttp);
+void btt_fini(struct btt *bttp);
diff --git a/src/btt_layout.h b/src/btt_layout.h
new file mode 100644
index 0000000000000000000000000000000000000000..f7cb956789c7a98de6c7cb0563e967679cfe8dc7
--- /dev/null
+++ b/src/btt_layout.h
@@ -0,0 +1,115 @@
+/*
+ * Copyright (c) 2014, Intel Corporation
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ *     * Redistributions of source code must retain the above copyright
+ *       notice, this list of conditions and the following disclaimer.
+ *
+ *     * Redistributions in binary form must reproduce the above copyright
+ *       notice, this list of conditions and the following disclaimer in
+ *       the documentation and/or other materials provided with the
+ *       distribution.
+ *
+ *     * Neither the name of Intel Corporation nor the names of its
+ *       contributors may be used to endorse or promote products derived
+ *       from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+/*
+ * btt_layout.h -- block translation table on-media layout definitions
+ */
+
+/*
+ * Layout of BTT info block.  All integers are stored little-endian.
+ */
+
+#define	BTT_ALIGNMENT 4096		/* alignment of all BTT structures */
+#define	BTTINFO_SIG_LEN 16
+#define	BTTINFO_UUID_LEN 16
+
+struct btt_info {
+	char sig[BTTINFO_SIG_LEN];	/* must be "BTT_ARENA_INFO\0\0" */
+	uint8_t parent_uuid[BTTINFO_UUID_LEN];	/* UUID of container */
+	uint32_t flags;			/* see flag bits below */
+	uint16_t major;			/* major version */
+	uint16_t minor;			/* minor version */
+	uint32_t external_lbasize;	/* advertised LBA size (bytes) */
+	uint32_t external_nlba;		/* advertised LBAs in this arena */
+	uint32_t internal_lbasize;	/* size of data area blocks (bytes) */
+	uint32_t internal_nlba;		/* number of blocks in data area */
+	uint32_t nfree;			/* number of free blocks */
+	uint32_t infosize;		/* size of this info block */
+
+	/*
+	 * The following offsets are relative to the beginning of
+	 * the btt_info block.
+	 */
+	uint64_t nextoff;		/* offset to next arena (or zero) */
+	uint64_t dataoff;		/* offset to arena data area */
+	uint64_t mapoff;		/* offset to area map */
+	uint64_t flogoff;		/* offset to area flog */
+	uint64_t infooff;		/* offset to backup info block */
+
+	char unused[3984];		/* must be zero */
+
+	uint64_t checksum;		/* Fletcher64 of all fields */
+};
+
+/*
+ * Definitions for flags mask for btt_info structure above.
+ */
+#define	BTTINFO_FLAG_ERROR	0x00000001 /* error state (read-only) */
+#define	BTTINFO_FLAG_ERROR_MASK	0x00000001 /* all error bits */
+
+/*
+ * Current on-media format versions.
+ */
+#define	BTTINFO_MAJOR_VERSION 1
+#define	BTTINFO_MINOR_VERSION 1
+
+/*
+ * Layout of a BTT "flog" entry.  All integers are stored little-endian.
+ *
+ * The "nfree" field in the BTT info block determines how many of these
+ * flog entries there are, and each entry consists of two of the following
+ * structs (entry updates alternate between the two structs).
+ */
+
+struct btt_flog {
+	uint32_t lba;		/* last pre-map LBA using this entry */
+	uint32_t old_map;	/* old post-map LBA (the freed block) */
+	uint32_t new_map;	/* new post-map LBA */
+	uint32_t seq;		/* sequence number (01, 10, 11) */
+};
+
+/*
+ * Layout of a BTT "map" entry.  4-byte internal LBA offset, little-endian.
+ */
+#define	BTT_MAP_ENTRY_SIZE 4
+#define	BTT_MAP_ENTRY_ZERO (1u << 30)
+#define	BTT_MAP_ENTRY_ERROR (1u << 31)
+#define	BTT_MAP_ENTRY_LBA_MASK 0x3fffffff
+
+/*
+ * BTT layout properties...
+ */
+#define	BTT_MIN_SIZE ((size_t)(1ul << 20) * 512)
+#define	BTT_MAX_ARENA ((size_t)(1ul << 39)) /* 512GB per arena */
+#define	BTT_MIN_LBA 512
+#define	BTT_INTERNAL_LBA_ALIGNMENT 256
+#define	BTT_DEFAULT_NFREE 256
diff --git a/src/debug/Makefile b/src/debug/Makefile
new file mode 100644
index 0000000000000000000000000000000000000000..7d7db8172756feb62ef5b353fecdba019382c024
--- /dev/null
+++ b/src/debug/Makefile
@@ -0,0 +1,45 @@
+#
+# Copyright (c) 2014, Intel Corporation
+#
+# Redistribution and use in source and binary forms, with or without
+# modification, are permitted provided that the following conditions
+# are met:
+#
+#     * Redistributions of source code must retain the above copyright
+#       notice, this list of conditions and the following disclaimer.
+#
+#     * Redistributions in binary form must reproduce the above copyright
+#       notice, this list of conditions and the following disclaimer in
+#       the documentation and/or other materials provided with the
+#       distribution.
+#
+#     * Neither the name of Intel Corporation nor the names of its
+#       contributors may be used to endorse or promote products derived
+#       from this software without specific prior written permission.
+#
+# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+#
+
+#
+# src/debug/Makefile -- build the debug versions of the NVM Library
+#
+
+JEMALLOC_MAKE_NAME = Makefile_debug
+JEMALLOC_OBJROOT = debug
+
+VARIANT_DESTDIR = nvml_debug
+
+include ../Makefile.inc
+
+CFLAGS += -DDEBUG
+EXTRA_JECONFIG += --enable-debug
diff --git a/src/debug/README b/src/debug/README
new file mode 100644
index 0000000000000000000000000000000000000000..5ed6e5a6d73c8e1106b9041ffd40b925c93590fa
--- /dev/null
+++ b/src/debug/README
@@ -0,0 +1,9 @@
+Linux NVM Library
+
+This is src/debug/README.
+
+This directory is where debug versions of the object files and
+the targets end up.  To build just the debug version of the
+library, use "make all" from this directory.  To build both
+the debug and nondebug version, use "make all" from the parent
+directory.
diff --git a/src/include/README b/src/include/README
new file mode 100644
index 0000000000000000000000000000000000000000..6c3cfa7010f0921a68d48929960b42ddef422d74
--- /dev/null
+++ b/src/include/README
@@ -0,0 +1,17 @@
+Linux NVM Library
+
+This is src/include/README.
+
+This directory contains include files that are meant to be
+installed on a system when the NVM Library package is installed.
+These include files provide the public information exported
+by the libraries that is necessary for applications to call into
+the libraries.  Private include files, used only internally in
+the libraries, don't live here -- they typically live next to
+the source for their module.
+
+Here you'll find:
+
+libpmem.h -- definitions of libpmem entry points (see libpmem(3))
+
+libvmem.h -- definitions of libvmem entry points (see libvmem(3))
diff --git a/src/include/libpmem.h b/src/include/libpmem.h
new file mode 100644
index 0000000000000000000000000000000000000000..017e642e142f4854b9440bdf078215c50910b417
--- /dev/null
+++ b/src/include/libpmem.h
@@ -0,0 +1,181 @@
+/*
+ * Copyright (c) 2014, Intel Corporation
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ *     * Redistributions of source code must retain the above copyright
+ *       notice, this list of conditions and the following disclaimer.
+ *
+ *     * Redistributions in binary form must reproduce the above copyright
+ *       notice, this list of conditions and the following disclaimer in
+ *       the documentation and/or other materials provided with the
+ *       distribution.
+ *
+ *     * Neither the name of Intel Corporation nor the names of its
+ *       contributors may be used to endorse or promote products derived
+ *       from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+/*
+ * libpmem.h -- definitions of libpmem entry points
+ *
+ * This library provides support for programming with Persistent Memory (PMEM).
+ *
+ * The libpmem entry points are divided below into these categories:
+ *	- basic PMEM flush-to-durability support
+ *	- support for memory allocation and transactions in PMEM
+ *	- support for arrays of atomically-writable blocks
+ *	- support for PMEM-resident log files
+ *	- managing overall library behavior
+ *
+ * See libpmem(3) for details.
+ */
+
+#ifndef	LIBPMEM_H
+#define	LIBPMEM_H 1
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#include <sys/types.h>
+#include <sys/uio.h>
+
+/*
+ * opaque types internal to libpmem...
+ */
+typedef struct pmemtrn PMEMtrn;
+typedef struct pmemblk PMEMblk;
+typedef struct pmemlog PMEMlog;
+
+/*
+ * basic PMEM flush-to-durability support...
+ */
+int pmem_is_pmem(void *addr, size_t len);
+void pmem_persist(void *addr, size_t len, int flags);
+void pmem_flush(void *addr, size_t len, int flags);
+void pmem_fence(void);
+void pmem_drain(void);
+
+/*
+ * support for memory allocation and transactions in PMEM...
+ */
+#define	PMEMTRN_MIN_POOL ((size_t)(1024 * 1024 * 2)) /* min pool size: 2MB */
+PMEMtrn *pmemtrn_map(int fd);
+void pmemtrn_unmap(PMEMtrn *ptp);
+void *pmemtrn_static_area(PMEMtrn *ptp);
+int pmemtrn_begin(PMEMtrn *ptp);
+int pmemtrn_commit(PMEMtrn *ptp, int tid);
+int pmemtrn_abort(PMEMtrn *ptp, int tid);
+void *pmemtrn_malloc(PMEMtrn *ptp, size_t size);
+void pmemtrn_free(PMEMtrn *ptp, void *ptr);
+void *pmemtrn_calloc(PMEMtrn *ptp, size_t nmemb, size_t size);
+void *pmemtrn_realloc(PMEMtrn *ptp, void *ptr, size_t size);
+void *pmemtrn_aligned_alloc(PMEMtrn *ptp, size_t alignment, size_t size);
+char *pmemtrn_strdup(PMEMtrn *ptp, const char *s);
+void *pmemtrn_alloc(PMEMtrn *ptp, void *oldptr, size_t alignment, int zeroed,
+		int tag, size_t size);
+void pmemtrn_set(PMEMtrn *ptp, void *pmem_dest, const void *src, size_t n);
+void pmemtrn_set_ptr(PMEMtrn *ptp, void *pmem_dest, const void *src);
+void *pmemtrn_ptr(PMEMtrn *ptp, void *pmem_src);
+void pmemtrn_strncpy(PMEMtrn *ptp, char *pmem_dest, const char *src, size_t n);
+void pmemtrn_walk(PMEMtrn *ptp,
+		void (*cb)(const void *ptr, int tag, void *arg), void *arg);
+PMEMtrn *pmemtrn_map_replicant(PMEMtrn *ptp, int fd);
+
+/*
+ * support for arrays of atomically-writable blocks...
+ */
+#define	PMEMBLK_MIN_POOL ((size_t)(1024 * 1024 * 1024)) /* min pool size: 1GB */
+#define	PMEMBLK_MIN_BLK ((size_t)512)
+PMEMblk *pmemblk_map(int fd, size_t bsize);
+void pmemblk_unmap(PMEMblk *pbp);
+size_t pmemblk_nblock(PMEMblk *pbp);
+int pmemblk_read(PMEMblk *pbp, void *buf, off_t blockno);
+int pmemblk_write(PMEMblk *pbp, const void *buf, off_t blockno);
+int pmemblk_set_zero(PMEMblk *pbp, off_t blockno);
+int pmemblk_set_error(PMEMblk *pbp, off_t blockno);
+
+/*
+ * support for PMEM-resident log files...
+ */
+#define	PMEMLOG_MIN_POOL ((size_t)(1024 * 1024 * 2)) /* min pool size: 2MB */
+PMEMlog *pmemlog_map(int fd);
+void pmemlog_unmap(PMEMlog *plp);
+size_t pmemlog_nbyte(PMEMlog *plp);
+int pmemlog_append(PMEMlog *plp, const void *buf, size_t count);
+int pmemlog_appendv(PMEMlog *plp, const struct iovec *iov, int iovcnt);
+off_t pmemlog_tell(PMEMlog *plp);
+void pmemlog_rewind(PMEMlog *plp);
+void pmemlog_walk(PMEMlog *plp, size_t chunksize,
+	int (*process_chunk)(const void *buf, size_t len, void *arg),
+	void *arg);
+
+/*
+ * managing overall library behavior...
+ */
+
+/*
+ * PMEM_MAJOR_VERSION and PMEM_MINOR_VERSION provide the current
+ * version of the libpmem API as provided by this header file.
+ * Applications can verify that the version available at run-time
+ * is compatible with the version used at compile-time by passing
+ * these defines to pmem_check_version().
+ */
+#define	PMEM_MAJOR_VERSION 1
+#define	PMEM_MINOR_VERSION 0
+const char *pmem_check_version(
+		unsigned major_required,
+		unsigned minor_required);
+
+/*
+ * Passing NULL to pmem_set_funcs() tells libpmem to continue to use
+ * the default for that function.  The replacement functions must
+ * not make calls back into libpmem.
+ *
+ * The print_func is called by libpmem based on the environment
+ * variable PMEM_LOG_LEVEL:
+ * 	0 or unset: print_func is only called for pmem_pool_stats_print()
+ * 	1:          additional details are logged when errors are returned
+ * 	2:          basic operations (allocations/frees) are logged
+ * 	3:          produce very verbose tracing of function calls in libpmem
+ * 	4:          also log obscure stuff used to debug the library itself
+ *
+ * The default print_func prints to stderr.  Applications can override this
+ * by setting the environment variable PMEM_LOG_FILE, or by supplying a
+ * replacement print function.
+ */
+void pmem_set_funcs(
+		void *(*malloc_func)(size_t size),
+		void (*free_func)(void *ptr),
+		void *(*realloc_func)(void *ptr, size_t size),
+		char *(*strdup_func)(const char *s),
+		void (*print_func)(const char *s),
+		void (*persist_func)(void *addr, size_t len, int flags));
+
+/*
+ * These are consistency checkers, for library debugging/testing, meant to
+ * work on persistent memory files that are not current mapped or in use.
+ */
+int pmemtrn_check(const char *path);
+int pmemblk_check(const char *path);
+int pmemlog_check(const char *path);
+
+#ifdef __cplusplus
+}
+#endif
+#endif	/* libpmem.h */
diff --git a/src/include/libvmem.h b/src/include/libvmem.h
new file mode 100644
index 0000000000000000000000000000000000000000..ba70969bc9e1e186d63945aace71f0879eee0d7c
--- /dev/null
+++ b/src/include/libvmem.h
@@ -0,0 +1,119 @@
+/*
+ * Copyright (c) 2014, Intel Corporation
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ *     * Redistributions of source code must retain the above copyright
+ *       notice, this list of conditions and the following disclaimer.
+ *
+ *     * Redistributions in binary form must reproduce the above copyright
+ *       notice, this list of conditions and the following disclaimer in
+ *       the documentation and/or other materials provided with the
+ *       distribution.
+ *
+ *     * Neither the name of Intel Corporation nor the names of its
+ *       contributors may be used to endorse or promote products derived
+ *       from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+/*
+ * libvmem.h -- definitions of libvmem entry points
+ *
+ * This library exposes memory-mapped files as volatile memory (a la malloc)
+ *
+ * See libvmem(3) for details.
+ */
+
+#ifndef	LIBVMEM_H
+#define	LIBVMEM_H 1
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#include <sys/types.h>
+
+typedef struct vmem VMEM;	/* opaque type internal to libvmem */
+
+/*
+ * managing volatile memory pools...
+ */
+
+#define	VMEM_MIN_POOL ((size_t)(1024 * 1024 * 14)) /* min pool size: 14MB */
+
+VMEM *vmem_pool_create(const char *dir, size_t size);
+VMEM *vmem_pool_create_in_region(void *addr, size_t size);
+void vmem_pool_delete(VMEM *vmp);
+int vmem_pool_check(VMEM *vmp);
+size_t vmem_pool_freespace(VMEM *vmp);
+void vmem_pool_stats_print(VMEM *vmp, const char *opts);
+
+/*
+ * support for malloc and friends...
+ */
+void *vmem_malloc(VMEM *vmp, size_t size);
+void vmem_free(VMEM *vmp, void *ptr);
+void *vmem_calloc(VMEM *vmp, size_t nmemb, size_t size);
+void *vmem_realloc(VMEM *vmp, void *ptr, size_t size);
+void *vmem_aligned_alloc(VMEM *vmp, size_t alignment, size_t size);
+char *vmem_strdup(VMEM *vmp, const char *s);
+
+/*
+ * managing overall library behavior...
+ */
+
+/*
+ * VMEM_MAJOR_VERSION and VMEM_MINOR_VERSION provide the current
+ * version of the libvmem API as provided by this header file.
+ * Applications can verify that the version available at run-time
+ * is compatible with the version used at compile-time by passing
+ * these defines to vmem_check_version().
+ */
+#define	VMEM_MAJOR_VERSION 1
+#define	VMEM_MINOR_VERSION 0
+const char *vmem_check_version(
+		unsigned major_required,
+		unsigned minor_required);
+
+/*
+ * Passing NULL to vmem_set_funcs() tells libvmem to continue to use
+ * the default for that function.  The replacement functions must
+ * not make calls back into libvmem.
+ *
+ * The print_func is called by libvmem based on the environment
+ * variable VMEM_LOG_LEVEL:
+ * 	0 or unset: print_func is only called for vmem_pool_stats_print()
+ * 	1:          additional details are logged when errors are returned
+ * 	2:          basic operations (allocations/frees) are logged
+ * 	3:          produce very verbose tracing of function calls in libvmem
+ * 	4:          also log obscure stuff used to debug the library itself
+ *
+ * The default print_func prints to stderr.  Applications can override this
+ * by setting the environment variable VMEM_LOG_FILE, or by supplying a
+ * replacement print function.
+ */
+void vmem_set_funcs(
+		void *(*malloc_func)(size_t size),
+		void (*free_func)(void *ptr),
+		void *(*realloc_func)(void *ptr, size_t size),
+		char *(*strdup_func)(const char *s),
+		void (*print_func)(const char *s));
+
+#ifdef __cplusplus
+}
+#endif
+#endif	/* libvmem.h */
diff --git a/src/jemalloc.cfg b/src/jemalloc.cfg
new file mode 100644
index 0000000000000000000000000000000000000000..90385c6834c4bf200ed0f65881eda3a6918b4754
--- /dev/null
+++ b/src/jemalloc.cfg
@@ -0,0 +1,7 @@
+--without-export
+--with-jemalloc-prefix=je_vmem_
+--with-private-namespace=je_vmem_
+--disable-xmalloc
+--disable-munmap
+EXTRA_CFLAGS="-DJEMALLOC_LIBVMEM -Werror"
+
diff --git a/src/jemalloc/.gitignore b/src/jemalloc/.gitignore
index 4c408ec2c28380571fd761abce5729b2cedc7ac5..a297b3d6a1a9749f1efd6c2cbf917392636aefe9 100644
--- a/src/jemalloc/.gitignore
+++ b/src/jemalloc/.gitignore
@@ -18,6 +18,7 @@
 /lib/
 
 /Makefile
+/Makefile_debug
 
 /include/jemalloc/internal/jemalloc_internal.h
 /include/jemalloc/internal/jemalloc_internal_defs.h
@@ -70,3 +71,5 @@ test/include/test/jemalloc_test_defs.h
 /test/unit/*.out
 
 /VERSION
+
+/debugsrc/*
\ No newline at end of file
diff --git a/src/jemalloc/INSTALL b/src/jemalloc/INSTALL
index 841704d2a08d4ef5f1c1434b4a4d8e5d4df295d5..2df667cad5c2b2e6735bd022ad2d8987cfce9ac7 100644
--- a/src/jemalloc/INSTALL
+++ b/src/jemalloc/INSTALL
@@ -71,10 +71,10 @@ any of the following arguments (not a definitive list) to 'configure':
     versions of jemalloc can coexist in the same installation directory.  For
     example, libjemalloc.so.0 becomes libjemalloc<suffix>.so.0.
 
---enable-cc-silence
-    Enable code that silences non-useful compiler warnings.  This is helpful
-    when trying to tell serious warnings from those due to compiler
-    limitations, but it potentially incurs a performance penalty.
+--disable-cc-silence
+    Disable code that silences non-useful compiler warnings.  This is mainly
+    useful during development when auditing the set of warnings that are being
+    silenced.
 
 --enable-debug
     Enable assertions and validation code.  This incurs a substantial
@@ -132,12 +132,6 @@ any of the following arguments (not a definitive list) to 'configure':
     released in bulk, thus reducing the total number of mutex operations.  See
     the "opt.tcache" option for usage details.
 
---enable-mremap
-    Enable huge realloc() via mremap(2).  mremap() is disabled by default
-    because the flavor used is specific to Linux, which has a quirk in its
-    virtual memory allocation algorithm that causes semi-permanent VM map holes
-    under normal jemalloc operation.
-
 --disable-munmap
     Disable virtual memory deallocation via munmap(2); instead keep track of
     the virtual memory for later use.  munmap() is disabled by default (i.e.
@@ -145,10 +139,6 @@ any of the following arguments (not a definitive list) to 'configure':
     memory allocation algorithm that causes semi-permanent VM map holes under
     normal jemalloc operation.
 
---enable-dss
-    Enable support for page allocation/deallocation via sbrk(2), in addition to
-    mmap(2).
-
 --disable-fill
     Disable support for junk/zero filling of memory, quarantine, and redzones.
     See the "opt.junk", "opt.zero", "opt.quarantine", and "opt.redzone" option
@@ -157,9 +147,6 @@ any of the following arguments (not a definitive list) to 'configure':
 --disable-valgrind
     Disable support for Valgrind.
 
---disable-experimental
-    Disable support for the experimental API (*allocm()).
-
 --disable-zone-allocator
     Disable zone allocator for Darwin. This means jemalloc won't be hooked as
     the default allocator on OSX/iOS.
diff --git a/src/jemalloc/Makefile.in b/src/jemalloc/Makefile.in
index d6b7d6ea3b49a4161275570f657e6102db665115..e0dbb019e6a8d55b30e52b37c027e4b621fab593 100644
--- a/src/jemalloc/Makefile.in
+++ b/src/jemalloc/Makefile.in
@@ -48,7 +48,7 @@ cfgoutputs_in := @cfgoutputs_in@
 cfgoutputs_out := @cfgoutputs_out@
 enable_autogen := @enable_autogen@
 enable_code_coverage := @enable_code_coverage@
-enable_experimental := @enable_experimental@
+enable_valgrind := @enable_valgrind@
 enable_zone_allocator := @enable_zone_allocator@
 DSO_LDFLAGS = @DSO_LDFLAGS@
 SOREV = @SOREV@
@@ -75,14 +75,17 @@ LIBJEMALLOC := $(LIBPREFIX)jemalloc$(install_suffix)
 # Lists of files.
 BINS := $(srcroot)bin/pprof $(objroot)bin/jemalloc.sh
 C_HDRS := $(objroot)include/jemalloc/jemalloc$(install_suffix).h
-C_SRCS := $(srcroot)src/jemalloc.c $(srcroot)src/arena.c \
+C_SRCS := $(srcroot)src/jemalloc.c $(srcroot)src/arena.c $(srcroot)src/pool.c \
 	$(srcroot)src/atomic.c $(srcroot)src/base.c $(srcroot)src/bitmap.c \
-	$(srcroot)src/chunk.c $(srcroot)src/chunk_dss.c \
+	$(srcroot)src/chunk.c $(srcroot)src/chunk_dss.c $(srcroot)src/vector.c \
 	$(srcroot)src/chunk_mmap.c $(srcroot)src/ckh.c $(srcroot)src/ctl.c \
 	$(srcroot)src/extent.c $(srcroot)src/hash.c $(srcroot)src/huge.c \
 	$(srcroot)src/mb.c $(srcroot)src/mutex.c $(srcroot)src/prof.c \
 	$(srcroot)src/quarantine.c $(srcroot)src/rtree.c $(srcroot)src/stats.c \
 	$(srcroot)src/tcache.c $(srcroot)src/util.c $(srcroot)src/tsd.c
+ifeq ($(enable_valgrind), 1)
+C_SRCS += $(srcroot)src/valgrind.c
+endif
 ifeq ($(enable_zone_allocator), 1)
 C_SRCS += $(srcroot)src/zone.c
 endif
@@ -127,23 +130,22 @@ TESTS_UNIT := $(srcroot)test/unit/bitmap.c \
 	$(srcroot)test/unit/stats.c \
 	$(srcroot)test/unit/tsd.c \
 	$(srcroot)test/unit/util.c \
-	$(srcroot)test/unit/zero.c
+	$(srcroot)test/unit/zero.c \
+	$(srcroot)test/unit/pool_base_alloc.c \
+	$(srcroot)test/unit/pool_custom_alloc.c \
+	$(srcroot)test/unit/pool_custom_alloc_internal.c
 TESTS_UNIT_AUX := $(srcroot)test/unit/prof_accum_a.c \
 	$(srcroot)test/unit/prof_accum_b.c
 TESTS_INTEGRATION := $(srcroot)test/integration/aligned_alloc.c \
 	$(srcroot)test/integration/allocated.c \
 	$(srcroot)test/integration/mallocx.c \
-	$(srcroot)test/integration/mremap.c \
+	$(srcroot)test/integration/MALLOCX_ARENA.c \
 	$(srcroot)test/integration/posix_memalign.c \
 	$(srcroot)test/integration/rallocx.c \
 	$(srcroot)test/integration/thread_arena.c \
 	$(srcroot)test/integration/thread_tcache_enabled.c \
-	$(srcroot)test/integration/xallocx.c
-ifeq ($(enable_experimental), 1)
-TESTS_INTEGRATION += $(srcroot)test/integration/allocm.c \
-	$(srcroot)test/integration/MALLOCX_ARENA.c \
-	$(srcroot)test/integration/rallocm.c
-endif
+	$(srcroot)test/integration/xallocx.c \
+	$(srcroot)test/integration/chunk.c
 TESTS_STRESS :=
 TESTS := $(TESTS_UNIT) $(TESTS_INTEGRATION) $(TESTS_STRESS)
 
@@ -214,13 +216,13 @@ define make-unit-link-dep
 $(1): TESTS_UNIT_LINK_OBJS += $(2)
 $(1): $(2)
 endef
-$(foreach test, $(TESTS_UNIT:$(srcroot)test/unit/%.c=$(objroot)test/unit/%$(EXE)), $(eval $(call make-unit-link-dep,$(test),$(filter $(test:%=%_a.$(O)) $(test:%=%_b.$(O)),$(TESTS_UNIT_AUX_OBJS)))))
+$(foreach test, $(TESTS_UNIT:$(srcroot)test/unit/%.c=$(objroot)test/unit/%$(EXE)), $(eval $(call make-unit-link-dep,$(test),$(filter $(test:%$(EXE)=%_a.$(O)) $(test:%$(EXE)=%_b.$(O)),$(TESTS_UNIT_AUX_OBJS)))))
 $(TESTS_INTEGRATION_OBJS): CPPFLAGS += -DJEMALLOC_INTEGRATION_TEST
 $(TESTS_STRESS_OBJS): CPPFLAGS += -DJEMALLOC_STRESS_TEST
 $(TESTS_OBJS): $(objroot)test/%.$(O): $(srcroot)test/%.c
 $(TESTS_OBJS): CPPFLAGS += -I$(srcroot)test/include -I$(objroot)test/include
 ifneq ($(IMPORTLIB),$(SO))
-$(C_OBJS): CPPFLAGS += -DDLLEXPORT
+$(C_OBJS) $(C_JET_OBJS): CPPFLAGS += -DDLLEXPORT
 endif
 
 ifndef CC_MM
@@ -229,7 +231,7 @@ HEADER_DIRS = $(srcroot)include/jemalloc/internal \
 	$(objroot)include/jemalloc $(objroot)include/jemalloc/internal
 HEADERS = $(wildcard $(foreach dir,$(HEADER_DIRS),$(dir)/*.h))
 $(C_OBJS) $(C_PIC_OBJS) $(C_JET_OBJS) $(C_TESTLIB_OBJS) $(TESTS_OBJS): $(HEADERS)
-$(TESTS_OBJS): $(objroot)test/unit/jemalloc_test.h
+$(TESTS_OBJS): $(objroot)test/include/test/jemalloc_test.h
 endif
 
 $(C_OBJS) $(C_PIC_OBJS) $(C_JET_OBJS) $(C_TESTLIB_OBJS) $(TESTS_OBJS): %.$(O):
diff --git a/src/jemalloc/bin/pprof b/src/jemalloc/bin/pprof
index a309943c1cb9383643fd06e3eb85371f184d274e..328138cd982f266bcfffa882a47c542416367bd9 100755
--- a/src/jemalloc/bin/pprof
+++ b/src/jemalloc/bin/pprof
@@ -2811,9 +2811,14 @@ sub RemoveUninterestingFrames {
                       'free',
                       'memalign',
                       'posix_memalign',
+                      'aligned_alloc',
                       'pvalloc',
                       'valloc',
                       'realloc',
+                      'mallocx', # jemalloc
+                      'rallocx', # jemalloc
+                      'xallocx', # jemalloc
+                      'dallocx', # jemalloc
                       'tc_calloc',
                       'tc_cfree',
                       'tc_malloc',
@@ -2923,6 +2928,10 @@ sub RemoveUninterestingFrames {
       if (exists($symbols->{$a})) {
         my $func = $symbols->{$a}->[0];
         if ($skip{$func} || ($func =~ m/$skip_regexp/)) {
+          # Throw away the portion of the backtrace seen so far, under the
+          # assumption that previous frames were for functions internal to the
+          # allocator.
+          @path = ();
           next;
         }
       }
diff --git a/src/jemalloc/config.sub b/src/jemalloc/config.sub
index 61cb4bc22db8e0a490b5ea5bffe6575c10ff92e0..c4cc98365fd3daa64d16f6ae1086bb3607ede579 100755
--- a/src/jemalloc/config.sub
+++ b/src/jemalloc/config.sub
@@ -1400,6 +1400,8 @@ case $os in
 	-mac*)
 		os=`echo $os | sed -e 's|mac|macos|'`
 		;;
+	-ios*)
+		;;
 	-linux-dietlibc)
 		os=-linux-dietlibc
 		;;
diff --git a/src/jemalloc/configure.ac b/src/jemalloc/configure.ac
index 4de81dc1d9f21a635cd04c3f63d8dd9892e7ff93..38da66206da1fad18eb7e6dfda0c02e18b44af24 100644
--- a/src/jemalloc/configure.ac
+++ b/src/jemalloc/configure.ac
@@ -44,7 +44,7 @@ AC_CACHE_CHECK([whether $1 is compilable],
 dnl ============================================================================
 
 dnl Library revision.
-rev=1
+rev=2
 AC_SUBST([rev])
 
 srcroot=$srcdir
@@ -141,7 +141,8 @@ if test "x$CFLAGS" = "x" ; then
     JE_CFLAGS_APPEND([-Zi])
     JE_CFLAGS_APPEND([-MT])
     JE_CFLAGS_APPEND([-W3])
-    CPPFLAGS="$CPPFLAGS -I${srcroot}/include/msvc_compat"
+    JE_CFLAGS_APPEND([-FS])
+    CPPFLAGS="$CPPFLAGS -I${srcdir}/include/msvc_compat"
   fi
 fi
 dnl Append EXTRA_CFLAGS to CFLAGS, if defined.
@@ -155,6 +156,10 @@ if test "x${ac_cv_big_endian}" = "x1" ; then
   AC_DEFINE_UNQUOTED([JEMALLOC_BIG_ENDIAN], [ ])
 fi
 
+if test "x${je_cv_msvc}" = "xyes" -a "x${ac_cv_header_inttypes_h}" = "xno"; then
+  CPPFLAGS="$CPPFLAGS -I${srcdir}/include/msvc_compat/C99"
+fi
+
 AC_CHECK_SIZEOF([void *])
 if test "x${ac_cv_sizeof_void_p}" = "x8" ; then
   LG_SIZEOF_PTR=3
@@ -258,9 +263,8 @@ dnl Define cpp macros in CPPFLAGS, rather than doing AC_DEFINE(macro), since the
 dnl definitions need to be seen before any headers are included, which is a pain
 dnl to make happen otherwise.
 default_munmap="1"
-JEMALLOC_USABLE_SIZE_CONST="const"
 case "${host}" in
-  *-*-darwin*)
+  *-*-darwin* | *-*-ios*)
 	CFLAGS="$CFLAGS"
 	abi="macho"
 	AC_DEFINE([JEMALLOC_PURGE_MADVISE_FREE], [ ])
@@ -286,7 +290,6 @@ case "${host}" in
 	AC_DEFINE([JEMALLOC_HAS_ALLOCA_H])
 	AC_DEFINE([JEMALLOC_PURGE_MADVISE_DONTNEED], [ ])
 	AC_DEFINE([JEMALLOC_THREADED_INIT], [ ])
-	JEMALLOC_USABLE_SIZE_CONST=""
 	default_munmap="0"
 	;;
   *-*-netbsd*)
@@ -351,6 +354,22 @@ case "${host}" in
 	abi="elf"
 	;;
 esac
+
+JEMALLOC_USABLE_SIZE_CONST=const
+AC_CHECK_HEADERS([malloc.h], [
+  AC_MSG_CHECKING([whether malloc_usable_size definition can use const argument])
+  AC_COMPILE_IFELSE([AC_LANG_PROGRAM(
+    [#include <malloc.h>
+     #include <stddef.h>
+    size_t malloc_usable_size(const void *ptr);
+    ],
+    [])],[
+                AC_MSG_RESULT([yes])
+         ],[
+                JEMALLOC_USABLE_SIZE_CONST=
+                AC_MSG_RESULT([no])
+         ])
+])
 AC_DEFINE_UNQUOTED([JEMALLOC_USABLE_SIZE_CONST], [$JEMALLOC_USABLE_SIZE_CONST])
 AC_SUBST([abi])
 AC_SUBST([RPATH])
@@ -428,7 +447,7 @@ AC_PROG_RANLIB
 AC_PATH_PROG([LD], [ld], [false], [$PATH])
 AC_PATH_PROG([AUTOCONF], [autoconf], [false], [$PATH])
 
-public_syms="malloc_conf malloc_message malloc calloc posix_memalign aligned_alloc realloc free mallocx rallocx xallocx sallocx dallocx nallocx mallctl mallctlnametomib mallctlbymib malloc_stats_print malloc_usable_size"
+public_syms="pool_create pool_delete pool_malloc pool_calloc pool_ralloc pool_aligned_alloc pool_free pool_malloc_stats_print pool_extend pool_set_alloc_funcs malloc_conf malloc_message malloc calloc posix_memalign aligned_alloc realloc free mallocx rallocx xallocx sallocx dallocx nallocx mallctl mallctlnametomib mallctlbymib malloc_stats_print malloc_usable_size"
 
 dnl Check for allocator-related functions that should be wrapped.
 AC_CHECK_FUNC([memalign],
@@ -438,24 +457,6 @@ AC_CHECK_FUNC([valloc],
 	      [AC_DEFINE([JEMALLOC_OVERRIDE_VALLOC], [ ])
 	       public_syms="${public_syms} valloc"])
 
-dnl Support the experimental API by default.
-AC_ARG_ENABLE([experimental],
-  [AS_HELP_STRING([--disable-experimental],
-   [Disable support for the experimental API])],
-[if test "x$enable_experimental" = "xno" ; then
-  enable_experimental="0"
-else
-  enable_experimental="1"
-fi
-],
-[enable_experimental="1"]
-)
-if test "x$enable_experimental" = "x1" ; then
-  AC_DEFINE([JEMALLOC_EXPERIMENTAL], [ ])
-  public_syms="${public_syms} allocm dallocm nallocm rallocm sallocm"
-fi
-AC_SUBST([enable_experimental])
-
 dnl Do not compute test code coverage by default.
 GCOV_FLAGS=
 AC_ARG_ENABLE([code-coverage],
@@ -595,18 +596,17 @@ cfghdrs_tup="include/jemalloc/jemalloc_defs.h:include/jemalloc/jemalloc_defs.h.i
 cfghdrs_tup="${cfghdrs_tup} include/jemalloc/internal/jemalloc_internal_defs.h:${srcroot}include/jemalloc/internal/jemalloc_internal_defs.h.in"
 cfghdrs_tup="${cfghdrs_tup} test/include/test/jemalloc_test_defs.h:${srcroot}test/include/test/jemalloc_test_defs.h.in"
 
-dnl Do not silence irrelevant compiler warnings by default, since enabling this
-dnl option incurs a performance penalty.
+dnl Silence irrelevant compiler warnings by default.
 AC_ARG_ENABLE([cc-silence],
-  [AS_HELP_STRING([--enable-cc-silence],
-                  [Silence irrelevant compiler warnings])],
+  [AS_HELP_STRING([--disable-cc-silence],
+                  [Do not silence irrelevant compiler warnings])],
 [if test "x$enable_cc_silence" = "xno" ; then
   enable_cc_silence="0"
 else
   enable_cc_silence="1"
 fi
 ],
-[enable_cc_silence="0"]
+[enable_cc_silence="1"]
 )
 if test "x$enable_cc_silence" = "x1" ; then
   AC_DEFINE([JEMALLOC_CC_SILENCE], [ ])
@@ -721,7 +721,7 @@ fi,
 if test "x$backtrace_method" = "x" -a "x$enable_prof_libunwind" = "x1" ; then
   AC_CHECK_HEADERS([libunwind.h], , [enable_prof_libunwind="0"])
   if test "x$LUNWIND" = "x-lunwind" ; then
-    AC_CHECK_LIB([unwind], [backtrace], [LIBS="$LIBS $LUNWIND"],
+    AC_CHECK_LIB([unwind], [unw_backtrace], [LIBS="$LIBS $LUNWIND"],
                  [enable_prof_libunwind="0"])
   else
     LIBS="$LIBS $LUNWIND"
@@ -812,33 +812,6 @@ if test "x$enable_tcache" = "x1" ; then
 fi
 AC_SUBST([enable_tcache])
 
-dnl Disable mremap() for huge realloc() by default.
-AC_ARG_ENABLE([mremap],
-  [AS_HELP_STRING([--enable-mremap], [Enable mremap(2) for huge realloc()])],
-[if test "x$enable_mremap" = "xno" ; then
-  enable_mremap="0"
-else
-  enable_mremap="1"
-fi
-],
-[enable_mremap="0"]
-)
-if test "x$enable_mremap" = "x1" ; then
-  JE_COMPILABLE([mremap(...MREMAP_FIXED...)], [
-#define	_GNU_SOURCE
-#include <sys/mman.h>
-], [
-void *p = mremap((void *)0, 0, 0, MREMAP_MAYMOVE|MREMAP_FIXED, (void *)0);
-], [je_cv_mremap_fixed])
-  if test "x${je_cv_mremap_fixed}" = "xno" ; then
-    enable_mremap="0"
-  fi
-fi
-if test "x$enable_mremap" = "x1" ; then
-  AC_DEFINE([JEMALLOC_MREMAP], [ ])
-fi
-AC_SUBST([enable_mremap])
-
 dnl Enable VM deallocation via munmap() by default.
 AC_ARG_ENABLE([munmap],
   [AS_HELP_STRING([--disable-munmap], [Disable VM deallocation via munmap(2)])],
@@ -855,34 +828,22 @@ if test "x$enable_munmap" = "x1" ; then
 fi
 AC_SUBST([enable_munmap])
 
-dnl Do not enable allocation from DSS by default.
-AC_ARG_ENABLE([dss],
-  [AS_HELP_STRING([--enable-dss], [Enable allocation from DSS])],
-[if test "x$enable_dss" = "xno" ; then
-  enable_dss="0"
-else
-  enable_dss="1"
-fi
-],
-[enable_dss="0"]
-)
+dnl Enable allocation from DSS if supported by the OS.
+have_dss="1"
 dnl Check whether the BSD/SUSv1 sbrk() exists.  If not, disable DSS support.
 AC_CHECK_FUNC([sbrk], [have_sbrk="1"], [have_sbrk="0"])
 if test "x$have_sbrk" = "x1" ; then
   if test "x$sbrk_deprecated" == "x1" ; then
     AC_MSG_RESULT([Disabling dss allocation because sbrk is deprecated])
-    enable_dss="0"
-  else
-    AC_DEFINE([JEMALLOC_HAVE_SBRK], [ ])
+    have_dss="0"
   fi
 else
-  enable_dss="0"
+  have_dss="0"
 fi
 
-if test "x$enable_dss" = "x1" ; then
+if test "x$have_dss" = "x1" ; then
   AC_DEFINE([JEMALLOC_DSS], [ ])
 fi
-AC_SUBST([enable_dss])
 
 dnl Support the junk/zero filling option by default.
 AC_ARG_ENABLE([fill],
@@ -974,6 +935,44 @@ if test "x$enable_xmalloc" = "x1" ; then
 fi
 AC_SUBST([enable_xmalloc])
 
+dnl ============================================================================
+dnl Check for  __builtin_ffsl(), then ffsl(3), and fail if neither are found.
+dnl One of those two functions should (theoretically) exist on all platforms
+dnl that jemalloc currently has a chance of functioning on without modification.
+dnl We additionally assume ffs() or __builtin_ffs() are defined if
+dnl ffsl() or __builtin_ffsl() are defined, respectively.
+JE_COMPILABLE([a program using __builtin_ffsl], [
+#include <stdio.h>
+#include <strings.h>
+#include <string.h>
+], [
+	{
+		int rv = __builtin_ffsl(0x08);
+		printf("%d\n", rv);
+	}
+], [je_cv_gcc_builtin_ffsl])
+if test "x${je_cv_gcc_builtin_ffsl}" == "xyes" ; then
+  AC_DEFINE([JEMALLOC_INTERNAL_FFSL], [__builtin_ffsl])
+  AC_DEFINE([JEMALLOC_INTERNAL_FFS], [__builtin_ffs])
+else
+  JE_COMPILABLE([a program using ffsl], [
+  #include <stdio.h>
+  #include <strings.h>
+  #include <string.h>
+  ], [
+	{
+		int rv = ffsl(0x08);
+		printf("%d\n", rv);
+	}
+  ], [je_cv_function_ffsl])
+  if test "x${je_cv_function_ffsl}" == "xyes" ; then
+    AC_DEFINE([JEMALLOC_INTERNAL_FFSL], [ffsl])
+    AC_DEFINE([JEMALLOC_INTERNAL_FFS], [ffs])
+  else
+    AC_MSG_ERROR([Cannot build without ffsl(3) or __builtin_ffsl()])
+  fi
+fi
+
 AC_CACHE_CHECK([STATIC_PAGE_SHIFT],
                [je_cv_static_page_shift],
                AC_RUN_IFELSE([AC_LANG_PROGRAM(
@@ -1000,7 +999,7 @@ AC_CACHE_CHECK([STATIC_PAGE_SHIFT],
     if (result == -1) {
 	return 1;
     }
-    result = ffsl(result) - 1;
+    result = JEMALLOC_INTERNAL_FFSL(result) - 1;
 
     f = fopen("conftest.out", "w");
     if (f == NULL) {
@@ -1012,7 +1011,8 @@ AC_CACHE_CHECK([STATIC_PAGE_SHIFT],
     return 0;
 ]])],
                              [je_cv_static_page_shift=`cat conftest.out`],
-                             [je_cv_static_page_shift=undefined]))
+                             [je_cv_static_page_shift=undefined],
+                             [je_cv_static_page_shift=12]))
 
 if test "x$je_cv_static_page_shift" != "xundefined"; then
    AC_DEFINE_UNQUOTED([STATIC_PAGE_SHIFT], [$je_cv_static_page_shift])
@@ -1146,24 +1146,6 @@ elif test "x${force_tls}" = "x1" ; then
   AC_MSG_ERROR([Failed to configure TLS, which is mandatory for correct function])
 fi
 
-dnl ============================================================================
-dnl Check for ffsl(3), and fail if not found.  This function exists on all
-dnl platforms that jemalloc currently has a chance of functioning on without
-dnl modification.
-JE_COMPILABLE([a program using ffsl], [
-#include <stdio.h>
-#include <strings.h>
-#include <string.h>
-], [
-	{
-		int rv = ffsl(0x08);
-		printf("%d\n", rv);
-	}
-], [je_cv_function_ffsl])
-if test "x${je_cv_function_ffsl}" != "xyes" ; then
-   AC_MSG_ERROR([Cannot build without ffsl(3)])
-fi
-
 dnl ============================================================================
 dnl Check for atomic(9) operations as provided on FreeBSD.
 
@@ -1209,6 +1191,20 @@ if test "x${je_cv_osatomic}" = "xyes" ; then
   AC_DEFINE([JEMALLOC_OSATOMIC], [ ])
 fi
 
+dnl ============================================================================
+dnl Check for madvise(2).
+
+JE_COMPILABLE([madvise(2)], [
+#include <sys/mman.h>
+], [
+	{
+		madvise((void *)0, 0, 0);
+	}
+], [je_cv_madvise])
+if test "x${je_cv_madvise}" = "xyes" ; then
+  AC_DEFINE([JEMALLOC_HAVE_MADVISE], [ ])
+fi
+
 dnl ============================================================================
 dnl Check whether __sync_{add,sub}_and_fetch() are available despite
 dnl __GCC_HAVE_SYNC_COMPARE_AND_SWAP_n macros being undefined.
@@ -1243,6 +1239,29 @@ if test "x${je_cv_atomic9}" != "xyes" -a "x${je_cv_osatomic}" != "xyes" ; then
   JE_SYNC_COMPARE_AND_SWAP_CHECK(64, 8)
 fi
 
+dnl ============================================================================
+dnl Check for __builtin_clz() and __builtin_clzl().
+
+AC_CACHE_CHECK([for __builtin_clz],
+               [je_cv_builtin_clz],
+               [AC_LINK_IFELSE([AC_LANG_PROGRAM([],
+                                                [
+                                                {
+                                                        unsigned x = 0;
+                                                        int y = __builtin_clz(x);
+                                                }
+                                                {
+                                                        unsigned long x = 0;
+                                                        int y = __builtin_clzl(x);
+                                                }
+                                                ])],
+                               [je_cv_builtin_clz=yes],
+                               [je_cv_builtin_clz=no])])
+
+if test "x${je_cv_builtin_clz}" = "xyes" ; then
+  AC_DEFINE([JEMALLOC_HAVE_BUILTIN_CLZ], [ ])
+fi
+
 dnl ============================================================================
 dnl Check for spinlock(3) operations as provided on Darwin.
 
@@ -1465,7 +1484,6 @@ AC_MSG_RESULT([JEMALLOC_PRIVATE_NAMESPACE])
 AC_MSG_RESULT([                   : ${JEMALLOC_PRIVATE_NAMESPACE}])
 AC_MSG_RESULT([install_suffix     : ${install_suffix}])
 AC_MSG_RESULT([autogen            : ${enable_autogen}])
-AC_MSG_RESULT([experimental       : ${enable_experimental}])
 AC_MSG_RESULT([cc-silence         : ${enable_cc_silence}])
 AC_MSG_RESULT([debug              : ${enable_debug}])
 AC_MSG_RESULT([code-coverage      : ${enable_code_coverage}])
@@ -1479,9 +1497,7 @@ AC_MSG_RESULT([fill               : ${enable_fill}])
 AC_MSG_RESULT([utrace             : ${enable_utrace}])
 AC_MSG_RESULT([valgrind           : ${enable_valgrind}])
 AC_MSG_RESULT([xmalloc            : ${enable_xmalloc}])
-AC_MSG_RESULT([mremap             : ${enable_mremap}])
 AC_MSG_RESULT([munmap             : ${enable_munmap}])
-AC_MSG_RESULT([dss                : ${enable_dss}])
 AC_MSG_RESULT([lazy_lock          : ${enable_lazy_lock}])
 AC_MSG_RESULT([tls                : ${enable_tls}])
 AC_MSG_RESULT([===============================================================================])
diff --git a/src/jemalloc/doc/jemalloc.xml.in b/src/jemalloc/doc/jemalloc.xml.in
index d8e2e711f2c8c25d90f64ea90feec4fce376afec..308d0c6530c789a32b3531b6e26b71afd3545b9d 100644
--- a/src/jemalloc/doc/jemalloc.xml.in
+++ b/src/jemalloc/doc/jemalloc.xml.in
@@ -44,11 +44,6 @@
     <refname>mallctlbymib</refname>
     <refname>malloc_stats_print</refname>
     <refname>malloc_usable_size</refname>
-    <refname>allocm</refname>
-    <refname>rallocm</refname>
-    <refname>sallocm</refname>
-    <refname>dallocm</refname>
-    <refname>nallocm</refname>
     -->
     <refpurpose>general purpose memory allocation functions</refpurpose>
   </refnamediv>
@@ -172,41 +167,6 @@
         </funcprototype>
         <para><type>const char *</type><varname>malloc_conf</varname>;</para>
       </refsect2>
-      <refsect2>
-      <title>Experimental API</title>
-        <funcprototype>
-          <funcdef>int <function>allocm</function></funcdef>
-          <paramdef>void **<parameter>ptr</parameter></paramdef>
-          <paramdef>size_t *<parameter>rsize</parameter></paramdef>
-          <paramdef>size_t <parameter>size</parameter></paramdef>
-          <paramdef>int <parameter>flags</parameter></paramdef>
-        </funcprototype>
-        <funcprototype>
-          <funcdef>int <function>rallocm</function></funcdef>
-          <paramdef>void **<parameter>ptr</parameter></paramdef>
-          <paramdef>size_t *<parameter>rsize</parameter></paramdef>
-          <paramdef>size_t <parameter>size</parameter></paramdef>
-          <paramdef>size_t <parameter>extra</parameter></paramdef>
-          <paramdef>int <parameter>flags</parameter></paramdef>
-        </funcprototype>
-        <funcprototype>
-          <funcdef>int <function>sallocm</function></funcdef>
-          <paramdef>const void *<parameter>ptr</parameter></paramdef>
-          <paramdef>size_t *<parameter>rsize</parameter></paramdef>
-          <paramdef>int <parameter>flags</parameter></paramdef>
-        </funcprototype>
-        <funcprototype>
-          <funcdef>int <function>dallocm</function></funcdef>
-          <paramdef>void *<parameter>ptr</parameter></paramdef>
-          <paramdef>int <parameter>flags</parameter></paramdef>
-        </funcprototype>
-        <funcprototype>
-          <funcdef>int <function>nallocm</function></funcdef>
-          <paramdef>size_t *<parameter>rsize</parameter></paramdef>
-          <paramdef>size_t <parameter>size</parameter></paramdef>
-          <paramdef>int <parameter>flags</parameter></paramdef>
-        </funcprototype>
-      </refsect2>
     </funcsynopsis>
   </refsynopsisdiv>
   <refsect1 id="description">
@@ -229,15 +189,15 @@
 
       <para>The <function>posix_memalign<parameter/></function> function
       allocates <parameter>size</parameter> bytes of memory such that the
-      allocation's base address is an even multiple of
+      allocation's base address is a multiple of
       <parameter>alignment</parameter>, and returns the allocation in the value
       pointed to by <parameter>ptr</parameter>.  The requested
-      <parameter>alignment</parameter> must be a power of 2 at least as large
-      as <code language="C">sizeof(<type>void *</type>)</code>.</para>
+      <parameter>alignment</parameter> must be a power of 2 at least as large as
+      <code language="C">sizeof(<type>void *</type>)</code>.</para>
 
       <para>The <function>aligned_alloc<parameter/></function> function
       allocates <parameter>size</parameter> bytes of memory such that the
-      allocation's base address is an even multiple of
+      allocation's base address is a multiple of
       <parameter>alignment</parameter>.  The requested
       <parameter>alignment</parameter> must be a power of 2.  Behavior is
       undefined if <parameter>size</parameter> is not an integral multiple of
@@ -310,10 +270,10 @@
 
             <listitem><para>Use the arena specified by the index
             <parameter>a</parameter> (and by necessity bypass the thread
-            cache).  This macro has no effect for huge regions, nor for regions
-            that were allocated via an arena other than the one specified.
-            This macro does not validate that <parameter>a</parameter>
-            specifies an arena index in the valid range.</para></listitem>
+            cache).  This macro has no effect for regions that were allocated
+            via an arena other than the one specified.  This macro does not
+            validate that <parameter>a</parameter> specifies an arena index in
+            the valid range.</para></listitem>
           </varlistentry>
         </variablelist>
       </para>
@@ -449,116 +409,6 @@ for (i = 0; i < nbins; i++) {
       depended on, since such behavior is entirely implementation-dependent.
       </para>
     </refsect2>
-    <refsect2>
-      <title>Experimental API</title>
-      <para>The experimental API is subject to change or removal without regard
-      for backward compatibility.  If <option>--disable-experimental</option>
-      is specified during configuration, the experimental API is
-      omitted.</para>
-
-      <para>The <function>allocm<parameter/></function>,
-      <function>rallocm<parameter/></function>,
-      <function>sallocm<parameter/></function>,
-      <function>dallocm<parameter/></function>, and
-      <function>nallocm<parameter/></function> functions all have a
-      <parameter>flags</parameter> argument that can be used to specify
-      options.  The functions only check the options that are contextually
-      relevant.  Use bitwise or (<code language="C">|</code>) operations to
-      specify one or more of the following:
-        <variablelist>
-          <varlistentry>
-            <term><constant>ALLOCM_LG_ALIGN(<parameter>la</parameter>)
-            </constant></term>
-
-            <listitem><para>Align the memory allocation to start at an address
-            that is a multiple of <code language="C">(1 &lt;&lt;
-            <parameter>la</parameter>)</code>.  This macro does not validate
-            that <parameter>la</parameter> is within the valid
-            range.</para></listitem>
-          </varlistentry>
-          <varlistentry>
-            <term><constant>ALLOCM_ALIGN(<parameter>a</parameter>)
-            </constant></term>
-
-            <listitem><para>Align the memory allocation to start at an address
-            that is a multiple of <parameter>a</parameter>, where
-            <parameter>a</parameter> is a power of two.  This macro does not
-            validate that <parameter>a</parameter> is a power of 2.
-            </para></listitem>
-          </varlistentry>
-          <varlistentry>
-            <term><constant>ALLOCM_ZERO</constant></term>
-
-            <listitem><para>Initialize newly allocated memory to contain zero
-            bytes.  In the growing reallocation case, the real size prior to
-            reallocation defines the boundary between untouched bytes and those
-            that are initialized to contain zero bytes.  If this macro is
-            absent, newly allocated memory is uninitialized.</para></listitem>
-          </varlistentry>
-          <varlistentry>
-            <term><constant>ALLOCM_NO_MOVE</constant></term>
-
-            <listitem><para>For reallocation, fail rather than moving the
-            object.  This constraint can apply to both growth and
-            shrinkage.</para></listitem>
-          </varlistentry>
-          <varlistentry>
-            <term><constant>ALLOCM_ARENA(<parameter>a</parameter>)
-            </constant></term>
-
-            <listitem><para>Use the arena specified by the index
-            <parameter>a</parameter> (and by necessity bypass the thread
-            cache).  This macro has no effect for huge regions, nor for regions
-            that were allocated via an arena other than the one specified.
-            This macro does not validate that <parameter>a</parameter>
-            specifies an arena index in the valid range.</para></listitem>
-          </varlistentry>
-        </variablelist>
-      </para>
-
-      <para>The <function>allocm<parameter/></function> function allocates at
-      least <parameter>size</parameter> bytes of memory, sets
-      <parameter>*ptr</parameter> to the base address of the allocation, and
-      sets <parameter>*rsize</parameter> to the real size of the allocation if
-      <parameter>rsize</parameter> is not <constant>NULL</constant>.  Behavior
-      is undefined if <parameter>size</parameter> is <constant>0</constant>, or
-      if request size overflows due to size class and/or alignment
-      constraints.</para>
-
-      <para>The <function>rallocm<parameter/></function> function resizes the
-      allocation at <parameter>*ptr</parameter> to be at least
-      <parameter>size</parameter> bytes, sets <parameter>*ptr</parameter> to
-      the base address of the allocation if it moved, and sets
-      <parameter>*rsize</parameter> to the real size of the allocation if
-      <parameter>rsize</parameter> is not <constant>NULL</constant>.  If
-      <parameter>extra</parameter> is non-zero, an attempt is made to resize
-      the allocation to be at least <code
-      language="C">(<parameter>size</parameter> +
-      <parameter>extra</parameter>)</code> bytes, though inability to allocate
-      the extra byte(s) will not by itself result in failure.  Behavior is
-      undefined if <parameter>size</parameter> is <constant>0</constant>, if
-      request size overflows due to size class and/or alignment constraints, or
-      if <code language="C">(<parameter>size</parameter> +
-      <parameter>extra</parameter> &gt;
-      <constant>SIZE_T_MAX</constant>)</code>.</para>
-
-      <para>The <function>sallocm<parameter/></function> function sets
-      <parameter>*rsize</parameter> to the real size of the allocation.</para>
-
-      <para>The <function>dallocm<parameter/></function> function causes the
-      memory referenced by <parameter>ptr</parameter> to be made available for
-      future allocations.</para>
-
-      <para>The <function>nallocm<parameter/></function> function allocates no
-      memory, but it performs the same size computation as the
-      <function>allocm<parameter/></function> function, and if
-      <parameter>rsize</parameter> is not <constant>NULL</constant> it sets
-      <parameter>*rsize</parameter> to the real size of the allocation that
-      would result from the equivalent <function>allocm<parameter/></function>
-      function call.  Behavior is undefined if <parameter>size</parameter> is
-      <constant>0</constant>, or if request size overflows due to size class
-      and/or alignment constraints.</para>
-    </refsect2>
   </refsect1>
   <refsect1 id="tuning">
     <title>TUNING</title>
@@ -598,8 +448,10 @@ for (i = 0; i < nbins; i++) {
     <manvolnum>2</manvolnum></citerefentry> to obtain memory, which is
     suboptimal for several reasons, including race conditions, increased
     fragmentation, and artificial limitations on maximum usable memory.  If
-    <option>--enable-dss</option> is specified during configuration, this
-    allocator uses both <citerefentry><refentrytitle>mmap</refentrytitle>
+    <citerefentry><refentrytitle>sbrk</refentrytitle>
+    <manvolnum>2</manvolnum></citerefentry> is supported by the operating
+    system, this allocator uses both
+    <citerefentry><refentrytitle>mmap</refentrytitle>
     <manvolnum>2</manvolnum></citerefentry> and
     <citerefentry><refentrytitle>sbrk</refentrytitle>
     <manvolnum>2</manvolnum></citerefentry>, in that order of preference;
@@ -634,10 +486,11 @@ for (i = 0; i < nbins; i++) {
     <para>User objects are broken into three categories according to size:
     small, large, and huge.  Small objects are smaller than one page.  Large
     objects are smaller than the chunk size.  Huge objects are a multiple of
-    the chunk size.  Small and large objects are managed by arenas; huge
-    objects are managed separately in a single data structure that is shared by
-    all threads.  Huge objects are used by applications infrequently enough
-    that this single data structure is not a scalability issue.</para>
+    the chunk size.  Small and large objects are managed entirely by arenas;
+    huge objects are additionally aggregated in a single data structure that is
+    shared by all threads.  Huge objects are typically used by applications
+    infrequently enough that this single data structure is not a scalability
+    issue.</para>
 
     <para>Each chunk that is managed by an arena tracks its contents as runs of
     contiguous pages (unused, backing a set of small objects, or backing one
@@ -775,16 +628,6 @@ for (i = 0; i < nbins; i++) {
         build configuration.</para></listitem>
       </varlistentry>
 
-      <varlistentry id="config.dss">
-        <term>
-          <mallctl>config.dss</mallctl>
-          (<type>bool</type>)
-          <literal>r-</literal>
-        </term>
-        <listitem><para><option>--enable-dss</option> was specified during
-        build configuration.</para></listitem>
-      </varlistentry>
-
       <varlistentry id="config.fill">
         <term>
           <mallctl>config.fill</mallctl>
@@ -805,16 +648,6 @@ for (i = 0; i < nbins; i++) {
         during build configuration.</para></listitem>
       </varlistentry>
 
-      <varlistentry id="config.mremap">
-        <term>
-          <mallctl>config.mremap</mallctl>
-          (<type>bool</type>)
-          <literal>r-</literal>
-        </term>
-        <listitem><para><option>--enable-mremap</option> was specified during
-        build configuration.</para></listitem>
-      </varlistentry>
-
       <varlistentry id="config.munmap">
         <term>
           <mallctl>config.munmap</mallctl>
@@ -940,10 +773,15 @@ for (i = 0; i < nbins; i++) {
         <manvolnum>2</manvolnum></citerefentry>) allocation precedence as
         related to <citerefentry><refentrytitle>mmap</refentrytitle>
         <manvolnum>2</manvolnum></citerefentry> allocation.  The following
-        settings are supported: &ldquo;disabled&rdquo;, &ldquo;primary&rdquo;,
-        and &ldquo;secondary&rdquo;.  The default is &ldquo;secondary&rdquo; if
-        <link linkend="config.dss"><mallctl>config.dss</mallctl></link> is
-        true, &ldquo;disabled&rdquo; otherwise.
+        settings are supported if
+        <citerefentry><refentrytitle>sbrk</refentrytitle>
+        <manvolnum>2</manvolnum></citerefentry> is supported by the operating
+        system: &ldquo;disabled&rdquo;, &ldquo;primary&rdquo;, and
+        &ldquo;secondary&rdquo;; otherwise only &ldquo;disabled&rdquo; is
+        supported.  The default is &ldquo;secondary&rdquo; if
+        <citerefentry><refentrytitle>sbrk</refentrytitle>
+        <manvolnum>2</manvolnum></citerefentry> is supported by the operating
+        system; &ldquo;disabled&rdquo; otherwise.
         </para></listitem>
       </varlistentry>
 
@@ -1076,9 +914,8 @@ for (i = 0; i < nbins; i++) {
         <listitem><para>Zero filling enabled/disabled.  If enabled, each byte
         of uninitialized allocated memory will be initialized to 0.  Note that
         this initialization only happens once for each byte, so
-        <function>realloc<parameter/></function>,
-        <function>rallocx<parameter/></function> and
-        <function>rallocm<parameter/></function> calls do not zero memory that
+        <function>realloc<parameter/></function> and
+        <function>rallocx<parameter/></function> calls do not zero memory that
         was previously allocated.  This is intended for debugging and will
         impact performance negatively.  This option is disabled by default.
         </para></listitem>
@@ -1097,19 +934,6 @@ for (i = 0; i < nbins; i++) {
         is disabled by default.</para></listitem>
       </varlistentry>
 
-      <varlistentry id="opt.valgrind">
-        <term>
-          <mallctl>opt.valgrind</mallctl>
-          (<type>bool</type>)
-          <literal>r-</literal>
-          [<option>--enable-valgrind</option>]
-        </term>
-        <listitem><para><ulink url="http://valgrind.org/">Valgrind</ulink>
-        support enabled/disabled.  This option is vestigal because jemalloc
-        auto-detects whether it is running inside Valgrind.  This option is
-        disabled by default, unless running inside Valgrind.</para></listitem>
-      </varlistentry>
-
       <varlistentry id="opt.xmalloc">
         <term>
           <mallctl>opt.xmalloc</mallctl>
@@ -1146,7 +970,8 @@ malloc_conf = "xmalloc:true";]]></programlisting>
         linkend="opt.lg_tcache_max"><mallctl>opt.lg_tcache_max</mallctl></link>
         option for related tuning information.  This option is enabled by
         default unless running inside <ulink
-        url="http://valgrind.org/">Valgrind</ulink>.</para></listitem>
+        url="http://valgrind.org/">Valgrind</ulink>, in which case it is
+        forcefully disabled.</para></listitem>
       </varlistentry>
 
       <varlistentry id="opt.lg_tcache_max">
@@ -1421,7 +1246,7 @@ malloc_conf = "xmalloc:true";]]></programlisting>
       <varlistentry id="arena.i.purge">
         <term>
           <mallctl>arena.&lt;i&gt;.purge</mallctl>
-          (<type>unsigned</type>)
+          (<type>void</type>)
           <literal>--</literal>
         </term>
         <listitem><para>Purge unused dirty pages for arena &lt;i&gt;, or for
@@ -1439,14 +1264,77 @@ malloc_conf = "xmalloc:true";]]></programlisting>
         <listitem><para>Set the precedence of dss allocation as related to mmap
         allocation for arena &lt;i&gt;, or for all arenas if &lt;i&gt; equals
         <link
-        linkend="arenas.narenas"><mallctl>arenas.narenas</mallctl></link>.  Note
-        that even during huge allocation this setting is read from the arena
-        that would be chosen for small or large allocation so that applications
-        can depend on consistent dss versus mmap allocation regardless of
-        allocation size.  See <link
-        linkend="opt.dss"><mallctl>opt.dss</mallctl></link> for supported
-        settings.
-        </para></listitem>
+        linkend="arenas.narenas"><mallctl>arenas.narenas</mallctl></link>.  See
+        <link linkend="opt.dss"><mallctl>opt.dss</mallctl></link> for supported
+        settings.</para></listitem>
+      </varlistentry>
+
+      <varlistentry id="arena.i.chunk.alloc">
+        <term>
+          <mallctl>arena.&lt;i&gt;.chunk.alloc</mallctl>
+          (<type>chunk_alloc_t *</type>)
+          <literal>rw</literal>
+        </term>
+        <listitem><para>Get or set the chunk allocation function for arena
+        &lt;i&gt;.  If setting, the chunk deallocation function should
+        also be set via <link linkend="arena.i.chunk.dalloc">
+        <mallctl>arena.&lt;i&gt;.chunk.dalloc</mallctl></link> to a companion
+        function that knows how to deallocate the chunks.
+        <funcprototype>
+          <funcdef>typedef void *<function>(chunk_alloc_t)</function></funcdef>
+          <paramdef>size_t <parameter>size</parameter></paramdef>
+          <paramdef>size_t <parameter>alignment</parameter></paramdef>
+          <paramdef>bool *<parameter>zero</parameter></paramdef>
+          <paramdef>unsigned <parameter>arena_ind</parameter></paramdef>
+        </funcprototype>
+        A chunk allocation function conforms to the <type>chunk_alloc_t</type>
+        type and upon success returns a pointer to <parameter>size</parameter>
+        bytes of memory on behalf of arena <parameter>arena_ind</parameter> such
+        that the chunk's base address is a multiple of
+        <parameter>alignment</parameter>, as well as setting
+        <parameter>*zero</parameter> to indicate whether the chunk is zeroed.
+        Upon error the function returns <constant>NULL</constant> and leaves
+        <parameter>*zero</parameter> unmodified.  The
+        <parameter>size</parameter> parameter is always a multiple of the chunk
+        size.  The <parameter>alignment</parameter> parameter is always a power
+        of two at least as large as the chunk size.  Zeroing is mandatory if
+        <parameter>*zero</parameter> is true upon function
+        entry.</para>
+
+        <para>Note that replacing the default chunk allocation function makes
+        the arena's <link
+        linkend="arena.i.dss"><mallctl>arena.&lt;i&gt;.dss</mallctl></link>
+        setting irrelevant.</para></listitem>
+      </varlistentry>
+
+      <varlistentry id="arena.i.chunk.dalloc">
+        <term>
+          <mallctl>arena.&lt;i&gt;.chunk.dalloc</mallctl>
+          (<type>chunk_dalloc_t *</type>)
+          <literal>rw</literal>
+        </term>
+        <listitem><para>Get or set the chunk deallocation function for arena
+        &lt;i&gt;.  If setting, the chunk deallocation function must
+        be capable of deallocating all extant chunks associated with arena
+        &lt;i&gt;, usually by passing unknown chunks to the deallocation
+        function that was replaced.  In practice, it is feasible to control
+        allocation for arenas created via <link
+        linkend="arenas.extend"><mallctl>arenas.extend</mallctl></link> such
+        that all chunks originate from an application-supplied chunk allocator
+        (by setting custom chunk allocation/deallocation functions just after
+        arena creation), but the automatically created arenas may have already
+        created chunks prior to the application having an opportunity to take
+        over chunk allocation.
+        <funcprototype>
+          <funcdef>typedef void <function>(chunk_dalloc_t)</function></funcdef>
+          <paramdef>void *<parameter>chunk</parameter></paramdef>
+          <paramdef>size_t <parameter>size</parameter></paramdef>
+          <paramdef>unsigned <parameter>arena_ind</parameter></paramdef>
+        </funcprototype>
+        A chunk deallocation function conforms to the
+        <type>chunk_dalloc_t</type> type and deallocates a
+        <parameter>chunk</parameter> of given <parameter>size</parameter> on
+        behalf of arena <parameter>arena_ind</parameter>.</para></listitem>
       </varlistentry>
 
       <varlistentry id="arenas.narenas">
@@ -1564,16 +1452,6 @@ malloc_conf = "xmalloc:true";]]></programlisting>
         class.</para></listitem>
       </varlistentry>
 
-      <varlistentry id="arenas.purge">
-        <term>
-          <mallctl>arenas.purge</mallctl>
-          (<type>unsigned</type>)
-          <literal>-w</literal>
-        </term>
-        <listitem><para>Purge unused dirty pages for the specified arena, or
-        for all arenas if none is specified.</para></listitem>
-      </varlistentry>
-
       <varlistentry id="arenas.extend">
         <term>
           <mallctl>arenas.extend</mallctl>
@@ -1721,39 +1599,6 @@ malloc_conf = "xmalloc:true";]]></programlisting>
         </para></listitem>
       </varlistentry>
 
-      <varlistentry id="stats.huge.allocated">
-        <term>
-          <mallctl>stats.huge.allocated</mallctl>
-          (<type>size_t</type>)
-          <literal>r-</literal>
-          [<option>--enable-stats</option>]
-        </term>
-        <listitem><para>Number of bytes currently allocated by huge objects.
-        </para></listitem>
-      </varlistentry>
-
-      <varlistentry id="stats.huge.nmalloc">
-        <term>
-          <mallctl>stats.huge.nmalloc</mallctl>
-          (<type>uint64_t</type>)
-          <literal>r-</literal>
-          [<option>--enable-stats</option>]
-        </term>
-        <listitem><para>Cumulative number of huge allocation requests.
-        </para></listitem>
-      </varlistentry>
-
-      <varlistentry id="stats.huge.ndalloc">
-        <term>
-          <mallctl>stats.huge.ndalloc</mallctl>
-          (<type>uint64_t</type>)
-          <literal>r-</literal>
-          [<option>--enable-stats</option>]
-        </term>
-        <listitem><para>Cumulative number of huge deallocation requests.
-        </para></listitem>
-      </varlistentry>
-
       <varlistentry id="stats.arenas.i.dss">
         <term>
           <mallctl>stats.arenas.&lt;i&gt;.dss</mallctl>
@@ -1930,6 +1775,50 @@ malloc_conf = "xmalloc:true";]]></programlisting>
         </para></listitem>
       </varlistentry>
 
+      <varlistentry id="stats.arenas.i.huge.allocated">
+        <term>
+          <mallctl>stats.arenas.&lt;i&gt;.huge.allocated</mallctl>
+          (<type>size_t</type>)
+          <literal>r-</literal>
+          [<option>--enable-stats</option>]
+        </term>
+        <listitem><para>Number of bytes currently allocated by huge objects.
+        </para></listitem>
+      </varlistentry>
+
+      <varlistentry id="stats.arenas.i.huge.nmalloc">
+        <term>
+          <mallctl>stats.arenas.&lt;i&gt;.huge.nmalloc</mallctl>
+          (<type>uint64_t</type>)
+          <literal>r-</literal>
+          [<option>--enable-stats</option>]
+        </term>
+        <listitem><para>Cumulative number of huge allocation requests served
+        directly by the arena.</para></listitem>
+      </varlistentry>
+
+      <varlistentry id="stats.arenas.i.huge.ndalloc">
+        <term>
+          <mallctl>stats.arenas.&lt;i&gt;.huge.ndalloc</mallctl>
+          (<type>uint64_t</type>)
+          <literal>r-</literal>
+          [<option>--enable-stats</option>]
+        </term>
+        <listitem><para>Cumulative number of huge deallocation requests served
+        directly by the arena.</para></listitem>
+      </varlistentry>
+
+      <varlistentry id="stats.arenas.i.huge.nrequests">
+        <term>
+          <mallctl>stats.arenas.&lt;i&gt;.huge.nrequests</mallctl>
+          (<type>uint64_t</type>)
+          <literal>r-</literal>
+          [<option>--enable-stats</option>]
+        </term>
+        <listitem><para>Cumulative number of huge allocation requests.
+        </para></listitem>
+      </varlistentry>
+
       <varlistentry id="stats.arenas.i.bins.j.allocated">
         <term>
           <mallctl>stats.arenas.&lt;i&gt;.bins.&lt;j&gt;.allocated</mallctl>
@@ -2253,42 +2142,6 @@ malloc_conf = "xmalloc:true";]]></programlisting>
       returns the usable size of the allocation pointed to by
       <parameter>ptr</parameter>.  </para>
     </refsect2>
-    <refsect2>
-      <title>Experimental API</title>
-      <para>The <function>allocm<parameter/></function>,
-      <function>rallocm<parameter/></function>,
-      <function>sallocm<parameter/></function>,
-      <function>dallocm<parameter/></function>, and
-      <function>nallocm<parameter/></function> functions return
-      <constant>ALLOCM_SUCCESS</constant> on success; otherwise they return an
-      error value.  The <function>allocm<parameter/></function>,
-      <function>rallocm<parameter/></function>, and
-      <function>nallocm<parameter/></function> functions will fail if:
-        <variablelist>
-          <varlistentry>
-            <term><errorname>ALLOCM_ERR_OOM</errorname></term>
-
-            <listitem><para>Out of memory.  Insufficient contiguous memory was
-            available to service the allocation request.  The
-            <function>allocm<parameter/></function> function additionally sets
-            <parameter>*ptr</parameter> to <constant>NULL</constant>, whereas
-            the <function>rallocm<parameter/></function> function leaves
-            <constant>*ptr</constant> unmodified.</para></listitem>
-          </varlistentry>
-        </variablelist>
-      The <function>rallocm<parameter/></function> function will also
-      fail if:
-        <variablelist>
-          <varlistentry>
-            <term><errorname>ALLOCM_ERR_NOT_MOVED</errorname></term>
-
-            <listitem><para><constant>ALLOCM_NO_MOVE</constant> was specified,
-            but the reallocation request could not be serviced without moving
-            the object.</para></listitem>
-          </varlistentry>
-        </variablelist>
-      </para>
-    </refsect2>
   </refsect1>
   <refsect1 id="environment">
     <title>ENVIRONMENT</title>
diff --git a/src/jemalloc/include/jemalloc/internal/arena.h b/src/jemalloc/include/jemalloc/internal/arena.h
index 9d000c03decbde17338f9c205f21b370854d7f7f..2a2145293cf5428a0b50435abe35b63f7dce83d6 100644
--- a/src/jemalloc/include/jemalloc/internal/arena.h
+++ b/src/jemalloc/include/jemalloc/internal/arena.h
@@ -110,7 +110,6 @@ struct arena_chunk_map_s {
 	 * p : run page offset
 	 * s : run size
 	 * n : binind for size class; large objects set these to BININD_INVALID
-	 *     except for promoted allocations (see prof_promote)
 	 * x : don't care
 	 * - : 0
 	 * + : 1
@@ -216,8 +215,6 @@ struct arena_run_s {
  *               | ...                |
  * bitmap_offset | bitmap             |
  *               | ...                |
- *   ctx0_offset | ctx map            |
- *               | ...                |
  *               |--------------------|
  *               | redzone            |
  *   reg0_offset | region 0           |
@@ -270,12 +267,6 @@ struct arena_bin_info_s {
 	 */
 	bitmap_info_t	bitmap_info;
 
-	/*
-	 * Offset of first (prof_ctx_t *) in a run header for this bin's size
-	 * class, or 0 if (config_prof == false || opt_prof == false).
-	 */
-	uint32_t	ctx0_offset;
-
 	/* Offset of first region in a run for this bin's size class. */
 	uint32_t	reg0_offset;
 };
@@ -312,6 +303,9 @@ struct arena_s {
 	/* This arena's index within the arenas array. */
 	unsigned		ind;
 
+	/* This arena's pool. */
+	pool_t			*pool;
+
 	/*
 	 * Number of threads currently assigned to this arena.  This field is
 	 * protected by arenas_lock.
@@ -354,7 +348,7 @@ struct arena_s {
 	 */
 	arena_chunk_t		*spare;
 
-	/* Number of pages in active runs. */
+	/* Number of pages in active runs and huge regions. */
 	size_t			nactive;
 
 	/*
@@ -379,6 +373,12 @@ struct arena_s {
 	 */
 	arena_avail_tree_t	runs_avail;
 
+	/*
+	 * user-configureable chunk allocation and deallocation functions.
+	 */
+	chunk_alloc_t		*chunk_alloc;
+	chunk_dalloc_t		*chunk_dalloc;
+
 	/* bins is used to store trees of free regions. */
 	arena_bin_t		bins[NBINS];
 };
@@ -389,18 +389,26 @@ struct arena_s {
 
 extern ssize_t	opt_lg_dirty_mult;
 /*
- * small_size2bin is a compact lookup table that rounds request sizes up to
+ * small_size2bin_tab is a compact lookup table that rounds request sizes up to
  * size classes.  In order to reduce cache footprint, the table is compressed,
- * and all accesses are via the SMALL_SIZE2BIN macro.
+ * and all accesses are via small_size2bin().
+ */
+extern uint8_t const	small_size2bin_tab[];
+/*
+ * small_bin2size_tab duplicates information in arena_bin_info, but in a const
+ * array, for which it is easier for the compiler to optimize repeated
+ * dereferences.
  */
-extern uint8_t const	small_size2bin[];
-#define	SMALL_SIZE2BIN(s)	(small_size2bin[(s-1) >> LG_TINY_MIN])
+extern uint32_t const	small_bin2size_tab[NBINS];
 
 extern arena_bin_info_t	arena_bin_info[NBINS];
 
 /* Number of large size classes. */
 #define			nlclasses (chunk_npages - map_bias)
 
+void	*arena_chunk_alloc_huge(arena_t *arena, size_t size, size_t alignment,
+    bool *zero);
+void	arena_chunk_dalloc_huge(arena_t *arena, void *chunk, size_t size);
 void	arena_purge_all(arena_t *arena);
 void	arena_tcache_fill_small(arena_t *arena, tcache_bin_t *tbin,
     size_t binind, uint64_t prof_accumbytes);
@@ -443,11 +451,11 @@ void	*arena_ralloc(arena_t *arena, void *ptr, size_t oldsize, size_t size,
     size_t extra, size_t alignment, bool zero, bool try_tcache_alloc,
     bool try_tcache_dalloc);
 dss_prec_t	arena_dss_prec_get(arena_t *arena);
-void	arena_dss_prec_set(arena_t *arena, dss_prec_t dss_prec);
+bool	arena_dss_prec_set(arena_t *arena, dss_prec_t dss_prec);
 void	arena_stats_merge(arena_t *arena, const char **dss, size_t *nactive,
     size_t *ndirty, arena_stats_t *astats, malloc_bin_stats_t *bstats,
     malloc_large_stats_t *lstats);
-bool	arena_new(arena_t *arena, unsigned ind);
+bool	arena_new(pool_t *pool, arena_t *arena, unsigned ind);
 void	arena_boot(void);
 void	arena_prefork(arena_t *arena);
 void	arena_postfork_parent(arena_t *arena);
@@ -458,6 +466,15 @@ void	arena_postfork_child(arena_t *arena);
 #ifdef JEMALLOC_H_INLINES
 
 #ifndef JEMALLOC_ENABLE_INLINE
+size_t	small_size2bin_compute(size_t size);
+size_t	small_size2bin_lookup(size_t size);
+size_t	small_size2bin(size_t size);
+size_t	small_bin2size_compute(size_t binind);
+size_t	small_bin2size_lookup(size_t binind);
+size_t	small_bin2size(size_t binind);
+size_t	small_s2u_compute(size_t size);
+size_t	small_s2u_lookup(size_t size);
+size_t	small_s2u(size_t size);
 arena_chunk_map_t	*arena_mapp_get(arena_chunk_t *chunk, size_t pageind);
 size_t	*arena_mapbitsp_get(arena_chunk_t *chunk, size_t pageind);
 size_t	arena_mapbitsp_read(size_t *mapbitsp);
@@ -492,15 +509,156 @@ size_t	arena_bin_index(arena_t *arena, arena_bin_t *bin);
 unsigned	arena_run_regind(arena_run_t *run, arena_bin_info_t *bin_info,
     const void *ptr);
 prof_ctx_t	*arena_prof_ctx_get(const void *ptr);
-void	arena_prof_ctx_set(const void *ptr, size_t usize, prof_ctx_t *ctx);
+void	arena_prof_ctx_set(const void *ptr, prof_ctx_t *ctx);
 void	*arena_malloc(arena_t *arena, size_t size, bool zero, bool try_tcache);
 size_t	arena_salloc(const void *ptr, bool demote);
-void	arena_dalloc(arena_t *arena, arena_chunk_t *chunk, void *ptr,
-    bool try_tcache);
+void	arena_dalloc(arena_chunk_t *chunk, void *ptr, bool try_tcache);
 #endif
 
 #if (defined(JEMALLOC_ENABLE_INLINE) || defined(JEMALLOC_ARENA_C_))
 #  ifdef JEMALLOC_ARENA_INLINE_A
+JEMALLOC_INLINE size_t
+small_size2bin_compute(size_t size)
+{
+#if (NTBINS != 0)
+	if (size <= (ZU(1) << LG_TINY_MAXCLASS)) {
+		size_t lg_tmin = LG_TINY_MAXCLASS - NTBINS + 1;
+		size_t lg_ceil = lg_floor(pow2_ceil(size));
+		return (lg_ceil < lg_tmin ? 0 : lg_ceil - lg_tmin);
+	} else
+#endif
+	{
+		size_t x = lg_floor((size<<1)-1);
+		size_t shift = (x < LG_SIZE_CLASS_GROUP + LG_QUANTUM) ? 0 :
+		    x - (LG_SIZE_CLASS_GROUP + LG_QUANTUM);
+		size_t grp = shift << LG_SIZE_CLASS_GROUP;
+
+		size_t lg_delta = (x < LG_SIZE_CLASS_GROUP + LG_QUANTUM + 1)
+		    ? LG_QUANTUM : x - LG_SIZE_CLASS_GROUP - 1;
+
+		size_t delta_inverse_mask = ZI(-1) << lg_delta;
+		size_t mod = ((((size-1) & delta_inverse_mask) >> lg_delta)) &
+		    ((ZU(1) << LG_SIZE_CLASS_GROUP) - 1);
+
+		size_t bin = NTBINS + grp + mod;
+		return (bin);
+	}
+}
+
+JEMALLOC_ALWAYS_INLINE size_t
+small_size2bin_lookup(size_t size)
+{
+
+	assert(size <= LOOKUP_MAXCLASS);
+	{
+		size_t ret = ((size_t)(small_size2bin_tab[(size-1) >>
+		    LG_TINY_MIN]));
+		assert(ret == small_size2bin_compute(size));
+		return (ret);
+	}
+}
+
+JEMALLOC_ALWAYS_INLINE size_t
+small_size2bin(size_t size)
+{
+
+	assert(size > 0);
+	if (size <= LOOKUP_MAXCLASS)
+		return (small_size2bin_lookup(size));
+	else
+		return (small_size2bin_compute(size));
+}
+
+JEMALLOC_INLINE size_t
+small_bin2size_compute(size_t binind)
+{
+#if (NTBINS > 0)
+	if (binind < NTBINS)
+		return (ZU(1) << (LG_TINY_MAXCLASS - NTBINS + 1 + binind));
+	else
+#endif
+	{
+		size_t reduced_binind = binind - NTBINS;
+		size_t grp = reduced_binind >> LG_SIZE_CLASS_GROUP;
+		size_t mod = reduced_binind & ((ZU(1) << LG_SIZE_CLASS_GROUP) -
+		    1);
+
+		size_t grp_size_mask = ~((!!grp)-1);
+		size_t grp_size = ((ZU(1) << (LG_QUANTUM +
+		    (LG_SIZE_CLASS_GROUP-1))) << grp) & grp_size_mask;
+
+		size_t shift = (grp == 0) ? 1 : grp;
+		size_t lg_delta = shift + (LG_QUANTUM-1);
+		size_t mod_size = (mod+1) << lg_delta;
+
+		size_t usize = grp_size + mod_size;
+		return (usize);
+	}
+}
+
+JEMALLOC_ALWAYS_INLINE size_t
+small_bin2size_lookup(size_t binind)
+{
+
+	assert(binind < NBINS);
+	{
+		size_t ret = ((size_t)(small_bin2size_tab[binind]));
+		assert(ret == small_bin2size_compute(binind));
+		return (ret);
+	}
+}
+
+JEMALLOC_ALWAYS_INLINE size_t
+small_bin2size(size_t binind)
+{
+
+	return (small_bin2size_lookup(binind));
+}
+
+JEMALLOC_ALWAYS_INLINE size_t
+small_s2u_compute(size_t size)
+{
+#if (NTBINS > 0)
+	if (size <= (ZU(1) << LG_TINY_MAXCLASS)) {
+		size_t lg_tmin = LG_TINY_MAXCLASS - NTBINS + 1;
+		size_t lg_ceil = lg_floor(pow2_ceil(size));
+		return (lg_ceil < lg_tmin ? (ZU(1) << lg_tmin) :
+		    (ZU(1) << lg_ceil));
+	} else
+#endif
+	{
+		size_t x = lg_floor((size<<1)-1);
+		size_t lg_delta = (x < LG_SIZE_CLASS_GROUP + LG_QUANTUM + 1)
+		    ?  LG_QUANTUM : x - LG_SIZE_CLASS_GROUP - 1;
+		size_t delta = ZU(1) << lg_delta;
+		size_t delta_mask = delta - 1;
+		size_t usize = (size + delta_mask) & ~delta_mask;
+		return (usize);
+	}
+}
+
+JEMALLOC_ALWAYS_INLINE size_t
+small_s2u_lookup(size_t size)
+{
+	size_t ret = (small_bin2size(small_size2bin(size)));
+
+	assert(ret == small_s2u_compute(size));
+	return (ret);
+}
+
+JEMALLOC_ALWAYS_INLINE size_t
+small_s2u(size_t size)
+{
+
+	assert(size > 0);
+	if (size <= LOOKUP_MAXCLASS)
+		return (small_s2u_lookup(size));
+	else
+		return (small_s2u_compute(size));
+}
+#  endif /* JEMALLOC_ARENA_INLINE_A */
+
+#  ifdef JEMALLOC_ARENA_INLINE_B
 JEMALLOC_ALWAYS_INLINE arena_chunk_map_t *
 arena_mapp_get(arena_chunk_t *chunk, size_t pageind)
 {
@@ -782,9 +940,9 @@ arena_ptr_small_binind_get(const void *ptr, size_t mapbits)
 
 	return (binind);
 }
-#  endif /* JEMALLOC_ARENA_INLINE_A */
+#  endif /* JEMALLOC_ARENA_INLINE_B */
 
-#  ifdef JEMALLOC_ARENA_INLINE_B
+#  ifdef JEMALLOC_ARENA_INLINE_C
 JEMALLOC_INLINE size_t
 arena_bin_index(arena_t *arena, arena_bin_t *bin)
 {
@@ -815,7 +973,7 @@ arena_run_regind(arena_run_t *run, arena_bin_info_t *bin_info, const void *ptr)
 
 	/* Rescale (factor powers of 2 out of the numerator and denominator). */
 	interval = bin_info->reg_interval;
-	shift = ffs(interval) - 1;
+	shift = jemalloc_ffs(interval) - 1;
 	diff >>= shift;
 	interval >>= shift;
 
@@ -880,31 +1038,16 @@ arena_prof_ctx_get(const void *ptr)
 	pageind = ((uintptr_t)ptr - (uintptr_t)chunk) >> LG_PAGE;
 	mapbits = arena_mapbits_get(chunk, pageind);
 	assert((mapbits & CHUNK_MAP_ALLOCATED) != 0);
-	if ((mapbits & CHUNK_MAP_LARGE) == 0) {
-		if (prof_promote)
-			ret = (prof_ctx_t *)(uintptr_t)1U;
-		else {
-			arena_run_t *run = (arena_run_t *)((uintptr_t)chunk +
-			    (uintptr_t)((pageind - (mapbits >> LG_PAGE)) <<
-			    LG_PAGE));
-			size_t binind = arena_ptr_small_binind_get(ptr,
-			    mapbits);
-			arena_bin_info_t *bin_info = &arena_bin_info[binind];
-			unsigned regind;
-
-			regind = arena_run_regind(run, bin_info, ptr);
-			ret = *(prof_ctx_t **)((uintptr_t)run +
-			    bin_info->ctx0_offset + (regind *
-			    sizeof(prof_ctx_t *)));
-		}
-	} else
+	if ((mapbits & CHUNK_MAP_LARGE) == 0)
+		ret = (prof_ctx_t *)(uintptr_t)1U;
+	else
 		ret = arena_mapp_get(chunk, pageind)->prof_ctx;
 
 	return (ret);
 }
 
 JEMALLOC_INLINE void
-arena_prof_ctx_set(const void *ptr, size_t usize, prof_ctx_t *ctx)
+arena_prof_ctx_set(const void *ptr, prof_ctx_t *ctx)
 {
 	arena_chunk_t *chunk;
 	size_t pageind;
@@ -917,43 +1060,21 @@ arena_prof_ctx_set(const void *ptr, size_t usize, prof_ctx_t *ctx)
 	pageind = ((uintptr_t)ptr - (uintptr_t)chunk) >> LG_PAGE;
 	assert(arena_mapbits_allocated_get(chunk, pageind) != 0);
 
-	if (usize > SMALL_MAXCLASS || (prof_promote &&
-	    ((uintptr_t)ctx != (uintptr_t)1U || arena_mapbits_large_get(chunk,
-	    pageind) != 0))) {
-		assert(arena_mapbits_large_get(chunk, pageind) != 0);
+	if (arena_mapbits_large_get(chunk, pageind) != 0)
 		arena_mapp_get(chunk, pageind)->prof_ctx = ctx;
-	} else {
-		assert(arena_mapbits_large_get(chunk, pageind) == 0);
-		if (prof_promote == false) {
-			size_t mapbits = arena_mapbits_get(chunk, pageind);
-			arena_run_t *run = (arena_run_t *)((uintptr_t)chunk +
-			    (uintptr_t)((pageind - (mapbits >> LG_PAGE)) <<
-			    LG_PAGE));
-			size_t binind;
-			arena_bin_info_t *bin_info;
-			unsigned regind;
-
-			binind = arena_ptr_small_binind_get(ptr, mapbits);
-			bin_info = &arena_bin_info[binind];
-			regind = arena_run_regind(run, bin_info, ptr);
-
-			*((prof_ctx_t **)((uintptr_t)run +
-			    bin_info->ctx0_offset + (regind * sizeof(prof_ctx_t
-			    *)))) = ctx;
-		}
-	}
 }
 
 JEMALLOC_ALWAYS_INLINE void *
 arena_malloc(arena_t *arena, size_t size, bool zero, bool try_tcache)
 {
 	tcache_t *tcache;
+	pool_t *pool = arena->pool;
 
 	assert(size != 0);
 	assert(size <= arena_maxclass);
 
 	if (size <= SMALL_MAXCLASS) {
-		if (try_tcache && (tcache = tcache_get(true)) != NULL)
+		if (try_tcache && (tcache = tcache_get(pool, true)) != NULL)
 			return (tcache_alloc_small(tcache, size, zero));
 		else {
 			return (arena_malloc_small(choose_arena(arena), size,
@@ -965,7 +1086,7 @@ arena_malloc(arena_t *arena, size_t size, bool zero, bool try_tcache)
 		 * infinite recursion during tcache initialization.
 		 */
 		if (try_tcache && size <= tcache_maxclass && (tcache =
-		    tcache_get(true)) != NULL)
+		    tcache_get(pool, true)) != NULL)
 			return (tcache_alloc_large(tcache, size, zero));
 		else {
 			return (arena_malloc_large(choose_arena(arena), size,
@@ -984,13 +1105,12 @@ arena_salloc(const void *ptr, bool demote)
 
 	assert(ptr != NULL);
 	assert(CHUNK_ADDR2BASE(ptr) != ptr);
-
 	chunk = (arena_chunk_t *)CHUNK_ADDR2BASE(ptr);
 	pageind = ((uintptr_t)ptr - (uintptr_t)chunk) >> LG_PAGE;
 	assert(arena_mapbits_allocated_get(chunk, pageind) != 0);
 	binind = arena_mapbits_binind_get(chunk, pageind);
 	if (binind == BININD_INVALID || (config_prof && demote == false &&
-	    prof_promote && arena_mapbits_large_get(chunk, pageind) != 0)) {
+	    arena_mapbits_large_get(chunk, pageind) != 0)) {
 		/*
 		 * Large allocation.  In the common case (demote == true), and
 		 * as this is an inline function, most callers will only end up
@@ -1008,27 +1128,22 @@ arena_salloc(const void *ptr, bool demote)
 		assert(arena_mapbits_dirty_get(chunk, pageind) ==
 		    arena_mapbits_dirty_get(chunk, pageind+(ret>>LG_PAGE)-1));
 	} else {
-		/*
-		 * Small allocation (possibly promoted to a large object due to
-		 * prof_promote).
-		 */
+		/* Small allocation (possibly promoted to a large object). */
 		assert(arena_mapbits_large_get(chunk, pageind) != 0 ||
 		    arena_ptr_small_binind_get(ptr, arena_mapbits_get(chunk,
 		    pageind)) == binind);
-		ret = arena_bin_info[binind].reg_size;
+		ret = small_bin2size(binind);
 	}
 
 	return (ret);
 }
 
 JEMALLOC_ALWAYS_INLINE void
-arena_dalloc(arena_t *arena, arena_chunk_t *chunk, void *ptr, bool try_tcache)
+arena_dalloc(arena_chunk_t *chunk, void *ptr, bool try_tcache)
 {
 	size_t pageind, mapbits;
 	tcache_t *tcache;
 
-	assert(arena != NULL);
-	assert(chunk->arena == arena);
 	assert(ptr != NULL);
 	assert(CHUNK_ADDR2BASE(ptr) != ptr);
 
@@ -1037,26 +1152,26 @@ arena_dalloc(arena_t *arena, arena_chunk_t *chunk, void *ptr, bool try_tcache)
 	assert(arena_mapbits_allocated_get(chunk, pageind) != 0);
 	if ((mapbits & CHUNK_MAP_LARGE) == 0) {
 		/* Small allocation. */
-		if (try_tcache && (tcache = tcache_get(false)) != NULL) {
+		if (try_tcache && (tcache = tcache_get(chunk->arena->pool, false)) != NULL) {
 			size_t binind;
 
 			binind = arena_ptr_small_binind_get(ptr, mapbits);
 			tcache_dalloc_small(tcache, ptr, binind);
 		} else
-			arena_dalloc_small(arena, chunk, ptr, pageind);
+			arena_dalloc_small(chunk->arena, chunk, ptr, pageind);
 	} else {
 		size_t size = arena_mapbits_large_size_get(chunk, pageind);
 
 		assert(((uintptr_t)ptr & PAGE_MASK) == 0);
 
 		if (try_tcache && size <= tcache_maxclass && (tcache =
-		    tcache_get(false)) != NULL) {
+		    tcache_get(chunk->arena->pool, false)) != NULL) {
 			tcache_dalloc_large(tcache, ptr, size);
 		} else
-			arena_dalloc_large(arena, chunk, ptr);
+			arena_dalloc_large(chunk->arena, chunk, ptr);
 	}
 }
-#  endif /* JEMALLOC_ARENA_INLINE_B */
+#  endif /* JEMALLOC_ARENA_INLINE_C */
 #endif
 
 #endif /* JEMALLOC_H_INLINES */
diff --git a/src/jemalloc/include/jemalloc/internal/base.h b/src/jemalloc/include/jemalloc/internal/base.h
index 9cf75ffb0b3c1d4e9ee5b5c855127f4112538872..d29115501562fdb36817f774362ac5ba1571a146 100644
--- a/src/jemalloc/include/jemalloc/internal/base.h
+++ b/src/jemalloc/include/jemalloc/internal/base.h
@@ -9,14 +9,15 @@
 /******************************************************************************/
 #ifdef JEMALLOC_H_EXTERNS
 
-void	*base_alloc(size_t size);
-void	*base_calloc(size_t number, size_t size);
-extent_node_t *base_node_alloc(void);
-void	base_node_dealloc(extent_node_t *node);
-bool	base_boot(void);
-void	base_prefork(void);
-void	base_postfork_parent(void);
-void	base_postfork_child(void);
+void	*base_alloc(pool_t *pool, size_t size);
+void	*base_calloc(pool_t *pool, size_t number, size_t size);
+extent_node_t *base_node_alloc(pool_t *pool);
+void	base_node_dalloc(pool_t *pool, extent_node_t *node);
+size_t	base_node_prealloc(pool_t *pool, size_t number);
+bool	base_boot(pool_t *pool);
+void	base_prefork(pool_t *pool);
+void	base_postfork_parent(pool_t *pool);
+void	base_postfork_child(pool_t *pool);
 
 #endif /* JEMALLOC_H_EXTERNS */
 /******************************************************************************/
diff --git a/src/jemalloc/include/jemalloc/internal/bitmap.h b/src/jemalloc/include/jemalloc/internal/bitmap.h
index 605ebac58c17a2650cd7cbe65a9b0ae795dee7f6..6db4ab703d7ecfebf4b06e5681750a38d7df0862 100644
--- a/src/jemalloc/include/jemalloc/internal/bitmap.h
+++ b/src/jemalloc/include/jemalloc/internal/bitmap.h
@@ -130,11 +130,11 @@ bitmap_sfu(bitmap_t *bitmap, const bitmap_info_t *binfo)
 
 	i = binfo->nlevels - 1;
 	g = bitmap[binfo->levels[i].group_offset];
-	bit = ffsl(g) - 1;
+	bit = jemalloc_ffsl(g) - 1;
 	while (i > 0) {
 		i--;
 		g = bitmap[binfo->levels[i].group_offset + bit];
-		bit = (bit << LG_BITMAP_GROUP_NBITS) + (ffsl(g) - 1);
+		bit = (bit << LG_BITMAP_GROUP_NBITS) + (jemalloc_ffsl(g) - 1);
 	}
 
 	bitmap_set(bitmap, binfo, bit);
diff --git a/src/jemalloc/include/jemalloc/internal/chunk.h b/src/jemalloc/include/jemalloc/internal/chunk.h
index 87d8700dac8adad1510d3b4a1cd978d7fe6b05e4..16a6aa619891013f54d36e186e828468489aebf4 100644
--- a/src/jemalloc/include/jemalloc/internal/chunk.h
+++ b/src/jemalloc/include/jemalloc/internal/chunk.h
@@ -30,27 +30,27 @@
 extern size_t		opt_lg_chunk;
 extern const char	*opt_dss;
 
-/* Protects stats_chunks; currently not used for any other purpose. */
-extern malloc_mutex_t	chunks_mtx;
-/* Chunk statistics. */
-extern chunk_stats_t	stats_chunks;
-
-extern rtree_t		*chunks_rtree;
-
 extern size_t		chunksize;
 extern size_t		chunksize_mask; /* (chunksize - 1). */
 extern size_t		chunk_npages;
 extern size_t		map_bias; /* Number of arena chunk header pages. */
 extern size_t		arena_maxclass; /* Max size class for arenas. */
 
-void	*chunk_alloc(size_t size, size_t alignment, bool base, bool *zero,
-    dss_prec_t dss_prec);
-void	chunk_unmap(void *chunk, size_t size);
-void	chunk_dealloc(void *chunk, size_t size, bool unmap);
-bool	chunk_boot(void);
-void	chunk_prefork(void);
-void	chunk_postfork_parent(void);
-void	chunk_postfork_child(void);
+void	*chunk_alloc_base(pool_t *pool, size_t size);
+void	*chunk_alloc_arena(chunk_alloc_t *chunk_alloc,
+    chunk_dalloc_t *chunk_dalloc, arena_t *arena, size_t size,
+    size_t alignment, bool *zero);
+void	*chunk_alloc_default(size_t size, size_t alignment, bool *zero,
+    unsigned arena_ind, pool_t *pool);
+void	chunk_unmap(pool_t *pool, void *chunk, size_t size);
+bool	chunk_dalloc_default(void *chunk, size_t size, unsigned arena_ind, pool_t *pool);
+void	chunk_record(pool_t *pool, extent_tree_t *chunks_szad,
+	extent_tree_t *chunks_ad, void *chunk, size_t size, bool zeroed);
+void	chunk_global_boot();
+bool	chunk_boot(pool_t *pool);
+void	chunk_prefork(pool_t *pool);
+void	chunk_postfork_parent(pool_t *pool);
+void	chunk_postfork_child(pool_t *pool);
 
 #endif /* JEMALLOC_H_EXTERNS */
 /******************************************************************************/
diff --git a/src/jemalloc/include/jemalloc/internal/chunk_mmap.h b/src/jemalloc/include/jemalloc/internal/chunk_mmap.h
index f24abac753823d1e06e1cc6e5663676c7442927f..c5d5c6c0c7ac41fa42bb1766a21e959a3d1db84f 100644
--- a/src/jemalloc/include/jemalloc/internal/chunk_mmap.h
+++ b/src/jemalloc/include/jemalloc/internal/chunk_mmap.h
@@ -12,7 +12,7 @@
 bool	pages_purge(void *addr, size_t length);
 
 void	*chunk_alloc_mmap(size_t size, size_t alignment, bool *zero);
-bool	chunk_dealloc_mmap(void *chunk, size_t size);
+bool	chunk_dalloc_mmap(void *chunk, size_t size);
 
 #endif /* JEMALLOC_H_EXTERNS */
 /******************************************************************************/
diff --git a/src/jemalloc/include/jemalloc/internal/ctl.h b/src/jemalloc/include/jemalloc/internal/ctl.h
index 0ffecc5f2a23feeba1f5dba9547eee8e63ae0a4e..fe0070c1b61249c4f0b7dccf4ce346e512a538d1 100644
--- a/src/jemalloc/include/jemalloc/internal/ctl.h
+++ b/src/jemalloc/include/jemalloc/internal/ctl.h
@@ -49,19 +49,11 @@ struct ctl_arena_stats_s {
 };
 
 struct ctl_stats_s {
-	size_t			allocated;
-	size_t			active;
-	size_t			mapped;
 	struct {
 		size_t		current;	/* stats_chunks.curchunks */
 		uint64_t	total;		/* stats_chunks.nchunks */
 		size_t		high;		/* stats_chunks.highchunks */
 	} chunks;
-	struct {
-		size_t		allocated;	/* huge_allocated */
-		uint64_t	nmalloc;	/* huge_nmalloc */
-		uint64_t	ndalloc;	/* huge_ndalloc */
-	} huge;
 	unsigned		narenas;
 	ctl_arena_stats_t	*arenas;	/* (narenas + 1) elements. */
 };
diff --git a/src/jemalloc/include/jemalloc/internal/extent.h b/src/jemalloc/include/jemalloc/internal/extent.h
index ba95ca816bd9a81feb9bb65c3fa69f71ce10ab28..000ef6d5aa8db198c7d77f4669bf9cf16dc7e10a 100644
--- a/src/jemalloc/include/jemalloc/internal/extent.h
+++ b/src/jemalloc/include/jemalloc/internal/extent.h
@@ -24,6 +24,9 @@ struct extent_node_s {
 	/* Total region size. */
 	size_t			size;
 
+	/* Arena from which this extent came, if any */
+	arena_t			*arena;
+
 	/* True if zero-filled; used by chunk recycling code. */
 	bool			zeroed;
 };
diff --git a/src/jemalloc/include/jemalloc/internal/hash.h b/src/jemalloc/include/jemalloc/internal/hash.h
index c7183ede82d7e846b7d27d19d98e4d5907891d25..a43bbbeccd4615ab96b00ddcf23276db76e2eb35 100644
--- a/src/jemalloc/include/jemalloc/internal/hash.h
+++ b/src/jemalloc/include/jemalloc/internal/hash.h
@@ -76,9 +76,9 @@ hash_fmix_64(uint64_t k)
 {
 
 	k ^= k >> 33;
-	k *= QU(0xff51afd7ed558ccdLLU);
+	k *= KQU(0xff51afd7ed558ccd);
 	k ^= k >> 33;
-	k *= QU(0xc4ceb9fe1a85ec53LLU);
+	k *= KQU(0xc4ceb9fe1a85ec53);
 	k ^= k >> 33;
 
 	return (k);
@@ -247,8 +247,8 @@ hash_x64_128(const void *key, const int len, const uint32_t seed,
 	uint64_t h1 = seed;
 	uint64_t h2 = seed;
 
-	const uint64_t c1 = QU(0x87c37b91114253d5LLU);
-	const uint64_t c2 = QU(0x4cf5ad432745937fLLU);
+	const uint64_t c1 = KQU(0x87c37b91114253d5);
+	const uint64_t c2 = KQU(0x4cf5ad432745937f);
 
 	/* body */
 	{
diff --git a/src/jemalloc/include/jemalloc/internal/huge.h b/src/jemalloc/include/jemalloc/internal/huge.h
index a2b9c779191f1eefb9f509bfbd46d6c585ca8f5e..d527d748f5941bab7d2e84af28e49dc29f451b7e 100644
--- a/src/jemalloc/include/jemalloc/internal/huge.h
+++ b/src/jemalloc/include/jemalloc/internal/huge.h
@@ -9,34 +9,24 @@
 /******************************************************************************/
 #ifdef JEMALLOC_H_EXTERNS
 
-/* Huge allocation statistics. */
-extern uint64_t		huge_nmalloc;
-extern uint64_t		huge_ndalloc;
-extern size_t		huge_allocated;
-
-/* Protects chunk-related data structures. */
-extern malloc_mutex_t	huge_mtx;
-
-void	*huge_malloc(size_t size, bool zero, dss_prec_t dss_prec);
-void	*huge_palloc(size_t size, size_t alignment, bool zero,
-    dss_prec_t dss_prec);
+void	*huge_malloc(arena_t *arena, size_t size, bool zero);
+void	*huge_palloc(arena_t *arena, size_t size, size_t alignment, bool zero);
 bool	huge_ralloc_no_move(void *ptr, size_t oldsize, size_t size,
     size_t extra);
-void	*huge_ralloc(void *ptr, size_t oldsize, size_t size, size_t extra,
-    size_t alignment, bool zero, bool try_tcache_dalloc, dss_prec_t dss_prec);
+void	*huge_ralloc(arena_t *arena, void *ptr, size_t oldsize, size_t size,
+    size_t extra, size_t alignment, bool zero, bool try_tcache_dalloc);
 #ifdef JEMALLOC_JET
 typedef void (huge_dalloc_junk_t)(void *, size_t);
 extern huge_dalloc_junk_t *huge_dalloc_junk;
 #endif
-void	huge_dalloc(void *ptr, bool unmap);
+void	huge_dalloc(pool_t *pool, void *ptr);
 size_t	huge_salloc(const void *ptr);
-dss_prec_t	huge_dss_prec_get(arena_t *arena);
 prof_ctx_t	*huge_prof_ctx_get(const void *ptr);
 void	huge_prof_ctx_set(const void *ptr, prof_ctx_t *ctx);
-bool	huge_boot(void);
-void	huge_prefork(void);
-void	huge_postfork_parent(void);
-void	huge_postfork_child(void);
+bool	huge_boot(pool_t *pool);
+void	huge_prefork(pool_t *pool);
+void	huge_postfork_parent(pool_t *pool);
+void	huge_postfork_child(pool_t *pool);
 
 #endif /* JEMALLOC_H_EXTERNS */
 /******************************************************************************/
diff --git a/src/jemalloc/include/jemalloc/internal/jemalloc_internal.h.in b/src/jemalloc/include/jemalloc/internal/jemalloc_internal.h.in
index 574bbb14186decae29948422ae19f64d4580a9da..3ce6a7e9abacd14df5ae03b45ac56b3ac24bb66d 100644
--- a/src/jemalloc/include/jemalloc/internal/jemalloc_internal.h.in
+++ b/src/jemalloc/include/jemalloc/internal/jemalloc_internal.h.in
@@ -1,70 +1,13 @@
 #ifndef JEMALLOC_INTERNAL_H
 #define	JEMALLOC_INTERNAL_H
-#include <math.h>
-#ifdef _WIN32
-#  include <windows.h>
-#  define ENOENT ERROR_PATH_NOT_FOUND
-#  define EINVAL ERROR_BAD_ARGUMENTS
-#  define EAGAIN ERROR_OUTOFMEMORY
-#  define EPERM  ERROR_WRITE_FAULT
-#  define EFAULT ERROR_INVALID_ADDRESS
-#  define ENOMEM ERROR_NOT_ENOUGH_MEMORY
-#  undef ERANGE
-#  define ERANGE ERROR_INVALID_DATA
-#else
-#  include <sys/param.h>
-#  include <sys/mman.h>
-#  include <sys/syscall.h>
-#  if !defined(SYS_write) && defined(__NR_write)
-#    define SYS_write __NR_write
-#  endif
-#  include <sys/uio.h>
-#  include <pthread.h>
-#  include <errno.h>
-#endif
-#include <sys/types.h>
-
-#include <limits.h>
-#ifndef SIZE_T_MAX
-#  define SIZE_T_MAX	SIZE_MAX
-#endif
-#include <stdarg.h>
-#include <stdbool.h>
-#include <stdio.h>
-#include <stdlib.h>
-#include <stdint.h>
-#include <stddef.h>
-#ifndef offsetof
-#  define offsetof(type, member)	((size_t)&(((type *)NULL)->member))
-#endif
-#include <inttypes.h>
-#include <string.h>
-#include <strings.h>
-#include <ctype.h>
-#ifdef _MSC_VER
-#  include <io.h>
-typedef intptr_t ssize_t;
-#  define PATH_MAX 1024
-#  define STDERR_FILENO 2
-#  define __func__ __FUNCTION__
-/* Disable warnings about deprecated system functions */
-#  pragma warning(disable: 4996)
-#else
-#  include <unistd.h>
-#endif
-#include <fcntl.h>
 
 #include "jemalloc_internal_defs.h"
+#include "jemalloc/internal/jemalloc_internal_decls.h"
 
 #ifdef JEMALLOC_UTRACE
 #include <sys/ktrace.h>
 #endif
 
-#ifdef JEMALLOC_VALGRIND
-#include <valgrind/valgrind.h>
-#include <valgrind/memcheck.h>
-#endif
-
 #define	JEMALLOC_NO_DEMANGLE
 #ifdef JEMALLOC_JET
 #  define JEMALLOC_N(n) jet_##n
@@ -85,7 +28,7 @@ static const bool config_debug =
     false
 #endif
     ;
-static const bool config_dss =
+static const bool have_dss =
 #ifdef JEMALLOC_DSS
     true
 #else
@@ -127,13 +70,6 @@ static const bool config_prof_libunwind =
     false
 #endif
     ;
-static const bool config_mremap =
-#ifdef JEMALLOC_MREMAP
-    true
-#else
-    false
-#endif
-    ;
 static const bool config_munmap =
 #ifdef JEMALLOC_MUNMAP
     true
@@ -230,7 +166,6 @@ static const bool config_ivsalloc =
 #include "jemalloc/internal/jemalloc_internal_macros.h"
 
 #define	MALLOCX_LG_ALIGN_MASK	((int)0x3f)
-#define	ALLOCM_LG_ALIGN_MASK	((int)0x3f)
 
 /* Smallest size class to support. */
 #define	LG_TINY_MIN		3
@@ -280,6 +215,9 @@ static const bool config_ivsalloc =
 #  ifdef __tile__
 #    define LG_QUANTUM		4
 #  endif
+#  ifdef __le32__
+#    define LG_QUANTUM		4
+#  endif
 #  ifndef LG_QUANTUM
 #    error "No LG_QUANTUM definition for architecture; specify via CPPFLAGS"
 #  endif
@@ -358,86 +296,12 @@ static const bool config_ivsalloc =
 #    endif
 #  endif
 #  define VARIABLE_ARRAY(type, name, count) \
-	type *name = alloca(sizeof(type) * count)
-#else
-#  define VARIABLE_ARRAY(type, name, count) type name[count]
-#endif
-
-#ifdef JEMALLOC_VALGRIND
-/*
- * The JEMALLOC_VALGRIND_*() macros must be macros rather than functions
- * so that when Valgrind reports errors, there are no extra stack frames
- * in the backtraces.
- *
- * The size that is reported to valgrind must be consistent through a chain of
- * malloc..realloc..realloc calls.  Request size isn't recorded anywhere in
- * jemalloc, so it is critical that all callers of these macros provide usize
- * rather than request size.  As a result, buffer overflow detection is
- * technically weakened for the standard API, though it is generally accepted
- * practice to consider any extra bytes reported by malloc_usable_size() as
- * usable space.
- */
-#define	JEMALLOC_VALGRIND_MALLOC(cond, ptr, usize, zero) do {		\
-	if (config_valgrind && opt_valgrind && cond)			\
-		VALGRIND_MALLOCLIKE_BLOCK(ptr, usize, p2rz(ptr), zero);	\
-} while (0)
-#define	JEMALLOC_VALGRIND_REALLOC(ptr, usize, old_ptr, old_usize,	\
-    old_rzsize, zero)  do {						\
-	if (config_valgrind && opt_valgrind) {				\
-		size_t rzsize = p2rz(ptr);				\
-									\
-		if (ptr == old_ptr) {					\
-			VALGRIND_RESIZEINPLACE_BLOCK(ptr, old_usize,	\
-			    usize, rzsize);				\
-			if (zero && old_usize < usize) {		\
-				VALGRIND_MAKE_MEM_DEFINED(		\
-				    (void *)((uintptr_t)ptr +		\
-				    old_usize), usize - old_usize);	\
-			}						\
-		} else {						\
-			if (old_ptr != NULL) {				\
-				VALGRIND_FREELIKE_BLOCK(old_ptr,	\
-				    old_rzsize);			\
-			}						\
-			if (ptr != NULL) {				\
-				size_t copy_size = (old_usize < usize)	\
-				    ?  old_usize : usize;		\
-				size_t tail_size = usize - copy_size;	\
-				VALGRIND_MALLOCLIKE_BLOCK(ptr, usize,	\
-				    rzsize, false);			\
-				if (copy_size > 0) {			\
-					VALGRIND_MAKE_MEM_DEFINED(ptr,	\
-					    copy_size);			\
-				}					\
-				if (zero && tail_size > 0) {		\
-					VALGRIND_MAKE_MEM_DEFINED(	\
-					    (void *)((uintptr_t)ptr +	\
-					    copy_size), tail_size);	\
-				}					\
-			}						\
-		}							\
-	}								\
-} while (0)
-#define	JEMALLOC_VALGRIND_FREE(ptr, rzsize) do {			\
-	if (config_valgrind && opt_valgrind)				\
-		VALGRIND_FREELIKE_BLOCK(ptr, rzsize);			\
-} while (0)
+	type *name = alloca(sizeof(type) * (count))
 #else
-#define	RUNNING_ON_VALGRIND	((unsigned)0)
-#define	VALGRIND_MALLOCLIKE_BLOCK(addr, sizeB, rzB, is_zeroed) \
-    do {} while (0)
-#define	VALGRIND_RESIZEINPLACE_BLOCK(addr, oldSizeB, newSizeB, rzB) \
-    do {} while (0)
-#define	VALGRIND_FREELIKE_BLOCK(addr, rzB) do {} while (0)
-#define	VALGRIND_MAKE_MEM_NOACCESS(_qzz_addr, _qzz_len) do {} while (0)
-#define	VALGRIND_MAKE_MEM_UNDEFINED(_qzz_addr, _qzz_len) do {} while (0)
-#define	VALGRIND_MAKE_MEM_DEFINED(_qzz_addr, _qzz_len) do {} while (0)
-#define	JEMALLOC_VALGRIND_MALLOC(cond, ptr, usize, zero) do {} while (0)
-#define	JEMALLOC_VALGRIND_REALLOC(ptr, usize, old_ptr, old_usize,	\
-    old_rzsize, zero) do {} while (0)
-#define	JEMALLOC_VALGRIND_FREE(ptr, rzsize) do {} while (0)
+#  define VARIABLE_ARRAY(type, name, count) type name[(count)]
 #endif
 
+#include "jemalloc/internal/valgrind.h"
 #include "jemalloc/internal/util.h"
 #include "jemalloc/internal/atomic.h"
 #include "jemalloc/internal/prng.h"
@@ -459,11 +323,14 @@ static const bool config_ivsalloc =
 #include "jemalloc/internal/hash.h"
 #include "jemalloc/internal/quarantine.h"
 #include "jemalloc/internal/prof.h"
+#include "jemalloc/internal/pool.h"
+#include "jemalloc/internal/vector.h"
 
 #undef JEMALLOC_H_TYPES
 /******************************************************************************/
 #define	JEMALLOC_H_STRUCTS
 
+#include "jemalloc/internal/valgrind.h"
 #include "jemalloc/internal/util.h"
 #include "jemalloc/internal/atomic.h"
 #include "jemalloc/internal/prng.h"
@@ -485,6 +352,8 @@ static const bool config_ivsalloc =
 #include "jemalloc/internal/hash.h"
 #include "jemalloc/internal/quarantine.h"
 #include "jemalloc/internal/prof.h"
+#include "jemalloc/internal/pool.h"
+#include "jemalloc/internal/vector.h"
 
 typedef struct {
 	uint64_t	allocated;
@@ -505,35 +374,30 @@ extern bool	opt_junk;
 extern size_t	opt_quarantine;
 extern bool	opt_redzone;
 extern bool	opt_utrace;
-extern bool	opt_valgrind;
 extern bool	opt_xmalloc;
 extern bool	opt_zero;
 extern size_t	opt_narenas;
 
+extern bool	in_valgrind;
+
 /* Number of CPUs. */
 extern unsigned		ncpus;
 
-/* Protects arenas initialization (arenas, arenas_total). */
-extern malloc_mutex_t	arenas_lock;
-/*
- * Arenas that are used to service external requests.  Not all elements of the
- * arenas array are necessarily used; arenas are created lazily as needed.
- *
- * arenas[0..narenas_auto) are used for automatic multiplexing of threads and
- * arenas.  arenas[narenas_auto..narenas_total) are only used if the application
- * takes some action to create them and allocate from them.
- */
-extern arena_t		**arenas;
-extern unsigned		narenas_total;
-extern unsigned		narenas_auto; /* Read-only after initialization. */
+extern unsigned	npools;
+extern pool_t	*pools[POOLS_MAX];
 
-arena_t	*arenas_extend(unsigned ind);
+extern malloc_mutex_t	pools_lock;
+extern void	*(*je_base_malloc)(size_t);
+extern void	(*je_base_free)(void *);
+
+arena_t	*arenas_extend(pool_t *pool, unsigned ind);
 void	arenas_cleanup(void *arg);
-arena_t	*choose_arena_hard(void);
+arena_t	*choose_arena_hard(pool_t *pool);
 void	jemalloc_prefork(void);
 void	jemalloc_postfork_parent(void);
 void	jemalloc_postfork_child(void);
 
+#include "jemalloc/internal/valgrind.h"
 #include "jemalloc/internal/util.h"
 #include "jemalloc/internal/atomic.h"
 #include "jemalloc/internal/prng.h"
@@ -555,11 +419,14 @@ void	jemalloc_postfork_child(void);
 #include "jemalloc/internal/hash.h"
 #include "jemalloc/internal/quarantine.h"
 #include "jemalloc/internal/prof.h"
+#include "jemalloc/internal/pool.h"
+#include "jemalloc/internal/vector.h"
 
 #undef JEMALLOC_H_EXTERNS
 /******************************************************************************/
 #define	JEMALLOC_H_INLINES
 
+#include "jemalloc/internal/valgrind.h"
 #include "jemalloc/internal/util.h"
 #include "jemalloc/internal/atomic.h"
 #include "jemalloc/internal/prng.h"
@@ -575,12 +442,20 @@ void	jemalloc_postfork_child(void);
 #include "jemalloc/internal/chunk.h"
 #include "jemalloc/internal/huge.h"
 
+/*
+ * Include arena.h the first time in order to provide inline functions for this
+ * header's inlines.
+ */
+#define	JEMALLOC_ARENA_INLINE_A
+#include "jemalloc/internal/arena.h"
+#undef JEMALLOC_ARENA_INLINE_A
+
 #ifndef JEMALLOC_ENABLE_INLINE
-malloc_tsd_protos(JEMALLOC_ATTR(unused), arenas, arena_t *)
+malloc_tsd_protos(JEMALLOC_ATTR(unused), arenas, tsd_pool_t)
 
 size_t	s2u(size_t size);
 size_t	sa2u(size_t size, size_t alignment);
-unsigned	narenas_total_get(void);
+unsigned	narenas_total_get(pool_t *pool);
 arena_t	*choose_arena(arena_t *arena);
 #endif
 
@@ -589,10 +464,19 @@ arena_t	*choose_arena(arena_t *arena);
  * Map of pthread_self() --> arenas[???], used for selecting an arena to use
  * for allocations.
  */
-malloc_tsd_externs(arenas, arena_t *)
-malloc_tsd_funcs(JEMALLOC_ALWAYS_INLINE, arenas, arena_t *, NULL,
+malloc_tsd_externs(arenas, tsd_pool_t)
+malloc_tsd_funcs(JEMALLOC_ALWAYS_INLINE, arenas, tsd_pool_t, NULL,
     arenas_cleanup)
 
+
+/*
+ * Check if the arena is dummy.
+ */
+JEMALLOC_ALWAYS_INLINE bool
+is_arena_dummy(arena_t *arena) {
+	return (arena->ind == ARENA_DUMMY_IND);
+}
+
 /*
  * Compute usable size that would result from allocating an object with the
  * specified size.
@@ -602,7 +486,7 @@ s2u(size_t size)
 {
 
 	if (size <= SMALL_MAXCLASS)
-		return (arena_bin_info[SMALL_SIZE2BIN(size)].reg_size);
+		return (small_s2u(size));
 	if (size <= arena_maxclass)
 		return (PAGE_CEILING(size));
 	return (CHUNK_CEILING(size));
@@ -645,7 +529,7 @@ sa2u(size_t size, size_t alignment)
 
 	if (usize <= arena_maxclass && alignment <= PAGE) {
 		if (usize <= SMALL_MAXCLASS)
-			return (arena_bin_info[SMALL_SIZE2BIN(usize)].reg_size);
+			return (small_s2u(usize));
 		return (PAGE_CEILING(usize));
 	} else {
 		size_t run_size;
@@ -687,28 +571,37 @@ sa2u(size_t size, size_t alignment)
 }
 
 JEMALLOC_INLINE unsigned
-narenas_total_get(void)
+narenas_total_get(pool_t *pool)
 {
 	unsigned narenas;
-
-	malloc_mutex_lock(&arenas_lock);
-	narenas = narenas_total;
-	malloc_mutex_unlock(&arenas_lock);
+	malloc_mutex_lock(&pool->arenas_lock);
+	narenas = pool->narenas_total;
+	malloc_mutex_unlock(&pool->arenas_lock);
 
 	return (narenas);
 }
 
-/* Choose an arena based on a per-thread value. */
+/* 
+ * Choose an arena based on a per-thread value.
+ * Arena pointer must be either a valid arena pointer or a dummy arena with
+ * pool field filled.
+ */
 JEMALLOC_INLINE arena_t *
 choose_arena(arena_t *arena)
 {
 	arena_t *ret;
+	tsd_pool_t *tsd;
+	pool_t *pool;
 
-	if (arena != NULL)
+	if (!is_arena_dummy(arena))
 		return (arena);
 
-	if ((ret = *arenas_tsd_get()) == NULL) {
-		ret = choose_arena_hard();
+	pool = arena->pool;
+	tsd = arenas_tsd_get();
+
+	if ( (tsd->seqno[pool->pool_id] != pool->seqno) || 
+		(ret = tsd->arenas[pool->pool_id]) == NULL) {
+		ret = choose_arena_hard(pool);
 		assert(ret != NULL);
 	}
 
@@ -719,27 +612,30 @@ choose_arena(arena_t *arena)
 #include "jemalloc/internal/bitmap.h"
 #include "jemalloc/internal/rtree.h"
 /*
- * Include arena.h twice in order to resolve circular dependencies with
- * tcache.h.
+ * Include arena.h the second and third times in order to resolve circular
+ * dependencies with tcache.h.
  */
-#define	JEMALLOC_ARENA_INLINE_A
-#include "jemalloc/internal/arena.h"
-#undef JEMALLOC_ARENA_INLINE_A
-#include "jemalloc/internal/tcache.h"
 #define	JEMALLOC_ARENA_INLINE_B
 #include "jemalloc/internal/arena.h"
 #undef JEMALLOC_ARENA_INLINE_B
+#include "jemalloc/internal/tcache.h"
+#define	JEMALLOC_ARENA_INLINE_C
+#include "jemalloc/internal/arena.h"
+#undef JEMALLOC_ARENA_INLINE_C
 #include "jemalloc/internal/hash.h"
 #include "jemalloc/internal/quarantine.h"
 
 #ifndef JEMALLOC_ENABLE_INLINE
 void	*imalloct(size_t size, bool try_tcache, arena_t *arena);
 void	*imalloc(size_t size);
+void	*pool_imalloc(pool_t *pool, size_t size);
 void	*icalloct(size_t size, bool try_tcache, arena_t *arena);
 void	*icalloc(size_t size);
+void	*pool_icalloc(pool_t *pool, size_t size);
 void	*ipalloct(size_t usize, size_t alignment, bool zero, bool try_tcache,
     arena_t *arena);
 void	*ipalloc(size_t usize, size_t alignment, bool zero);
+void	*pool_ipalloc(pool_t *pool, size_t usize, size_t alignment, bool zero);
 size_t	isalloc(const void *ptr, bool demote);
 size_t	ivsalloc(const void *ptr, bool demote);
 size_t	u2rz(size_t usize);
@@ -755,6 +651,8 @@ void	*iralloct(void *ptr, size_t size, size_t extra, size_t alignment,
     bool zero, bool try_tcache_alloc, bool try_tcache_dalloc, arena_t *arena);
 void	*iralloc(void *ptr, size_t size, size_t extra, size_t alignment,
     bool zero);
+void	*pool_iralloc(pool_t *pool, void *ptr, size_t size, size_t extra,
+    size_t alignment, bool zero);
 bool	ixalloc(void *ptr, size_t size, size_t extra, size_t alignment,
     bool zero);
 malloc_tsd_protos(JEMALLOC_ATTR(unused), thread_allocated, thread_allocated_t)
@@ -764,37 +662,53 @@ malloc_tsd_protos(JEMALLOC_ATTR(unused), thread_allocated, thread_allocated_t)
 JEMALLOC_ALWAYS_INLINE void *
 imalloct(size_t size, bool try_tcache, arena_t *arena)
 {
-
 	assert(size != 0);
 
 	if (size <= arena_maxclass)
 		return (arena_malloc(arena, size, false, try_tcache));
 	else
-		return (huge_malloc(size, false, huge_dss_prec_get(arena)));
+		return (huge_malloc(arena, size, false));
 }
 
 JEMALLOC_ALWAYS_INLINE void *
 imalloc(size_t size)
 {
+	arena_t dummy;
+	DUMMY_ARENA_INITIALIZE(dummy, pools[0]);
+	return (imalloct(size, true, &dummy));
+}
 
-	return (imalloct(size, true, NULL));
+JEMALLOC_ALWAYS_INLINE void *
+pool_imalloc(pool_t *pool, size_t size)
+{
+	arena_t dummy;
+	DUMMY_ARENA_INITIALIZE(dummy, pool);
+	return (imalloct(size, true, &dummy));
 }
 
 JEMALLOC_ALWAYS_INLINE void *
 icalloct(size_t size, bool try_tcache, arena_t *arena)
 {
-
 	if (size <= arena_maxclass)
 		return (arena_malloc(arena, size, true, try_tcache));
 	else
-		return (huge_malloc(size, true, huge_dss_prec_get(arena)));
+		return (huge_malloc(arena, size, true));
 }
 
 JEMALLOC_ALWAYS_INLINE void *
 icalloc(size_t size)
 {
+	arena_t dummy;
+	DUMMY_ARENA_INITIALIZE(dummy, pools[0]);
+	return (icalloct(size, true, &dummy));
+}
 
-	return (icalloct(size, true, NULL));
+JEMALLOC_ALWAYS_INLINE void *
+pool_icalloc(pool_t *pool, size_t size)
+{
+	arena_t dummy;
+	DUMMY_ARENA_INITIALIZE(dummy, pool);
+	return (icalloct(size, true, &dummy));
 }
 
 JEMALLOC_ALWAYS_INLINE void *
@@ -813,9 +727,9 @@ ipalloct(size_t usize, size_t alignment, bool zero, bool try_tcache,
 			ret = arena_palloc(choose_arena(arena), usize,
 			    alignment, zero);
 		} else if (alignment <= chunksize)
-			ret = huge_malloc(usize, zero, huge_dss_prec_get(arena));
+			ret = huge_malloc(arena, usize, zero);
 		else
-			ret = huge_palloc(usize, alignment, zero, huge_dss_prec_get(arena));
+			ret = huge_palloc(arena, usize, alignment, zero);
 	}
 
 	assert(ALIGNMENT_ADDR2BASE(ret, alignment) == ret);
@@ -825,8 +739,17 @@ ipalloct(size_t usize, size_t alignment, bool zero, bool try_tcache,
 JEMALLOC_ALWAYS_INLINE void *
 ipalloc(size_t usize, size_t alignment, bool zero)
 {
+	arena_t dummy;
+	DUMMY_ARENA_INITIALIZE(dummy, pools[0]);
+	return (ipalloct(usize, alignment, zero, true, &dummy));
+}
 
-	return (ipalloct(usize, alignment, zero, true, NULL));
+JEMALLOC_ALWAYS_INLINE void *
+pool_ipalloc(pool_t *pool, size_t usize, size_t alignment, bool zero)
+{
+	arena_t dummy;
+	DUMMY_ARENA_INITIALIZE(dummy, pool);
+	return (ipalloct(usize, alignment, zero, true, &dummy));
 }
 
 /*
@@ -856,9 +779,18 @@ isalloc(const void *ptr, bool demote)
 JEMALLOC_ALWAYS_INLINE size_t
 ivsalloc(const void *ptr, bool demote)
 {
+	int i;
+	for (i = 0; i < POOLS_MAX; ++i) {
+	    pool_t *pool = pools[i];
+		if (pool == NULL)
+			continue;
+
+	    /* Return 0 if ptr is not within a chunk managed by jemalloc. */
+	    if (rtree_get(pool->chunks_rtree, (uintptr_t)CHUNK_ADDR2BASE(ptr)) != 0)
+		break;
+	}
 
-	/* Return 0 if ptr is not within a chunk managed by jemalloc. */
-	if (rtree_get(chunks_rtree, (uintptr_t)CHUNK_ADDR2BASE(ptr)) == 0)
+	if (i == POOLS_MAX)
 		return (0);
 
 	return (isalloc(ptr, demote));
@@ -870,7 +802,7 @@ u2rz(size_t usize)
 	size_t ret;
 
 	if (usize <= SMALL_MAXCLASS) {
-		size_t binind = SMALL_SIZE2BIN(usize);
+		size_t binind = small_size2bin(usize);
 		ret = arena_bin_info[binind].redzone_size;
 	} else
 		ret = 0;
@@ -890,14 +822,15 @@ JEMALLOC_ALWAYS_INLINE void
 idalloct(void *ptr, bool try_tcache)
 {
 	arena_chunk_t *chunk;
+	pool_t *base_pool = pools[0];
 
 	assert(ptr != NULL);
 
 	chunk = (arena_chunk_t *)CHUNK_ADDR2BASE(ptr);
 	if (chunk != ptr)
-		arena_dalloc(chunk->arena, chunk, ptr, try_tcache);
+		arena_dalloc(chunk, ptr, try_tcache);
 	else
-		huge_dalloc(ptr, true);
+		huge_dalloc(base_pool, ptr);
 }
 
 JEMALLOC_ALWAYS_INLINE void
@@ -983,16 +916,26 @@ iralloct(void *ptr, size_t size, size_t extra, size_t alignment, bool zero,
 		    alignment, zero, try_tcache_alloc,
 		    try_tcache_dalloc));
 	} else {
-		return (huge_ralloc(ptr, oldsize, size, extra,
-		    alignment, zero, try_tcache_dalloc, huge_dss_prec_get(arena)));
+		return (huge_ralloc(arena, ptr, oldsize, size, extra,
+		    alignment, zero, try_tcache_dalloc));
 	}
 }
 
 JEMALLOC_ALWAYS_INLINE void *
 iralloc(void *ptr, size_t size, size_t extra, size_t alignment, bool zero)
 {
+	arena_t dummy;
+	DUMMY_ARENA_INITIALIZE(dummy, pools[0]);
+	return (iralloct(ptr, size, extra, alignment, zero, true, true, &dummy));
+}
 
-	return (iralloct(ptr, size, extra, alignment, zero, true, true, NULL));
+JEMALLOC_ALWAYS_INLINE void *
+pool_iralloc(pool_t *pool, void *ptr, size_t size, size_t extra,
+    size_t alignment, bool zero)
+{
+	arena_t dummy;
+	DUMMY_ARENA_INITIALIZE(dummy, pool);
+	return (iralloct(ptr, size, extra, alignment, zero, true, true, &dummy));
 }
 
 JEMALLOC_ALWAYS_INLINE bool
diff --git a/src/jemalloc/include/jemalloc/internal/jemalloc_internal_decls.h b/src/jemalloc/include/jemalloc/internal/jemalloc_internal_decls.h
new file mode 100644
index 0000000000000000000000000000000000000000..fa590404708baf8129564203da583fe829be60bb
--- /dev/null
+++ b/src/jemalloc/include/jemalloc/internal/jemalloc_internal_decls.h
@@ -0,0 +1,60 @@
+#ifndef JEMALLOC_INTERNAL_DECLS_H
+#define	JEMALLOC_INTERNAL_DECLS_H
+
+#include <math.h>
+#ifdef _WIN32
+#  include <windows.h>
+#  define ENOENT ERROR_PATH_NOT_FOUND
+#  define EINVAL ERROR_BAD_ARGUMENTS
+#  define EAGAIN ERROR_OUTOFMEMORY
+#  define EPERM  ERROR_WRITE_FAULT
+#  define EFAULT ERROR_INVALID_ADDRESS
+#  define ENOMEM ERROR_NOT_ENOUGH_MEMORY
+#  undef ERANGE
+#  define ERANGE ERROR_INVALID_DATA
+#else
+#  include <sys/param.h>
+#  include <sys/mman.h>
+#  if !defined(__pnacl__) && !defined(__native_client__)
+#    include <sys/syscall.h>
+#    if !defined(SYS_write) && defined(__NR_write)
+#      define SYS_write __NR_write
+#    endif
+#    include <sys/uio.h>
+#  endif
+#  include <pthread.h>
+#  include <errno.h>
+#endif
+#include <sys/types.h>
+
+#include <limits.h>
+#ifndef SIZE_T_MAX
+#  define SIZE_T_MAX	SIZE_MAX
+#endif
+#include <stdarg.h>
+#include <stdbool.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <stdint.h>
+#include <stddef.h>
+#ifndef offsetof
+#  define offsetof(type, member)	((size_t)&(((type *)NULL)->member))
+#endif
+#include <inttypes.h>
+#include <string.h>
+#include <strings.h>
+#include <ctype.h>
+#ifdef _MSC_VER
+#  include <io.h>
+typedef intptr_t ssize_t;
+#  define PATH_MAX 1024
+#  define STDERR_FILENO 2
+#  define __func__ __FUNCTION__
+/* Disable warnings about deprecated system functions */
+#  pragma warning(disable: 4996)
+#else
+#  include <unistd.h>
+#endif
+#include <fcntl.h>
+
+#endif /* JEMALLOC_INTERNAL_H */
diff --git a/src/jemalloc/include/jemalloc/internal/jemalloc_internal_defs.h.in b/src/jemalloc/include/jemalloc/internal/jemalloc_internal_defs.h.in
index c166fbd9e41b6a7160cee51883399cddaa8cf1d1..93716b0a4b96931f44a2833d7333688300028fe1 100644
--- a/src/jemalloc/include/jemalloc/internal/jemalloc_internal_defs.h.in
+++ b/src/jemalloc/include/jemalloc/internal/jemalloc_internal_defs.h.in
@@ -47,6 +47,16 @@
  */
 #undef JE_FORCE_SYNC_COMPARE_AND_SWAP_8
 
+/*
+ * Defined if __builtin_clz() and __builtin_clzl() are available.
+ */
+#undef JEMALLOC_HAVE_BUILTIN_CLZ
+
+/*
+ * Defined if madvise(2) is available.
+ */
+#undef JEMALLOC_HAVE_MADVISE
+
 /*
  * Defined if OSSpin*() functions are available, as provided by Darwin, and
  * documented in the spinlock(3) manual page.
@@ -76,9 +86,6 @@
  */
 #undef JEMALLOC_MUTEX_INIT_CB
 
-/* Defined if sbrk() is supported. */
-#undef JEMALLOC_HAVE_SBRK
-
 /* Non-empty if the tls_model attribute is supported. */
 #undef JEMALLOC_TLS_MODEL
 
@@ -147,16 +154,16 @@
  */
 #undef JEMALLOC_MUNMAP
 
-/*
- * If defined, use mremap(...MREMAP_FIXED...) for huge realloc().  This is
- * disabled by default because it is Linux-specific and it will cause virtual
- * memory map holes, much like munmap(2) does.
- */
-#undef JEMALLOC_MREMAP
-
 /* TLS is used to map arenas and magazine caches to threads. */
 #undef JEMALLOC_TLS
 
+/*
+ * ffs()/ffsl() functions to use for bitmapping.  Don't use these directly;
+ * instead, use jemalloc_ffs() or jemalloc_ffsl() from util.h.
+ */
+#undef JEMALLOC_INTERNAL_FFSL
+#undef JEMALLOC_INTERNAL_FFS
+
 /*
  * JEMALLOC_IVSALLOC enables ivsalloc(), which verifies that pointers reside
  * within jemalloc-owned chunks before dereferencing them.
diff --git a/src/jemalloc/include/jemalloc/internal/jemalloc_internal_macros.h b/src/jemalloc/include/jemalloc/internal/jemalloc_internal_macros.h
index 4e2392302c7687ab91d6980ebce9e847ea5f3a9d..a08ba772ead406d34e5739d7b62b58597ab28d66 100644
--- a/src/jemalloc/include/jemalloc/internal/jemalloc_internal_macros.h
+++ b/src/jemalloc/include/jemalloc/internal/jemalloc_internal_macros.h
@@ -39,9 +39,15 @@
 #endif
 
 #define	ZU(z)	((size_t)z)
+#define	ZI(z)	((ssize_t)z)
 #define	QU(q)	((uint64_t)q)
 #define	QI(q)	((int64_t)q)
 
+#define	KZU(z)	ZU(z##ULL)
+#define	KZI(z)	ZI(z##LL)
+#define	KQU(q)	QU(q##ULL)
+#define	KQI(q)	QI(q##LL)
+
 #ifndef __DECONST
 #  define	__DECONST(type, var)	((type)(uintptr_t)(const void *)(var))
 #endif
diff --git a/src/jemalloc/include/jemalloc/internal/pool.h b/src/jemalloc/include/jemalloc/internal/pool.h
new file mode 100644
index 0000000000000000000000000000000000000000..ef4c5fb700c4e08b04811928a6e6de622a9c4f71
--- /dev/null
+++ b/src/jemalloc/include/jemalloc/internal/pool.h
@@ -0,0 +1,129 @@
+/******************************************************************************/
+#ifdef JEMALLOC_H_TYPES
+
+#define POOLS_MAX  10
+
+/*
+ * We want to expose pool_t to the library user
+ * as a result typedef for pool_s is located in "jemalloc.h"
+ */
+typedef struct tsd_pool_s tsd_pool_t;
+
+/*
+ * Dummy arena is used to pass pool structure to choose_arena function
+ * through various alloc/free variants
+ */
+#define ARENA_DUMMY_IND			(~0)
+#define DUMMY_ARENA_INITIALIZE(name, p)		\
+do {						\
+(name).ind = ARENA_DUMMY_IND;			\
+(name).pool = (p);				\
+} while (0)
+
+#define	TSD_POOL_INITIALIZER		JEMALLOC_ARG_CONCAT({.arenas = {0}})
+
+
+#endif /* JEMALLOC_H_TYPES */
+/******************************************************************************/
+#ifdef JEMALLOC_H_STRUCTS
+
+struct pool_s {
+	/* This pool's index within the pools array. */
+	unsigned pool_id;
+	/*
+	 * Unique pool number. A pool_id can be reused, seqno helping to check
+	 * that data in Thread Storage Data are still valid.
+	 */
+	unsigned seqno;
+	/* Protects arenas initialization (arenas, arenas_total). */
+	malloc_mutex_t	arenas_lock;
+	/*
+	 * Arenas that are used to service external requests.  Not all elements of the
+	 * arenas array are necessarily used; arenas are created lazily as needed.
+	 *
+	 * arenas[0..narenas_auto) are used for automatic multiplexing of threads and
+	 * arenas.  arenas[narenas_auto..narenas_total) are only used if the application
+	 * takes some action to create them and allocate from them.
+	 */
+	arena_t **arenas;
+	unsigned narenas_total;
+	unsigned narenas_auto;
+
+	/* Tree of chunks that are stand-alone huge allocations. */
+	extent_tree_t	huge;
+	/* Protects chunk-related data structures. */
+	malloc_mutex_t	huge_mtx;
+
+	malloc_mutex_t	chunks_mtx;
+	chunk_stats_t	stats_chunks;
+
+	/*
+	 * Trees of chunks that were previously allocated (trees differ only in node
+	 * ordering).  These are used when allocating chunks, in an attempt to re-use
+	 * address space.  Depending on function, different tree orderings are needed,
+	 * which is why there are two trees with the same contents.
+	 */
+	extent_tree_t	chunks_szad_mmap;
+	extent_tree_t	chunks_ad_mmap;
+	extent_tree_t	chunks_szad_dss;
+	extent_tree_t	chunks_ad_dss;
+
+	rtree_t		*chunks_rtree;
+
+	/* Protects base-related data structures. */
+	malloc_mutex_t	base_mtx;
+	malloc_mutex_t	base_node_mtx;
+	/*
+	 * Current pages that are being used for internal memory allocations.  These
+	 * pages are carved up in cacheline-size quanta, so that there is no chance of
+	 * false cache line sharing.
+	 */
+	void		*base_next_addr;
+	void		*base_past_addr; /* Addr immediately past base_pages. */
+	extent_node_t	*base_nodes;
+
+	/*
+	 * Per pool statistics variables
+	 */
+	bool		ctl_initialized;
+	ctl_stats_t	ctl_stats;
+	size_t		ctl_stats_allocated;
+	size_t		ctl_stats_active;
+	size_t		ctl_stats_mapped;
+	size_t		stats_cactive;
+};
+
+struct tsd_pool_s {
+	unsigned seqno[POOLS_MAX]; /* Sequence number of pool */
+	arena_t *arenas[POOLS_MAX];
+};
+
+/*
+ * Minimal size of pool, includes header alignment to cache line size,
+ * initial space for base allocator, and size of at least one chunk
+ * of memory with address alignment to multiple of chunksize.
+ */
+#define POOL_MINIMAL_SIZE (3*chunksize)
+
+
+#endif /* JEMALLOC_H_STRUCTS */
+/******************************************************************************/
+#ifdef JEMALLOC_H_EXTERNS
+
+bool pool_new(pool_t *pool, unsigned pool_id);
+void pool_destroy(pool_t *pool);
+
+extern malloc_mutex_t	pools_lock;
+extern malloc_mutex_t	pool_base_lock;
+
+bool pool_boot();
+void pool_prefork();
+void pool_postfork_parent();
+void pool_postfork_child();
+
+#endif /* JEMALLOC_H_EXTERNS */
+/******************************************************************************/
+#ifdef JEMALLOC_H_INLINES
+
+#endif /* JEMALLOC_H_INLINES */
+/******************************************************************************/
diff --git a/src/jemalloc/include/jemalloc/internal/private_symbols.txt b/src/jemalloc/include/jemalloc/internal/private_symbols.txt
index 93516d242b69e6a0e11b1b7ff91035b625b486c6..66335375eac1285ebc8677e7848eb7aff1b460a8 100644
--- a/src/jemalloc/include/jemalloc/internal/private_symbols.txt
+++ b/src/jemalloc/include/jemalloc/internal/private_symbols.txt
@@ -5,6 +5,8 @@ arena_alloc_junk_small
 arena_bin_index
 arena_bin_info
 arena_boot
+arena_chunk_alloc_huge
+arena_chunk_dalloc_huge
 arena_dalloc
 arena_dalloc_bin
 arena_dalloc_bin_locked
@@ -61,6 +63,7 @@ arena_salloc
 arena_stats_merge
 arena_tcache_fill_small
 arenas
+pools
 arenas_booted
 arenas_cleanup
 arenas_extend
@@ -86,7 +89,7 @@ base_alloc
 base_boot
 base_calloc
 base_node_alloc
-base_node_dealloc
+base_node_dalloc
 base_postfork_child
 base_postfork_parent
 base_prefork
@@ -103,12 +106,15 @@ bt_init
 buferror
 choose_arena
 choose_arena_hard
-chunk_alloc
+chunk_alloc_arena
+chunk_alloc_base
+chunk_alloc_default
 chunk_alloc_dss
 chunk_alloc_mmap
+chunk_global_boot
 chunk_boot
-chunk_dealloc
-chunk_dealloc_mmap
+chunk_dalloc_default
+chunk_dalloc_mmap
 chunk_dss_boot
 chunk_dss_postfork_child
 chunk_dss_postfork_parent
@@ -121,6 +127,7 @@ chunk_postfork_child
 chunk_postfork_parent
 chunk_prefork
 chunk_unmap
+chunk_record
 chunks_mtx
 chunks_rtree
 chunksize
@@ -197,9 +204,7 @@ huge_allocated
 huge_boot
 huge_dalloc
 huge_dalloc_junk
-huge_dss_prec_get
 huge_malloc
-huge_mtx
 huge_ndalloc
 huge_nmalloc
 huge_palloc
@@ -211,13 +216,13 @@ huge_prof_ctx_set
 huge_ralloc
 huge_ralloc_no_move
 huge_salloc
-iallocm
 icalloc
 icalloct
 idalloc
 idalloct
 imalloc
 imalloct
+in_valgrind
 ipalloc
 ipalloct
 iqalloc
@@ -232,6 +237,7 @@ ixalloc
 jemalloc_postfork_child
 jemalloc_postfork_parent
 jemalloc_prefork
+lg_floor
 malloc_cprintf
 malloc_mutex_init
 malloc_mutex_lock
@@ -279,7 +285,6 @@ opt_redzone
 opt_stats_print
 opt_tcache
 opt_utrace
-opt_valgrind
 opt_xmalloc
 opt_zero
 p2rz
@@ -299,11 +304,11 @@ prof_idump
 prof_interval
 prof_lookup
 prof_malloc
+prof_malloc_record_object
 prof_mdump
 prof_postfork_child
 prof_postfork_parent
 prof_prefork
-prof_promote
 prof_realloc
 prof_sample_accum_update
 prof_sample_threshold_update
@@ -346,7 +351,17 @@ rtree_set
 s2u
 sa2u
 set_errno
+small_bin2size
+small_bin2size_compute
+small_bin2size_lookup
+small_bin2size_tab
+small_s2u
+small_s2u_compute
+small_s2u_lookup
 small_size2bin
+small_size2bin_compute
+small_size2bin_lookup
+small_size2bin_tab
 stats_cactive
 stats_cactive_add
 stats_cactive_get
@@ -385,6 +400,7 @@ tcache_event
 tcache_event_hard
 tcache_flush
 tcache_get
+tcache_get_hard
 tcache_initialized
 tcache_maxclass
 tcache_salloc
@@ -411,3 +427,19 @@ thread_allocated_tsd_set
 tsd_init_check_recursion
 tsd_init_finish
 u2rz
+valgrind_freelike_block
+valgrind_make_mem_defined
+valgrind_make_mem_noaccess
+valgrind_make_mem_undefined
+pool_new
+pool_destroy
+pools_lock
+pool_base_lock
+pool_boot
+pool_prefork
+pool_postfork_parent
+pool_postfork_child
+pool_alloc
+vec_get
+vec_set
+vec_delete
\ No newline at end of file
diff --git a/src/jemalloc/include/jemalloc/internal/prof.h b/src/jemalloc/include/jemalloc/internal/prof.h
index 6f162d21e8403ce6dc1ac8d6df1b4468a70d5693..d82fbc4f21d48d1da990801579431128ff33a3a6 100644
--- a/src/jemalloc/include/jemalloc/internal/prof.h
+++ b/src/jemalloc/include/jemalloc/internal/prof.h
@@ -63,7 +63,6 @@ struct prof_bt_s {
 /* Data structure passed to libgcc _Unwind_Backtrace() callback functions. */
 typedef struct {
 	prof_bt_t	*bt;
-	unsigned	nignore;
 	unsigned	max;
 } prof_unwind_data_t;
 #endif
@@ -177,8 +176,7 @@ struct prof_tdata_s {
 
 	/* Sampling state. */
 	uint64_t		prng_state;
-	uint64_t		threshold;
-	uint64_t		accum;
+	uint64_t		bytes_until_sample;
 
 	/* State used to avoid dumping while operating on prof internals. */
 	bool			enq;
@@ -220,14 +218,8 @@ extern char	opt_prof_prefix[
  */
 extern uint64_t	prof_interval;
 
-/*
- * If true, promote small sampled objects to large objects, since small run
- * headers do not have embedded profile context pointers.
- */
-extern bool	prof_promote;
-
 void	bt_init(prof_bt_t *bt, void **vec);
-void	prof_backtrace(prof_bt_t *bt, unsigned nignore);
+void	prof_backtrace(prof_bt_t *bt);
 prof_thr_cnt_t	*prof_lookup(prof_bt_t *bt);
 #ifdef JEMALLOC_JET
 size_t	prof_bt_count(void);
@@ -245,60 +237,25 @@ bool	prof_boot2(void);
 void	prof_prefork(void);
 void	prof_postfork_parent(void);
 void	prof_postfork_child(void);
+void	prof_sample_threshold_update(prof_tdata_t *prof_tdata);
 
 #endif /* JEMALLOC_H_EXTERNS */
 /******************************************************************************/
 #ifdef JEMALLOC_H_INLINES
 
-#define	PROF_ALLOC_PREP(nignore, size, ret) do {			\
+#define	PROF_ALLOC_PREP(size, ret) do {					\
 	prof_tdata_t *prof_tdata;					\
 	prof_bt_t bt;							\
 									\
 	assert(size == s2u(size));					\
 									\
-	prof_tdata = prof_tdata_get(true);				\
-	if ((uintptr_t)prof_tdata <= (uintptr_t)PROF_TDATA_STATE_MAX) {	\
-		if (prof_tdata != NULL)					\
-			ret = (prof_thr_cnt_t *)(uintptr_t)1U;		\
-		else							\
-			ret = NULL;					\
-		break;							\
-	}								\
-									\
-	if (opt_prof_active == false) {					\
-		/* Sampling is currently inactive, so avoid sampling. */\
+	if (!opt_prof_active ||						\
+	    prof_sample_accum_update(size, false, &prof_tdata)) {	\
 		ret = (prof_thr_cnt_t *)(uintptr_t)1U;			\
-	} else if (opt_lg_prof_sample == 0) {				\
-		/* Don't bother with sampling logic, since sampling   */\
-		/* interval is 1.                                     */\
+	} else {							\
 		bt_init(&bt, prof_tdata->vec);				\
-		prof_backtrace(&bt, nignore);				\
+		prof_backtrace(&bt);					\
 		ret = prof_lookup(&bt);					\
-	} else {							\
-		if (prof_tdata->threshold == 0) {			\
-			/* Initialize.  Seed the prng differently for */\
-			/* each thread.                               */\
-			prof_tdata->prng_state =			\
-			    (uint64_t)(uintptr_t)&size;			\
-			prof_sample_threshold_update(prof_tdata);	\
-		}							\
-									\
-		/* Determine whether to capture a backtrace based on  */\
-		/* whether size is enough for prof_accum to reach     */\
-		/* prof_tdata->threshold.  However, delay updating    */\
-		/* these variables until prof_{m,re}alloc(), because  */\
-		/* we don't know for sure that the allocation will    */\
-		/* succeed.                                           */\
-		/*                                                    */\
-		/* Use subtraction rather than addition to avoid      */\
-		/* potential integer overflow.                        */\
-		if (size >= prof_tdata->threshold -			\
-		    prof_tdata->accum) {				\
-			bt_init(&bt, prof_tdata->vec);			\
-			prof_backtrace(&bt, nignore);			\
-			ret = prof_lookup(&bt);				\
-		} else							\
-			ret = (prof_thr_cnt_t *)(uintptr_t)1U;		\
 	}								\
 } while (0)
 
@@ -306,10 +263,12 @@ void	prof_postfork_child(void);
 malloc_tsd_protos(JEMALLOC_ATTR(unused), prof_tdata, prof_tdata_t *)
 
 prof_tdata_t	*prof_tdata_get(bool create);
-void	prof_sample_threshold_update(prof_tdata_t *prof_tdata);
+bool	prof_sample_accum_update(size_t size, bool commit,
+    prof_tdata_t **prof_tdata_out);
 prof_ctx_t	*prof_ctx_get(const void *ptr);
-void	prof_ctx_set(const void *ptr, size_t usize, prof_ctx_t *ctx);
-bool	prof_sample_accum_update(size_t size);
+void	prof_ctx_set(const void *ptr, prof_ctx_t *ctx);
+void	prof_malloc_record_object(const void *ptr, size_t usize,
+    prof_thr_cnt_t *cnt);
 void	prof_malloc(const void *ptr, size_t usize, prof_thr_cnt_t *cnt);
 void	prof_realloc(const void *ptr, size_t usize, prof_thr_cnt_t *cnt,
     size_t old_usize, prof_ctx_t *old_ctx);
@@ -336,55 +295,6 @@ prof_tdata_get(bool create)
 	return (prof_tdata);
 }
 
-JEMALLOC_INLINE void
-prof_sample_threshold_update(prof_tdata_t *prof_tdata)
-{
-	/*
-	 * The body of this function is compiled out unless heap profiling is
-	 * enabled, so that it is possible to compile jemalloc with floating
-	 * point support completely disabled.  Avoiding floating point code is
-	 * important on memory-constrained systems, but it also enables a
-	 * workaround for versions of glibc that don't properly save/restore
-	 * floating point registers during dynamic lazy symbol loading (which
-	 * internally calls into whatever malloc implementation happens to be
-	 * integrated into the application).  Note that some compilers (e.g.
-	 * gcc 4.8) may use floating point registers for fast memory moves, so
-	 * jemalloc must be compiled with such optimizations disabled (e.g.
-	 * -mno-sse) in order for the workaround to be complete.
-	 */
-#ifdef JEMALLOC_PROF
-	uint64_t r;
-	double u;
-
-	cassert(config_prof);
-
-	/*
-	 * Compute sample threshold as a geometrically distributed random
-	 * variable with mean (2^opt_lg_prof_sample).
-	 *
-	 *                         __        __
-	 *                         |  log(u)  |                     1
-	 * prof_tdata->threshold = | -------- |, where p = -------------------
-	 *                         | log(1-p) |             opt_lg_prof_sample
-	 *                                                 2
-	 *
-	 * For more information on the math, see:
-	 *
-	 *   Non-Uniform Random Variate Generation
-	 *   Luc Devroye
-	 *   Springer-Verlag, New York, 1986
-	 *   pp 500
-	 *   (http://luc.devroye.org/rnbookindex.html)
-	 */
-	prng64(r, 53, prof_tdata->prng_state,
-	    UINT64_C(6364136223846793005), UINT64_C(1442695040888963407));
-	u = (double)r * (1.0/9007199254740992.0L);
-	prof_tdata->threshold = (uint64_t)(log(u) /
-	    log(1.0 - (1.0 / (double)((uint64_t)1U << opt_lg_prof_sample))))
-	    + (uint64_t)1U;
-#endif
-}
-
 JEMALLOC_INLINE prof_ctx_t *
 prof_ctx_get(const void *ptr)
 {
@@ -405,7 +315,7 @@ prof_ctx_get(const void *ptr)
 }
 
 JEMALLOC_INLINE void
-prof_ctx_set(const void *ptr, size_t usize, prof_ctx_t *ctx)
+prof_ctx_set(const void *ptr, prof_ctx_t *ctx)
 {
 	arena_chunk_t *chunk;
 
@@ -415,40 +325,64 @@ prof_ctx_set(const void *ptr, size_t usize, prof_ctx_t *ctx)
 	chunk = (arena_chunk_t *)CHUNK_ADDR2BASE(ptr);
 	if (chunk != ptr) {
 		/* Region. */
-		arena_prof_ctx_set(ptr, usize, ctx);
+		arena_prof_ctx_set(ptr, ctx);
 	} else
 		huge_prof_ctx_set(ptr, ctx);
 }
 
 JEMALLOC_INLINE bool
-prof_sample_accum_update(size_t size)
+prof_sample_accum_update(size_t size, bool commit,
+    prof_tdata_t **prof_tdata_out)
 {
 	prof_tdata_t *prof_tdata;
 
 	cassert(config_prof);
-	/* Sampling logic is unnecessary if the interval is 1. */
-	assert(opt_lg_prof_sample != 0);
 
-	prof_tdata = prof_tdata_get(false);
+	prof_tdata = prof_tdata_get(true);
 	if ((uintptr_t)prof_tdata <= (uintptr_t)PROF_TDATA_STATE_MAX)
+		prof_tdata = NULL;
+
+	if (prof_tdata_out != NULL)
+		*prof_tdata_out = prof_tdata;
+
+	if (prof_tdata == NULL)
 		return (true);
 
-	/* Take care to avoid integer overflow. */
-	if (size >= prof_tdata->threshold - prof_tdata->accum) {
-		prof_tdata->accum -= (prof_tdata->threshold - size);
+	if (prof_tdata->bytes_until_sample >= size) {
+		if (commit)
+			prof_tdata->bytes_until_sample -= size;
+		return (true);
+	} else {
 		/* Compute new sample threshold. */
-		prof_sample_threshold_update(prof_tdata);
-		while (prof_tdata->accum >= prof_tdata->threshold) {
-			prof_tdata->accum -= prof_tdata->threshold;
+		if (commit)
 			prof_sample_threshold_update(prof_tdata);
-		}
 		return (false);
-	} else {
-		prof_tdata->accum += size;
-		return (true);
 	}
 }
 
+JEMALLOC_INLINE void
+prof_malloc_record_object(const void *ptr, size_t usize, prof_thr_cnt_t *cnt) {
+	prof_ctx_set(ptr, cnt->ctx);
+
+	cnt->epoch++;
+	/*********/
+	mb_write();
+	/*********/
+	cnt->cnts.curobjs++;
+	cnt->cnts.curbytes += usize;
+	if (opt_prof_accum) {
+		cnt->cnts.accumobjs++;
+		cnt->cnts.accumbytes += usize;
+	}
+	/*********/
+	mb_write();
+	/*********/
+	cnt->epoch++;
+	/*********/
+	mb_write();
+	/*********/
+}
+
 JEMALLOC_INLINE void
 prof_malloc(const void *ptr, size_t usize, prof_thr_cnt_t *cnt)
 {
@@ -457,41 +391,21 @@ prof_malloc(const void *ptr, size_t usize, prof_thr_cnt_t *cnt)
 	assert(ptr != NULL);
 	assert(usize == isalloc(ptr, true));
 
-	if (opt_lg_prof_sample != 0) {
-		if (prof_sample_accum_update(usize)) {
-			/*
-			 * Don't sample.  For malloc()-like allocation, it is
-			 * always possible to tell in advance how large an
-			 * object's usable size will be, so there should never
-			 * be a difference between the usize passed to
-			 * PROF_ALLOC_PREP() and prof_malloc().
-			 */
-			assert((uintptr_t)cnt == (uintptr_t)1U);
-		}
+	if (prof_sample_accum_update(usize, true, NULL)) {
+		/*
+		 * Don't sample.  For malloc()-like allocation, it is
+		 * always possible to tell in advance how large an
+		 * object's usable size will be, so there should never
+		 * be a difference between the usize passed to
+		 * PROF_ALLOC_PREP() and prof_malloc().
+		 */
+		assert((uintptr_t)cnt == (uintptr_t)1U);
 	}
 
-	if ((uintptr_t)cnt > (uintptr_t)1U) {
-		prof_ctx_set(ptr, usize, cnt->ctx);
-
-		cnt->epoch++;
-		/*********/
-		mb_write();
-		/*********/
-		cnt->cnts.curobjs++;
-		cnt->cnts.curbytes += usize;
-		if (opt_prof_accum) {
-			cnt->cnts.accumobjs++;
-			cnt->cnts.accumbytes += usize;
-		}
-		/*********/
-		mb_write();
-		/*********/
-		cnt->epoch++;
-		/*********/
-		mb_write();
-		/*********/
-	} else
-		prof_ctx_set(ptr, usize, (prof_ctx_t *)(uintptr_t)1U);
+	if ((uintptr_t)cnt > (uintptr_t)1U)
+		prof_malloc_record_object(ptr, usize, cnt);
+	else
+		prof_ctx_set(ptr, (prof_ctx_t *)(uintptr_t)1U);
 }
 
 JEMALLOC_INLINE void
@@ -505,18 +419,16 @@ prof_realloc(const void *ptr, size_t usize, prof_thr_cnt_t *cnt,
 
 	if (ptr != NULL) {
 		assert(usize == isalloc(ptr, true));
-		if (opt_lg_prof_sample != 0) {
-			if (prof_sample_accum_update(usize)) {
-				/*
-				 * Don't sample.  The usize passed to
-				 * PROF_ALLOC_PREP() was larger than what
-				 * actually got allocated, so a backtrace was
-				 * captured for this allocation, even though
-				 * its actual usize was insufficient to cross
-				 * the sample threshold.
-				 */
-				cnt = (prof_thr_cnt_t *)(uintptr_t)1U;
-			}
+		if (prof_sample_accum_update(usize, true, NULL)) {
+			/*
+			 * Don't sample.  The usize passed to
+			 * PROF_ALLOC_PREP() was larger than what
+			 * actually got allocated, so a backtrace was
+			 * captured for this allocation, even though
+			 * its actual usize was insufficient to cross
+			 * the sample threshold.
+			 */
+			cnt = (prof_thr_cnt_t *)(uintptr_t)1U;
 		}
 	}
 
@@ -539,10 +451,10 @@ prof_realloc(const void *ptr, size_t usize, prof_thr_cnt_t *cnt,
 	if ((uintptr_t)told_cnt > (uintptr_t)1U)
 		told_cnt->epoch++;
 	if ((uintptr_t)cnt > (uintptr_t)1U) {
-		prof_ctx_set(ptr, usize, cnt->ctx);
+		prof_ctx_set(ptr, cnt->ctx);
 		cnt->epoch++;
 	} else if (ptr != NULL)
-		prof_ctx_set(ptr, usize, (prof_ctx_t *)(uintptr_t)1U);
+		prof_ctx_set(ptr, (prof_ctx_t *)(uintptr_t)1U);
 	/*********/
 	mb_write();
 	/*********/
diff --git a/src/jemalloc/include/jemalloc/internal/rtree.h b/src/jemalloc/include/jemalloc/internal/rtree.h
index bc74769f50ed68588850c36366b9ec7df9896f8d..3a1d62667fe8c38e31f4763160ae5a07913c8415 100644
--- a/src/jemalloc/include/jemalloc/internal/rtree.h
+++ b/src/jemalloc/include/jemalloc/internal/rtree.h
@@ -16,8 +16,8 @@ typedef struct rtree_s rtree_t;
  */
 #define	RTREE_NODESIZE (1U << 16)
 
-typedef void *(rtree_alloc_t)(size_t);
-typedef void (rtree_dalloc_t)(void *);
+typedef void *(rtree_alloc_t)(pool_t *, size_t);
+typedef void (rtree_dalloc_t)(pool_t *, void *);
 
 #endif /* JEMALLOC_H_TYPES */
 /******************************************************************************/
@@ -26,6 +26,7 @@ typedef void (rtree_dalloc_t)(void *);
 struct rtree_s {
 	rtree_alloc_t	*alloc;
 	rtree_dalloc_t	*dalloc;
+	pool_t          *pool;
 	malloc_mutex_t	mutex;
 	void		**root;
 	unsigned	height;
@@ -36,7 +37,8 @@ struct rtree_s {
 /******************************************************************************/
 #ifdef JEMALLOC_H_EXTERNS
 
-rtree_t	*rtree_new(unsigned bits, rtree_alloc_t *alloc, rtree_dalloc_t *dalloc);
+rtree_t	*rtree_new(unsigned bits, rtree_alloc_t *alloc, rtree_dalloc_t *dalloc,
+	pool_t *pool);
 void	rtree_delete(rtree_t *rtree);
 void	rtree_prefork(rtree_t *rtree);
 void	rtree_postfork_parent(rtree_t *rtree);
@@ -145,7 +147,7 @@ rtree_set(rtree_t *rtree, uintptr_t key, uint8_t val)
 		if (child == NULL) {
 			size_t size = ((i + 1 < height - 1) ? sizeof(void *)
 			    : (sizeof(uint8_t))) << rtree->level2bits[i+1];
-			child = (void**)rtree->alloc(size);
+			child = (void**)rtree->alloc(rtree->pool, size);
 			if (child == NULL) {
 				malloc_mutex_unlock(&rtree->mutex);
 				return (true);
diff --git a/src/jemalloc/include/jemalloc/internal/size_classes.sh b/src/jemalloc/include/jemalloc/internal/size_classes.sh
index 29c80c1fb8d1bdfd7ebe880043a2d06aa367f4d4..3edebf2387cd75aa65bf860f306cbb0d8e0d29ac 100755
--- a/src/jemalloc/include/jemalloc/internal/size_classes.sh
+++ b/src/jemalloc/include/jemalloc/internal/size_classes.sh
@@ -2,16 +2,23 @@
 
 # The following limits are chosen such that they cover all supported platforms.
 
-# Range of quanta.
-lg_qmin=3
-lg_qmax=4
+# Pointer sizes.
+lg_zarr="2 3"
+
+# Quanta.
+lg_qarr="3 4"
 
 # The range of tiny size classes is [2^lg_tmin..2^(lg_q-1)].
 lg_tmin=3
 
-# Range of page sizes.
-lg_pmin=12
-lg_pmax=16
+# Maximum lookup size.
+lg_kmax=12
+
+# Page sizes.
+lg_parr="12 13 16"
+
+# Size class group size (number of size classes for each size doubling).
+lg_g=2
 
 pow2() {
   e=$1
@@ -22,68 +29,206 @@ pow2() {
   done
 }
 
+lg() {
+  x=$1
+  lg_result=0
+  while [ ${x} -gt 1 ] ; do
+    lg_result=$((${lg_result} + 1))
+    x=$((${x} / 2))
+  done
+}
+
+size_class() {
+  index=$1
+  lg_grp=$2
+  lg_delta=$3
+  ndelta=$4
+  lg_p=$5
+  lg_kmax=$6
+
+  lg ${ndelta}; lg_ndelta=${lg_result}; pow2 ${lg_ndelta}
+  if [ ${pow2_result} -lt ${ndelta} ] ; then
+    rem="yes"
+  else
+    rem="no"
+  fi
+
+  lg_size=${lg_grp}
+  if [ $((${lg_delta} + ${lg_ndelta})) -eq ${lg_grp} ] ; then
+    lg_size=$((${lg_grp} + 1))
+  else
+    lg_size=${lg_grp}
+    rem="yes"
+  fi
+
+  if [ ${lg_size} -lt ${lg_p} ] ; then
+    bin="yes"
+  else
+    bin="no"
+  fi
+  if [ ${lg_size} -lt ${lg_kmax} \
+      -o ${lg_size} -eq ${lg_kmax} -a ${rem} = "no" ] ; then
+    lg_delta_lookup=${lg_delta}
+  else
+    lg_delta_lookup="no"
+  fi
+  printf '    SC(%3d, %6d, %8d, %6d, %3s, %2s) \\\n' ${index} ${lg_grp} ${lg_delta} ${ndelta} ${bin} ${lg_delta_lookup}
+  # Defined upon return:
+  # - lg_delta_lookup (${lg_delta} or "no")
+  # - bin ("yes" or "no")
+}
+
+sep_line() {
+  echo "                                               \\"
+}
+
+size_classes() {
+  lg_z=$1
+  lg_q=$2
+  lg_t=$3
+  lg_p=$4
+  lg_g=$5
+
+  pow2 $((${lg_z} + 3)); ptr_bits=${pow2_result}
+  pow2 ${lg_g}; g=${pow2_result}
+
+  echo "#define	SIZE_CLASSES \\"
+  echo "  /* index, lg_grp, lg_delta, ndelta, bin, lg_delta_lookup */ \\"
+
+  ntbins=0
+  nlbins=0
+  lg_tiny_maxclass='"NA"'
+  nbins=0
+
+  # Tiny size classes.
+  ndelta=0
+  index=0
+  lg_grp=${lg_t}
+  lg_delta=${lg_grp}
+  while [ ${lg_grp} -lt ${lg_q} ] ; do
+    size_class ${index} ${lg_grp} ${lg_delta} ${ndelta} ${lg_p} ${lg_kmax}
+    if [ ${lg_delta_lookup} != "no" ] ; then
+      nlbins=$((${index} + 1))
+    fi
+    if [ ${bin} != "no" ] ; then
+      nbins=$((${index} + 1))
+    fi
+    ntbins=$((${ntbins} + 1))
+    lg_tiny_maxclass=${lg_grp} # Final written value is correct.
+    index=$((${index} + 1))
+    lg_delta=${lg_grp}
+    lg_grp=$((${lg_grp} + 1))
+  done
+
+  # First non-tiny group.
+  if [ ${ntbins} -gt 0 ] ; then
+    sep_line
+    # The first size class has an unusual encoding, because the size has to be
+    # split between grp and delta*ndelta.
+    lg_grp=$((${lg_grp} - 1))
+    ndelta=1
+    size_class ${index} ${lg_grp} ${lg_delta} ${ndelta} ${lg_p} ${lg_kmax}
+    index=$((${index} + 1))
+    lg_grp=$((${lg_grp} + 1))
+    lg_delta=$((${lg_delta} + 1))
+  fi
+  while [ ${ndelta} -lt ${g} ] ; do
+    size_class ${index} ${lg_grp} ${lg_delta} ${ndelta} ${lg_p} ${lg_kmax}
+    index=$((${index} + 1))
+    ndelta=$((${ndelta} + 1))
+  done
+
+  # All remaining groups.
+  lg_grp=$((${lg_grp} + ${lg_g}))
+  while [ ${lg_grp} -lt ${ptr_bits} ] ; do
+    sep_line
+    ndelta=1
+    if [ ${lg_grp} -eq $((${ptr_bits} - 1)) ] ; then
+      ndelta_limit=$((${g} - 1))
+    else
+      ndelta_limit=${g}
+    fi
+    while [ ${ndelta} -le ${ndelta_limit} ] ; do
+      size_class ${index} ${lg_grp} ${lg_delta} ${ndelta} ${lg_p} ${lg_kmax}
+      if [ ${lg_delta_lookup} != "no" ] ; then
+        nlbins=$((${index} + 1))
+        # Final written value is correct:
+        lookup_maxclass="((((size_t)1) << ${lg_grp}) + (((size_t)${ndelta}) << ${lg_delta}))"
+      fi
+      if [ ${bin} != "no" ] ; then
+        nbins=$((${index} + 1))
+        # Final written value is correct:
+        small_maxclass="((((size_t)1) << ${lg_grp}) + (((size_t)${ndelta}) << ${lg_delta}))"
+      fi
+      index=$((${index} + 1))
+      ndelta=$((${ndelta} + 1))
+    done
+    lg_grp=$((${lg_grp} + 1))
+    lg_delta=$((${lg_delta} + 1))
+  done
+  echo
+
+  # Defined upon completion:
+  # - ntbins
+  # - nlbins
+  # - nbins
+  # - lg_tiny_maxclass
+  # - lookup_maxclass
+  # - small_maxclass
+}
+
 cat <<EOF
 /* This file was automatically generated by size_classes.sh. */
 /******************************************************************************/
 #ifdef JEMALLOC_H_TYPES
 
+/*
+ * This header requires LG_SIZEOF_PTR, LG_TINY_MIN, LG_QUANTUM, and LG_PAGE to
+ * be defined prior to inclusion, and it in turn defines:
+ *
+ *   LG_SIZE_CLASS_GROUP: Lg of size class count for each size doubling.
+ *   SIZE_CLASSES: Complete table of
+ *                 SC(index, lg_delta, size, bin, lg_delta_lookup) tuples.
+ *     index: Size class index.
+ *     lg_grp: Lg group base size (no deltas added).
+ *     lg_delta: Lg delta to previous size class.
+ *     ndelta: Delta multiplier.  size == 1<<lg_grp + ndelta<<lg_delta
+ *     bin: 'yes' if a small bin size class, 'no' otherwise.
+ *     lg_delta_lookup: Same as lg_delta if a lookup table size class, 'no'
+ *                      otherwise.
+ *   NTBINS: Number of tiny bins.
+ *   NLBINS: Number of bins supported by the lookup table.
+ *   NBINS: Number of small size class bins.
+ *   LG_TINY_MAXCLASS: Lg of maximum tiny size class.
+ *   LOOKUP_MAXCLASS: Maximum size class included in lookup table.
+ *   SMALL_MAXCLASS: Maximum small size class.
+ */
+
+#define	LG_SIZE_CLASS_GROUP	${lg_g}
+
 EOF
 
-lg_q=${lg_qmin}
-while [ ${lg_q} -le ${lg_qmax} ] ; do
-  lg_t=${lg_tmin}
-  while [ ${lg_t} -le ${lg_q} ] ; do
-    lg_p=${lg_pmin}
-    while [ ${lg_p} -le ${lg_pmax} ] ; do
-      echo "#if (LG_TINY_MIN == ${lg_t} && LG_QUANTUM == ${lg_q} && LG_PAGE == ${lg_p})"
-      echo "#define	SIZE_CLASSES_DEFINED"
-      pow2 ${lg_q}; q=${pow2_result}
-      pow2 ${lg_t}; t=${pow2_result}
-      pow2 ${lg_p}; p=${pow2_result}
-      bin=0
-      psz=0
-      sz=${t}
-      delta=$((${sz} - ${psz}))
-      echo "/*  SIZE_CLASS(bin,	delta,	sz) */"
-      echo "#define	SIZE_CLASSES							\\"
-
-      # Tiny size classes.
-      while [ ${sz} -lt ${q} ] ; do
-        echo "    SIZE_CLASS(${bin},	${delta},	${sz})					\\"
-        bin=$((${bin} + 1))
-        psz=${sz}
-        sz=$((${sz} + ${sz}))
-        delta=$((${sz} - ${psz}))
-      done
-      # Quantum-multiple size classes.  For each doubling of sz, as many as 4
-      # size classes exist.  Their spacing is the greater of:
-      # - q
-      # - sz/4, where sz is a power of 2
-      while [ ${sz} -lt ${p} ] ; do
-        if [ ${sz} -ge $((${q} * 4)) ] ; then
-          i=$((${sz} / 4))
-        else
-          i=${q}
-        fi
-        next_2pow=$((${sz} * 2))
-        while [ ${sz} -lt $next_2pow ] ; do
-          echo "    SIZE_CLASS(${bin},	${delta},	${sz})					\\"
-          bin=$((${bin} + 1))
-          psz=${sz}
-          sz=$((${sz} + ${i}))
-          delta=$((${sz} - ${psz}))
-        done
+for lg_z in ${lg_zarr} ; do
+  for lg_q in ${lg_qarr} ; do
+    lg_t=${lg_tmin}
+    while [ ${lg_t} -le ${lg_q} ] ; do
+      # Iterate through page sizes and compute how many bins there are.
+      for lg_p in ${lg_parr} ; do
+        echo "#if (LG_SIZEOF_PTR == ${lg_z} && LG_TINY_MIN == ${lg_t} && LG_QUANTUM == ${lg_q} && LG_PAGE == ${lg_p})"
+        size_classes ${lg_z} ${lg_q} ${lg_t} ${lg_p} ${lg_g}
+        echo "#define	SIZE_CLASSES_DEFINED"
+        echo "#define	NTBINS			${ntbins}"
+        echo "#define	NLBINS			${nlbins}"
+        echo "#define	NBINS			${nbins}"
+        echo "#define	LG_TINY_MAXCLASS	${lg_tiny_maxclass}"
+        echo "#define	LOOKUP_MAXCLASS		${lookup_maxclass}"
+        echo "#define	SMALL_MAXCLASS		${small_maxclass}"
+        echo "#endif"
+        echo
       done
-      echo
-      echo "#define	NBINS		${bin}"
-      echo "#define	SMALL_MAXCLASS	${psz}"
-      echo "#endif"
-      echo
-      lg_p=$((${lg_p} + 1))
+      lg_t=$((${lg_t} + 1))
     done
-    lg_t=$((${lg_t} + 1))
   done
-  lg_q=$((${lg_q} + 1))
 done
 
 cat <<EOF
@@ -94,9 +239,8 @@ cat <<EOF
 /*
  * The small_size2bin lookup table uses uint8_t to encode each bin index, so we
  * cannot support more than 256 small size classes.  Further constrain NBINS to
- * 255 to support prof_promote, since all small size classes, plus a "not
- * small" size class must be stored in 8 bits of arena_chunk_map_t's bits
- * field.
+ * 255 since all small size classes, plus a "not small" size class must be
+ * stored in 8 bits of arena_chunk_map_t's bits field.
  */
 #if (NBINS > 255)
 #  error "Too many small size classes"
diff --git a/src/jemalloc/include/jemalloc/internal/stats.h b/src/jemalloc/include/jemalloc/internal/stats.h
index 27f68e3681cfa7480612b871a083b3ca8b126e6e..5540d84059eb80e541574e80ccb9b654ee2bb4ed 100644
--- a/src/jemalloc/include/jemalloc/internal/stats.h
+++ b/src/jemalloc/include/jemalloc/internal/stats.h
@@ -101,6 +101,11 @@ struct arena_stats_s {
 	uint64_t	ndalloc_large;
 	uint64_t	nrequests_large;
 
+	size_t		allocated_huge;
+	uint64_t	nmalloc_huge;
+	uint64_t	ndalloc_huge;
+	uint64_t	nrequests_huge;
+
 	/*
 	 * One element for each possible size class, including sizes that
 	 * overlap with bin size classes.  This is necessary because ipalloc()
@@ -131,9 +136,7 @@ struct chunk_stats_s {
 
 extern bool	opt_stats_print;
 
-extern size_t	stats_cactive;
-
-void	stats_print(void (*write)(void *, const char *), void *cbopaque,
+void	stats_print(pool_t *pool, void (*write)(void *, const char *), void *cbopaque,
     const char *opts);
 
 #endif /* JEMALLOC_H_EXTERNS */
@@ -141,31 +144,31 @@ void	stats_print(void (*write)(void *, const char *), void *cbopaque,
 #ifdef JEMALLOC_H_INLINES
 
 #ifndef JEMALLOC_ENABLE_INLINE
-size_t	stats_cactive_get(void);
-void	stats_cactive_add(size_t size);
-void	stats_cactive_sub(size_t size);
+size_t	stats_cactive_get(pool_t *pool);
+void	stats_cactive_add(pool_t *pool, size_t size);
+void	stats_cactive_sub(pool_t *pool, size_t size);
 #endif
 
 #if (defined(JEMALLOC_ENABLE_INLINE) || defined(JEMALLOC_STATS_C_))
 JEMALLOC_INLINE size_t
-stats_cactive_get(void)
+stats_cactive_get(pool_t *pool)
 {
 
-	return (atomic_read_z(&stats_cactive));
+	return (atomic_read_z(&(pool->stats_cactive)));
 }
 
 JEMALLOC_INLINE void
-stats_cactive_add(size_t size)
+stats_cactive_add(pool_t *pool, size_t size)
 {
 
-	atomic_add_z(&stats_cactive, size);
+	atomic_add_z(&(pool->stats_cactive), size);
 }
 
 JEMALLOC_INLINE void
-stats_cactive_sub(size_t size)
+stats_cactive_sub(pool_t *pool, size_t size)
 {
 
-	atomic_sub_z(&stats_cactive, size);
+	atomic_sub_z(&(pool->stats_cactive), size);
 }
 #endif
 
diff --git a/src/jemalloc/include/jemalloc/internal/tcache.h b/src/jemalloc/include/jemalloc/internal/tcache.h
index c3d4b58d4dc5ff572f4cad3245c2c3faf98f56a6..eaccd8e465f78ca479d48ed1c9290fe036cb002b 100644
--- a/src/jemalloc/include/jemalloc/internal/tcache.h
+++ b/src/jemalloc/include/jemalloc/internal/tcache.h
@@ -4,6 +4,7 @@
 typedef struct tcache_bin_info_s tcache_bin_info_t;
 typedef struct tcache_bin_s tcache_bin_t;
 typedef struct tcache_s tcache_t;
+typedef struct tsd_tcache_s tsd_tcache_t;
 
 /*
  * tcache pointers close to NULL are used to encode state information that is
@@ -41,6 +42,8 @@ typedef struct tcache_s tcache_t;
 #define	TCACHE_GC_INCR							\
     ((TCACHE_GC_SWEEP / NBINS) + ((TCACHE_GC_SWEEP / NBINS == 0) ? 0 : 1))
 
+#define	TSD_TCACHE_INITIALIZER	JEMALLOC_ARG_CONCAT({.tcaches = {0}})
+
 #endif /* JEMALLOC_H_TYPES */
 /******************************************************************************/
 #ifdef JEMALLOC_H_STRUCTS
@@ -82,6 +85,11 @@ struct tcache_s {
 	 */
 };
 
+struct tsd_tcache_s {
+	unsigned seqno[POOLS_MAX]; /* Sequence number of pool */
+	tcache_t* tcaches[POOLS_MAX];
+};
+
 #endif /* JEMALLOC_H_STRUCTS */
 /******************************************************************************/
 #ifdef JEMALLOC_H_EXTERNS
@@ -110,6 +118,7 @@ void	tcache_bin_flush_large(tcache_bin_t *tbin, size_t binind, unsigned rem,
     tcache_t *tcache);
 void	tcache_arena_associate(tcache_t *tcache, arena_t *arena);
 void	tcache_arena_dissociate(tcache_t *tcache);
+tcache_t *tcache_get_hard(tcache_t *tcache, pool_t *pool, bool create);
 tcache_t *tcache_create(arena_t *arena);
 void	tcache_destroy(tcache_t *tcache);
 void	tcache_thread_cleanup(void *arg);
@@ -122,13 +131,13 @@ bool	tcache_boot1(void);
 #ifdef JEMALLOC_H_INLINES
 
 #ifndef JEMALLOC_ENABLE_INLINE
-malloc_tsd_protos(JEMALLOC_ATTR(unused), tcache, tcache_t *)
+malloc_tsd_protos(JEMALLOC_ATTR(unused), tcache, tsd_tcache_t)
 malloc_tsd_protos(JEMALLOC_ATTR(unused), tcache_enabled, tcache_enabled_t)
 
 void	tcache_event(tcache_t *tcache);
-void	tcache_flush(void);
+void	tcache_flush(pool_t *pool);
 bool	tcache_enabled_get(void);
-tcache_t *tcache_get(bool create);
+tcache_t *tcache_get(pool_t *pool, bool create);
 void	tcache_enabled_set(bool enabled);
 void	*tcache_alloc_easy(tcache_bin_t *tbin);
 void	*tcache_alloc_small(tcache_t *tcache, size_t size, bool zero);
@@ -139,8 +148,8 @@ void	tcache_dalloc_large(tcache_t *tcache, void *ptr, size_t size);
 
 #if (defined(JEMALLOC_ENABLE_INLINE) || defined(JEMALLOC_TCACHE_C_))
 /* Map of thread-specific caches. */
-malloc_tsd_externs(tcache, tcache_t *)
-malloc_tsd_funcs(JEMALLOC_ALWAYS_INLINE, tcache, tcache_t *, NULL,
+malloc_tsd_externs(tcache, tsd_tcache_t)
+malloc_tsd_funcs(JEMALLOC_ALWAYS_INLINE, tcache, tsd_tcache_t, NULL,
     tcache_thread_cleanup)
 /* Per thread flag that allows thread caches to be disabled. */
 malloc_tsd_externs(tcache_enabled, tcache_enabled_t)
@@ -148,18 +157,20 @@ malloc_tsd_funcs(JEMALLOC_ALWAYS_INLINE, tcache_enabled, tcache_enabled_t,
     tcache_enabled_default, malloc_tsd_no_cleanup)
 
 JEMALLOC_INLINE void
-tcache_flush(void)
+tcache_flush(pool_t *pool)
 {
-	tcache_t *tcache;
+	tsd_tcache_t *tsd = tcache_tsd_get();
 
-	cassert(config_tcache);
+	tcache_t *tcache = tsd->tcaches[pool->pool_id];
 
-	tcache = *tcache_tsd_get();
-	if ((uintptr_t)tcache <= (uintptr_t)TCACHE_STATE_MAX)
-		return;
-	tcache_destroy(tcache);
-	tcache = NULL;
-	tcache_tsd_set(&tcache);
+	if (tsd->seqno[pool->pool_id] == pool->seqno) {
+		cassert(config_tcache);
+
+		if ((uintptr_t)tcache <= (uintptr_t)TCACHE_STATE_MAX)
+			return;
+		tcache_destroy(tcache);
+	}
+	tsd->tcaches[pool->pool_id] = NULL;
 }
 
 JEMALLOC_INLINE bool
@@ -182,77 +193,66 @@ JEMALLOC_INLINE void
 tcache_enabled_set(bool enabled)
 {
 	tcache_enabled_t tcache_enabled;
+	tsd_tcache_t *tsd;
 	tcache_t *tcache;
+	int i;
 
 	cassert(config_tcache);
 
 	tcache_enabled = (tcache_enabled_t)enabled;
 	tcache_enabled_tsd_set(&tcache_enabled);
-	tcache = *tcache_tsd_get();
-	if (enabled) {
-		if (tcache == TCACHE_STATE_DISABLED) {
-			tcache = NULL;
-			tcache_tsd_set(&tcache);
-		}
-	} else /* disabled */ {
-		if (tcache > TCACHE_STATE_MAX) {
-			tcache_destroy(tcache);
-			tcache = NULL;
-		}
-		if (tcache == NULL) {
-			tcache = TCACHE_STATE_DISABLED;
-			tcache_tsd_set(&tcache);
+	tsd = tcache_tsd_get();
+
+	malloc_mutex_lock(&pools_lock);
+	for (i = 0; i < POOLS_MAX; i++) {
+		tcache = tsd->tcaches[i];
+		if (tcache != NULL) {
+			if (enabled) {
+				if (tcache == TCACHE_STATE_DISABLED) {
+					tsd->tcaches[i] = NULL;
+				}
+			} else /* disabled */ {
+				if (tcache > TCACHE_STATE_MAX) {
+					if (pools[i] != NULL && tsd->seqno[i] == pools[i]->seqno)
+						tcache_destroy(tcache);
+
+					tcache = NULL;
+				}
+				if (tcache == NULL) {
+					tsd->tcaches[i] = TCACHE_STATE_DISABLED;
+				}
+			}
 		}
 	}
+	malloc_mutex_unlock(&pools_lock);
 }
 
 JEMALLOC_ALWAYS_INLINE tcache_t *
-tcache_get(bool create)
+tcache_get(pool_t *pool, bool create)
 {
 	tcache_t *tcache;
+	tsd_tcache_t *tsd;
 
 	if (config_tcache == false)
 		return (NULL);
 	if (config_lazy_lock && isthreaded == false)
 		return (NULL);
 
-	tcache = *tcache_tsd_get();
+	tsd = tcache_tsd_get();
+
+	/*
+	 * All subsequent pools with the same id have to cleanup tcache before
+	 * calling tcache_get_hard.
+	 */
+	if (tsd->seqno[pool->pool_id] != pool->seqno) {
+		tsd->tcaches[pool->pool_id] = NULL;
+	}
+
+	tcache = tsd->tcaches[pool->pool_id];
 	if ((uintptr_t)tcache <= (uintptr_t)TCACHE_STATE_MAX) {
 		if (tcache == TCACHE_STATE_DISABLED)
 			return (NULL);
-		if (tcache == NULL) {
-			if (create == false) {
-				/*
-				 * Creating a tcache here would cause
-				 * allocation as a side effect of free().
-				 * Ordinarily that would be okay since
-				 * tcache_create() failure is a soft failure
-				 * that doesn't propagate.  However, if TLS
-				 * data are freed via free() as in glibc,
-				 * subtle corruption could result from setting
-				 * a TLS variable after its backing memory is
-				 * freed.
-				 */
-				return (NULL);
-			}
-			if (tcache_enabled_get() == false) {
-				tcache_enabled_set(false); /* Memoize. */
-				return (NULL);
-			}
-			return (tcache_create(choose_arena(NULL)));
-		}
-		if (tcache == TCACHE_STATE_PURGATORY) {
-			/*
-			 * Make a note that an allocator function was called
-			 * after tcache_thread_cleanup() was called.
-			 */
-			tcache = TCACHE_STATE_REINCARNATED;
-			tcache_tsd_set(&tcache);
-			return (NULL);
-		}
-		if (tcache == TCACHE_STATE_REINCARNATED)
-			return (NULL);
-		not_reached();
+		tcache = tcache_get_hard(tcache, pool, create);
 	}
 
 	return (tcache);
@@ -294,17 +294,17 @@ tcache_alloc_small(tcache_t *tcache, size_t size, bool zero)
 	size_t binind;
 	tcache_bin_t *tbin;
 
-	binind = SMALL_SIZE2BIN(size);
+	binind = small_size2bin(size);
 	assert(binind < NBINS);
 	tbin = &tcache->tbins[binind];
-	size = arena_bin_info[binind].reg_size;
+	size = small_bin2size(binind);
 	ret = tcache_alloc_easy(tbin);
 	if (ret == NULL) {
 		ret = tcache_alloc_small_hard(tcache, tbin, binind);
 		if (ret == NULL)
 			return (NULL);
 	}
-	assert(tcache_salloc(ret) == arena_bin_info[binind].reg_size);
+	assert(tcache_salloc(ret) == size);
 
 	if (zero == false) {
 		if (config_fill) {
@@ -314,20 +314,18 @@ tcache_alloc_small(tcache_t *tcache, size_t size, bool zero)
 			} else if (opt_zero)
 				memset(ret, 0, size);
 		}
-		VALGRIND_MAKE_MEM_UNDEFINED(ret, size);
 	} else {
 		if (config_fill && opt_junk) {
 			arena_alloc_junk_small(ret, &arena_bin_info[binind],
 			    true);
 		}
-		VALGRIND_MAKE_MEM_UNDEFINED(ret, size);
 		memset(ret, 0, size);
 	}
 
 	if (config_stats)
 		tbin->tstats.nrequests++;
 	if (config_prof)
-		tcache->prof_accumbytes += arena_bin_info[binind].reg_size;
+		tcache->prof_accumbytes += size;
 	tcache_event(tcache);
 	return (ret);
 }
@@ -354,7 +352,7 @@ tcache_alloc_large(tcache_t *tcache, size_t size, bool zero)
 		if (ret == NULL)
 			return (NULL);
 	} else {
-		if (config_prof && prof_promote && size == PAGE) {
+		if (config_prof && size == PAGE) {
 			arena_chunk_t *chunk =
 			    (arena_chunk_t *)CHUNK_ADDR2BASE(ret);
 			size_t pageind = (((uintptr_t)ret - (uintptr_t)chunk) >>
@@ -369,11 +367,8 @@ tcache_alloc_large(tcache_t *tcache, size_t size, bool zero)
 				else if (opt_zero)
 					memset(ret, 0, size);
 			}
-			VALGRIND_MAKE_MEM_UNDEFINED(ret, size);
-		} else {
-			VALGRIND_MAKE_MEM_UNDEFINED(ret, size);
+		} else
 			memset(ret, 0, size);
-		}
 
 		if (config_stats)
 			tbin->tstats.nrequests++;
diff --git a/src/jemalloc/include/jemalloc/internal/tsd.h b/src/jemalloc/include/jemalloc/internal/tsd.h
index 9fb4a23ec6bfcaa951a112c336d876e1ad25d980..11d99f08878de8c3246c3a6465151936474df076 100644
--- a/src/jemalloc/include/jemalloc/internal/tsd.h
+++ b/src/jemalloc/include/jemalloc/internal/tsd.h
@@ -393,6 +393,42 @@ a_name##_tsd_set(a_type *val)						\
 }
 #endif
 
+
+
+/*
+ * Vector data container implemented as TSD/TLS macros.
+ * These functions behave exactly like the regular version,
+ * except for the fact that they take an index argument in accessor functions.
+ */
+
+/* malloc_tsd_vector_protos(). */
+#define	malloc_tsd_vector_protos(a_attr, a_name)			\
+malloc_tsd_protos(a_attr, a_name, vector_t)
+
+#define	malloc_tsd_vector_externs(a_name)				\
+malloc_tsd_externs(a_name, vector_t)
+
+#define	malloc_tsd_vector_data(a_attr, a_name)				\
+malloc_tsd_data(a_attr, a_name, vector_t, VECTOR_INITIALIZER)
+
+#define	malloc_tsd_vector_funcs(a_attr, a_name, a_type, a_cleanup)	\
+malloc_tsd_funcs(a_attr, a_name, vector_t, VECTOR_INITIALIZER,		\
+	a_cleanup)							\
+									\
+a_attr a_type *								\
+a_name##_vec_tsd_get(uint32_t index)					\
+{									\
+	vector_t *v = a_name##_tsd_get();				\
+	return (a_type *)vec_get(v, index);				\
+}									\
+									\
+a_attr void								\
+a_name##_vec_tsd_set(uint32_t index, a_type *val)			\
+{									\
+	vector_t *v = a_name##_tsd_get();				\
+	vec_set(v, index, (void *)val);					\
+}									\
+
 #endif /* JEMALLOC_H_TYPES */
 /******************************************************************************/
 #ifdef JEMALLOC_H_STRUCTS
diff --git a/src/jemalloc/include/jemalloc/internal/util.h b/src/jemalloc/include/jemalloc/internal/util.h
index 6b938f746889bc3350b8996077946451222b8fa5..d2b7a9678ff807763173cd3f0afdfbc81f436b15 100644
--- a/src/jemalloc/include/jemalloc/internal/util.h
+++ b/src/jemalloc/include/jemalloc/internal/util.h
@@ -109,12 +109,35 @@ void	malloc_printf(const char *format, ...)
 #ifdef JEMALLOC_H_INLINES
 
 #ifndef JEMALLOC_ENABLE_INLINE
+int	jemalloc_ffsl(long bitmap);
+int	jemalloc_ffs(int bitmap);
 size_t	pow2_ceil(size_t x);
+size_t	lg_floor(size_t x);
 void	set_errno(int errnum);
 int	get_errno(void);
 #endif
 
 #if (defined(JEMALLOC_ENABLE_INLINE) || defined(JEMALLOC_UTIL_C_))
+
+/* Sanity check: */
+#if !defined(JEMALLOC_INTERNAL_FFSL) || !defined(JEMALLOC_INTERNAL_FFS)
+#  error Both JEMALLOC_INTERNAL_FFSL && JEMALLOC_INTERNAL_FFS should have been defined by configure
+#endif
+
+JEMALLOC_ALWAYS_INLINE int
+jemalloc_ffsl(long bitmap)
+{
+
+        return (JEMALLOC_INTERNAL_FFSL(bitmap));
+}
+
+JEMALLOC_ALWAYS_INLINE int
+jemalloc_ffs(int bitmap)
+{
+
+        return (JEMALLOC_INTERNAL_FFS(bitmap));
+}
+
 /* Compute the smallest power of 2 that is >= x. */
 JEMALLOC_INLINE size_t
 pow2_ceil(size_t x)
@@ -133,6 +156,58 @@ pow2_ceil(size_t x)
 	return (x);
 }
 
+#if (defined(__i386__) || defined(__amd64__) || defined(__x86_64__))
+JEMALLOC_INLINE size_t
+lg_floor(size_t x)
+{
+	size_t ret;
+
+	asm ("bsr %1, %0"
+	    : "=r"(ret) // Outputs.
+	    : "r"(x)    // Inputs.
+	    );
+	return (ret);
+}
+#elif (defined(JEMALLOC_HAVE_BUILTIN_CLZ))
+JEMALLOC_INLINE size_t
+lg_floor(size_t x)
+{
+
+#if (LG_SIZEOF_PTR == LG_SIZEOF_INT)
+	return (((8 << LG_SIZEOF_PTR) - 1) - __builtin_clz(x));
+#elif (LG_SIZEOF_PTR == LG_SIZEOF_LONG)
+	return (((8 << LG_SIZEOF_PTR) - 1) - __builtin_clzl(x));
+#else
+#  error "Unsupported type sizes for lg_floor()"
+#endif
+}
+#else
+JEMALLOC_INLINE size_t
+lg_floor(size_t x)
+{
+
+	x |= (x >> 1);
+	x |= (x >> 2);
+	x |= (x >> 4);
+	x |= (x >> 8);
+	x |= (x >> 16);
+#if (LG_SIZEOF_PTR == 3 && LG_SIZEOF_PTR == LG_SIZEOF_LONG)
+	x |= (x >> 32);
+	if (x == KZU(0xffffffffffffffff))
+		return (63);
+	x++;
+	return (jemalloc_ffsl(x) - 2);
+#elif (LG_SIZEOF_PTR == 2)
+	if (x == KZU(0xffffffff))
+		return (31);
+	x++;
+	return (jemalloc_ffs(x) - 2);
+#else
+#  error "Unsupported type sizes for lg_floor()"
+#endif
+}
+#endif
+
 /* Sets error code */
 JEMALLOC_INLINE void
 set_errno(int errnum)
diff --git a/src/jemalloc/include/jemalloc/internal/valgrind.h b/src/jemalloc/include/jemalloc/internal/valgrind.h
new file mode 100644
index 0000000000000000000000000000000000000000..52c93f2999222f6dc93cd2dad91c3d9e9add69a2
--- /dev/null
+++ b/src/jemalloc/include/jemalloc/internal/valgrind.h
@@ -0,0 +1,112 @@
+/******************************************************************************/
+#ifdef JEMALLOC_H_TYPES
+
+#ifdef JEMALLOC_VALGRIND
+#include <valgrind/valgrind.h>
+
+/*
+ * The size that is reported to Valgrind must be consistent through a chain of
+ * malloc..realloc..realloc calls.  Request size isn't recorded anywhere in
+ * jemalloc, so it is critical that all callers of these macros provide usize
+ * rather than request size.  As a result, buffer overflow detection is
+ * technically weakened for the standard API, though it is generally accepted
+ * practice to consider any extra bytes reported by malloc_usable_size() as
+ * usable space.
+ */
+#define	JEMALLOC_VALGRIND_MAKE_MEM_NOACCESS(ptr, usize) do {		\
+	if (in_valgrind)						\
+		valgrind_make_mem_noaccess(ptr, usize);			\
+} while (0)
+#define	JEMALLOC_VALGRIND_MAKE_MEM_UNDEFINED(ptr, usize) do {		\
+	if (in_valgrind)						\
+		valgrind_make_mem_undefined(ptr, usize);		\
+} while (0)
+#define	JEMALLOC_VALGRIND_MAKE_MEM_DEFINED(ptr, usize) do {		\
+	if (in_valgrind)						\
+		valgrind_make_mem_defined(ptr, usize);			\
+} while (0)
+/*
+ * The VALGRIND_MALLOCLIKE_BLOCK() and VALGRIND_RESIZEINPLACE_BLOCK() macro
+ * calls must be embedded in macros rather than in functions so that when
+ * Valgrind reports errors, there are no extra stack frames in the backtraces.
+ */
+#define	JEMALLOC_VALGRIND_MALLOC(cond, ptr, usize, zero) do {		\
+	if (in_valgrind && cond)					\
+		VALGRIND_MALLOCLIKE_BLOCK(ptr, usize, p2rz(ptr), zero);	\
+} while (0)
+#define	JEMALLOC_VALGRIND_REALLOC(maybe_moved, ptr, usize,		\
+    ptr_maybe_null, old_ptr, old_usize, old_rzsize, old_ptr_maybe_null,	\
+    zero) do {								\
+	if (in_valgrind) {						\
+		size_t rzsize = p2rz(ptr);				\
+									\
+		if (!maybe_moved || ptr == old_ptr) {			\
+			VALGRIND_RESIZEINPLACE_BLOCK(ptr, old_usize,	\
+			    usize, rzsize);				\
+			if (zero && old_usize < usize) {		\
+				valgrind_make_mem_defined(		\
+				    (void *)((uintptr_t)ptr +		\
+				    old_usize), usize - old_usize);	\
+			}						\
+		} else {						\
+			if (!old_ptr_maybe_null || old_ptr != NULL) {	\
+				valgrind_freelike_block(old_ptr,	\
+				    old_rzsize);			\
+			}						\
+			if (!ptr_maybe_null || ptr != NULL) {		\
+				size_t copy_size = (old_usize < usize)	\
+				    ?  old_usize : usize;		\
+				size_t tail_size = usize - copy_size;	\
+				VALGRIND_MALLOCLIKE_BLOCK(ptr, usize,	\
+				    rzsize, false);			\
+				if (copy_size > 0) {			\
+					valgrind_make_mem_defined(ptr,	\
+					copy_size);			\
+				}					\
+				if (zero && tail_size > 0) {		\
+					valgrind_make_mem_defined(	\
+					    (void *)((uintptr_t)ptr +	\
+					    copy_size), tail_size);	\
+				}					\
+			}						\
+		}							\
+	}								\
+} while (0)
+#define	JEMALLOC_VALGRIND_FREE(ptr, rzsize) do {			\
+	if (in_valgrind)						\
+		valgrind_freelike_block(ptr, rzsize);			\
+} while (0)
+#else
+#define	RUNNING_ON_VALGRIND	((unsigned)0)
+#define	JEMALLOC_VALGRIND_MAKE_MEM_NOACCESS(ptr, usize) do {} while (0)
+#define	JEMALLOC_VALGRIND_MAKE_MEM_UNDEFINED(ptr, usize) do {} while (0)
+#define	JEMALLOC_VALGRIND_MAKE_MEM_DEFINED(ptr, usize) do {} while (0)
+#define	JEMALLOC_VALGRIND_MALLOC(cond, ptr, usize, zero) do {} while (0)
+#define	JEMALLOC_VALGRIND_REALLOC(maybe_moved, ptr, usize,		\
+    ptr_maybe_null, old_ptr, old_usize, old_rzsize, old_ptr_maybe_null,	\
+    zero) do {} while (0)
+#define	JEMALLOC_VALGRIND_FREE(ptr, rzsize) do {} while (0)
+#endif
+
+#endif /* JEMALLOC_H_TYPES */
+/******************************************************************************/
+#ifdef JEMALLOC_H_STRUCTS
+
+#endif /* JEMALLOC_H_STRUCTS */
+/******************************************************************************/
+#ifdef JEMALLOC_H_EXTERNS
+
+#ifdef JEMALLOC_VALGRIND
+void	valgrind_make_mem_noaccess(void *ptr, size_t usize);
+void	valgrind_make_mem_undefined(void *ptr, size_t usize);
+void	valgrind_make_mem_defined(void *ptr, size_t usize);
+void	valgrind_freelike_block(void *ptr, size_t usize);
+#endif
+
+#endif /* JEMALLOC_H_EXTERNS */
+/******************************************************************************/
+#ifdef JEMALLOC_H_INLINES
+
+#endif /* JEMALLOC_H_INLINES */
+/******************************************************************************/
+
diff --git a/src/jemalloc/include/jemalloc/internal/vector.h b/src/jemalloc/include/jemalloc/internal/vector.h
new file mode 100644
index 0000000000000000000000000000000000000000..8cbd747bdcf83a48a09df177f75141c92d258b63
--- /dev/null
+++ b/src/jemalloc/include/jemalloc/internal/vector.h
@@ -0,0 +1,38 @@
+/******************************************************************************/
+#ifdef JEMALLOC_H_TYPES
+
+typedef struct vector_s vector_t;
+typedef struct vec_list_s vec_list_t;
+
+#define VECTOR_MIN_PART_SIZE 8
+
+#define VECTOR_INITIALIZER	JEMALLOC_ARG_CONCAT({.data = NULL, .size = 0})
+
+#endif /* JEMALLOC_H_TYPES */
+/******************************************************************************/
+#ifdef JEMALLOC_H_STRUCTS
+
+struct vec_list_s {
+	vec_list_t *next;
+	int length;
+	void *data[];
+};
+
+struct vector_s {
+	vec_list_t *list;
+};
+
+#endif /* JEMALLOC_H_STRUCTS */
+/******************************************************************************/
+#ifdef JEMALLOC_H_EXTERNS
+
+void *vec_get(vector_t *vector, int index);
+void vec_set(vector_t *vector, int index, void *val);
+void vec_delete(vector_t *vector);
+
+#endif /* JEMALLOC_H_EXTERNS */
+/******************************************************************************/
+#ifdef JEMALLOC_H_INLINES
+
+#endif /* JEMALLOC_H_INLINES */
+/******************************************************************************/
diff --git a/src/jemalloc/include/jemalloc/jemalloc_defs.h.in b/src/jemalloc/include/jemalloc/jemalloc_defs.h.in
index eb38d7105ca54882fe3c9e30d8d9dac7873696b9..ce6c6987c5b07d4fbea4b3f62b4d8c5e31d78cf0 100644
--- a/src/jemalloc/include/jemalloc/jemalloc_defs.h.in
+++ b/src/jemalloc/include/jemalloc/jemalloc_defs.h.in
@@ -1,9 +1,6 @@
 /* Defined if __attribute__((...)) syntax is supported. */
 #undef JEMALLOC_HAVE_ATTR
 
-/* Support the experimental API. */
-#undef JEMALLOC_EXPERIMENTAL
-
 /*
  * Define overrides for non-standard allocator-related functions if they are
  * present on the system.
diff --git a/src/jemalloc/include/jemalloc/jemalloc_macros.h.in b/src/jemalloc/include/jemalloc/jemalloc_macros.h.in
index 13dbdd91209a46cf5a845a4182ec362557efa3c1..0f09bea1e7814bb0358cc0790d91f151d9601f7e 100644
--- a/src/jemalloc/include/jemalloc/jemalloc_macros.h.in
+++ b/src/jemalloc/include/jemalloc/jemalloc_macros.h.in
@@ -1,5 +1,6 @@
 #include <limits.h>
 #include <strings.h>
+#include <stdbool.h>
 
 #define	JEMALLOC_VERSION "@jemalloc_version@"
 #define	JEMALLOC_VERSION_MAJOR @jemalloc_version_major@
@@ -19,23 +20,6 @@
 /* Bias arena index bits so that 0 encodes "MALLOCX_ARENA() unspecified". */
 #  define MALLOCX_ARENA(a)	((int)(((a)+1) << 8))
 
-#ifdef JEMALLOC_EXPERIMENTAL
-#  define ALLOCM_LG_ALIGN(la)	(la)
-#  if LG_SIZEOF_PTR == 2
-#    define ALLOCM_ALIGN(a)	(ffs(a)-1)
-#  else
-#    define ALLOCM_ALIGN(a)						\
-	 ((a < (size_t)INT_MAX) ? ffs(a)-1 : ffs(a>>32)+31)
-#  endif
-#  define ALLOCM_ZERO	((int)0x40)
-#  define ALLOCM_NO_MOVE	((int)0x80)
-/* Bias arena index bits so that 0 encodes "ALLOCM_ARENA() unspecified". */
-#  define ALLOCM_ARENA(a)	((int)(((a)+1) << 8))
-#  define ALLOCM_SUCCESS	0
-#  define ALLOCM_ERR_OOM	1
-#  define ALLOCM_ERR_NOT_MOVED	2
-#endif
-
 #ifdef JEMALLOC_HAVE_ATTR
 #  define JEMALLOC_ATTR(s) __attribute__((s))
 #  define JEMALLOC_EXPORT JEMALLOC_ATTR(visibility("default"))
diff --git a/src/jemalloc/include/jemalloc/jemalloc_protos.h.in b/src/jemalloc/include/jemalloc/jemalloc_protos.h.in
index 25446de3d96ec376f26e8cf33b745aa0705bb116..8a2e35a0e8393ce1f29b85d417a4d239ed96e3c4 100644
--- a/src/jemalloc/include/jemalloc/jemalloc_protos.h.in
+++ b/src/jemalloc/include/jemalloc/jemalloc_protos.h.in
@@ -7,6 +7,23 @@ extern JEMALLOC_EXPORT const char	*@je_@malloc_conf;
 extern JEMALLOC_EXPORT void		(*@je_@malloc_message)(void *cbopaque,
     const char *s);
 
+typedef struct pool_s pool_t;
+
+JEMALLOC_EXPORT pool_t	*@je_@pool_create(void *addr, size_t size, int zeroed);
+JEMALLOC_EXPORT void	@je_@pool_delete(pool_t *pool);
+JEMALLOC_EXPORT size_t	@je_@pool_extend(pool_t *pool, void *addr,
+					    size_t size, int zeroed);
+JEMALLOC_EXPORT void	*@je_@pool_malloc(pool_t *pool, size_t size);
+JEMALLOC_EXPORT void	*@je_@pool_calloc(pool_t *pool, size_t nmemb, size_t size);
+JEMALLOC_EXPORT void	*@je_@pool_ralloc(pool_t *pool, void *ptr, size_t size);
+JEMALLOC_EXPORT void	*@je_@pool_aligned_alloc(pool_t *pool,  size_t alignment, size_t size);
+JEMALLOC_EXPORT void	@je_@pool_free(pool_t *pool, void *ptr);
+JEMALLOC_EXPORT void	@je_@pool_malloc_stats_print(pool_t *pool,
+							void (*write_cb)(void *, const char *),
+							void *cbopaque, const char *opts);
+JEMALLOC_EXPORT void	@je_@pool_set_alloc_funcs(void *(*malloc_func)(size_t),
+							void (*free_func)(void *));
+
 JEMALLOC_EXPORT void	*@je_@malloc(size_t size) JEMALLOC_ATTR(malloc);
 JEMALLOC_EXPORT void	*@je_@calloc(size_t num, size_t size)
     JEMALLOC_ATTR(malloc);
@@ -45,14 +62,5 @@ JEMALLOC_EXPORT void *	@je_@memalign(size_t alignment, size_t size)
 JEMALLOC_EXPORT void *	@je_@valloc(size_t size) JEMALLOC_ATTR(malloc);
 #endif
 
-#ifdef JEMALLOC_EXPERIMENTAL
-JEMALLOC_EXPORT int	@je_@allocm(void **ptr, size_t *rsize, size_t size,
-    int flags) JEMALLOC_ATTR(nonnull(1));
-JEMALLOC_EXPORT int	@je_@rallocm(void **ptr, size_t *rsize, size_t size,
-    size_t extra, int flags) JEMALLOC_ATTR(nonnull(1));
-JEMALLOC_EXPORT int	@je_@sallocm(const void *ptr, size_t *rsize, int flags)
-    JEMALLOC_ATTR(nonnull(1));
-JEMALLOC_EXPORT int	@je_@dallocm(void *ptr, int flags)
-    JEMALLOC_ATTR(nonnull(1));
-JEMALLOC_EXPORT int	@je_@nallocm(size_t *rsize, size_t size, int flags);
-#endif
+typedef void *(chunk_alloc_t)(size_t, size_t, bool *, unsigned, pool_t *);
+typedef bool (chunk_dalloc_t)(void *, size_t, unsigned, pool_t *);
diff --git a/src/jemalloc/include/msvc_compat/C99/inttypes.h b/src/jemalloc/include/msvc_compat/C99/inttypes.h
new file mode 100644
index 0000000000000000000000000000000000000000..a4e6b75cb9146411972426ebf530a21cf4dccb15
--- /dev/null
+++ b/src/jemalloc/include/msvc_compat/C99/inttypes.h
@@ -0,0 +1,313 @@
+// ISO C9x  compliant inttypes.h for Microsoft Visual Studio
+// Based on ISO/IEC 9899:TC2 Committee draft (May 6, 2005) WG14/N1124 
+// 
+//  Copyright (c) 2006 Alexander Chemeris
+// 
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are met:
+// 
+//   1. Redistributions of source code must retain the above copyright notice,
+//      this list of conditions and the following disclaimer.
+// 
+//   2. Redistributions in binary form must reproduce the above copyright
+//      notice, this list of conditions and the following disclaimer in the
+//      documentation and/or other materials provided with the distribution.
+// 
+//   3. The name of the author may be used to endorse or promote products
+//      derived from this software without specific prior written permission.
+// 
+// THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED
+// WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+// MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO
+// EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+// PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
+// OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, 
+// WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
+// OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
+// ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+// 
+///////////////////////////////////////////////////////////////////////////////
+
+#ifndef _MSC_VER // [
+#error "Use this header only with Microsoft Visual C++ compilers!"
+#endif // _MSC_VER ]
+
+#ifndef _MSC_INTTYPES_H_ // [
+#define _MSC_INTTYPES_H_
+
+#if _MSC_VER > 1000
+#pragma once
+#endif
+
+#include "stdint.h"
+
+// 7.8 Format conversion of integer types
+
+typedef struct {
+   intmax_t quot;
+   intmax_t rem;
+} imaxdiv_t;
+
+// 7.8.1 Macros for format specifiers
+
+#if !defined(__cplusplus) || defined(__STDC_FORMAT_MACROS) // [   See footnote 185 at page 198
+
+#ifdef _WIN64
+#  define __PRI64_PREFIX        "l"
+#  define __PRIPTR_PREFIX       "l"
+#else
+#  define __PRI64_PREFIX        "ll"
+#  define __PRIPTR_PREFIX
+#endif
+
+// The fprintf macros for signed integers are:
+#define PRId8       "d"
+#define PRIi8       "i"
+#define PRIdLEAST8  "d"
+#define PRIiLEAST8  "i"
+#define PRIdFAST8   "d"
+#define PRIiFAST8   "i"
+
+#define PRId16       "hd"
+#define PRIi16       "hi"
+#define PRIdLEAST16  "hd"
+#define PRIiLEAST16  "hi"
+#define PRIdFAST16   "hd"
+#define PRIiFAST16   "hi"
+
+#define PRId32       "d"
+#define PRIi32       "i"
+#define PRIdLEAST32  "d"
+#define PRIiLEAST32  "i"
+#define PRIdFAST32   "d"
+#define PRIiFAST32   "i"
+
+#define PRId64       __PRI64_PREFIX "d"
+#define PRIi64       __PRI64_PREFIX "i"
+#define PRIdLEAST64  __PRI64_PREFIX "d"
+#define PRIiLEAST64  __PRI64_PREFIX "i"
+#define PRIdFAST64   __PRI64_PREFIX "d"
+#define PRIiFAST64   __PRI64_PREFIX "i"
+
+#define PRIdMAX     __PRI64_PREFIX "d"
+#define PRIiMAX     __PRI64_PREFIX "i"
+
+#define PRIdPTR     __PRIPTR_PREFIX "d"
+#define PRIiPTR     __PRIPTR_PREFIX "i"
+
+// The fprintf macros for unsigned integers are:
+#define PRIo8       "o"
+#define PRIu8       "u"
+#define PRIx8       "x"
+#define PRIX8       "X"
+#define PRIoLEAST8  "o"
+#define PRIuLEAST8  "u"
+#define PRIxLEAST8  "x"
+#define PRIXLEAST8  "X"
+#define PRIoFAST8   "o"
+#define PRIuFAST8   "u"
+#define PRIxFAST8   "x"
+#define PRIXFAST8   "X"
+
+#define PRIo16       "ho"
+#define PRIu16       "hu"
+#define PRIx16       "hx"
+#define PRIX16       "hX"
+#define PRIoLEAST16  "ho"
+#define PRIuLEAST16  "hu"
+#define PRIxLEAST16  "hx"
+#define PRIXLEAST16  "hX"
+#define PRIoFAST16   "ho"
+#define PRIuFAST16   "hu"
+#define PRIxFAST16   "hx"
+#define PRIXFAST16   "hX"
+
+#define PRIo32       "o"
+#define PRIu32       "u"
+#define PRIx32       "x"
+#define PRIX32       "X"
+#define PRIoLEAST32  "o"
+#define PRIuLEAST32  "u"
+#define PRIxLEAST32  "x"
+#define PRIXLEAST32  "X"
+#define PRIoFAST32   "o"
+#define PRIuFAST32   "u"
+#define PRIxFAST32   "x"
+#define PRIXFAST32   "X"
+
+#define PRIo64       __PRI64_PREFIX "o"
+#define PRIu64       __PRI64_PREFIX "u"
+#define PRIx64       __PRI64_PREFIX "x"
+#define PRIX64       __PRI64_PREFIX "X"
+#define PRIoLEAST64  __PRI64_PREFIX "o"
+#define PRIuLEAST64  __PRI64_PREFIX "u"
+#define PRIxLEAST64  __PRI64_PREFIX "x"
+#define PRIXLEAST64  __PRI64_PREFIX "X"
+#define PRIoFAST64   __PRI64_PREFIX "o"
+#define PRIuFAST64   __PRI64_PREFIX "u"
+#define PRIxFAST64   __PRI64_PREFIX "x"
+#define PRIXFAST64   __PRI64_PREFIX "X"
+
+#define PRIoMAX     __PRI64_PREFIX "o"
+#define PRIuMAX     __PRI64_PREFIX "u"
+#define PRIxMAX     __PRI64_PREFIX "x"
+#define PRIXMAX     __PRI64_PREFIX "X"
+
+#define PRIoPTR     __PRIPTR_PREFIX "o"
+#define PRIuPTR     __PRIPTR_PREFIX "u"
+#define PRIxPTR     __PRIPTR_PREFIX "x"
+#define PRIXPTR     __PRIPTR_PREFIX "X"
+
+// The fscanf macros for signed integers are:
+#define SCNd8       "d"
+#define SCNi8       "i"
+#define SCNdLEAST8  "d"
+#define SCNiLEAST8  "i"
+#define SCNdFAST8   "d"
+#define SCNiFAST8   "i"
+
+#define SCNd16       "hd"
+#define SCNi16       "hi"
+#define SCNdLEAST16  "hd"
+#define SCNiLEAST16  "hi"
+#define SCNdFAST16   "hd"
+#define SCNiFAST16   "hi"
+
+#define SCNd32       "ld"
+#define SCNi32       "li"
+#define SCNdLEAST32  "ld"
+#define SCNiLEAST32  "li"
+#define SCNdFAST32   "ld"
+#define SCNiFAST32   "li"
+
+#define SCNd64       "I64d"
+#define SCNi64       "I64i"
+#define SCNdLEAST64  "I64d"
+#define SCNiLEAST64  "I64i"
+#define SCNdFAST64   "I64d"
+#define SCNiFAST64   "I64i"
+
+#define SCNdMAX     "I64d"
+#define SCNiMAX     "I64i"
+
+#ifdef _WIN64 // [
+#  define SCNdPTR     "I64d"
+#  define SCNiPTR     "I64i"
+#else  // _WIN64 ][
+#  define SCNdPTR     "ld"
+#  define SCNiPTR     "li"
+#endif  // _WIN64 ]
+
+// The fscanf macros for unsigned integers are:
+#define SCNo8       "o"
+#define SCNu8       "u"
+#define SCNx8       "x"
+#define SCNX8       "X"
+#define SCNoLEAST8  "o"
+#define SCNuLEAST8  "u"
+#define SCNxLEAST8  "x"
+#define SCNXLEAST8  "X"
+#define SCNoFAST8   "o"
+#define SCNuFAST8   "u"
+#define SCNxFAST8   "x"
+#define SCNXFAST8   "X"
+
+#define SCNo16       "ho"
+#define SCNu16       "hu"
+#define SCNx16       "hx"
+#define SCNX16       "hX"
+#define SCNoLEAST16  "ho"
+#define SCNuLEAST16  "hu"
+#define SCNxLEAST16  "hx"
+#define SCNXLEAST16  "hX"
+#define SCNoFAST16   "ho"
+#define SCNuFAST16   "hu"
+#define SCNxFAST16   "hx"
+#define SCNXFAST16   "hX"
+
+#define SCNo32       "lo"
+#define SCNu32       "lu"
+#define SCNx32       "lx"
+#define SCNX32       "lX"
+#define SCNoLEAST32  "lo"
+#define SCNuLEAST32  "lu"
+#define SCNxLEAST32  "lx"
+#define SCNXLEAST32  "lX"
+#define SCNoFAST32   "lo"
+#define SCNuFAST32   "lu"
+#define SCNxFAST32   "lx"
+#define SCNXFAST32   "lX"
+
+#define SCNo64       "I64o"
+#define SCNu64       "I64u"
+#define SCNx64       "I64x"
+#define SCNX64       "I64X"
+#define SCNoLEAST64  "I64o"
+#define SCNuLEAST64  "I64u"
+#define SCNxLEAST64  "I64x"
+#define SCNXLEAST64  "I64X"
+#define SCNoFAST64   "I64o"
+#define SCNuFAST64   "I64u"
+#define SCNxFAST64   "I64x"
+#define SCNXFAST64   "I64X"
+
+#define SCNoMAX     "I64o"
+#define SCNuMAX     "I64u"
+#define SCNxMAX     "I64x"
+#define SCNXMAX     "I64X"
+
+#ifdef _WIN64 // [
+#  define SCNoPTR     "I64o"
+#  define SCNuPTR     "I64u"
+#  define SCNxPTR     "I64x"
+#  define SCNXPTR     "I64X"
+#else  // _WIN64 ][
+#  define SCNoPTR     "lo"
+#  define SCNuPTR     "lu"
+#  define SCNxPTR     "lx"
+#  define SCNXPTR     "lX"
+#endif  // _WIN64 ]
+
+#endif // __STDC_FORMAT_MACROS ]
+
+// 7.8.2 Functions for greatest-width integer types
+
+// 7.8.2.1 The imaxabs function
+#define imaxabs _abs64
+
+// 7.8.2.2 The imaxdiv function
+
+// This is modified version of div() function from Microsoft's div.c found
+// in %MSVC.NET%\crt\src\div.c
+#ifdef STATIC_IMAXDIV // [
+static
+#else // STATIC_IMAXDIV ][
+_inline
+#endif // STATIC_IMAXDIV ]
+imaxdiv_t __cdecl imaxdiv(intmax_t numer, intmax_t denom)
+{
+   imaxdiv_t result;
+
+   result.quot = numer / denom;
+   result.rem = numer % denom;
+
+   if (numer < 0 && result.rem > 0) {
+      // did division wrong; must fix up
+      ++result.quot;
+      result.rem -= denom;
+   }
+
+   return result;
+}
+
+// 7.8.2.3 The strtoimax and strtoumax functions
+#define strtoimax _strtoi64
+#define strtoumax _strtoui64
+
+// 7.8.2.4 The wcstoimax and wcstoumax functions
+#define wcstoimax _wcstoi64
+#define wcstoumax _wcstoui64
+
+
+#endif // _MSC_INTTYPES_H_ ]
diff --git a/src/jemalloc/include/msvc_compat/C99/stdbool.h b/src/jemalloc/include/msvc_compat/C99/stdbool.h
new file mode 100644
index 0000000000000000000000000000000000000000..d92160ebc752ff28f9b9f66cd9b5c0d7755c3f4d
--- /dev/null
+++ b/src/jemalloc/include/msvc_compat/C99/stdbool.h
@@ -0,0 +1,20 @@
+#ifndef stdbool_h
+#define stdbool_h
+
+#include <wtypes.h>
+
+/* MSVC doesn't define _Bool or bool in C, but does have BOOL */
+/* Note this doesn't pass autoconf's test because (bool) 0.5 != true */
+/* Clang-cl uses MSVC headers, so needs msvc_compat, but has _Bool as
+ * a built-in type. */
+#ifndef __clang__
+typedef BOOL _Bool;
+#endif
+
+#define bool _Bool
+#define true 1
+#define false 0
+
+#define __bool_true_false_are_defined 1
+
+#endif /* stdbool_h */
diff --git a/src/jemalloc/include/msvc_compat/C99/stdint.h b/src/jemalloc/include/msvc_compat/C99/stdint.h
new file mode 100644
index 0000000000000000000000000000000000000000..d02608a5972642c7b7a13b987f21e2502a5af3ea
--- /dev/null
+++ b/src/jemalloc/include/msvc_compat/C99/stdint.h
@@ -0,0 +1,247 @@
+// ISO C9x  compliant stdint.h for Microsoft Visual Studio
+// Based on ISO/IEC 9899:TC2 Committee draft (May 6, 2005) WG14/N1124 
+// 
+//  Copyright (c) 2006-2008 Alexander Chemeris
+// 
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are met:
+// 
+//   1. Redistributions of source code must retain the above copyright notice,
+//      this list of conditions and the following disclaimer.
+// 
+//   2. Redistributions in binary form must reproduce the above copyright
+//      notice, this list of conditions and the following disclaimer in the
+//      documentation and/or other materials provided with the distribution.
+// 
+//   3. The name of the author may be used to endorse or promote products
+//      derived from this software without specific prior written permission.
+// 
+// THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED
+// WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+// MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO
+// EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+// PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
+// OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, 
+// WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
+// OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
+// ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+// 
+///////////////////////////////////////////////////////////////////////////////
+
+#ifndef _MSC_VER // [
+#error "Use this header only with Microsoft Visual C++ compilers!"
+#endif // _MSC_VER ]
+
+#ifndef _MSC_STDINT_H_ // [
+#define _MSC_STDINT_H_
+
+#if _MSC_VER > 1000
+#pragma once
+#endif
+
+#include <limits.h>
+
+// For Visual Studio 6 in C++ mode and for many Visual Studio versions when
+// compiling for ARM we should wrap <wchar.h> include with 'extern "C++" {}'
+// or compiler give many errors like this:
+//   error C2733: second C linkage of overloaded function 'wmemchr' not allowed
+#ifdef __cplusplus
+extern "C" {
+#endif
+#  include <wchar.h>
+#ifdef __cplusplus
+}
+#endif
+
+// Define _W64 macros to mark types changing their size, like intptr_t.
+#ifndef _W64
+#  if !defined(__midl) && (defined(_X86_) || defined(_M_IX86)) && _MSC_VER >= 1300
+#     define _W64 __w64
+#  else
+#     define _W64
+#  endif
+#endif
+
+
+// 7.18.1 Integer types
+
+// 7.18.1.1 Exact-width integer types
+
+// Visual Studio 6 and Embedded Visual C++ 4 doesn't
+// realize that, e.g. char has the same size as __int8
+// so we give up on __intX for them.
+#if (_MSC_VER < 1300)
+   typedef signed char       int8_t;
+   typedef signed short      int16_t;
+   typedef signed int        int32_t;
+   typedef unsigned char     uint8_t;
+   typedef unsigned short    uint16_t;
+   typedef unsigned int      uint32_t;
+#else
+   typedef signed __int8     int8_t;
+   typedef signed __int16    int16_t;
+   typedef signed __int32    int32_t;
+   typedef unsigned __int8   uint8_t;
+   typedef unsigned __int16  uint16_t;
+   typedef unsigned __int32  uint32_t;
+#endif
+typedef signed __int64       int64_t;
+typedef unsigned __int64     uint64_t;
+
+
+// 7.18.1.2 Minimum-width integer types
+typedef int8_t    int_least8_t;
+typedef int16_t   int_least16_t;
+typedef int32_t   int_least32_t;
+typedef int64_t   int_least64_t;
+typedef uint8_t   uint_least8_t;
+typedef uint16_t  uint_least16_t;
+typedef uint32_t  uint_least32_t;
+typedef uint64_t  uint_least64_t;
+
+// 7.18.1.3 Fastest minimum-width integer types
+typedef int8_t    int_fast8_t;
+typedef int16_t   int_fast16_t;
+typedef int32_t   int_fast32_t;
+typedef int64_t   int_fast64_t;
+typedef uint8_t   uint_fast8_t;
+typedef uint16_t  uint_fast16_t;
+typedef uint32_t  uint_fast32_t;
+typedef uint64_t  uint_fast64_t;
+
+// 7.18.1.4 Integer types capable of holding object pointers
+#ifdef _WIN64 // [
+   typedef signed __int64    intptr_t;
+   typedef unsigned __int64  uintptr_t;
+#else // _WIN64 ][
+   typedef _W64 signed int   intptr_t;
+   typedef _W64 unsigned int uintptr_t;
+#endif // _WIN64 ]
+
+// 7.18.1.5 Greatest-width integer types
+typedef int64_t   intmax_t;
+typedef uint64_t  uintmax_t;
+
+
+// 7.18.2 Limits of specified-width integer types
+
+#if !defined(__cplusplus) || defined(__STDC_LIMIT_MACROS) // [   See footnote 220 at page 257 and footnote 221 at page 259
+
+// 7.18.2.1 Limits of exact-width integer types
+#define INT8_MIN     ((int8_t)_I8_MIN)
+#define INT8_MAX     _I8_MAX
+#define INT16_MIN    ((int16_t)_I16_MIN)
+#define INT16_MAX    _I16_MAX
+#define INT32_MIN    ((int32_t)_I32_MIN)
+#define INT32_MAX    _I32_MAX
+#define INT64_MIN    ((int64_t)_I64_MIN)
+#define INT64_MAX    _I64_MAX
+#define UINT8_MAX    _UI8_MAX
+#define UINT16_MAX   _UI16_MAX
+#define UINT32_MAX   _UI32_MAX
+#define UINT64_MAX   _UI64_MAX
+
+// 7.18.2.2 Limits of minimum-width integer types
+#define INT_LEAST8_MIN    INT8_MIN
+#define INT_LEAST8_MAX    INT8_MAX
+#define INT_LEAST16_MIN   INT16_MIN
+#define INT_LEAST16_MAX   INT16_MAX
+#define INT_LEAST32_MIN   INT32_MIN
+#define INT_LEAST32_MAX   INT32_MAX
+#define INT_LEAST64_MIN   INT64_MIN
+#define INT_LEAST64_MAX   INT64_MAX
+#define UINT_LEAST8_MAX   UINT8_MAX
+#define UINT_LEAST16_MAX  UINT16_MAX
+#define UINT_LEAST32_MAX  UINT32_MAX
+#define UINT_LEAST64_MAX  UINT64_MAX
+
+// 7.18.2.3 Limits of fastest minimum-width integer types
+#define INT_FAST8_MIN    INT8_MIN
+#define INT_FAST8_MAX    INT8_MAX
+#define INT_FAST16_MIN   INT16_MIN
+#define INT_FAST16_MAX   INT16_MAX
+#define INT_FAST32_MIN   INT32_MIN
+#define INT_FAST32_MAX   INT32_MAX
+#define INT_FAST64_MIN   INT64_MIN
+#define INT_FAST64_MAX   INT64_MAX
+#define UINT_FAST8_MAX   UINT8_MAX
+#define UINT_FAST16_MAX  UINT16_MAX
+#define UINT_FAST32_MAX  UINT32_MAX
+#define UINT_FAST64_MAX  UINT64_MAX
+
+// 7.18.2.4 Limits of integer types capable of holding object pointers
+#ifdef _WIN64 // [
+#  define INTPTR_MIN   INT64_MIN
+#  define INTPTR_MAX   INT64_MAX
+#  define UINTPTR_MAX  UINT64_MAX
+#else // _WIN64 ][
+#  define INTPTR_MIN   INT32_MIN
+#  define INTPTR_MAX   INT32_MAX
+#  define UINTPTR_MAX  UINT32_MAX
+#endif // _WIN64 ]
+
+// 7.18.2.5 Limits of greatest-width integer types
+#define INTMAX_MIN   INT64_MIN
+#define INTMAX_MAX   INT64_MAX
+#define UINTMAX_MAX  UINT64_MAX
+
+// 7.18.3 Limits of other integer types
+
+#ifdef _WIN64 // [
+#  define PTRDIFF_MIN  _I64_MIN
+#  define PTRDIFF_MAX  _I64_MAX
+#else  // _WIN64 ][
+#  define PTRDIFF_MIN  _I32_MIN
+#  define PTRDIFF_MAX  _I32_MAX
+#endif  // _WIN64 ]
+
+#define SIG_ATOMIC_MIN  INT_MIN
+#define SIG_ATOMIC_MAX  INT_MAX
+
+#ifndef SIZE_MAX // [
+#  ifdef _WIN64 // [
+#     define SIZE_MAX  _UI64_MAX
+#  else // _WIN64 ][
+#     define SIZE_MAX  _UI32_MAX
+#  endif // _WIN64 ]
+#endif // SIZE_MAX ]
+
+// WCHAR_MIN and WCHAR_MAX are also defined in <wchar.h>
+#ifndef WCHAR_MIN // [
+#  define WCHAR_MIN  0
+#endif  // WCHAR_MIN ]
+#ifndef WCHAR_MAX // [
+#  define WCHAR_MAX  _UI16_MAX
+#endif  // WCHAR_MAX ]
+
+#define WINT_MIN  0
+#define WINT_MAX  _UI16_MAX
+
+#endif // __STDC_LIMIT_MACROS ]
+
+
+// 7.18.4 Limits of other integer types
+
+#if !defined(__cplusplus) || defined(__STDC_CONSTANT_MACROS) // [   See footnote 224 at page 260
+
+// 7.18.4.1 Macros for minimum-width integer constants
+
+#define INT8_C(val)  val##i8
+#define INT16_C(val) val##i16
+#define INT32_C(val) val##i32
+#define INT64_C(val) val##i64
+
+#define UINT8_C(val)  val##ui8
+#define UINT16_C(val) val##ui16
+#define UINT32_C(val) val##ui32
+#define UINT64_C(val) val##ui64
+
+// 7.18.4.2 Macros for greatest-width integer constants
+#define INTMAX_C   INT64_C
+#define UINTMAX_C  UINT64_C
+
+#endif // __STDC_CONSTANT_MACROS ]
+
+
+#endif // _MSC_STDINT_H_ ]
diff --git a/src/jemalloc/src/arena.c b/src/jemalloc/src/arena.c
index dad707b63d0539d0b78511751a0c4fed53862693..5212d748b73256e9bfe11e9a079ec25eabe9fec0 100644
--- a/src/jemalloc/src/arena.c
+++ b/src/jemalloc/src/arena.c
@@ -8,33 +8,40 @@ ssize_t		opt_lg_dirty_mult = LG_DIRTY_MULT_DEFAULT;
 arena_bin_info_t	arena_bin_info[NBINS];
 
 JEMALLOC_ALIGNED(CACHELINE)
-const uint8_t	small_size2bin[] = {
-#define	S2B_8(i)	i,
-#define	S2B_16(i)	S2B_8(i) S2B_8(i)
-#define	S2B_32(i)	S2B_16(i) S2B_16(i)
-#define	S2B_64(i)	S2B_32(i) S2B_32(i)
-#define	S2B_128(i)	S2B_64(i) S2B_64(i)
-#define	S2B_256(i)	S2B_128(i) S2B_128(i)
-#define	S2B_512(i)	S2B_256(i) S2B_256(i)
-#define	S2B_1024(i)	S2B_512(i) S2B_512(i)
-#define	S2B_2048(i)	S2B_1024(i) S2B_1024(i)
-#define	S2B_4096(i)	S2B_2048(i) S2B_2048(i)
-#define	S2B_8192(i)	S2B_4096(i) S2B_4096(i)
-#define	SIZE_CLASS(bin, delta, size)					\
-	S2B_##delta(bin)
+const uint32_t	small_bin2size_tab[NBINS] = {
+#define	B2S_bin_yes(size) \
+	size,
+#define	B2S_bin_no(size)
+#define	SC(index, lg_grp, lg_delta, ndelta, bin, lg_delta_lookup) \
+	B2S_bin_##bin((ZU(1)<<lg_grp) + (ZU(ndelta)<<lg_delta))
 	SIZE_CLASSES
+#undef B2S_bin_yes
+#undef B2S_bin_no
+#undef SC
+};
+
+JEMALLOC_ALIGNED(CACHELINE)
+const uint8_t	small_size2bin_tab[] = {
+#define	S2B_3(i)	i,
+#define	S2B_4(i)	S2B_3(i) S2B_3(i)
+#define	S2B_5(i)	S2B_4(i) S2B_4(i)
+#define	S2B_6(i)	S2B_5(i) S2B_5(i)
+#define	S2B_7(i)	S2B_6(i) S2B_6(i)
+#define	S2B_8(i)	S2B_7(i) S2B_7(i)
+#define	S2B_9(i)	S2B_8(i) S2B_8(i)
+#define	S2B_no(i)
+#define	SC(index, lg_grp, lg_delta, ndelta, bin, lg_delta_lookup) \
+	S2B_##lg_delta_lookup(index)
+	SIZE_CLASSES
+#undef S2B_3
+#undef S2B_4
+#undef S2B_5
+#undef S2B_6
+#undef S2B_7
 #undef S2B_8
-#undef S2B_16
-#undef S2B_32
-#undef S2B_64
-#undef S2B_128
-#undef S2B_256
-#undef S2B_512
-#undef S2B_1024
-#undef S2B_2048
-#undef S2B_4096
-#undef S2B_8192
-#undef SIZE_CLASS
+#undef S2B_9
+#undef S2B_no
+#undef SC
 };
 
 /******************************************************************************/
@@ -53,6 +60,22 @@ static void	arena_bin_lower_run(arena_t *arena, arena_chunk_t *chunk,
 
 /******************************************************************************/
 
+JEMALLOC_INLINE_C size_t
+arena_mapelm_to_pageind(arena_chunk_map_t *mapelm)
+{
+	uintptr_t map_offset =
+	    CHUNK_ADDR2OFFSET(mapelm) - offsetof(arena_chunk_t, map);
+
+	return ((map_offset / sizeof(arena_chunk_map_t)) + map_bias);
+}
+
+JEMALLOC_INLINE_C size_t
+arena_mapelm_to_bits(arena_chunk_map_t *mapelm)
+{
+
+	return (mapelm->bits);
+}
+
 static inline int
 arena_run_comp(arena_chunk_map_t *a, arena_chunk_map_t *b)
 {
@@ -73,26 +96,19 @@ static inline int
 arena_avail_comp(arena_chunk_map_t *a, arena_chunk_map_t *b)
 {
 	int ret;
-	size_t a_size = a->bits & ~PAGE_MASK;
-	size_t b_size = b->bits & ~PAGE_MASK;
-
-	ret = (a_size > b_size) - (a_size < b_size);
-	if (ret == 0) {
-		uintptr_t a_mapelm, b_mapelm;
+	size_t a_size;
+	size_t b_size = arena_mapelm_to_bits(b) & ~PAGE_MASK;
+	uintptr_t a_mapelm = (uintptr_t)a;
+	uintptr_t b_mapelm = (uintptr_t)b;
 
-		if ((a->bits & CHUNK_MAP_KEY) != CHUNK_MAP_KEY)
-			a_mapelm = (uintptr_t)a;
-		else {
-			/*
-			 * Treat keys as though they are lower than anything
-			 * else.
-			 */
-			a_mapelm = 0;
-		}
-		b_mapelm = (uintptr_t)b;
+        if (a_mapelm & CHUNK_MAP_KEY)
+		a_size = a_mapelm & ~PAGE_MASK;
+        else
+		a_size = arena_mapelm_to_bits(a) & ~PAGE_MASK;
 
+	ret = (a_size > b_size) - (a_size < b_size);
+	if (ret == 0 && (!(a_mapelm & CHUNK_MAP_KEY)))
 		ret = (a_mapelm > b_mapelm) - (a_mapelm < b_mapelm);
-	}
 
 	return (ret);
 }
@@ -328,8 +344,8 @@ static inline void
 arena_run_zero(arena_chunk_t *chunk, size_t run_ind, size_t npages)
 {
 
-	VALGRIND_MAKE_MEM_UNDEFINED((void *)((uintptr_t)chunk + (run_ind <<
-	    LG_PAGE)), (npages << LG_PAGE));
+	JEMALLOC_VALGRIND_MAKE_MEM_UNDEFINED((void *)((uintptr_t)chunk +
+	    (run_ind << LG_PAGE)), (npages << LG_PAGE));
 	memset((void *)((uintptr_t)chunk + (run_ind << LG_PAGE)), 0,
 	    (npages << LG_PAGE));
 }
@@ -338,8 +354,8 @@ static inline void
 arena_run_page_mark_zeroed(arena_chunk_t *chunk, size_t run_ind)
 {
 
-	VALGRIND_MAKE_MEM_DEFINED((void *)((uintptr_t)chunk + (run_ind <<
-	    LG_PAGE)), PAGE);
+	JEMALLOC_VALGRIND_MAKE_MEM_DEFINED((void *)((uintptr_t)chunk + (run_ind
+	    << LG_PAGE)), PAGE);
 }
 
 static inline void
@@ -362,7 +378,7 @@ arena_cactive_update(arena_t *arena, size_t add_pages, size_t sub_pages)
 		    add_pages) << LG_PAGE) - CHUNK_CEILING((arena->nactive -
 		    sub_pages) << LG_PAGE);
 		if (cactive_diff != 0)
-			stats_cactive_add(cactive_diff);
+			stats_cactive_add(arena->pool, cactive_diff);
 	}
 }
 
@@ -448,7 +464,7 @@ arena_run_split_large_helper(arena_t *arena, arena_run_t *run, size_t size,
 			arena_run_zero(chunk, run_ind, need_pages);
 		}
 	} else {
-		VALGRIND_MAKE_MEM_UNDEFINED((void *)((uintptr_t)chunk +
+		JEMALLOC_VALGRIND_MAKE_MEM_UNDEFINED((void *)((uintptr_t)chunk +
 		    (run_ind << LG_PAGE)), (need_pages << LG_PAGE));
 	}
 
@@ -516,7 +532,7 @@ arena_run_split_small(arena_t *arena, arena_run_t *run, size_t size,
 	if (config_debug && flag_dirty == 0 && arena_mapbits_unzeroed_get(chunk,
 	    run_ind+need_pages-1) == 0)
 		arena_run_page_validate_zeroed(chunk, run_ind+need_pages-1);
-	VALGRIND_MAKE_MEM_UNDEFINED((void *)((uintptr_t)chunk +
+	JEMALLOC_VALGRIND_MAKE_MEM_UNDEFINED((void *)((uintptr_t)chunk +
 	    (run_ind << LG_PAGE)), (need_pages << LG_PAGE));
 }
 
@@ -542,6 +558,65 @@ arena_chunk_init_spare(arena_t *arena)
 	return (chunk);
 }
 
+static arena_chunk_t *
+arena_chunk_alloc_internal(arena_t *arena, size_t size, size_t alignment,
+    bool *zero)
+{
+	arena_chunk_t *chunk;
+	chunk_alloc_t *chunk_alloc;
+	chunk_dalloc_t *chunk_dalloc;
+
+	chunk_alloc = arena->chunk_alloc;
+	chunk_dalloc = arena->chunk_dalloc;
+	malloc_mutex_unlock(&arena->lock);
+	chunk = (arena_chunk_t *)chunk_alloc_arena(chunk_alloc, chunk_dalloc,
+	    arena, size, alignment, zero);
+	malloc_mutex_lock(&arena->lock);
+	if (config_stats && chunk != NULL)
+		arena->stats.mapped += chunksize;
+
+	return (chunk);
+}
+
+void *
+arena_chunk_alloc_huge(arena_t *arena, size_t size, size_t alignment,
+    bool *zero)
+{
+	void *ret;
+	chunk_alloc_t *chunk_alloc;
+	chunk_dalloc_t *chunk_dalloc;
+
+	malloc_mutex_lock(&arena->lock);
+	chunk_alloc = arena->chunk_alloc;
+	chunk_dalloc = arena->chunk_dalloc;
+	if (config_stats) {
+		/* Optimistically update stats prior to unlocking. */
+		arena->stats.mapped += size;
+		arena->stats.allocated_huge += size;
+		arena->stats.nmalloc_huge++;
+		arena->stats.nrequests_huge++;
+	}
+	arena->nactive += (size >> LG_PAGE);
+	malloc_mutex_unlock(&arena->lock);
+
+	ret = chunk_alloc_arena(chunk_alloc, chunk_dalloc, arena, size,
+		alignment, zero);
+	if (config_stats) {
+		if (ret != NULL)
+			stats_cactive_add(arena->pool, size);
+		else {
+			/* Revert optimistic stats updates. */
+			malloc_mutex_lock(&arena->lock);
+			arena->stats.mapped -= size;
+			arena->stats.allocated_huge -= size;
+			arena->stats.nmalloc_huge--;
+			malloc_mutex_unlock(&arena->lock);
+		}
+	}
+
+	return (ret);
+}
+
 static arena_chunk_t *
 arena_chunk_init_hard(arena_t *arena)
 {
@@ -552,14 +627,9 @@ arena_chunk_init_hard(arena_t *arena)
 	assert(arena->spare == NULL);
 
 	zero = false;
-	malloc_mutex_unlock(&arena->lock);
-	chunk = (arena_chunk_t *)chunk_alloc(chunksize, chunksize, false,
-	    &zero, arena->dss_prec);
-	malloc_mutex_lock(&arena->lock);
+	chunk = arena_chunk_alloc_internal(arena, chunksize, chunksize, &zero);
 	if (chunk == NULL)
 		return (NULL);
-	if (config_stats)
-		arena->stats.mapped += chunksize;
 
 	chunk->arena = arena;
 
@@ -583,14 +653,14 @@ arena_chunk_init_hard(arena_t *arena)
 	 * the chunk is not zeroed.
 	 */
 	if (zero == false) {
-		VALGRIND_MAKE_MEM_UNDEFINED((void *)arena_mapp_get(chunk,
-		    map_bias+1), (size_t)((uintptr_t) arena_mapp_get(chunk,
-		    chunk_npages-1) - (uintptr_t)arena_mapp_get(chunk,
-		    map_bias+1)));
+		JEMALLOC_VALGRIND_MAKE_MEM_UNDEFINED(
+		    (void *)arena_mapp_get(chunk, map_bias+1),
+		    (size_t)((uintptr_t) arena_mapp_get(chunk, chunk_npages-1) -
+		    (uintptr_t)arena_mapp_get(chunk, map_bias+1)));
 		for (i = map_bias+1; i < chunk_npages-1; i++)
 			arena_mapbits_unzeroed_set(chunk, i, unzeroed);
 	} else {
-		VALGRIND_MAKE_MEM_DEFINED((void *)arena_mapp_get(chunk,
+		JEMALLOC_VALGRIND_MAKE_MEM_DEFINED((void *)arena_mapp_get(chunk,
 		    map_bias+1), (size_t)((uintptr_t) arena_mapp_get(chunk,
 		    chunk_npages-1) - (uintptr_t)arena_mapp_get(chunk,
 		    map_bias+1)));
@@ -628,7 +698,38 @@ arena_chunk_alloc(arena_t *arena)
 }
 
 static void
-arena_chunk_dealloc(arena_t *arena, arena_chunk_t *chunk)
+arena_chunk_dalloc_internal(arena_t *arena, arena_chunk_t *chunk)
+{
+	chunk_dalloc_t *chunk_dalloc;
+
+	chunk_dalloc = arena->chunk_dalloc;
+	malloc_mutex_unlock(&arena->lock);
+	chunk_dalloc((void *)chunk, chunksize, arena->ind, arena->pool);
+	malloc_mutex_lock(&arena->lock);
+	if (config_stats)
+		arena->stats.mapped -= chunksize;
+}
+
+void
+arena_chunk_dalloc_huge(arena_t *arena, void *chunk, size_t size)
+{
+	chunk_dalloc_t *chunk_dalloc;
+
+	malloc_mutex_lock(&arena->lock);
+	chunk_dalloc = arena->chunk_dalloc;
+	if (config_stats) {
+		arena->stats.mapped -= size;
+		arena->stats.allocated_huge -= size;
+		arena->stats.ndalloc_huge++;
+		stats_cactive_sub(arena->pool, size);
+	}
+	arena->nactive -= (size >> LG_PAGE);
+	malloc_mutex_unlock(&arena->lock);
+	chunk_dalloc(chunk, size, arena->ind, arena->pool);
+}
+
+static void
+arena_chunk_dalloc(arena_t *arena, arena_chunk_t *chunk)
 {
 	assert(arena_mapbits_allocated_get(chunk, map_bias) == 0);
 	assert(arena_mapbits_allocated_get(chunk, chunk_npages-1) == 0);
@@ -650,11 +751,7 @@ arena_chunk_dealloc(arena_t *arena, arena_chunk_t *chunk)
 		arena_chunk_t *spare = arena->spare;
 
 		arena->spare = chunk;
-		malloc_mutex_unlock(&arena->lock);
-		chunk_dealloc((void *)spare, chunksize, true);
-		malloc_mutex_lock(&arena->lock);
-		if (config_stats)
-			arena->stats.mapped -= chunksize;
+		arena_chunk_dalloc_internal(arena, spare);
 	} else
 		arena->spare = chunk;
 }
@@ -663,15 +760,14 @@ static arena_run_t *
 arena_run_alloc_large_helper(arena_t *arena, size_t size, bool zero)
 {
 	arena_run_t *run;
-	arena_chunk_map_t *mapelm, key;
+	arena_chunk_map_t *mapelm;
+	arena_chunk_map_t *key;
 
-	key.bits = size | CHUNK_MAP_KEY;
-	mapelm = arena_avail_tree_nsearch(&arena->runs_avail, &key);
+	key = (arena_chunk_map_t *)(size | CHUNK_MAP_KEY);
+	mapelm = arena_avail_tree_nsearch(&arena->runs_avail, key);
 	if (mapelm != NULL) {
 		arena_chunk_t *run_chunk = CHUNK_ADDR2BASE(mapelm);
-		size_t pageind = (((uintptr_t)mapelm -
-		    (uintptr_t)run_chunk->map) / sizeof(arena_chunk_map_t))
-		    + map_bias;
+		size_t pageind = arena_mapelm_to_pageind(mapelm);
 
 		run = (arena_run_t *)((uintptr_t)run_chunk + (pageind <<
 		    LG_PAGE));
@@ -718,15 +814,14 @@ static arena_run_t *
 arena_run_alloc_small_helper(arena_t *arena, size_t size, size_t binind)
 {
 	arena_run_t *run;
-	arena_chunk_map_t *mapelm, key;
+	arena_chunk_map_t *mapelm;
+	arena_chunk_map_t *key;
 
-	key.bits = size | CHUNK_MAP_KEY;
-	mapelm = arena_avail_tree_nsearch(&arena->runs_avail, &key);
+	key = (arena_chunk_map_t *)(size | CHUNK_MAP_KEY);
+	mapelm = arena_avail_tree_nsearch(&arena->runs_avail, key);
 	if (mapelm != NULL) {
 		arena_chunk_t *run_chunk = CHUNK_ADDR2BASE(mapelm);
-		size_t pageind = (((uintptr_t)mapelm -
-		    (uintptr_t)run_chunk->map) / sizeof(arena_chunk_map_t))
-		    + map_bias;
+		size_t pageind = arena_mapelm_to_pageind(mapelm);
 
 		run = (arena_run_t *)((uintptr_t)run_chunk + (pageind <<
 		    LG_PAGE));
@@ -897,8 +992,7 @@ arena_chunk_purge_stashed(arena_t *arena, arena_chunk_t *chunk,
 		bool unzeroed;
 		size_t flag_unzeroed, i;
 
-		pageind = (((uintptr_t)mapelm - (uintptr_t)chunk->map) /
-		    sizeof(arena_chunk_map_t)) + map_bias;
+		pageind = arena_mapelm_to_pageind(mapelm);
 		npages = arena_mapbits_large_size_get(chunk, pageind) >>
 		    LG_PAGE;
 		assert(pageind + npages <= chunk_npages);
@@ -942,8 +1036,7 @@ arena_chunk_unstash_purged(arena_t *arena, arena_chunk_t *chunk,
 	    mapelm = ql_first(mapelms)) {
 		arena_run_t *run;
 
-		pageind = (((uintptr_t)mapelm - (uintptr_t)chunk->map) /
-		    sizeof(arena_chunk_map_t)) + map_bias;
+		pageind = arena_mapelm_to_pageind(mapelm);
 		run = (arena_run_t *)((uintptr_t)chunk + (uintptr_t)(pageind <<
 		    LG_PAGE));
 		ql_remove(mapelms, mapelm, u.ql_link);
@@ -1082,7 +1175,6 @@ arena_purge(arena_t *arena, bool all)
 void
 arena_purge_all(arena_t *arena)
 {
-
 	malloc_mutex_lock(&arena->lock);
 	arena_purge(arena, true);
 	malloc_mutex_unlock(&arena->lock);
@@ -1218,7 +1310,7 @@ arena_run_dalloc(arena_t *arena, arena_run_t *run, bool dirty, bool cleaned)
 	if (size == arena_maxclass) {
 		assert(run_ind == map_bias);
 		assert(run_pages == (arena_maxclass >> LG_PAGE));
-		arena_chunk_dealloc(arena, chunk);
+		arena_chunk_dalloc(arena, chunk);
 	}
 
 	/*
@@ -1307,8 +1399,7 @@ arena_bin_runs_first(arena_bin_t *bin)
 		arena_run_t *run;
 
 		chunk = (arena_chunk_t *)CHUNK_ADDR2BASE(mapelm);
-		pageind = ((((uintptr_t)mapelm - (uintptr_t)chunk->map) /
-		    sizeof(arena_chunk_map_t))) + map_bias;
+		pageind = arena_mapelm_to_pageind(mapelm);
 		run = (arena_run_t *)((uintptr_t)chunk + (uintptr_t)((pageind -
 		    arena_mapbits_small_runind_get(chunk, pageind)) <<
 		    LG_PAGE));
@@ -1485,8 +1576,7 @@ arena_tcache_fill_small(arena_t *arena, tcache_bin_t *tbin, size_t binind,
 			arena_alloc_junk_small(ptr, &arena_bin_info[binind],
 			    true);
 		}
-		/* Insert such that low regions get used first. */
-		tbin->avail[nfill - 1 - i] = ptr;
+		tbin->avail[i] = ptr;
 	}
 	if (config_stats) {
 		bin->stats.allocated += i * arena_bin_info[binind].reg_size;
@@ -1595,7 +1685,7 @@ arena_quarantine_junk_small(void *ptr, size_t usize)
 	assert(opt_quarantine);
 	assert(usize <= SMALL_MAXCLASS);
 
-	binind = SMALL_SIZE2BIN(usize);
+	binind = small_size2bin(usize);
 	bin_info = &arena_bin_info[binind];
 	arena_redzones_validate(ptr, bin_info, true);
 }
@@ -1608,10 +1698,10 @@ arena_malloc_small(arena_t *arena, size_t size, bool zero)
 	arena_run_t *run;
 	size_t binind;
 
-	binind = SMALL_SIZE2BIN(size);
+	binind = small_size2bin(size);
 	assert(binind < NBINS);
 	bin = &arena->bins[binind];
-	size = arena_bin_info[binind].reg_size;
+	size = small_bin2size(binind);
 
 	malloc_mutex_lock(&bin->lock);
 	if ((run = bin->runcur) != NULL && run->nfree > 0)
@@ -1641,13 +1731,13 @@ arena_malloc_small(arena_t *arena, size_t size, bool zero)
 			} else if (opt_zero)
 				memset(ret, 0, size);
 		}
-		VALGRIND_MAKE_MEM_UNDEFINED(ret, size);
+		JEMALLOC_VALGRIND_MAKE_MEM_UNDEFINED(ret, size);
 	} else {
 		if (config_fill && opt_junk) {
 			arena_alloc_junk_small(ret, &arena_bin_info[binind],
 			    true);
 		}
-		VALGRIND_MAKE_MEM_UNDEFINED(ret, size);
+		JEMALLOC_VALGRIND_MAKE_MEM_UNDEFINED(ret, size);
 		memset(ret, 0, size);
 	}
 
@@ -1765,7 +1855,7 @@ arena_prof_promoted(const void *ptr, size_t size)
 
 	chunk = (arena_chunk_t *)CHUNK_ADDR2BASE(ptr);
 	pageind = ((uintptr_t)ptr - (uintptr_t)chunk) >> LG_PAGE;
-	binind = SMALL_SIZE2BIN(size);
+	binind = small_size2bin(size);
 	assert(binind < NBINS);
 	arena_mapbits_large_binind_set(chunk, pageind, binind);
 
@@ -1882,7 +1972,7 @@ arena_dalloc_bin_locked(arena_t *arena, arena_chunk_t *chunk, void *ptr,
 	run = (arena_run_t *)((uintptr_t)chunk + (uintptr_t)((pageind -
 	    arena_mapbits_small_runind_get(chunk, pageind)) << LG_PAGE));
 	bin = run->bin;
-	binind = arena_ptr_small_binind_get(ptr, mapelm->bits);
+	binind = arena_ptr_small_binind_get(ptr, arena_mapbits_get(chunk, pageind));
 	bin_info = &arena_bin_info[binind];
 	if (config_fill || config_stats)
 		size = bin_info->reg_size;
@@ -2152,11 +2242,11 @@ arena_ralloc_no_move(void *ptr, size_t oldsize, size_t size, size_t extra,
 	 */
 	if (oldsize <= arena_maxclass) {
 		if (oldsize <= SMALL_MAXCLASS) {
-			assert(arena_bin_info[SMALL_SIZE2BIN(oldsize)].reg_size
+			assert(arena_bin_info[small_size2bin(oldsize)].reg_size
 			    == oldsize);
 			if ((size + extra <= SMALL_MAXCLASS &&
-			    SMALL_SIZE2BIN(size + extra) ==
-			    SMALL_SIZE2BIN(oldsize)) || (size <= oldsize &&
+			    small_size2bin(size + extra) ==
+			    small_size2bin(oldsize)) || (size <= oldsize &&
 			    size + extra >= oldsize))
 				return (false);
 		} else {
@@ -2222,7 +2312,7 @@ arena_ralloc(arena_t *arena, void *ptr, size_t oldsize, size_t size,
 	 * expectation that the extra bytes will be reliably preserved.
 	 */
 	copysize = (size < oldsize) ? size : oldsize;
-	VALGRIND_MAKE_MEM_UNDEFINED(ret, copysize);
+	JEMALLOC_VALGRIND_MAKE_MEM_UNDEFINED(ret, copysize);
 	memcpy(ret, ptr, copysize);
 	iqalloct(ptr, try_tcache_dalloc);
 	return (ret);
@@ -2239,13 +2329,16 @@ arena_dss_prec_get(arena_t *arena)
 	return (ret);
 }
 
-void
+bool
 arena_dss_prec_set(arena_t *arena, dss_prec_t dss_prec)
 {
 
+	if (have_dss == false)
+		return (dss_prec != dss_prec_disabled);
 	malloc_mutex_lock(&arena->lock);
 	arena->dss_prec = dss_prec;
 	malloc_mutex_unlock(&arena->lock);
+	return (false);
 }
 
 void
@@ -2268,6 +2361,10 @@ arena_stats_merge(arena_t *arena, const char **dss, size_t *nactive,
 	astats->nmalloc_large += arena->stats.nmalloc_large;
 	astats->ndalloc_large += arena->stats.ndalloc_large;
 	astats->nrequests_large += arena->stats.nrequests_large;
+	astats->allocated_huge += arena->stats.allocated_huge;
+	astats->nmalloc_huge += arena->stats.nmalloc_huge;
+	astats->ndalloc_huge += arena->stats.ndalloc_huge;
+	astats->nrequests_huge += arena->stats.nrequests_huge;
 
 	for (i = 0; i < nlclasses; i++) {
 		lstats[i].nmalloc += arena->stats.lstats[i].nmalloc;
@@ -2297,13 +2394,16 @@ arena_stats_merge(arena_t *arena, const char **dss, size_t *nactive,
 }
 
 bool
-arena_new(arena_t *arena, unsigned ind)
+arena_new(pool_t *pool, arena_t *arena, unsigned ind)
 {
 	unsigned i;
 	arena_bin_t *bin;
 
 	arena->ind = ind;
 	arena->nthreads = 0;
+	arena->chunk_alloc = chunk_alloc_default;
+	arena->chunk_dalloc = chunk_dalloc_default;
+	arena->pool = pool;
 
 	if (malloc_mutex_init(&arena->lock))
 		return (true);
@@ -2311,7 +2411,7 @@ arena_new(arena_t *arena, unsigned ind)
 	if (config_stats) {
 		memset(&arena->stats, 0, sizeof(arena_stats_t));
 		arena->stats.lstats =
-		    (malloc_large_stats_t *)base_alloc(nlclasses *
+		    (malloc_large_stats_t *)base_alloc(pool, nlclasses *
 		    sizeof(malloc_large_stats_t));
 		if (arena->stats.lstats == NULL)
 			return (true);
@@ -2369,7 +2469,6 @@ bin_info_run_size_calc(arena_bin_info_t *bin_info, size_t min_run_size)
 	uint32_t try_nregs, good_nregs;
 	uint32_t try_hdr_size, good_hdr_size;
 	uint32_t try_bitmap_offset, good_bitmap_offset;
-	uint32_t try_ctx0_offset, good_ctx0_offset;
 	uint32_t try_redzone0_offset, good_redzone0_offset;
 
 	assert(min_run_size >= PAGE);
@@ -2383,7 +2482,7 @@ bin_info_run_size_calc(arena_bin_info_t *bin_info, size_t min_run_size)
 	 * be twice as large in order to maintain alignment.
 	 */
 	if (config_fill && opt_redzone) {
-		size_t align_min = ZU(1) << (ffs(bin_info->reg_size) - 1);
+		size_t align_min = ZU(1) << (jemalloc_ffs(bin_info->reg_size) - 1);
 		if (align_min <= REDZONE_MINSIZE) {
 			bin_info->redzone_size = REDZONE_MINSIZE;
 			pad_size = 0;
@@ -2424,14 +2523,6 @@ bin_info_run_size_calc(arena_bin_info_t *bin_info, size_t min_run_size)
 		try_bitmap_offset = try_hdr_size;
 		/* Add space for bitmap. */
 		try_hdr_size += bitmap_size(try_nregs);
-		if (config_prof && opt_prof && prof_promote == false) {
-			/* Pad to a quantum boundary. */
-			try_hdr_size = QUANTUM_CEILING(try_hdr_size);
-			try_ctx0_offset = try_hdr_size;
-			/* Add space for one (prof_ctx_t *) per region. */
-			try_hdr_size += try_nregs * sizeof(prof_ctx_t *);
-		} else
-			try_ctx0_offset = 0;
 		try_redzone0_offset = try_run_size - (try_nregs *
 		    bin_info->reg_interval) - pad_size;
 	} while (try_hdr_size > try_redzone0_offset);
@@ -2445,7 +2536,6 @@ bin_info_run_size_calc(arena_bin_info_t *bin_info, size_t min_run_size)
 		good_nregs = try_nregs;
 		good_hdr_size = try_hdr_size;
 		good_bitmap_offset = try_bitmap_offset;
-		good_ctx0_offset = try_ctx0_offset;
 		good_redzone0_offset = try_redzone0_offset;
 
 		/* Try more aggressive settings. */
@@ -2465,16 +2555,6 @@ bin_info_run_size_calc(arena_bin_info_t *bin_info, size_t min_run_size)
 			try_bitmap_offset = try_hdr_size;
 			/* Add space for bitmap. */
 			try_hdr_size += bitmap_size(try_nregs);
-			if (config_prof && opt_prof && prof_promote == false) {
-				/* Pad to a quantum boundary. */
-				try_hdr_size = QUANTUM_CEILING(try_hdr_size);
-				try_ctx0_offset = try_hdr_size;
-				/*
-				 * Add space for one (prof_ctx_t *) per region.
-				 */
-				try_hdr_size += try_nregs *
-				    sizeof(prof_ctx_t *);
-			}
 			try_redzone0_offset = try_run_size - (try_nregs *
 			    bin_info->reg_interval) - pad_size;
 		} while (try_hdr_size > try_redzone0_offset);
@@ -2490,7 +2570,6 @@ bin_info_run_size_calc(arena_bin_info_t *bin_info, size_t min_run_size)
 	bin_info->run_size = good_run_size;
 	bin_info->nregs = good_nregs;
 	bin_info->bitmap_offset = good_bitmap_offset;
-	bin_info->ctx0_offset = good_ctx0_offset;
 	bin_info->reg0_offset = good_redzone0_offset + bin_info->redzone_size;
 
 	assert(bin_info->reg0_offset - bin_info->redzone_size + (bin_info->nregs
@@ -2505,13 +2584,18 @@ bin_info_init(void)
 	arena_bin_info_t *bin_info;
 	size_t prev_run_size = PAGE;
 
-#define	SIZE_CLASS(bin, delta, size)					\
-	bin_info = &arena_bin_info[bin];				\
+#define	BIN_INFO_INIT_bin_yes(index, size) \
+	bin_info = &arena_bin_info[index];				\
 	bin_info->reg_size = size;					\
 	prev_run_size = bin_info_run_size_calc(bin_info, prev_run_size);\
 	bitmap_info_init(&bin_info->bitmap_info, bin_info->nregs);
+#define	BIN_INFO_INIT_bin_no(index, size)
+#define	SC(index, lg_grp, lg_delta, ndelta, bin, lg_delta_lookup)	\
+	BIN_INFO_INIT_bin_##bin(index, (ZU(1)<<lg_grp) + (ZU(ndelta)<<lg_delta))
 	SIZE_CLASSES
-#undef SIZE_CLASS
+#undef BIN_INFO_INIT_bin_yes
+#undef BIN_INFO_INIT_bin_no
+#undef SC
 }
 
 void
diff --git a/src/jemalloc/src/base.c b/src/jemalloc/src/base.c
index 4e62e8fa9189fe9ebdcdbbe7e49e38c62cb5de62..91178eba61f73db790bc0f07ecaff0e9548df2da 100644
--- a/src/jemalloc/src/base.c
+++ b/src/jemalloc/src/base.c
@@ -1,49 +1,26 @@
 #define	JEMALLOC_BASE_C_
 #include "jemalloc/internal/jemalloc_internal.h"
 
-/******************************************************************************/
-/* Data. */
-
-static malloc_mutex_t	base_mtx;
-
-/*
- * Current pages that are being used for internal memory allocations.  These
- * pages are carved up in cacheline-size quanta, so that there is no chance of
- * false cache line sharing.
- */
-static void		*base_pages;
-static void		*base_next_addr;
-static void		*base_past_addr; /* Addr immediately past base_pages. */
-static extent_node_t	*base_nodes;
-
-/******************************************************************************/
-/* Function prototypes for non-inline static functions. */
-
-static bool	base_pages_alloc(size_t minsize);
-
-/******************************************************************************/
 
 static bool
-base_pages_alloc(size_t minsize)
+base_pages_alloc(pool_t *pool, size_t minsize)
 {
 	size_t csize;
-	bool zero;
+	void* base_pages;
 
 	assert(minsize != 0);
 	csize = CHUNK_CEILING(minsize);
-	zero = false;
-	base_pages = chunk_alloc(csize, chunksize, true, &zero,
-	    chunk_dss_prec_get());
+	base_pages = chunk_alloc_base(pool, csize);
 	if (base_pages == NULL)
 		return (true);
-	base_next_addr = base_pages;
-	base_past_addr = (void *)((uintptr_t)base_pages + csize);
+	pool->base_next_addr = base_pages;
+	pool->base_past_addr = (void *)((uintptr_t)base_pages + csize);
 
 	return (false);
 }
 
 void *
-base_alloc(size_t size)
+base_alloc(pool_t *pool, size_t size)
 {
 	void *ret;
 	size_t csize;
@@ -51,27 +28,27 @@ base_alloc(size_t size)
 	/* Round size up to nearest multiple of the cacheline size. */
 	csize = CACHELINE_CEILING(size);
 
-	malloc_mutex_lock(&base_mtx);
+	malloc_mutex_lock(&pool->base_mtx);
 	/* Make sure there's enough space for the allocation. */
-	if ((uintptr_t)base_next_addr + csize > (uintptr_t)base_past_addr) {
-		if (base_pages_alloc(csize)) {
-			malloc_mutex_unlock(&base_mtx);
+	if ((uintptr_t)pool->base_next_addr + csize > (uintptr_t)pool->base_past_addr) {
+		if (base_pages_alloc(pool, csize)) {
+			malloc_mutex_unlock(&pool->base_mtx);
 			return (NULL);
 		}
 	}
 	/* Allocate. */
-	ret = base_next_addr;
-	base_next_addr = (void *)((uintptr_t)base_next_addr + csize);
-	malloc_mutex_unlock(&base_mtx);
-	VALGRIND_MAKE_MEM_UNDEFINED(ret, csize);
+	ret = pool->base_next_addr;
+	pool->base_next_addr = (void *)((uintptr_t)pool->base_next_addr + csize);
+	malloc_mutex_unlock(&pool->base_mtx);
+	JEMALLOC_VALGRIND_MAKE_MEM_UNDEFINED(ret, csize);
 
 	return (ret);
 }
 
 void *
-base_calloc(size_t number, size_t size)
+base_calloc(pool_t *pool, size_t number, size_t size)
 {
-	void *ret = base_alloc(number * size);
+	void *ret = base_alloc(pool, number * size);
 
 	if (ret != NULL)
 		memset(ret, 0, number * size);
@@ -80,63 +57,88 @@ base_calloc(size_t number, size_t size)
 }
 
 extent_node_t *
-base_node_alloc(void)
+base_node_alloc(pool_t *pool)
 {
 	extent_node_t *ret;
 
-	malloc_mutex_lock(&base_mtx);
-	if (base_nodes != NULL) {
-		ret = base_nodes;
-		base_nodes = *(extent_node_t **)ret;
-		malloc_mutex_unlock(&base_mtx);
-		VALGRIND_MAKE_MEM_UNDEFINED(ret, sizeof(extent_node_t));
+	malloc_mutex_lock(&pool->base_node_mtx);
+	if (pool->base_nodes != NULL) {
+		ret = pool->base_nodes;
+		pool->base_nodes = *(extent_node_t **)ret;
+		JEMALLOC_VALGRIND_MAKE_MEM_UNDEFINED(ret,
+			sizeof(extent_node_t));
 	} else {
-		malloc_mutex_unlock(&base_mtx);
-		ret = (extent_node_t *)base_alloc(sizeof(extent_node_t));
+		/* preallocated nodes for pools other than 0 */
+		if (pool->pool_id == 0) {
+			ret = (extent_node_t *)base_alloc(pool, sizeof(extent_node_t));
+		} else {
+			ret = NULL;
+		}
 	}
-
+	malloc_mutex_unlock(&pool->base_node_mtx);
 	return (ret);
 }
 
 void
-base_node_dealloc(extent_node_t *node)
+base_node_dalloc(pool_t *pool, extent_node_t *node)
 {
 
-	VALGRIND_MAKE_MEM_UNDEFINED(node, sizeof(extent_node_t));
-	malloc_mutex_lock(&base_mtx);
-	*(extent_node_t **)node = base_nodes;
-	base_nodes = node;
-	malloc_mutex_unlock(&base_mtx);
+	JEMALLOC_VALGRIND_MAKE_MEM_UNDEFINED(node, sizeof(extent_node_t));
+	malloc_mutex_lock(&pool->base_node_mtx);
+	*(extent_node_t **)node = pool->base_nodes;
+	pool->base_nodes = node;
+	malloc_mutex_unlock(&pool->base_node_mtx);
+}
+
+size_t
+base_node_prealloc(pool_t *pool, size_t number)
+{
+	extent_node_t *node;
+	malloc_mutex_lock(&pool->base_node_mtx);
+	for (; number > 0; --number) {
+		node = (extent_node_t *)base_alloc(pool, sizeof(extent_node_t));
+		if (node == NULL)
+			break;
+		JEMALLOC_VALGRIND_MAKE_MEM_UNDEFINED(node, sizeof(extent_node_t));
+		*(extent_node_t **)node = pool->base_nodes;
+		pool->base_nodes = node;
+	}
+	malloc_mutex_unlock(&pool->base_node_mtx);
+
+	/* return number of nodes that couldn't be allocated */
+	return number;
 }
 
 bool
-base_boot(void)
+base_boot(pool_t *pool)
 {
+	pool->base_nodes = NULL;
+	if (malloc_mutex_init(&pool->base_mtx))
+		return (true);
 
-	base_nodes = NULL;
-	if (malloc_mutex_init(&base_mtx))
+	if (malloc_mutex_init(&pool->base_node_mtx))
 		return (true);
 
 	return (false);
 }
 
 void
-base_prefork(void)
+base_prefork(pool_t *pool)
 {
 
-	malloc_mutex_prefork(&base_mtx);
+	malloc_mutex_prefork(&pool->base_mtx);
 }
 
 void
-base_postfork_parent(void)
+base_postfork_parent(pool_t *pool)
 {
 
-	malloc_mutex_postfork_parent(&base_mtx);
+	malloc_mutex_postfork_parent(&pool->base_mtx);
 }
 
 void
-base_postfork_child(void)
+base_postfork_child(pool_t *pool)
 {
 
-	malloc_mutex_postfork_child(&base_mtx);
+	malloc_mutex_postfork_child(&pool->base_mtx);
 }
diff --git a/src/jemalloc/src/chunk.c b/src/jemalloc/src/chunk.c
index 90ab116ae5fa42e53070ff03d389ff22420a25c1..746c6bc0aa82c6eedb7a07d6a5e28eb8396cc957 100644
--- a/src/jemalloc/src/chunk.c
+++ b/src/jemalloc/src/chunk.c
@@ -7,21 +7,6 @@
 const char	*opt_dss = DSS_DEFAULT;
 size_t		opt_lg_chunk = LG_CHUNK_DEFAULT;
 
-malloc_mutex_t	chunks_mtx;
-chunk_stats_t	stats_chunks;
-
-/*
- * Trees of chunks that were previously allocated (trees differ only in node
- * ordering).  These are used when allocating chunks, in an attempt to re-use
- * address space.  Depending on function, different tree orderings are needed,
- * which is why there are two trees with the same contents.
- */
-static extent_tree_t	chunks_szad_mmap;
-static extent_tree_t	chunks_ad_mmap;
-static extent_tree_t	chunks_szad_dss;
-static extent_tree_t	chunks_ad_dss;
-
-rtree_t		*chunks_rtree;
 
 /* Various chunk-related settings. */
 size_t		chunksize;
@@ -31,18 +16,17 @@ size_t		map_bias;
 size_t		arena_maxclass; /* Max size class for arenas. */
 
 /******************************************************************************/
-/* Function prototypes for non-inline static functions. */
+/*
+ * Function prototypes for static functions that are referenced prior to
+ * definition.
+ */
 
-static void	*chunk_recycle(extent_tree_t *chunks_szad,
-    extent_tree_t *chunks_ad, size_t size, size_t alignment, bool base,
-    bool *zero);
-static void	chunk_record(extent_tree_t *chunks_szad,
-    extent_tree_t *chunks_ad, void *chunk, size_t size);
+static void chunk_dalloc_core(pool_t *pool, void *chunk, size_t size);
 
 /******************************************************************************/
 
 static void *
-chunk_recycle(extent_tree_t *chunks_szad, extent_tree_t *chunks_ad, size_t size,
+chunk_recycle(pool_t *pool, extent_tree_t *chunks_szad, extent_tree_t *chunks_ad, size_t size,
     size_t alignment, bool base, bool *zero)
 {
 	void *ret;
@@ -67,10 +51,10 @@ chunk_recycle(extent_tree_t *chunks_szad, extent_tree_t *chunks_ad, size_t size,
 		return (NULL);
 	key.addr = NULL;
 	key.size = alloc_size;
-	malloc_mutex_lock(&chunks_mtx);
+	malloc_mutex_lock(&pool->chunks_mtx);
 	node = extent_tree_szad_nsearch(chunks_szad, &key);
 	if (node == NULL) {
-		malloc_mutex_unlock(&chunks_mtx);
+		malloc_mutex_unlock(&pool->chunks_mtx);
 		return (NULL);
 	}
 	leadsize = ALIGNMENT_CEILING((uintptr_t)node->addr, alignment) -
@@ -101,13 +85,13 @@ chunk_recycle(extent_tree_t *chunks_szad, extent_tree_t *chunks_ad, size_t size,
 			 * deadlock, and if node allocation fails, deallocate
 			 * the result before returning an error.
 			 */
-			malloc_mutex_unlock(&chunks_mtx);
-			node = base_node_alloc();
+			malloc_mutex_unlock(&pool->chunks_mtx);
+			node = base_node_alloc(pool);
 			if (node == NULL) {
-				chunk_dealloc(ret, size, true);
+				chunk_dalloc_core(pool, ret, size);
 				return (NULL);
 			}
-			malloc_mutex_lock(&chunks_mtx);
+			malloc_mutex_lock(&pool->chunks_mtx);
 		}
 		node->addr = (void *)((uintptr_t)(ret) + size);
 		node->size = trailsize;
@@ -116,10 +100,10 @@ chunk_recycle(extent_tree_t *chunks_szad, extent_tree_t *chunks_ad, size_t size,
 		extent_tree_ad_insert(chunks_ad, node);
 		node = NULL;
 	}
-	malloc_mutex_unlock(&chunks_mtx);
+	malloc_mutex_unlock(&pool->chunks_mtx);
 
 	if (node != NULL)
-		base_node_dealloc(node);
+		base_node_dalloc(pool, node);
 	if (*zero) {
 		if (zeroed == false)
 			memset(ret, 0, size);
@@ -127,7 +111,7 @@ chunk_recycle(extent_tree_t *chunks_szad, extent_tree_t *chunks_ad, size_t size,
 			size_t i;
 			size_t *p = (size_t *)(uintptr_t)ret;
 
-			VALGRIND_MAKE_MEM_DEFINED(ret, size);
+			JEMALLOC_VALGRIND_MAKE_MEM_DEFINED(ret, size);
 			for (i = 0; i < size / sizeof(size_t); i++)
 				assert(p[i] == 0);
 		}
@@ -141,8 +125,8 @@ chunk_recycle(extent_tree_t *chunks_szad, extent_tree_t *chunks_ad, size_t size,
  * takes advantage of this to avoid demanding zeroed chunks, but taking
  * advantage of them if they are returned.
  */
-void *
-chunk_alloc(size_t size, size_t alignment, bool base, bool *zero,
+static void *
+chunk_alloc_core(pool_t *pool, size_t size, size_t alignment, bool base, bool *zero,
     dss_prec_t dss_prec)
 {
 	void *ret;
@@ -152,72 +136,132 @@ chunk_alloc(size_t size, size_t alignment, bool base, bool *zero,
 	assert(alignment != 0);
 	assert((alignment & chunksize_mask) == 0);
 
+	/* Custom pools can only use existing chunks. */
+	if (pool->pool_id != 0) {
+		return chunk_recycle(pool,
+			&pool->chunks_szad_mmap, &pool->chunks_ad_mmap,
+			size, alignment, false, zero);
+	}
+
 	/* "primary" dss. */
-	if (config_dss && dss_prec == dss_prec_primary) {
-		if ((ret = chunk_recycle(&chunks_szad_dss, &chunks_ad_dss, size,
+	if (have_dss && dss_prec == dss_prec_primary) {
+		if ((ret = chunk_recycle(pool, &pool->chunks_szad_dss, &pool->chunks_ad_dss, size,
 		    alignment, base, zero)) != NULL)
-			goto label_return;
+			return (ret);
 		if ((ret = chunk_alloc_dss(size, alignment, zero)) != NULL)
-			goto label_return;
+			return (ret);
 	}
 	/* mmap. */
-	if ((ret = chunk_recycle(&chunks_szad_mmap, &chunks_ad_mmap, size,
+	if ((ret = chunk_recycle(pool, &pool->chunks_szad_mmap, &pool->chunks_ad_mmap, size,
 	    alignment, base, zero)) != NULL)
-		goto label_return;
+		return (ret);
 	if ((ret = chunk_alloc_mmap(size, alignment, zero)) != NULL)
-		goto label_return;
+		return (ret);
 	/* "secondary" dss. */
-	if (config_dss && dss_prec == dss_prec_secondary) {
-		if ((ret = chunk_recycle(&chunks_szad_dss, &chunks_ad_dss, size,
+	if (have_dss && dss_prec == dss_prec_secondary) {
+		if ((ret = chunk_recycle(pool, &pool->chunks_szad_dss, &pool->chunks_ad_dss, size,
 		    alignment, base, zero)) != NULL)
-			goto label_return;
+			return (ret);
 		if ((ret = chunk_alloc_dss(size, alignment, zero)) != NULL)
-			goto label_return;
+			return (ret);
 	}
 
 	/* All strategies for allocation failed. */
-	ret = NULL;
-label_return:
-	if (ret != NULL) {
-		if (config_ivsalloc && base == false) {
-			if (rtree_set(chunks_rtree, (uintptr_t)ret, 1)) {
-				chunk_dealloc(ret, size, true);
-				return (NULL);
-			}
-		}
-		if (config_stats || config_prof) {
-			bool gdump;
-			malloc_mutex_lock(&chunks_mtx);
-			if (config_stats)
-				stats_chunks.nchunks += (size / chunksize);
-			stats_chunks.curchunks += (size / chunksize);
-			if (stats_chunks.curchunks > stats_chunks.highchunks) {
-				stats_chunks.highchunks =
-				    stats_chunks.curchunks;
-				if (config_prof)
-					gdump = true;
-			} else if (config_prof)
-				gdump = false;
-			malloc_mutex_unlock(&chunks_mtx);
-			if (config_prof && opt_prof && opt_prof_gdump && gdump)
-				prof_gdump();
-		}
-		if (config_valgrind)
-			VALGRIND_MAKE_MEM_UNDEFINED(ret, size);
+	return (NULL);
+}
+
+static bool
+chunk_register(pool_t *pool, void *chunk, size_t size, bool base)
+{
+	assert(chunk != NULL);
+	assert(CHUNK_ADDR2BASE(chunk) == chunk);
+
+	if (config_ivsalloc && base == false) {
+		if (rtree_set(pool->chunks_rtree, (uintptr_t)chunk, 1))
+			return (true);
+	}
+	if (config_stats || config_prof) {
+		bool gdump;
+		malloc_mutex_lock(&pool->chunks_mtx);
+		if (config_stats)
+			pool->stats_chunks.nchunks += (size / chunksize);
+		pool->stats_chunks.curchunks += (size / chunksize);
+		if (pool->stats_chunks.curchunks > pool->stats_chunks.highchunks) {
+			pool->stats_chunks.highchunks =
+			    pool->stats_chunks.curchunks;
+			if (config_prof)
+				gdump = true;
+		} else if (config_prof)
+			gdump = false;
+		malloc_mutex_unlock(&pool->chunks_mtx);
+		if (config_prof && opt_prof && opt_prof_gdump && gdump)
+			prof_gdump();
+	}
+	if (config_valgrind)
+		JEMALLOC_VALGRIND_MAKE_MEM_UNDEFINED(chunk, size);
+	return (false);
+}
+
+void *
+chunk_alloc_base(pool_t *pool, size_t size)
+{
+	void *ret;
+	bool zero;
+
+	zero = false;
+	ret = chunk_alloc_core(pool, size, chunksize, true, &zero,
+	    chunk_dss_prec_get());
+	if (ret == NULL)
+		return (NULL);
+	if (chunk_register(pool, ret, size, true)) {
+		chunk_dalloc_core(pool, ret, size);
+		return (NULL);
 	}
-	assert(CHUNK_ADDR2BASE(ret) == ret);
 	return (ret);
 }
 
-static void
-chunk_record(extent_tree_t *chunks_szad, extent_tree_t *chunks_ad, void *chunk,
-    size_t size)
+void *
+chunk_alloc_arena(chunk_alloc_t *chunk_alloc, chunk_dalloc_t *chunk_dalloc,
+	arena_t *arena, size_t size, size_t alignment, bool *zero)
+{
+	void *ret;
+
+	ret = chunk_alloc(size, alignment, zero,
+		arena->ind, arena->pool);
+	if (ret != NULL && chunk_register(arena->pool, ret, size, false)) {
+		chunk_dalloc(ret, size, arena->ind, arena->pool);
+		ret = NULL;
+	}
+
+	return (ret);
+}
+
+/* Default arena chunk allocation routine in the absence of user override. */
+void *
+chunk_alloc_default(size_t size, size_t alignment, bool *zero,
+    unsigned arena_ind, pool_t *pool)
+{
+	return (chunk_alloc_core(pool, size, alignment, false, zero,
+	    pool->arenas[arena_ind]->dss_prec));
+}
+
+void
+chunk_record(pool_t *pool, extent_tree_t *chunks_szad, extent_tree_t *chunks_ad, void *chunk,
+    size_t size, bool zeroed)
 {
 	bool unzeroed;
 	extent_node_t *xnode, *node, *prev, *xprev, key;
 
 	unzeroed = pages_purge(chunk, size);
-	VALGRIND_MAKE_MEM_NOACCESS(chunk, size);
+	JEMALLOC_VALGRIND_MAKE_MEM_NOACCESS(chunk, size);
+	
+	/*
+	 * If pages_purge() returned that the pages were zeroed
+	 * as a side effect of purging we can safely do this assignment.
+	 */
+	if (zeroed == false && unzeroed == false) {
+		zeroed = true;
+	}
 
 	/*
 	 * Allocate a node before acquiring chunks_mtx even though it might not
@@ -225,11 +269,11 @@ chunk_record(extent_tree_t *chunks_szad, extent_tree_t *chunks_ad, void *chunk,
 	 * be allocated, which could cause deadlock if chunks_mtx were already
 	 * held.
 	 */
-	xnode = base_node_alloc();
+	xnode = base_node_alloc(pool);
 	/* Use xprev to implement conditional deferred deallocation of prev. */
 	xprev = NULL;
 
-	malloc_mutex_lock(&chunks_mtx);
+	malloc_mutex_lock(&pool->chunks_mtx);
 	key.addr = (void *)((uintptr_t)chunk + size);
 	node = extent_tree_ad_nsearch(chunks_ad, &key);
 	/* Try to coalesce forward. */
@@ -242,7 +286,7 @@ chunk_record(extent_tree_t *chunks_szad, extent_tree_t *chunks_ad, void *chunk,
 		extent_tree_szad_remove(chunks_szad, node);
 		node->addr = chunk;
 		node->size += size;
-		node->zeroed = (node->zeroed && (unzeroed == false));
+		node->zeroed = (node->zeroed && zeroed);
 		extent_tree_szad_insert(chunks_szad, node);
 	} else {
 		/* Coalescing forward failed, so insert a new node. */
@@ -259,7 +303,7 @@ chunk_record(extent_tree_t *chunks_szad, extent_tree_t *chunks_ad, void *chunk,
 		xnode = NULL; /* Prevent deallocation below. */
 		node->addr = chunk;
 		node->size = size;
-		node->zeroed = (unzeroed == false);
+		node->zeroed = zeroed;
 		extent_tree_ad_insert(chunks_ad, node);
 		extent_tree_szad_insert(chunks_szad, node);
 	}
@@ -286,33 +330,33 @@ chunk_record(extent_tree_t *chunks_szad, extent_tree_t *chunks_ad, void *chunk,
 	}
 
 label_return:
-	malloc_mutex_unlock(&chunks_mtx);
+	malloc_mutex_unlock(&pool->chunks_mtx);
 	/*
 	 * Deallocate xnode and/or xprev after unlocking chunks_mtx in order to
 	 * avoid potential deadlock.
 	 */
 	if (xnode != NULL)
-		base_node_dealloc(xnode);
+		base_node_dalloc(pool, xnode);
 	if (xprev != NULL)
-		base_node_dealloc(xprev);
+		base_node_dalloc(pool, xprev);
 }
 
 void
-chunk_unmap(void *chunk, size_t size)
+chunk_unmap(pool_t *pool, void *chunk, size_t size)
 {
 	assert(chunk != NULL);
 	assert(CHUNK_ADDR2BASE(chunk) == chunk);
 	assert(size != 0);
 	assert((size & chunksize_mask) == 0);
 
-	if (config_dss && chunk_in_dss(chunk))
-		chunk_record(&chunks_szad_dss, &chunks_ad_dss, chunk, size);
-	else if (chunk_dealloc_mmap(chunk, size))
-		chunk_record(&chunks_szad_mmap, &chunks_ad_mmap, chunk, size);
+	if (have_dss && chunk_in_dss(chunk))
+		chunk_record(pool, &pool->chunks_szad_dss, &pool->chunks_ad_dss, chunk, size, false);
+	else if (chunk_dalloc_mmap(chunk, size))
+		chunk_record(pool, &pool->chunks_szad_mmap, &pool->chunks_ad_mmap, chunk, size, false);
 }
 
-void
-chunk_dealloc(void *chunk, size_t size, bool unmap)
+static void
+chunk_dalloc_core(pool_t *pool, void *chunk, size_t size)
 {
 
 	assert(chunk != NULL);
@@ -321,43 +365,52 @@ chunk_dealloc(void *chunk, size_t size, bool unmap)
 	assert((size & chunksize_mask) == 0);
 
 	if (config_ivsalloc)
-		rtree_set(chunks_rtree, (uintptr_t)chunk, 0);
+		rtree_set(pool->chunks_rtree, (uintptr_t)chunk, 0);
 	if (config_stats || config_prof) {
-		malloc_mutex_lock(&chunks_mtx);
-		assert(stats_chunks.curchunks >= (size / chunksize));
-		stats_chunks.curchunks -= (size / chunksize);
-		malloc_mutex_unlock(&chunks_mtx);
+		malloc_mutex_lock(&pool->chunks_mtx);
+		assert(pool->stats_chunks.curchunks >= (size / chunksize));
+		pool->stats_chunks.curchunks -= (size / chunksize);
+		malloc_mutex_unlock(&pool->chunks_mtx);
 	}
 
-	if (unmap)
-		chunk_unmap(chunk, size);
+	chunk_unmap(pool, chunk, size);
 }
 
+/* Default arena chunk deallocation routine in the absence of user override. */
 bool
-chunk_boot(void)
+chunk_dalloc_default(void *chunk, size_t size, unsigned arena_ind, pool_t *pool)
 {
+	chunk_dalloc_core(pool, chunk, size);
+	return (false);
+}
 
+void
+chunk_global_boot() {
 	/* Set variables according to the value of opt_lg_chunk. */
 	chunksize = (ZU(1) << opt_lg_chunk);
 	assert(chunksize >= PAGE);
 	chunksize_mask = chunksize - 1;
-	chunk_npages = (chunksize >> LG_PAGE);
+	chunk_npages = (chunksize >> LG_PAGE);	
+}
 
+bool
+chunk_boot(pool_t *pool)
+{
 	if (config_stats || config_prof) {
-		if (malloc_mutex_init(&chunks_mtx))
+		if (malloc_mutex_init(&pool->chunks_mtx))
 			return (true);
-		memset(&stats_chunks, 0, sizeof(chunk_stats_t));
+		memset(&pool->stats_chunks, 0, sizeof(chunk_stats_t));
 	}
-	if (config_dss && chunk_dss_boot())
+	if (have_dss && chunk_dss_boot())
 		return (true);
-	extent_tree_szad_new(&chunks_szad_mmap);
-	extent_tree_ad_new(&chunks_ad_mmap);
-	extent_tree_szad_new(&chunks_szad_dss);
-	extent_tree_ad_new(&chunks_ad_dss);
+	extent_tree_szad_new(&pool->chunks_szad_mmap);
+	extent_tree_ad_new(&pool->chunks_ad_mmap);
+	extent_tree_szad_new(&pool->chunks_szad_dss);
+	extent_tree_ad_new(&pool->chunks_ad_dss);
 	if (config_ivsalloc) {
-		chunks_rtree = rtree_new((ZU(1) << (LG_SIZEOF_PTR+3)) -
-		    opt_lg_chunk, base_alloc, NULL);
-		if (chunks_rtree == NULL)
+		pool->chunks_rtree = rtree_new((ZU(1) << (LG_SIZEOF_PTR+3)) -
+		    opt_lg_chunk, base_alloc, NULL, pool);
+		if (pool->chunks_rtree == NULL)
 			return (true);
 	}
 
@@ -365,31 +418,31 @@ chunk_boot(void)
 }
 
 void
-chunk_prefork(void)
+chunk_prefork(pool_t *pool)
 {
 
-	malloc_mutex_prefork(&chunks_mtx);
+	malloc_mutex_prefork(&pool->chunks_mtx);
 	if (config_ivsalloc)
-		rtree_prefork(chunks_rtree);
+		rtree_prefork(pool->chunks_rtree);
 	chunk_dss_prefork();
 }
 
 void
-chunk_postfork_parent(void)
+chunk_postfork_parent(pool_t *pool)
 {
 
 	chunk_dss_postfork_parent();
 	if (config_ivsalloc)
-		rtree_postfork_parent(chunks_rtree);
-	malloc_mutex_postfork_parent(&chunks_mtx);
+		rtree_postfork_parent(pool->chunks_rtree);
+	malloc_mutex_postfork_parent(&pool->chunks_mtx);
 }
 
 void
-chunk_postfork_child(void)
+chunk_postfork_child(pool_t *pool)
 {
 
 	chunk_dss_postfork_child();
 	if (config_ivsalloc)
-		rtree_postfork_child(chunks_rtree);
-	malloc_mutex_postfork_child(&chunks_mtx);
+		rtree_postfork_child(pool->chunks_rtree);
+	malloc_mutex_postfork_child(&pool->chunks_mtx);
 }
diff --git a/src/jemalloc/src/chunk_dss.c b/src/jemalloc/src/chunk_dss.c
index 510bb8bee8590121db55d4fc4413520df859bf62..8f5b0f30eb3c36bb3e2f1ebdfc76b8ffb0504778 100644
--- a/src/jemalloc/src/chunk_dss.c
+++ b/src/jemalloc/src/chunk_dss.c
@@ -32,7 +32,7 @@ static void *
 chunk_dss_sbrk(intptr_t increment)
 {
 
-#ifdef JEMALLOC_HAVE_SBRK
+#ifdef JEMALLOC_DSS
 	return (sbrk(increment));
 #else
 	not_implemented();
@@ -45,7 +45,7 @@ chunk_dss_prec_get(void)
 {
 	dss_prec_t ret;
 
-	if (config_dss == false)
+	if (have_dss == false)
 		return (dss_prec_disabled);
 	malloc_mutex_lock(&dss_mtx);
 	ret = dss_prec_default;
@@ -57,8 +57,8 @@ bool
 chunk_dss_prec_set(dss_prec_t dss_prec)
 {
 
-	if (config_dss == false)
-		return (true);
+	if (have_dss == false)
+		return (dss_prec != dss_prec_disabled);
 	malloc_mutex_lock(&dss_mtx);
 	dss_prec_default = dss_prec;
 	malloc_mutex_unlock(&dss_mtx);
@@ -69,8 +69,9 @@ void *
 chunk_alloc_dss(size_t size, size_t alignment, bool *zero)
 {
 	void *ret;
+	pool_t *base_pool = pools[0];
 
-	cassert(config_dss);
+	cassert(have_dss);
 	assert(size > 0 && (size & chunksize_mask) == 0);
 	assert(alignment > 0 && (alignment & chunksize_mask) == 0);
 
@@ -124,9 +125,10 @@ chunk_alloc_dss(size_t size, size_t alignment, bool *zero)
 				dss_max = dss_next;
 				malloc_mutex_unlock(&dss_mtx);
 				if (cpad_size != 0)
-					chunk_unmap(cpad, cpad_size);
+					chunk_unmap(base_pool, cpad, cpad_size);
 				if (*zero) {
-					VALGRIND_MAKE_MEM_UNDEFINED(ret, size);
+					JEMALLOC_VALGRIND_MAKE_MEM_UNDEFINED(
+					    ret, size);
 					memset(ret, 0, size);
 				}
 				return (ret);
@@ -143,7 +145,7 @@ chunk_in_dss(void *chunk)
 {
 	bool ret;
 
-	cassert(config_dss);
+	cassert(have_dss);
 
 	malloc_mutex_lock(&dss_mtx);
 	if ((uintptr_t)chunk >= (uintptr_t)dss_base
@@ -160,7 +162,7 @@ bool
 chunk_dss_boot(void)
 {
 
-	cassert(config_dss);
+	cassert(have_dss);
 
 	if (malloc_mutex_init(&dss_mtx))
 		return (true);
@@ -175,7 +177,7 @@ void
 chunk_dss_prefork(void)
 {
 
-	if (config_dss)
+	if (have_dss)
 		malloc_mutex_prefork(&dss_mtx);
 }
 
@@ -183,7 +185,7 @@ void
 chunk_dss_postfork_parent(void)
 {
 
-	if (config_dss)
+	if (have_dss)
 		malloc_mutex_postfork_parent(&dss_mtx);
 }
 
@@ -191,7 +193,7 @@ void
 chunk_dss_postfork_child(void)
 {
 
-	if (config_dss)
+	if (have_dss)
 		malloc_mutex_postfork_child(&dss_mtx);
 }
 
diff --git a/src/jemalloc/src/chunk_mmap.c b/src/jemalloc/src/chunk_mmap.c
index 2056d793f05314689751f71b0bbd3f65cb893912..65137b4181dd8e6988618150828ac75f47db3891 100644
--- a/src/jemalloc/src/chunk_mmap.c
+++ b/src/jemalloc/src/chunk_mmap.c
@@ -121,7 +121,7 @@ pages_purge(void *addr, size_t length)
 #ifdef _WIN32
 	VirtualAlloc(addr, length, MEM_RESET, PAGE_READWRITE);
 	unzeroed = true;
-#else
+#elif defined(JEMALLOC_HAVE_MADVISE)
 #  ifdef JEMALLOC_PURGE_MADVISE_DONTNEED
 #    define JEMALLOC_MADV_PURGE MADV_DONTNEED
 #    define JEMALLOC_MADV_ZEROS true
@@ -129,12 +129,15 @@ pages_purge(void *addr, size_t length)
 #    define JEMALLOC_MADV_PURGE MADV_FREE
 #    define JEMALLOC_MADV_ZEROS false
 #  else
-#    error "No method defined for purging unused dirty pages."
+#    error "No madvise(2) flag defined for purging unused dirty pages."
 #  endif
 	int err = madvise(addr, length, JEMALLOC_MADV_PURGE);
 	unzeroed = (JEMALLOC_MADV_ZEROS == false || err != 0);
 #  undef JEMALLOC_MADV_PURGE
 #  undef JEMALLOC_MADV_ZEROS
+#else
+	/* Last resort no-op. */
+	unzeroed = true;
 #endif
 	return (unzeroed);
 }
@@ -200,7 +203,7 @@ chunk_alloc_mmap(size_t size, size_t alignment, bool *zero)
 }
 
 bool
-chunk_dealloc_mmap(void *chunk, size_t size)
+chunk_dalloc_mmap(void *chunk, size_t size)
 {
 
 	if (config_munmap)
diff --git a/src/jemalloc/src/ctl.c b/src/jemalloc/src/ctl.c
index cc2c5aef570f293a04eb182c83af712e2012dbf8..553a446d62f796f95cdc0f346cb0ef5326b0ea43 100644
--- a/src/jemalloc/src/ctl.c
+++ b/src/jemalloc/src/ctl.c
@@ -1,5 +1,6 @@
 #define	JEMALLOC_CTL_C_
 #include "jemalloc/internal/jemalloc_internal.h"
+#include "jemalloc/internal/pool.h"
 
 /******************************************************************************/
 /* Data. */
@@ -9,10 +10,8 @@
  * - ctl_stats.*
  * - opt_prof_active
  */
-static malloc_mutex_t	ctl_mtx;
-static bool		ctl_initialized;
+static malloc_mutex_t	ctl_mtx; /* XXX seperate mutex for each pool? */
 static uint64_t		ctl_epoch;
-static ctl_stats_t	ctl_stats;
 
 /******************************************************************************/
 /* Helpers for named and indexed nodes. */
@@ -58,14 +57,17 @@ static void	ctl_arena_stats_amerge(ctl_arena_stats_t *cstats,
 static void	ctl_arena_stats_smerge(ctl_arena_stats_t *sstats,
     ctl_arena_stats_t *astats);
 static void	ctl_arena_refresh(arena_t *arena, unsigned i);
-static bool	ctl_grow(void);
+static bool	ctl_grow(pool_t *pool);
+static void	ctl_refresh_pool(pool_t *pool);
 static void	ctl_refresh(void);
+static bool	ctl_init_pool(pool_t *pool);
 static bool	ctl_init(void);
 static int	ctl_lookup(const char *name, ctl_node_t const **nodesp,
     size_t *mibp, size_t *depthp);
 
 CTL_PROTO(version)
 CTL_PROTO(epoch)
+INDEX_PROTO(thread_pool_i)
 CTL_PROTO(thread_tcache_enabled)
 CTL_PROTO(thread_tcache_flush)
 CTL_PROTO(thread_arena)
@@ -74,10 +76,8 @@ CTL_PROTO(thread_allocatedp)
 CTL_PROTO(thread_deallocated)
 CTL_PROTO(thread_deallocatedp)
 CTL_PROTO(config_debug)
-CTL_PROTO(config_dss)
 CTL_PROTO(config_fill)
 CTL_PROTO(config_lazy_lock)
-CTL_PROTO(config_mremap)
 CTL_PROTO(config_munmap)
 CTL_PROTO(config_prof)
 CTL_PROTO(config_prof_libgcc)
@@ -99,7 +99,6 @@ CTL_PROTO(opt_zero)
 CTL_PROTO(opt_quarantine)
 CTL_PROTO(opt_redzone)
 CTL_PROTO(opt_utrace)
-CTL_PROTO(opt_valgrind)
 CTL_PROTO(opt_xmalloc)
 CTL_PROTO(opt_tcache)
 CTL_PROTO(opt_lg_tcache_max)
@@ -113,8 +112,10 @@ CTL_PROTO(opt_prof_final)
 CTL_PROTO(opt_prof_leak)
 CTL_PROTO(opt_prof_accum)
 CTL_PROTO(arena_i_purge)
-static void	arena_purge(unsigned arena_ind);
+static void	arena_purge(pool_t *pool, unsigned arena_ind);
 CTL_PROTO(arena_i_dss)
+CTL_PROTO(arena_i_chunk_alloc)
+CTL_PROTO(arena_i_chunk_dalloc)
 INDEX_PROTO(arena_i)
 CTL_PROTO(arenas_bin_i_size)
 CTL_PROTO(arenas_bin_i_nregs)
@@ -130,7 +131,6 @@ CTL_PROTO(arenas_tcache_max)
 CTL_PROTO(arenas_nbins)
 CTL_PROTO(arenas_nhbins)
 CTL_PROTO(arenas_nlruns)
-CTL_PROTO(arenas_purge)
 CTL_PROTO(arenas_extend)
 CTL_PROTO(prof_active)
 CTL_PROTO(prof_dump)
@@ -138,9 +138,6 @@ CTL_PROTO(prof_interval)
 CTL_PROTO(stats_chunks_current)
 CTL_PROTO(stats_chunks_total)
 CTL_PROTO(stats_chunks_high)
-CTL_PROTO(stats_huge_allocated)
-CTL_PROTO(stats_huge_nmalloc)
-CTL_PROTO(stats_huge_ndalloc)
 CTL_PROTO(stats_arenas_i_small_allocated)
 CTL_PROTO(stats_arenas_i_small_nmalloc)
 CTL_PROTO(stats_arenas_i_small_ndalloc)
@@ -149,6 +146,10 @@ CTL_PROTO(stats_arenas_i_large_allocated)
 CTL_PROTO(stats_arenas_i_large_nmalloc)
 CTL_PROTO(stats_arenas_i_large_ndalloc)
 CTL_PROTO(stats_arenas_i_large_nrequests)
+CTL_PROTO(stats_arenas_i_huge_allocated)
+CTL_PROTO(stats_arenas_i_huge_nmalloc)
+CTL_PROTO(stats_arenas_i_huge_ndalloc)
+CTL_PROTO(stats_arenas_i_huge_nrequests)
 CTL_PROTO(stats_arenas_i_bins_j_allocated)
 CTL_PROTO(stats_arenas_i_bins_j_nmalloc)
 CTL_PROTO(stats_arenas_i_bins_j_ndalloc)
@@ -177,12 +178,16 @@ CTL_PROTO(stats_cactive)
 CTL_PROTO(stats_allocated)
 CTL_PROTO(stats_active)
 CTL_PROTO(stats_mapped)
+INDEX_PROTO(pool_i)
+CTL_PROTO(pools_npools)
+CTL_PROTO(pool_i_base)
+CTL_PROTO(pool_i_size)
 
 /******************************************************************************/
 /* mallctl tree. */
 
 /* Maximum tree depth. */
-#define	CTL_MAX_DEPTH	6
+#define	CTL_MAX_DEPTH	8
 
 #define	NAME(n)	{true},	n
 #define	CHILD(t, c)							\
@@ -201,9 +206,21 @@ static const ctl_named_node_t	tcache_node[] = {
 	{NAME("enabled"),	CTL(thread_tcache_enabled)},
 	{NAME("flush"),		CTL(thread_tcache_flush)}
 };
+static const ctl_named_node_t thread_pool_i_node[] = {
+	{NAME("arena"),		CTL(thread_arena)},
+};
+
+static const ctl_named_node_t super_thread_pool_i_node[] = {
+	{NAME(""),                      CHILD(named, thread_pool_i)}
+};
+
+static const ctl_indexed_node_t thread_pool_node[] = {
+	{INDEX(thread_pool_i)}
+};
+
 
 static const ctl_named_node_t	thread_node[] = {
-	{NAME("arena"),		CTL(thread_arena)},
+	{NAME("pool"),		CHILD(indexed, thread_pool)},
 	{NAME("allocated"),	CTL(thread_allocated)},
 	{NAME("allocatedp"),	CTL(thread_allocatedp)},
 	{NAME("deallocated"),	CTL(thread_deallocated)},
@@ -213,10 +230,8 @@ static const ctl_named_node_t	thread_node[] = {
 
 static const ctl_named_node_t	config_node[] = {
 	{NAME("debug"),			CTL(config_debug)},
-	{NAME("dss"),			CTL(config_dss)},
 	{NAME("fill"),			CTL(config_fill)},
 	{NAME("lazy_lock"),		CTL(config_lazy_lock)},
-	{NAME("mremap"),		CTL(config_mremap)},
 	{NAME("munmap"),		CTL(config_munmap)},
 	{NAME("prof"),			CTL(config_prof)},
 	{NAME("prof_libgcc"),		CTL(config_prof_libgcc)},
@@ -241,7 +256,6 @@ static const ctl_named_node_t opt_node[] = {
 	{NAME("quarantine"),		CTL(opt_quarantine)},
 	{NAME("redzone"),		CTL(opt_redzone)},
 	{NAME("utrace"),		CTL(opt_utrace)},
-	{NAME("valgrind"),		CTL(opt_valgrind)},
 	{NAME("xmalloc"),		CTL(opt_xmalloc)},
 	{NAME("tcache"),		CTL(opt_tcache)},
 	{NAME("lg_tcache_max"),		CTL(opt_lg_tcache_max)},
@@ -256,9 +270,15 @@ static const ctl_named_node_t opt_node[] = {
 	{NAME("prof_accum"),		CTL(opt_prof_accum)}
 };
 
+static const ctl_named_node_t chunk_node[] = {
+	{NAME("alloc"),			CTL(arena_i_chunk_alloc)},
+	{NAME("dalloc"),		CTL(arena_i_chunk_dalloc)}
+};
+
 static const ctl_named_node_t arena_i_node[] = {
 	{NAME("purge"),			CTL(arena_i_purge)},
-	{NAME("dss"),			CTL(arena_i_dss)}
+	{NAME("dss"),			CTL(arena_i_dss)},
+	{NAME("chunk"),			CHILD(named, chunk)},
 };
 static const ctl_named_node_t super_arena_i_node[] = {
 	{NAME(""),			CHILD(named, arena_i)}
@@ -303,7 +323,6 @@ static const ctl_named_node_t arenas_node[] = {
 	{NAME("bin"),			CHILD(indexed, arenas_bin)},
 	{NAME("nlruns"),		CTL(arenas_nlruns)},
 	{NAME("lrun"),			CHILD(indexed, arenas_lrun)},
-	{NAME("purge"),			CTL(arenas_purge)},
 	{NAME("extend"),		CTL(arenas_extend)}
 };
 
@@ -319,12 +338,6 @@ static const ctl_named_node_t stats_chunks_node[] = {
 	{NAME("high"),			CTL(stats_chunks_high)}
 };
 
-static const ctl_named_node_t stats_huge_node[] = {
-	{NAME("allocated"),		CTL(stats_huge_allocated)},
-	{NAME("nmalloc"),		CTL(stats_huge_nmalloc)},
-	{NAME("ndalloc"),		CTL(stats_huge_ndalloc)}
-};
-
 static const ctl_named_node_t stats_arenas_i_small_node[] = {
 	{NAME("allocated"),		CTL(stats_arenas_i_small_allocated)},
 	{NAME("nmalloc"),		CTL(stats_arenas_i_small_nmalloc)},
@@ -339,6 +352,13 @@ static const ctl_named_node_t stats_arenas_i_large_node[] = {
 	{NAME("nrequests"),		CTL(stats_arenas_i_large_nrequests)}
 };
 
+static const ctl_named_node_t stats_arenas_i_huge_node[] = {
+	{NAME("allocated"),		CTL(stats_arenas_i_huge_allocated)},
+	{NAME("nmalloc"),		CTL(stats_arenas_i_huge_nmalloc)},
+	{NAME("ndalloc"),		CTL(stats_arenas_i_huge_ndalloc)},
+	{NAME("nrequests"),		CTL(stats_arenas_i_huge_nrequests)},
+};
+
 static const ctl_named_node_t stats_arenas_i_bins_j_node[] = {
 	{NAME("allocated"),		CTL(stats_arenas_i_bins_j_allocated)},
 	{NAME("nmalloc"),		CTL(stats_arenas_i_bins_j_nmalloc)},
@@ -383,9 +403,11 @@ static const ctl_named_node_t stats_arenas_i_node[] = {
 	{NAME("purged"),		CTL(stats_arenas_i_purged)},
 	{NAME("small"),			CHILD(named, stats_arenas_i_small)},
 	{NAME("large"),			CHILD(named, stats_arenas_i_large)},
+	{NAME("huge"),			CHILD(named, stats_arenas_i_huge)},
 	{NAME("bins"),			CHILD(indexed, stats_arenas_i_bins)},
 	{NAME("lruns"),			CHILD(indexed, stats_arenas_i_lruns)}
 };
+
 static const ctl_named_node_t super_stats_arenas_i_node[] = {
 	{NAME(""),			CHILD(named, stats_arenas_i)}
 };
@@ -394,14 +416,33 @@ static const ctl_indexed_node_t stats_arenas_node[] = {
 	{INDEX(stats_arenas_i)}
 };
 
-static const ctl_named_node_t stats_node[] = {
+static const ctl_named_node_t pool_stats_node[] = {
+	{NAME("chunks"),		CHILD(named, stats_chunks)},
+	{NAME("arenas"),		CHILD(indexed, stats_arenas)},
 	{NAME("cactive"),		CTL(stats_cactive)},
 	{NAME("allocated"),		CTL(stats_allocated)},
 	{NAME("active"),		CTL(stats_active)},
-	{NAME("mapped"),		CTL(stats_mapped)},
-	{NAME("chunks"),		CHILD(named, stats_chunks)},
-	{NAME("huge"),			CHILD(named, stats_huge)},
-	{NAME("arenas"),		CHILD(indexed, stats_arenas)}
+	{NAME("mapped"),		CTL(stats_mapped)}
+};
+
+static const ctl_named_node_t pools_node[] = {
+	{NAME("npools"),               CTL(pools_npools)},
+};
+
+static const ctl_named_node_t pool_i_node[] = {
+	{NAME("mem_base"),      CTL(pool_i_base)},
+	{NAME("mem_size"),	CTL(pool_i_size)},
+	{NAME("arena"),		CHILD(indexed, arena)},
+	{NAME("arenas"),	CHILD(named, arenas)},
+	{NAME("stats"),		CHILD(named, pool_stats)}
+};
+
+static const ctl_named_node_t super_pool_i_node[] = {
+	{NAME(""),                      CHILD(named, pool_i)}
+};
+
+static const ctl_indexed_node_t pool_node[] = {
+	{INDEX(pool_i)}
 };
 
 static const ctl_named_node_t	root_node[] = {
@@ -410,10 +451,9 @@ static const ctl_named_node_t	root_node[] = {
 	{NAME("thread"),	CHILD(named, thread)},
 	{NAME("config"),	CHILD(named, config)},
 	{NAME("opt"),		CHILD(named, opt)},
-	{NAME("arena"),		CHILD(indexed, arena)},
-	{NAME("arenas"),	CHILD(named, arenas)},
-	{NAME("prof"),		CHILD(named, prof)},
-	{NAME("stats"),		CHILD(named, stats)}
+	{NAME("pool"),		CHILD(indexed, pool)},
+	{NAME("pools"),		CHILD(named, pools)},
+	{NAME("prof"),		CHILD(named, prof)}
 };
 static const ctl_named_node_t super_root_node[] = {
 	{NAME(""),		CHILD(named, root)}
@@ -429,9 +469,9 @@ static const ctl_named_node_t super_root_node[] = {
 static bool
 ctl_arena_init(ctl_arena_stats_t *astats)
 {
-
+	pool_t *pool = pools[0];
 	if (astats->lstats == NULL) {
-		astats->lstats = (malloc_large_stats_t *)base_alloc(nlclasses *
+		astats->lstats = (malloc_large_stats_t *)base_alloc(pool, nlclasses *
 		    sizeof(malloc_large_stats_t));
 		if (astats->lstats == NULL)
 			return (true);
@@ -498,6 +538,11 @@ ctl_arena_stats_smerge(ctl_arena_stats_t *sstats, ctl_arena_stats_t *astats)
 	sstats->astats.ndalloc_large += astats->astats.ndalloc_large;
 	sstats->astats.nrequests_large += astats->astats.nrequests_large;
 
+	sstats->astats.allocated_huge += astats->astats.allocated_huge;
+	sstats->astats.nmalloc_huge += astats->astats.nmalloc_huge;
+	sstats->astats.ndalloc_huge += astats->astats.ndalloc_huge;
+	sstats->astats.nrequests_huge += astats->astats.nrequests_huge;
+
 	for (i = 0; i < nlclasses; i++) {
 		sstats->lstats[i].nmalloc += astats->lstats[i].nmalloc;
 		sstats->lstats[i].ndalloc += astats->lstats[i].ndalloc;
@@ -524,8 +569,9 @@ ctl_arena_stats_smerge(ctl_arena_stats_t *sstats, ctl_arena_stats_t *astats)
 static void
 ctl_arena_refresh(arena_t *arena, unsigned i)
 {
-	ctl_arena_stats_t *astats = &ctl_stats.arenas[i];
-	ctl_arena_stats_t *sstats = &ctl_stats.arenas[ctl_stats.narenas];
+	pool_t *pool = arena->pool;
+	ctl_arena_stats_t *astats = &pool->ctl_stats.arenas[i];
+	ctl_arena_stats_t *sstats = &pool->ctl_stats.arenas[pool->ctl_stats.narenas];
 
 	ctl_arena_clear(astats);
 
@@ -544,17 +590,17 @@ ctl_arena_refresh(arena_t *arena, unsigned i)
 }
 
 static bool
-ctl_grow(void)
+ctl_grow(pool_t *pool)
 {
 	ctl_arena_stats_t *astats;
 	arena_t **tarenas;
 
 	/* Allocate extended arena stats and arenas arrays. */
-	astats = (ctl_arena_stats_t *)imalloc((ctl_stats.narenas + 2) *
+	astats = (ctl_arena_stats_t *)imalloc((pool->ctl_stats.narenas + 2) *
 	    sizeof(ctl_arena_stats_t));
 	if (astats == NULL)
 		return (true);
-	tarenas = (arena_t **)imalloc((ctl_stats.narenas + 1) *
+	tarenas = (arena_t **)imalloc((pool->ctl_stats.narenas + 1) *
 	    sizeof(arena_t *));
 	if (tarenas == NULL) {
 		idalloc(astats);
@@ -562,10 +608,10 @@ ctl_grow(void)
 	}
 
 	/* Initialize the new astats element. */
-	memcpy(astats, ctl_stats.arenas, (ctl_stats.narenas + 1) *
+	memcpy(astats, pool->ctl_stats.arenas, (pool->ctl_stats.narenas + 1) *
 	    sizeof(ctl_arena_stats_t));
-	memset(&astats[ctl_stats.narenas + 1], 0, sizeof(ctl_arena_stats_t));
-	if (ctl_arena_init(&astats[ctl_stats.narenas + 1])) {
+	memset(&astats[pool->ctl_stats.narenas + 1], 0, sizeof(ctl_arena_stats_t));
+	if (ctl_arena_init(&astats[pool->ctl_stats.narenas + 1])) {
 		idalloc(tarenas);
 		idalloc(astats);
 		return (true);
@@ -573,17 +619,17 @@ ctl_grow(void)
 	/* Swap merged stats to their new location. */
 	{
 		ctl_arena_stats_t tstats;
-		memcpy(&tstats, &astats[ctl_stats.narenas],
+		memcpy(&tstats, &astats[pool->ctl_stats.narenas],
 		    sizeof(ctl_arena_stats_t));
-		memcpy(&astats[ctl_stats.narenas],
-		    &astats[ctl_stats.narenas + 1], sizeof(ctl_arena_stats_t));
-		memcpy(&astats[ctl_stats.narenas + 1], &tstats,
+		memcpy(&astats[pool->ctl_stats.narenas],
+		    &astats[pool->ctl_stats.narenas + 1], sizeof(ctl_arena_stats_t));
+		memcpy(&astats[pool->ctl_stats.narenas + 1], &tstats,
 		    sizeof(ctl_arena_stats_t));
 	}
 	/* Initialize the new arenas element. */
-	tarenas[ctl_stats.narenas] = NULL;
+	tarenas[pool->ctl_stats.narenas] = NULL;
 	{
-		arena_t **arenas_old = arenas;
+		arena_t **arenas_old = pool->arenas;
 		/*
 		 * Swap extended arenas array into place.  Although ctl_mtx
 		 * protects this function from other threads extending the
@@ -592,126 +638,127 @@ ctl_grow(void)
 		 * point to them).  Therefore, array copying must happen under
 		 * the protection of arenas_lock.
 		 */
-		malloc_mutex_lock(&arenas_lock);
-		arenas = tarenas;
-		memcpy(arenas, arenas_old, ctl_stats.narenas *
+		malloc_mutex_lock(&pool->arenas_lock);
+		pool->arenas = tarenas;
+		memcpy(pool->arenas, arenas_old, pool->ctl_stats.narenas *
 		    sizeof(arena_t *));
-		narenas_total++;
-		arenas_extend(narenas_total - 1);
-		malloc_mutex_unlock(&arenas_lock);
+		pool->narenas_total++;
+		arenas_extend(pool, pool->narenas_total - 1);
+		malloc_mutex_unlock(&pool->arenas_lock);
 		/*
 		 * Deallocate arenas_old only if it came from imalloc() (not
 		 * base_alloc()).
 		 */
-		if (ctl_stats.narenas != narenas_auto)
+		if (pool->ctl_stats.narenas != pool->narenas_auto)
 			idalloc(arenas_old);
 	}
-	ctl_stats.arenas = astats;
-	ctl_stats.narenas++;
+	pool->ctl_stats.arenas = astats;
+	pool->ctl_stats.narenas++;
 
 	return (false);
 }
 
 static void
-ctl_refresh(void)
+ctl_refresh_pool(pool_t *pool)
 {
 	unsigned i;
-	VARIABLE_ARRAY(arena_t *, tarenas, ctl_stats.narenas);
+	VARIABLE_ARRAY(arena_t *, tarenas, pool->ctl_stats.narenas);
 
 	if (config_stats) {
-		malloc_mutex_lock(&chunks_mtx);
-		ctl_stats.chunks.current = stats_chunks.curchunks;
-		ctl_stats.chunks.total = stats_chunks.nchunks;
-		ctl_stats.chunks.high = stats_chunks.highchunks;
-		malloc_mutex_unlock(&chunks_mtx);
-
-		malloc_mutex_lock(&huge_mtx);
-		ctl_stats.huge.allocated = huge_allocated;
-		ctl_stats.huge.nmalloc = huge_nmalloc;
-		ctl_stats.huge.ndalloc = huge_ndalloc;
-		malloc_mutex_unlock(&huge_mtx);
+		malloc_mutex_lock(&pool->chunks_mtx);
+		pool->ctl_stats.chunks.current = pool->stats_chunks.curchunks;
+		pool->ctl_stats.chunks.total = pool->stats_chunks.nchunks;
+		pool->ctl_stats.chunks.high = pool->stats_chunks.highchunks;
+		malloc_mutex_unlock(&pool->chunks_mtx);
 	}
 
 	/*
 	 * Clear sum stats, since they will be merged into by
 	 * ctl_arena_refresh().
 	 */
-	ctl_stats.arenas[ctl_stats.narenas].nthreads = 0;
-	ctl_arena_clear(&ctl_stats.arenas[ctl_stats.narenas]);
-
-	malloc_mutex_lock(&arenas_lock);
-	memcpy(tarenas, arenas, sizeof(arena_t *) * ctl_stats.narenas);
-	for (i = 0; i < ctl_stats.narenas; i++) {
-		if (arenas[i] != NULL)
-			ctl_stats.arenas[i].nthreads = arenas[i]->nthreads;
+	pool->ctl_stats.arenas[pool->ctl_stats.narenas].nthreads = 0;
+	ctl_arena_clear(&pool->ctl_stats.arenas[pool->ctl_stats.narenas]);
+
+	malloc_mutex_lock(&pool->arenas_lock);
+	memcpy(tarenas, pool->arenas, sizeof(arena_t *) * pool->ctl_stats.narenas);
+	for (i = 0; i < pool->ctl_stats.narenas; i++) {
+		if (pool->arenas[i] != NULL)
+			pool->ctl_stats.arenas[i].nthreads = pool->arenas[i]->nthreads;
 		else
-			ctl_stats.arenas[i].nthreads = 0;
+			pool->ctl_stats.arenas[i].nthreads = 0;
 	}
-	malloc_mutex_unlock(&arenas_lock);
-	for (i = 0; i < ctl_stats.narenas; i++) {
+	malloc_mutex_unlock(&pool->arenas_lock);
+	for (i = 0; i < pool->ctl_stats.narenas; i++) {
 		bool initialized = (tarenas[i] != NULL);
 
-		ctl_stats.arenas[i].initialized = initialized;
+		pool->ctl_stats.arenas[i].initialized = initialized;
 		if (initialized)
 			ctl_arena_refresh(tarenas[i], i);
 	}
 
 	if (config_stats) {
-		ctl_stats.allocated =
-		    ctl_stats.arenas[ctl_stats.narenas].allocated_small
-		    + ctl_stats.arenas[ctl_stats.narenas].astats.allocated_large
-		    + ctl_stats.huge.allocated;
-		ctl_stats.active =
-		    (ctl_stats.arenas[ctl_stats.narenas].pactive << LG_PAGE)
-		    + ctl_stats.huge.allocated;
-		ctl_stats.mapped = (ctl_stats.chunks.current << opt_lg_chunk);
+		pool->ctl_stats_allocated =
+		    pool->ctl_stats.arenas[pool->ctl_stats.narenas].allocated_small
+		    + pool->ctl_stats.arenas[pool->ctl_stats.narenas].astats.allocated_large
+		    + pool->ctl_stats.arenas[pool->ctl_stats.narenas].astats.allocated_huge;
+		pool->ctl_stats_active =
+		    (pool->ctl_stats.arenas[pool->ctl_stats.narenas].pactive << LG_PAGE);
+		pool->ctl_stats_mapped = (pool->ctl_stats.chunks.current << opt_lg_chunk);
 	}
 
 	ctl_epoch++;
 }
 
+static void
+ctl_refresh(void)
+{
+	for (int i = 0; i < POOLS_MAX; ++i) {
+		if (pools[i] != NULL) {
+			ctl_refresh_pool(pools[i]);
+		}
+	}
+}
+
 static bool
-ctl_init(void)
+ctl_init_pool(pool_t *pool)
 {
 	bool ret;
 
-	malloc_mutex_lock(&ctl_mtx);
-	if (ctl_initialized == false) {
-		/*
-		 * Allocate space for one extra arena stats element, which
-		 * contains summed stats across all arenas.
-		 */
-		assert(narenas_auto == narenas_total_get());
-		ctl_stats.narenas = narenas_auto;
-		ctl_stats.arenas = (ctl_arena_stats_t *)base_alloc(
-		    (ctl_stats.narenas + 1) * sizeof(ctl_arena_stats_t));
-		if (ctl_stats.arenas == NULL) {
-			ret = true;
-			goto label_return;
-		}
-		memset(ctl_stats.arenas, 0, (ctl_stats.narenas + 1) *
-		    sizeof(ctl_arena_stats_t));
+	/*
+	 * Allocate space for one extra arena stats element, which
+	 * contains summed stats across all arenas.
+	 */
+	assert(pool->narenas_auto == narenas_total_get(pool));
+	pool->ctl_stats.narenas = pool->narenas_auto;
+	pool->ctl_stats.arenas = (ctl_arena_stats_t *)base_alloc(pool,
+	    (pool->ctl_stats.narenas + 1) * sizeof(ctl_arena_stats_t));
 
-		/*
-		 * Initialize all stats structures, regardless of whether they
-		 * ever get used.  Lazy initialization would allow errors to
-		 * cause inconsistent state to be viewable by the application.
-		 */
-		if (config_stats) {
-			unsigned i;
-			for (i = 0; i <= ctl_stats.narenas; i++) {
-				if (ctl_arena_init(&ctl_stats.arenas[i])) {
-					ret = true;
-					goto label_return;
-				}
+	if (pool->ctl_stats.arenas == NULL) {
+		ret = true;
+		goto label_return;
+	}
+	memset(pool->ctl_stats.arenas, 0, (pool->ctl_stats.narenas + 1) *
+	    sizeof(ctl_arena_stats_t));
+
+	/*
+	 * Initialize all stats structures, regardless of whether they
+	 * ever get used.  Lazy initialization would allow errors to
+	 * cause inconsistent state to be viewable by the application.
+	 */
+	if (config_stats) {
+		unsigned i;
+		for (i = 0; i <= pool->ctl_stats.narenas; i++) {
+			if (ctl_arena_init(&pool->ctl_stats.arenas[i])) {
+				ret = true;
+				goto label_return;
 			}
 		}
-		ctl_stats.arenas[ctl_stats.narenas].initialized = true;
-
-		ctl_epoch = 0;
-		ctl_refresh();
-		ctl_initialized = true;
 	}
+	pool->ctl_stats.arenas[pool->ctl_stats.narenas].initialized = true;
+
+	ctl_epoch = 0;
+	ctl_refresh_pool(pool);
+	pool->ctl_initialized = true;
 
 	ret = false;
 label_return:
@@ -719,6 +766,27 @@ label_return:
 	return (ret);
 }
 
+static bool
+ctl_init(void)
+{
+	bool ret;
+	malloc_mutex_lock(&ctl_mtx);
+	for (int i = 0; i < POOLS_MAX; ++i) {
+		if (pools[i] != NULL && pools[i]->ctl_initialized == false) {
+			if (ctl_init_pool(pools[i])) {
+				ret = true;
+				goto label_return;
+			}
+		}
+	}
+	/* false means that functions ends with success */
+	ret = false;
+
+label_return:
+	malloc_mutex_unlock(&ctl_mtx);
+	return (ret);
+}
+
 static int
 ctl_lookup(const char *name, ctl_node_t const **nodesp, size_t *mibp,
     size_t *depthp)
@@ -826,7 +894,7 @@ ctl_byname(const char *name, void *oldp, size_t *oldlenp, void *newp,
 	size_t mib[CTL_MAX_DEPTH];
 	const ctl_named_node_t *node;
 
-	if (ctl_initialized == false && ctl_init()) {
+	if (ctl_init()) {
 		ret = EAGAIN;
 		goto label_return;
 	}
@@ -853,7 +921,7 @@ ctl_nametomib(const char *name, size_t *mibp, size_t *miblenp)
 {
 	int ret;
 
-	if (ctl_initialized == false && ctl_init()) {
+	if (ctl_init()) {
 		ret = EAGAIN;
 		goto label_return;
 	}
@@ -871,7 +939,7 @@ ctl_bymib(const size_t *mib, size_t miblen, void *oldp, size_t *oldlenp,
 	const ctl_named_node_t *node;
 	size_t i;
 
-	if (ctl_initialized == false && ctl_init()) {
+	if (ctl_init()) {
 		ret = EAGAIN;
 		goto label_return;
 	}
@@ -920,8 +988,6 @@ ctl_boot(void)
 	if (malloc_mutex_init(&ctl_mtx))
 		return (true);
 
-	ctl_initialized = false;
-
 	return (false);
 }
 
@@ -1136,10 +1202,8 @@ label_return:
 /******************************************************************************/
 
 CTL_RO_BOOL_CONFIG_GEN(config_debug)
-CTL_RO_BOOL_CONFIG_GEN(config_dss)
 CTL_RO_BOOL_CONFIG_GEN(config_fill)
 CTL_RO_BOOL_CONFIG_GEN(config_lazy_lock)
-CTL_RO_BOOL_CONFIG_GEN(config_mremap)
 CTL_RO_BOOL_CONFIG_GEN(config_munmap)
 CTL_RO_BOOL_CONFIG_GEN(config_prof)
 CTL_RO_BOOL_CONFIG_GEN(config_prof_libgcc)
@@ -1164,7 +1228,6 @@ CTL_RO_NL_CGEN(config_fill, opt_quarantine, opt_quarantine, size_t)
 CTL_RO_NL_CGEN(config_fill, opt_redzone, opt_redzone, bool)
 CTL_RO_NL_CGEN(config_fill, opt_zero, opt_zero, bool)
 CTL_RO_NL_CGEN(config_utrace, opt_utrace, opt_utrace, bool)
-CTL_RO_NL_CGEN(config_valgrind, opt_valgrind, opt_valgrind, bool)
 CTL_RO_NL_CGEN(config_xmalloc, opt_xmalloc, opt_xmalloc, bool)
 CTL_RO_NL_CGEN(config_tcache, opt_tcache, opt_tcache, bool)
 CTL_RO_NL_CGEN(config_tcache, opt_lg_tcache_max, opt_lg_tcache_max, ssize_t)
@@ -1186,43 +1249,60 @@ thread_arena_ctl(const size_t *mib, size_t miblen, void *oldp, size_t *oldlenp,
 {
 	int ret;
 	unsigned newind, oldind;
+	unsigned pool_ind = mib[1];
+	pool_t *pool;
+	arena_t dummy;
+	if (pool_ind >= POOLS_MAX) {
+		ret = ENOENT;
+		goto label_return;
+	}
+	pool = pools[pool_ind];
+	DUMMY_ARENA_INITIALIZE(dummy, pool);
+	tsd_tcache_t *tcache_tsd = tcache_tsd_get();
 
 	malloc_mutex_lock(&ctl_mtx);
-	newind = oldind = choose_arena(NULL)->ind;
+	newind = oldind = choose_arena(&dummy)->ind;
 	WRITE(newind, unsigned);
 	READ(oldind, unsigned);
 	if (newind != oldind) {
 		arena_t *arena;
+		tsd_pool_t *tsd;
 
-		if (newind >= ctl_stats.narenas) {
+		if (newind >= pool->ctl_stats.narenas) {
 			/* New arena index is out of range. */
 			ret = EFAULT;
 			goto label_return;
 		}
 
 		/* Initialize arena if necessary. */
-		malloc_mutex_lock(&arenas_lock);
-		if ((arena = arenas[newind]) == NULL && (arena =
-		    arenas_extend(newind)) == NULL) {
-			malloc_mutex_unlock(&arenas_lock);
+		malloc_mutex_lock(&pool->arenas_lock);
+		if ((arena = pool->arenas[newind]) == NULL && (arena =
+		    arenas_extend(pool, newind)) == NULL) {
+			malloc_mutex_unlock(&pool->arenas_lock);
 			ret = EAGAIN;
 			goto label_return;
 		}
-		assert(arena == arenas[newind]);
-		arenas[oldind]->nthreads--;
-		arenas[newind]->nthreads++;
-		malloc_mutex_unlock(&arenas_lock);
+		assert(arena == pool->arenas[newind]);
+		pool->arenas[oldind]->nthreads--;
+		pool->arenas[newind]->nthreads++;
+		malloc_mutex_unlock(&pool->arenas_lock);
 
 		/* Set new arena association. */
 		if (config_tcache) {
-			tcache_t *tcache;
-			if ((uintptr_t)(tcache = *tcache_tsd_get()) >
-			    (uintptr_t)TCACHE_STATE_MAX) {
-				tcache_arena_dissociate(tcache);
+			tcache_t *tcache = tcache_tsd->tcaches[pool->pool_id];
+			if ((uintptr_t)(tcache) > (uintptr_t)TCACHE_STATE_MAX) {
+
+				if(tcache_tsd->seqno[pool->pool_id] == pool->seqno)
+					tcache_arena_dissociate(tcache);
+
 				tcache_arena_associate(tcache, arena);
+				tcache_tsd->seqno[pool->pool_id] = pool->seqno;
 			}
 		}
-		arenas_tsd_set(&arena);
+
+		tsd = arenas_tsd_get();
+		tsd->seqno[0] = pool->seqno;
+		tsd->arenas[0] = arena;
 	}
 
 	ret = 0;
@@ -1271,13 +1351,15 @@ thread_tcache_flush_ctl(const size_t *mib, size_t miblen, void *oldp,
 {
 	int ret;
 
+	pool_t *pool = pools[0];
+
 	if (config_tcache == false)
 		return (ENOENT);
 
 	READONLY();
 	WRITEONLY();
 
-	tcache_flush();
+	tcache_flush(pool);
 
 	ret = 0;
 label_return:
@@ -1288,22 +1370,22 @@ label_return:
 
 /* ctl_mutex must be held during execution of this function. */
 static void
-arena_purge(unsigned arena_ind)
+arena_purge(pool_t *pool, unsigned arena_ind)
 {
-	VARIABLE_ARRAY(arena_t *, tarenas, ctl_stats.narenas);
+	VARIABLE_ARRAY(arena_t *, tarenas, pool->ctl_stats.narenas);
 
-	malloc_mutex_lock(&arenas_lock);
-	memcpy(tarenas, arenas, sizeof(arena_t *) * ctl_stats.narenas);
-	malloc_mutex_unlock(&arenas_lock);
+	malloc_mutex_lock(&pool->arenas_lock);
+	memcpy(tarenas, pool->arenas, sizeof(arena_t *) * pool->ctl_stats.narenas);
+	malloc_mutex_unlock(&pool->arenas_lock);
 
-	if (arena_ind == ctl_stats.narenas) {
+	if (arena_ind == pool->ctl_stats.narenas) {
 		unsigned i;
-		for (i = 0; i < ctl_stats.narenas; i++) {
+		for (i = 0; i < pool->ctl_stats.narenas; i++) {
 			if (tarenas[i] != NULL)
 				arena_purge_all(tarenas[i]);
 		}
 	} else {
-		assert(arena_ind < ctl_stats.narenas);
+		assert(arena_ind < pool->ctl_stats.narenas);
 		if (tarenas[arena_ind] != NULL)
 			arena_purge_all(tarenas[arena_ind]);
 	}
@@ -1315,10 +1397,15 @@ arena_i_purge_ctl(const size_t *mib, size_t miblen, void *oldp, size_t *oldlenp,
 {
 	int ret;
 
+	if (mib[1] >= POOLS_MAX) {
+		ret = ENOENT;
+		goto label_return;
+	}
+
 	READONLY();
 	WRITEONLY();
 	malloc_mutex_lock(&ctl_mtx);
-	arena_purge(mib[1]);
+	arena_purge(pools[mib[1]], mib[3]);
 	malloc_mutex_unlock(&ctl_mtx);
 
 	ret = 0;
@@ -1333,11 +1420,19 @@ arena_i_dss_ctl(const size_t *mib, size_t miblen, void *oldp, size_t *oldlenp,
 	int ret, i;
 	bool match, err;
 	const char *dss;
-	unsigned arena_ind = mib[1];
+	unsigned pool_ind = mib[1];
+	unsigned arena_ind = mib[3];
 	dss_prec_t dss_prec_old = dss_prec_limit;
 	dss_prec_t dss_prec = dss_prec_limit;
+	pool_t *pool;
+
+	if (pool_ind >= POOLS_MAX) {
+		ret = ENOENT;
+		goto label_return;
+	}
 
 	malloc_mutex_lock(&ctl_mtx);
+	pool = pools[pool_ind];
 	WRITE(dss, const char *);
 	match = false;
 	for (i = 0; i < dss_prec_limit; i++) {
@@ -1352,12 +1447,11 @@ arena_i_dss_ctl(const size_t *mib, size_t miblen, void *oldp, size_t *oldlenp,
 		goto label_return;
 	}
 
-	if (arena_ind < ctl_stats.narenas) {
-		arena_t *arena = arenas[arena_ind];
+	if (arena_ind < pool->ctl_stats.narenas) {
+		arena_t *arena = pool->arenas[arena_ind];
 		if (arena != NULL) {
 			dss_prec_old = arena_dss_prec_get(arena);
-			arena_dss_prec_set(arena, dss_prec);
-			err = false;
+			err = arena_dss_prec_set(arena, dss_prec);
 		} else
 			err = true;
 	} else {
@@ -1377,13 +1471,80 @@ label_return:
 	return (ret);
 }
 
+static int
+arena_i_chunk_alloc_ctl(const size_t *mib, size_t miblen, void *oldp,
+    size_t *oldlenp, void *newp, size_t newlen)
+{
+	int ret;
+	unsigned pool_ind = mib[1];
+	unsigned arena_ind = mib[3];
+	arena_t *arena;
+	pool_t *pool;
+
+	if (pool_ind >= POOLS_MAX) {
+		ret = ENOENT;
+		goto label_outer_return;
+	}
+
+	malloc_mutex_lock(&ctl_mtx);
+	pool = pools[pool_ind];
+	if (arena_ind < pool->narenas_total && (arena = pool->arenas[arena_ind]) != NULL) {
+		malloc_mutex_lock(&arena->lock);
+		READ(arena->chunk_alloc, chunk_alloc_t *);
+		WRITE(arena->chunk_alloc, chunk_alloc_t *);
+	} else {
+		ret = EFAULT;
+		goto label_outer_return;
+	}
+	ret = 0;
+label_return:
+	malloc_mutex_unlock(&arena->lock);
+label_outer_return:
+	malloc_mutex_unlock(&ctl_mtx);
+	return (ret);
+}
+
+static int
+arena_i_chunk_dalloc_ctl(const size_t *mib, size_t miblen, void *oldp,
+    size_t *oldlenp, void *newp, size_t newlen)
+{
+
+	int ret;
+	unsigned pool_ind = mib[1];
+	unsigned arena_ind = mib[3];
+	arena_t *arena;
+	pool_t *pool;
+
+	if (pool_ind >= POOLS_MAX) {
+		ret = ENOENT;
+		goto label_outer_return;
+	}
+
+	malloc_mutex_lock(&ctl_mtx);
+	pool = pools[pool_ind];
+	if (arena_ind < pool->narenas_total && (arena = pool->arenas[arena_ind]) != NULL) {
+		malloc_mutex_lock(&arena->lock);
+		READ(arena->chunk_dalloc, chunk_dalloc_t *);
+		WRITE(arena->chunk_dalloc, chunk_dalloc_t *);
+	} else {
+		ret = EFAULT;
+		goto label_outer_return;
+	}
+	ret = 0;
+label_return:
+	malloc_mutex_unlock(&arena->lock);
+label_outer_return:
+	malloc_mutex_unlock(&ctl_mtx);
+	return (ret);
+}
+
 static const ctl_named_node_t *
 arena_i_index(const size_t *mib, size_t miblen, size_t i)
 {
 	const ctl_named_node_t * ret;
 
 	malloc_mutex_lock(&ctl_mtx);
-	if (i > ctl_stats.narenas) {
+	if (i > pools[mib[1]]->ctl_stats.narenas) {
 		ret = NULL;
 		goto label_return;
 	}
@@ -1409,7 +1570,7 @@ arenas_narenas_ctl(const size_t *mib, size_t miblen, void *oldp,
 		ret = EINVAL;
 		goto label_return;
 	}
-	narenas = ctl_stats.narenas;
+	narenas = pools[mib[1]]->ctl_stats.narenas;
 	READ(narenas, unsigned);
 
 	ret = 0;
@@ -1424,20 +1585,22 @@ arenas_initialized_ctl(const size_t *mib, size_t miblen, void *oldp,
 {
 	int ret;
 	unsigned nread, i;
+	pool_t *pool;
 
 	malloc_mutex_lock(&ctl_mtx);
 	READONLY();
-	if (*oldlenp != ctl_stats.narenas * sizeof(bool)) {
+	pool = pools[mib[1]];
+	if (*oldlenp != pool->ctl_stats.narenas * sizeof(bool)) {
 		ret = EINVAL;
-		nread = (*oldlenp < ctl_stats.narenas * sizeof(bool))
-		    ? (*oldlenp / sizeof(bool)) : ctl_stats.narenas;
+		nread = (*oldlenp < pool->ctl_stats.narenas * sizeof(bool))
+		    ? (*oldlenp / sizeof(bool)) : pool->ctl_stats.narenas;
 	} else {
 		ret = 0;
-		nread = ctl_stats.narenas;
+		nread = pool->ctl_stats.narenas;
 	}
 
 	for (i = 0; i < nread; i++)
-		((bool *)oldp)[i] = ctl_stats.arenas[i].initialized;
+		((bool *)oldp)[i] = pool->ctl_stats.arenas[i].initialized;
 
 label_return:
 	malloc_mutex_unlock(&ctl_mtx);
@@ -1449,9 +1612,9 @@ CTL_RO_NL_GEN(arenas_page, PAGE, size_t)
 CTL_RO_NL_CGEN(config_tcache, arenas_tcache_max, tcache_maxclass, size_t)
 CTL_RO_NL_GEN(arenas_nbins, NBINS, unsigned)
 CTL_RO_NL_CGEN(config_tcache, arenas_nhbins, nhbins, unsigned)
-CTL_RO_NL_GEN(arenas_bin_i_size, arena_bin_info[mib[2]].reg_size, size_t)
-CTL_RO_NL_GEN(arenas_bin_i_nregs, arena_bin_info[mib[2]].nregs, uint32_t)
-CTL_RO_NL_GEN(arenas_bin_i_run_size, arena_bin_info[mib[2]].run_size, size_t)
+CTL_RO_NL_GEN(arenas_bin_i_size, arena_bin_info[mib[4]].reg_size, size_t)
+CTL_RO_NL_GEN(arenas_bin_i_nregs, arena_bin_info[mib[4]].nregs, uint32_t)
+CTL_RO_NL_GEN(arenas_bin_i_run_size, arena_bin_info[mib[4]].run_size, size_t)
 static const ctl_named_node_t *
 arenas_bin_i_index(const size_t *mib, size_t miblen, size_t i)
 {
@@ -1462,7 +1625,7 @@ arenas_bin_i_index(const size_t *mib, size_t miblen, size_t i)
 }
 
 CTL_RO_NL_GEN(arenas_nlruns, nlclasses, size_t)
-CTL_RO_NL_GEN(arenas_lrun_i_size, ((mib[2]+1) << LG_PAGE), size_t)
+CTL_RO_NL_GEN(arenas_lrun_i_size, ((mib[4]+1) << LG_PAGE), size_t)
 static const ctl_named_node_t *
 arenas_lrun_i_index(const size_t *mib, size_t miblen, size_t i)
 {
@@ -1473,52 +1636,121 @@ arenas_lrun_i_index(const size_t *mib, size_t miblen, size_t i)
 }
 
 static int
-arenas_purge_ctl(const size_t *mib, size_t miblen, void *oldp, size_t *oldlenp,
+arenas_extend_ctl(const size_t *mib, size_t miblen, void *oldp, size_t *oldlenp,
     void *newp, size_t newlen)
 {
 	int ret;
-	unsigned arena_ind;
+	unsigned narenas;
+	unsigned pool_ind = mib[1];
+	pool_t *pool;
+
+	if (pool_ind >= POOLS_MAX) {
+		ret = ENOENT;
+		goto label_return;
+	}
+	pool = pools[pool_ind];
 
 	malloc_mutex_lock(&ctl_mtx);
-	WRITEONLY();
-	arena_ind = UINT_MAX;
-	WRITE(arena_ind, unsigned);
-	if (newp != NULL && arena_ind >= ctl_stats.narenas)
-		ret = EFAULT;
-	else {
-		if (arena_ind == UINT_MAX)
-			arena_ind = ctl_stats.narenas;
-		arena_purge(arena_ind);
-		ret = 0;
+	READONLY();
+	if (ctl_grow(pool)) {
+		ret = EAGAIN;
+		goto label_return;
 	}
+	narenas = pool->ctl_stats.narenas - 1;
+	READ(narenas, unsigned);
 
+	ret = 0;
 label_return:
 	malloc_mutex_unlock(&ctl_mtx);
 	return (ret);
 }
 
+/**
+ * @stub
+ */
 static int
-arenas_extend_ctl(const size_t *mib, size_t miblen, void *oldp, size_t *oldlenp,
+pools_npools_ctl(const size_t *mib, size_t miblen, void *oldp, size_t *oldlenp,
     void *newp, size_t newlen)
 {
-	int ret;
-	unsigned narenas;
+       int ret;
+       unsigned _npools;
+
+       malloc_mutex_lock(&ctl_mtx);
+       READONLY();
+       if (*oldlenp != sizeof(unsigned)) {
+               ret = EINVAL;
+               goto label_return;
+       }
+       _npools = npools;
+       READ(_npools, unsigned);
+
+       ret = 0;
+label_return:
+       malloc_mutex_unlock(&ctl_mtx);
+       return (ret);
+}
 
-	malloc_mutex_lock(&ctl_mtx);
-	READONLY();
-	if (ctl_grow()) {
-		ret = EAGAIN;
-		goto label_return;
-	}
-	narenas = ctl_stats.narenas - 1;
-	READ(narenas, unsigned);
+/**
+ * @stub
+ */
+static int
+pool_i_base_ctl(const size_t *mib, size_t miblen, void *oldp, size_t *oldlenp,
+    void *newp, size_t newlen)
+{
+       int ret;
 
-	ret = 0;
+       READONLY();
+       WRITEONLY();
+       malloc_mutex_lock(&ctl_mtx);
+       //TODO
+       malloc_mutex_unlock(&ctl_mtx);
+
+       ret = 0;
 label_return:
-	malloc_mutex_unlock(&ctl_mtx);
-	return (ret);
+       return (ret);
+}
+
+/**
+ * @stub
+ */
+static int
+pool_i_size_ctl(const size_t *mib, size_t miblen, void *oldp, size_t *oldlenp,
+    void *newp, size_t newlen)
+{
+       int ret;
+
+       READONLY();
+       WRITEONLY();
+       malloc_mutex_lock(&ctl_mtx);
+       //TODO
+       malloc_mutex_unlock(&ctl_mtx);
+
+       ret = 0;
+label_return:
+       return (ret);
+}
+
+/**
+ * @stub
+ */
+static const ctl_named_node_t *
+pool_i_index(const size_t *mib, size_t miblen, size_t i)
+{
+       const ctl_named_node_t * ret;
+
+       malloc_mutex_lock(&ctl_mtx);
+       if (i > POOLS_MAX) {
+               ret = NULL;
+               goto label_return;
+       }
+
+       ret = super_pool_i_node;
+label_return:
+       malloc_mutex_unlock(&ctl_mtx);
+       return (ret);
 }
 
+
 /******************************************************************************/
 
 static int
@@ -1576,68 +1808,75 @@ label_return:
 CTL_RO_NL_CGEN(config_prof, prof_interval, prof_interval, uint64_t)
 
 /******************************************************************************/
+/*
+ * @TODO remember to split up stats to arena-related and th rest
+ */
 
-CTL_RO_CGEN(config_stats, stats_cactive, &stats_cactive, size_t *)
-CTL_RO_CGEN(config_stats, stats_allocated, ctl_stats.allocated, size_t)
-CTL_RO_CGEN(config_stats, stats_active, ctl_stats.active, size_t)
-CTL_RO_CGEN(config_stats, stats_mapped, ctl_stats.mapped, size_t)
-
-CTL_RO_CGEN(config_stats, stats_chunks_current, ctl_stats.chunks.current,
+CTL_RO_CGEN(config_stats, stats_cactive, &(pools[mib[1]]->stats_cactive), size_t *)
+CTL_RO_CGEN(config_stats, stats_allocated, pools[mib[1]]->ctl_stats_allocated, size_t)
+CTL_RO_CGEN(config_stats, stats_active, pools[mib[1]]->ctl_stats_active, size_t)
+CTL_RO_CGEN(config_stats, stats_mapped, pools[mib[1]]->ctl_stats_mapped, size_t)
+CTL_RO_CGEN(config_stats, stats_chunks_current, pools[mib[1]]->ctl_stats.chunks.current,
     size_t)
-CTL_RO_CGEN(config_stats, stats_chunks_total, ctl_stats.chunks.total, uint64_t)
-CTL_RO_CGEN(config_stats, stats_chunks_high, ctl_stats.chunks.high, size_t)
-CTL_RO_CGEN(config_stats, stats_huge_allocated, huge_allocated, size_t)
-CTL_RO_CGEN(config_stats, stats_huge_nmalloc, huge_nmalloc, uint64_t)
-CTL_RO_CGEN(config_stats, stats_huge_ndalloc, huge_ndalloc, uint64_t)
-
-CTL_RO_GEN(stats_arenas_i_dss, ctl_stats.arenas[mib[2]].dss, const char *)
-CTL_RO_GEN(stats_arenas_i_nthreads, ctl_stats.arenas[mib[2]].nthreads, unsigned)
-CTL_RO_GEN(stats_arenas_i_pactive, ctl_stats.arenas[mib[2]].pactive, size_t)
-CTL_RO_GEN(stats_arenas_i_pdirty, ctl_stats.arenas[mib[2]].pdirty, size_t)
+CTL_RO_CGEN(config_stats, stats_chunks_total, pools[mib[1]]->ctl_stats.chunks.total, uint64_t)
+CTL_RO_CGEN(config_stats, stats_chunks_high, pools[mib[1]]->ctl_stats.chunks.high, size_t)
+
+CTL_RO_GEN(stats_arenas_i_dss, pools[mib[1]]->ctl_stats.arenas[mib[4]].dss, const char *)
+CTL_RO_GEN(stats_arenas_i_nthreads, pools[mib[1]]->ctl_stats.arenas[mib[4]].nthreads, unsigned)
+CTL_RO_GEN(stats_arenas_i_pactive, pools[mib[1]]->ctl_stats.arenas[mib[4]].pactive, size_t)
+CTL_RO_GEN(stats_arenas_i_pdirty, pools[mib[1]]->ctl_stats.arenas[mib[4]].pdirty, size_t)
 CTL_RO_CGEN(config_stats, stats_arenas_i_mapped,
-    ctl_stats.arenas[mib[2]].astats.mapped, size_t)
+    pools[mib[1]]->ctl_stats.arenas[mib[4]].astats.mapped, size_t)
 CTL_RO_CGEN(config_stats, stats_arenas_i_npurge,
-    ctl_stats.arenas[mib[2]].astats.npurge, uint64_t)
+    pools[mib[1]]->ctl_stats.arenas[mib[4]].astats.npurge, uint64_t)
 CTL_RO_CGEN(config_stats, stats_arenas_i_nmadvise,
-    ctl_stats.arenas[mib[2]].astats.nmadvise, uint64_t)
+    pools[mib[1]]->ctl_stats.arenas[mib[4]].astats.nmadvise, uint64_t)
 CTL_RO_CGEN(config_stats, stats_arenas_i_purged,
-    ctl_stats.arenas[mib[2]].astats.purged, uint64_t)
+    pools[mib[1]]->ctl_stats.arenas[mib[4]].astats.purged, uint64_t)
 
 CTL_RO_CGEN(config_stats, stats_arenas_i_small_allocated,
-    ctl_stats.arenas[mib[2]].allocated_small, size_t)
+    pools[mib[1]]->ctl_stats.arenas[mib[4]].allocated_small, size_t)
 CTL_RO_CGEN(config_stats, stats_arenas_i_small_nmalloc,
-    ctl_stats.arenas[mib[2]].nmalloc_small, uint64_t)
+    pools[mib[1]]->ctl_stats.arenas[mib[4]].nmalloc_small, uint64_t)
 CTL_RO_CGEN(config_stats, stats_arenas_i_small_ndalloc,
-    ctl_stats.arenas[mib[2]].ndalloc_small, uint64_t)
+    pools[mib[1]]->ctl_stats.arenas[mib[4]].ndalloc_small, uint64_t)
 CTL_RO_CGEN(config_stats, stats_arenas_i_small_nrequests,
-    ctl_stats.arenas[mib[2]].nrequests_small, uint64_t)
+    pools[mib[1]]->ctl_stats.arenas[mib[4]].nrequests_small, uint64_t)
 CTL_RO_CGEN(config_stats, stats_arenas_i_large_allocated,
-    ctl_stats.arenas[mib[2]].astats.allocated_large, size_t)
+    pools[mib[1]]->ctl_stats.arenas[mib[4]].astats.allocated_large, size_t)
 CTL_RO_CGEN(config_stats, stats_arenas_i_large_nmalloc,
-    ctl_stats.arenas[mib[2]].astats.nmalloc_large, uint64_t)
+    pools[mib[1]]->ctl_stats.arenas[mib[4]].astats.nmalloc_large, uint64_t)
 CTL_RO_CGEN(config_stats, stats_arenas_i_large_ndalloc,
-    ctl_stats.arenas[mib[2]].astats.ndalloc_large, uint64_t)
+    pools[mib[1]]->ctl_stats.arenas[mib[4]].astats.ndalloc_large, uint64_t)
 CTL_RO_CGEN(config_stats, stats_arenas_i_large_nrequests,
-    ctl_stats.arenas[mib[2]].astats.nrequests_large, uint64_t)
+    pools[mib[1]]->ctl_stats.arenas[mib[4]].astats.nrequests_large, uint64_t)
+CTL_RO_CGEN(config_stats, stats_arenas_i_huge_allocated,
+    pools[mib[1]]->ctl_stats.arenas[mib[4]].astats.allocated_huge, size_t)
+CTL_RO_CGEN(config_stats, stats_arenas_i_huge_nmalloc,
+    pools[mib[1]]->ctl_stats.arenas[mib[4]].astats.nmalloc_huge, uint64_t)
+CTL_RO_CGEN(config_stats, stats_arenas_i_huge_ndalloc,
+    pools[mib[1]]->ctl_stats.arenas[mib[4]].astats.ndalloc_huge, uint64_t)
+CTL_RO_CGEN(config_stats, stats_arenas_i_huge_nrequests,
+    pools[mib[1]]->ctl_stats.arenas[mib[4]].astats.nrequests_huge, uint64_t)
 
 CTL_RO_CGEN(config_stats, stats_arenas_i_bins_j_allocated,
-    ctl_stats.arenas[mib[2]].bstats[mib[4]].allocated, size_t)
+    pools[mib[1]]->ctl_stats.arenas[mib[4]].bstats[mib[6]].allocated, size_t)
 CTL_RO_CGEN(config_stats, stats_arenas_i_bins_j_nmalloc,
-    ctl_stats.arenas[mib[2]].bstats[mib[4]].nmalloc, uint64_t)
+    pools[mib[1]]->ctl_stats.arenas[mib[4]].bstats[mib[6]].nmalloc, uint64_t)
 CTL_RO_CGEN(config_stats, stats_arenas_i_bins_j_ndalloc,
-    ctl_stats.arenas[mib[2]].bstats[mib[4]].ndalloc, uint64_t)
+    pools[mib[1]]->ctl_stats.arenas[mib[4]].bstats[mib[6]].ndalloc, uint64_t)
 CTL_RO_CGEN(config_stats, stats_arenas_i_bins_j_nrequests,
-    ctl_stats.arenas[mib[2]].bstats[mib[4]].nrequests, uint64_t)
+    pools[mib[1]]->ctl_stats.arenas[mib[4]].bstats[mib[6]].nrequests, uint64_t)
 CTL_RO_CGEN(config_stats && config_tcache, stats_arenas_i_bins_j_nfills,
-    ctl_stats.arenas[mib[2]].bstats[mib[4]].nfills, uint64_t)
+    pools[mib[1]]->ctl_stats.arenas[mib[4]].bstats[mib[6]].nfills, uint64_t)
 CTL_RO_CGEN(config_stats && config_tcache, stats_arenas_i_bins_j_nflushes,
-    ctl_stats.arenas[mib[2]].bstats[mib[4]].nflushes, uint64_t)
+    pools[mib[1]]->ctl_stats.arenas[mib[4]].bstats[mib[6]].nflushes, uint64_t)
 CTL_RO_CGEN(config_stats, stats_arenas_i_bins_j_nruns,
-    ctl_stats.arenas[mib[2]].bstats[mib[4]].nruns, uint64_t)
+    pools[mib[1]]->ctl_stats.arenas[mib[4]].bstats[mib[6]].nruns, uint64_t)
 CTL_RO_CGEN(config_stats, stats_arenas_i_bins_j_nreruns,
-    ctl_stats.arenas[mib[2]].bstats[mib[4]].reruns, uint64_t)
+    pools[mib[1]]->ctl_stats.arenas[mib[4]].bstats[mib[6]].reruns, uint64_t)
 CTL_RO_CGEN(config_stats, stats_arenas_i_bins_j_curruns,
-    ctl_stats.arenas[mib[2]].bstats[mib[4]].curruns, size_t)
+    pools[mib[1]]->ctl_stats.arenas[mib[4]].bstats[mib[6]].curruns, size_t)
 
 static const ctl_named_node_t *
 stats_arenas_i_bins_j_index(const size_t *mib, size_t miblen, size_t j)
@@ -1649,13 +1888,13 @@ stats_arenas_i_bins_j_index(const size_t *mib, size_t miblen, size_t j)
 }
 
 CTL_RO_CGEN(config_stats, stats_arenas_i_lruns_j_nmalloc,
-    ctl_stats.arenas[mib[2]].lstats[mib[4]].nmalloc, uint64_t)
+    pools[mib[1]]->ctl_stats.arenas[mib[4]].lstats[mib[6]].nmalloc, uint64_t)
 CTL_RO_CGEN(config_stats, stats_arenas_i_lruns_j_ndalloc,
-    ctl_stats.arenas[mib[2]].lstats[mib[4]].ndalloc, uint64_t)
+    pools[mib[1]]->ctl_stats.arenas[mib[4]].lstats[mib[6]].ndalloc, uint64_t)
 CTL_RO_CGEN(config_stats, stats_arenas_i_lruns_j_nrequests,
-    ctl_stats.arenas[mib[2]].lstats[mib[4]].nrequests, uint64_t)
+    pools[mib[1]]->ctl_stats.arenas[mib[4]].lstats[mib[6]].nrequests, uint64_t)
 CTL_RO_CGEN(config_stats, stats_arenas_i_lruns_j_curruns,
-    ctl_stats.arenas[mib[2]].lstats[mib[4]].curruns, size_t)
+    pools[mib[1]]->ctl_stats.arenas[mib[4]].lstats[mib[6]].curruns, size_t)
 
 static const ctl_named_node_t *
 stats_arenas_i_lruns_j_index(const size_t *mib, size_t miblen, size_t j)
@@ -1669,10 +1908,11 @@ stats_arenas_i_lruns_j_index(const size_t *mib, size_t miblen, size_t j)
 static const ctl_named_node_t *
 stats_arenas_i_index(const size_t *mib, size_t miblen, size_t i)
 {
-	const ctl_named_node_t * ret;
+	const ctl_named_node_t *ret;
 
 	malloc_mutex_lock(&ctl_mtx);
-	if (i > ctl_stats.narenas || ctl_stats.arenas[i].initialized == false) {
+	if (i > pools[mib[1]]->ctl_stats.narenas ||
+			pools[mib[1]]->ctl_stats.arenas[i].initialized == false) {
 		ret = NULL;
 		goto label_return;
 	}
@@ -1682,3 +1922,20 @@ label_return:
 	malloc_mutex_unlock(&ctl_mtx);
 	return (ret);
 }
+
+static const ctl_named_node_t *
+thread_pool_i_index(const size_t *mib, size_t miblen, size_t i)
+{
+	const ctl_named_node_t *ret;
+
+	malloc_mutex_lock(&ctl_mtx);
+	if (i > POOLS_MAX) {
+		ret = NULL;
+		goto label_return;
+	}
+
+	ret = super_thread_pool_i_node;
+label_return:
+	malloc_mutex_unlock(&ctl_mtx);
+	return (ret);
+}
diff --git a/src/jemalloc/src/huge.c b/src/jemalloc/src/huge.c
index d72f21357021aee8d14ca7971e0b75e03c4675cb..536e0821917e54f31c982e90b230d6ae08d5aeeb 100644
--- a/src/jemalloc/src/huge.c
+++ b/src/jemalloc/src/huge.c
@@ -1,34 +1,20 @@
 #define	JEMALLOC_HUGE_C_
 #include "jemalloc/internal/jemalloc_internal.h"
 
-/******************************************************************************/
-/* Data. */
-
-uint64_t	huge_nmalloc;
-uint64_t	huge_ndalloc;
-size_t		huge_allocated;
-
-malloc_mutex_t	huge_mtx;
-
-/******************************************************************************/
-
-/* Tree of chunks that are stand-alone huge allocations. */
-static extent_tree_t	huge;
-
 void *
-huge_malloc(size_t size, bool zero, dss_prec_t dss_prec)
+huge_malloc(arena_t *arena, size_t size, bool zero)
 {
-
-	return (huge_palloc(size, chunksize, zero, dss_prec));
+	return (huge_palloc(arena, size, chunksize, zero));
 }
 
 void *
-huge_palloc(size_t size, size_t alignment, bool zero, dss_prec_t dss_prec)
+huge_palloc(arena_t *arena, size_t size, size_t alignment, bool zero)
 {
 	void *ret;
 	size_t csize;
 	extent_node_t *node;
 	bool is_zeroed;
+	pool_t *pool;
 
 	/* Allocate one or more contiguous chunks for this request. */
 
@@ -38,34 +24,33 @@ huge_palloc(size_t size, size_t alignment, bool zero, dss_prec_t dss_prec)
 		return (NULL);
 	}
 
-	/* Allocate an extent node with which to track the chunk. */
-	node = base_node_alloc();
-	if (node == NULL)
-		return (NULL);
-
 	/*
 	 * Copy zero into is_zeroed and pass the copy to chunk_alloc(), so that
 	 * it is possible to make correct junk/zero fill decisions below.
 	 */
 	is_zeroed = zero;
-	ret = chunk_alloc(csize, alignment, false, &is_zeroed, dss_prec);
+	arena = choose_arena(arena);
+	pool = arena->pool;
+
+	/* Allocate an extent node with which to track the chunk. */
+	node = base_node_alloc(pool);
+	if (node == NULL)
+		return (NULL);
+
+	ret = arena_chunk_alloc_huge(arena, csize, alignment, &is_zeroed);
 	if (ret == NULL) {
-		base_node_dealloc(node);
+		base_node_dalloc(pool, node);
 		return (NULL);
 	}
 
 	/* Insert node into huge. */
 	node->addr = ret;
 	node->size = csize;
+	node->arena = arena;
 
-	malloc_mutex_lock(&huge_mtx);
-	extent_tree_ad_insert(&huge, node);
-	if (config_stats) {
-		stats_cactive_add(csize);
-		huge_nmalloc++;
-		huge_allocated += csize;
-	}
-	malloc_mutex_unlock(&huge_mtx);
+	malloc_mutex_lock(&pool->huge_mtx);
+	extent_tree_ad_insert(&pool->huge, node);
+	malloc_mutex_unlock(&pool->huge_mtx);
 
 	if (config_fill && zero == false) {
 		if (opt_junk)
@@ -96,8 +81,8 @@ huge_ralloc_no_move(void *ptr, size_t oldsize, size_t size, size_t extra)
 }
 
 void *
-huge_ralloc(void *ptr, size_t oldsize, size_t size, size_t extra,
-    size_t alignment, bool zero, bool try_tcache_dalloc, dss_prec_t dss_prec)
+huge_ralloc(arena_t *arena, void *ptr, size_t oldsize, size_t size,
+    size_t extra, size_t alignment, bool zero, bool try_tcache_dalloc)
 {
 	void *ret;
 	size_t copysize;
@@ -112,18 +97,18 @@ huge_ralloc(void *ptr, size_t oldsize, size_t size, size_t extra,
 	 * space and copying.
 	 */
 	if (alignment > chunksize)
-		ret = huge_palloc(size + extra, alignment, zero, dss_prec);
+		ret = huge_palloc(arena, size + extra, alignment, zero);
 	else
-		ret = huge_malloc(size + extra, zero, dss_prec);
+		ret = huge_malloc(arena, size + extra, zero);
 
 	if (ret == NULL) {
 		if (extra == 0)
 			return (NULL);
 		/* Try again, this time without extra. */
 		if (alignment > chunksize)
-			ret = huge_palloc(size, alignment, zero, dss_prec);
+			ret = huge_palloc(arena, size, alignment, zero);
 		else
-			ret = huge_malloc(size, zero, dss_prec);
+			ret = huge_malloc(arena, size, zero);
 
 		if (ret == NULL)
 			return (NULL);
@@ -134,59 +119,8 @@ huge_ralloc(void *ptr, size_t oldsize, size_t size, size_t extra,
 	 * expectation that the extra bytes will be reliably preserved.
 	 */
 	copysize = (size < oldsize) ? size : oldsize;
-
-#ifdef JEMALLOC_MREMAP
-	/*
-	 * Use mremap(2) if this is a huge-->huge reallocation, and neither the
-	 * source nor the destination are in dss.
-	 */
-	if (oldsize >= chunksize && (config_dss == false || (chunk_in_dss(ptr)
-	    == false && chunk_in_dss(ret) == false))) {
-		size_t newsize = huge_salloc(ret);
-
-		/*
-		 * Remove ptr from the tree of huge allocations before
-		 * performing the remap operation, in order to avoid the
-		 * possibility of another thread acquiring that mapping before
-		 * this one removes it from the tree.
-		 */
-		huge_dalloc(ptr, false);
-		if (mremap(ptr, oldsize, newsize, MREMAP_MAYMOVE|MREMAP_FIXED,
-		    ret) == MAP_FAILED) {
-			/*
-			 * Assuming no chunk management bugs in the allocator,
-			 * the only documented way an error can occur here is
-			 * if the application changed the map type for a
-			 * portion of the old allocation.  This is firmly in
-			 * undefined behavior territory, so write a diagnostic
-			 * message, and optionally abort.
-			 */
-			char buf[BUFERROR_BUF];
-
-			buferror(get_errno(), buf, sizeof(buf));
-			malloc_printf("<jemalloc>: Error in mremap(): %s\n",
-			    buf);
-			if (opt_abort)
-				abort();
-			memcpy(ret, ptr, copysize);
-			chunk_dealloc_mmap(ptr, oldsize);
-		} else if (config_fill && zero == false && opt_junk && oldsize
-		    < newsize) {
-			/*
-			 * mremap(2) clobbers the original mapping, so
-			 * junk/zero filling is not preserved.  There is no
-			 * need to zero fill here, since any trailing
-			 * uninititialized memory is demand-zeroed by the
-			 * kernel, but junk filling must be redone.
-			 */
-			memset(ret + oldsize, 0xa5, newsize - oldsize);
-		}
-	} else
-#endif
-	{
-		memcpy(ret, ptr, copysize);
-		iqalloct(ptr, try_tcache_dalloc);
-	}
+	memcpy(ret, ptr, copysize);
+	iqalloct(ptr, try_tcache_dalloc);
 	return (ret);
 }
 
@@ -198,12 +132,12 @@ static void
 huge_dalloc_junk(void *ptr, size_t usize)
 {
 
-	if (config_fill && config_dss && opt_junk) {
+	if (config_fill && have_dss && opt_junk) {
 		/*
 		 * Only bother junk filling if the chunk isn't about to be
 		 * unmapped.
 		 */
-		if (config_munmap == false || (config_dss && chunk_in_dss(ptr)))
+		if (config_munmap == false || (have_dss && chunk_in_dss(ptr)))
 			memset(ptr, 0x5a, usize);
 	}
 }
@@ -214,78 +148,75 @@ huge_dalloc_junk_t *huge_dalloc_junk = JEMALLOC_N(huge_dalloc_junk_impl);
 #endif
 
 void
-huge_dalloc(void *ptr, bool unmap)
+huge_dalloc(pool_t *pool, void *ptr)
 {
 	extent_node_t *node, key;
 
-	malloc_mutex_lock(&huge_mtx);
+	malloc_mutex_lock(&pool->huge_mtx);
 
 	/* Extract from tree of huge allocations. */
 	key.addr = ptr;
-	node = extent_tree_ad_search(&huge, &key);
+	node = extent_tree_ad_search(&pool->huge, &key);
 	assert(node != NULL);
 	assert(node->addr == ptr);
-	extent_tree_ad_remove(&huge, node);
-
-	if (config_stats) {
-		stats_cactive_sub(node->size);
-		huge_ndalloc++;
-		huge_allocated -= node->size;
-	}
-
-	malloc_mutex_unlock(&huge_mtx);
+	extent_tree_ad_remove(&pool->huge, node);
 
-	if (unmap)
-		huge_dalloc_junk(node->addr, node->size);
+	malloc_mutex_unlock(&pool->huge_mtx);
 
-	chunk_dealloc(node->addr, node->size, unmap);
-
-	base_node_dealloc(node);
+	huge_dalloc_junk(node->addr, node->size);
+	arena_chunk_dalloc_huge(node->arena, node->addr, node->size);
+	base_node_dalloc(pool, node);
 }
 
 size_t
 huge_salloc(const void *ptr)
 {
-	size_t ret;
+	size_t ret = 0;
+	int i;
 	extent_node_t *node, key;
-
-	malloc_mutex_lock(&huge_mtx);
-
-	/* Extract from tree of huge allocations. */
-	key.addr = __DECONST(void *, ptr);
-	node = extent_tree_ad_search(&huge, &key);
-	assert(node != NULL);
-
-	ret = node->size;
-
-	malloc_mutex_unlock(&huge_mtx);
+	for (i = 0; i < POOLS_MAX; ++i) {
+		pool_t *pool = pools[i];
+		if (pool == NULL)
+			continue;
+		malloc_mutex_lock(&pool->huge_mtx);
+
+		/* Extract from tree of huge allocations. */
+		key.addr = __DECONST(void *, ptr);
+		node = extent_tree_ad_search(&pool->huge, &key);
+		if (node != NULL)
+			ret = node->size;
+
+		malloc_mutex_unlock(&pool->huge_mtx);
+		if (ret != 0)
+			break;
+	}
 
 	return (ret);
 }
 
-dss_prec_t
-huge_dss_prec_get(arena_t *arena)
-{
-
-	return (arena_dss_prec_get(choose_arena(arena)));
-}
-
 prof_ctx_t *
 huge_prof_ctx_get(const void *ptr)
 {
-	prof_ctx_t *ret;
+	prof_ctx_t *ret = NULL;
+	int i;
 	extent_node_t *node, key;
 
-	malloc_mutex_lock(&huge_mtx);
-
-	/* Extract from tree of huge allocations. */
-	key.addr = __DECONST(void *, ptr);
-	node = extent_tree_ad_search(&huge, &key);
-	assert(node != NULL);
-
-	ret = node->prof_ctx;
-
-	malloc_mutex_unlock(&huge_mtx);
+	for (i = 0; i < POOLS_MAX; ++i) {
+		pool_t *pool = pools[i];
+		if (pool == NULL)
+			continue;
+		malloc_mutex_lock(&pool->huge_mtx);
+
+		/* Extract from tree of huge allocations. */
+		key.addr = __DECONST(void *, ptr);
+		node = extent_tree_ad_search(&pool->huge, &key);
+		if (node != NULL)
+			ret = node->prof_ctx;
+
+		malloc_mutex_unlock(&pool->huge_mtx);
+		if (ret != NULL)
+			break;
+	}
 
 	return (ret);
 }
@@ -294,54 +225,56 @@ void
 huge_prof_ctx_set(const void *ptr, prof_ctx_t *ctx)
 {
 	extent_node_t *node, key;
+	int i;
 
-	malloc_mutex_lock(&huge_mtx);
+	for (i = 0; i < POOLS_MAX; ++i) {
+		pool_t *pool = pools[i];
+		if (pool == NULL)
+			continue;
+		malloc_mutex_lock(&pool->huge_mtx);
 
-	/* Extract from tree of huge allocations. */
-	key.addr = __DECONST(void *, ptr);
-	node = extent_tree_ad_search(&huge, &key);
-	assert(node != NULL);
+		/* Extract from tree of huge allocations. */
+		key.addr = __DECONST(void *, ptr);
+		node = extent_tree_ad_search(&pool->huge, &key);
+		if (node != NULL)
+			node->prof_ctx = ctx;
 
-	node->prof_ctx = ctx;
+		malloc_mutex_unlock(&pool->huge_mtx);
 
-	malloc_mutex_unlock(&huge_mtx);
+		if (node != NULL)
+			break;
+	}
 }
 
 bool
-huge_boot(void)
+huge_boot(pool_t *pool)
 {
 
 	/* Initialize chunks data. */
-	if (malloc_mutex_init(&huge_mtx))
+	if (malloc_mutex_init(&pool->huge_mtx))
 		return (true);
-	extent_tree_ad_new(&huge);
-
-	if (config_stats) {
-		huge_nmalloc = 0;
-		huge_ndalloc = 0;
-		huge_allocated = 0;
-	}
+	extent_tree_ad_new(&pool->huge);
 
 	return (false);
 }
 
 void
-huge_prefork(void)
+huge_prefork(pool_t *pool)
 {
 
-	malloc_mutex_prefork(&huge_mtx);
+	malloc_mutex_prefork(&pool->huge_mtx);
 }
 
 void
-huge_postfork_parent(void)
+huge_postfork_parent(pool_t *pool)
 {
 
-	malloc_mutex_postfork_parent(&huge_mtx);
+	malloc_mutex_postfork_parent(&pool->huge_mtx);
 }
 
 void
-huge_postfork_child(void)
+huge_postfork_child(pool_t *pool)
 {
 
-	malloc_mutex_postfork_child(&huge_mtx);
+	malloc_mutex_postfork_child(&pool->huge_mtx);
 }
diff --git a/src/jemalloc/src/jemalloc.c b/src/jemalloc/src/jemalloc.c
index 204778bc89d8f40105a7fc4943df3620d24c8cfa..cb5ed9ec2867084475abc8c22c5579b49a6a522f 100644
--- a/src/jemalloc/src/jemalloc.c
+++ b/src/jemalloc/src/jemalloc.c
@@ -3,8 +3,7 @@
 
 /******************************************************************************/
 /* Data. */
-
-malloc_tsd_data(, arenas, arena_t *, NULL)
+malloc_tsd_data(, arenas, tsd_pool_t, TSD_POOL_INITIALIZER)
 malloc_tsd_data(, thread_allocated, thread_allocated_t,
     THREAD_ALLOCATED_INITIALIZER)
 
@@ -27,17 +26,29 @@ bool	opt_junk =
 size_t	opt_quarantine = ZU(0);
 bool	opt_redzone = false;
 bool	opt_utrace = false;
-bool	opt_valgrind = false;
 bool	opt_xmalloc = false;
 bool	opt_zero = false;
 size_t	opt_narenas = 0;
 
+/* Initialized to true if the process is running inside Valgrind. */
+bool	in_valgrind;
+
+
+unsigned	npools;
 unsigned	ncpus;
 
-malloc_mutex_t		arenas_lock;
-arena_t			**arenas;
-unsigned		narenas_total;
-unsigned		narenas_auto;
+pool_t			*pools[POOLS_MAX];
+pool_t			init_pool;
+unsigned		pool_seqno = 0;
+bool			pools_shared_data_initialized;
+
+/*
+ * Custom malloc() and free() for shared data and for data needed to
+ * initialize pool. If not defined functions then base_pool will be
+ * created for allocations from RAM.
+ */
+void	*(*je_base_malloc)(size_t);
+void	(*je_base_free)(void *);
 
 /* Set to true once the allocator has been initialized. */
 static bool		malloc_initialized = false;
@@ -106,6 +117,10 @@ typedef struct {
  */
 
 static bool	malloc_init_hard(void);
+static bool	malloc_init_base_pool(void);
+static bool	pools_shared_data_create(void);
+static void	*base_malloc_default(size_t size);
+static void	base_free_default(void *ptr);
 
 /******************************************************************************/
 /*
@@ -114,13 +129,13 @@ static bool	malloc_init_hard(void);
 
 /* Create a new arena and insert it into the arenas array at index ind. */
 arena_t *
-arenas_extend(unsigned ind)
+arenas_extend(pool_t *pool, unsigned ind)
 {
 	arena_t *ret;
 
-	ret = (arena_t *)base_alloc(sizeof(arena_t));
-	if (ret != NULL && arena_new(ret, ind) == false) {
-		arenas[ind] = ret;
+	ret = (arena_t *)base_alloc(pool, sizeof(arena_t));
+	if (ret != NULL && arena_new(pool, ret, ind) == false) {
+		pool->arenas[ind] = ret;
 		return (ret);
 	}
 	/* Only reached if there is an OOM error. */
@@ -135,32 +150,33 @@ arenas_extend(unsigned ind)
 	if (opt_abort)
 		abort();
 
-	return (arenas[0]);
+	return (pool->arenas[0]);
 }
 
 /* Slow path, called only by choose_arena(). */
 arena_t *
-choose_arena_hard(void)
+choose_arena_hard(pool_t *pool)
 {
 	arena_t *ret;
+	tsd_pool_t *tsd;
 
-	if (narenas_auto > 1) {
+	if (pool->narenas_auto > 1) {
 		unsigned i, choose, first_null;
 
 		choose = 0;
-		first_null = narenas_auto;
-		malloc_mutex_lock(&arenas_lock);
-		assert(arenas[0] != NULL);
-		for (i = 1; i < narenas_auto; i++) {
-			if (arenas[i] != NULL) {
+		first_null = pool->narenas_auto;
+		malloc_mutex_lock(&pool->arenas_lock);
+		assert(pool->arenas[0] != NULL);
+		for (i = 1; i < pool->narenas_auto; i++) {
+			if (pool->arenas[i] != NULL) {
 				/*
 				 * Choose the first arena that has the lowest
 				 * number of threads assigned to it.
 				 */
-				if (arenas[i]->nthreads <
-				    arenas[choose]->nthreads)
+				if (pool->arenas[i]->nthreads <
+				    pool->arenas[choose]->nthreads)
 					choose = i;
-			} else if (first_null == narenas_auto) {
+			} else if (first_null == pool->narenas_auto) {
 				/*
 				 * Record the index of the first uninitialized
 				 * arena, in case all extant arenas are in use.
@@ -174,27 +190,30 @@ choose_arena_hard(void)
 			}
 		}
 
-		if (arenas[choose]->nthreads == 0
-		    || first_null == narenas_auto) {
+		if (pool->arenas[choose]->nthreads == 0
+		    || first_null == pool->narenas_auto) {
 			/*
 			 * Use an unloaded arena, or the least loaded arena if
 			 * all arenas are already initialized.
 			 */
-			ret = arenas[choose];
+			ret = pool->arenas[choose];
 		} else {
 			/* Initialize a new arena. */
-			ret = arenas_extend(first_null);
+			ret = arenas_extend(pool, first_null);
 		}
 		ret->nthreads++;
-		malloc_mutex_unlock(&arenas_lock);
+		malloc_mutex_unlock(&pool->arenas_lock);
 	} else {
-		ret = arenas[0];
-		malloc_mutex_lock(&arenas_lock);
+		ret = pool->arenas[0];
+		malloc_mutex_lock(&pool->arenas_lock);
 		ret->nthreads++;
-		malloc_mutex_unlock(&arenas_lock);
+		malloc_mutex_unlock(&pool->arenas_lock);
 	}
 
-	arenas_tsd_set(&ret);
+	tsd = arenas_tsd_get();
+	tsd->seqno[pool->pool_id] = pool->seqno;
+	tsd->arenas[pool->pool_id] = ret;
+
 
 	return (ret);
 }
@@ -204,7 +223,8 @@ stats_print_atexit(void)
 {
 
 	if (config_tcache && config_stats) {
-		unsigned narenas, i;
+		unsigned narenas, i, j;
+		pool_t *pool;
 
 		/*
 		 * Merge stats from extant threads.  This is racy, since
@@ -213,24 +233,31 @@ stats_print_atexit(void)
 		 * out of date by the time they are reported, if other threads
 		 * continue to allocate.
 		 */
-		for (i = 0, narenas = narenas_total_get(); i < narenas; i++) {
-			arena_t *arena = arenas[i];
-			if (arena != NULL) {
-				tcache_t *tcache;
-
-				/*
-				 * tcache_stats_merge() locks bins, so if any
-				 * code is introduced that acquires both arena
-				 * and bin locks in the opposite order,
-				 * deadlocks may result.
-				 */
-				malloc_mutex_lock(&arena->lock);
-				ql_foreach(tcache, &arena->tcache_ql, link) {
-					tcache_stats_merge(tcache, arena);
+		malloc_mutex_lock(&pools_lock);
+		for (i = 0; i < POOLS_MAX; i++) {
+			pool = pools[i];
+			if (pool != NULL) {
+				for (j = 0, narenas = narenas_total_get(pool); j < narenas; j++) {
+					arena_t *arena = pool->arenas[j];
+					if (arena != NULL) {
+						tcache_t *tcache;
+
+						/*
+						 * tcache_stats_merge() locks bins, so if any
+						 * code is introduced that acquires both arena
+						 * and bin locks in the opposite order,
+						 * deadlocks may result.
+						 */
+						malloc_mutex_lock(&arena->lock);
+						ql_foreach(tcache, &arena->tcache_ql, link) {
+							tcache_stats_merge(tcache, arena);
+						}
+						malloc_mutex_unlock(&arena->lock);
+					}
 				}
-				malloc_mutex_unlock(&arena->lock);
 			}
 		}
+		malloc_mutex_unlock(&pools_lock);
 	}
 	je_malloc_stats_print(NULL, NULL, NULL);
 }
@@ -261,16 +288,77 @@ malloc_ncpus(void)
 void
 arenas_cleanup(void *arg)
 {
-	arena_t *arena = *(arena_t **)arg;
+	unsigned i;
+	pool_t *pool;
+	tsd_pool_t *tsd = arg;
+	malloc_mutex_lock(&pools_lock);
+	for (i = 0; i < POOLS_MAX; i++) {
+		pool = pools[i];
+		if (pool != NULL) {
+			if (pool->seqno == tsd->seqno[i] && tsd->arenas[i] != NULL) {
+				malloc_mutex_lock(&pool->arenas_lock);
+				tsd->arenas[i]->nthreads--;
+				malloc_mutex_unlock(&pool->arenas_lock);
+			}
+		}
+	}
+	malloc_mutex_unlock(&pools_lock);
 
-	malloc_mutex_lock(&arenas_lock);
-	arena->nthreads--;
-	malloc_mutex_unlock(&arenas_lock);
 }
 
 JEMALLOC_ALWAYS_INLINE_C void
 malloc_thread_init(void)
 {
+	if (config_fill && opt_quarantine && je_base_malloc == base_malloc_default) {
+		/* create pool base and call quarantine_alloc_hook() inside */
+		malloc_init_base_pool();
+	}
+}
+
+JEMALLOC_ALWAYS_INLINE_C bool
+malloc_init(void)
+{
+
+	if (malloc_initialized == false && malloc_init_hard())
+		return (true);
+
+	return (false);
+}
+
+static bool
+malloc_init_base_pool(void)
+{
+	pool_t *base_pool;
+
+	if (malloc_initialized == false && malloc_init_hard())
+		return (true);
+
+	if (pools[0] != NULL)
+		return (false);
+
+	malloc_mutex_lock(&pool_base_lock);
+	if (pools[0] != NULL) {
+		/*
+		 * Another thread initialized the base pool before this one
+		 * acquired pools_lock.
+		 */
+		malloc_mutex_unlock(&pool_base_lock);
+		return (false);
+	}
+
+	base_pool = &init_pool;
+	npools++;
+	pools[0] = base_pool;
+	pools[0]->seqno = ++pool_seqno;
+
+	pools_shared_data_create();
+
+	if (pool_new(base_pool, 0)) {
+		malloc_mutex_unlock(&pool_base_lock);
+		return (true);
+	}
+
+	malloc_mutex_unlock(&pool_base_lock);
 
 	/*
 	 * TSD initialization can't be safely done as a side effect of
@@ -281,17 +369,10 @@ malloc_thread_init(void)
 	 * a best effort attempt at initializing its TSD by hooking all
 	 * allocation events.
 	 */
-	if (config_fill && opt_quarantine)
+	if (config_fill && opt_quarantine) {
 		quarantine_alloc_hook();
-}
-
-JEMALLOC_ALWAYS_INLINE_C bool
-malloc_init(void)
-{
+	}
 
-	if (malloc_initialized == false && malloc_init_hard())
-		return (true);
-	malloc_thread_init();
 
 	return (false);
 }
@@ -394,14 +475,14 @@ malloc_conf_init(void)
 	 * valgrind option remains in jemalloc 3.x for compatibility reasons.
 	 */
 	if (config_valgrind) {
-		opt_valgrind = (RUNNING_ON_VALGRIND != 0) ? true : false;
-		if (config_fill && opt_valgrind) {
+		in_valgrind = (RUNNING_ON_VALGRIND != 0) ? true : false;
+		if (config_fill && in_valgrind) {
 			opt_junk = false;
 			assert(opt_zero == false);
 			opt_quarantine = JEMALLOC_VALGRIND_QUARANTINE_DEFAULT;
 			opt_redzone = true;
 		}
-		if (config_tcache && opt_valgrind)
+		if (config_tcache && in_valgrind)
 			opt_tcache = false;
 	}
 
@@ -477,9 +558,10 @@ malloc_conf_init(void)
 
 		while (*opts != '\0' && malloc_conf_next(&opts, &k, &klen, &v,
 		    &vlen) == false) {
-#define	CONF_HANDLE_BOOL(o, n)						\
-			if (sizeof(n)-1 == klen && strncmp(n, k,	\
-			    klen) == 0) {				\
+#define	CONF_MATCH(n)							\
+	(sizeof(n)-1 == klen && strncmp(n, k, klen) == 0)
+#define	CONF_HANDLE_BOOL(o, n, cont)					\
+			if (CONF_MATCH(n)) {				\
 				if (strncmp("true", v, vlen) == 0 &&	\
 				    vlen == sizeof("true")-1)		\
 					o = true;			\
@@ -491,11 +573,11 @@ malloc_conf_init(void)
 					    "Invalid conf value",	\
 					    k, klen, v, vlen);		\
 				}					\
-				continue;				\
+				if (cont)				\
+					continue;			\
 			}
 #define	CONF_HANDLE_SIZE_T(o, n, min, max, clip)			\
-			if (sizeof(n)-1 == klen && strncmp(n, k,	\
-			    klen) == 0) {				\
+			if (CONF_MATCH(n)) {				\
 				uintmax_t um;				\
 				char *end;				\
 									\
@@ -526,8 +608,7 @@ malloc_conf_init(void)
 				continue;				\
 			}
 #define	CONF_HANDLE_SSIZE_T(o, n, min, max)				\
-			if (sizeof(n)-1 == klen && strncmp(n, k,	\
-			    klen) == 0) {				\
+			if (CONF_MATCH(n)) {				\
 				long l;					\
 				char *end;				\
 									\
@@ -548,8 +629,7 @@ malloc_conf_init(void)
 				continue;				\
 			}
 #define	CONF_HANDLE_CHAR_P(o, n, d)					\
-			if (sizeof(n)-1 == klen && strncmp(n, k,	\
-			    klen) == 0) {				\
+			if (CONF_MATCH(n)) {				\
 				size_t cpylen = (vlen <=		\
 				    sizeof(o)-1) ? vlen :		\
 				    sizeof(o)-1;			\
@@ -558,7 +638,7 @@ malloc_conf_init(void)
 				continue;				\
 			}
 
-			CONF_HANDLE_BOOL(opt_abort, "abort")
+			CONF_HANDLE_BOOL(opt_abort, "abort", true)
 			/*
 			 * Chunks always require at least one header page, plus
 			 * one data page in the absence of redzones, or three
@@ -597,47 +677,62 @@ malloc_conf_init(void)
 			    SIZE_T_MAX, false)
 			CONF_HANDLE_SSIZE_T(opt_lg_dirty_mult, "lg_dirty_mult",
 			    -1, (sizeof(size_t) << 3) - 1)
-			CONF_HANDLE_BOOL(opt_stats_print, "stats_print")
+			CONF_HANDLE_BOOL(opt_stats_print, "stats_print", true)
 			if (config_fill) {
-				CONF_HANDLE_BOOL(opt_junk, "junk")
+				CONF_HANDLE_BOOL(opt_junk, "junk", true)
 				CONF_HANDLE_SIZE_T(opt_quarantine, "quarantine",
 				    0, SIZE_T_MAX, false)
-				CONF_HANDLE_BOOL(opt_redzone, "redzone")
-				CONF_HANDLE_BOOL(opt_zero, "zero")
+				CONF_HANDLE_BOOL(opt_redzone, "redzone", true)
+				CONF_HANDLE_BOOL(opt_zero, "zero", true)
 			}
 			if (config_utrace) {
-				CONF_HANDLE_BOOL(opt_utrace, "utrace")
-			}
-			if (config_valgrind) {
-				CONF_HANDLE_BOOL(opt_valgrind, "valgrind")
+				CONF_HANDLE_BOOL(opt_utrace, "utrace", true)
 			}
 			if (config_xmalloc) {
-				CONF_HANDLE_BOOL(opt_xmalloc, "xmalloc")
+				CONF_HANDLE_BOOL(opt_xmalloc, "xmalloc", true)
 			}
 			if (config_tcache) {
-				CONF_HANDLE_BOOL(opt_tcache, "tcache")
+				CONF_HANDLE_BOOL(opt_tcache, "tcache",
+				    !config_valgrind || !in_valgrind)
+				if (CONF_MATCH("tcache")) {
+					assert(config_valgrind && in_valgrind);
+					if (opt_tcache) {
+						opt_tcache = false;
+						malloc_conf_error(
+						"tcache cannot be enabled "
+						"while running inside Valgrind",
+						k, klen, v, vlen);
+					}
+					continue;
+				}
 				CONF_HANDLE_SSIZE_T(opt_lg_tcache_max,
 				    "lg_tcache_max", -1,
 				    (sizeof(size_t) << 3) - 1)
 			}
 			if (config_prof) {
-				CONF_HANDLE_BOOL(opt_prof, "prof")
+				CONF_HANDLE_BOOL(opt_prof, "prof", true)
 				CONF_HANDLE_CHAR_P(opt_prof_prefix,
 				    "prof_prefix", "jeprof")
-				CONF_HANDLE_BOOL(opt_prof_active, "prof_active")
+				CONF_HANDLE_BOOL(opt_prof_active, "prof_active",
+				    true)
 				CONF_HANDLE_SSIZE_T(opt_lg_prof_sample,
 				    "lg_prof_sample", 0,
 				    (sizeof(uint64_t) << 3) - 1)
-				CONF_HANDLE_BOOL(opt_prof_accum, "prof_accum")
+				CONF_HANDLE_BOOL(opt_prof_accum, "prof_accum",
+				    true)
 				CONF_HANDLE_SSIZE_T(opt_lg_prof_interval,
 				    "lg_prof_interval", -1,
 				    (sizeof(uint64_t) << 3) - 1)
-				CONF_HANDLE_BOOL(opt_prof_gdump, "prof_gdump")
-				CONF_HANDLE_BOOL(opt_prof_final, "prof_final")
-				CONF_HANDLE_BOOL(opt_prof_leak, "prof_leak")
+				CONF_HANDLE_BOOL(opt_prof_gdump, "prof_gdump",
+				    true)
+				CONF_HANDLE_BOOL(opt_prof_final, "prof_final",
+				    true)
+				CONF_HANDLE_BOOL(opt_prof_leak, "prof_leak",
+				    true)
 			}
 			malloc_conf_error("Invalid conf pair", k, klen, v,
 			    vlen);
+#undef CONF_MATCH
 #undef CONF_HANDLE_BOOL
 #undef CONF_HANDLE_SIZE_T
 #undef CONF_HANDLE_SSIZE_T
@@ -649,8 +744,6 @@ malloc_conf_init(void)
 static bool
 malloc_init_hard(void)
 {
-	arena_t *init_arenas[1];
-
 	malloc_mutex_lock(&init_lock);
 	if (malloc_initialized || IS_INITIALIZER) {
 		/*
@@ -690,15 +783,14 @@ malloc_init_hard(void)
 		}
 	}
 
-	if (base_boot()) {
-		malloc_mutex_unlock(&init_lock);
-		return (true);
-	}
+	npools = 0;
+	pools_shared_data_initialized = false;
+	memset(pools, 0, sizeof(pool_t *) * POOLS_MAX);
 
-	if (chunk_boot()) {
-		malloc_mutex_unlock(&init_lock);
-		return (true);
-	}
+	je_base_malloc = base_malloc_default;
+	je_base_free = base_free_default;
+
+	chunk_global_boot();
 
 	if (ctl_boot()) {
 		malloc_mutex_unlock(&init_lock);
@@ -710,38 +802,7 @@ malloc_init_hard(void)
 
 	arena_boot();
 
-	if (config_tcache && tcache_boot0()) {
-		malloc_mutex_unlock(&init_lock);
-		return (true);
-	}
-
-	if (huge_boot()) {
-		malloc_mutex_unlock(&init_lock);
-		return (true);
-	}
-
-	if (malloc_mutex_init(&arenas_lock)) {
-		malloc_mutex_unlock(&init_lock);
-		return (true);
-	}
-
-	/*
-	 * Create enough scaffolding to allow recursive allocation in
-	 * malloc_ncpus().
-	 */
-	narenas_total = narenas_auto = 1;
-	arenas = init_arenas;
-	memset(arenas, 0, sizeof(arena_t *) * narenas_auto);
-
-	/*
-	 * Initialize one arena here.  The rest are lazily created in
-	 * choose_arena_hard().
-	 */
-	arenas_extend(0);
-	if (arenas[0] == NULL) {
-		malloc_mutex_unlock(&init_lock);
-		return (true);
-	}
+	pool_boot();
 
 	/* Initialize allocation counters before any allocations can occur. */
 	if (config_stats && thread_allocated_tsd_boot()) {
@@ -776,7 +837,7 @@ malloc_init_hard(void)
 	ncpus = malloc_ncpus();
 
 #if (!defined(JEMALLOC_MUTEX_INIT_CB) && !defined(JEMALLOC_ZONE) \
-    && !defined(_WIN32))
+    && !defined(_WIN32) && !defined(__native_client__))
 	/* LinuxThreads's pthread_atfork() allocates. */
 	if (pthread_atfork(jemalloc_prefork, jemalloc_postfork_parent,
 	    jemalloc_postfork_child) != 0) {
@@ -805,32 +866,6 @@ malloc_init_hard(void)
 		else
 			opt_narenas = 1;
 	}
-	narenas_auto = opt_narenas;
-	/*
-	 * Make sure that the arenas array can be allocated.  In practice, this
-	 * limit is enough to allow the allocator to function, but the ctl
-	 * machinery will fail to allocate memory at far lower limits.
-	 */
-	if (narenas_auto > chunksize / sizeof(arena_t *)) {
-		narenas_auto = chunksize / sizeof(arena_t *);
-		malloc_printf("<jemalloc>: Reducing narenas to limit (%d)\n",
-		    narenas_auto);
-	}
-	narenas_total = narenas_auto;
-
-	/* Allocate and initialize arenas. */
-	arenas = (arena_t **)base_alloc(sizeof(arena_t *) * narenas_total);
-	if (arenas == NULL) {
-		malloc_mutex_unlock(&init_lock);
-		return (true);
-	}
-	/*
-	 * Zero the array.  In practice, this should always be pre-zeroed,
-	 * since it was just mmap()ed, but let's be sure.
-	 */
-	memset(arenas, 0, sizeof(arena_t *) * narenas_total);
-	/* Copy the pointer to the one arena that was already initialized. */
-	arenas[0] = init_arenas[0];
 
 	malloc_initialized = true;
 	malloc_mutex_unlock(&init_lock);
@@ -853,7 +888,7 @@ imalloc_prof_sample(size_t usize, prof_thr_cnt_t *cnt)
 
 	if (cnt == NULL)
 		return (NULL);
-	if (prof_promote && usize <= SMALL_MAXCLASS) {
+	if (usize <= SMALL_MAXCLASS) {
 		p = imalloc(SMALL_MAXCLASS+1);
 		if (p == NULL)
 			return (NULL);
@@ -865,10 +900,12 @@ imalloc_prof_sample(size_t usize, prof_thr_cnt_t *cnt)
 }
 
 JEMALLOC_ALWAYS_INLINE_C void *
-imalloc_prof(size_t usize, prof_thr_cnt_t *cnt)
+imalloc_prof(size_t usize)
 {
 	void *p;
+	prof_thr_cnt_t *cnt;
 
+	PROF_ALLOC_PREP(usize, cnt);
 	if ((uintptr_t)cnt != (uintptr_t)1U)
 		p = imalloc_prof_sample(usize, cnt);
 	else
@@ -880,42 +917,22 @@ imalloc_prof(size_t usize, prof_thr_cnt_t *cnt)
 	return (p);
 }
 
-/*
- * MALLOC_BODY() is a macro rather than a function because its contents are in
- * the fast path, but inlining would cause reliability issues when determining
- * how many frames to discard from heap profiling backtraces.
- */
-#define	MALLOC_BODY(ret, size, usize) do {				\
-	if (malloc_init())						\
-		ret = NULL;						\
-	else {								\
-		if (config_prof && opt_prof) {				\
-			prof_thr_cnt_t *cnt;				\
-									\
-			usize = s2u(size);				\
-			/*						\
-			 * Call PROF_ALLOC_PREP() here rather than in	\
-			 * imalloc_prof() so that imalloc_prof() can be	\
-			 * inlined without introducing uncertainty	\
-			 * about the number of backtrace frames to	\
-			 * ignore.  imalloc_prof() is in the fast path	\
-			 * when heap profiling is enabled, so inlining	\
-			 * is critical to performance.  (For		\
-			 * consistency all callers of PROF_ALLOC_PREP()	\
-			 * are structured similarly, even though e.g.	\
-			 * realloc() isn't called enough for inlining	\
-			 * to be critical.)				\
-			 */						\
-			PROF_ALLOC_PREP(1, usize, cnt);			\
-			ret = imalloc_prof(usize, cnt);			\
-		} else {						\
-			if (config_stats || (config_valgrind &&		\
-			    opt_valgrind))				\
-				usize = s2u(size);			\
-			ret = imalloc(size);				\
-		}							\
-	}								\
-} while (0)
+JEMALLOC_ALWAYS_INLINE_C void *
+imalloc_body(size_t size, size_t *usize)
+{
+
+	if (malloc_init_base_pool())
+		return (NULL);
+
+	if (config_prof && opt_prof) {
+		*usize = s2u(size);
+		return (imalloc_prof(*usize));
+	}
+
+	if (config_stats || (config_valgrind && in_valgrind))
+		*usize = s2u(size);
+	return (imalloc(size));
+}
 
 void *
 je_malloc(size_t size)
@@ -926,8 +943,7 @@ je_malloc(size_t size)
 	if (size == 0)
 		size = 1;
 
-	MALLOC_BODY(ret, size, usize);
-
+	ret = imalloc_body(size, &usize);
 	if (ret == NULL) {
 		if (config_xmalloc && opt_xmalloc) {
 			malloc_write("<jemalloc>: Error in malloc(): "
@@ -952,7 +968,7 @@ imemalign_prof_sample(size_t alignment, size_t usize, prof_thr_cnt_t *cnt)
 
 	if (cnt == NULL)
 		return (NULL);
-	if (prof_promote && usize <= SMALL_MAXCLASS) {
+	if (usize <= SMALL_MAXCLASS) {
 		assert(sa2u(SMALL_MAXCLASS+1, alignment) != 0);
 		p = ipalloc(sa2u(SMALL_MAXCLASS+1, alignment), alignment,
 		    false);
@@ -982,13 +998,6 @@ imemalign_prof(size_t alignment, size_t usize, prof_thr_cnt_t *cnt)
 }
 
 JEMALLOC_ATTR(nonnull(1))
-#ifdef JEMALLOC_PROF
-/*
- * Avoid any uncertainty as to how many backtrace frames to ignore in
- * PROF_ALLOC_PREP().
- */
-JEMALLOC_NOINLINE
-#endif
 static int
 imemalign(void **memptr, size_t alignment, size_t size, size_t min_alignment)
 {
@@ -998,7 +1007,7 @@ imemalign(void **memptr, size_t alignment, size_t size, size_t min_alignment)
 
 	assert(min_alignment != 0);
 
-	if (malloc_init()) {
+	if (malloc_init_base_pool()) {
 		result = NULL;
 		goto label_oom;
 	} else {
@@ -1027,7 +1036,7 @@ imemalign(void **memptr, size_t alignment, size_t size, size_t min_alignment)
 		if (config_prof && opt_prof) {
 			prof_thr_cnt_t *cnt;
 
-			PROF_ALLOC_PREP(2, usize, cnt);
+			PROF_ALLOC_PREP(usize, cnt);
 			result = imemalign_prof(alignment, usize, cnt);
 		} else
 			result = ipalloc(usize, alignment, false);
@@ -1086,7 +1095,7 @@ icalloc_prof_sample(size_t usize, prof_thr_cnt_t *cnt)
 
 	if (cnt == NULL)
 		return (NULL);
-	if (prof_promote && usize <= SMALL_MAXCLASS) {
+	if (usize <= SMALL_MAXCLASS) {
 		p = icalloc(SMALL_MAXCLASS+1);
 		if (p == NULL)
 			return (NULL);
@@ -1120,7 +1129,7 @@ je_calloc(size_t num, size_t size)
 	size_t num_size;
 	size_t usize JEMALLOC_CC_SILENCE_INIT(0);
 
-	if (malloc_init()) {
+	if (malloc_init_base_pool()) {
 		num_size = 0;
 		ret = NULL;
 		goto label_return;
@@ -1150,10 +1159,10 @@ je_calloc(size_t num, size_t size)
 		prof_thr_cnt_t *cnt;
 
 		usize = s2u(num_size);
-		PROF_ALLOC_PREP(1, usize, cnt);
+		PROF_ALLOC_PREP(usize, cnt);
 		ret = icalloc_prof(usize, cnt);
 	} else {
-		if (config_stats || (config_valgrind && opt_valgrind))
+		if (config_stats || (config_valgrind && in_valgrind))
 			usize = s2u(num_size);
 		ret = icalloc(num_size);
 	}
@@ -1183,7 +1192,7 @@ irealloc_prof_sample(void *oldptr, size_t usize, prof_thr_cnt_t *cnt)
 
 	if (cnt == NULL)
 		return (NULL);
-	if (prof_promote && usize <= SMALL_MAXCLASS) {
+	if (usize <= SMALL_MAXCLASS) {
 		p = iralloc(oldptr, SMALL_MAXCLASS+1, 0, 0, false);
 		if (p == NULL)
 			return (NULL);
@@ -1220,6 +1229,7 @@ ifree(void *ptr)
 
 	assert(ptr != NULL);
 	assert(malloc_initialized || IS_INITIALIZER);
+	assert(pools[0] != NULL);
 
 	if (config_prof && opt_prof) {
 		usize = isalloc(ptr, config_prof);
@@ -1228,7 +1238,7 @@ ifree(void *ptr)
 		usize = isalloc(ptr, config_prof);
 	if (config_stats)
 		thread_allocated_tsd_get()->deallocated += usize;
-	if (config_valgrind && opt_valgrind)
+	if (config_valgrind && in_valgrind)
 		rzsize = p2rz(ptr);
 	iqalloc(ptr);
 	JEMALLOC_VALGRIND_FREE(ptr, rzsize);
@@ -1254,28 +1264,29 @@ je_realloc(void *ptr, size_t size)
 
 	if (ptr != NULL) {
 		assert(malloc_initialized || IS_INITIALIZER);
+		assert(pools[0] != NULL);
 		malloc_thread_init();
 
 		if ((config_prof && opt_prof) || config_stats ||
-		    (config_valgrind && opt_valgrind))
+		    (config_valgrind && in_valgrind))
 			old_usize = isalloc(ptr, config_prof);
-		if (config_valgrind && opt_valgrind)
+		if (config_valgrind && in_valgrind)
 			old_rzsize = config_prof ? p2rz(ptr) : u2rz(old_usize);
 
 		if (config_prof && opt_prof) {
 			prof_thr_cnt_t *cnt;
 
 			usize = s2u(size);
-			PROF_ALLOC_PREP(1, usize, cnt);
+			PROF_ALLOC_PREP(usize, cnt);
 			ret = irealloc_prof(ptr, old_usize, usize, cnt);
 		} else {
-			if (config_stats || (config_valgrind && opt_valgrind))
+			if (config_stats || (config_valgrind && in_valgrind))
 				usize = s2u(size);
 			ret = iralloc(ptr, size, 0, 0, false);
 		}
 	} else {
 		/* realloc(NULL, size) is equivalent to malloc(size). */
-		MALLOC_BODY(ret, size, usize);
+		ret = imalloc_body(size, &usize);
 	}
 
 	if (ret == NULL) {
@@ -1294,8 +1305,8 @@ je_realloc(void *ptr, size_t size)
 		ta->deallocated += old_usize;
 	}
 	UTRACE(ptr, size, ret);
-	JEMALLOC_VALGRIND_REALLOC(ret, usize, ptr, old_usize, old_rzsize,
-	    false);
+	JEMALLOC_VALGRIND_REALLOC(true, ret, usize, true, ptr, old_usize,
+	    old_rzsize, true, false);
 	return (ret);
 }
 
@@ -1356,10 +1367,10 @@ je_valloc(size_t size)
  * passed an extra argument for the caller return address, which will be
  * ignored.
  */
-JEMALLOC_EXPORT void (* __free_hook)(void *ptr) = je_free;
-JEMALLOC_EXPORT void *(* __malloc_hook)(size_t size) = je_malloc;
-JEMALLOC_EXPORT void *(* __realloc_hook)(void *ptr, size_t size) = je_realloc;
-JEMALLOC_EXPORT void *(* __memalign_hook)(size_t alignment, size_t size) =
+JEMALLOC_EXPORT void (*__free_hook)(void *ptr) = je_free;
+JEMALLOC_EXPORT void *(*__malloc_hook)(size_t size) = je_malloc;
+JEMALLOC_EXPORT void *(*__realloc_hook)(void *ptr, size_t size) = je_realloc;
+JEMALLOC_EXPORT void *(*__memalign_hook)(size_t alignment, size_t size) =
     je_memalign;
 #endif
 
@@ -1371,56 +1382,242 @@ JEMALLOC_EXPORT void *(* __memalign_hook)(size_t alignment, size_t size) =
  * Begin non-standard functions.
  */
 
-JEMALLOC_ALWAYS_INLINE_C void *
-imallocx(size_t usize, size_t alignment, bool zero, bool try_tcache,
-    arena_t *arena)
+static void*
+base_malloc_default(size_t size)
 {
+	pool_t *pool = pools[0];
+	return base_alloc(pool, size);
+}
 
-	assert(usize == ((alignment == 0) ? s2u(usize) : sa2u(usize,
-	    alignment)));
+static void
+base_free_default(void *ptr)
+{
 
-	if (alignment != 0)
-		return (ipalloct(usize, alignment, zero, try_tcache, arena));
-	else if (zero)
-		return (icalloct(usize, try_tcache, arena));
-	else
-		return (imalloct(usize, try_tcache, arena));
+}
+
+static bool
+pools_shared_data_create(void)
+{
+	if (malloc_initialized == false && malloc_init_hard())
+		return (true);
+
+	assert(je_base_malloc != base_malloc_default || pools[0] != NULL);
+
+	if (pools_shared_data_initialized)
+		return (false);
+
+	if (config_tcache && tcache_boot0()) {
+		return (true);
+	}
+
+	pools_shared_data_initialized = true;
+
+	return (false);
+}
+
+void pools_shared_data_destroy(void)
+{
+	/* Only destroy when no pools exist */
+	if (npools == 0) {
+		pools_shared_data_initialized = false;
+
+		je_base_free(tcache_bin_info);
+		tcache_bin_info = NULL;
+	}
+}
+
+pool_t *
+je_pool_create(void *addr, size_t size, int zeroed)
+{
+	if (addr == NULL || size < POOL_MINIMAL_SIZE)
+		return NULL;
+
+	pool_t *pool = (pool_t *)addr;
+	unsigned pool_id = POOLS_MAX;
+	size_t result;
+
+	if (je_base_malloc == base_malloc_default) {
+		/* Preinit base pool if not exist, before lock pool_lock */
+		if (malloc_init_base_pool())
+			return NULL;
+	}
+
+	malloc_mutex_lock(&pools_lock);
+
+	/* Find unused pool ID */
+	if (npools < POOLS_MAX) {
+		/*
+		 * Pool 0 is a special pool with reserved ID. Pool is created during
+		 * malloc_init_pool_base() and allocates memory from RAM.
+		 */
+		int i;
+		for (i = 1; i < POOLS_MAX; ++i) {
+			if (pools[i] == NULL) {
+				pool_id = i;
+				break;
+			}
+		}
+	}
+
+	if (pool_id == POOLS_MAX) {
+		malloc_mutex_unlock(&pools_lock);
+		malloc_printf("<jemalloc>: Too many pools\n");
+		return NULL;
+	}
+
+	if (pools_shared_data_create()) {
+		malloc_mutex_unlock(&pools_lock);
+		return NULL;
+	}
+
+	if (!zeroed)
+		memset(addr, 0, sizeof (pool_t));
+
+	/* preinit base allocator in unused space, align the address to the cache line */
+	pool->base_next_addr = (void *)CACHELINE_CEILING((uintptr_t)addr +
+		sizeof (pool_t));
+	pool->base_past_addr = (void *)((uintptr_t)addr + size);
+
+	/* prepare pool and internal structures */
+	if (pool_new(pool, pool_id)) {
+		assert(pools[pool_id] == NULL);
+		malloc_mutex_unlock(&pools_lock);
+		pools_shared_data_destroy();
+		return NULL;
+	}
+
+	/* preallocate the chunk tree nodes for the maximum possible number of chunks */
+	result = base_node_prealloc(pool, size/chunksize);
+	assert(result == 0);
+
+	assert(pools[pool_id] == NULL);
+	pool->seqno = pool_seqno++;
+	pools[pool_id] = pool;
+	npools++;
+	malloc_mutex_unlock(&pools_lock);
+
+	/* pointer to the address of chunks, align the address to chunksize */
+	void *usable_addr = (void*)CHUNK_CEILING((uintptr_t)pool->base_next_addr);
+
+	/* reduce end of base allocator up to chunks start */
+	pool->base_past_addr = usable_addr;
+
+	/* usable chunks space, must be multiple of chunksize */
+	size_t usable_size = (size - (uintptr_t)(usable_addr - addr))
+		& ~chunksize_mask;
+
+	assert(usable_size > 0);
+
+	/* register the usable pool space as a single big chunk */
+	chunk_record(pool,
+		&pool->chunks_szad_mmap, &pool->chunks_ad_mmap,
+		usable_addr, usable_size, zeroed);
+
+	pool->ctl_initialized = false;
+
+	return pool;
+}
+
+void
+je_pool_delete(pool_t *pool)
+{
+	unsigned pool_id = pool->pool_id;
+
+	/* Remove pool from global array */
+	malloc_mutex_lock(&pools_lock);
+	pool_destroy(pool);
+	pools[pool_id] = NULL;
+	npools--;
+
+	/*
+	 * TODO: Destroy mutex
+	 * base_mtx
+	 */
+
+	pools_shared_data_destroy();
+
+	malloc_mutex_unlock(&pools_lock);
+}
+
+/*
+ * add more memory to a pool
+ */
+size_t
+je_pool_extend(pool_t *pool, void *addr, size_t size, int zeroed)
+{
+	void *usable_addr = addr;
+	size_t nodes_number = size/chunksize;
+	if (size < POOL_MINIMAL_SIZE)
+		return 0;
+
+	/* preallocate the chunk tree nodes for the maximum possible number of chunks */
+	nodes_number = base_node_prealloc(pool, nodes_number);
+	if (nodes_number > 0) {
+		/*
+		 * If base allocation using existing chunks fails, then use the new
+		 * chunk as a source for further base allocations.
+		 */
+		malloc_mutex_lock(&pool->base_mtx);
+		/* preinit base allocator in unused space, align the address to the cache line */
+		pool->base_next_addr = (void *)CACHELINE_CEILING((uintptr_t)addr);
+		pool->base_past_addr = (void *)((uintptr_t)addr + size);
+		malloc_mutex_unlock(&pool->base_mtx);
+
+		nodes_number = base_node_prealloc(pool, nodes_number);
+		assert(nodes_number == 0);
+
+		/* pointer to the address of chunks, align the address to chunksize */
+		usable_addr = (void*)CHUNK_CEILING((uintptr_t)pool->base_next_addr);
+		/* reduce end of base allocator up to chunks */
+		pool->base_past_addr = usable_addr;
+	}
+
+
+	usable_addr = (void*)CHUNK_CEILING((uintptr_t)usable_addr);
+
+	size_t usable_size = (size - (uintptr_t)(usable_addr - addr))
+		& ~chunksize_mask;
+
+	assert(usable_size > 0);
+
+	chunk_record(pool,
+		&pool->chunks_szad_mmap, &pool->chunks_ad_mmap,
+		usable_addr, usable_size, zeroed);
+
+	return usable_size;
 }
 
 static void *
-imallocx_prof_sample(size_t usize, size_t alignment, bool zero, bool try_tcache,
-    arena_t *arena, prof_thr_cnt_t *cnt)
+pool_ialloc_prof_sample(pool_t *pool, size_t usize, prof_thr_cnt_t *cnt,
+	void *(*ialloc)(pool_t *, size_t))
 {
 	void *p;
 
 	if (cnt == NULL)
 		return (NULL);
-	if (prof_promote && usize <= SMALL_MAXCLASS) {
-		size_t usize_promoted = (alignment == 0) ?
-		    s2u(SMALL_MAXCLASS+1) : sa2u(SMALL_MAXCLASS+1, alignment);
-		assert(usize_promoted != 0);
-		p = imallocx(usize_promoted, alignment, zero, try_tcache,
-		    arena);
+	if (usize <= SMALL_MAXCLASS) {
+		p = ialloc(pool, SMALL_MAXCLASS+1);
 		if (p == NULL)
 			return (NULL);
 		arena_prof_promoted(p, usize);
 	} else
-		p = imallocx(usize, alignment, zero, try_tcache, arena);
+		p = ialloc(pool, usize);
 
 	return (p);
 }
 
 JEMALLOC_ALWAYS_INLINE_C void *
-imallocx_prof(size_t usize, size_t alignment, bool zero, bool try_tcache,
-    arena_t *arena, prof_thr_cnt_t *cnt)
+pool_ialloc_prof(pool_t *pool, size_t usize,
+	void *(*ialloc)(pool_t *, size_t))
 {
 	void *p;
+	prof_thr_cnt_t *cnt;
 
-	if ((uintptr_t)cnt != (uintptr_t)1U) {
-		p = imallocx_prof_sample(usize, alignment, zero, try_tcache,
-		    arena, cnt);
-	} else
-		p = imallocx(usize, alignment, zero, try_tcache, arena);
+	PROF_ALLOC_PREP(usize, cnt);
+	if ((uintptr_t)cnt != (uintptr_t)1U)
+		p = pool_ialloc_prof_sample(pool, usize, cnt, ialloc);
+	else
+		p = ialloc(pool, usize);
 	if (p == NULL)
 		return (NULL);
 	prof_malloc(p, usize, cnt);
@@ -1428,39 +1625,480 @@ imallocx_prof(size_t usize, size_t alignment, bool zero, bool try_tcache,
 	return (p);
 }
 
-void *
-je_mallocx(size_t size, int flags)
+JEMALLOC_ALWAYS_INLINE_C void *
+pool_imalloc_body(pool_t *pool, size_t size, size_t *usize)
 {
-	void *p;
-	size_t usize;
-	size_t alignment = (ZU(1) << (flags & MALLOCX_LG_ALIGN_MASK)
-	    & (SIZE_T_MAX-1));
-	bool zero = flags & MALLOCX_ZERO;
-	unsigned arena_ind = ((unsigned)(flags >> 8)) - 1;
-	arena_t *arena;
-	bool try_tcache;
-
-	assert(size != 0);
 
 	if (malloc_init())
-		goto label_oom;
+		return (NULL);
 
-	if (arena_ind != UINT_MAX) {
-		arena = arenas[arena_ind];
-		try_tcache = false;
-	} else {
-		arena = NULL;
-		try_tcache = true;
+	if (config_prof && opt_prof) {
+		*usize = s2u(size);
+		return (pool_ialloc_prof(pool, *usize, pool_imalloc));
 	}
 
-	usize = (alignment == 0) ? s2u(size) : sa2u(size, alignment);
-	assert(usize != 0);
+	if (config_stats || (config_valgrind && in_valgrind))
+		*usize = s2u(size);
+	return (pool_imalloc(pool, size));
+}
 
-	if (config_prof && opt_prof) {
-		prof_thr_cnt_t *cnt;
+void *
+je_pool_malloc(pool_t *pool, size_t size)
+{
+	void *ret;
+	size_t usize JEMALLOC_CC_SILENCE_INIT(0);
 
-		PROF_ALLOC_PREP(1, usize, cnt);
-		p = imallocx_prof(usize, alignment, zero, try_tcache, arena,
+	if (size == 0)
+		size = 1;
+
+	ret = pool_imalloc_body(pool, size, &usize);
+	if (ret == NULL) {
+		if (config_xmalloc && opt_xmalloc) {
+			malloc_write("<jemalloc>: Error in pool_malloc(): "
+			    "out of memory\n");
+			abort();
+		}
+		set_errno(ENOMEM);
+	}
+	if (config_stats && ret != NULL) {
+		assert(usize == isalloc(ret, config_prof));
+		thread_allocated_tsd_get()->allocated += usize;
+	}
+	UTRACE(0, size, ret);
+	JEMALLOC_VALGRIND_MALLOC(ret != NULL, ret, usize, false);
+	return (ret);
+}
+
+void *
+je_pool_calloc(pool_t *pool, size_t num, size_t size)
+{
+	void *ret;
+	size_t usize JEMALLOC_CC_SILENCE_INIT(0);
+	size_t num_size;
+
+	num_size = num * size;
+	if (num_size == 0) {
+		if (num == 0 || size == 0)
+			num_size = 1;
+		else {
+			ret = NULL;
+			goto label_return;
+		}
+
+	} else if (((num | size) & (SIZE_T_MAX << (sizeof(size_t) << 2)))
+	    && (num_size / size != num)) {
+		ret = NULL;
+		goto label_return;
+	}
+
+	if (config_prof && opt_prof) {
+		usize = s2u(num_size);
+		ret = pool_ialloc_prof(pool, usize, pool_icalloc);
+	} else {
+		if (config_stats || (config_valgrind && in_valgrind))
+			usize = s2u(num_size);
+		ret = pool_icalloc(pool, num_size);
+	}
+
+label_return:
+	if (ret == NULL) {
+		if (config_xmalloc && opt_xmalloc) {
+			malloc_write("<jemalloc>: Error in pool_calloc(): "
+				"out of memory\n");
+			abort();
+		}
+		set_errno(ENOMEM);
+	}
+	if (config_stats && ret != NULL) {
+		assert(usize == isalloc(ret, config_prof));
+		thread_allocated_tsd_get()->allocated += usize;
+	}
+	UTRACE(0, num_size, ret);
+	JEMALLOC_VALGRIND_MALLOC(ret != NULL, ret, usize, true);
+	return (ret);
+}
+
+static void *
+pool_irealloc_prof_sample(pool_t *pool, void *oldptr, size_t usize,
+	prof_thr_cnt_t *cnt)
+{
+	void *p;
+
+	if (cnt == NULL)
+		return (NULL);
+	if (usize <= SMALL_MAXCLASS) {
+		p = pool_iralloc(pool, oldptr, SMALL_MAXCLASS+1, 0, 0, false);
+		if (p == NULL)
+			return (NULL);
+		arena_prof_promoted(p, usize);
+	} else
+		p = pool_iralloc(pool, oldptr, usize, 0, 0, false);
+
+	return (p);
+}
+
+JEMALLOC_ALWAYS_INLINE_C void *
+pool_irealloc_prof(pool_t *pool, void *oldptr, size_t old_usize,
+	size_t usize, prof_thr_cnt_t *cnt)
+{
+	void *p;
+	prof_ctx_t *old_ctx;
+
+	old_ctx = prof_ctx_get(oldptr);
+	if ((uintptr_t)cnt != (uintptr_t)1U)
+		p = pool_irealloc_prof_sample(pool, oldptr, usize, cnt);
+	else
+		p = pool_iralloc(pool, oldptr, usize, 0, 0, false);
+	if (p == NULL)
+		return (NULL);
+	prof_realloc(p, usize, cnt, old_usize, old_ctx);
+
+	return (p);
+}
+
+JEMALLOC_INLINE_C void
+pool_ifree(pool_t *pool, void *ptr)
+{
+	size_t usize;
+	UNUSED size_t rzsize JEMALLOC_CC_SILENCE_INIT(0);
+	arena_chunk_t *chunk;
+
+	assert(ptr != NULL);
+	assert(malloc_initialized || IS_INITIALIZER);
+
+	if (config_prof && opt_prof) {
+		usize = isalloc(ptr, config_prof);
+		prof_free(ptr, usize);
+	} else if (config_stats || config_valgrind)
+		usize = isalloc(ptr, config_prof);
+	if (config_stats)
+		thread_allocated_tsd_get()->deallocated += usize;
+	if (config_valgrind && in_valgrind)
+		rzsize = p2rz(ptr);
+
+	chunk = (arena_chunk_t *)CHUNK_ADDR2BASE(ptr);
+	if (chunk != ptr)
+		arena_dalloc(chunk, ptr, false);
+	else
+		huge_dalloc(pool, ptr);
+
+	JEMALLOC_VALGRIND_FREE(ptr, rzsize);
+}
+
+void *
+je_pool_ralloc(pool_t *pool, void *ptr, size_t size)
+{
+	void *ret;
+	size_t usize JEMALLOC_CC_SILENCE_INIT(0);
+	size_t old_usize = 0;
+	UNUSED size_t old_rzsize JEMALLOC_CC_SILENCE_INIT(0);
+
+	if (size == 0) {
+		if (ptr != NULL) {
+			/* realloc(ptr, 0) is equivalent to free(ptr). */
+			UTRACE(ptr, 0, 0);
+			pool_ifree(pool, ptr);
+			return (NULL);
+		}
+		size = 1;
+	}
+
+	if (ptr != NULL) {
+		assert(malloc_initialized || IS_INITIALIZER);
+		malloc_init();
+
+		if ((config_prof && opt_prof) || config_stats ||
+		    (config_valgrind && in_valgrind))
+			old_usize = isalloc(ptr, config_prof);
+		if (config_valgrind && in_valgrind)
+			old_rzsize = config_prof ? p2rz(ptr) : u2rz(old_usize);
+
+		if (config_prof && opt_prof) {
+			prof_thr_cnt_t *cnt;
+
+			usize = s2u(size);
+			PROF_ALLOC_PREP(usize, cnt);
+			ret = pool_irealloc_prof(pool, ptr, old_usize,
+				usize, cnt);
+		} else {
+			if (config_stats || (config_valgrind && in_valgrind))
+				usize = s2u(size);
+			ret = pool_iralloc(pool, ptr, size, 0, 0, false);
+		}
+	} else {
+		/* realloc(NULL, size) is equivalent to malloc(size). */
+		ret = pool_imalloc_body(pool, size, &usize);
+	}
+
+	if (ret == NULL) {
+		if (config_xmalloc && opt_xmalloc) {
+			malloc_write("<jemalloc>: Error in pool_ralloc(): "
+			    "out of memory\n");
+			abort();
+		}
+		set_errno(ENOMEM);
+	}
+	if (config_stats && ret != NULL) {
+		thread_allocated_t *ta;
+		assert(usize == isalloc(ret, config_prof));
+		ta = thread_allocated_tsd_get();
+		ta->allocated += usize;
+		ta->deallocated += old_usize;
+	}
+	UTRACE(ptr, size, ret);
+	JEMALLOC_VALGRIND_REALLOC(true, ret, usize, true, ptr, old_usize,
+	    old_rzsize, true, false);
+	return (ret);
+}
+
+static void *
+pool_imemalign_prof_sample(pool_t *pool, size_t alignment, size_t usize,
+	prof_thr_cnt_t *cnt)
+{
+	void *p;
+
+	if (cnt == NULL)
+		return (NULL);
+	if (usize <= SMALL_MAXCLASS) {
+		assert(sa2u(SMALL_MAXCLASS+1, alignment) != 0);
+		p = pool_ipalloc(pool, sa2u(SMALL_MAXCLASS+1, alignment),
+			alignment, false);
+		if (p == NULL)
+			return (NULL);
+		arena_prof_promoted(p, usize);
+	} else
+		p = pool_ipalloc(pool, usize, alignment, false);
+
+	return (p);
+}
+
+JEMALLOC_ALWAYS_INLINE_C void *
+pool_imemalign_prof(pool_t *pool, size_t alignment, size_t usize,
+	prof_thr_cnt_t *cnt)
+{
+	void *p;
+
+	if ((uintptr_t)cnt != (uintptr_t)1U)
+		p = pool_imemalign_prof_sample(pool, alignment, usize, cnt);
+	else
+		p = pool_ipalloc(pool, usize, alignment, false);
+	if (p == NULL)
+		return (NULL);
+	prof_malloc(p, usize, cnt);
+
+	return (p);
+}
+
+JEMALLOC_ATTR(nonnull(1))
+static int
+pool_imemalign(pool_t *pool, void **memptr, size_t alignment, size_t size,
+	size_t min_alignment)
+{
+	int ret;
+	size_t usize;
+	void *result;
+
+	assert(min_alignment != 0);
+
+	if (malloc_init()) {
+		result = NULL;
+		goto label_oom;
+	} else {
+		if (size == 0)
+			size = 1;
+
+		/* Make sure that alignment is a large enough power of 2. */
+		if (((alignment - 1) & alignment) != 0
+		    || (alignment < min_alignment)) {
+			if (config_xmalloc && opt_xmalloc) {
+				malloc_write("<jemalloc>: Error allocating pool"
+				    " aligned memory: invalid alignment\n");
+				abort();
+			}
+			result = NULL;
+			ret = EINVAL;
+			goto label_return;
+		}
+
+		usize = sa2u(size, alignment);
+		if (usize == 0) {
+			result = NULL;
+			goto label_oom;
+		}
+
+		if (config_prof && opt_prof) {
+			prof_thr_cnt_t *cnt;
+
+			PROF_ALLOC_PREP(usize, cnt);
+			result = pool_imemalign_prof(pool, alignment,
+				usize, cnt);
+		} else
+			result = pool_ipalloc(pool, usize, alignment, false);
+		if (result == NULL)
+			goto label_oom;
+	}
+
+	*memptr = result;
+	ret = 0;
+label_return:
+	if (config_stats && result != NULL) {
+		assert(usize == isalloc(result, config_prof));
+		thread_allocated_tsd_get()->allocated += usize;
+	}
+	UTRACE(0, size, result);
+	return (ret);
+label_oom:
+	assert(result == NULL);
+	if (config_xmalloc && opt_xmalloc) {
+		malloc_write("<jemalloc>: Error allocating pool "
+			"aligned memory: out of memory\n");
+		abort();
+	}
+	ret = ENOMEM;
+	goto label_return;
+}
+
+void *
+je_pool_aligned_alloc(pool_t *pool, size_t alignment, size_t size)
+{
+	void *ret;
+	int err;
+
+	if ((err = pool_imemalign(pool, &ret, alignment, size, 1)) != 0) {
+		ret = NULL;
+		set_errno(err);
+	}
+	JEMALLOC_VALGRIND_MALLOC(err == 0, ret, isalloc(ret, config_prof),
+	    false);
+	return (ret);
+}
+
+void
+je_pool_free(pool_t *pool, void *ptr)
+{
+	UTRACE(ptr, 0, 0);
+	if (ptr != NULL)
+		pool_ifree(pool, ptr);
+}
+
+void
+je_pool_malloc_stats_print(pool_t *pool,
+				void (*write_cb)(void *, const char *),
+				void *cbopaque, const char *opts)
+{
+
+	stats_print(pool, write_cb, cbopaque, opts);
+}
+
+void
+je_pool_set_alloc_funcs(void *(*malloc_func)(size_t),
+				void (*free_func)(void *))
+{
+	if (malloc_func != NULL && free_func != NULL) {
+		malloc_mutex_lock(&pool_base_lock);
+		if (pools[0] == NULL) {
+			je_base_malloc = malloc_func;
+			je_base_free = free_func;
+		}
+		malloc_mutex_unlock(&pool_base_lock);
+	}
+}
+
+
+JEMALLOC_ALWAYS_INLINE_C void *
+imallocx(size_t usize, size_t alignment, bool zero, bool try_tcache,
+    arena_t *arena)
+{
+
+	assert(usize == ((alignment == 0) ? s2u(usize) : sa2u(usize,
+	    alignment)));
+
+	if (alignment != 0)
+		return (ipalloct(usize, alignment, zero, try_tcache, arena));
+	else if (zero)
+		return (icalloct(usize, try_tcache, arena));
+	else
+		return (imalloct(usize, try_tcache, arena));
+}
+
+static void *
+imallocx_prof_sample(size_t usize, size_t alignment, bool zero, bool try_tcache,
+    arena_t *arena, prof_thr_cnt_t *cnt)
+{
+	void *p;
+
+	if (cnt == NULL)
+		return (NULL);
+	if (usize <= SMALL_MAXCLASS) {
+		size_t usize_promoted = (alignment == 0) ?
+		    s2u(SMALL_MAXCLASS+1) : sa2u(SMALL_MAXCLASS+1, alignment);
+		assert(usize_promoted != 0);
+		p = imallocx(usize_promoted, alignment, zero, try_tcache,
+		    arena);
+		if (p == NULL)
+			return (NULL);
+		arena_prof_promoted(p, usize);
+	} else
+		p = imallocx(usize, alignment, zero, try_tcache, arena);
+
+	return (p);
+}
+
+JEMALLOC_ALWAYS_INLINE_C void *
+imallocx_prof(size_t usize, size_t alignment, bool zero, bool try_tcache,
+    arena_t *arena, prof_thr_cnt_t *cnt)
+{
+	void *p;
+
+	if ((uintptr_t)cnt != (uintptr_t)1U) {
+		p = imallocx_prof_sample(usize, alignment, zero, try_tcache,
+		    arena, cnt);
+	} else
+		p = imallocx(usize, alignment, zero, try_tcache, arena);
+	if (p == NULL)
+		return (NULL);
+	prof_malloc(p, usize, cnt);
+
+	return (p);
+}
+
+void *
+je_mallocx(size_t size, int flags)
+{
+	void *p;
+	size_t usize;
+	size_t alignment = (ZU(1) << (flags & MALLOCX_LG_ALIGN_MASK)
+	    & (SIZE_T_MAX-1));
+	bool zero = flags & MALLOCX_ZERO;
+	unsigned arena_ind = ((unsigned)(flags >> 8)) - 1;
+	unsigned pool_id = 0; // TODO add another flag
+	pool_t *pool = pools[pool_id];
+	arena_t dummy_arena;
+	DUMMY_ARENA_INITIALIZE(dummy_arena, pool);
+	arena_t *arena;
+	bool try_tcache;
+
+	assert(size != 0);
+
+	if (malloc_init_base_pool())
+		goto label_oom;
+
+	if (arena_ind != UINT_MAX) {
+		arena = pool->arenas[arena_ind];
+		try_tcache = false;
+	} else {
+		arena = &dummy_arena;
+		try_tcache = true;
+	}
+
+	usize = (alignment == 0) ? s2u(size) : sa2u(size, alignment);
+	assert(usize != 0);
+
+	if (config_prof && opt_prof) {
+		prof_thr_cnt_t *cnt;
+
+		PROF_ALLOC_PREP(usize, cnt);
+		p = imallocx_prof(usize, alignment, zero, try_tcache, arena,
 		    cnt);
 	} else
 		p = imallocx(usize, alignment, zero, try_tcache, arena);
@@ -1492,7 +2130,7 @@ irallocx_prof_sample(void *oldptr, size_t size, size_t alignment, size_t usize,
 
 	if (cnt == NULL)
 		return (NULL);
-	if (prof_promote && usize <= SMALL_MAXCLASS) {
+	if (usize <= SMALL_MAXCLASS) {
 		p = iralloct(oldptr, SMALL_MAXCLASS+1, (SMALL_MAXCLASS+1 >=
 		    size) ? 0 : size - (SMALL_MAXCLASS+1), alignment, zero,
 		    try_tcache_alloc, try_tcache_dalloc, arena);
@@ -1552,12 +2190,17 @@ je_rallocx(void *ptr, size_t size, int flags)
 	    & (SIZE_T_MAX-1));
 	bool zero = flags & MALLOCX_ZERO;
 	unsigned arena_ind = ((unsigned)(flags >> 8)) - 1;
+	unsigned pool_id = 0; // TODO add another flag
+	pool_t *pool = pools[pool_id];
+	arena_t dummy_arena;
+	DUMMY_ARENA_INITIALIZE(dummy_arena, pool);
 	bool try_tcache_alloc, try_tcache_dalloc;
 	arena_t *arena;
 
 	assert(ptr != NULL);
 	assert(size != 0);
 	assert(malloc_initialized || IS_INITIALIZER);
+	assert(pools[0] != NULL);
 	malloc_thread_init();
 
 	if (arena_ind != UINT_MAX) {
@@ -1565,18 +2208,18 @@ je_rallocx(void *ptr, size_t size, int flags)
 		try_tcache_alloc = false;
 		chunk = (arena_chunk_t *)CHUNK_ADDR2BASE(ptr);
 		try_tcache_dalloc = (chunk == ptr || chunk->arena !=
-		    arenas[arena_ind]);
-		arena = arenas[arena_ind];
+		    pool->arenas[arena_ind]);
+		arena = pool->arenas[arena_ind];
 	} else {
 		try_tcache_alloc = true;
 		try_tcache_dalloc = true;
-		arena = NULL;
+		arena = &dummy_arena;
 	}
 
 	if ((config_prof && opt_prof) || config_stats ||
-	    (config_valgrind && opt_valgrind))
+	    (config_valgrind && in_valgrind))
 		old_usize = isalloc(ptr, config_prof);
-	if (config_valgrind && opt_valgrind)
+	if (config_valgrind && in_valgrind)
 		old_rzsize = u2rz(old_usize);
 
 	if (config_prof && opt_prof) {
@@ -1584,7 +2227,7 @@ je_rallocx(void *ptr, size_t size, int flags)
 
 		usize = (alignment == 0) ? s2u(size) : sa2u(size, alignment);
 		assert(usize != 0);
-		PROF_ALLOC_PREP(1, usize, cnt);
+		PROF_ALLOC_PREP(usize, cnt);
 		p = irallocx_prof(ptr, old_usize, size, alignment, &usize, zero,
 		    try_tcache_alloc, try_tcache_dalloc, arena, cnt);
 		if (p == NULL)
@@ -1594,7 +2237,7 @@ je_rallocx(void *ptr, size_t size, int flags)
 		    try_tcache_dalloc, arena);
 		if (p == NULL)
 			goto label_oom;
-		if (config_stats || (config_valgrind && opt_valgrind))
+		if (config_stats || (config_valgrind && in_valgrind))
 			usize = isalloc(p, config_prof);
 	}
 
@@ -1605,7 +2248,8 @@ je_rallocx(void *ptr, size_t size, int flags)
 		ta->deallocated += old_usize;
 	}
 	UTRACE(ptr, size, p);
-	JEMALLOC_VALGRIND_REALLOC(p, usize, ptr, old_usize, old_rzsize, zero);
+	JEMALLOC_VALGRIND_REALLOC(true, p, usize, false, ptr, old_usize,
+	    old_rzsize, false, zero);
 	return (p);
 label_oom:
 	if (config_xmalloc && opt_xmalloc) {
@@ -1639,8 +2283,8 @@ ixallocx_prof_sample(void *ptr, size_t old_usize, size_t size, size_t extra,
 	if (cnt == NULL)
 		return (old_usize);
 	/* Use minimum usize to determine whether promotion may happen. */
-	if (prof_promote && ((alignment == 0) ? s2u(size) : sa2u(size,
-	    alignment)) <= SMALL_MAXCLASS) {
+	if (((alignment == 0) ? s2u(size) : sa2u(size, alignment)) <=
+	    SMALL_MAXCLASS) {
 		if (ixalloc(ptr, SMALL_MAXCLASS+1, (SMALL_MAXCLASS+1 >=
 		    size+extra) ? 0 : size+extra - (SMALL_MAXCLASS+1),
 		    alignment, zero))
@@ -1688,21 +2332,26 @@ je_xallocx(void *ptr, size_t size, size_t extra, int flags)
 	    & (SIZE_T_MAX-1));
 	bool zero = flags & MALLOCX_ZERO;
 	unsigned arena_ind = ((unsigned)(flags >> 8)) - 1;
+	unsigned pool_id = 0; // TODO add another flag
+	pool_t *pool = pools[pool_id];
+	arena_t dummy_arena;
+	DUMMY_ARENA_INITIALIZE(dummy_arena, pool);
 	arena_t *arena;
 
 	assert(ptr != NULL);
 	assert(size != 0);
 	assert(SIZE_T_MAX - size >= extra);
 	assert(malloc_initialized || IS_INITIALIZER);
+	assert(pools[0] != NULL);
 	malloc_thread_init();
 
 	if (arena_ind != UINT_MAX)
-		arena = arenas[arena_ind];
+		arena = pool->arenas[arena_ind];
 	else
-		arena = NULL;
+		arena = &dummy_arena;
 
 	old_usize = isalloc(ptr, config_prof);
-	if (config_valgrind && opt_valgrind)
+	if (config_valgrind && in_valgrind)
 		old_rzsize = u2rz(old_usize);
 
 	if (config_prof && opt_prof) {
@@ -1716,7 +2365,7 @@ je_xallocx(void *ptr, size_t size, size_t extra, int flags)
 		 */
 		size_t max_usize = (alignment == 0) ? s2u(size+extra) :
 		    sa2u(size+extra, alignment);
-		PROF_ALLOC_PREP(1, max_usize, cnt);
+		PROF_ALLOC_PREP(max_usize, cnt);
 		usize = ixallocx_prof(ptr, old_usize, size, extra, alignment,
 		    max_usize, zero, arena, cnt);
 	} else {
@@ -1732,7 +2381,8 @@ je_xallocx(void *ptr, size_t size, size_t extra, int flags)
 		ta->allocated += usize;
 		ta->deallocated += old_usize;
 	}
-	JEMALLOC_VALGRIND_REALLOC(ptr, usize, ptr, old_usize, old_rzsize, zero);
+	JEMALLOC_VALGRIND_REALLOC(false, ptr, usize, false, ptr, old_usize,
+	    old_rzsize, false, zero);
 label_not_resized:
 	UTRACE(ptr, size, ptr);
 	return (usize);
@@ -1744,6 +2394,7 @@ je_sallocx(const void *ptr, int flags)
 	size_t usize;
 
 	assert(malloc_initialized || IS_INITIALIZER);
+	assert(pools[0] != NULL);
 	malloc_thread_init();
 
 	if (config_ivsalloc)
@@ -1762,15 +2413,18 @@ je_dallocx(void *ptr, int flags)
 	size_t usize;
 	UNUSED size_t rzsize JEMALLOC_CC_SILENCE_INIT(0);
 	unsigned arena_ind = ((unsigned)(flags >> 8)) - 1;
+	unsigned pool_id = 0; // TODO add another flag
+	pool_t *pool = pools[pool_id];
 	bool try_tcache;
 
 	assert(ptr != NULL);
 	assert(malloc_initialized || IS_INITIALIZER);
+	assert(pools[0] != NULL);
 
 	if (arena_ind != UINT_MAX) {
 		arena_chunk_t *chunk = (arena_chunk_t *)CHUNK_ADDR2BASE(ptr);
 		try_tcache = (chunk == ptr || chunk->arena !=
-		    arenas[arena_ind]);
+		    pool->arenas[arena_ind]);
 	} else
 		try_tcache = true;
 
@@ -1784,7 +2438,7 @@ je_dallocx(void *ptr, int flags)
 	}
 	if (config_stats)
 		thread_allocated_tsd_get()->deallocated += usize;
-	if (config_valgrind && opt_valgrind)
+	if (config_valgrind && in_valgrind)
 		rzsize = p2rz(ptr);
 	iqalloct(ptr, try_tcache);
 	JEMALLOC_VALGRIND_FREE(ptr, rzsize);
@@ -1799,7 +2453,7 @@ je_nallocx(size_t size, int flags)
 
 	assert(size != 0);
 
-	if (malloc_init())
+	if (malloc_init_base_pool())
 		return (0);
 
 	usize = (alignment == 0) ? s2u(size) : sa2u(size, alignment);
@@ -1812,7 +2466,7 @@ je_mallctl(const char *name, void *oldp, size_t *oldlenp, void *newp,
     size_t newlen)
 {
 
-	if (malloc_init())
+	if (malloc_init_base_pool())
 		return (EAGAIN);
 
 	return (ctl_byname(name, oldp, oldlenp, newp, newlen));
@@ -1822,7 +2476,7 @@ int
 je_mallctlnametomib(const char *name, size_t *mibp, size_t *miblenp)
 {
 
-	if (malloc_init())
+	if (malloc_init_base_pool())
 		return (EAGAIN);
 
 	return (ctl_nametomib(name, mibp, miblenp));
@@ -1833,7 +2487,7 @@ je_mallctlbymib(const size_t *mib, size_t miblen, void *oldp, size_t *oldlenp,
   void *newp, size_t newlen)
 {
 
-	if (malloc_init())
+	if (malloc_init_base_pool())
 		return (EAGAIN);
 
 	return (ctl_bymib(mib, miblen, oldp, oldlenp, newp, newlen));
@@ -1843,8 +2497,8 @@ void
 je_malloc_stats_print(void (*write_cb)(void *, const char *), void *cbopaque,
     const char *opts)
 {
-
-	stats_print(write_cb, cbopaque, opts);
+	pool_t *base_pool = pools[0];
+	stats_print(base_pool, write_cb, cbopaque, opts);
 }
 
 size_t
@@ -1853,6 +2507,7 @@ je_malloc_usable_size(JEMALLOC_USABLE_SIZE_CONST void *ptr)
 	size_t ret;
 
 	assert(malloc_initialized || IS_INITIALIZER);
+	assert(pools[0] != NULL);
 	malloc_thread_init();
 
 	if (config_ivsalloc)
@@ -1867,91 +2522,6 @@ je_malloc_usable_size(JEMALLOC_USABLE_SIZE_CONST void *ptr)
  * End non-standard functions.
  */
 /******************************************************************************/
-/*
- * Begin experimental functions.
- */
-#ifdef JEMALLOC_EXPERIMENTAL
-
-int
-je_allocm(void **ptr, size_t *rsize, size_t size, int flags)
-{
-	void *p;
-
-	assert(ptr != NULL);
-
-	p = je_mallocx(size, flags);
-	if (p == NULL)
-		return (ALLOCM_ERR_OOM);
-	if (rsize != NULL)
-		*rsize = isalloc(p, config_prof);
-	*ptr = p;
-	return (ALLOCM_SUCCESS);
-}
-
-int
-je_rallocm(void **ptr, size_t *rsize, size_t size, size_t extra, int flags)
-{
-	int ret;
-	bool no_move = flags & ALLOCM_NO_MOVE;
-
-	assert(ptr != NULL);
-	assert(*ptr != NULL);
-	assert(size != 0);
-	assert(SIZE_T_MAX - size >= extra);
-
-	if (no_move) {
-		size_t usize = je_xallocx(*ptr, size, extra, flags);
-		ret = (usize >= size) ? ALLOCM_SUCCESS : ALLOCM_ERR_NOT_MOVED;
-		if (rsize != NULL)
-			*rsize = usize;
-	} else {
-		void *p = je_rallocx(*ptr, size+extra, flags);
-		if (p != NULL) {
-			*ptr = p;
-			ret = ALLOCM_SUCCESS;
-		} else
-			ret = ALLOCM_ERR_OOM;
-		if (rsize != NULL)
-			*rsize = isalloc(*ptr, config_prof);
-	}
-	return (ret);
-}
-
-int
-je_sallocm(const void *ptr, size_t *rsize, int flags)
-{
-
-	assert(rsize != NULL);
-	*rsize = je_sallocx(ptr, flags);
-	return (ALLOCM_SUCCESS);
-}
-
-int
-je_dallocm(void *ptr, int flags)
-{
-
-	je_dallocx(ptr, flags);
-	return (ALLOCM_SUCCESS);
-}
-
-int
-je_nallocm(size_t *rsize, size_t size, int flags)
-{
-	size_t usize;
-
-	usize = je_nallocx(size, flags);
-	if (usize == 0)
-		return (ALLOCM_ERR_OOM);
-	if (rsize != NULL)
-		*rsize = usize;
-	return (ALLOCM_SUCCESS);
-}
-
-#endif
-/*
- * End experimental functions.
- */
-/******************************************************************************/
 /*
  * The following functions are used by threading libraries for protection of
  * malloc during fork().
@@ -1978,6 +2548,16 @@ jemalloc_constructor(void)
 	malloc_init();
 }
 
+
+#define FOREACH_POOL(func)		\
+do {								\
+	unsigned i;					\
+	for (i = 0; i < POOLS_MAX; i++) {	\
+		if (pools[i])			\
+			(func)(pools[i]);	\
+	}							\
+} while(0)
+
 #ifndef JEMALLOC_MUTEX_INIT_CB
 void
 jemalloc_prefork(void)
@@ -1986,7 +2566,8 @@ JEMALLOC_EXPORT void
 _malloc_prefork(void)
 #endif
 {
-	unsigned i;
+	unsigned i, j;
+	pool_t *pool;
 
 #ifdef JEMALLOC_MUTEX_INIT_CB
 	if (malloc_initialized == false)
@@ -1997,14 +2578,22 @@ _malloc_prefork(void)
 	/* Acquire all mutexes in a safe order. */
 	ctl_prefork();
 	prof_prefork();
-	malloc_mutex_prefork(&arenas_lock);
-	for (i = 0; i < narenas_total; i++) {
-		if (arenas[i] != NULL)
-			arena_prefork(arenas[i]);
+	pool_prefork();
+	for (i = 0; i < POOLS_MAX; i++) {
+		pool = pools[i];
+		if (pool != NULL) {
+			for (j = 0; j < pool->narenas_total; j++) {
+				if (pool->arenas[j] != NULL)
+					arena_prefork(pool->arenas[j]);
+			}
+		}
 	}
-	chunk_prefork();
-	base_prefork();
-	huge_prefork();
+
+	FOREACH_POOL(chunk_prefork);
+
+	FOREACH_POOL(base_prefork);
+
+	FOREACH_POOL(huge_prefork);
 }
 
 #ifndef JEMALLOC_MUTEX_INIT_CB
@@ -2015,7 +2604,8 @@ JEMALLOC_EXPORT void
 _malloc_postfork(void)
 #endif
 {
-	unsigned i;
+	unsigned i, j;
+	pool_t *pool;
 
 #ifdef JEMALLOC_MUTEX_INIT_CB
 	if (malloc_initialized == false)
@@ -2024,14 +2614,22 @@ _malloc_postfork(void)
 	assert(malloc_initialized);
 
 	/* Release all mutexes, now that fork() has completed. */
-	huge_postfork_parent();
-	base_postfork_parent();
-	chunk_postfork_parent();
-	for (i = 0; i < narenas_total; i++) {
-		if (arenas[i] != NULL)
-			arena_postfork_parent(arenas[i]);
-	}
-	malloc_mutex_postfork_parent(&arenas_lock);
+	FOREACH_POOL(huge_postfork_parent);
+
+	FOREACH_POOL(base_postfork_parent);
+
+	FOREACH_POOL(chunk_postfork_parent);
+
+	for (i = 0; i < POOLS_MAX; i++) {
+		pool = pools[i];
+		if (pool != NULL) {
+			for (j = 0; j < pool->narenas_total; j++) {
+				if (pool->arenas[j] != NULL)
+					arena_postfork_parent(pool->arenas[j]);
+			}
+		}
+	}
+	pool_postfork_parent();
 	prof_postfork_parent();
 	ctl_postfork_parent();
 }
@@ -2039,19 +2637,28 @@ _malloc_postfork(void)
 void
 jemalloc_postfork_child(void)
 {
-	unsigned i;
+	unsigned i, j;
+	pool_t *pool;
 
 	assert(malloc_initialized);
 
 	/* Release all mutexes, now that fork() has completed. */
-	huge_postfork_child();
-	base_postfork_child();
-	chunk_postfork_child();
-	for (i = 0; i < narenas_total; i++) {
-		if (arenas[i] != NULL)
-			arena_postfork_child(arenas[i]);
-	}
-	malloc_mutex_postfork_child(&arenas_lock);
+	FOREACH_POOL(huge_postfork_child);
+
+	FOREACH_POOL(base_postfork_child);
+
+	FOREACH_POOL(chunk_postfork_child);
+
+	for (i = 0; i < POOLS_MAX; i++) {
+		pool = pools[i];
+		if (pool != NULL) {
+			for (j = 0; j < pool->narenas_total; j++) {
+				if (pool->arenas[j] != NULL)
+					arena_postfork_child(pool->arenas[j]);
+			}
+		}
+	}
+	pool_postfork_child();
 	prof_postfork_child();
 	ctl_postfork_child();
 }
@@ -2066,17 +2673,18 @@ jemalloc_postfork_child(void)
 static void *
 a0alloc(size_t size, bool zero)
 {
+	pool_t *base_pool = pools[0];
 
-	if (malloc_init())
+	if (malloc_init_base_pool())
 		return (NULL);
 
 	if (size == 0)
 		size = 1;
 
 	if (size <= arena_maxclass)
-		return (arena_malloc(arenas[0], size, zero, false));
+		return (arena_malloc(base_pool->arenas[0], size, zero, false));
 	else
-		return (huge_malloc(size, zero, huge_dss_prec_get(arenas[0])));
+		return (huge_malloc(NULL, size, zero));
 }
 
 void *
@@ -2096,6 +2704,7 @@ a0calloc(size_t num, size_t size)
 void
 a0free(void *ptr)
 {
+	pool_t *base_pool = pools[0];
 	arena_chunk_t *chunk;
 
 	if (ptr == NULL)
@@ -2103,9 +2712,9 @@ a0free(void *ptr)
 
 	chunk = (arena_chunk_t *)CHUNK_ADDR2BASE(ptr);
 	if (chunk != ptr)
-		arena_dalloc(chunk->arena, chunk, ptr, false);
+		arena_dalloc(chunk, ptr, false);
 	else
-		huge_dalloc(ptr, true);
+		huge_dalloc(base_pool, ptr);
 }
 
 /******************************************************************************/
diff --git a/src/jemalloc/src/pool.c b/src/jemalloc/src/pool.c
new file mode 100644
index 0000000000000000000000000000000000000000..f3cd79a6ef706ccc9822226972b6e995696e6a42
--- /dev/null
+++ b/src/jemalloc/src/pool.c
@@ -0,0 +1,99 @@
+#define	JEMALLOC_POOL_C_
+#include "jemalloc/internal/jemalloc_internal.h"
+
+malloc_mutex_t	pool_base_lock;
+malloc_mutex_t	pools_lock;
+
+/* Initialize pool and create its base arena. */
+bool pool_new(pool_t *pool, unsigned pool_id)
+{
+	pool->pool_id = pool_id;
+
+	if (malloc_mutex_init(&pool->arenas_lock)) {
+		return (true);
+	}
+
+	if (base_boot(pool)) {
+		return (true);
+	}
+
+	if (chunk_boot(pool)) {
+		return (true);
+	}
+
+	if (huge_boot(pool)) {
+		return (true);
+	}
+
+	pool->stats_cactive = 0;
+	pool->ctl_stats_active = 0;
+	pool->ctl_stats_allocated = 0;
+	pool->ctl_stats_mapped = 0;
+
+	pool->narenas_auto = opt_narenas;
+	/*
+	 * Make sure that the arenas array can be allocated.  In practice, this
+	 * limit is enough to allow the allocator to function, but the ctl
+	 * machinery will fail to allocate memory at far lower limits.
+	 */
+	if (pool->narenas_auto > chunksize / sizeof(arena_t *)) {
+		pool->narenas_auto = chunksize / sizeof(arena_t *);
+		malloc_printf("<jemalloc>: Reducing narenas to limit (%d)\n",
+		   pool->narenas_auto);
+	}
+	pool->narenas_total = pool->narenas_auto;
+
+	/* Allocate and initialize arenas. */
+	pool->arenas = (arena_t **)base_calloc(pool, sizeof(arena_t *),
+		pool->narenas_total);
+
+	if (pool->arenas == NULL) {
+		return (true);
+	}
+
+	arenas_extend(pool, 0);
+
+	return false;
+}
+
+/* Release the arenas associated with a pool. */
+void pool_destroy(pool_t *pool)
+{
+	int i;
+	for (i = 0; i < pool->narenas_total; ++i) {
+		if (pool->arenas[i] != NULL) {
+			arena_purge_all(pool->arenas[i]);
+		}
+	}
+}
+
+bool pool_boot()
+{
+	if (malloc_mutex_init(&pools_lock)) {
+		return (true);
+	}
+
+	if (malloc_mutex_init(&pool_base_lock)) {
+		return (true);
+	}
+
+	return (false);
+}
+
+void pool_prefork()
+{
+	malloc_mutex_prefork(&pools_lock);
+	malloc_mutex_prefork(&pool_base_lock);
+}
+
+void pool_postfork_parent()
+{
+	malloc_mutex_postfork_parent(&pools_lock);
+	malloc_mutex_prefork(&pool_base_lock);
+}
+
+void pool_postfork_child()
+{
+	malloc_mutex_postfork_child(&pools_lock);
+	malloc_mutex_prefork(&pool_base_lock);
+}
\ No newline at end of file
diff --git a/src/jemalloc/src/prof.c b/src/jemalloc/src/prof.c
index 7722b7b4373940feaccbc1ab7c15fc8da16fe483..1dd9b6117761a041d300476973a7037cf411d7b3 100644
--- a/src/jemalloc/src/prof.c
+++ b/src/jemalloc/src/prof.c
@@ -32,7 +32,6 @@ char		opt_prof_prefix[
     1];
 
 uint64_t	prof_interval = 0;
-bool		prof_promote;
 
 /*
  * Table of mutexes that are shared among ctx's.  These are leaf locks, so
@@ -159,38 +158,18 @@ prof_leave(prof_tdata_t *prof_tdata)
 
 #ifdef JEMALLOC_PROF_LIBUNWIND
 void
-prof_backtrace(prof_bt_t *bt, unsigned nignore)
+prof_backtrace(prof_bt_t *bt)
 {
-	unw_context_t uc;
-	unw_cursor_t cursor;
-	unsigned i;
-	int err;
+	int nframes;
 
 	cassert(config_prof);
 	assert(bt->len == 0);
 	assert(bt->vec != NULL);
 
-	unw_getcontext(&uc);
-	unw_init_local(&cursor, &uc);
-
-	/* Throw away (nignore+1) stack frames, if that many exist. */
-	for (i = 0; i < nignore + 1; i++) {
-		err = unw_step(&cursor);
-		if (err <= 0)
-			return;
-	}
-
-	/*
-	 * Iterate over stack frames until there are no more, or until no space
-	 * remains in bt.
-	 */
-	for (i = 0; i < PROF_BT_MAX; i++) {
-		unw_get_reg(&cursor, UNW_REG_IP, (unw_word_t *)&bt->vec[i]);
-		bt->len++;
-		err = unw_step(&cursor);
-		if (err <= 0)
-			break;
-	}
+	nframes = unw_backtrace(bt->vec, PROF_BT_MAX);
+	if (nframes <= 0)
+		return;
+	bt->len = nframes;
 }
 #elif (defined(JEMALLOC_PROF_LIBGCC))
 static _Unwind_Reason_Code
@@ -206,25 +185,25 @@ static _Unwind_Reason_Code
 prof_unwind_callback(struct _Unwind_Context *context, void *arg)
 {
 	prof_unwind_data_t *data = (prof_unwind_data_t *)arg;
+	void *ip;
 
 	cassert(config_prof);
 
-	if (data->nignore > 0)
-		data->nignore--;
-	else {
-		data->bt->vec[data->bt->len] = (void *)_Unwind_GetIP(context);
-		data->bt->len++;
-		if (data->bt->len == data->max)
-			return (_URC_END_OF_STACK);
-	}
+	ip = (void *)_Unwind_GetIP(context);
+	if (ip == NULL)
+		return (_URC_END_OF_STACK);
+	data->bt->vec[data->bt->len] = ip;
+	data->bt->len++;
+	if (data->bt->len == data->max)
+		return (_URC_END_OF_STACK);
 
 	return (_URC_NO_REASON);
 }
 
 void
-prof_backtrace(prof_bt_t *bt, unsigned nignore)
+prof_backtrace(prof_bt_t *bt)
 {
-	prof_unwind_data_t data = {bt, nignore, PROF_BT_MAX};
+	prof_unwind_data_t data = {bt, PROF_BT_MAX};
 
 	cassert(config_prof);
 
@@ -232,25 +211,22 @@ prof_backtrace(prof_bt_t *bt, unsigned nignore)
 }
 #elif (defined(JEMALLOC_PROF_GCC))
 void
-prof_backtrace(prof_bt_t *bt, unsigned nignore)
+prof_backtrace(prof_bt_t *bt)
 {
 #define	BT_FRAME(i)							\
-	if ((i) < nignore + PROF_BT_MAX) {				\
+	if ((i) < PROF_BT_MAX) {					\
 		void *p;						\
 		if (__builtin_frame_address(i) == 0)			\
 			return;						\
 		p = __builtin_return_address(i);			\
 		if (p == NULL)						\
 			return;						\
-		if (i >= nignore) {					\
-			bt->vec[(i) - nignore] = p;			\
-			bt->len = (i) - nignore + 1;			\
-		}							\
+		bt->vec[(i)] = p;					\
+		bt->len = (i) + 1;					\
 	} else								\
 		return;
 
 	cassert(config_prof);
-	assert(nignore <= 3);
 
 	BT_FRAME(0)
 	BT_FRAME(1)
@@ -392,16 +368,11 @@ prof_backtrace(prof_bt_t *bt, unsigned nignore)
 	BT_FRAME(125)
 	BT_FRAME(126)
 	BT_FRAME(127)
-
-	/* Extras to compensate for nignore. */
-	BT_FRAME(128)
-	BT_FRAME(129)
-	BT_FRAME(130)
 #undef BT_FRAME
 }
 #else
 void
-prof_backtrace(prof_bt_t *bt, unsigned nignore)
+prof_backtrace(prof_bt_t *bt)
 {
 
 	cassert(config_prof);
@@ -646,6 +617,66 @@ prof_lookup(prof_bt_t *bt)
 	return (ret.p);
 }
 
+
+void
+prof_sample_threshold_update(prof_tdata_t *prof_tdata)
+{
+	/*
+	 * The body of this function is compiled out unless heap profiling is
+	 * enabled, so that it is possible to compile jemalloc with floating
+	 * point support completely disabled.  Avoiding floating point code is
+	 * important on memory-constrained systems, but it also enables a
+	 * workaround for versions of glibc that don't properly save/restore
+	 * floating point registers during dynamic lazy symbol loading (which
+	 * internally calls into whatever malloc implementation happens to be
+	 * integrated into the application).  Note that some compilers (e.g.
+	 * gcc 4.8) may use floating point registers for fast memory moves, so
+	 * jemalloc must be compiled with such optimizations disabled (e.g.
+	 * -mno-sse) in order for the workaround to be complete.
+	 */
+#ifdef JEMALLOC_PROF
+	uint64_t r;
+	double u;
+
+	if (!config_prof)
+		return;
+
+	if (prof_tdata == NULL)
+		prof_tdata = prof_tdata_get(false);
+
+	if (opt_lg_prof_sample == 0) {
+		prof_tdata->bytes_until_sample = 0;
+		return;
+	}
+
+	/*
+	 * Compute sample threshold as a geometrically distributed random
+	 * variable with mean (2^opt_lg_prof_sample).
+	 *
+	 *                         __        __
+	 *                         |  log(u)  |                     1
+	 * prof_tdata->threshold = | -------- |, where p = -------------------
+	 *                         | log(1-p) |             opt_lg_prof_sample
+	 *                                                 2
+	 *
+	 * For more information on the math, see:
+	 *
+	 *   Non-Uniform Random Variate Generation
+	 *   Luc Devroye
+	 *   Springer-Verlag, New York, 1986
+	 *   pp 500
+	 *   (http://luc.devroye.org/rnbookindex.html)
+	 */
+	prng64(r, 53, prof_tdata->prng_state,
+	    UINT64_C(6364136223846793005), UINT64_C(1442695040888963407));
+	u = (double)r * (1.0/9007199254740992.0L);
+	prof_tdata->bytes_until_sample = (uint64_t)(log(u) /
+	    log(1.0 - (1.0 / (double)((uint64_t)1U << opt_lg_prof_sample))))
+	    + (uint64_t)1U;
+#endif
+}
+
+
 #ifdef JEMALLOC_JET
 size_t
 prof_bt_count(void)
@@ -1062,7 +1093,7 @@ label_open_close_error:
 #define	DUMP_FILENAME_BUFSIZE	(PATH_MAX + 1)
 #define	VSEQ_INVALID		UINT64_C(0xffffffffffffffff)
 static void
-prof_dump_filename(char *filename, char v, int64_t vseq)
+prof_dump_filename(char *filename, char v, uint64_t vseq)
 {
 
 	cassert(config_prof);
@@ -1070,7 +1101,7 @@ prof_dump_filename(char *filename, char v, int64_t vseq)
 	if (vseq != VSEQ_INVALID) {
 	        /* "<prefix>.<pid>.<seq>.v<vseq>.heap" */
 		malloc_snprintf(filename, DUMP_FILENAME_BUFSIZE,
-		    "%s.%d.%"PRIu64".%c%"PRId64".heap",
+		    "%s.%d.%"PRIu64".%c%"PRIu64".heap",
 		    opt_prof_prefix, (int)getpid(), prof_dump_seq, v, vseq);
 	} else {
 	        /* "<prefix>.<pid>.<seq>.<v>.heap" */
@@ -1225,9 +1256,8 @@ prof_tdata_init(void)
 		return (NULL);
 	}
 
-	prof_tdata->prng_state = 0;
-	prof_tdata->threshold = 0;
-	prof_tdata->accum = 0;
+	prof_tdata->prng_state = (uint64_t)(uintptr_t)prof_tdata;
+	prof_sample_threshold_update(prof_tdata);
 
 	prof_tdata->enq = false;
 	prof_tdata->enq_idump = false;
@@ -1300,8 +1330,8 @@ prof_boot1(void)
 	cassert(config_prof);
 
 	/*
-	 * opt_prof and prof_promote must be in their final state before any
-	 * arenas are initialized, so this function must be executed early.
+	 * opt_prof must be in its final state before any arenas are
+	 * initialized, so this function must be executed early.
 	 */
 
 	if (opt_prof_leak && opt_prof == false) {
@@ -1317,14 +1347,11 @@ prof_boot1(void)
 			    opt_lg_prof_interval);
 		}
 	}
-
-	prof_promote = (opt_prof && opt_lg_prof_sample > LG_PAGE);
 }
 
 bool
 prof_boot2(void)
 {
-
 	cassert(config_prof);
 
 	if (opt_prof) {
@@ -1351,8 +1378,7 @@ prof_boot2(void)
 			if (opt_abort)
 				abort();
 		}
-
-		ctx_locks = (malloc_mutex_t *)base_alloc(PROF_NCTX_LOCKS *
+		ctx_locks = (malloc_mutex_t *)je_base_malloc(PROF_NCTX_LOCKS *
 		    sizeof(malloc_mutex_t));
 		if (ctx_locks == NULL)
 			return (true);
diff --git a/src/jemalloc/src/quarantine.c b/src/jemalloc/src/quarantine.c
index 5431511640a59e0880c958b18f9b47f1f0127002..3b874422c638b93112fc792222c0ded170163d4b 100644
--- a/src/jemalloc/src/quarantine.c
+++ b/src/jemalloc/src/quarantine.c
@@ -146,7 +146,7 @@ quarantine(void *ptr)
 			 * Only do redzone validation if Valgrind isn't in
 			 * operation.
 			 */
-			if ((config_valgrind == false || opt_valgrind == false)
+			if ((config_valgrind == false || in_valgrind == false)
 			    && usize <= SMALL_MAXCLASS)
 				arena_quarantine_junk_small(ptr, usize);
 			else
diff --git a/src/jemalloc/src/rtree.c b/src/jemalloc/src/rtree.c
index 205957ac4e1a447d077c68f7fdc733dc2de0abea..25f603193d8e97e3c356841f97a7d42203adbcb8 100644
--- a/src/jemalloc/src/rtree.c
+++ b/src/jemalloc/src/rtree.c
@@ -2,15 +2,16 @@
 #include "jemalloc/internal/jemalloc_internal.h"
 
 rtree_t *
-rtree_new(unsigned bits, rtree_alloc_t *alloc, rtree_dalloc_t *dalloc)
+rtree_new(unsigned bits, rtree_alloc_t *alloc, rtree_dalloc_t *dalloc,
+	pool_t *pool)
 {
 	rtree_t *ret;
 	unsigned bits_per_level, bits_in_leaf, height, i;
 
 	assert(bits > 0 && bits <= (sizeof(uintptr_t) << 3));
 
-	bits_per_level = ffs(pow2_ceil((RTREE_NODESIZE / sizeof(void *)))) - 1;
-	bits_in_leaf = ffs(pow2_ceil((RTREE_NODESIZE / sizeof(uint8_t)))) - 1;
+	bits_per_level = jemalloc_ffs(pow2_ceil((RTREE_NODESIZE / sizeof(void *)))) - 1;
+	bits_in_leaf = jemalloc_ffs(pow2_ceil((RTREE_NODESIZE / sizeof(uint8_t)))) - 1;
 	if (bits > bits_in_leaf) {
 		height = 1 + (bits - bits_in_leaf) / bits_per_level;
 		if ((height-1) * bits_per_level + bits_in_leaf != bits)
@@ -20,7 +21,7 @@ rtree_new(unsigned bits, rtree_alloc_t *alloc, rtree_dalloc_t *dalloc)
 	}
 	assert((height-1) * bits_per_level + bits_in_leaf >= bits);
 
-	ret = (rtree_t*)alloc(offsetof(rtree_t, level2bits) +
+	ret = (rtree_t*)alloc(pool, offsetof(rtree_t, level2bits) +
 	    (sizeof(unsigned) * height));
 	if (ret == NULL)
 		return (NULL);
@@ -29,9 +30,10 @@ rtree_new(unsigned bits, rtree_alloc_t *alloc, rtree_dalloc_t *dalloc)
 
 	ret->alloc = alloc;
 	ret->dalloc = dalloc;
+	ret->pool = pool;
 	if (malloc_mutex_init(&ret->mutex)) {
 		if (dalloc != NULL)
-			dalloc(ret);
+			dalloc(pool, ret);
 		return (NULL);
 	}
 	ret->height = height;
@@ -47,10 +49,10 @@ rtree_new(unsigned bits, rtree_alloc_t *alloc, rtree_dalloc_t *dalloc)
 	} else
 		ret->level2bits[0] = bits;
 
-	ret->root = (void**)alloc(sizeof(void *) << ret->level2bits[0]);
+	ret->root = (void**)alloc(pool, sizeof(void *) << ret->level2bits[0]);
 	if (ret->root == NULL) {
 		if (dalloc != NULL)
-			dalloc(ret);
+			dalloc(pool, ret);
 		return (NULL);
 	}
 	memset(ret->root, 0, sizeof(void *) << ret->level2bits[0]);
@@ -72,7 +74,7 @@ rtree_delete_subtree(rtree_t *rtree, void **node, unsigned level)
 				rtree_delete_subtree(rtree, child, level + 1);
 		}
 	}
-	rtree->dalloc(node);
+	rtree->dalloc(rtree->pool, node);
 }
 
 void
@@ -80,7 +82,7 @@ rtree_delete(rtree_t *rtree)
 {
 
 	rtree_delete_subtree(rtree, rtree->root, 0);
-	rtree->dalloc(rtree);
+	rtree->dalloc(rtree->pool, rtree);
 }
 
 void
diff --git a/src/jemalloc/src/stats.c b/src/jemalloc/src/stats.c
index bef2ab33cd4de0891826afb8573d65095211b8ef..70aff04bbfcabcfdd1d2c99926d3a746aab32c2b 100644
--- a/src/jemalloc/src/stats.c
+++ b/src/jemalloc/src/stats.c
@@ -6,64 +6,76 @@
 	xmallctl(n, v, &sz, NULL, 0);					\
 } while (0)
 
-#define	CTL_I_GET(n, v, t) do {						\
-	size_t mib[6];							\
+#define	CTL_P_GET_ARRAY(n, v, t, c) do {				\
+	size_t mib[8];							\
 	size_t miblen = sizeof(mib) / sizeof(size_t);			\
-	size_t sz = sizeof(t);						\
+	size_t sz = sizeof(t) * c;					\
 	xmallctlnametomib(n, mib, &miblen);				\
-	mib[2] = i;							\
+	mib[1] = p;							\
 	xmallctlbymib(mib, miblen, v, &sz, NULL, 0);			\
 } while (0)
 
-#define	CTL_J_GET(n, v, t) do {						\
-	size_t mib[6];							\
+#define	CTL_P_GET(n, v, t) CTL_P_GET_ARRAY(n, v, t, 1)
+
+#define	CTL_PI_GET(n, v, t) do {					\
+	size_t mib[8];							\
 	size_t miblen = sizeof(mib) / sizeof(size_t);			\
 	size_t sz = sizeof(t);						\
 	xmallctlnametomib(n, mib, &miblen);				\
-	mib[2] = j;							\
+	mib[1] = p;							\
+	mib[4] = i;							\
 	xmallctlbymib(mib, miblen, v, &sz, NULL, 0);			\
 } while (0)
 
-#define	CTL_IJ_GET(n, v, t) do {					\
-	size_t mib[6];							\
+#define	CTL_PJ_GET(n, v, t) do {					\
+	size_t mib[8];							\
 	size_t miblen = sizeof(mib) / sizeof(size_t);			\
 	size_t sz = sizeof(t);						\
 	xmallctlnametomib(n, mib, &miblen);				\
-	mib[2] = i;							\
+	mib[1] = p;							\
 	mib[4] = j;							\
 	xmallctlbymib(mib, miblen, v, &sz, NULL, 0);			\
 } while (0)
 
+#define	CTL_PIJ_GET(n, v, t) do {					\
+	size_t mib[8];							\
+	size_t miblen = sizeof(mib) / sizeof(size_t);			\
+	size_t sz = sizeof(t);						\
+	xmallctlnametomib(n, mib, &miblen);				\
+	mib[1] = p;							\
+	mib[4] = i;							\
+	mib[6] = j;							\
+	xmallctlbymib(mib, miblen, v, &sz, NULL, 0);			\
+} while (0)
+
 /******************************************************************************/
 /* Data. */
 
 bool	opt_stats_print = false;
 
-size_t	stats_cactive = 0;
-
 /******************************************************************************/
 /* Function prototypes for non-inline static functions. */
 
 static void	stats_arena_bins_print(void (*write_cb)(void *, const char *),
-    void *cbopaque, unsigned i);
+    void *cbopaque, unsigned p, unsigned i);
 static void	stats_arena_lruns_print(void (*write_cb)(void *, const char *),
-    void *cbopaque, unsigned i);
+    void *cbopaque, unsigned p, unsigned i);
 static void	stats_arena_print(void (*write_cb)(void *, const char *),
-    void *cbopaque, unsigned i, bool bins, bool large);
+    void *cbopaque, unsigned p, unsigned i, bool bins, bool large);
 
 /******************************************************************************/
 
 static void
 stats_arena_bins_print(void (*write_cb)(void *, const char *), void *cbopaque,
-    unsigned i)
+    unsigned p, unsigned i)
 {
 	size_t page;
 	bool config_tcache;
 	unsigned nbins, j, gap_start;
 
-	CTL_GET("arenas.page", &page, size_t);
+	CTL_P_GET("pool.0.arenas.page", &page, size_t);
 
-	CTL_GET("config.tcache", &config_tcache, bool);
+	CTL_P_GET("config.tcache", &config_tcache, bool);
 	if (config_tcache) {
 		malloc_cprintf(write_cb, cbopaque,
 		    "bins:     bin  size regs pgs    allocated      nmalloc"
@@ -74,11 +86,11 @@ stats_arena_bins_print(void (*write_cb)(void *, const char *), void *cbopaque,
 		    "bins:     bin  size regs pgs    allocated      nmalloc"
 		    "      ndalloc      newruns       reruns      curruns\n");
 	}
-	CTL_GET("arenas.nbins", &nbins, unsigned);
+	CTL_P_GET("pool.0.arenas.nbins", &nbins, unsigned);
 	for (j = 0, gap_start = UINT_MAX; j < nbins; j++) {
 		uint64_t nruns;
 
-		CTL_IJ_GET("stats.arenas.0.bins.0.nruns", &nruns, uint64_t);
+		CTL_PIJ_GET("pool.0.stats.arenas.0.bins.0.nruns", &nruns, uint64_t);
 		if (nruns == 0) {
 			if (gap_start == UINT_MAX)
 				gap_start = j;
@@ -102,26 +114,26 @@ stats_arena_bins_print(void (*write_cb)(void *, const char *), void *cbopaque,
 				}
 				gap_start = UINT_MAX;
 			}
-			CTL_J_GET("arenas.bin.0.size", &reg_size, size_t);
-			CTL_J_GET("arenas.bin.0.nregs", &nregs, uint32_t);
-			CTL_J_GET("arenas.bin.0.run_size", &run_size, size_t);
-			CTL_IJ_GET("stats.arenas.0.bins.0.allocated",
+			CTL_PJ_GET("pool.0.arenas.bin.0.size", &reg_size, size_t);
+			CTL_PJ_GET("pool.0.arenas.bin.0.nregs", &nregs, uint32_t);
+			CTL_PJ_GET("pool.0.arenas.bin.0.run_size", &run_size, size_t);
+			CTL_PIJ_GET("pool.0.stats.arenas.0.bins.0.allocated",
 			    &allocated, size_t);
-			CTL_IJ_GET("stats.arenas.0.bins.0.nmalloc",
+			CTL_PIJ_GET("pool.0.stats.arenas.0.bins.0.nmalloc",
 			    &nmalloc, uint64_t);
-			CTL_IJ_GET("stats.arenas.0.bins.0.ndalloc",
+			CTL_PIJ_GET("pool.0.stats.arenas.0.bins.0.ndalloc",
 			    &ndalloc, uint64_t);
 			if (config_tcache) {
-				CTL_IJ_GET("stats.arenas.0.bins.0.nrequests",
+				CTL_PIJ_GET("pool.0.stats.arenas.0.bins.0.nrequests",
 				    &nrequests, uint64_t);
-				CTL_IJ_GET("stats.arenas.0.bins.0.nfills",
+				CTL_PIJ_GET("pool.0.stats.arenas.0.bins.0.nfills",
 				    &nfills, uint64_t);
-				CTL_IJ_GET("stats.arenas.0.bins.0.nflushes",
+				CTL_PIJ_GET("pool.0.stats.arenas.0.bins.0.nflushes",
 				    &nflushes, uint64_t);
 			}
-			CTL_IJ_GET("stats.arenas.0.bins.0.nreruns", &reruns,
+			CTL_PIJ_GET("pool.0.stats.arenas.0.bins.0.nreruns", &reruns,
 			    uint64_t);
-			CTL_IJ_GET("stats.arenas.0.bins.0.curruns", &curruns,
+			CTL_PIJ_GET("pool.0.stats.arenas.0.bins.0.curruns", &curruns,
 			    size_t);
 			if (config_tcache) {
 				malloc_cprintf(write_cb, cbopaque,
@@ -157,33 +169,33 @@ stats_arena_bins_print(void (*write_cb)(void *, const char *), void *cbopaque,
 
 static void
 stats_arena_lruns_print(void (*write_cb)(void *, const char *), void *cbopaque,
-    unsigned i)
+    unsigned p, unsigned i)
 {
 	size_t page, nlruns, j;
 	ssize_t gap_start;
 
-	CTL_GET("arenas.page", &page, size_t);
+	CTL_P_GET("pool.0.arenas.page", &page, size_t);
 
 	malloc_cprintf(write_cb, cbopaque,
 	    "large:   size pages      nmalloc      ndalloc    nrequests"
 	    "      curruns\n");
-	CTL_GET("arenas.nlruns", &nlruns, size_t);
+	CTL_P_GET("pool.0.arenas.nlruns", &nlruns, size_t);
 	for (j = 0, gap_start = -1; j < nlruns; j++) {
 		uint64_t nmalloc, ndalloc, nrequests;
 		size_t run_size, curruns;
 
-		CTL_IJ_GET("stats.arenas.0.lruns.0.nmalloc", &nmalloc,
+		CTL_PIJ_GET("pool.0.stats.arenas.0.lruns.0.nmalloc", &nmalloc,
 		    uint64_t);
-		CTL_IJ_GET("stats.arenas.0.lruns.0.ndalloc", &ndalloc,
+		CTL_PIJ_GET("pool.0.stats.arenas.0.lruns.0.ndalloc", &ndalloc,
 		    uint64_t);
-		CTL_IJ_GET("stats.arenas.0.lruns.0.nrequests", &nrequests,
+		CTL_PIJ_GET("pool.0.stats.arenas.0.lruns.0.nrequests", &nrequests,
 		    uint64_t);
 		if (nrequests == 0) {
 			if (gap_start == -1)
 				gap_start = j;
 		} else {
-			CTL_J_GET("arenas.lrun.0.size", &run_size, size_t);
-			CTL_IJ_GET("stats.arenas.0.lruns.0.curruns", &curruns,
+			CTL_PJ_GET("pool.0.arenas.lrun.0.size", &run_size, size_t);
+			CTL_PIJ_GET("pool.0.stats.arenas.0.lruns.0.curruns", &curruns,
 			    size_t);
 			if (gap_start != -1) {
 				malloc_cprintf(write_cb, cbopaque, "[%zu]\n",
@@ -203,7 +215,7 @@ stats_arena_lruns_print(void (*write_cb)(void *, const char *), void *cbopaque,
 
 static void
 stats_arena_print(void (*write_cb)(void *, const char *), void *cbopaque,
-    unsigned i, bool bins, bool large)
+    unsigned p, unsigned i, bool bins, bool large)
 {
 	unsigned nthreads;
 	const char *dss;
@@ -213,20 +225,22 @@ stats_arena_print(void (*write_cb)(void *, const char *), void *cbopaque,
 	uint64_t small_nmalloc, small_ndalloc, small_nrequests;
 	size_t large_allocated;
 	uint64_t large_nmalloc, large_ndalloc, large_nrequests;
+	size_t huge_allocated;
+	uint64_t huge_nmalloc, huge_ndalloc, huge_nrequests;
 
-	CTL_GET("arenas.page", &page, size_t);
+	CTL_P_GET("pool.0.arenas.page", &page, size_t);
 
-	CTL_I_GET("stats.arenas.0.nthreads", &nthreads, unsigned);
+	CTL_PI_GET("pool.0.stats.arenas.0.nthreads", &nthreads, unsigned);
 	malloc_cprintf(write_cb, cbopaque,
 	    "assigned threads: %u\n", nthreads);
-	CTL_I_GET("stats.arenas.0.dss", &dss, const char *);
+	CTL_PI_GET("pool.0.stats.arenas.0.dss", &dss, const char *);
 	malloc_cprintf(write_cb, cbopaque, "dss allocation precedence: %s\n",
 	    dss);
-	CTL_I_GET("stats.arenas.0.pactive", &pactive, size_t);
-	CTL_I_GET("stats.arenas.0.pdirty", &pdirty, size_t);
-	CTL_I_GET("stats.arenas.0.npurge", &npurge, uint64_t);
-	CTL_I_GET("stats.arenas.0.nmadvise", &nmadvise, uint64_t);
-	CTL_I_GET("stats.arenas.0.purged", &purged, uint64_t);
+	CTL_PI_GET("pool.0.stats.arenas.0.pactive", &pactive, size_t);
+	CTL_PI_GET("pool.0.stats.arenas.0.pdirty", &pdirty, size_t);
+	CTL_PI_GET("pool.0.stats.arenas.0.npurge", &npurge, uint64_t);
+	CTL_PI_GET("pool.0.stats.arenas.0.nmadvise", &nmadvise, uint64_t);
+	CTL_PI_GET("pool.0.stats.arenas.0.purged", &purged, uint64_t);
 	malloc_cprintf(write_cb, cbopaque,
 	    "dirty pages: %zu:%zu active:dirty, %"PRIu64" sweep%s,"
 	    " %"PRIu64" madvise%s, %"PRIu64" purged\n",
@@ -235,38 +249,45 @@ stats_arena_print(void (*write_cb)(void *, const char *), void *cbopaque,
 
 	malloc_cprintf(write_cb, cbopaque,
 	    "            allocated      nmalloc      ndalloc    nrequests\n");
-	CTL_I_GET("stats.arenas.0.small.allocated", &small_allocated, size_t);
-	CTL_I_GET("stats.arenas.0.small.nmalloc", &small_nmalloc, uint64_t);
-	CTL_I_GET("stats.arenas.0.small.ndalloc", &small_ndalloc, uint64_t);
-	CTL_I_GET("stats.arenas.0.small.nrequests", &small_nrequests, uint64_t);
+	CTL_PI_GET("pool.0.stats.arenas.0.small.allocated", &small_allocated, size_t);
+	CTL_PI_GET("pool.0.stats.arenas.0.small.nmalloc", &small_nmalloc, uint64_t);
+	CTL_PI_GET("pool.0.stats.arenas.0.small.ndalloc", &small_ndalloc, uint64_t);
+	CTL_PI_GET("pool.0.stats.arenas.0.small.nrequests", &small_nrequests, uint64_t);
 	malloc_cprintf(write_cb, cbopaque,
 	    "small:   %12zu %12"PRIu64" %12"PRIu64" %12"PRIu64"\n",
 	    small_allocated, small_nmalloc, small_ndalloc, small_nrequests);
-	CTL_I_GET("stats.arenas.0.large.allocated", &large_allocated, size_t);
-	CTL_I_GET("stats.arenas.0.large.nmalloc", &large_nmalloc, uint64_t);
-	CTL_I_GET("stats.arenas.0.large.ndalloc", &large_ndalloc, uint64_t);
-	CTL_I_GET("stats.arenas.0.large.nrequests", &large_nrequests, uint64_t);
+	CTL_PI_GET("pool.0.stats.arenas.0.large.allocated", &large_allocated, size_t);
+	CTL_PI_GET("pool.0.stats.arenas.0.large.nmalloc", &large_nmalloc, uint64_t);
+	CTL_PI_GET("pool.0.stats.arenas.0.large.ndalloc", &large_ndalloc, uint64_t);
+	CTL_PI_GET("pool.0.stats.arenas.0.large.nrequests", &large_nrequests, uint64_t);
 	malloc_cprintf(write_cb, cbopaque,
 	    "large:   %12zu %12"PRIu64" %12"PRIu64" %12"PRIu64"\n",
 	    large_allocated, large_nmalloc, large_ndalloc, large_nrequests);
+	CTL_PI_GET("pool.0.stats.arenas.0.huge.allocated", &huge_allocated, size_t);
+	CTL_PI_GET("pool.0.stats.arenas.0.huge.nmalloc", &huge_nmalloc, uint64_t);
+	CTL_PI_GET("pool.0.stats.arenas.0.huge.ndalloc", &huge_ndalloc, uint64_t);
+	CTL_PI_GET("pool.0.stats.arenas.0.huge.nrequests", &huge_nrequests, uint64_t);
+	malloc_cprintf(write_cb, cbopaque,
+	    "huge:    %12zu %12"PRIu64" %12"PRIu64" %12"PRIu64"\n",
+	    huge_allocated, huge_nmalloc, huge_ndalloc, huge_nrequests);
 	malloc_cprintf(write_cb, cbopaque,
 	    "total:   %12zu %12"PRIu64" %12"PRIu64" %12"PRIu64"\n",
-	    small_allocated + large_allocated,
-	    small_nmalloc + large_nmalloc,
-	    small_ndalloc + large_ndalloc,
-	    small_nrequests + large_nrequests);
+	    small_allocated + large_allocated + huge_allocated,
+	    small_nmalloc + large_nmalloc + huge_nmalloc,
+	    small_ndalloc + large_ndalloc + huge_ndalloc,
+	    small_nrequests + large_nrequests + huge_nrequests);
 	malloc_cprintf(write_cb, cbopaque, "active:  %12zu\n", pactive * page);
-	CTL_I_GET("stats.arenas.0.mapped", &mapped, size_t);
+	CTL_PI_GET("pool.0.stats.arenas.0.mapped", &mapped, size_t);
 	malloc_cprintf(write_cb, cbopaque, "mapped:  %12zu\n", mapped);
 
 	if (bins)
-		stats_arena_bins_print(write_cb, cbopaque, i);
+		stats_arena_bins_print(write_cb, cbopaque, p, i);
 	if (large)
-		stats_arena_lruns_print(write_cb, cbopaque, i);
+		stats_arena_lruns_print(write_cb, cbopaque, p, i);
 }
 
 void
-stats_print(void (*write_cb)(void *, const char *), void *cbopaque,
+stats_print(pool_t *pool, void (*write_cb)(void *, const char *), void *cbopaque,
     const char *opts)
 {
 	int err;
@@ -277,6 +298,7 @@ stats_print(void (*write_cb)(void *, const char *), void *cbopaque,
 	bool unmerged = true;
 	bool bins = true;
 	bool large = true;
+	unsigned p = pool->pool_id;
 
 	/*
 	 * Refresh stats, in case mallctl() was called by the application.
@@ -404,19 +426,19 @@ stats_print(void (*write_cb)(void *, const char *), void *cbopaque,
 
 		malloc_cprintf(write_cb, cbopaque, "CPUs: %u\n", ncpus);
 
-		CTL_GET("arenas.narenas", &uv, unsigned);
+		CTL_P_GET("pool.0.arenas.narenas", &uv, unsigned);
 		malloc_cprintf(write_cb, cbopaque, "Arenas: %u\n", uv);
 
 		malloc_cprintf(write_cb, cbopaque, "Pointer size: %zu\n",
 		    sizeof(void *));
 
-		CTL_GET("arenas.quantum", &sv, size_t);
+		CTL_P_GET("pool.0.arenas.quantum", &sv, size_t);
 		malloc_cprintf(write_cb, cbopaque, "Quantum size: %zu\n", sv);
 
-		CTL_GET("arenas.page", &sv, size_t);
+		CTL_P_GET("pool.0.arenas.page", &sv, size_t);
 		malloc_cprintf(write_cb, cbopaque, "Page size: %zu\n", sv);
 
-		CTL_GET("opt.lg_dirty_mult", &ssv, ssize_t);
+		CTL_P_GET("opt.lg_dirty_mult", &ssv, ssize_t);
 		if (ssv >= 0) {
 			malloc_cprintf(write_cb, cbopaque,
 			    "Min active:dirty page ratio per arena: %u:1\n",
@@ -458,13 +480,11 @@ stats_print(void (*write_cb)(void *, const char *), void *cbopaque,
 		size_t allocated, active, mapped;
 		size_t chunks_current, chunks_high;
 		uint64_t chunks_total;
-		size_t huge_allocated;
-		uint64_t huge_nmalloc, huge_ndalloc;
 
-		CTL_GET("stats.cactive", &cactive, size_t *);
-		CTL_GET("stats.allocated", &allocated, size_t);
-		CTL_GET("stats.active", &active, size_t);
-		CTL_GET("stats.mapped", &mapped, size_t);
+		CTL_P_GET("pool.0.stats.cactive", &cactive, size_t *);
+		CTL_P_GET("pool.0.stats.allocated", &allocated, size_t);
+		CTL_P_GET("pool.0.stats.active", &active, size_t);
+		CTL_P_GET("pool.0.stats.mapped", &mapped, size_t);
 		malloc_cprintf(write_cb, cbopaque,
 		    "Allocated: %zu, active: %zu, mapped: %zu\n",
 		    allocated, active, mapped);
@@ -472,36 +492,26 @@ stats_print(void (*write_cb)(void *, const char *), void *cbopaque,
 		    "Current active ceiling: %zu\n", atomic_read_z(cactive));
 
 		/* Print chunk stats. */
-		CTL_GET("stats.chunks.total", &chunks_total, uint64_t);
-		CTL_GET("stats.chunks.high", &chunks_high, size_t);
-		CTL_GET("stats.chunks.current", &chunks_current, size_t);
+		CTL_P_GET("pool.0.stats.chunks.total", &chunks_total, uint64_t);
+		CTL_P_GET("pool.0.stats.chunks.high", &chunks_high, size_t);
+		CTL_P_GET("pool.0.stats.chunks.current", &chunks_current, size_t);
 		malloc_cprintf(write_cb, cbopaque, "chunks: nchunks   "
 		    "highchunks    curchunks\n");
 		malloc_cprintf(write_cb, cbopaque,
 		    "  %13"PRIu64" %12zu %12zu\n",
 		    chunks_total, chunks_high, chunks_current);
 
-		/* Print huge stats. */
-		CTL_GET("stats.huge.nmalloc", &huge_nmalloc, uint64_t);
-		CTL_GET("stats.huge.ndalloc", &huge_ndalloc, uint64_t);
-		CTL_GET("stats.huge.allocated", &huge_allocated, size_t);
-		malloc_cprintf(write_cb, cbopaque,
-		    "huge: nmalloc      ndalloc    allocated\n");
-		malloc_cprintf(write_cb, cbopaque,
-		    " %12"PRIu64" %12"PRIu64" %12zu\n",
-		    huge_nmalloc, huge_ndalloc, huge_allocated);
-
 		if (merged) {
 			unsigned narenas;
 
-			CTL_GET("arenas.narenas", &narenas, unsigned);
+			CTL_P_GET("pool.0.arenas.narenas", &narenas, unsigned);
 			{
 				VARIABLE_ARRAY(bool, initialized, narenas);
 				size_t isz;
 				unsigned i, ninitialized;
 
 				isz = sizeof(bool) * narenas;
-				xmallctl("arenas.initialized", initialized,
+				xmallctl("pool.0.arenas.initialized", initialized,
 				    &isz, NULL, 0);
 				for (i = ninitialized = 0; i < narenas; i++) {
 					if (initialized[i])
@@ -513,7 +523,7 @@ stats_print(void (*write_cb)(void *, const char *), void *cbopaque,
 					malloc_cprintf(write_cb, cbopaque,
 					    "\nMerged arenas stats:\n");
 					stats_arena_print(write_cb, cbopaque,
-					    narenas, bins, large);
+					    p, narenas, bins, large);
 				}
 			}
 		}
@@ -523,15 +533,13 @@ stats_print(void (*write_cb)(void *, const char *), void *cbopaque,
 
 			/* Print stats for each arena. */
 
-			CTL_GET("arenas.narenas", &narenas, unsigned);
+			CTL_P_GET("pool.0.arenas.narenas", &narenas, unsigned);
 			{
 				VARIABLE_ARRAY(bool, initialized, narenas);
-				size_t isz;
 				unsigned i;
 
-				isz = sizeof(bool) * narenas;
-				xmallctl("arenas.initialized", initialized,
-				    &isz, NULL, 0);
+				CTL_P_GET_ARRAY("pool.0.arenas.initialized",
+					initialized, bool, narenas);
 
 				for (i = 0; i < narenas; i++) {
 					if (initialized[i]) {
@@ -539,7 +547,7 @@ stats_print(void (*write_cb)(void *, const char *), void *cbopaque,
 						    cbopaque,
 						    "\narenas[%u]:\n", i);
 						stats_arena_print(write_cb,
-						    cbopaque, i, bins, large);
+						    cbopaque, p, i, bins, large);
 					}
 				}
 			}
diff --git a/src/jemalloc/src/tcache.c b/src/jemalloc/src/tcache.c
index 6de92960b2df249b1d71094ef365205aa73508f5..aaa126f150cf4d238accde612cbfc123c28de56e 100644
--- a/src/jemalloc/src/tcache.c
+++ b/src/jemalloc/src/tcache.c
@@ -3,8 +3,8 @@
 
 /******************************************************************************/
 /* Data. */
-
-malloc_tsd_data(, tcache, tcache_t *, NULL)
+#define ARR_INITIALIZER JEMALLOC_ARG_CONCAT({0})
+malloc_tsd_data(, tcache, tsd_tcache_t, TSD_TCACHE_INITIALIZER)
 malloc_tsd_data(, tcache_enabled, tcache_enabled_t, tcache_enabled_default)
 
 bool	opt_tcache = true;
@@ -265,12 +265,56 @@ tcache_arena_dissociate(tcache_t *tcache)
 	}
 }
 
+tcache_t *
+tcache_get_hard(tcache_t *tcache, pool_t *pool, bool create)
+{
+	arena_t dummy;
+	DUMMY_ARENA_INITIALIZE(dummy, pool);
+	if (tcache == NULL) {
+		if (create == false) {
+			/*
+			 * Creating a tcache here would cause
+			 * allocation as a side effect of free().
+			 * Ordinarily that would be okay since
+			 * tcache_create() failure is a soft failure
+			 * that doesn't propagate.  However, if TLS
+			 * data are freed via free() as in glibc,
+			 * subtle corruption could result from setting
+			 * a TLS variable after its backing memory is
+			 * freed.
+			 */
+			return (NULL);
+		}
+		if (tcache_enabled_get() == false) {
+			tcache_enabled_set(false); /* Memoize. */
+			return (NULL);
+		}
+		return (tcache_create(choose_arena(&dummy)));
+	}
+	if (tcache == TCACHE_STATE_PURGATORY) {
+		/*
+		 * Make a note that an allocator function was called
+		 * after tcache_thread_cleanup() was called.
+		 */
+		tsd_tcache_t *tsd = tcache_tsd_get();
+		tcache = TCACHE_STATE_REINCARNATED;
+		tsd->seqno[pool->pool_id] = pool->seqno;
+		tsd->tcaches[pool->pool_id] = tcache;
+		return (NULL);
+	}
+	if (tcache == TCACHE_STATE_REINCARNATED)
+		return (NULL);
+	not_reached();
+	return (NULL);
+}
+
 tcache_t *
 tcache_create(arena_t *arena)
 {
 	tcache_t *tcache;
 	size_t size, stack_offset;
 	unsigned i;
+	tsd_tcache_t *tsd = tcache_tsd_get();
 
 	size = offsetof(tcache_t, tbins) + (sizeof(tcache_bin_t) * nhbins);
 	/* Naturally align the pointer stacks. */
@@ -307,7 +351,8 @@ tcache_create(arena_t *arena)
 		stack_offset += tcache_bin_info[i].ncached_max * sizeof(void *);
 	}
 
-	tcache_tsd_set(&tcache);
+	tsd->seqno[arena->pool->pool_id] = arena->pool->seqno;
+	tsd->tcaches[arena->pool->pool_id] = tcache;
 
 	return (tcache);
 }
@@ -372,31 +417,39 @@ tcache_destroy(tcache_t *tcache)
 void
 tcache_thread_cleanup(void *arg)
 {
-	tcache_t *tcache = *(tcache_t **)arg;
+	int i;
+	tsd_tcache_t *tsd_array = arg;
+
+	malloc_mutex_lock(&pools_lock);
+	for (i = 0; i < POOLS_MAX; ++i) {
+		tcache_t *tcache = tsd_array->tcaches[i];
+		if (tcache != NULL) {
+			if (tcache == TCACHE_STATE_DISABLED) {
+				/* Do nothing. */
+			} else if (tcache == TCACHE_STATE_REINCARNATED) {
+				/*
+				 * Another destructor called an allocator function after this
+				 * destructor was called.  Reset tcache to
+				 * TCACHE_STATE_PURGATORY in order to receive another callback.
+				 */
+				tsd_array->tcaches[i] = TCACHE_STATE_PURGATORY;
+			} else if (tcache == TCACHE_STATE_PURGATORY) {
+				/*
+				 * The previous time this destructor was called, we set the key
+				 * to TCACHE_STATE_PURGATORY so that other destructors wouldn't
+				 * cause re-creation of the tcache.  This time, do nothing, so
+				 * that the destructor will not be called again.
+				 */
+			} else if (tcache != NULL) {
+				assert(tcache != TCACHE_STATE_PURGATORY);
+				if (pools[i] != NULL && tsd_array->seqno[i] == pools[i]->seqno)
+					tcache_destroy(tcache);
 
-	if (tcache == TCACHE_STATE_DISABLED) {
-		/* Do nothing. */
-	} else if (tcache == TCACHE_STATE_REINCARNATED) {
-		/*
-		 * Another destructor called an allocator function after this
-		 * destructor was called.  Reset tcache to
-		 * TCACHE_STATE_PURGATORY in order to receive another callback.
-		 */
-		tcache = TCACHE_STATE_PURGATORY;
-		tcache_tsd_set(&tcache);
-	} else if (tcache == TCACHE_STATE_PURGATORY) {
-		/*
-		 * The previous time this destructor was called, we set the key
-		 * to TCACHE_STATE_PURGATORY so that other destructors wouldn't
-		 * cause re-creation of the tcache.  This time, do nothing, so
-		 * that the destructor will not be called again.
-		 */
-	} else if (tcache != NULL) {
-		assert(tcache != TCACHE_STATE_PURGATORY);
-		tcache_destroy(tcache);
-		tcache = TCACHE_STATE_PURGATORY;
-		tcache_tsd_set(&tcache);
+				tsd_array->tcaches[i] = TCACHE_STATE_PURGATORY;
+			}
+		}
 	}
+	malloc_mutex_unlock(&pools_lock);
 }
 
 /* Caller must own arena->lock. */
@@ -431,6 +484,10 @@ tcache_boot0(void)
 {
 	unsigned i;
 
+	/* Array still initialized */
+	if (tcache_bin_info != NULL)
+		return (false);
+
 	/*
 	 * If necessary, clamp opt_lg_tcache_max, now that arena_maxclass is
 	 * known.
@@ -445,8 +502,9 @@ tcache_boot0(void)
 	nhbins = NBINS + (tcache_maxclass >> LG_PAGE);
 
 	/* Initialize tcache_bin_info. */
-	tcache_bin_info = (tcache_bin_info_t *)base_alloc(nhbins *
-	    sizeof(tcache_bin_info_t));
+	tcache_bin_info = (tcache_bin_info_t *)je_base_malloc(nhbins *
+		sizeof(tcache_bin_info_t));
+
 	if (tcache_bin_info == NULL)
 		return (true);
 	stack_nelms = 0;
diff --git a/src/jemalloc/src/tsd.c b/src/jemalloc/src/tsd.c
index 700caabfe47789f57e3ea6ea67196e2b15f7e88e..a116d86999a66bebff0e46643f17e731420190ae 100644
--- a/src/jemalloc/src/tsd.c
+++ b/src/jemalloc/src/tsd.c
@@ -12,9 +12,9 @@ static malloc_tsd_cleanup_t cleanups[MALLOC_TSD_CLEANUPS_MAX];
 void *
 malloc_tsd_malloc(size_t size)
 {
-
+	pool_t *base_pool = pools[0];
 	/* Avoid choose_arena() in order to dodge bootstrapping issues. */
-	return (arena_malloc(arenas[0], size, false, false));
+	return (arena_malloc(base_pool->arenas[0], size, false, false));
 }
 
 void
diff --git a/src/jemalloc/src/util.c b/src/jemalloc/src/util.c
index 93a19fd16f7609efb5b49dc704fdcd3bd89a5da8..1717f08eac61ff576ebafdb942fe82a46441033f 100644
--- a/src/jemalloc/src/util.c
+++ b/src/jemalloc/src/util.c
@@ -100,7 +100,7 @@ uintmax_t
 malloc_strtoumax(const char *restrict nptr, char **restrict endptr, int base)
 {
 	uintmax_t ret, digit;
-	int b;
+	unsigned b;
 	bool neg;
 	const char *p, *ns;
 
@@ -381,7 +381,9 @@ malloc_vsnprintf(char *str, size_t size, const char *format, va_list ap)
 	case 'p': /* Synthetic; used for %p. */				\
 		val = va_arg(ap, uintptr_t);				\
 		break;							\
-	default: not_reached();						\
+	default:							\
+		not_reached();						\
+		val = 0;						\
 	}								\
 } while (0)
 
@@ -548,7 +550,7 @@ malloc_vsnprintf(char *str, size_t size, const char *format, va_list ap)
 				assert(len == '?' || len == 'l');
 				assert_not_implemented(len != 'l');
 				s = va_arg(ap, char *);
-				slen = (prec < 0) ? strlen(s) : prec;
+				slen = (prec < 0) ? strlen(s) : (size_t)prec;
 				APPEND_PADDED_S(s, slen, width, left_justify);
 				f++;
 				break;
diff --git a/src/jemalloc/src/valgrind.c b/src/jemalloc/src/valgrind.c
new file mode 100644
index 0000000000000000000000000000000000000000..ffee4c738cf41bf4fc258cfbc25a4e90d17d0809
--- /dev/null
+++ b/src/jemalloc/src/valgrind.c
@@ -0,0 +1,34 @@
+#include "jemalloc/internal/jemalloc_internal.h"
+#ifndef JEMALLOC_VALGRIND
+#  error "This source file is for Valgrind integration."
+#endif
+
+#include <valgrind/memcheck.h>
+
+void
+valgrind_make_mem_noaccess(void *ptr, size_t usize)
+{
+
+	(void)VALGRIND_MAKE_MEM_NOACCESS(ptr, usize);
+}
+
+void
+valgrind_make_mem_undefined(void *ptr, size_t usize)
+{
+
+	(void)VALGRIND_MAKE_MEM_UNDEFINED(ptr, usize);
+}
+
+void
+valgrind_make_mem_defined(void *ptr, size_t usize)
+{
+
+	(void)VALGRIND_MAKE_MEM_DEFINED(ptr, usize);
+}
+
+void
+valgrind_freelike_block(void *ptr, size_t usize)
+{
+
+	VALGRIND_FREELIKE_BLOCK(ptr, usize);
+}
diff --git a/src/jemalloc/src/vector.c b/src/jemalloc/src/vector.c
new file mode 100644
index 0000000000000000000000000000000000000000..0067b693ff76293a0adf9f5120753a2bb247adb7
--- /dev/null
+++ b/src/jemalloc/src/vector.c
@@ -0,0 +1,82 @@
+#define	JEMALLOC_VECTOR_C_
+#include "jemalloc/internal/jemalloc_internal.h"
+
+/* Round up the value to the closest power of two. */
+static inline unsigned
+ceil_p2(unsigned n)
+{
+	return 1 << (32 - __builtin_clz(n));
+}
+
+/* Calculate how big should be the vector list array. */
+static inline unsigned
+get_vec_part_len(unsigned n)
+{
+	return MAX(ceil_p2(n), VECTOR_MIN_PART_SIZE);
+}
+
+/*
+ * Find the vector list element in which the index should be stored,
+ * if no such list exist return a pointer to a place in memory where it should
+ * be allocated.
+ */
+static vec_list_t  **
+find_vec_list(vector_t *vector, int *index)
+{
+	vec_list_t **vec_list;
+
+	for (vec_list = &vector->list;
+		*vec_list != NULL; vec_list = &(*vec_list)->next) {
+		if (*index < (*vec_list)->length)
+			break;
+
+		*index -= (*vec_list)->length;
+	}
+
+	return vec_list;
+}
+
+/* Return a value from vector at index. */
+void *
+vec_get(vector_t *vector, int index)
+{
+	vec_list_t *vec_list = *find_vec_list(vector, &index);
+
+	return (vec_list == NULL) ? NULL : vec_list->data[index];
+}
+
+/* Set a value to vector at index. */
+void
+vec_set(vector_t *vector, int index, void *val)
+{
+	vec_list_t **vec_list = find_vec_list(vector, &index);
+
+	/*
+	 * There's no array to put the value in,
+	 * which means a new one has to be allocated.
+	 */
+	if (*vec_list == NULL) {
+		int vec_part_len = get_vec_part_len(index);
+
+		*vec_list = je_base_malloc(sizeof(vec_list_t) +
+				sizeof(void *) * vec_part_len);
+		if (*vec_list == NULL)
+			return;
+		(*vec_list)->next = NULL;
+		(*vec_list)->length = vec_part_len;
+	}
+
+	(*vec_list)->data[index] = val;
+}
+
+/* Free all the memory in the container. */
+void
+vec_delete(vector_t *vector)
+{
+	vec_list_t *vec_list_next, *vec_list = vector->list;
+	while (vec_list != NULL) {
+		vec_list_next = vec_list->next;
+		je_base_free(vec_list);
+		vec_list = vec_list_next;
+	}
+}
\ No newline at end of file
diff --git a/src/jemalloc/src/zone.c b/src/jemalloc/src/zone.c
index e0302ef4edc35402adef563fdc72252ce8431cb7..a722287b2e9c70e380752a6c4357259199b552c1 100644
--- a/src/jemalloc/src/zone.c
+++ b/src/jemalloc/src/zone.c
@@ -176,6 +176,7 @@ register_zone(void)
 	 * register jemalloc's.
 	 */
 	malloc_zone_t *default_zone = malloc_default_zone();
+	malloc_zone_t *purgeable_zone = NULL;
 	if (!default_zone->zone_name ||
 	    strcmp(default_zone->zone_name, "DefaultMallocZone") != 0) {
 		return;
@@ -237,22 +238,37 @@ register_zone(void)
 	 * run time.
 	 */
 	if (malloc_default_purgeable_zone != NULL)
-		malloc_default_purgeable_zone();
+		purgeable_zone = malloc_default_purgeable_zone();
 
 	/* Register the custom zone.  At this point it won't be the default. */
 	malloc_zone_register(&zone);
 
-	/*
-	 * Unregister and reregister the default zone.  On OSX >= 10.6,
-	 * unregistering takes the last registered zone and places it at the
-	 * location of the specified zone.  Unregistering the default zone thus
-	 * makes the last registered one the default.  On OSX < 10.6,
-	 * unregistering shifts all registered zones.  The first registered zone
-	 * then becomes the default.
-	 */
 	do {
 		default_zone = malloc_default_zone();
+		/*
+		 * Unregister and reregister the default zone.  On OSX >= 10.6,
+		 * unregistering takes the last registered zone and places it
+		 * at the location of the specified zone.  Unregistering the
+		 * default zone thus makes the last registered one the default.
+		 * On OSX < 10.6, unregistering shifts all registered zones.
+		 * The first registered zone then becomes the default.
+		 */
 		malloc_zone_unregister(default_zone);
 		malloc_zone_register(default_zone);
+		/*
+		 * On OSX 10.6, having the default purgeable zone appear before
+		 * the default zone makes some things crash because it thinks it
+		 * owns the default zone allocated pointers. We thus unregister/
+		 * re-register it in order to ensure it's always after the
+		 * default zone. On OSX < 10.6, there is no purgeable zone, so
+		 * this does nothing. On OSX >= 10.6, unregistering replaces the
+		 * purgeable zone with the last registered zone above, i.e the
+		 * default zone. Registering it again then puts it at the end,
+		 * obviously after the default zone.
+		 */
+		if (purgeable_zone) {
+			malloc_zone_unregister(purgeable_zone);
+			malloc_zone_register(purgeable_zone);
+		}
 	} while (malloc_default_zone() != &zone);
 }
diff --git a/src/jemalloc/test/include/test/jemalloc_test_defs.h.in b/src/jemalloc/test/include/test/jemalloc_test_defs.h.in
index 18a9773d705e8001e0a30cd9ad625754a0d61564..aaaaec14b2cb890736d56f0c01664e7b378fd73d 100644
--- a/src/jemalloc/test/include/test/jemalloc_test_defs.h.in
+++ b/src/jemalloc/test/include/test/jemalloc_test_defs.h.in
@@ -1,4 +1,5 @@
 #include "jemalloc/internal/jemalloc_internal_defs.h"
+#include "jemalloc/internal/jemalloc_internal_decls.h"
 
 /* For use by SFMT. */
 #undef HAVE_SSE2
diff --git a/src/jemalloc/test/include/test/test.h b/src/jemalloc/test/include/test/test.h
index a32ec07c4c51362428b313173f4ae54f1026a90f..863e20b234828592ccc55ca1ab6717b4c7748922 100644
--- a/src/jemalloc/test/include/test/test.h
+++ b/src/jemalloc/test/include/test/test.h
@@ -1,6 +1,6 @@
 #define	ASSERT_BUFSIZE	256
 
-#define	assert_cmp(t, a, b, cmp, neg_cmp, pri, fmt...) do {		\
+#define	assert_cmp(t, a, b, cmp, neg_cmp, pri, ...) do {		\
 	t a_ = (a);							\
 	t b_ = (b);							\
 	if (!(a_ cmp b_)) {						\
@@ -12,205 +12,205 @@
 		    "%"pri" "#neg_cmp" %"pri": ",			\
 		    __func__, __FILE__, __LINE__,			\
 		    #a, #b, a_, b_);					\
-		malloc_snprintf(message, sizeof(message), fmt);		\
+		malloc_snprintf(message, sizeof(message), __VA_ARGS__);	\
 		p_test_fail(prefix, message);				\
 	}								\
 } while (0)
 
-#define	assert_ptr_eq(a, b, fmt...)	assert_cmp(void *, a, b, ==,	\
-    !=, "p", fmt)
-#define	assert_ptr_ne(a, b, fmt...)	assert_cmp(void *, a, b, !=,	\
-    ==, "p", fmt)
-#define	assert_ptr_null(a, fmt...)	assert_cmp(void *, a, NULL, ==,	\
-    !=, "p", fmt)
-#define	assert_ptr_not_null(a, fmt...)	assert_cmp(void *, a, NULL, !=,	\
-    ==, "p", fmt)
-
-#define	assert_c_eq(a, b, fmt...)	assert_cmp(char, a, b, ==, !=, "c", fmt)
-#define	assert_c_ne(a, b, fmt...)	assert_cmp(char, a, b, !=, ==, "c", fmt)
-#define	assert_c_lt(a, b, fmt...)	assert_cmp(char, a, b, <, >=, "c", fmt)
-#define	assert_c_le(a, b, fmt...)	assert_cmp(char, a, b, <=, >, "c", fmt)
-#define	assert_c_ge(a, b, fmt...)	assert_cmp(char, a, b, >=, <, "c", fmt)
-#define	assert_c_gt(a, b, fmt...)	assert_cmp(char, a, b, >, <=, "c", fmt)
-
-#define	assert_x_eq(a, b, fmt...)	assert_cmp(int, a, b, ==, !=, "#x", fmt)
-#define	assert_x_ne(a, b, fmt...)	assert_cmp(int, a, b, !=, ==, "#x", fmt)
-#define	assert_x_lt(a, b, fmt...)	assert_cmp(int, a, b, <, >=, "#x", fmt)
-#define	assert_x_le(a, b, fmt...)	assert_cmp(int, a, b, <=, >, "#x", fmt)
-#define	assert_x_ge(a, b, fmt...)	assert_cmp(int, a, b, >=, <, "#x", fmt)
-#define	assert_x_gt(a, b, fmt...)	assert_cmp(int, a, b, >, <=, "#x", fmt)
-
-#define	assert_d_eq(a, b, fmt...)	assert_cmp(int, a, b, ==, !=, "d", fmt)
-#define	assert_d_ne(a, b, fmt...)	assert_cmp(int, a, b, !=, ==, "d", fmt)
-#define	assert_d_lt(a, b, fmt...)	assert_cmp(int, a, b, <, >=, "d", fmt)
-#define	assert_d_le(a, b, fmt...)	assert_cmp(int, a, b, <=, >, "d", fmt)
-#define	assert_d_ge(a, b, fmt...)	assert_cmp(int, a, b, >=, <, "d", fmt)
-#define	assert_d_gt(a, b, fmt...)	assert_cmp(int, a, b, >, <=, "d", fmt)
-
-#define	assert_u_eq(a, b, fmt...)	assert_cmp(int, a, b, ==, !=, "u", fmt)
-#define	assert_u_ne(a, b, fmt...)	assert_cmp(int, a, b, !=, ==, "u", fmt)
-#define	assert_u_lt(a, b, fmt...)	assert_cmp(int, a, b, <, >=, "u", fmt)
-#define	assert_u_le(a, b, fmt...)	assert_cmp(int, a, b, <=, >, "u", fmt)
-#define	assert_u_ge(a, b, fmt...)	assert_cmp(int, a, b, >=, <, "u", fmt)
-#define	assert_u_gt(a, b, fmt...)	assert_cmp(int, a, b, >, <=, "u", fmt)
-
-#define	assert_ld_eq(a, b, fmt...)	assert_cmp(long, a, b, ==,	\
-    !=, "ld", fmt)
-#define	assert_ld_ne(a, b, fmt...)	assert_cmp(long, a, b, !=,	\
-    ==, "ld", fmt)
-#define	assert_ld_lt(a, b, fmt...)	assert_cmp(long, a, b, <,	\
-    >=, "ld", fmt)
-#define	assert_ld_le(a, b, fmt...)	assert_cmp(long, a, b, <=,	\
-    >, "ld", fmt)
-#define	assert_ld_ge(a, b, fmt...)	assert_cmp(long, a, b, >=,	\
-    <, "ld", fmt)
-#define	assert_ld_gt(a, b, fmt...)	assert_cmp(long, a, b, >,	\
-    <=, "ld", fmt)
-
-#define	assert_lu_eq(a, b, fmt...)	assert_cmp(unsigned long,	\
-    a, b, ==, !=, "lu", fmt)
-#define	assert_lu_ne(a, b, fmt...)	assert_cmp(unsigned long,	\
-    a, b, !=, ==, "lu", fmt)
-#define	assert_lu_lt(a, b, fmt...)	assert_cmp(unsigned long,	\
-    a, b, <, >=, "lu", fmt)
-#define	assert_lu_le(a, b, fmt...)	assert_cmp(unsigned long,	\
-    a, b, <=, >, "lu", fmt)
-#define	assert_lu_ge(a, b, fmt...)	assert_cmp(unsigned long,	\
-    a, b, >=, <, "lu", fmt)
-#define	assert_lu_gt(a, b, fmt...)	assert_cmp(unsigned long,	\
-    a, b, >, <=, "lu", fmt)
-
-#define	assert_qd_eq(a, b, fmt...)	assert_cmp(long long, a, b, ==,	\
-    !=, "qd", fmt)
-#define	assert_qd_ne(a, b, fmt...)	assert_cmp(long long, a, b, !=,	\
-    ==, "qd", fmt)
-#define	assert_qd_lt(a, b, fmt...)	assert_cmp(long long, a, b, <,	\
-    >=, "qd", fmt)
-#define	assert_qd_le(a, b, fmt...)	assert_cmp(long long, a, b, <=,	\
-    >, "qd", fmt)
-#define	assert_qd_ge(a, b, fmt...)	assert_cmp(long long, a, b, >=,	\
-    <, "qd", fmt)
-#define	assert_qd_gt(a, b, fmt...)	assert_cmp(long long, a, b, >,	\
-    <=, "qd", fmt)
-
-#define	assert_qu_eq(a, b, fmt...)	assert_cmp(unsigned long long,	\
-    a, b, ==, !=, "qu", fmt)
-#define	assert_qu_ne(a, b, fmt...)	assert_cmp(unsigned long long,	\
-    a, b, !=, ==, "qu", fmt)
-#define	assert_qu_lt(a, b, fmt...)	assert_cmp(unsigned long long,	\
-    a, b, <, >=, "qu", fmt)
-#define	assert_qu_le(a, b, fmt...)	assert_cmp(unsigned long long,	\
-    a, b, <=, >, "qu", fmt)
-#define	assert_qu_ge(a, b, fmt...)	assert_cmp(unsigned long long,	\
-    a, b, >=, <, "qu", fmt)
-#define	assert_qu_gt(a, b, fmt...)	assert_cmp(unsigned long long,	\
-    a, b, >, <=, "qu", fmt)
-
-#define	assert_jd_eq(a, b, fmt...)	assert_cmp(intmax_t, a, b, ==,	\
-    !=, "jd", fmt)
-#define	assert_jd_ne(a, b, fmt...)	assert_cmp(intmax_t, a, b, !=,	\
-    ==, "jd", fmt)
-#define	assert_jd_lt(a, b, fmt...)	assert_cmp(intmax_t, a, b, <,	\
-    >=, "jd", fmt)
-#define	assert_jd_le(a, b, fmt...)	assert_cmp(intmax_t, a, b, <=,	\
-    >, "jd", fmt)
-#define	assert_jd_ge(a, b, fmt...)	assert_cmp(intmax_t, a, b, >=,	\
-    <, "jd", fmt)
-#define	assert_jd_gt(a, b, fmt...)	assert_cmp(intmax_t, a, b, >,	\
-    <=, "jd", fmt)
-
-#define	assert_ju_eq(a, b, fmt...)	assert_cmp(uintmax_t, a, b, ==,	\
-    !=, "ju", fmt)
-#define	assert_ju_ne(a, b, fmt...)	assert_cmp(uintmax_t, a, b, !=,	\
-    ==, "ju", fmt)
-#define	assert_ju_lt(a, b, fmt...)	assert_cmp(uintmax_t, a, b, <,	\
-    >=, "ju", fmt)
-#define	assert_ju_le(a, b, fmt...)	assert_cmp(uintmax_t, a, b, <=,	\
-    >, "ju", fmt)
-#define	assert_ju_ge(a, b, fmt...)	assert_cmp(uintmax_t, a, b, >=,	\
-    <, "ju", fmt)
-#define	assert_ju_gt(a, b, fmt...)	assert_cmp(uintmax_t, a, b, >,	\
-    <=, "ju", fmt)
-
-#define	assert_zd_eq(a, b, fmt...)	assert_cmp(ssize_t, a, b, ==,	\
-    !=, "zd", fmt)
-#define	assert_zd_ne(a, b, fmt...)	assert_cmp(ssize_t, a, b, !=,	\
-    ==, "zd", fmt)
-#define	assert_zd_lt(a, b, fmt...)	assert_cmp(ssize_t, a, b, <,	\
-    >=, "zd", fmt)
-#define	assert_zd_le(a, b, fmt...)	assert_cmp(ssize_t, a, b, <=,	\
-    >, "zd", fmt)
-#define	assert_zd_ge(a, b, fmt...)	assert_cmp(ssize_t, a, b, >=,	\
-    <, "zd", fmt)
-#define	assert_zd_gt(a, b, fmt...)	assert_cmp(ssize_t, a, b, >,	\
-    <=, "zd", fmt)
-
-#define	assert_zu_eq(a, b, fmt...)	assert_cmp(size_t, a, b, ==,	\
-    !=, "zu", fmt)
-#define	assert_zu_ne(a, b, fmt...)	assert_cmp(size_t, a, b, !=,	\
-    ==, "zu", fmt)
-#define	assert_zu_lt(a, b, fmt...)	assert_cmp(size_t, a, b, <,	\
-    >=, "zu", fmt)
-#define	assert_zu_le(a, b, fmt...)	assert_cmp(size_t, a, b, <=,	\
-    >, "zu", fmt)
-#define	assert_zu_ge(a, b, fmt...)	assert_cmp(size_t, a, b, >=,	\
-    <, "zu", fmt)
-#define	assert_zu_gt(a, b, fmt...)	assert_cmp(size_t, a, b, >,	\
-    <=, "zu", fmt)
-
-#define	assert_d32_eq(a, b, fmt...)	assert_cmp(int32_t, a, b, ==,	\
-    !=, PRId32, fmt)
-#define	assert_d32_ne(a, b, fmt...)	assert_cmp(int32_t, a, b, !=,	\
-    ==, PRId32, fmt)
-#define	assert_d32_lt(a, b, fmt...)	assert_cmp(int32_t, a, b, <,	\
-    >=, PRId32, fmt)
-#define	assert_d32_le(a, b, fmt...)	assert_cmp(int32_t, a, b, <=,	\
-    >, PRId32, fmt)
-#define	assert_d32_ge(a, b, fmt...)	assert_cmp(int32_t, a, b, >=,	\
-    <, PRId32, fmt)
-#define	assert_d32_gt(a, b, fmt...)	assert_cmp(int32_t, a, b, >,	\
-    <=, PRId32, fmt)
-
-#define	assert_u32_eq(a, b, fmt...)	assert_cmp(uint32_t, a, b, ==,	\
-    !=, PRIu32, fmt)
-#define	assert_u32_ne(a, b, fmt...)	assert_cmp(uint32_t, a, b, !=,	\
-    ==, PRIu32, fmt)
-#define	assert_u32_lt(a, b, fmt...)	assert_cmp(uint32_t, a, b, <,	\
-    >=, PRIu32, fmt)
-#define	assert_u32_le(a, b, fmt...)	assert_cmp(uint32_t, a, b, <=,	\
-    >, PRIu32, fmt)
-#define	assert_u32_ge(a, b, fmt...)	assert_cmp(uint32_t, a, b, >=,	\
-    <, PRIu32, fmt)
-#define	assert_u32_gt(a, b, fmt...)	assert_cmp(uint32_t, a, b, >,	\
-    <=, PRIu32, fmt)
-
-#define	assert_d64_eq(a, b, fmt...)	assert_cmp(int64_t, a, b, ==,	\
-    !=, PRId64, fmt)
-#define	assert_d64_ne(a, b, fmt...)	assert_cmp(int64_t, a, b, !=,	\
-    ==, PRId64, fmt)
-#define	assert_d64_lt(a, b, fmt...)	assert_cmp(int64_t, a, b, <,	\
-    >=, PRId64, fmt)
-#define	assert_d64_le(a, b, fmt...)	assert_cmp(int64_t, a, b, <=,	\
-    >, PRId64, fmt)
-#define	assert_d64_ge(a, b, fmt...)	assert_cmp(int64_t, a, b, >=,	\
-    <, PRId64, fmt)
-#define	assert_d64_gt(a, b, fmt...)	assert_cmp(int64_t, a, b, >,	\
-    <=, PRId64, fmt)
-
-#define	assert_u64_eq(a, b, fmt...)	assert_cmp(uint64_t, a, b, ==,	\
-    !=, PRIu64, fmt)
-#define	assert_u64_ne(a, b, fmt...)	assert_cmp(uint64_t, a, b, !=,	\
-    ==, PRIu64, fmt)
-#define	assert_u64_lt(a, b, fmt...)	assert_cmp(uint64_t, a, b, <,	\
-    >=, PRIu64, fmt)
-#define	assert_u64_le(a, b, fmt...)	assert_cmp(uint64_t, a, b, <=,	\
-    >, PRIu64, fmt)
-#define	assert_u64_ge(a, b, fmt...)	assert_cmp(uint64_t, a, b, >=,	\
-    <, PRIu64, fmt)
-#define	assert_u64_gt(a, b, fmt...)	assert_cmp(uint64_t, a, b, >,	\
-    <=, PRIu64, fmt)
-
-#define	assert_b_eq(a, b, fmt...) do {					\
+#define	assert_ptr_eq(a, b, ...)	assert_cmp(void *, a, b, ==,	\
+    !=, "p", __VA_ARGS__)
+#define	assert_ptr_ne(a, b, ...)	assert_cmp(void *, a, b, !=,	\
+    ==, "p", __VA_ARGS__)
+#define	assert_ptr_null(a, ...)		assert_cmp(void *, a, NULL, ==,	\
+    !=, "p", __VA_ARGS__)
+#define	assert_ptr_not_null(a, ...)	assert_cmp(void *, a, NULL, !=,	\
+    ==, "p", __VA_ARGS__)
+
+#define	assert_c_eq(a, b, ...)	assert_cmp(char, a, b, ==, !=, "c", __VA_ARGS__)
+#define	assert_c_ne(a, b, ...)	assert_cmp(char, a, b, !=, ==, "c", __VA_ARGS__)
+#define	assert_c_lt(a, b, ...)	assert_cmp(char, a, b, <, >=, "c", __VA_ARGS__)
+#define	assert_c_le(a, b, ...)	assert_cmp(char, a, b, <=, >, "c", __VA_ARGS__)
+#define	assert_c_ge(a, b, ...)	assert_cmp(char, a, b, >=, <, "c", __VA_ARGS__)
+#define	assert_c_gt(a, b, ...)	assert_cmp(char, a, b, >, <=, "c", __VA_ARGS__)
+
+#define	assert_x_eq(a, b, ...)	assert_cmp(int, a, b, ==, !=, "#x", __VA_ARGS__)
+#define	assert_x_ne(a, b, ...)	assert_cmp(int, a, b, !=, ==, "#x", __VA_ARGS__)
+#define	assert_x_lt(a, b, ...)	assert_cmp(int, a, b, <, >=, "#x", __VA_ARGS__)
+#define	assert_x_le(a, b, ...)	assert_cmp(int, a, b, <=, >, "#x", __VA_ARGS__)
+#define	assert_x_ge(a, b, ...)	assert_cmp(int, a, b, >=, <, "#x", __VA_ARGS__)
+#define	assert_x_gt(a, b, ...)	assert_cmp(int, a, b, >, <=, "#x", __VA_ARGS__)
+
+#define	assert_d_eq(a, b, ...)	assert_cmp(int, a, b, ==, !=, "d", __VA_ARGS__)
+#define	assert_d_ne(a, b, ...)	assert_cmp(int, a, b, !=, ==, "d", __VA_ARGS__)
+#define	assert_d_lt(a, b, ...)	assert_cmp(int, a, b, <, >=, "d", __VA_ARGS__)
+#define	assert_d_le(a, b, ...)	assert_cmp(int, a, b, <=, >, "d", __VA_ARGS__)
+#define	assert_d_ge(a, b, ...)	assert_cmp(int, a, b, >=, <, "d", __VA_ARGS__)
+#define	assert_d_gt(a, b, ...)	assert_cmp(int, a, b, >, <=, "d", __VA_ARGS__)
+
+#define	assert_u_eq(a, b, ...)	assert_cmp(int, a, b, ==, !=, "u", __VA_ARGS__)
+#define	assert_u_ne(a, b, ...)	assert_cmp(int, a, b, !=, ==, "u", __VA_ARGS__)
+#define	assert_u_lt(a, b, ...)	assert_cmp(int, a, b, <, >=, "u", __VA_ARGS__)
+#define	assert_u_le(a, b, ...)	assert_cmp(int, a, b, <=, >, "u", __VA_ARGS__)
+#define	assert_u_ge(a, b, ...)	assert_cmp(int, a, b, >=, <, "u", __VA_ARGS__)
+#define	assert_u_gt(a, b, ...)	assert_cmp(int, a, b, >, <=, "u", __VA_ARGS__)
+
+#define	assert_ld_eq(a, b, ...)	assert_cmp(long, a, b, ==,	\
+    !=, "ld", __VA_ARGS__)
+#define	assert_ld_ne(a, b, ...)	assert_cmp(long, a, b, !=,	\
+    ==, "ld", __VA_ARGS__)
+#define	assert_ld_lt(a, b, ...)	assert_cmp(long, a, b, <,	\
+    >=, "ld", __VA_ARGS__)
+#define	assert_ld_le(a, b, ...)	assert_cmp(long, a, b, <=,	\
+    >, "ld", __VA_ARGS__)
+#define	assert_ld_ge(a, b, ...)	assert_cmp(long, a, b, >=,	\
+    <, "ld", __VA_ARGS__)
+#define	assert_ld_gt(a, b, ...)	assert_cmp(long, a, b, >,	\
+    <=, "ld", __VA_ARGS__)
+
+#define	assert_lu_eq(a, b, ...)	assert_cmp(unsigned long,	\
+    a, b, ==, !=, "lu", __VA_ARGS__)
+#define	assert_lu_ne(a, b, ...)	assert_cmp(unsigned long,	\
+    a, b, !=, ==, "lu", __VA_ARGS__)
+#define	assert_lu_lt(a, b, ...)	assert_cmp(unsigned long,	\
+    a, b, <, >=, "lu", __VA_ARGS__)
+#define	assert_lu_le(a, b, ...)	assert_cmp(unsigned long,	\
+    a, b, <=, >, "lu", __VA_ARGS__)
+#define	assert_lu_ge(a, b, ...)	assert_cmp(unsigned long,	\
+    a, b, >=, <, "lu", __VA_ARGS__)
+#define	assert_lu_gt(a, b, ...)	assert_cmp(unsigned long,	\
+    a, b, >, <=, "lu", __VA_ARGS__)
+
+#define	assert_qd_eq(a, b, ...)	assert_cmp(long long, a, b, ==,	\
+    !=, "qd", __VA_ARGS__)
+#define	assert_qd_ne(a, b, ...)	assert_cmp(long long, a, b, !=,	\
+    ==, "qd", __VA_ARGS__)
+#define	assert_qd_lt(a, b, ...)	assert_cmp(long long, a, b, <,	\
+    >=, "qd", __VA_ARGS__)
+#define	assert_qd_le(a, b, ...)	assert_cmp(long long, a, b, <=,	\
+    >, "qd", __VA_ARGS__)
+#define	assert_qd_ge(a, b, ...)	assert_cmp(long long, a, b, >=,	\
+    <, "qd", __VA_ARGS__)
+#define	assert_qd_gt(a, b, ...)	assert_cmp(long long, a, b, >,	\
+    <=, "qd", __VA_ARGS__)
+
+#define	assert_qu_eq(a, b, ...)	assert_cmp(unsigned long long,	\
+    a, b, ==, !=, "qu", __VA_ARGS__)
+#define	assert_qu_ne(a, b, ...)	assert_cmp(unsigned long long,	\
+    a, b, !=, ==, "qu", __VA_ARGS__)
+#define	assert_qu_lt(a, b, ...)	assert_cmp(unsigned long long,	\
+    a, b, <, >=, "qu", __VA_ARGS__)
+#define	assert_qu_le(a, b, ...)	assert_cmp(unsigned long long,	\
+    a, b, <=, >, "qu", __VA_ARGS__)
+#define	assert_qu_ge(a, b, ...)	assert_cmp(unsigned long long,	\
+    a, b, >=, <, "qu", __VA_ARGS__)
+#define	assert_qu_gt(a, b, ...)	assert_cmp(unsigned long long,	\
+    a, b, >, <=, "qu", __VA_ARGS__)
+
+#define	assert_jd_eq(a, b, ...)	assert_cmp(intmax_t, a, b, ==,	\
+    !=, "jd", __VA_ARGS__)
+#define	assert_jd_ne(a, b, ...)	assert_cmp(intmax_t, a, b, !=,	\
+    ==, "jd", __VA_ARGS__)
+#define	assert_jd_lt(a, b, ...)	assert_cmp(intmax_t, a, b, <,	\
+    >=, "jd", __VA_ARGS__)
+#define	assert_jd_le(a, b, ...)	assert_cmp(intmax_t, a, b, <=,	\
+    >, "jd", __VA_ARGS__)
+#define	assert_jd_ge(a, b, ...)	assert_cmp(intmax_t, a, b, >=,	\
+    <, "jd", __VA_ARGS__)
+#define	assert_jd_gt(a, b, ...)	assert_cmp(intmax_t, a, b, >,	\
+    <=, "jd", __VA_ARGS__)
+
+#define	assert_ju_eq(a, b, ...)	assert_cmp(uintmax_t, a, b, ==,	\
+    !=, "ju", __VA_ARGS__)
+#define	assert_ju_ne(a, b, ...)	assert_cmp(uintmax_t, a, b, !=,	\
+    ==, "ju", __VA_ARGS__)
+#define	assert_ju_lt(a, b, ...)	assert_cmp(uintmax_t, a, b, <,	\
+    >=, "ju", __VA_ARGS__)
+#define	assert_ju_le(a, b, ...)	assert_cmp(uintmax_t, a, b, <=,	\
+    >, "ju", __VA_ARGS__)
+#define	assert_ju_ge(a, b, ...)	assert_cmp(uintmax_t, a, b, >=,	\
+    <, "ju", __VA_ARGS__)
+#define	assert_ju_gt(a, b, ...)	assert_cmp(uintmax_t, a, b, >,	\
+    <=, "ju", __VA_ARGS__)
+
+#define	assert_zd_eq(a, b, ...)	assert_cmp(ssize_t, a, b, ==,	\
+    !=, "zd", __VA_ARGS__)
+#define	assert_zd_ne(a, b, ...)	assert_cmp(ssize_t, a, b, !=,	\
+    ==, "zd", __VA_ARGS__)
+#define	assert_zd_lt(a, b, ...)	assert_cmp(ssize_t, a, b, <,	\
+    >=, "zd", __VA_ARGS__)
+#define	assert_zd_le(a, b, ...)	assert_cmp(ssize_t, a, b, <=,	\
+    >, "zd", __VA_ARGS__)
+#define	assert_zd_ge(a, b, ...)	assert_cmp(ssize_t, a, b, >=,	\
+    <, "zd", __VA_ARGS__)
+#define	assert_zd_gt(a, b, ...)	assert_cmp(ssize_t, a, b, >,	\
+    <=, "zd", __VA_ARGS__)
+
+#define	assert_zu_eq(a, b, ...)	assert_cmp(size_t, a, b, ==,	\
+    !=, "zu", __VA_ARGS__)
+#define	assert_zu_ne(a, b, ...)	assert_cmp(size_t, a, b, !=,	\
+    ==, "zu", __VA_ARGS__)
+#define	assert_zu_lt(a, b, ...)	assert_cmp(size_t, a, b, <,	\
+    >=, "zu", __VA_ARGS__)
+#define	assert_zu_le(a, b, ...)	assert_cmp(size_t, a, b, <=,	\
+    >, "zu", __VA_ARGS__)
+#define	assert_zu_ge(a, b, ...)	assert_cmp(size_t, a, b, >=,	\
+    <, "zu", __VA_ARGS__)
+#define	assert_zu_gt(a, b, ...)	assert_cmp(size_t, a, b, >,	\
+    <=, "zu", __VA_ARGS__)
+
+#define	assert_d32_eq(a, b, ...)	assert_cmp(int32_t, a, b, ==,	\
+    !=, PRId32, __VA_ARGS__)
+#define	assert_d32_ne(a, b, ...)	assert_cmp(int32_t, a, b, !=,	\
+    ==, PRId32, __VA_ARGS__)
+#define	assert_d32_lt(a, b, ...)	assert_cmp(int32_t, a, b, <,	\
+    >=, PRId32, __VA_ARGS__)
+#define	assert_d32_le(a, b, ...)	assert_cmp(int32_t, a, b, <=,	\
+    >, PRId32, __VA_ARGS__)
+#define	assert_d32_ge(a, b, ...)	assert_cmp(int32_t, a, b, >=,	\
+    <, PRId32, __VA_ARGS__)
+#define	assert_d32_gt(a, b, ...)	assert_cmp(int32_t, a, b, >,	\
+    <=, PRId32, __VA_ARGS__)
+
+#define	assert_u32_eq(a, b, ...)	assert_cmp(uint32_t, a, b, ==,	\
+    !=, PRIu32, __VA_ARGS__)
+#define	assert_u32_ne(a, b, ...)	assert_cmp(uint32_t, a, b, !=,	\
+    ==, PRIu32, __VA_ARGS__)
+#define	assert_u32_lt(a, b, ...)	assert_cmp(uint32_t, a, b, <,	\
+    >=, PRIu32, __VA_ARGS__)
+#define	assert_u32_le(a, b, ...)	assert_cmp(uint32_t, a, b, <=,	\
+    >, PRIu32, __VA_ARGS__)
+#define	assert_u32_ge(a, b, ...)	assert_cmp(uint32_t, a, b, >=,	\
+    <, PRIu32, __VA_ARGS__)
+#define	assert_u32_gt(a, b, ...)	assert_cmp(uint32_t, a, b, >,	\
+    <=, PRIu32, __VA_ARGS__)
+
+#define	assert_d64_eq(a, b, ...)	assert_cmp(int64_t, a, b, ==,	\
+    !=, PRId64, __VA_ARGS__)
+#define	assert_d64_ne(a, b, ...)	assert_cmp(int64_t, a, b, !=,	\
+    ==, PRId64, __VA_ARGS__)
+#define	assert_d64_lt(a, b, ...)	assert_cmp(int64_t, a, b, <,	\
+    >=, PRId64, __VA_ARGS__)
+#define	assert_d64_le(a, b, ...)	assert_cmp(int64_t, a, b, <=,	\
+    >, PRId64, __VA_ARGS__)
+#define	assert_d64_ge(a, b, ...)	assert_cmp(int64_t, a, b, >=,	\
+    <, PRId64, __VA_ARGS__)
+#define	assert_d64_gt(a, b, ...)	assert_cmp(int64_t, a, b, >,	\
+    <=, PRId64, __VA_ARGS__)
+
+#define	assert_u64_eq(a, b, ...)	assert_cmp(uint64_t, a, b, ==,	\
+    !=, PRIu64, __VA_ARGS__)
+#define	assert_u64_ne(a, b, ...)	assert_cmp(uint64_t, a, b, !=,	\
+    ==, PRIu64, __VA_ARGS__)
+#define	assert_u64_lt(a, b, ...)	assert_cmp(uint64_t, a, b, <,	\
+    >=, PRIu64, __VA_ARGS__)
+#define	assert_u64_le(a, b, ...)	assert_cmp(uint64_t, a, b, <=,	\
+    >, PRIu64, __VA_ARGS__)
+#define	assert_u64_ge(a, b, ...)	assert_cmp(uint64_t, a, b, >=,	\
+    <, PRIu64, __VA_ARGS__)
+#define	assert_u64_gt(a, b, ...)	assert_cmp(uint64_t, a, b, >,	\
+    <=, PRIu64, __VA_ARGS__)
+
+#define	assert_b_eq(a, b, ...) do {					\
 	bool a_ = (a);							\
 	bool b_ = (b);							\
 	if (!(a_ == b_)) {						\
@@ -222,11 +222,11 @@
 		    __func__, __FILE__, __LINE__,			\
 		    #a, #b, a_ ? "true" : "false",			\
 		    b_ ? "true" : "false");				\
-		malloc_snprintf(message, sizeof(message), fmt);		\
+		malloc_snprintf(message, sizeof(message), __VA_ARGS__);	\
 		p_test_fail(prefix, message);				\
 	}								\
 } while (0)
-#define	assert_b_ne(a, b, fmt...) do {					\
+#define	assert_b_ne(a, b, ...) do {					\
 	bool a_ = (a);							\
 	bool b_ = (b);							\
 	if (!(a_ != b_)) {						\
@@ -238,14 +238,14 @@
 		    __func__, __FILE__, __LINE__,			\
 		    #a, #b, a_ ? "true" : "false",			\
 		    b_ ? "true" : "false");				\
-		malloc_snprintf(message, sizeof(message), fmt);		\
+		malloc_snprintf(message, sizeof(message), __VA_ARGS__);	\
 		p_test_fail(prefix, message);				\
 	}								\
 } while (0)
-#define	assert_true(a, fmt...)	assert_b_eq(a, true, fmt)
-#define	assert_false(a, fmt...)	assert_b_eq(a, false, fmt)
+#define	assert_true(a, ...)	assert_b_eq(a, true, __VA_ARGS__)
+#define	assert_false(a, ...)	assert_b_eq(a, false, __VA_ARGS__)
 
-#define	assert_str_eq(a, b, fmt...) do {				\
+#define	assert_str_eq(a, b, ...) do {				\
 	if (strcmp((a), (b))) {						\
 		char prefix[ASSERT_BUFSIZE];				\
 		char message[ASSERT_BUFSIZE];				\
@@ -254,11 +254,11 @@
 		    "(%s) same as (%s) --> "				\
 		    "\"%s\" differs from \"%s\": ",			\
 		    __func__, __FILE__, __LINE__, #a, #b, a, b);	\
-		malloc_snprintf(message, sizeof(message), fmt);		\
+		malloc_snprintf(message, sizeof(message), __VA_ARGS__);	\
 		p_test_fail(prefix, message);				\
 	}								\
 } while (0)
-#define	assert_str_ne(a, b, fmt...) do {				\
+#define	assert_str_ne(a, b, ...) do {				\
 	if (!strcmp((a), (b))) {					\
 		char prefix[ASSERT_BUFSIZE];				\
 		char message[ASSERT_BUFSIZE];				\
@@ -267,18 +267,18 @@
 		    "(%s) differs from (%s) --> "			\
 		    "\"%s\" same as \"%s\": ",				\
 		    __func__, __FILE__, __LINE__, #a, #b, a, b);	\
-		malloc_snprintf(message, sizeof(message), fmt);		\
+		malloc_snprintf(message, sizeof(message), __VA_ARGS__);	\
 		p_test_fail(prefix, message);				\
 	}								\
 } while (0)
 
-#define	assert_not_reached(fmt...) do {					\
+#define	assert_not_reached(...) do {					\
 	char prefix[ASSERT_BUFSIZE];					\
 	char message[ASSERT_BUFSIZE];					\
 	malloc_snprintf(prefix, sizeof(prefix),				\
 	    "%s:%s:%d: Unreachable code reached: ",			\
 	    __func__, __FILE__, __LINE__);				\
-	malloc_snprintf(message, sizeof(message), fmt);			\
+	malloc_snprintf(message, sizeof(message), __VA_ARGS__);		\
 	p_test_fail(prefix, message);					\
 } while (0)
 
@@ -308,8 +308,12 @@ label_test_end:								\
 	p_test_fini();							\
 }
 
-#define	test(tests...)							\
-	p_test(tests, NULL)
+#define	test(...)							\
+	p_test(__VA_ARGS__, NULL)
+
+#define	test_not_init(...)							\
+	p_test_not_init(__VA_ARGS__, NULL)
+
 
 #define	test_skip_if(e) do {						\
 	if (e) {							\
@@ -323,7 +327,8 @@ void	test_skip(const char *format, ...) JEMALLOC_ATTR(format(printf, 1, 2));
 void	test_fail(const char *format, ...) JEMALLOC_ATTR(format(printf, 1, 2));
 
 /* For private use by macros. */
-test_status_t	p_test(test_t* t, ...);
+test_status_t	p_test(test_t *t, ...);
+test_status_t	p_test_not_init(test_t *t, ...);
 void	p_test_init(const char *name);
 void	p_test_fini(void);
 void	p_test_fail(const char *prefix, const char *message);
diff --git a/src/jemalloc/test/integration/MALLOCX_ARENA.c b/src/jemalloc/test/integration/MALLOCX_ARENA.c
index 71cf6f255e84fddf78a753c63ed7ffc9fe0b8998..88623fd28bc5c03698534aeeca30fc3788d11135 100644
--- a/src/jemalloc/test/integration/MALLOCX_ARENA.c
+++ b/src/jemalloc/test/integration/MALLOCX_ARENA.c
@@ -2,6 +2,14 @@
 
 #define	NTHREADS 10
 
+static bool have_dss =
+#ifdef JEMALLOC_DSS
+    true
+#else
+    false
+#endif
+    ;
+
 void *
 thd_start(void *arg)
 {
@@ -11,20 +19,23 @@ thd_start(void *arg)
 	size_t sz;
 
 	sz = sizeof(arena_ind);
-	assert_d_eq(mallctl("arenas.extend", &arena_ind, &sz, NULL, 0), 0,
-	    "Error in arenas.extend");
+	assert_d_eq(mallctl("pool.0.arenas.extend", &arena_ind, &sz, NULL, 0), 0,
+	    "Error in pool.0.arenas.extend");
 
 	if (thread_ind % 4 != 3) {
-		size_t mib[3];
+		size_t mib[5];
 		size_t miblen = sizeof(mib) / sizeof(size_t);
 		const char *dss_precs[] = {"disabled", "primary", "secondary"};
-		const char *dss = dss_precs[thread_ind %
-		    (sizeof(dss_precs)/sizeof(char*))];
-		assert_d_eq(mallctlnametomib("arena.0.dss", mib, &miblen), 0,
+		unsigned prec_ind = thread_ind %
+		    (sizeof(dss_precs)/sizeof(char*));
+		const char *dss = dss_precs[prec_ind];
+		int expected_err = (have_dss || prec_ind == 0) ? 0 : EFAULT;
+		assert_d_eq(mallctlnametomib("pool.0.arena.0.dss", mib, &miblen), 0,
 		    "Error in mallctlnametomib()");
-		mib[1] = arena_ind;
+		mib[3] = arena_ind;
 		assert_d_eq(mallctlbymib(mib, miblen, NULL, NULL, (void *)&dss,
-		    sizeof(const char *)), 0, "Error in mallctlbymib()");
+		    sizeof(const char *)), expected_err,
+		    "Error in mallctlbymib()");
 	}
 
 	p = mallocx(1, MALLOCX_ARENA(arena_ind));
@@ -34,7 +45,7 @@ thd_start(void *arg)
 	return (NULL);
 }
 
-TEST_BEGIN(test_ALLOCM_ARENA)
+TEST_BEGIN(test_MALLOCX_ARENA)
 {
 	thd_t thds[NTHREADS];
 	unsigned i;
@@ -54,5 +65,5 @@ main(void)
 {
 
 	return (test(
-	    test_ALLOCM_ARENA));
+	    test_MALLOCX_ARENA));
 }
diff --git a/src/jemalloc/test/integration/chunk.c b/src/jemalloc/test/integration/chunk.c
new file mode 100644
index 0000000000000000000000000000000000000000..1ed0954a0938b53e7cf0bf440d4adbb883648493
--- /dev/null
+++ b/src/jemalloc/test/integration/chunk.c
@@ -0,0 +1,58 @@
+#include "test/jemalloc_test.h"
+
+chunk_alloc_t *old_alloc;
+chunk_dalloc_t *old_dalloc;
+
+bool
+chunk_dalloc(void *chunk, size_t size, unsigned arena_ind, pool_t *pool)
+{
+
+	return (old_dalloc(chunk, size, arena_ind, pool));
+}
+
+void *
+chunk_alloc(size_t size, size_t alignment, bool *zero, unsigned arena_ind, pool_t *pool)
+{
+
+	return (old_alloc(size, alignment, zero, arena_ind, pool));
+}
+
+TEST_BEGIN(test_chunk)
+{
+	void *p;
+	chunk_alloc_t *new_alloc;
+	chunk_dalloc_t *new_dalloc;
+	size_t old_size, new_size;
+
+	new_alloc = chunk_alloc;
+	new_dalloc = chunk_dalloc;
+	old_size = sizeof(chunk_alloc_t *);
+	new_size = sizeof(chunk_alloc_t *);
+
+	assert_d_eq(mallctl("pool.0.arena.0.chunk.alloc", &old_alloc,
+	    &old_size, &new_alloc, new_size), 0,
+	    "Unexpected alloc error");
+	assert_ptr_ne(old_alloc, new_alloc,
+	    "Unexpected alloc error");
+	assert_d_eq(mallctl("pool.0.arena.0.chunk.dalloc", &old_dalloc, &old_size,
+	    &new_dalloc, new_size), 0, "Unexpected dalloc error");
+	assert_ptr_ne(old_dalloc, new_dalloc, "Unexpected dalloc error");
+
+	p = mallocx(42, 0);
+	assert_ptr_ne(p, NULL, "Unexpected alloc error");
+	free(p);
+
+	assert_d_eq(mallctl("pool.0.arena.0.chunk.alloc", NULL,
+	    NULL, &old_alloc, old_size), 0,
+	    "Unexpected alloc error");
+	assert_d_eq(mallctl("pool.0.arena.0.chunk.dalloc", NULL, NULL, &old_dalloc,
+	    old_size), 0, "Unexpected dalloc error");
+}
+TEST_END
+
+int
+main(void)
+{
+
+	return (test(test_chunk));
+}
diff --git a/src/jemalloc/test/integration/rallocx.c b/src/jemalloc/test/integration/rallocx.c
index ee21aedff70ef2fde48b1e7a50238e2c9bce99e7..b69807298c0703205dcb21d260672c0d24371c42 100644
--- a/src/jemalloc/test/integration/rallocx.c
+++ b/src/jemalloc/test/integration/rallocx.c
@@ -95,7 +95,8 @@ TEST_BEGIN(test_zero)
 				    "Expected zeroed memory");
 			}
 			if (psz != qsz) {
-				memset(q+psz, FILL_BYTE, qsz-psz);
+				memset((void *)((uintptr_t)q+psz), FILL_BYTE,
+				    qsz-psz);
 				psz = qsz;
 			}
 			p = q;
@@ -159,8 +160,9 @@ TEST_BEGIN(test_lg_align_and_zero)
 		} else {
 			assert_false(validate_fill(q, 0, 0, MAX_VALIDATE),
 			    "Expected zeroed memory");
-			assert_false(validate_fill(q+sz-MAX_VALIDATE, 0, 0,
-			    MAX_VALIDATE), "Expected zeroed memory");
+			assert_false(validate_fill(
+			    (void *)((uintptr_t)q+sz-MAX_VALIDATE),
+			    0, 0, MAX_VALIDATE), "Expected zeroed memory");
 		}
 		p = q;
 	}
diff --git a/src/jemalloc/test/integration/thread_arena.c b/src/jemalloc/test/integration/thread_arena.c
index 67be5351335078baa5074f8bde0f553da29d093a..c43542dfd48ef474ad70e0518bf61e452d9cc7c7 100644
--- a/src/jemalloc/test/integration/thread_arena.c
+++ b/src/jemalloc/test/integration/thread_arena.c
@@ -16,7 +16,7 @@ thd_start(void *arg)
 	free(p);
 
 	size = sizeof(arena_ind);
-	if ((err = mallctl("thread.arena", &arena_ind, &size, &main_arena_ind,
+	if ((err = mallctl("thread.pool.0.arena", &arena_ind, &size, &main_arena_ind,
 	    sizeof(main_arena_ind)))) {
 		char buf[BUFERROR_BUF];
 
@@ -25,7 +25,7 @@ thd_start(void *arg)
 	}
 
 	size = sizeof(arena_ind);
-	if ((err = mallctl("thread.arena", &arena_ind, &size, NULL, 0))) {
+	if ((err = mallctl("thread.pool.0.arena", &arena_ind, &size, NULL, 0))) {
 		char buf[BUFERROR_BUF];
 
 		buferror(err, buf, sizeof(buf));
@@ -50,7 +50,7 @@ TEST_BEGIN(test_thread_arena)
 	assert_ptr_not_null(p, "Error in malloc()");
 
 	size = sizeof(arena_ind);
-	if ((err = mallctl("thread.arena", &arena_ind, &size, NULL, 0))) {
+	if ((err = mallctl("thread.pool.0.arena", &arena_ind, &size, NULL, 0))) {
 		char buf[BUFERROR_BUF];
 
 		buferror(err, buf, sizeof(buf));
diff --git a/src/jemalloc/test/src/SFMT.c b/src/jemalloc/test/src/SFMT.c
index e6f8deecb37808a83c2093ceb1d8e158af652592..22a5ac554b1cb2b663768a8ab5f9cdcf544a5c5a 100644
--- a/src/jemalloc/test/src/SFMT.c
+++ b/src/jemalloc/test/src/SFMT.c
@@ -511,7 +511,7 @@ uint64_t gen_rand64(sfmt_t *ctx) {
 uint64_t gen_rand64_range(sfmt_t *ctx, uint64_t limit) {
     uint64_t ret, above;
 
-    above = 0xffffffffffffffffLLU - (0xffffffffffffffffLLU  % limit);
+    above = KQU(0xffffffffffffffff) - (KQU(0xffffffffffffffff) % limit);
     while (1) {
         ret = gen_rand64(ctx);
         if (ret < above) {
diff --git a/src/jemalloc/test/src/mtx.c b/src/jemalloc/test/src/mtx.c
index 41b95d59de80fc4d080effd5417aad4a3d464646..73bd02f6df11c0436c6fa1a82d386f7ca1ae23ac 100644
--- a/src/jemalloc/test/src/mtx.c
+++ b/src/jemalloc/test/src/mtx.c
@@ -1,5 +1,9 @@
 #include "test/jemalloc_test.h"
 
+#ifndef _CRT_SPINCOUNT
+#define	_CRT_SPINCOUNT 4000
+#endif
+
 bool
 mtx_init(mtx_t *mtx)
 {
diff --git a/src/jemalloc/test/src/test.c b/src/jemalloc/test/src/test.c
index 528d858317a1dc3e794a2b39dfbffa7d5fe98d74..0dd2f69bd327e08f70d2ad8bede295141d4ab3bf 100644
--- a/src/jemalloc/test/src/test.c
+++ b/src/jemalloc/test/src/test.c
@@ -61,13 +61,52 @@ p_test_fini(void)
 }
 
 test_status_t
-p_test(test_t* t, ...)
+p_test(test_t *t, ...)
 {
-	test_status_t ret = test_status_pass;
+	test_status_t ret;
 	va_list ap;
 
+	/*
+	 * Make sure initialization occurs prior to running tests.  Tests are
+	 * special because they may use internal facilities prior to triggering
+	 * initialization as a side effect of calling into the public API.  This
+	 * is a final safety that works even if jemalloc_constructor() doesn't
+	 * run, as for MSVC builds.
+	 */
+	if (nallocx(1, 0) == 0) {
+		malloc_printf("Initialization error");
+		return (test_status_fail);
+	}
+
+	ret = test_status_pass;
+	va_start(ap, t);
+	for (; t != NULL; t = va_arg(ap, test_t *)) {
+		t();
+		if (test_status > ret)
+			ret = test_status;
+	}
+	va_end(ap);
+
+	malloc_printf("--- %s: %u/%u, %s: %u/%u, %s: %u/%u ---\n",
+	    test_status_string(test_status_pass),
+	    test_counts[test_status_pass], test_count,
+	    test_status_string(test_status_skip),
+	    test_counts[test_status_skip], test_count,
+	    test_status_string(test_status_fail),
+	    test_counts[test_status_fail], test_count);
+
+	return (ret);
+}
+
+test_status_t
+p_test_not_init(test_t *t, ...)
+{
+	test_status_t ret;
+	va_list ap;
+
+	ret = test_status_pass;
 	va_start(ap, t);
-	for (; t != NULL; t = va_arg(ap, test_t*)) {
+	for (; t != NULL; t = va_arg(ap, test_t *)) {
 		t();
 		if (test_status > ret)
 			ret = test_status;
diff --git a/src/jemalloc/test/src/thd.c b/src/jemalloc/test/src/thd.c
index 233242a161e246cb31173ca936bf265ab6a0bd9b..c9d0065869b3275b77d63ffd3f9afe3fc53b2adf 100644
--- a/src/jemalloc/test/src/thd.c
+++ b/src/jemalloc/test/src/thd.c
@@ -14,7 +14,11 @@ void
 thd_join(thd_t thd, void **ret)
 {
 
-	WaitForSingleObject(thd, INFINITE);
+	if (WaitForSingleObject(thd, INFINITE) == WAIT_OBJECT_0 && ret) {
+		DWORD exit_code;
+		GetExitCodeThread(thd, (LPDWORD) &exit_code);
+		*ret = (void *)(uintptr_t)exit_code;
+	}
 }
 
 #else
diff --git a/src/jemalloc/test/unit/SFMT.c b/src/jemalloc/test/unit/SFMT.c
index c57bd68df3d887a0bb95c65ecd5f9e6b0b945f16..88b31f6efdb8f70fd24a7d6ba736a66debb693e2 100644
--- a/src/jemalloc/test/unit/SFMT.c
+++ b/src/jemalloc/test/unit/SFMT.c
@@ -445,1008 +445,1008 @@ static const uint32_t init_by_array_32_expected[] = {
 	2750138839U, 3518055702U,  733072558U, 4169325400U,  788493625U
 };
 static const uint64_t init_gen_rand_64_expected[] = {
-	QU(16924766246869039260LLU), QU( 8201438687333352714LLU),
-	QU( 2265290287015001750LLU), QU(18397264611805473832LLU),
-	QU( 3375255223302384358LLU), QU( 6345559975416828796LLU),
-	QU(18229739242790328073LLU), QU( 7596792742098800905LLU),
-	QU(  255338647169685981LLU), QU( 2052747240048610300LLU),
-	QU(18328151576097299343LLU), QU(12472905421133796567LLU),
-	QU(11315245349717600863LLU), QU(16594110197775871209LLU),
-	QU(15708751964632456450LLU), QU(10452031272054632535LLU),
-	QU(11097646720811454386LLU), QU( 4556090668445745441LLU),
-	QU(17116187693090663106LLU), QU(14931526836144510645LLU),
-	QU( 9190752218020552591LLU), QU( 9625800285771901401LLU),
-	QU(13995141077659972832LLU), QU( 5194209094927829625LLU),
-	QU( 4156788379151063303LLU), QU( 8523452593770139494LLU),
-	QU(14082382103049296727LLU), QU( 2462601863986088483LLU),
-	QU( 3030583461592840678LLU), QU( 5221622077872827681LLU),
-	QU( 3084210671228981236LLU), QU(13956758381389953823LLU),
-	QU(13503889856213423831LLU), QU(15696904024189836170LLU),
-	QU( 4612584152877036206LLU), QU( 6231135538447867881LLU),
-	QU(10172457294158869468LLU), QU( 6452258628466708150LLU),
-	QU(14044432824917330221LLU), QU(  370168364480044279LLU),
-	QU(10102144686427193359LLU), QU(  667870489994776076LLU),
-	QU( 2732271956925885858LLU), QU(18027788905977284151LLU),
-	QU(15009842788582923859LLU), QU( 7136357960180199542LLU),
-	QU(15901736243475578127LLU), QU(16951293785352615701LLU),
-	QU(10551492125243691632LLU), QU(17668869969146434804LLU),
-	QU(13646002971174390445LLU), QU( 9804471050759613248LLU),
-	QU( 5511670439655935493LLU), QU(18103342091070400926LLU),
-	QU(17224512747665137533LLU), QU(15534627482992618168LLU),
-	QU( 1423813266186582647LLU), QU(15821176807932930024LLU),
-	QU(   30323369733607156LLU), QU(11599382494723479403LLU),
-	QU(  653856076586810062LLU), QU( 3176437395144899659LLU),
-	QU(14028076268147963917LLU), QU(16156398271809666195LLU),
-	QU( 3166955484848201676LLU), QU( 5746805620136919390LLU),
-	QU(17297845208891256593LLU), QU(11691653183226428483LLU),
-	QU(17900026146506981577LLU), QU(15387382115755971042LLU),
-	QU(16923567681040845943LLU), QU( 8039057517199388606LLU),
-	QU(11748409241468629263LLU), QU(  794358245539076095LLU),
-	QU(13438501964693401242LLU), QU(14036803236515618962LLU),
-	QU( 5252311215205424721LLU), QU(17806589612915509081LLU),
-	QU( 6802767092397596006LLU), QU(14212120431184557140LLU),
-	QU( 1072951366761385712LLU), QU(13098491780722836296LLU),
-	QU( 9466676828710797353LLU), QU(12673056849042830081LLU),
-	QU(12763726623645357580LLU), QU(16468961652999309493LLU),
-	QU(15305979875636438926LLU), QU(17444713151223449734LLU),
-	QU( 5692214267627883674LLU), QU(13049589139196151505LLU),
-	QU(  880115207831670745LLU), QU( 1776529075789695498LLU),
-	QU(16695225897801466485LLU), QU(10666901778795346845LLU),
-	QU( 6164389346722833869LLU), QU( 2863817793264300475LLU),
-	QU( 9464049921886304754LLU), QU( 3993566636740015468LLU),
-	QU( 9983749692528514136LLU), QU(16375286075057755211LLU),
-	QU(16042643417005440820LLU), QU(11445419662923489877LLU),
-	QU( 7999038846885158836LLU), QU( 6721913661721511535LLU),
-	QU( 5363052654139357320LLU), QU( 1817788761173584205LLU),
-	QU(13290974386445856444LLU), QU( 4650350818937984680LLU),
-	QU( 8219183528102484836LLU), QU( 1569862923500819899LLU),
-	QU( 4189359732136641860LLU), QU(14202822961683148583LLU),
-	QU( 4457498315309429058LLU), QU(13089067387019074834LLU),
-	QU(11075517153328927293LLU), QU(10277016248336668389LLU),
-	QU( 7070509725324401122LLU), QU(17808892017780289380LLU),
-	QU(13143367339909287349LLU), QU( 1377743745360085151LLU),
-	QU( 5749341807421286485LLU), QU(14832814616770931325LLU),
-	QU( 7688820635324359492LLU), QU(10960474011539770045LLU),
-	QU(   81970066653179790LLU), QU(12619476072607878022LLU),
-	QU( 4419566616271201744LLU), QU(15147917311750568503LLU),
-	QU( 5549739182852706345LLU), QU( 7308198397975204770LLU),
-	QU(13580425496671289278LLU), QU(17070764785210130301LLU),
-	QU( 8202832846285604405LLU), QU( 6873046287640887249LLU),
-	QU( 6927424434308206114LLU), QU( 6139014645937224874LLU),
-	QU(10290373645978487639LLU), QU(15904261291701523804LLU),
-	QU( 9628743442057826883LLU), QU(18383429096255546714LLU),
-	QU( 4977413265753686967LLU), QU( 7714317492425012869LLU),
-	QU( 9025232586309926193LLU), QU(14627338359776709107LLU),
-	QU(14759849896467790763LLU), QU(10931129435864423252LLU),
-	QU( 4588456988775014359LLU), QU(10699388531797056724LLU),
-	QU(  468652268869238792LLU), QU( 5755943035328078086LLU),
-	QU( 2102437379988580216LLU), QU( 9986312786506674028LLU),
-	QU( 2654207180040945604LLU), QU( 8726634790559960062LLU),
-	QU(  100497234871808137LLU), QU( 2800137176951425819LLU),
-	QU( 6076627612918553487LLU), QU( 5780186919186152796LLU),
-	QU( 8179183595769929098LLU), QU( 6009426283716221169LLU),
-	QU( 2796662551397449358LLU), QU( 1756961367041986764LLU),
-	QU( 6972897917355606205LLU), QU(14524774345368968243LLU),
-	QU( 2773529684745706940LLU), QU( 4853632376213075959LLU),
-	QU( 4198177923731358102LLU), QU( 8271224913084139776LLU),
-	QU( 2741753121611092226LLU), QU(16782366145996731181LLU),
-	QU(15426125238972640790LLU), QU(13595497100671260342LLU),
-	QU( 3173531022836259898LLU), QU( 6573264560319511662LLU),
-	QU(18041111951511157441LLU), QU( 2351433581833135952LLU),
-	QU( 3113255578908173487LLU), QU( 1739371330877858784LLU),
-	QU(16046126562789165480LLU), QU( 8072101652214192925LLU),
-	QU(15267091584090664910LLU), QU( 9309579200403648940LLU),
-	QU( 5218892439752408722LLU), QU(14492477246004337115LLU),
-	QU(17431037586679770619LLU), QU( 7385248135963250480LLU),
-	QU( 9580144956565560660LLU), QU( 4919546228040008720LLU),
-	QU(15261542469145035584LLU), QU(18233297270822253102LLU),
-	QU( 5453248417992302857LLU), QU( 9309519155931460285LLU),
-	QU(10342813012345291756LLU), QU(15676085186784762381LLU),
-	QU(15912092950691300645LLU), QU( 9371053121499003195LLU),
-	QU( 9897186478226866746LLU), QU(14061858287188196327LLU),
-	QU(  122575971620788119LLU), QU(12146750969116317754LLU),
-	QU( 4438317272813245201LLU), QU( 8332576791009527119LLU),
-	QU(13907785691786542057LLU), QU(10374194887283287467LLU),
-	QU( 2098798755649059566LLU), QU( 3416235197748288894LLU),
-	QU( 8688269957320773484LLU), QU( 7503964602397371571LLU),
-	QU(16724977015147478236LLU), QU( 9461512855439858184LLU),
-	QU(13259049744534534727LLU), QU( 3583094952542899294LLU),
-	QU( 8764245731305528292LLU), QU(13240823595462088985LLU),
-	QU(13716141617617910448LLU), QU(18114969519935960955LLU),
-	QU( 2297553615798302206LLU), QU( 4585521442944663362LLU),
-	QU(17776858680630198686LLU), QU( 4685873229192163363LLU),
-	QU(  152558080671135627LLU), QU(15424900540842670088LLU),
-	QU(13229630297130024108LLU), QU(17530268788245718717LLU),
-	QU(16675633913065714144LLU), QU( 3158912717897568068LLU),
-	QU(15399132185380087288LLU), QU( 7401418744515677872LLU),
-	QU(13135412922344398535LLU), QU( 6385314346100509511LLU),
-	QU(13962867001134161139LLU), QU(10272780155442671999LLU),
-	QU(12894856086597769142LLU), QU(13340877795287554994LLU),
-	QU(12913630602094607396LLU), QU(12543167911119793857LLU),
-	QU(17343570372251873096LLU), QU(10959487764494150545LLU),
-	QU( 6966737953093821128LLU), QU(13780699135496988601LLU),
-	QU( 4405070719380142046LLU), QU(14923788365607284982LLU),
-	QU( 2869487678905148380LLU), QU( 6416272754197188403LLU),
-	QU(15017380475943612591LLU), QU( 1995636220918429487LLU),
-	QU( 3402016804620122716LLU), QU(15800188663407057080LLU),
-	QU(11362369990390932882LLU), QU(15262183501637986147LLU),
-	QU(10239175385387371494LLU), QU( 9352042420365748334LLU),
-	QU( 1682457034285119875LLU), QU( 1724710651376289644LLU),
-	QU( 2038157098893817966LLU), QU( 9897825558324608773LLU),
-	QU( 1477666236519164736LLU), QU(16835397314511233640LLU),
-	QU(10370866327005346508LLU), QU(10157504370660621982LLU),
-	QU(12113904045335882069LLU), QU(13326444439742783008LLU),
-	QU(11302769043000765804LLU), QU(13594979923955228484LLU),
-	QU(11779351762613475968LLU), QU( 3786101619539298383LLU),
-	QU( 8021122969180846063LLU), QU(15745904401162500495LLU),
-	QU(10762168465993897267LLU), QU(13552058957896319026LLU),
-	QU(11200228655252462013LLU), QU( 5035370357337441226LLU),
-	QU( 7593918984545500013LLU), QU( 5418554918361528700LLU),
-	QU( 4858270799405446371LLU), QU( 9974659566876282544LLU),
-	QU(18227595922273957859LLU), QU( 2772778443635656220LLU),
-	QU(14285143053182085385LLU), QU( 9939700992429600469LLU),
-	QU(12756185904545598068LLU), QU( 2020783375367345262LLU),
-	QU(   57026775058331227LLU), QU(  950827867930065454LLU),
-	QU( 6602279670145371217LLU), QU( 2291171535443566929LLU),
-	QU( 5832380724425010313LLU), QU( 1220343904715982285LLU),
-	QU(17045542598598037633LLU), QU(15460481779702820971LLU),
-	QU(13948388779949365130LLU), QU(13975040175430829518LLU),
-	QU(17477538238425541763LLU), QU(11104663041851745725LLU),
-	QU(15860992957141157587LLU), QU(14529434633012950138LLU),
-	QU( 2504838019075394203LLU), QU( 7512113882611121886LLU),
-	QU( 4859973559980886617LLU), QU( 1258601555703250219LLU),
-	QU(15594548157514316394LLU), QU( 4516730171963773048LLU),
-	QU(11380103193905031983LLU), QU( 6809282239982353344LLU),
-	QU(18045256930420065002LLU), QU( 2453702683108791859LLU),
-	QU(  977214582986981460LLU), QU( 2006410402232713466LLU),
-	QU( 6192236267216378358LLU), QU( 3429468402195675253LLU),
-	QU(18146933153017348921LLU), QU(17369978576367231139LLU),
-	QU( 1246940717230386603LLU), QU(11335758870083327110LLU),
-	QU(14166488801730353682LLU), QU( 9008573127269635732LLU),
-	QU(10776025389820643815LLU), QU(15087605441903942962LLU),
-	QU( 1359542462712147922LLU), QU(13898874411226454206LLU),
-	QU(17911176066536804411LLU), QU( 9435590428600085274LLU),
-	QU(  294488509967864007LLU), QU( 8890111397567922046LLU),
-	QU( 7987823476034328778LLU), QU(13263827582440967651LLU),
-	QU( 7503774813106751573LLU), QU(14974747296185646837LLU),
-	QU( 8504765037032103375LLU), QU(17340303357444536213LLU),
-	QU( 7704610912964485743LLU), QU( 8107533670327205061LLU),
-	QU( 9062969835083315985LLU), QU(16968963142126734184LLU),
-	QU(12958041214190810180LLU), QU( 2720170147759570200LLU),
-	QU( 2986358963942189566LLU), QU(14884226322219356580LLU),
-	QU(  286224325144368520LLU), QU(11313800433154279797LLU),
-	QU(18366849528439673248LLU), QU(17899725929482368789LLU),
-	QU( 3730004284609106799LLU), QU( 1654474302052767205LLU),
-	QU( 5006698007047077032LLU), QU( 8196893913601182838LLU),
-	QU(15214541774425211640LLU), QU(17391346045606626073LLU),
-	QU( 8369003584076969089LLU), QU( 3939046733368550293LLU),
-	QU(10178639720308707785LLU), QU( 2180248669304388697LLU),
-	QU(   62894391300126322LLU), QU( 9205708961736223191LLU),
-	QU( 6837431058165360438LLU), QU( 3150743890848308214LLU),
-	QU(17849330658111464583LLU), QU(12214815643135450865LLU),
-	QU(13410713840519603402LLU), QU( 3200778126692046802LLU),
-	QU(13354780043041779313LLU), QU(  800850022756886036LLU),
-	QU(15660052933953067433LLU), QU( 6572823544154375676LLU),
-	QU(11030281857015819266LLU), QU(12682241941471433835LLU),
-	QU(11654136407300274693LLU), QU( 4517795492388641109LLU),
-	QU( 9757017371504524244LLU), QU(17833043400781889277LLU),
-	QU(12685085201747792227LLU), QU(10408057728835019573LLU),
-	QU(   98370418513455221LLU), QU( 6732663555696848598LLU),
-	QU(13248530959948529780LLU), QU( 3530441401230622826LLU),
-	QU(18188251992895660615LLU), QU( 1847918354186383756LLU),
-	QU( 1127392190402660921LLU), QU(11293734643143819463LLU),
-	QU( 3015506344578682982LLU), QU(13852645444071153329LLU),
-	QU( 2121359659091349142LLU), QU( 1294604376116677694LLU),
-	QU( 5616576231286352318LLU), QU( 7112502442954235625LLU),
-	QU(11676228199551561689LLU), QU(12925182803007305359LLU),
-	QU( 7852375518160493082LLU), QU( 1136513130539296154LLU),
-	QU( 5636923900916593195LLU), QU( 3221077517612607747LLU),
-	QU(17784790465798152513LLU), QU( 3554210049056995938LLU),
-	QU(17476839685878225874LLU), QU( 3206836372585575732LLU),
-	QU( 2765333945644823430LLU), QU(10080070903718799528LLU),
-	QU( 5412370818878286353LLU), QU( 9689685887726257728LLU),
-	QU( 8236117509123533998LLU), QU( 1951139137165040214LLU),
-	QU( 4492205209227980349LLU), QU(16541291230861602967LLU),
-	QU( 1424371548301437940LLU), QU( 9117562079669206794LLU),
-	QU(14374681563251691625LLU), QU(13873164030199921303LLU),
-	QU( 6680317946770936731LLU), QU(15586334026918276214LLU),
-	QU(10896213950976109802LLU), QU( 9506261949596413689LLU),
-	QU( 9903949574308040616LLU), QU( 6038397344557204470LLU),
-	QU(  174601465422373648LLU), QU(15946141191338238030LLU),
-	QU(17142225620992044937LLU), QU( 7552030283784477064LLU),
-	QU( 2947372384532947997LLU), QU(  510797021688197711LLU),
-	QU( 4962499439249363461LLU), QU(   23770320158385357LLU),
-	QU(  959774499105138124LLU), QU( 1468396011518788276LLU),
-	QU( 2015698006852312308LLU), QU( 4149400718489980136LLU),
-	QU( 5992916099522371188LLU), QU(10819182935265531076LLU),
-	QU(16189787999192351131LLU), QU(  342833961790261950LLU),
-	QU(12470830319550495336LLU), QU(18128495041912812501LLU),
-	QU( 1193600899723524337LLU), QU( 9056793666590079770LLU),
-	QU( 2154021227041669041LLU), QU( 4963570213951235735LLU),
-	QU( 4865075960209211409LLU), QU( 2097724599039942963LLU),
-	QU( 2024080278583179845LLU), QU(11527054549196576736LLU),
-	QU(10650256084182390252LLU), QU( 4808408648695766755LLU),
-	QU( 1642839215013788844LLU), QU(10607187948250398390LLU),
-	QU( 7076868166085913508LLU), QU(  730522571106887032LLU),
-	QU(12500579240208524895LLU), QU( 4484390097311355324LLU),
-	QU(15145801330700623870LLU), QU( 8055827661392944028LLU),
-	QU( 5865092976832712268LLU), QU(15159212508053625143LLU),
-	QU( 3560964582876483341LLU), QU( 4070052741344438280LLU),
-	QU( 6032585709886855634LLU), QU(15643262320904604873LLU),
-	QU( 2565119772293371111LLU), QU(  318314293065348260LLU),
-	QU(15047458749141511872LLU), QU( 7772788389811528730LLU),
-	QU( 7081187494343801976LLU), QU( 6465136009467253947LLU),
-	QU(10425940692543362069LLU), QU(  554608190318339115LLU),
-	QU(14796699860302125214LLU), QU( 1638153134431111443LLU),
-	QU(10336967447052276248LLU), QU( 8412308070396592958LLU),
-	QU( 4004557277152051226LLU), QU( 8143598997278774834LLU),
-	QU(16413323996508783221LLU), QU(13139418758033994949LLU),
-	QU( 9772709138335006667LLU), QU( 2818167159287157659LLU),
-	QU(17091740573832523669LLU), QU(14629199013130751608LLU),
-	QU(18268322711500338185LLU), QU( 8290963415675493063LLU),
-	QU( 8830864907452542588LLU), QU( 1614839084637494849LLU),
-	QU(14855358500870422231LLU), QU( 3472996748392519937LLU),
-	QU(15317151166268877716LLU), QU( 5825895018698400362LLU),
-	QU(16730208429367544129LLU), QU(10481156578141202800LLU),
-	QU( 4746166512382823750LLU), QU(12720876014472464998LLU),
-	QU( 8825177124486735972LLU), QU(13733447296837467838LLU),
-	QU( 6412293741681359625LLU), QU( 8313213138756135033LLU),
-	QU(11421481194803712517LLU), QU( 7997007691544174032LLU),
-	QU( 6812963847917605930LLU), QU( 9683091901227558641LLU),
-	QU(14703594165860324713LLU), QU( 1775476144519618309LLU),
-	QU( 2724283288516469519LLU), QU(  717642555185856868LLU),
-	QU( 8736402192215092346LLU), QU(11878800336431381021LLU),
-	QU( 4348816066017061293LLU), QU( 6115112756583631307LLU),
-	QU( 9176597239667142976LLU), QU(12615622714894259204LLU),
-	QU(10283406711301385987LLU), QU( 5111762509485379420LLU),
-	QU( 3118290051198688449LLU), QU( 7345123071632232145LLU),
-	QU( 9176423451688682359LLU), QU( 4843865456157868971LLU),
-	QU(12008036363752566088LLU), QU(12058837181919397720LLU),
-	QU( 2145073958457347366LLU), QU( 1526504881672818067LLU),
-	QU( 3488830105567134848LLU), QU(13208362960674805143LLU),
-	QU( 4077549672899572192LLU), QU( 7770995684693818365LLU),
-	QU( 1398532341546313593LLU), QU(12711859908703927840LLU),
-	QU( 1417561172594446813LLU), QU(17045191024194170604LLU),
-	QU( 4101933177604931713LLU), QU(14708428834203480320LLU),
-	QU(17447509264469407724LLU), QU(14314821973983434255LLU),
-	QU(17990472271061617265LLU), QU( 5087756685841673942LLU),
-	QU(12797820586893859939LLU), QU( 1778128952671092879LLU),
-	QU( 3535918530508665898LLU), QU( 9035729701042481301LLU),
-	QU(14808661568277079962LLU), QU(14587345077537747914LLU),
-	QU(11920080002323122708LLU), QU( 6426515805197278753LLU),
-	QU( 3295612216725984831LLU), QU(11040722532100876120LLU),
-	QU(12305952936387598754LLU), QU(16097391899742004253LLU),
-	QU( 4908537335606182208LLU), QU(12446674552196795504LLU),
-	QU(16010497855816895177LLU), QU( 9194378874788615551LLU),
-	QU( 3382957529567613384LLU), QU( 5154647600754974077LLU),
-	QU( 9801822865328396141LLU), QU( 9023662173919288143LLU),
-	QU(17623115353825147868LLU), QU( 8238115767443015816LLU),
-	QU(15811444159859002560LLU), QU( 9085612528904059661LLU),
-	QU( 6888601089398614254LLU), QU(  258252992894160189LLU),
-	QU( 6704363880792428622LLU), QU( 6114966032147235763LLU),
-	QU(11075393882690261875LLU), QU( 8797664238933620407LLU),
-	QU( 5901892006476726920LLU), QU( 5309780159285518958LLU),
-	QU(14940808387240817367LLU), QU(14642032021449656698LLU),
-	QU( 9808256672068504139LLU), QU( 3670135111380607658LLU),
-	QU(11211211097845960152LLU), QU( 1474304506716695808LLU),
-	QU(15843166204506876239LLU), QU( 7661051252471780561LLU),
-	QU(10170905502249418476LLU), QU( 7801416045582028589LLU),
-	QU( 2763981484737053050LLU), QU( 9491377905499253054LLU),
-	QU(16201395896336915095LLU), QU( 9256513756442782198LLU),
-	QU( 5411283157972456034LLU), QU( 5059433122288321676LLU),
-	QU( 4327408006721123357LLU), QU( 9278544078834433377LLU),
-	QU( 7601527110882281612LLU), QU(11848295896975505251LLU),
-	QU(12096998801094735560LLU), QU(14773480339823506413LLU),
-	QU(15586227433895802149LLU), QU(12786541257830242872LLU),
-	QU( 6904692985140503067LLU), QU( 5309011515263103959LLU),
-	QU(12105257191179371066LLU), QU(14654380212442225037LLU),
-	QU( 2556774974190695009LLU), QU( 4461297399927600261LLU),
-	QU(14888225660915118646LLU), QU(14915459341148291824LLU),
-	QU( 2738802166252327631LLU), QU( 6047155789239131512LLU),
-	QU(12920545353217010338LLU), QU(10697617257007840205LLU),
-	QU( 2751585253158203504LLU), QU(13252729159780047496LLU),
-	QU(14700326134672815469LLU), QU(14082527904374600529LLU),
-	QU(16852962273496542070LLU), QU(17446675504235853907LLU),
-	QU(15019600398527572311LLU), QU(12312781346344081551LLU),
-	QU(14524667935039810450LLU), QU( 5634005663377195738LLU),
-	QU(11375574739525000569LLU), QU( 2423665396433260040LLU),
-	QU( 5222836914796015410LLU), QU( 4397666386492647387LLU),
-	QU( 4619294441691707638LLU), QU(  665088602354770716LLU),
-	QU(13246495665281593610LLU), QU( 6564144270549729409LLU),
-	QU(10223216188145661688LLU), QU( 3961556907299230585LLU),
-	QU(11543262515492439914LLU), QU(16118031437285993790LLU),
-	QU( 7143417964520166465LLU), QU(13295053515909486772LLU),
-	QU(   40434666004899675LLU), QU(17127804194038347164LLU),
-	QU( 8599165966560586269LLU), QU( 8214016749011284903LLU),
-	QU(13725130352140465239LLU), QU( 5467254474431726291LLU),
-	QU( 7748584297438219877LLU), QU(16933551114829772472LLU),
-	QU( 2169618439506799400LLU), QU( 2169787627665113463LLU),
-	QU(17314493571267943764LLU), QU(18053575102911354912LLU),
-	QU(11928303275378476973LLU), QU(11593850925061715550LLU),
-	QU(17782269923473589362LLU), QU( 3280235307704747039LLU),
-	QU( 6145343578598685149LLU), QU(17080117031114086090LLU),
-	QU(18066839902983594755LLU), QU( 6517508430331020706LLU),
-	QU( 8092908893950411541LLU), QU(12558378233386153732LLU),
-	QU( 4476532167973132976LLU), QU(16081642430367025016LLU),
-	QU( 4233154094369139361LLU), QU( 8693630486693161027LLU),
-	QU(11244959343027742285LLU), QU(12273503967768513508LLU),
-	QU(14108978636385284876LLU), QU( 7242414665378826984LLU),
-	QU( 6561316938846562432LLU), QU( 8601038474994665795LLU),
-	QU(17532942353612365904LLU), QU(17940076637020912186LLU),
-	QU( 7340260368823171304LLU), QU( 7061807613916067905LLU),
-	QU(10561734935039519326LLU), QU(17990796503724650862LLU),
-	QU( 6208732943911827159LLU), QU(  359077562804090617LLU),
-	QU(14177751537784403113LLU), QU(10659599444915362902LLU),
-	QU(15081727220615085833LLU), QU(13417573895659757486LLU),
-	QU(15513842342017811524LLU), QU(11814141516204288231LLU),
-	QU( 1827312513875101814LLU), QU( 2804611699894603103LLU),
-	QU(17116500469975602763LLU), QU(12270191815211952087LLU),
-	QU(12256358467786024988LLU), QU(18435021722453971267LLU),
-	QU(  671330264390865618LLU), QU(  476504300460286050LLU),
-	QU(16465470901027093441LLU), QU( 4047724406247136402LLU),
-	QU( 1322305451411883346LLU), QU( 1388308688834322280LLU),
-	QU( 7303989085269758176LLU), QU( 9323792664765233642LLU),
-	QU( 4542762575316368936LLU), QU(17342696132794337618LLU),
-	QU( 4588025054768498379LLU), QU(13415475057390330804LLU),
-	QU(17880279491733405570LLU), QU(10610553400618620353LLU),
-	QU( 3180842072658960139LLU), QU(13002966655454270120LLU),
-	QU( 1665301181064982826LLU), QU( 7083673946791258979LLU),
-	QU(  190522247122496820LLU), QU(17388280237250677740LLU),
-	QU( 8430770379923642945LLU), QU(12987180971921668584LLU),
-	QU( 2311086108365390642LLU), QU( 2870984383579822345LLU),
-	QU(14014682609164653318LLU), QU(14467187293062251484LLU),
-	QU(  192186361147413298LLU), QU(15171951713531796524LLU),
-	QU( 9900305495015948728LLU), QU(17958004775615466344LLU),
-	QU(14346380954498606514LLU), QU(18040047357617407096LLU),
-	QU( 5035237584833424532LLU), QU(15089555460613972287LLU),
-	QU( 4131411873749729831LLU), QU( 1329013581168250330LLU),
-	QU(10095353333051193949LLU), QU(10749518561022462716LLU),
-	QU( 9050611429810755847LLU), QU(15022028840236655649LLU),
-	QU( 8775554279239748298LLU), QU(13105754025489230502LLU),
-	QU(15471300118574167585LLU), QU(   89864764002355628LLU),
-	QU( 8776416323420466637LLU), QU( 5280258630612040891LLU),
-	QU( 2719174488591862912LLU), QU( 7599309137399661994LLU),
-	QU(15012887256778039979LLU), QU(14062981725630928925LLU),
-	QU(12038536286991689603LLU), QU( 7089756544681775245LLU),
-	QU(10376661532744718039LLU), QU( 1265198725901533130LLU),
-	QU(13807996727081142408LLU), QU( 2935019626765036403LLU),
-	QU( 7651672460680700141LLU), QU( 3644093016200370795LLU),
-	QU( 2840982578090080674LLU), QU(17956262740157449201LLU),
-	QU(18267979450492880548LLU), QU(11799503659796848070LLU),
-	QU( 9942537025669672388LLU), QU(11886606816406990297LLU),
-	QU( 5488594946437447576LLU), QU( 7226714353282744302LLU),
-	QU( 3784851653123877043LLU), QU(  878018453244803041LLU),
-	QU(12110022586268616085LLU), QU(  734072179404675123LLU),
-	QU(11869573627998248542LLU), QU(  469150421297783998LLU),
-	QU(  260151124912803804LLU), QU(11639179410120968649LLU),
-	QU( 9318165193840846253LLU), QU(12795671722734758075LLU),
-	QU(15318410297267253933LLU), QU(  691524703570062620LLU),
-	QU( 5837129010576994601LLU), QU(15045963859726941052LLU),
-	QU( 5850056944932238169LLU), QU(12017434144750943807LLU),
-	QU( 7447139064928956574LLU), QU( 3101711812658245019LLU),
-	QU(16052940704474982954LLU), QU(18195745945986994042LLU),
-	QU( 8932252132785575659LLU), QU(13390817488106794834LLU),
-	QU(11582771836502517453LLU), QU( 4964411326683611686LLU),
-	QU( 2195093981702694011LLU), QU(14145229538389675669LLU),
-	QU(16459605532062271798LLU), QU(  866316924816482864LLU),
-	QU( 4593041209937286377LLU), QU( 8415491391910972138LLU),
-	QU( 4171236715600528969LLU), QU(16637569303336782889LLU),
-	QU( 2002011073439212680LLU), QU(17695124661097601411LLU),
-	QU( 4627687053598611702LLU), QU( 7895831936020190403LLU),
-	QU( 8455951300917267802LLU), QU( 2923861649108534854LLU),
-	QU( 8344557563927786255LLU), QU( 6408671940373352556LLU),
-	QU(12210227354536675772LLU), QU(14294804157294222295LLU),
-	QU(10103022425071085127LLU), QU(10092959489504123771LLU),
-	QU( 6554774405376736268LLU), QU(12629917718410641774LLU),
-	QU( 6260933257596067126LLU), QU( 2460827021439369673LLU),
-	QU( 2541962996717103668LLU), QU(  597377203127351475LLU),
-	QU( 5316984203117315309LLU), QU( 4811211393563241961LLU),
-	QU(13119698597255811641LLU), QU( 8048691512862388981LLU),
-	QU(10216818971194073842LLU), QU( 4612229970165291764LLU),
-	QU(10000980798419974770LLU), QU( 6877640812402540687LLU),
-	QU( 1488727563290436992LLU), QU( 2227774069895697318LLU),
-	QU(11237754507523316593LLU), QU(13478948605382290972LLU),
-	QU( 1963583846976858124LLU), QU( 5512309205269276457LLU),
-	QU( 3972770164717652347LLU), QU( 3841751276198975037LLU),
-	QU(10283343042181903117LLU), QU( 8564001259792872199LLU),
-	QU(16472187244722489221LLU), QU( 8953493499268945921LLU),
-	QU( 3518747340357279580LLU), QU( 4003157546223963073LLU),
-	QU( 3270305958289814590LLU), QU( 3966704458129482496LLU),
-	QU( 8122141865926661939LLU), QU(14627734748099506653LLU),
-	QU(13064426990862560568LLU), QU( 2414079187889870829LLU),
-	QU( 5378461209354225306LLU), QU(10841985740128255566LLU),
-	QU(  538582442885401738LLU), QU( 7535089183482905946LLU),
-	QU(16117559957598879095LLU), QU( 8477890721414539741LLU),
-	QU( 1459127491209533386LLU), QU(17035126360733620462LLU),
-	QU( 8517668552872379126LLU), QU(10292151468337355014LLU),
-	QU(17081267732745344157LLU), QU(13751455337946087178LLU),
-	QU(14026945459523832966LLU), QU( 6653278775061723516LLU),
-	QU(10619085543856390441LLU), QU( 2196343631481122885LLU),
-	QU(10045966074702826136LLU), QU(10082317330452718282LLU),
-	QU( 5920859259504831242LLU), QU( 9951879073426540617LLU),
-	QU( 7074696649151414158LLU), QU(15808193543879464318LLU),
-	QU( 7385247772746953374LLU), QU( 3192003544283864292LLU),
-	QU(18153684490917593847LLU), QU(12423498260668568905LLU),
-	QU(10957758099756378169LLU), QU(11488762179911016040LLU),
-	QU( 2099931186465333782LLU), QU(11180979581250294432LLU),
-	QU( 8098916250668367933LLU), QU( 3529200436790763465LLU),
-	QU(12988418908674681745LLU), QU( 6147567275954808580LLU),
-	QU( 3207503344604030989LLU), QU(10761592604898615360LLU),
-	QU(  229854861031893504LLU), QU( 8809853962667144291LLU),
-	QU(13957364469005693860LLU), QU( 7634287665224495886LLU),
-	QU(12353487366976556874LLU), QU( 1134423796317152034LLU),
-	QU( 2088992471334107068LLU), QU( 7393372127190799698LLU),
-	QU( 1845367839871058391LLU), QU(  207922563987322884LLU),
-	QU(11960870813159944976LLU), QU(12182120053317317363LLU),
-	QU(17307358132571709283LLU), QU(13871081155552824936LLU),
-	QU(18304446751741566262LLU), QU( 7178705220184302849LLU),
-	QU(10929605677758824425LLU), QU(16446976977835806844LLU),
-	QU(13723874412159769044LLU), QU( 6942854352100915216LLU),
-	QU( 1726308474365729390LLU), QU( 2150078766445323155LLU),
-	QU(15345558947919656626LLU), QU(12145453828874527201LLU),
-	QU( 2054448620739726849LLU), QU( 2740102003352628137LLU),
-	QU(11294462163577610655LLU), QU(  756164283387413743LLU),
-	QU(17841144758438810880LLU), QU(10802406021185415861LLU),
-	QU( 8716455530476737846LLU), QU( 6321788834517649606LLU),
-	QU(14681322910577468426LLU), QU(17330043563884336387LLU),
-	QU(12701802180050071614LLU), QU(14695105111079727151LLU),
-	QU( 5112098511654172830LLU), QU( 4957505496794139973LLU),
-	QU( 8270979451952045982LLU), QU(12307685939199120969LLU),
-	QU(12425799408953443032LLU), QU( 8376410143634796588LLU),
-	QU(16621778679680060464LLU), QU( 3580497854566660073LLU),
-	QU( 1122515747803382416LLU), QU(  857664980960597599LLU),
-	QU( 6343640119895925918LLU), QU(12878473260854462891LLU),
-	QU(10036813920765722626LLU), QU(14451335468363173812LLU),
-	QU( 5476809692401102807LLU), QU(16442255173514366342LLU),
-	QU(13060203194757167104LLU), QU(14354124071243177715LLU),
-	QU(15961249405696125227LLU), QU(13703893649690872584LLU),
-	QU(  363907326340340064LLU), QU( 6247455540491754842LLU),
-	QU(12242249332757832361LLU), QU(  156065475679796717LLU),
-	QU( 9351116235749732355LLU), QU( 4590350628677701405LLU),
-	QU( 1671195940982350389LLU), QU(13501398458898451905LLU),
-	QU( 6526341991225002255LLU), QU( 1689782913778157592LLU),
-	QU( 7439222350869010334LLU), QU(13975150263226478308LLU),
-	QU(11411961169932682710LLU), QU(17204271834833847277LLU),
-	QU(  541534742544435367LLU), QU( 6591191931218949684LLU),
-	QU( 2645454775478232486LLU), QU( 4322857481256485321LLU),
-	QU( 8477416487553065110LLU), QU(12902505428548435048LLU),
-	QU(  971445777981341415LLU), QU(14995104682744976712LLU),
-	QU( 4243341648807158063LLU), QU( 8695061252721927661LLU),
-	QU( 5028202003270177222LLU), QU( 2289257340915567840LLU),
-	QU(13870416345121866007LLU), QU(13994481698072092233LLU),
-	QU( 6912785400753196481LLU), QU( 2278309315841980139LLU),
-	QU( 4329765449648304839LLU), QU( 5963108095785485298LLU),
-	QU( 4880024847478722478LLU), QU(16015608779890240947LLU),
-	QU( 1866679034261393544LLU), QU(  914821179919731519LLU),
-	QU( 9643404035648760131LLU), QU( 2418114953615593915LLU),
-	QU(  944756836073702374LLU), QU(15186388048737296834LLU),
-	QU( 7723355336128442206LLU), QU( 7500747479679599691LLU),
-	QU(18013961306453293634LLU), QU( 2315274808095756456LLU),
-	QU(13655308255424029566LLU), QU(17203800273561677098LLU),
-	QU( 1382158694422087756LLU), QU( 5090390250309588976LLU),
-	QU(  517170818384213989LLU), QU( 1612709252627729621LLU),
-	QU( 1330118955572449606LLU), QU(  300922478056709885LLU),
-	QU(18115693291289091987LLU), QU(13491407109725238321LLU),
-	QU(15293714633593827320LLU), QU( 5151539373053314504LLU),
-	QU( 5951523243743139207LLU), QU(14459112015249527975LLU),
-	QU( 5456113959000700739LLU), QU( 3877918438464873016LLU),
-	QU(12534071654260163555LLU), QU(15871678376893555041LLU),
-	QU(11005484805712025549LLU), QU(16353066973143374252LLU),
-	QU( 4358331472063256685LLU), QU( 8268349332210859288LLU),
-	QU(12485161590939658075LLU), QU(13955993592854471343LLU),
-	QU( 5911446886848367039LLU), QU(14925834086813706974LLU),
-	QU( 6590362597857994805LLU), QU( 1280544923533661875LLU),
-	QU( 1637756018947988164LLU), QU( 4734090064512686329LLU),
-	QU(16693705263131485912LLU), QU( 6834882340494360958LLU),
-	QU( 8120732176159658505LLU), QU( 2244371958905329346LLU),
-	QU(10447499707729734021LLU), QU( 7318742361446942194LLU),
-	QU( 8032857516355555296LLU), QU(14023605983059313116LLU),
-	QU( 1032336061815461376LLU), QU( 9840995337876562612LLU),
-	QU( 9869256223029203587LLU), QU(12227975697177267636LLU),
-	QU(12728115115844186033LLU), QU( 7752058479783205470LLU),
-	QU(  729733219713393087LLU), QU(12954017801239007622LLU)
+	KQU(16924766246869039260), KQU( 8201438687333352714),
+	KQU( 2265290287015001750), KQU(18397264611805473832),
+	KQU( 3375255223302384358), KQU( 6345559975416828796),
+	KQU(18229739242790328073), KQU( 7596792742098800905),
+	KQU(  255338647169685981), KQU( 2052747240048610300),
+	KQU(18328151576097299343), KQU(12472905421133796567),
+	KQU(11315245349717600863), KQU(16594110197775871209),
+	KQU(15708751964632456450), KQU(10452031272054632535),
+	KQU(11097646720811454386), KQU( 4556090668445745441),
+	KQU(17116187693090663106), KQU(14931526836144510645),
+	KQU( 9190752218020552591), KQU( 9625800285771901401),
+	KQU(13995141077659972832), KQU( 5194209094927829625),
+	KQU( 4156788379151063303), KQU( 8523452593770139494),
+	KQU(14082382103049296727), KQU( 2462601863986088483),
+	KQU( 3030583461592840678), KQU( 5221622077872827681),
+	KQU( 3084210671228981236), KQU(13956758381389953823),
+	KQU(13503889856213423831), KQU(15696904024189836170),
+	KQU( 4612584152877036206), KQU( 6231135538447867881),
+	KQU(10172457294158869468), KQU( 6452258628466708150),
+	KQU(14044432824917330221), KQU(  370168364480044279),
+	KQU(10102144686427193359), KQU(  667870489994776076),
+	KQU( 2732271956925885858), KQU(18027788905977284151),
+	KQU(15009842788582923859), KQU( 7136357960180199542),
+	KQU(15901736243475578127), KQU(16951293785352615701),
+	KQU(10551492125243691632), KQU(17668869969146434804),
+	KQU(13646002971174390445), KQU( 9804471050759613248),
+	KQU( 5511670439655935493), KQU(18103342091070400926),
+	KQU(17224512747665137533), KQU(15534627482992618168),
+	KQU( 1423813266186582647), KQU(15821176807932930024),
+	KQU(   30323369733607156), KQU(11599382494723479403),
+	KQU(  653856076586810062), KQU( 3176437395144899659),
+	KQU(14028076268147963917), KQU(16156398271809666195),
+	KQU( 3166955484848201676), KQU( 5746805620136919390),
+	KQU(17297845208891256593), KQU(11691653183226428483),
+	KQU(17900026146506981577), KQU(15387382115755971042),
+	KQU(16923567681040845943), KQU( 8039057517199388606),
+	KQU(11748409241468629263), KQU(  794358245539076095),
+	KQU(13438501964693401242), KQU(14036803236515618962),
+	KQU( 5252311215205424721), KQU(17806589612915509081),
+	KQU( 6802767092397596006), KQU(14212120431184557140),
+	KQU( 1072951366761385712), KQU(13098491780722836296),
+	KQU( 9466676828710797353), KQU(12673056849042830081),
+	KQU(12763726623645357580), KQU(16468961652999309493),
+	KQU(15305979875636438926), KQU(17444713151223449734),
+	KQU( 5692214267627883674), KQU(13049589139196151505),
+	KQU(  880115207831670745), KQU( 1776529075789695498),
+	KQU(16695225897801466485), KQU(10666901778795346845),
+	KQU( 6164389346722833869), KQU( 2863817793264300475),
+	KQU( 9464049921886304754), KQU( 3993566636740015468),
+	KQU( 9983749692528514136), KQU(16375286075057755211),
+	KQU(16042643417005440820), KQU(11445419662923489877),
+	KQU( 7999038846885158836), KQU( 6721913661721511535),
+	KQU( 5363052654139357320), KQU( 1817788761173584205),
+	KQU(13290974386445856444), KQU( 4650350818937984680),
+	KQU( 8219183528102484836), KQU( 1569862923500819899),
+	KQU( 4189359732136641860), KQU(14202822961683148583),
+	KQU( 4457498315309429058), KQU(13089067387019074834),
+	KQU(11075517153328927293), KQU(10277016248336668389),
+	KQU( 7070509725324401122), KQU(17808892017780289380),
+	KQU(13143367339909287349), KQU( 1377743745360085151),
+	KQU( 5749341807421286485), KQU(14832814616770931325),
+	KQU( 7688820635324359492), KQU(10960474011539770045),
+	KQU(   81970066653179790), KQU(12619476072607878022),
+	KQU( 4419566616271201744), KQU(15147917311750568503),
+	KQU( 5549739182852706345), KQU( 7308198397975204770),
+	KQU(13580425496671289278), KQU(17070764785210130301),
+	KQU( 8202832846285604405), KQU( 6873046287640887249),
+	KQU( 6927424434308206114), KQU( 6139014645937224874),
+	KQU(10290373645978487639), KQU(15904261291701523804),
+	KQU( 9628743442057826883), KQU(18383429096255546714),
+	KQU( 4977413265753686967), KQU( 7714317492425012869),
+	KQU( 9025232586309926193), KQU(14627338359776709107),
+	KQU(14759849896467790763), KQU(10931129435864423252),
+	KQU( 4588456988775014359), KQU(10699388531797056724),
+	KQU(  468652268869238792), KQU( 5755943035328078086),
+	KQU( 2102437379988580216), KQU( 9986312786506674028),
+	KQU( 2654207180040945604), KQU( 8726634790559960062),
+	KQU(  100497234871808137), KQU( 2800137176951425819),
+	KQU( 6076627612918553487), KQU( 5780186919186152796),
+	KQU( 8179183595769929098), KQU( 6009426283716221169),
+	KQU( 2796662551397449358), KQU( 1756961367041986764),
+	KQU( 6972897917355606205), KQU(14524774345368968243),
+	KQU( 2773529684745706940), KQU( 4853632376213075959),
+	KQU( 4198177923731358102), KQU( 8271224913084139776),
+	KQU( 2741753121611092226), KQU(16782366145996731181),
+	KQU(15426125238972640790), KQU(13595497100671260342),
+	KQU( 3173531022836259898), KQU( 6573264560319511662),
+	KQU(18041111951511157441), KQU( 2351433581833135952),
+	KQU( 3113255578908173487), KQU( 1739371330877858784),
+	KQU(16046126562789165480), KQU( 8072101652214192925),
+	KQU(15267091584090664910), KQU( 9309579200403648940),
+	KQU( 5218892439752408722), KQU(14492477246004337115),
+	KQU(17431037586679770619), KQU( 7385248135963250480),
+	KQU( 9580144956565560660), KQU( 4919546228040008720),
+	KQU(15261542469145035584), KQU(18233297270822253102),
+	KQU( 5453248417992302857), KQU( 9309519155931460285),
+	KQU(10342813012345291756), KQU(15676085186784762381),
+	KQU(15912092950691300645), KQU( 9371053121499003195),
+	KQU( 9897186478226866746), KQU(14061858287188196327),
+	KQU(  122575971620788119), KQU(12146750969116317754),
+	KQU( 4438317272813245201), KQU( 8332576791009527119),
+	KQU(13907785691786542057), KQU(10374194887283287467),
+	KQU( 2098798755649059566), KQU( 3416235197748288894),
+	KQU( 8688269957320773484), KQU( 7503964602397371571),
+	KQU(16724977015147478236), KQU( 9461512855439858184),
+	KQU(13259049744534534727), KQU( 3583094952542899294),
+	KQU( 8764245731305528292), KQU(13240823595462088985),
+	KQU(13716141617617910448), KQU(18114969519935960955),
+	KQU( 2297553615798302206), KQU( 4585521442944663362),
+	KQU(17776858680630198686), KQU( 4685873229192163363),
+	KQU(  152558080671135627), KQU(15424900540842670088),
+	KQU(13229630297130024108), KQU(17530268788245718717),
+	KQU(16675633913065714144), KQU( 3158912717897568068),
+	KQU(15399132185380087288), KQU( 7401418744515677872),
+	KQU(13135412922344398535), KQU( 6385314346100509511),
+	KQU(13962867001134161139), KQU(10272780155442671999),
+	KQU(12894856086597769142), KQU(13340877795287554994),
+	KQU(12913630602094607396), KQU(12543167911119793857),
+	KQU(17343570372251873096), KQU(10959487764494150545),
+	KQU( 6966737953093821128), KQU(13780699135496988601),
+	KQU( 4405070719380142046), KQU(14923788365607284982),
+	KQU( 2869487678905148380), KQU( 6416272754197188403),
+	KQU(15017380475943612591), KQU( 1995636220918429487),
+	KQU( 3402016804620122716), KQU(15800188663407057080),
+	KQU(11362369990390932882), KQU(15262183501637986147),
+	KQU(10239175385387371494), KQU( 9352042420365748334),
+	KQU( 1682457034285119875), KQU( 1724710651376289644),
+	KQU( 2038157098893817966), KQU( 9897825558324608773),
+	KQU( 1477666236519164736), KQU(16835397314511233640),
+	KQU(10370866327005346508), KQU(10157504370660621982),
+	KQU(12113904045335882069), KQU(13326444439742783008),
+	KQU(11302769043000765804), KQU(13594979923955228484),
+	KQU(11779351762613475968), KQU( 3786101619539298383),
+	KQU( 8021122969180846063), KQU(15745904401162500495),
+	KQU(10762168465993897267), KQU(13552058957896319026),
+	KQU(11200228655252462013), KQU( 5035370357337441226),
+	KQU( 7593918984545500013), KQU( 5418554918361528700),
+	KQU( 4858270799405446371), KQU( 9974659566876282544),
+	KQU(18227595922273957859), KQU( 2772778443635656220),
+	KQU(14285143053182085385), KQU( 9939700992429600469),
+	KQU(12756185904545598068), KQU( 2020783375367345262),
+	KQU(   57026775058331227), KQU(  950827867930065454),
+	KQU( 6602279670145371217), KQU( 2291171535443566929),
+	KQU( 5832380724425010313), KQU( 1220343904715982285),
+	KQU(17045542598598037633), KQU(15460481779702820971),
+	KQU(13948388779949365130), KQU(13975040175430829518),
+	KQU(17477538238425541763), KQU(11104663041851745725),
+	KQU(15860992957141157587), KQU(14529434633012950138),
+	KQU( 2504838019075394203), KQU( 7512113882611121886),
+	KQU( 4859973559980886617), KQU( 1258601555703250219),
+	KQU(15594548157514316394), KQU( 4516730171963773048),
+	KQU(11380103193905031983), KQU( 6809282239982353344),
+	KQU(18045256930420065002), KQU( 2453702683108791859),
+	KQU(  977214582986981460), KQU( 2006410402232713466),
+	KQU( 6192236267216378358), KQU( 3429468402195675253),
+	KQU(18146933153017348921), KQU(17369978576367231139),
+	KQU( 1246940717230386603), KQU(11335758870083327110),
+	KQU(14166488801730353682), KQU( 9008573127269635732),
+	KQU(10776025389820643815), KQU(15087605441903942962),
+	KQU( 1359542462712147922), KQU(13898874411226454206),
+	KQU(17911176066536804411), KQU( 9435590428600085274),
+	KQU(  294488509967864007), KQU( 8890111397567922046),
+	KQU( 7987823476034328778), KQU(13263827582440967651),
+	KQU( 7503774813106751573), KQU(14974747296185646837),
+	KQU( 8504765037032103375), KQU(17340303357444536213),
+	KQU( 7704610912964485743), KQU( 8107533670327205061),
+	KQU( 9062969835083315985), KQU(16968963142126734184),
+	KQU(12958041214190810180), KQU( 2720170147759570200),
+	KQU( 2986358963942189566), KQU(14884226322219356580),
+	KQU(  286224325144368520), KQU(11313800433154279797),
+	KQU(18366849528439673248), KQU(17899725929482368789),
+	KQU( 3730004284609106799), KQU( 1654474302052767205),
+	KQU( 5006698007047077032), KQU( 8196893913601182838),
+	KQU(15214541774425211640), KQU(17391346045606626073),
+	KQU( 8369003584076969089), KQU( 3939046733368550293),
+	KQU(10178639720308707785), KQU( 2180248669304388697),
+	KQU(   62894391300126322), KQU( 9205708961736223191),
+	KQU( 6837431058165360438), KQU( 3150743890848308214),
+	KQU(17849330658111464583), KQU(12214815643135450865),
+	KQU(13410713840519603402), KQU( 3200778126692046802),
+	KQU(13354780043041779313), KQU(  800850022756886036),
+	KQU(15660052933953067433), KQU( 6572823544154375676),
+	KQU(11030281857015819266), KQU(12682241941471433835),
+	KQU(11654136407300274693), KQU( 4517795492388641109),
+	KQU( 9757017371504524244), KQU(17833043400781889277),
+	KQU(12685085201747792227), KQU(10408057728835019573),
+	KQU(   98370418513455221), KQU( 6732663555696848598),
+	KQU(13248530959948529780), KQU( 3530441401230622826),
+	KQU(18188251992895660615), KQU( 1847918354186383756),
+	KQU( 1127392190402660921), KQU(11293734643143819463),
+	KQU( 3015506344578682982), KQU(13852645444071153329),
+	KQU( 2121359659091349142), KQU( 1294604376116677694),
+	KQU( 5616576231286352318), KQU( 7112502442954235625),
+	KQU(11676228199551561689), KQU(12925182803007305359),
+	KQU( 7852375518160493082), KQU( 1136513130539296154),
+	KQU( 5636923900916593195), KQU( 3221077517612607747),
+	KQU(17784790465798152513), KQU( 3554210049056995938),
+	KQU(17476839685878225874), KQU( 3206836372585575732),
+	KQU( 2765333945644823430), KQU(10080070903718799528),
+	KQU( 5412370818878286353), KQU( 9689685887726257728),
+	KQU( 8236117509123533998), KQU( 1951139137165040214),
+	KQU( 4492205209227980349), KQU(16541291230861602967),
+	KQU( 1424371548301437940), KQU( 9117562079669206794),
+	KQU(14374681563251691625), KQU(13873164030199921303),
+	KQU( 6680317946770936731), KQU(15586334026918276214),
+	KQU(10896213950976109802), KQU( 9506261949596413689),
+	KQU( 9903949574308040616), KQU( 6038397344557204470),
+	KQU(  174601465422373648), KQU(15946141191338238030),
+	KQU(17142225620992044937), KQU( 7552030283784477064),
+	KQU( 2947372384532947997), KQU(  510797021688197711),
+	KQU( 4962499439249363461), KQU(   23770320158385357),
+	KQU(  959774499105138124), KQU( 1468396011518788276),
+	KQU( 2015698006852312308), KQU( 4149400718489980136),
+	KQU( 5992916099522371188), KQU(10819182935265531076),
+	KQU(16189787999192351131), KQU(  342833961790261950),
+	KQU(12470830319550495336), KQU(18128495041912812501),
+	KQU( 1193600899723524337), KQU( 9056793666590079770),
+	KQU( 2154021227041669041), KQU( 4963570213951235735),
+	KQU( 4865075960209211409), KQU( 2097724599039942963),
+	KQU( 2024080278583179845), KQU(11527054549196576736),
+	KQU(10650256084182390252), KQU( 4808408648695766755),
+	KQU( 1642839215013788844), KQU(10607187948250398390),
+	KQU( 7076868166085913508), KQU(  730522571106887032),
+	KQU(12500579240208524895), KQU( 4484390097311355324),
+	KQU(15145801330700623870), KQU( 8055827661392944028),
+	KQU( 5865092976832712268), KQU(15159212508053625143),
+	KQU( 3560964582876483341), KQU( 4070052741344438280),
+	KQU( 6032585709886855634), KQU(15643262320904604873),
+	KQU( 2565119772293371111), KQU(  318314293065348260),
+	KQU(15047458749141511872), KQU( 7772788389811528730),
+	KQU( 7081187494343801976), KQU( 6465136009467253947),
+	KQU(10425940692543362069), KQU(  554608190318339115),
+	KQU(14796699860302125214), KQU( 1638153134431111443),
+	KQU(10336967447052276248), KQU( 8412308070396592958),
+	KQU( 4004557277152051226), KQU( 8143598997278774834),
+	KQU(16413323996508783221), KQU(13139418758033994949),
+	KQU( 9772709138335006667), KQU( 2818167159287157659),
+	KQU(17091740573832523669), KQU(14629199013130751608),
+	KQU(18268322711500338185), KQU( 8290963415675493063),
+	KQU( 8830864907452542588), KQU( 1614839084637494849),
+	KQU(14855358500870422231), KQU( 3472996748392519937),
+	KQU(15317151166268877716), KQU( 5825895018698400362),
+	KQU(16730208429367544129), KQU(10481156578141202800),
+	KQU( 4746166512382823750), KQU(12720876014472464998),
+	KQU( 8825177124486735972), KQU(13733447296837467838),
+	KQU( 6412293741681359625), KQU( 8313213138756135033),
+	KQU(11421481194803712517), KQU( 7997007691544174032),
+	KQU( 6812963847917605930), KQU( 9683091901227558641),
+	KQU(14703594165860324713), KQU( 1775476144519618309),
+	KQU( 2724283288516469519), KQU(  717642555185856868),
+	KQU( 8736402192215092346), KQU(11878800336431381021),
+	KQU( 4348816066017061293), KQU( 6115112756583631307),
+	KQU( 9176597239667142976), KQU(12615622714894259204),
+	KQU(10283406711301385987), KQU( 5111762509485379420),
+	KQU( 3118290051198688449), KQU( 7345123071632232145),
+	KQU( 9176423451688682359), KQU( 4843865456157868971),
+	KQU(12008036363752566088), KQU(12058837181919397720),
+	KQU( 2145073958457347366), KQU( 1526504881672818067),
+	KQU( 3488830105567134848), KQU(13208362960674805143),
+	KQU( 4077549672899572192), KQU( 7770995684693818365),
+	KQU( 1398532341546313593), KQU(12711859908703927840),
+	KQU( 1417561172594446813), KQU(17045191024194170604),
+	KQU( 4101933177604931713), KQU(14708428834203480320),
+	KQU(17447509264469407724), KQU(14314821973983434255),
+	KQU(17990472271061617265), KQU( 5087756685841673942),
+	KQU(12797820586893859939), KQU( 1778128952671092879),
+	KQU( 3535918530508665898), KQU( 9035729701042481301),
+	KQU(14808661568277079962), KQU(14587345077537747914),
+	KQU(11920080002323122708), KQU( 6426515805197278753),
+	KQU( 3295612216725984831), KQU(11040722532100876120),
+	KQU(12305952936387598754), KQU(16097391899742004253),
+	KQU( 4908537335606182208), KQU(12446674552196795504),
+	KQU(16010497855816895177), KQU( 9194378874788615551),
+	KQU( 3382957529567613384), KQU( 5154647600754974077),
+	KQU( 9801822865328396141), KQU( 9023662173919288143),
+	KQU(17623115353825147868), KQU( 8238115767443015816),
+	KQU(15811444159859002560), KQU( 9085612528904059661),
+	KQU( 6888601089398614254), KQU(  258252992894160189),
+	KQU( 6704363880792428622), KQU( 6114966032147235763),
+	KQU(11075393882690261875), KQU( 8797664238933620407),
+	KQU( 5901892006476726920), KQU( 5309780159285518958),
+	KQU(14940808387240817367), KQU(14642032021449656698),
+	KQU( 9808256672068504139), KQU( 3670135111380607658),
+	KQU(11211211097845960152), KQU( 1474304506716695808),
+	KQU(15843166204506876239), KQU( 7661051252471780561),
+	KQU(10170905502249418476), KQU( 7801416045582028589),
+	KQU( 2763981484737053050), KQU( 9491377905499253054),
+	KQU(16201395896336915095), KQU( 9256513756442782198),
+	KQU( 5411283157972456034), KQU( 5059433122288321676),
+	KQU( 4327408006721123357), KQU( 9278544078834433377),
+	KQU( 7601527110882281612), KQU(11848295896975505251),
+	KQU(12096998801094735560), KQU(14773480339823506413),
+	KQU(15586227433895802149), KQU(12786541257830242872),
+	KQU( 6904692985140503067), KQU( 5309011515263103959),
+	KQU(12105257191179371066), KQU(14654380212442225037),
+	KQU( 2556774974190695009), KQU( 4461297399927600261),
+	KQU(14888225660915118646), KQU(14915459341148291824),
+	KQU( 2738802166252327631), KQU( 6047155789239131512),
+	KQU(12920545353217010338), KQU(10697617257007840205),
+	KQU( 2751585253158203504), KQU(13252729159780047496),
+	KQU(14700326134672815469), KQU(14082527904374600529),
+	KQU(16852962273496542070), KQU(17446675504235853907),
+	KQU(15019600398527572311), KQU(12312781346344081551),
+	KQU(14524667935039810450), KQU( 5634005663377195738),
+	KQU(11375574739525000569), KQU( 2423665396433260040),
+	KQU( 5222836914796015410), KQU( 4397666386492647387),
+	KQU( 4619294441691707638), KQU(  665088602354770716),
+	KQU(13246495665281593610), KQU( 6564144270549729409),
+	KQU(10223216188145661688), KQU( 3961556907299230585),
+	KQU(11543262515492439914), KQU(16118031437285993790),
+	KQU( 7143417964520166465), KQU(13295053515909486772),
+	KQU(   40434666004899675), KQU(17127804194038347164),
+	KQU( 8599165966560586269), KQU( 8214016749011284903),
+	KQU(13725130352140465239), KQU( 5467254474431726291),
+	KQU( 7748584297438219877), KQU(16933551114829772472),
+	KQU( 2169618439506799400), KQU( 2169787627665113463),
+	KQU(17314493571267943764), KQU(18053575102911354912),
+	KQU(11928303275378476973), KQU(11593850925061715550),
+	KQU(17782269923473589362), KQU( 3280235307704747039),
+	KQU( 6145343578598685149), KQU(17080117031114086090),
+	KQU(18066839902983594755), KQU( 6517508430331020706),
+	KQU( 8092908893950411541), KQU(12558378233386153732),
+	KQU( 4476532167973132976), KQU(16081642430367025016),
+	KQU( 4233154094369139361), KQU( 8693630486693161027),
+	KQU(11244959343027742285), KQU(12273503967768513508),
+	KQU(14108978636385284876), KQU( 7242414665378826984),
+	KQU( 6561316938846562432), KQU( 8601038474994665795),
+	KQU(17532942353612365904), KQU(17940076637020912186),
+	KQU( 7340260368823171304), KQU( 7061807613916067905),
+	KQU(10561734935039519326), KQU(17990796503724650862),
+	KQU( 6208732943911827159), KQU(  359077562804090617),
+	KQU(14177751537784403113), KQU(10659599444915362902),
+	KQU(15081727220615085833), KQU(13417573895659757486),
+	KQU(15513842342017811524), KQU(11814141516204288231),
+	KQU( 1827312513875101814), KQU( 2804611699894603103),
+	KQU(17116500469975602763), KQU(12270191815211952087),
+	KQU(12256358467786024988), KQU(18435021722453971267),
+	KQU(  671330264390865618), KQU(  476504300460286050),
+	KQU(16465470901027093441), KQU( 4047724406247136402),
+	KQU( 1322305451411883346), KQU( 1388308688834322280),
+	KQU( 7303989085269758176), KQU( 9323792664765233642),
+	KQU( 4542762575316368936), KQU(17342696132794337618),
+	KQU( 4588025054768498379), KQU(13415475057390330804),
+	KQU(17880279491733405570), KQU(10610553400618620353),
+	KQU( 3180842072658960139), KQU(13002966655454270120),
+	KQU( 1665301181064982826), KQU( 7083673946791258979),
+	KQU(  190522247122496820), KQU(17388280237250677740),
+	KQU( 8430770379923642945), KQU(12987180971921668584),
+	KQU( 2311086108365390642), KQU( 2870984383579822345),
+	KQU(14014682609164653318), KQU(14467187293062251484),
+	KQU(  192186361147413298), KQU(15171951713531796524),
+	KQU( 9900305495015948728), KQU(17958004775615466344),
+	KQU(14346380954498606514), KQU(18040047357617407096),
+	KQU( 5035237584833424532), KQU(15089555460613972287),
+	KQU( 4131411873749729831), KQU( 1329013581168250330),
+	KQU(10095353333051193949), KQU(10749518561022462716),
+	KQU( 9050611429810755847), KQU(15022028840236655649),
+	KQU( 8775554279239748298), KQU(13105754025489230502),
+	KQU(15471300118574167585), KQU(   89864764002355628),
+	KQU( 8776416323420466637), KQU( 5280258630612040891),
+	KQU( 2719174488591862912), KQU( 7599309137399661994),
+	KQU(15012887256778039979), KQU(14062981725630928925),
+	KQU(12038536286991689603), KQU( 7089756544681775245),
+	KQU(10376661532744718039), KQU( 1265198725901533130),
+	KQU(13807996727081142408), KQU( 2935019626765036403),
+	KQU( 7651672460680700141), KQU( 3644093016200370795),
+	KQU( 2840982578090080674), KQU(17956262740157449201),
+	KQU(18267979450492880548), KQU(11799503659796848070),
+	KQU( 9942537025669672388), KQU(11886606816406990297),
+	KQU( 5488594946437447576), KQU( 7226714353282744302),
+	KQU( 3784851653123877043), KQU(  878018453244803041),
+	KQU(12110022586268616085), KQU(  734072179404675123),
+	KQU(11869573627998248542), KQU(  469150421297783998),
+	KQU(  260151124912803804), KQU(11639179410120968649),
+	KQU( 9318165193840846253), KQU(12795671722734758075),
+	KQU(15318410297267253933), KQU(  691524703570062620),
+	KQU( 5837129010576994601), KQU(15045963859726941052),
+	KQU( 5850056944932238169), KQU(12017434144750943807),
+	KQU( 7447139064928956574), KQU( 3101711812658245019),
+	KQU(16052940704474982954), KQU(18195745945986994042),
+	KQU( 8932252132785575659), KQU(13390817488106794834),
+	KQU(11582771836502517453), KQU( 4964411326683611686),
+	KQU( 2195093981702694011), KQU(14145229538389675669),
+	KQU(16459605532062271798), KQU(  866316924816482864),
+	KQU( 4593041209937286377), KQU( 8415491391910972138),
+	KQU( 4171236715600528969), KQU(16637569303336782889),
+	KQU( 2002011073439212680), KQU(17695124661097601411),
+	KQU( 4627687053598611702), KQU( 7895831936020190403),
+	KQU( 8455951300917267802), KQU( 2923861649108534854),
+	KQU( 8344557563927786255), KQU( 6408671940373352556),
+	KQU(12210227354536675772), KQU(14294804157294222295),
+	KQU(10103022425071085127), KQU(10092959489504123771),
+	KQU( 6554774405376736268), KQU(12629917718410641774),
+	KQU( 6260933257596067126), KQU( 2460827021439369673),
+	KQU( 2541962996717103668), KQU(  597377203127351475),
+	KQU( 5316984203117315309), KQU( 4811211393563241961),
+	KQU(13119698597255811641), KQU( 8048691512862388981),
+	KQU(10216818971194073842), KQU( 4612229970165291764),
+	KQU(10000980798419974770), KQU( 6877640812402540687),
+	KQU( 1488727563290436992), KQU( 2227774069895697318),
+	KQU(11237754507523316593), KQU(13478948605382290972),
+	KQU( 1963583846976858124), KQU( 5512309205269276457),
+	KQU( 3972770164717652347), KQU( 3841751276198975037),
+	KQU(10283343042181903117), KQU( 8564001259792872199),
+	KQU(16472187244722489221), KQU( 8953493499268945921),
+	KQU( 3518747340357279580), KQU( 4003157546223963073),
+	KQU( 3270305958289814590), KQU( 3966704458129482496),
+	KQU( 8122141865926661939), KQU(14627734748099506653),
+	KQU(13064426990862560568), KQU( 2414079187889870829),
+	KQU( 5378461209354225306), KQU(10841985740128255566),
+	KQU(  538582442885401738), KQU( 7535089183482905946),
+	KQU(16117559957598879095), KQU( 8477890721414539741),
+	KQU( 1459127491209533386), KQU(17035126360733620462),
+	KQU( 8517668552872379126), KQU(10292151468337355014),
+	KQU(17081267732745344157), KQU(13751455337946087178),
+	KQU(14026945459523832966), KQU( 6653278775061723516),
+	KQU(10619085543856390441), KQU( 2196343631481122885),
+	KQU(10045966074702826136), KQU(10082317330452718282),
+	KQU( 5920859259504831242), KQU( 9951879073426540617),
+	KQU( 7074696649151414158), KQU(15808193543879464318),
+	KQU( 7385247772746953374), KQU( 3192003544283864292),
+	KQU(18153684490917593847), KQU(12423498260668568905),
+	KQU(10957758099756378169), KQU(11488762179911016040),
+	KQU( 2099931186465333782), KQU(11180979581250294432),
+	KQU( 8098916250668367933), KQU( 3529200436790763465),
+	KQU(12988418908674681745), KQU( 6147567275954808580),
+	KQU( 3207503344604030989), KQU(10761592604898615360),
+	KQU(  229854861031893504), KQU( 8809853962667144291),
+	KQU(13957364469005693860), KQU( 7634287665224495886),
+	KQU(12353487366976556874), KQU( 1134423796317152034),
+	KQU( 2088992471334107068), KQU( 7393372127190799698),
+	KQU( 1845367839871058391), KQU(  207922563987322884),
+	KQU(11960870813159944976), KQU(12182120053317317363),
+	KQU(17307358132571709283), KQU(13871081155552824936),
+	KQU(18304446751741566262), KQU( 7178705220184302849),
+	KQU(10929605677758824425), KQU(16446976977835806844),
+	KQU(13723874412159769044), KQU( 6942854352100915216),
+	KQU( 1726308474365729390), KQU( 2150078766445323155),
+	KQU(15345558947919656626), KQU(12145453828874527201),
+	KQU( 2054448620739726849), KQU( 2740102003352628137),
+	KQU(11294462163577610655), KQU(  756164283387413743),
+	KQU(17841144758438810880), KQU(10802406021185415861),
+	KQU( 8716455530476737846), KQU( 6321788834517649606),
+	KQU(14681322910577468426), KQU(17330043563884336387),
+	KQU(12701802180050071614), KQU(14695105111079727151),
+	KQU( 5112098511654172830), KQU( 4957505496794139973),
+	KQU( 8270979451952045982), KQU(12307685939199120969),
+	KQU(12425799408953443032), KQU( 8376410143634796588),
+	KQU(16621778679680060464), KQU( 3580497854566660073),
+	KQU( 1122515747803382416), KQU(  857664980960597599),
+	KQU( 6343640119895925918), KQU(12878473260854462891),
+	KQU(10036813920765722626), KQU(14451335468363173812),
+	KQU( 5476809692401102807), KQU(16442255173514366342),
+	KQU(13060203194757167104), KQU(14354124071243177715),
+	KQU(15961249405696125227), KQU(13703893649690872584),
+	KQU(  363907326340340064), KQU( 6247455540491754842),
+	KQU(12242249332757832361), KQU(  156065475679796717),
+	KQU( 9351116235749732355), KQU( 4590350628677701405),
+	KQU( 1671195940982350389), KQU(13501398458898451905),
+	KQU( 6526341991225002255), KQU( 1689782913778157592),
+	KQU( 7439222350869010334), KQU(13975150263226478308),
+	KQU(11411961169932682710), KQU(17204271834833847277),
+	KQU(  541534742544435367), KQU( 6591191931218949684),
+	KQU( 2645454775478232486), KQU( 4322857481256485321),
+	KQU( 8477416487553065110), KQU(12902505428548435048),
+	KQU(  971445777981341415), KQU(14995104682744976712),
+	KQU( 4243341648807158063), KQU( 8695061252721927661),
+	KQU( 5028202003270177222), KQU( 2289257340915567840),
+	KQU(13870416345121866007), KQU(13994481698072092233),
+	KQU( 6912785400753196481), KQU( 2278309315841980139),
+	KQU( 4329765449648304839), KQU( 5963108095785485298),
+	KQU( 4880024847478722478), KQU(16015608779890240947),
+	KQU( 1866679034261393544), KQU(  914821179919731519),
+	KQU( 9643404035648760131), KQU( 2418114953615593915),
+	KQU(  944756836073702374), KQU(15186388048737296834),
+	KQU( 7723355336128442206), KQU( 7500747479679599691),
+	KQU(18013961306453293634), KQU( 2315274808095756456),
+	KQU(13655308255424029566), KQU(17203800273561677098),
+	KQU( 1382158694422087756), KQU( 5090390250309588976),
+	KQU(  517170818384213989), KQU( 1612709252627729621),
+	KQU( 1330118955572449606), KQU(  300922478056709885),
+	KQU(18115693291289091987), KQU(13491407109725238321),
+	KQU(15293714633593827320), KQU( 5151539373053314504),
+	KQU( 5951523243743139207), KQU(14459112015249527975),
+	KQU( 5456113959000700739), KQU( 3877918438464873016),
+	KQU(12534071654260163555), KQU(15871678376893555041),
+	KQU(11005484805712025549), KQU(16353066973143374252),
+	KQU( 4358331472063256685), KQU( 8268349332210859288),
+	KQU(12485161590939658075), KQU(13955993592854471343),
+	KQU( 5911446886848367039), KQU(14925834086813706974),
+	KQU( 6590362597857994805), KQU( 1280544923533661875),
+	KQU( 1637756018947988164), KQU( 4734090064512686329),
+	KQU(16693705263131485912), KQU( 6834882340494360958),
+	KQU( 8120732176159658505), KQU( 2244371958905329346),
+	KQU(10447499707729734021), KQU( 7318742361446942194),
+	KQU( 8032857516355555296), KQU(14023605983059313116),
+	KQU( 1032336061815461376), KQU( 9840995337876562612),
+	KQU( 9869256223029203587), KQU(12227975697177267636),
+	KQU(12728115115844186033), KQU( 7752058479783205470),
+	KQU(  729733219713393087), KQU(12954017801239007622)
 };
 static const uint64_t init_by_array_64_expected[] = {
-	QU( 2100341266307895239LLU), QU( 8344256300489757943LLU),
-	QU(15687933285484243894LLU), QU( 8268620370277076319LLU),
-	QU(12371852309826545459LLU), QU( 8800491541730110238LLU),
-	QU(18113268950100835773LLU), QU( 2886823658884438119LLU),
-	QU( 3293667307248180724LLU), QU( 9307928143300172731LLU),
-	QU( 7688082017574293629LLU), QU(  900986224735166665LLU),
-	QU( 9977972710722265039LLU), QU( 6008205004994830552LLU),
-	QU(  546909104521689292LLU), QU( 7428471521869107594LLU),
-	QU(14777563419314721179LLU), QU(16116143076567350053LLU),
-	QU( 5322685342003142329LLU), QU( 4200427048445863473LLU),
-	QU( 4693092150132559146LLU), QU(13671425863759338582LLU),
-	QU( 6747117460737639916LLU), QU( 4732666080236551150LLU),
-	QU( 5912839950611941263LLU), QU( 3903717554504704909LLU),
-	QU( 2615667650256786818LLU), QU(10844129913887006352LLU),
-	QU(13786467861810997820LLU), QU(14267853002994021570LLU),
-	QU(13767807302847237439LLU), QU(16407963253707224617LLU),
-	QU( 4802498363698583497LLU), QU( 2523802839317209764LLU),
-	QU( 3822579397797475589LLU), QU( 8950320572212130610LLU),
-	QU( 3745623504978342534LLU), QU(16092609066068482806LLU),
-	QU( 9817016950274642398LLU), QU(10591660660323829098LLU),
-	QU(11751606650792815920LLU), QU( 5122873818577122211LLU),
-	QU(17209553764913936624LLU), QU( 6249057709284380343LLU),
-	QU(15088791264695071830LLU), QU(15344673071709851930LLU),
-	QU( 4345751415293646084LLU), QU( 2542865750703067928LLU),
-	QU(13520525127852368784LLU), QU(18294188662880997241LLU),
-	QU( 3871781938044881523LLU), QU( 2873487268122812184LLU),
-	QU(15099676759482679005LLU), QU(15442599127239350490LLU),
-	QU( 6311893274367710888LLU), QU( 3286118760484672933LLU),
-	QU( 4146067961333542189LLU), QU(13303942567897208770LLU),
-	QU( 8196013722255630418LLU), QU( 4437815439340979989LLU),
-	QU(15433791533450605135LLU), QU( 4254828956815687049LLU),
-	QU( 1310903207708286015LLU), QU(10529182764462398549LLU),
-	QU(14900231311660638810LLU), QU( 9727017277104609793LLU),
-	QU( 1821308310948199033LLU), QU(11628861435066772084LLU),
-	QU( 9469019138491546924LLU), QU( 3145812670532604988LLU),
-	QU( 9938468915045491919LLU), QU( 1562447430672662142LLU),
-	QU(13963995266697989134LLU), QU( 3356884357625028695LLU),
-	QU( 4499850304584309747LLU), QU( 8456825817023658122LLU),
-	QU(10859039922814285279LLU), QU( 8099512337972526555LLU),
-	QU(  348006375109672149LLU), QU(11919893998241688603LLU),
-	QU( 1104199577402948826LLU), QU(16689191854356060289LLU),
-	QU(10992552041730168078LLU), QU( 7243733172705465836LLU),
-	QU( 5668075606180319560LLU), QU(18182847037333286970LLU),
-	QU( 4290215357664631322LLU), QU( 4061414220791828613LLU),
-	QU(13006291061652989604LLU), QU( 7140491178917128798LLU),
-	QU(12703446217663283481LLU), QU( 5500220597564558267LLU),
-	QU(10330551509971296358LLU), QU(15958554768648714492LLU),
-	QU( 5174555954515360045LLU), QU( 1731318837687577735LLU),
-	QU( 3557700801048354857LLU), QU(13764012341928616198LLU),
-	QU(13115166194379119043LLU), QU( 7989321021560255519LLU),
-	QU( 2103584280905877040LLU), QU( 9230788662155228488LLU),
-	QU(16396629323325547654LLU), QU(  657926409811318051LLU),
-	QU(15046700264391400727LLU), QU( 5120132858771880830LLU),
-	QU( 7934160097989028561LLU), QU( 6963121488531976245LLU),
-	QU(17412329602621742089LLU), QU(15144843053931774092LLU),
-	QU(17204176651763054532LLU), QU(13166595387554065870LLU),
-	QU( 8590377810513960213LLU), QU( 5834365135373991938LLU),
-	QU( 7640913007182226243LLU), QU( 3479394703859418425LLU),
-	QU(16402784452644521040LLU), QU( 4993979809687083980LLU),
-	QU(13254522168097688865LLU), QU(15643659095244365219LLU),
-	QU( 5881437660538424982LLU), QU(11174892200618987379LLU),
-	QU(  254409966159711077LLU), QU(17158413043140549909LLU),
-	QU( 3638048789290376272LLU), QU( 1376816930299489190LLU),
-	QU( 4622462095217761923LLU), QU(15086407973010263515LLU),
-	QU(13253971772784692238LLU), QU( 5270549043541649236LLU),
-	QU(11182714186805411604LLU), QU(12283846437495577140LLU),
-	QU( 5297647149908953219LLU), QU(10047451738316836654LLU),
-	QU( 4938228100367874746LLU), QU(12328523025304077923LLU),
-	QU( 3601049438595312361LLU), QU( 9313624118352733770LLU),
-	QU(13322966086117661798LLU), QU(16660005705644029394LLU),
-	QU(11337677526988872373LLU), QU(13869299102574417795LLU),
-	QU(15642043183045645437LLU), QU( 3021755569085880019LLU),
-	QU( 4979741767761188161LLU), QU(13679979092079279587LLU),
-	QU( 3344685842861071743LLU), QU(13947960059899588104LLU),
-	QU(  305806934293368007LLU), QU( 5749173929201650029LLU),
-	QU(11123724852118844098LLU), QU(15128987688788879802LLU),
-	QU(15251651211024665009LLU), QU( 7689925933816577776LLU),
-	QU(16732804392695859449LLU), QU(17087345401014078468LLU),
-	QU(14315108589159048871LLU), QU( 4820700266619778917LLU),
-	QU(16709637539357958441LLU), QU( 4936227875177351374LLU),
-	QU( 2137907697912987247LLU), QU(11628565601408395420LLU),
-	QU( 2333250549241556786LLU), QU( 5711200379577778637LLU),
-	QU( 5170680131529031729LLU), QU(12620392043061335164LLU),
-	QU(   95363390101096078LLU), QU( 5487981914081709462LLU),
-	QU( 1763109823981838620LLU), QU( 3395861271473224396LLU),
-	QU( 1300496844282213595LLU), QU( 6894316212820232902LLU),
-	QU(10673859651135576674LLU), QU( 5911839658857903252LLU),
-	QU(17407110743387299102LLU), QU( 8257427154623140385LLU),
-	QU(11389003026741800267LLU), QU( 4070043211095013717LLU),
-	QU(11663806997145259025LLU), QU(15265598950648798210LLU),
-	QU(  630585789434030934LLU), QU( 3524446529213587334LLU),
-	QU( 7186424168495184211LLU), QU(10806585451386379021LLU),
-	QU(11120017753500499273LLU), QU( 1586837651387701301LLU),
-	QU(17530454400954415544LLU), QU( 9991670045077880430LLU),
-	QU( 7550997268990730180LLU), QU( 8640249196597379304LLU),
-	QU( 3522203892786893823LLU), QU(10401116549878854788LLU),
-	QU(13690285544733124852LLU), QU( 8295785675455774586LLU),
-	QU(15535716172155117603LLU), QU( 3112108583723722511LLU),
-	QU(17633179955339271113LLU), QU(18154208056063759375LLU),
-	QU( 1866409236285815666LLU), QU(13326075895396412882LLU),
-	QU( 8756261842948020025LLU), QU( 6281852999868439131LLU),
-	QU(15087653361275292858LLU), QU(10333923911152949397LLU),
-	QU( 5265567645757408500LLU), QU(12728041843210352184LLU),
-	QU( 6347959327507828759LLU), QU(  154112802625564758LLU),
-	QU(18235228308679780218LLU), QU( 3253805274673352418LLU),
-	QU( 4849171610689031197LLU), QU(17948529398340432518LLU),
-	QU(13803510475637409167LLU), QU(13506570190409883095LLU),
-	QU(15870801273282960805LLU), QU( 8451286481299170773LLU),
-	QU( 9562190620034457541LLU), QU( 8518905387449138364LLU),
-	QU(12681306401363385655LLU), QU( 3788073690559762558LLU),
-	QU( 5256820289573487769LLU), QU( 2752021372314875467LLU),
-	QU( 6354035166862520716LLU), QU( 4328956378309739069LLU),
-	QU(  449087441228269600LLU), QU( 5533508742653090868LLU),
-	QU( 1260389420404746988LLU), QU(18175394473289055097LLU),
-	QU( 1535467109660399420LLU), QU( 8818894282874061442LLU),
-	QU(12140873243824811213LLU), QU(15031386653823014946LLU),
-	QU( 1286028221456149232LLU), QU( 6329608889367858784LLU),
-	QU( 9419654354945132725LLU), QU( 6094576547061672379LLU),
-	QU(17706217251847450255LLU), QU( 1733495073065878126LLU),
-	QU(16918923754607552663LLU), QU( 8881949849954945044LLU),
-	QU(12938977706896313891LLU), QU(14043628638299793407LLU),
-	QU(18393874581723718233LLU), QU( 6886318534846892044LLU),
-	QU(14577870878038334081LLU), QU(13541558383439414119LLU),
-	QU(13570472158807588273LLU), QU(18300760537910283361LLU),
-	QU(  818368572800609205LLU), QU( 1417000585112573219LLU),
-	QU(12337533143867683655LLU), QU(12433180994702314480LLU),
-	QU(  778190005829189083LLU), QU(13667356216206524711LLU),
-	QU( 9866149895295225230LLU), QU(11043240490417111999LLU),
-	QU( 1123933826541378598LLU), QU( 6469631933605123610LLU),
-	QU(14508554074431980040LLU), QU(13918931242962026714LLU),
-	QU( 2870785929342348285LLU), QU(14786362626740736974LLU),
-	QU(13176680060902695786LLU), QU( 9591778613541679456LLU),
-	QU( 9097662885117436706LLU), QU(  749262234240924947LLU),
-	QU( 1944844067793307093LLU), QU( 4339214904577487742LLU),
-	QU( 8009584152961946551LLU), QU(16073159501225501777LLU),
-	QU( 3335870590499306217LLU), QU(17088312653151202847LLU),
-	QU( 3108893142681931848LLU), QU(16636841767202792021LLU),
-	QU(10423316431118400637LLU), QU( 8008357368674443506LLU),
-	QU(11340015231914677875LLU), QU(17687896501594936090LLU),
-	QU(15173627921763199958LLU), QU(  542569482243721959LLU),
-	QU(15071714982769812975LLU), QU( 4466624872151386956LLU),
-	QU( 1901780715602332461LLU), QU( 9822227742154351098LLU),
-	QU( 1479332892928648780LLU), QU( 6981611948382474400LLU),
-	QU( 7620824924456077376LLU), QU(14095973329429406782LLU),
-	QU( 7902744005696185404LLU), QU(15830577219375036920LLU),
-	QU(10287076667317764416LLU), QU(12334872764071724025LLU),
-	QU( 4419302088133544331LLU), QU(14455842851266090520LLU),
-	QU(12488077416504654222LLU), QU( 7953892017701886766LLU),
-	QU( 6331484925529519007LLU), QU( 4902145853785030022LLU),
-	QU(17010159216096443073LLU), QU(11945354668653886087LLU),
-	QU(15112022728645230829LLU), QU(17363484484522986742LLU),
-	QU( 4423497825896692887LLU), QU( 8155489510809067471LLU),
-	QU(  258966605622576285LLU), QU( 5462958075742020534LLU),
-	QU( 6763710214913276228LLU), QU( 2368935183451109054LLU),
-	QU(14209506165246453811LLU), QU( 2646257040978514881LLU),
-	QU( 3776001911922207672LLU), QU( 1419304601390147631LLU),
-	QU(14987366598022458284LLU), QU( 3977770701065815721LLU),
-	QU(  730820417451838898LLU), QU( 3982991703612885327LLU),
-	QU( 2803544519671388477LLU), QU(17067667221114424649LLU),
-	QU( 2922555119737867166LLU), QU( 1989477584121460932LLU),
-	QU(15020387605892337354LLU), QU( 9293277796427533547LLU),
-	QU(10722181424063557247LLU), QU(16704542332047511651LLU),
-	QU( 5008286236142089514LLU), QU(16174732308747382540LLU),
-	QU(17597019485798338402LLU), QU(13081745199110622093LLU),
-	QU( 8850305883842258115LLU), QU(12723629125624589005LLU),
-	QU( 8140566453402805978LLU), QU(15356684607680935061LLU),
-	QU(14222190387342648650LLU), QU(11134610460665975178LLU),
-	QU( 1259799058620984266LLU), QU(13281656268025610041LLU),
-	QU(  298262561068153992LLU), QU(12277871700239212922LLU),
-	QU(13911297774719779438LLU), QU(16556727962761474934LLU),
-	QU(17903010316654728010LLU), QU( 9682617699648434744LLU),
-	QU(14757681836838592850LLU), QU( 1327242446558524473LLU),
-	QU(11126645098780572792LLU), QU( 1883602329313221774LLU),
-	QU( 2543897783922776873LLU), QU(15029168513767772842LLU),
-	QU(12710270651039129878LLU), QU(16118202956069604504LLU),
-	QU(15010759372168680524LLU), QU( 2296827082251923948LLU),
-	QU(10793729742623518101LLU), QU(13829764151845413046LLU),
-	QU(17769301223184451213LLU), QU( 3118268169210783372LLU),
-	QU(17626204544105123127LLU), QU( 7416718488974352644LLU),
-	QU(10450751996212925994LLU), QU( 9352529519128770586LLU),
-	QU(  259347569641110140LLU), QU( 8048588892269692697LLU),
-	QU( 1774414152306494058LLU), QU(10669548347214355622LLU),
-	QU(13061992253816795081LLU), QU(18432677803063861659LLU),
-	QU( 8879191055593984333LLU), QU(12433753195199268041LLU),
-	QU(14919392415439730602LLU), QU( 6612848378595332963LLU),
-	QU( 6320986812036143628LLU), QU(10465592420226092859LLU),
-	QU( 4196009278962570808LLU), QU( 3747816564473572224LLU),
-	QU(17941203486133732898LLU), QU( 2350310037040505198LLU),
-	QU( 5811779859134370113LLU), QU(10492109599506195126LLU),
-	QU( 7699650690179541274LLU), QU( 1954338494306022961LLU),
-	QU(14095816969027231152LLU), QU( 5841346919964852061LLU),
-	QU(14945969510148214735LLU), QU( 3680200305887550992LLU),
-	QU( 6218047466131695792LLU), QU( 8242165745175775096LLU),
-	QU(11021371934053307357LLU), QU( 1265099502753169797LLU),
-	QU( 4644347436111321718LLU), QU( 3609296916782832859LLU),
-	QU( 8109807992218521571LLU), QU(18387884215648662020LLU),
-	QU(14656324896296392902LLU), QU(17386819091238216751LLU),
-	QU(17788300878582317152LLU), QU( 7919446259742399591LLU),
-	QU( 4466613134576358004LLU), QU(12928181023667938509LLU),
-	QU(13147446154454932030LLU), QU(16552129038252734620LLU),
-	QU( 8395299403738822450LLU), QU(11313817655275361164LLU),
-	QU(  434258809499511718LLU), QU( 2074882104954788676LLU),
-	QU( 7929892178759395518LLU), QU( 9006461629105745388LLU),
-	QU( 5176475650000323086LLU), QU(11128357033468341069LLU),
-	QU(12026158851559118955LLU), QU(14699716249471156500LLU),
-	QU(  448982497120206757LLU), QU( 4156475356685519900LLU),
-	QU( 6063816103417215727LLU), QU(10073289387954971479LLU),
-	QU( 8174466846138590962LLU), QU( 2675777452363449006LLU),
-	QU( 9090685420572474281LLU), QU( 6659652652765562060LLU),
-	QU(12923120304018106621LLU), QU(11117480560334526775LLU),
-	QU(  937910473424587511LLU), QU( 1838692113502346645LLU),
-	QU(11133914074648726180LLU), QU( 7922600945143884053LLU),
-	QU(13435287702700959550LLU), QU( 5287964921251123332LLU),
-	QU(11354875374575318947LLU), QU(17955724760748238133LLU),
-	QU(13728617396297106512LLU), QU( 4107449660118101255LLU),
-	QU( 1210269794886589623LLU), QU(11408687205733456282LLU),
-	QU( 4538354710392677887LLU), QU(13566803319341319267LLU),
-	QU(17870798107734050771LLU), QU( 3354318982568089135LLU),
-	QU( 9034450839405133651LLU), QU(13087431795753424314LLU),
-	QU(  950333102820688239LLU), QU( 1968360654535604116LLU),
-	QU(16840551645563314995LLU), QU( 8867501803892924995LLU),
-	QU(11395388644490626845LLU), QU( 1529815836300732204LLU),
-	QU(13330848522996608842LLU), QU( 1813432878817504265LLU),
-	QU( 2336867432693429560LLU), QU(15192805445973385902LLU),
-	QU( 2528593071076407877LLU), QU(  128459777936689248LLU),
-	QU( 9976345382867214866LLU), QU( 6208885766767996043LLU),
-	QU(14982349522273141706LLU), QU( 3099654362410737822LLU),
-	QU(13776700761947297661LLU), QU( 8806185470684925550LLU),
-	QU( 8151717890410585321LLU), QU(  640860591588072925LLU),
-	QU(14592096303937307465LLU), QU( 9056472419613564846LLU),
-	QU(14861544647742266352LLU), QU(12703771500398470216LLU),
-	QU( 3142372800384138465LLU), QU( 6201105606917248196LLU),
-	QU(18337516409359270184LLU), QU(15042268695665115339LLU),
-	QU(15188246541383283846LLU), QU(12800028693090114519LLU),
-	QU( 5992859621101493472LLU), QU(18278043971816803521LLU),
-	QU( 9002773075219424560LLU), QU( 7325707116943598353LLU),
-	QU( 7930571931248040822LLU), QU( 5645275869617023448LLU),
-	QU( 7266107455295958487LLU), QU( 4363664528273524411LLU),
-	QU(14313875763787479809LLU), QU(17059695613553486802LLU),
-	QU( 9247761425889940932LLU), QU(13704726459237593128LLU),
-	QU( 2701312427328909832LLU), QU(17235532008287243115LLU),
-	QU(14093147761491729538LLU), QU( 6247352273768386516LLU),
-	QU( 8268710048153268415LLU), QU( 7985295214477182083LLU),
-	QU(15624495190888896807LLU), QU( 3772753430045262788LLU),
-	QU( 9133991620474991698LLU), QU( 5665791943316256028LLU),
-	QU( 7551996832462193473LLU), QU(13163729206798953877LLU),
-	QU( 9263532074153846374LLU), QU( 1015460703698618353LLU),
-	QU(17929874696989519390LLU), QU(18257884721466153847LLU),
-	QU(16271867543011222991LLU), QU( 3905971519021791941LLU),
-	QU(16814488397137052085LLU), QU( 1321197685504621613LLU),
-	QU( 2870359191894002181LLU), QU(14317282970323395450LLU),
-	QU(13663920845511074366LLU), QU( 2052463995796539594LLU),
-	QU(14126345686431444337LLU), QU( 1727572121947022534LLU),
-	QU(17793552254485594241LLU), QU( 6738857418849205750LLU),
-	QU( 1282987123157442952LLU), QU(16655480021581159251LLU),
-	QU( 6784587032080183866LLU), QU(14726758805359965162LLU),
-	QU( 7577995933961987349LLU), QU(12539609320311114036LLU),
-	QU(10789773033385439494LLU), QU( 8517001497411158227LLU),
-	QU(10075543932136339710LLU), QU(14838152340938811081LLU),
-	QU( 9560840631794044194LLU), QU(17445736541454117475LLU),
-	QU(10633026464336393186LLU), QU(15705729708242246293LLU),
-	QU( 1117517596891411098LLU), QU( 4305657943415886942LLU),
-	QU( 4948856840533979263LLU), QU(16071681989041789593LLU),
-	QU(13723031429272486527LLU), QU( 7639567622306509462LLU),
-	QU(12670424537483090390LLU), QU( 9715223453097197134LLU),
-	QU( 5457173389992686394LLU), QU(  289857129276135145LLU),
-	QU(17048610270521972512LLU), QU(  692768013309835485LLU),
-	QU(14823232360546632057LLU), QU(18218002361317895936LLU),
-	QU( 3281724260212650204LLU), QU(16453957266549513795LLU),
-	QU( 8592711109774511881LLU), QU(  929825123473369579LLU),
-	QU(15966784769764367791LLU), QU( 9627344291450607588LLU),
-	QU(10849555504977813287LLU), QU( 9234566913936339275LLU),
-	QU( 6413807690366911210LLU), QU(10862389016184219267LLU),
-	QU(13842504799335374048LLU), QU( 1531994113376881174LLU),
-	QU( 2081314867544364459LLU), QU(16430628791616959932LLU),
-	QU( 8314714038654394368LLU), QU( 9155473892098431813LLU),
-	QU(12577843786670475704LLU), QU( 4399161106452401017LLU),
-	QU( 1668083091682623186LLU), QU( 1741383777203714216LLU),
-	QU( 2162597285417794374LLU), QU(15841980159165218736LLU),
-	QU( 1971354603551467079LLU), QU( 1206714764913205968LLU),
-	QU( 4790860439591272330LLU), QU(14699375615594055799LLU),
-	QU( 8374423871657449988LLU), QU(10950685736472937738LLU),
-	QU(  697344331343267176LLU), QU(10084998763118059810LLU),
-	QU(12897369539795983124LLU), QU(12351260292144383605LLU),
-	QU( 1268810970176811234LLU), QU( 7406287800414582768LLU),
-	QU(  516169557043807831LLU), QU( 5077568278710520380LLU),
-	QU( 3828791738309039304LLU), QU( 7721974069946943610LLU),
-	QU( 3534670260981096460LLU), QU( 4865792189600584891LLU),
-	QU(16892578493734337298LLU), QU( 9161499464278042590LLU),
-	QU(11976149624067055931LLU), QU(13219479887277343990LLU),
-	QU(14161556738111500680LLU), QU(14670715255011223056LLU),
-	QU( 4671205678403576558LLU), QU(12633022931454259781LLU),
-	QU(14821376219869187646LLU), QU(  751181776484317028LLU),
-	QU( 2192211308839047070LLU), QU(11787306362361245189LLU),
-	QU(10672375120744095707LLU), QU( 4601972328345244467LLU),
-	QU(15457217788831125879LLU), QU( 8464345256775460809LLU),
-	QU(10191938789487159478LLU), QU( 6184348739615197613LLU),
-	QU(11425436778806882100LLU), QU( 2739227089124319793LLU),
-	QU(  461464518456000551LLU), QU( 4689850170029177442LLU),
-	QU( 6120307814374078625LLU), QU(11153579230681708671LLU),
-	QU( 7891721473905347926LLU), QU(10281646937824872400LLU),
-	QU( 3026099648191332248LLU), QU( 8666750296953273818LLU),
-	QU(14978499698844363232LLU), QU(13303395102890132065LLU),
-	QU( 8182358205292864080LLU), QU(10560547713972971291LLU),
-	QU(11981635489418959093LLU), QU( 3134621354935288409LLU),
-	QU(11580681977404383968LLU), QU(14205530317404088650LLU),
-	QU( 5997789011854923157LLU), QU(13659151593432238041LLU),
-	QU(11664332114338865086LLU), QU( 7490351383220929386LLU),
-	QU( 7189290499881530378LLU), QU(15039262734271020220LLU),
-	QU( 2057217285976980055LLU), QU(  555570804905355739LLU),
-	QU(11235311968348555110LLU), QU(13824557146269603217LLU),
-	QU(16906788840653099693LLU), QU( 7222878245455661677LLU),
-	QU( 5245139444332423756LLU), QU( 4723748462805674292LLU),
-	QU(12216509815698568612LLU), QU(17402362976648951187LLU),
-	QU(17389614836810366768LLU), QU( 4880936484146667711LLU),
-	QU( 9085007839292639880LLU), QU(13837353458498535449LLU),
-	QU(11914419854360366677LLU), QU(16595890135313864103LLU),
-	QU( 6313969847197627222LLU), QU(18296909792163910431LLU),
-	QU(10041780113382084042LLU), QU( 2499478551172884794LLU),
-	QU(11057894246241189489LLU), QU( 9742243032389068555LLU),
-	QU(12838934582673196228LLU), QU(13437023235248490367LLU),
-	QU(13372420669446163240LLU), QU( 6752564244716909224LLU),
-	QU( 7157333073400313737LLU), QU(12230281516370654308LLU),
-	QU( 1182884552219419117LLU), QU( 2955125381312499218LLU),
-	QU(10308827097079443249LLU), QU( 1337648572986534958LLU),
-	QU(16378788590020343939LLU), QU(  108619126514420935LLU),
-	QU( 3990981009621629188LLU), QU( 5460953070230946410LLU),
-	QU( 9703328329366531883LLU), QU(13166631489188077236LLU),
-	QU( 1104768831213675170LLU), QU( 3447930458553877908LLU),
-	QU( 8067172487769945676LLU), QU( 5445802098190775347LLU),
-	QU( 3244840981648973873LLU), QU(17314668322981950060LLU),
-	QU( 5006812527827763807LLU), QU(18158695070225526260LLU),
-	QU( 2824536478852417853LLU), QU(13974775809127519886LLU),
-	QU( 9814362769074067392LLU), QU(17276205156374862128LLU),
-	QU(11361680725379306967LLU), QU( 3422581970382012542LLU),
-	QU(11003189603753241266LLU), QU(11194292945277862261LLU),
-	QU( 6839623313908521348LLU), QU(11935326462707324634LLU),
-	QU( 1611456788685878444LLU), QU(13112620989475558907LLU),
-	QU(  517659108904450427LLU), QU(13558114318574407624LLU),
-	QU(15699089742731633077LLU), QU( 4988979278862685458LLU),
-	QU( 8111373583056521297LLU), QU( 3891258746615399627LLU),
-	QU( 8137298251469718086LLU), QU(12748663295624701649LLU),
-	QU( 4389835683495292062LLU), QU( 5775217872128831729LLU),
-	QU( 9462091896405534927LLU), QU( 8498124108820263989LLU),
-	QU( 8059131278842839525LLU), QU(10503167994254090892LLU),
-	QU(11613153541070396656LLU), QU(18069248738504647790LLU),
-	QU(  570657419109768508LLU), QU( 3950574167771159665LLU),
-	QU( 5514655599604313077LLU), QU( 2908460854428484165LLU),
-	QU(10777722615935663114LLU), QU(12007363304839279486LLU),
-	QU( 9800646187569484767LLU), QU( 8795423564889864287LLU),
-	QU(14257396680131028419LLU), QU( 6405465117315096498LLU),
-	QU( 7939411072208774878LLU), QU(17577572378528990006LLU),
-	QU(14785873806715994850LLU), QU(16770572680854747390LLU),
-	QU(18127549474419396481LLU), QU(11637013449455757750LLU),
-	QU(14371851933996761086LLU), QU( 3601181063650110280LLU),
-	QU( 4126442845019316144LLU), QU(10198287239244320669LLU),
-	QU(18000169628555379659LLU), QU(18392482400739978269LLU),
-	QU( 6219919037686919957LLU), QU( 3610085377719446052LLU),
-	QU( 2513925039981776336LLU), QU(16679413537926716955LLU),
-	QU(12903302131714909434LLU), QU( 5581145789762985009LLU),
-	QU(12325955044293303233LLU), QU(17216111180742141204LLU),
-	QU( 6321919595276545740LLU), QU( 3507521147216174501LLU),
-	QU( 9659194593319481840LLU), QU(11473976005975358326LLU),
-	QU(14742730101435987026LLU), QU(  492845897709954780LLU),
-	QU(16976371186162599676LLU), QU(17712703422837648655LLU),
-	QU( 9881254778587061697LLU), QU( 8413223156302299551LLU),
-	QU( 1563841828254089168LLU), QU( 9996032758786671975LLU),
-	QU(  138877700583772667LLU), QU(13003043368574995989LLU),
-	QU( 4390573668650456587LLU), QU( 8610287390568126755LLU),
-	QU(15126904974266642199LLU), QU( 6703637238986057662LLU),
-	QU( 2873075592956810157LLU), QU( 6035080933946049418LLU),
-	QU(13382846581202353014LLU), QU( 7303971031814642463LLU),
-	QU(18418024405307444267LLU), QU( 5847096731675404647LLU),
-	QU( 4035880699639842500LLU), QU(11525348625112218478LLU),
-	QU( 3041162365459574102LLU), QU( 2604734487727986558LLU),
-	QU(15526341771636983145LLU), QU(14556052310697370254LLU),
-	QU(12997787077930808155LLU), QU( 9601806501755554499LLU),
-	QU(11349677952521423389LLU), QU(14956777807644899350LLU),
-	QU(16559736957742852721LLU), QU(12360828274778140726LLU),
-	QU( 6685373272009662513LLU), QU(16932258748055324130LLU),
-	QU(15918051131954158508LLU), QU( 1692312913140790144LLU),
-	QU(  546653826801637367LLU), QU( 5341587076045986652LLU),
-	QU(14975057236342585662LLU), QU(12374976357340622412LLU),
-	QU(10328833995181940552LLU), QU(12831807101710443149LLU),
-	QU(10548514914382545716LLU), QU( 2217806727199715993LLU),
-	QU(12627067369242845138LLU), QU( 4598965364035438158LLU),
-	QU(  150923352751318171LLU), QU(14274109544442257283LLU),
-	QU( 4696661475093863031LLU), QU( 1505764114384654516LLU),
-	QU(10699185831891495147LLU), QU( 2392353847713620519LLU),
-	QU( 3652870166711788383LLU), QU( 8640653276221911108LLU),
-	QU( 3894077592275889704LLU), QU( 4918592872135964845LLU),
-	QU(16379121273281400789LLU), QU(12058465483591683656LLU),
-	QU(11250106829302924945LLU), QU( 1147537556296983005LLU),
-	QU( 6376342756004613268LLU), QU(14967128191709280506LLU),
-	QU(18007449949790627628LLU), QU( 9497178279316537841LLU),
-	QU( 7920174844809394893LLU), QU(10037752595255719907LLU),
-	QU(15875342784985217697LLU), QU(15311615921712850696LLU),
-	QU( 9552902652110992950LLU), QU(14054979450099721140LLU),
-	QU( 5998709773566417349LLU), QU(18027910339276320187LLU),
-	QU( 8223099053868585554LLU), QU( 7842270354824999767LLU),
-	QU( 4896315688770080292LLU), QU(12969320296569787895LLU),
-	QU( 2674321489185759961LLU), QU( 4053615936864718439LLU),
-	QU(11349775270588617578LLU), QU( 4743019256284553975LLU),
-	QU( 5602100217469723769LLU), QU(14398995691411527813LLU),
-	QU( 7412170493796825470LLU), QU(  836262406131744846LLU),
-	QU( 8231086633845153022LLU), QU( 5161377920438552287LLU),
-	QU( 8828731196169924949LLU), QU(16211142246465502680LLU),
-	QU( 3307990879253687818LLU), QU( 5193405406899782022LLU),
-	QU( 8510842117467566693LLU), QU( 6070955181022405365LLU),
-	QU(14482950231361409799LLU), QU(12585159371331138077LLU),
-	QU( 3511537678933588148LLU), QU( 2041849474531116417LLU),
-	QU(10944936685095345792LLU), QU(18303116923079107729LLU),
-	QU( 2720566371239725320LLU), QU( 4958672473562397622LLU),
-	QU( 3032326668253243412LLU), QU(13689418691726908338LLU),
-	QU( 1895205511728843996LLU), QU( 8146303515271990527LLU),
-	QU(16507343500056113480LLU), QU(  473996939105902919LLU),
-	QU( 9897686885246881481LLU), QU(14606433762712790575LLU),
-	QU( 6732796251605566368LLU), QU( 1399778120855368916LLU),
-	QU(  935023885182833777LLU), QU(16066282816186753477LLU),
-	QU( 7291270991820612055LLU), QU(17530230393129853844LLU),
-	QU(10223493623477451366LLU), QU(15841725630495676683LLU),
-	QU(17379567246435515824LLU), QU( 8588251429375561971LLU),
-	QU(18339511210887206423LLU), QU(17349587430725976100LLU),
-	QU(12244876521394838088LLU), QU( 6382187714147161259LLU),
-	QU(12335807181848950831LLU), QU(16948885622305460665LLU),
-	QU(13755097796371520506LLU), QU(14806740373324947801LLU),
-	QU( 4828699633859287703LLU), QU( 8209879281452301604LLU),
-	QU(12435716669553736437LLU), QU(13970976859588452131LLU),
-	QU( 6233960842566773148LLU), QU(12507096267900505759LLU),
-	QU( 1198713114381279421LLU), QU(14989862731124149015LLU),
-	QU(15932189508707978949LLU), QU( 2526406641432708722LLU),
-	QU(   29187427817271982LLU), QU( 1499802773054556353LLU),
-	QU(10816638187021897173LLU), QU( 5436139270839738132LLU),
-	QU( 6659882287036010082LLU), QU( 2154048955317173697LLU),
-	QU(10887317019333757642LLU), QU(16281091802634424955LLU),
-	QU(10754549879915384901LLU), QU(10760611745769249815LLU),
-	QU( 2161505946972504002LLU), QU( 5243132808986265107LLU),
-	QU(10129852179873415416LLU), QU(  710339480008649081LLU),
-	QU( 7802129453068808528LLU), QU(17967213567178907213LLU),
-	QU(15730859124668605599LLU), QU(13058356168962376502LLU),
-	QU( 3701224985413645909LLU), QU(14464065869149109264LLU),
-	QU( 9959272418844311646LLU), QU(10157426099515958752LLU),
-	QU(14013736814538268528LLU), QU(17797456992065653951LLU),
-	QU(17418878140257344806LLU), QU(15457429073540561521LLU),
-	QU( 2184426881360949378LLU), QU( 2062193041154712416LLU),
-	QU( 8553463347406931661LLU), QU( 4913057625202871854LLU),
-	QU( 2668943682126618425LLU), QU(17064444737891172288LLU),
-	QU( 4997115903913298637LLU), QU(12019402608892327416LLU),
-	QU(17603584559765897352LLU), QU(11367529582073647975LLU),
-	QU( 8211476043518436050LLU), QU( 8676849804070323674LLU),
-	QU(18431829230394475730LLU), QU(10490177861361247904LLU),
-	QU( 9508720602025651349LLU), QU( 7409627448555722700LLU),
-	QU( 5804047018862729008LLU), QU(11943858176893142594LLU),
-	QU(11908095418933847092LLU), QU( 5415449345715887652LLU),
-	QU( 1554022699166156407LLU), QU( 9073322106406017161LLU),
-	QU( 7080630967969047082LLU), QU(18049736940860732943LLU),
-	QU(12748714242594196794LLU), QU( 1226992415735156741LLU),
-	QU(17900981019609531193LLU), QU(11720739744008710999LLU),
-	QU( 3006400683394775434LLU), QU(11347974011751996028LLU),
-	QU( 3316999628257954608LLU), QU( 8384484563557639101LLU),
-	QU(18117794685961729767LLU), QU( 1900145025596618194LLU),
-	QU(17459527840632892676LLU), QU( 5634784101865710994LLU),
-	QU( 7918619300292897158LLU), QU( 3146577625026301350LLU),
-	QU( 9955212856499068767LLU), QU( 1873995843681746975LLU),
-	QU( 1561487759967972194LLU), QU( 8322718804375878474LLU),
-	QU(11300284215327028366LLU), QU( 4667391032508998982LLU),
-	QU( 9820104494306625580LLU), QU(17922397968599970610LLU),
-	QU( 1784690461886786712LLU), QU(14940365084341346821LLU),
-	QU( 5348719575594186181LLU), QU(10720419084507855261LLU),
-	QU(14210394354145143274LLU), QU( 2426468692164000131LLU),
-	QU(16271062114607059202LLU), QU(14851904092357070247LLU),
-	QU( 6524493015693121897LLU), QU( 9825473835127138531LLU),
-	QU(14222500616268569578LLU), QU(15521484052007487468LLU),
-	QU(14462579404124614699LLU), QU(11012375590820665520LLU),
-	QU(11625327350536084927LLU), QU(14452017765243785417LLU),
-	QU( 9989342263518766305LLU), QU( 3640105471101803790LLU),
-	QU( 4749866455897513242LLU), QU(13963064946736312044LLU),
-	QU(10007416591973223791LLU), QU(18314132234717431115LLU),
-	QU( 3286596588617483450LLU), QU( 7726163455370818765LLU),
-	QU( 7575454721115379328LLU), QU( 5308331576437663422LLU),
-	QU(18288821894903530934LLU), QU( 8028405805410554106LLU),
-	QU(15744019832103296628LLU), QU(  149765559630932100LLU),
-	QU( 6137705557200071977LLU), QU(14513416315434803615LLU),
-	QU(11665702820128984473LLU), QU(  218926670505601386LLU),
-	QU( 6868675028717769519LLU), QU(15282016569441512302LLU),
-	QU( 5707000497782960236LLU), QU( 6671120586555079567LLU),
-	QU( 2194098052618985448LLU), QU(16849577895477330978LLU),
-	QU(12957148471017466283LLU), QU( 1997805535404859393LLU),
-	QU( 1180721060263860490LLU), QU(13206391310193756958LLU),
-	QU(12980208674461861797LLU), QU( 3825967775058875366LLU),
-	QU(17543433670782042631LLU), QU( 1518339070120322730LLU),
-	QU(16344584340890991669LLU), QU( 2611327165318529819LLU),
-	QU(11265022723283422529LLU), QU( 4001552800373196817LLU),
-	QU(14509595890079346161LLU), QU( 3528717165416234562LLU),
-	QU(18153222571501914072LLU), QU( 9387182977209744425LLU),
-	QU(10064342315985580021LLU), QU(11373678413215253977LLU),
-	QU( 2308457853228798099LLU), QU( 9729042942839545302LLU),
-	QU( 7833785471140127746LLU), QU( 6351049900319844436LLU),
-	QU(14454610627133496067LLU), QU(12533175683634819111LLU),
-	QU(15570163926716513029LLU), QU(13356980519185762498LLU)
+	KQU( 2100341266307895239), KQU( 8344256300489757943),
+	KQU(15687933285484243894), KQU( 8268620370277076319),
+	KQU(12371852309826545459), KQU( 8800491541730110238),
+	KQU(18113268950100835773), KQU( 2886823658884438119),
+	KQU( 3293667307248180724), KQU( 9307928143300172731),
+	KQU( 7688082017574293629), KQU(  900986224735166665),
+	KQU( 9977972710722265039), KQU( 6008205004994830552),
+	KQU(  546909104521689292), KQU( 7428471521869107594),
+	KQU(14777563419314721179), KQU(16116143076567350053),
+	KQU( 5322685342003142329), KQU( 4200427048445863473),
+	KQU( 4693092150132559146), KQU(13671425863759338582),
+	KQU( 6747117460737639916), KQU( 4732666080236551150),
+	KQU( 5912839950611941263), KQU( 3903717554504704909),
+	KQU( 2615667650256786818), KQU(10844129913887006352),
+	KQU(13786467861810997820), KQU(14267853002994021570),
+	KQU(13767807302847237439), KQU(16407963253707224617),
+	KQU( 4802498363698583497), KQU( 2523802839317209764),
+	KQU( 3822579397797475589), KQU( 8950320572212130610),
+	KQU( 3745623504978342534), KQU(16092609066068482806),
+	KQU( 9817016950274642398), KQU(10591660660323829098),
+	KQU(11751606650792815920), KQU( 5122873818577122211),
+	KQU(17209553764913936624), KQU( 6249057709284380343),
+	KQU(15088791264695071830), KQU(15344673071709851930),
+	KQU( 4345751415293646084), KQU( 2542865750703067928),
+	KQU(13520525127852368784), KQU(18294188662880997241),
+	KQU( 3871781938044881523), KQU( 2873487268122812184),
+	KQU(15099676759482679005), KQU(15442599127239350490),
+	KQU( 6311893274367710888), KQU( 3286118760484672933),
+	KQU( 4146067961333542189), KQU(13303942567897208770),
+	KQU( 8196013722255630418), KQU( 4437815439340979989),
+	KQU(15433791533450605135), KQU( 4254828956815687049),
+	KQU( 1310903207708286015), KQU(10529182764462398549),
+	KQU(14900231311660638810), KQU( 9727017277104609793),
+	KQU( 1821308310948199033), KQU(11628861435066772084),
+	KQU( 9469019138491546924), KQU( 3145812670532604988),
+	KQU( 9938468915045491919), KQU( 1562447430672662142),
+	KQU(13963995266697989134), KQU( 3356884357625028695),
+	KQU( 4499850304584309747), KQU( 8456825817023658122),
+	KQU(10859039922814285279), KQU( 8099512337972526555),
+	KQU(  348006375109672149), KQU(11919893998241688603),
+	KQU( 1104199577402948826), KQU(16689191854356060289),
+	KQU(10992552041730168078), KQU( 7243733172705465836),
+	KQU( 5668075606180319560), KQU(18182847037333286970),
+	KQU( 4290215357664631322), KQU( 4061414220791828613),
+	KQU(13006291061652989604), KQU( 7140491178917128798),
+	KQU(12703446217663283481), KQU( 5500220597564558267),
+	KQU(10330551509971296358), KQU(15958554768648714492),
+	KQU( 5174555954515360045), KQU( 1731318837687577735),
+	KQU( 3557700801048354857), KQU(13764012341928616198),
+	KQU(13115166194379119043), KQU( 7989321021560255519),
+	KQU( 2103584280905877040), KQU( 9230788662155228488),
+	KQU(16396629323325547654), KQU(  657926409811318051),
+	KQU(15046700264391400727), KQU( 5120132858771880830),
+	KQU( 7934160097989028561), KQU( 6963121488531976245),
+	KQU(17412329602621742089), KQU(15144843053931774092),
+	KQU(17204176651763054532), KQU(13166595387554065870),
+	KQU( 8590377810513960213), KQU( 5834365135373991938),
+	KQU( 7640913007182226243), KQU( 3479394703859418425),
+	KQU(16402784452644521040), KQU( 4993979809687083980),
+	KQU(13254522168097688865), KQU(15643659095244365219),
+	KQU( 5881437660538424982), KQU(11174892200618987379),
+	KQU(  254409966159711077), KQU(17158413043140549909),
+	KQU( 3638048789290376272), KQU( 1376816930299489190),
+	KQU( 4622462095217761923), KQU(15086407973010263515),
+	KQU(13253971772784692238), KQU( 5270549043541649236),
+	KQU(11182714186805411604), KQU(12283846437495577140),
+	KQU( 5297647149908953219), KQU(10047451738316836654),
+	KQU( 4938228100367874746), KQU(12328523025304077923),
+	KQU( 3601049438595312361), KQU( 9313624118352733770),
+	KQU(13322966086117661798), KQU(16660005705644029394),
+	KQU(11337677526988872373), KQU(13869299102574417795),
+	KQU(15642043183045645437), KQU( 3021755569085880019),
+	KQU( 4979741767761188161), KQU(13679979092079279587),
+	KQU( 3344685842861071743), KQU(13947960059899588104),
+	KQU(  305806934293368007), KQU( 5749173929201650029),
+	KQU(11123724852118844098), KQU(15128987688788879802),
+	KQU(15251651211024665009), KQU( 7689925933816577776),
+	KQU(16732804392695859449), KQU(17087345401014078468),
+	KQU(14315108589159048871), KQU( 4820700266619778917),
+	KQU(16709637539357958441), KQU( 4936227875177351374),
+	KQU( 2137907697912987247), KQU(11628565601408395420),
+	KQU( 2333250549241556786), KQU( 5711200379577778637),
+	KQU( 5170680131529031729), KQU(12620392043061335164),
+	KQU(   95363390101096078), KQU( 5487981914081709462),
+	KQU( 1763109823981838620), KQU( 3395861271473224396),
+	KQU( 1300496844282213595), KQU( 6894316212820232902),
+	KQU(10673859651135576674), KQU( 5911839658857903252),
+	KQU(17407110743387299102), KQU( 8257427154623140385),
+	KQU(11389003026741800267), KQU( 4070043211095013717),
+	KQU(11663806997145259025), KQU(15265598950648798210),
+	KQU(  630585789434030934), KQU( 3524446529213587334),
+	KQU( 7186424168495184211), KQU(10806585451386379021),
+	KQU(11120017753500499273), KQU( 1586837651387701301),
+	KQU(17530454400954415544), KQU( 9991670045077880430),
+	KQU( 7550997268990730180), KQU( 8640249196597379304),
+	KQU( 3522203892786893823), KQU(10401116549878854788),
+	KQU(13690285544733124852), KQU( 8295785675455774586),
+	KQU(15535716172155117603), KQU( 3112108583723722511),
+	KQU(17633179955339271113), KQU(18154208056063759375),
+	KQU( 1866409236285815666), KQU(13326075895396412882),
+	KQU( 8756261842948020025), KQU( 6281852999868439131),
+	KQU(15087653361275292858), KQU(10333923911152949397),
+	KQU( 5265567645757408500), KQU(12728041843210352184),
+	KQU( 6347959327507828759), KQU(  154112802625564758),
+	KQU(18235228308679780218), KQU( 3253805274673352418),
+	KQU( 4849171610689031197), KQU(17948529398340432518),
+	KQU(13803510475637409167), KQU(13506570190409883095),
+	KQU(15870801273282960805), KQU( 8451286481299170773),
+	KQU( 9562190620034457541), KQU( 8518905387449138364),
+	KQU(12681306401363385655), KQU( 3788073690559762558),
+	KQU( 5256820289573487769), KQU( 2752021372314875467),
+	KQU( 6354035166862520716), KQU( 4328956378309739069),
+	KQU(  449087441228269600), KQU( 5533508742653090868),
+	KQU( 1260389420404746988), KQU(18175394473289055097),
+	KQU( 1535467109660399420), KQU( 8818894282874061442),
+	KQU(12140873243824811213), KQU(15031386653823014946),
+	KQU( 1286028221456149232), KQU( 6329608889367858784),
+	KQU( 9419654354945132725), KQU( 6094576547061672379),
+	KQU(17706217251847450255), KQU( 1733495073065878126),
+	KQU(16918923754607552663), KQU( 8881949849954945044),
+	KQU(12938977706896313891), KQU(14043628638299793407),
+	KQU(18393874581723718233), KQU( 6886318534846892044),
+	KQU(14577870878038334081), KQU(13541558383439414119),
+	KQU(13570472158807588273), KQU(18300760537910283361),
+	KQU(  818368572800609205), KQU( 1417000585112573219),
+	KQU(12337533143867683655), KQU(12433180994702314480),
+	KQU(  778190005829189083), KQU(13667356216206524711),
+	KQU( 9866149895295225230), KQU(11043240490417111999),
+	KQU( 1123933826541378598), KQU( 6469631933605123610),
+	KQU(14508554074431980040), KQU(13918931242962026714),
+	KQU( 2870785929342348285), KQU(14786362626740736974),
+	KQU(13176680060902695786), KQU( 9591778613541679456),
+	KQU( 9097662885117436706), KQU(  749262234240924947),
+	KQU( 1944844067793307093), KQU( 4339214904577487742),
+	KQU( 8009584152961946551), KQU(16073159501225501777),
+	KQU( 3335870590499306217), KQU(17088312653151202847),
+	KQU( 3108893142681931848), KQU(16636841767202792021),
+	KQU(10423316431118400637), KQU( 8008357368674443506),
+	KQU(11340015231914677875), KQU(17687896501594936090),
+	KQU(15173627921763199958), KQU(  542569482243721959),
+	KQU(15071714982769812975), KQU( 4466624872151386956),
+	KQU( 1901780715602332461), KQU( 9822227742154351098),
+	KQU( 1479332892928648780), KQU( 6981611948382474400),
+	KQU( 7620824924456077376), KQU(14095973329429406782),
+	KQU( 7902744005696185404), KQU(15830577219375036920),
+	KQU(10287076667317764416), KQU(12334872764071724025),
+	KQU( 4419302088133544331), KQU(14455842851266090520),
+	KQU(12488077416504654222), KQU( 7953892017701886766),
+	KQU( 6331484925529519007), KQU( 4902145853785030022),
+	KQU(17010159216096443073), KQU(11945354668653886087),
+	KQU(15112022728645230829), KQU(17363484484522986742),
+	KQU( 4423497825896692887), KQU( 8155489510809067471),
+	KQU(  258966605622576285), KQU( 5462958075742020534),
+	KQU( 6763710214913276228), KQU( 2368935183451109054),
+	KQU(14209506165246453811), KQU( 2646257040978514881),
+	KQU( 3776001911922207672), KQU( 1419304601390147631),
+	KQU(14987366598022458284), KQU( 3977770701065815721),
+	KQU(  730820417451838898), KQU( 3982991703612885327),
+	KQU( 2803544519671388477), KQU(17067667221114424649),
+	KQU( 2922555119737867166), KQU( 1989477584121460932),
+	KQU(15020387605892337354), KQU( 9293277796427533547),
+	KQU(10722181424063557247), KQU(16704542332047511651),
+	KQU( 5008286236142089514), KQU(16174732308747382540),
+	KQU(17597019485798338402), KQU(13081745199110622093),
+	KQU( 8850305883842258115), KQU(12723629125624589005),
+	KQU( 8140566453402805978), KQU(15356684607680935061),
+	KQU(14222190387342648650), KQU(11134610460665975178),
+	KQU( 1259799058620984266), KQU(13281656268025610041),
+	KQU(  298262561068153992), KQU(12277871700239212922),
+	KQU(13911297774719779438), KQU(16556727962761474934),
+	KQU(17903010316654728010), KQU( 9682617699648434744),
+	KQU(14757681836838592850), KQU( 1327242446558524473),
+	KQU(11126645098780572792), KQU( 1883602329313221774),
+	KQU( 2543897783922776873), KQU(15029168513767772842),
+	KQU(12710270651039129878), KQU(16118202956069604504),
+	KQU(15010759372168680524), KQU( 2296827082251923948),
+	KQU(10793729742623518101), KQU(13829764151845413046),
+	KQU(17769301223184451213), KQU( 3118268169210783372),
+	KQU(17626204544105123127), KQU( 7416718488974352644),
+	KQU(10450751996212925994), KQU( 9352529519128770586),
+	KQU(  259347569641110140), KQU( 8048588892269692697),
+	KQU( 1774414152306494058), KQU(10669548347214355622),
+	KQU(13061992253816795081), KQU(18432677803063861659),
+	KQU( 8879191055593984333), KQU(12433753195199268041),
+	KQU(14919392415439730602), KQU( 6612848378595332963),
+	KQU( 6320986812036143628), KQU(10465592420226092859),
+	KQU( 4196009278962570808), KQU( 3747816564473572224),
+	KQU(17941203486133732898), KQU( 2350310037040505198),
+	KQU( 5811779859134370113), KQU(10492109599506195126),
+	KQU( 7699650690179541274), KQU( 1954338494306022961),
+	KQU(14095816969027231152), KQU( 5841346919964852061),
+	KQU(14945969510148214735), KQU( 3680200305887550992),
+	KQU( 6218047466131695792), KQU( 8242165745175775096),
+	KQU(11021371934053307357), KQU( 1265099502753169797),
+	KQU( 4644347436111321718), KQU( 3609296916782832859),
+	KQU( 8109807992218521571), KQU(18387884215648662020),
+	KQU(14656324896296392902), KQU(17386819091238216751),
+	KQU(17788300878582317152), KQU( 7919446259742399591),
+	KQU( 4466613134576358004), KQU(12928181023667938509),
+	KQU(13147446154454932030), KQU(16552129038252734620),
+	KQU( 8395299403738822450), KQU(11313817655275361164),
+	KQU(  434258809499511718), KQU( 2074882104954788676),
+	KQU( 7929892178759395518), KQU( 9006461629105745388),
+	KQU( 5176475650000323086), KQU(11128357033468341069),
+	KQU(12026158851559118955), KQU(14699716249471156500),
+	KQU(  448982497120206757), KQU( 4156475356685519900),
+	KQU( 6063816103417215727), KQU(10073289387954971479),
+	KQU( 8174466846138590962), KQU( 2675777452363449006),
+	KQU( 9090685420572474281), KQU( 6659652652765562060),
+	KQU(12923120304018106621), KQU(11117480560334526775),
+	KQU(  937910473424587511), KQU( 1838692113502346645),
+	KQU(11133914074648726180), KQU( 7922600945143884053),
+	KQU(13435287702700959550), KQU( 5287964921251123332),
+	KQU(11354875374575318947), KQU(17955724760748238133),
+	KQU(13728617396297106512), KQU( 4107449660118101255),
+	KQU( 1210269794886589623), KQU(11408687205733456282),
+	KQU( 4538354710392677887), KQU(13566803319341319267),
+	KQU(17870798107734050771), KQU( 3354318982568089135),
+	KQU( 9034450839405133651), KQU(13087431795753424314),
+	KQU(  950333102820688239), KQU( 1968360654535604116),
+	KQU(16840551645563314995), KQU( 8867501803892924995),
+	KQU(11395388644490626845), KQU( 1529815836300732204),
+	KQU(13330848522996608842), KQU( 1813432878817504265),
+	KQU( 2336867432693429560), KQU(15192805445973385902),
+	KQU( 2528593071076407877), KQU(  128459777936689248),
+	KQU( 9976345382867214866), KQU( 6208885766767996043),
+	KQU(14982349522273141706), KQU( 3099654362410737822),
+	KQU(13776700761947297661), KQU( 8806185470684925550),
+	KQU( 8151717890410585321), KQU(  640860591588072925),
+	KQU(14592096303937307465), KQU( 9056472419613564846),
+	KQU(14861544647742266352), KQU(12703771500398470216),
+	KQU( 3142372800384138465), KQU( 6201105606917248196),
+	KQU(18337516409359270184), KQU(15042268695665115339),
+	KQU(15188246541383283846), KQU(12800028693090114519),
+	KQU( 5992859621101493472), KQU(18278043971816803521),
+	KQU( 9002773075219424560), KQU( 7325707116943598353),
+	KQU( 7930571931248040822), KQU( 5645275869617023448),
+	KQU( 7266107455295958487), KQU( 4363664528273524411),
+	KQU(14313875763787479809), KQU(17059695613553486802),
+	KQU( 9247761425889940932), KQU(13704726459237593128),
+	KQU( 2701312427328909832), KQU(17235532008287243115),
+	KQU(14093147761491729538), KQU( 6247352273768386516),
+	KQU( 8268710048153268415), KQU( 7985295214477182083),
+	KQU(15624495190888896807), KQU( 3772753430045262788),
+	KQU( 9133991620474991698), KQU( 5665791943316256028),
+	KQU( 7551996832462193473), KQU(13163729206798953877),
+	KQU( 9263532074153846374), KQU( 1015460703698618353),
+	KQU(17929874696989519390), KQU(18257884721466153847),
+	KQU(16271867543011222991), KQU( 3905971519021791941),
+	KQU(16814488397137052085), KQU( 1321197685504621613),
+	KQU( 2870359191894002181), KQU(14317282970323395450),
+	KQU(13663920845511074366), KQU( 2052463995796539594),
+	KQU(14126345686431444337), KQU( 1727572121947022534),
+	KQU(17793552254485594241), KQU( 6738857418849205750),
+	KQU( 1282987123157442952), KQU(16655480021581159251),
+	KQU( 6784587032080183866), KQU(14726758805359965162),
+	KQU( 7577995933961987349), KQU(12539609320311114036),
+	KQU(10789773033385439494), KQU( 8517001497411158227),
+	KQU(10075543932136339710), KQU(14838152340938811081),
+	KQU( 9560840631794044194), KQU(17445736541454117475),
+	KQU(10633026464336393186), KQU(15705729708242246293),
+	KQU( 1117517596891411098), KQU( 4305657943415886942),
+	KQU( 4948856840533979263), KQU(16071681989041789593),
+	KQU(13723031429272486527), KQU( 7639567622306509462),
+	KQU(12670424537483090390), KQU( 9715223453097197134),
+	KQU( 5457173389992686394), KQU(  289857129276135145),
+	KQU(17048610270521972512), KQU(  692768013309835485),
+	KQU(14823232360546632057), KQU(18218002361317895936),
+	KQU( 3281724260212650204), KQU(16453957266549513795),
+	KQU( 8592711109774511881), KQU(  929825123473369579),
+	KQU(15966784769764367791), KQU( 9627344291450607588),
+	KQU(10849555504977813287), KQU( 9234566913936339275),
+	KQU( 6413807690366911210), KQU(10862389016184219267),
+	KQU(13842504799335374048), KQU( 1531994113376881174),
+	KQU( 2081314867544364459), KQU(16430628791616959932),
+	KQU( 8314714038654394368), KQU( 9155473892098431813),
+	KQU(12577843786670475704), KQU( 4399161106452401017),
+	KQU( 1668083091682623186), KQU( 1741383777203714216),
+	KQU( 2162597285417794374), KQU(15841980159165218736),
+	KQU( 1971354603551467079), KQU( 1206714764913205968),
+	KQU( 4790860439591272330), KQU(14699375615594055799),
+	KQU( 8374423871657449988), KQU(10950685736472937738),
+	KQU(  697344331343267176), KQU(10084998763118059810),
+	KQU(12897369539795983124), KQU(12351260292144383605),
+	KQU( 1268810970176811234), KQU( 7406287800414582768),
+	KQU(  516169557043807831), KQU( 5077568278710520380),
+	KQU( 3828791738309039304), KQU( 7721974069946943610),
+	KQU( 3534670260981096460), KQU( 4865792189600584891),
+	KQU(16892578493734337298), KQU( 9161499464278042590),
+	KQU(11976149624067055931), KQU(13219479887277343990),
+	KQU(14161556738111500680), KQU(14670715255011223056),
+	KQU( 4671205678403576558), KQU(12633022931454259781),
+	KQU(14821376219869187646), KQU(  751181776484317028),
+	KQU( 2192211308839047070), KQU(11787306362361245189),
+	KQU(10672375120744095707), KQU( 4601972328345244467),
+	KQU(15457217788831125879), KQU( 8464345256775460809),
+	KQU(10191938789487159478), KQU( 6184348739615197613),
+	KQU(11425436778806882100), KQU( 2739227089124319793),
+	KQU(  461464518456000551), KQU( 4689850170029177442),
+	KQU( 6120307814374078625), KQU(11153579230681708671),
+	KQU( 7891721473905347926), KQU(10281646937824872400),
+	KQU( 3026099648191332248), KQU( 8666750296953273818),
+	KQU(14978499698844363232), KQU(13303395102890132065),
+	KQU( 8182358205292864080), KQU(10560547713972971291),
+	KQU(11981635489418959093), KQU( 3134621354935288409),
+	KQU(11580681977404383968), KQU(14205530317404088650),
+	KQU( 5997789011854923157), KQU(13659151593432238041),
+	KQU(11664332114338865086), KQU( 7490351383220929386),
+	KQU( 7189290499881530378), KQU(15039262734271020220),
+	KQU( 2057217285976980055), KQU(  555570804905355739),
+	KQU(11235311968348555110), KQU(13824557146269603217),
+	KQU(16906788840653099693), KQU( 7222878245455661677),
+	KQU( 5245139444332423756), KQU( 4723748462805674292),
+	KQU(12216509815698568612), KQU(17402362976648951187),
+	KQU(17389614836810366768), KQU( 4880936484146667711),
+	KQU( 9085007839292639880), KQU(13837353458498535449),
+	KQU(11914419854360366677), KQU(16595890135313864103),
+	KQU( 6313969847197627222), KQU(18296909792163910431),
+	KQU(10041780113382084042), KQU( 2499478551172884794),
+	KQU(11057894246241189489), KQU( 9742243032389068555),
+	KQU(12838934582673196228), KQU(13437023235248490367),
+	KQU(13372420669446163240), KQU( 6752564244716909224),
+	KQU( 7157333073400313737), KQU(12230281516370654308),
+	KQU( 1182884552219419117), KQU( 2955125381312499218),
+	KQU(10308827097079443249), KQU( 1337648572986534958),
+	KQU(16378788590020343939), KQU(  108619126514420935),
+	KQU( 3990981009621629188), KQU( 5460953070230946410),
+	KQU( 9703328329366531883), KQU(13166631489188077236),
+	KQU( 1104768831213675170), KQU( 3447930458553877908),
+	KQU( 8067172487769945676), KQU( 5445802098190775347),
+	KQU( 3244840981648973873), KQU(17314668322981950060),
+	KQU( 5006812527827763807), KQU(18158695070225526260),
+	KQU( 2824536478852417853), KQU(13974775809127519886),
+	KQU( 9814362769074067392), KQU(17276205156374862128),
+	KQU(11361680725379306967), KQU( 3422581970382012542),
+	KQU(11003189603753241266), KQU(11194292945277862261),
+	KQU( 6839623313908521348), KQU(11935326462707324634),
+	KQU( 1611456788685878444), KQU(13112620989475558907),
+	KQU(  517659108904450427), KQU(13558114318574407624),
+	KQU(15699089742731633077), KQU( 4988979278862685458),
+	KQU( 8111373583056521297), KQU( 3891258746615399627),
+	KQU( 8137298251469718086), KQU(12748663295624701649),
+	KQU( 4389835683495292062), KQU( 5775217872128831729),
+	KQU( 9462091896405534927), KQU( 8498124108820263989),
+	KQU( 8059131278842839525), KQU(10503167994254090892),
+	KQU(11613153541070396656), KQU(18069248738504647790),
+	KQU(  570657419109768508), KQU( 3950574167771159665),
+	KQU( 5514655599604313077), KQU( 2908460854428484165),
+	KQU(10777722615935663114), KQU(12007363304839279486),
+	KQU( 9800646187569484767), KQU( 8795423564889864287),
+	KQU(14257396680131028419), KQU( 6405465117315096498),
+	KQU( 7939411072208774878), KQU(17577572378528990006),
+	KQU(14785873806715994850), KQU(16770572680854747390),
+	KQU(18127549474419396481), KQU(11637013449455757750),
+	KQU(14371851933996761086), KQU( 3601181063650110280),
+	KQU( 4126442845019316144), KQU(10198287239244320669),
+	KQU(18000169628555379659), KQU(18392482400739978269),
+	KQU( 6219919037686919957), KQU( 3610085377719446052),
+	KQU( 2513925039981776336), KQU(16679413537926716955),
+	KQU(12903302131714909434), KQU( 5581145789762985009),
+	KQU(12325955044293303233), KQU(17216111180742141204),
+	KQU( 6321919595276545740), KQU( 3507521147216174501),
+	KQU( 9659194593319481840), KQU(11473976005975358326),
+	KQU(14742730101435987026), KQU(  492845897709954780),
+	KQU(16976371186162599676), KQU(17712703422837648655),
+	KQU( 9881254778587061697), KQU( 8413223156302299551),
+	KQU( 1563841828254089168), KQU( 9996032758786671975),
+	KQU(  138877700583772667), KQU(13003043368574995989),
+	KQU( 4390573668650456587), KQU( 8610287390568126755),
+	KQU(15126904974266642199), KQU( 6703637238986057662),
+	KQU( 2873075592956810157), KQU( 6035080933946049418),
+	KQU(13382846581202353014), KQU( 7303971031814642463),
+	KQU(18418024405307444267), KQU( 5847096731675404647),
+	KQU( 4035880699639842500), KQU(11525348625112218478),
+	KQU( 3041162365459574102), KQU( 2604734487727986558),
+	KQU(15526341771636983145), KQU(14556052310697370254),
+	KQU(12997787077930808155), KQU( 9601806501755554499),
+	KQU(11349677952521423389), KQU(14956777807644899350),
+	KQU(16559736957742852721), KQU(12360828274778140726),
+	KQU( 6685373272009662513), KQU(16932258748055324130),
+	KQU(15918051131954158508), KQU( 1692312913140790144),
+	KQU(  546653826801637367), KQU( 5341587076045986652),
+	KQU(14975057236342585662), KQU(12374976357340622412),
+	KQU(10328833995181940552), KQU(12831807101710443149),
+	KQU(10548514914382545716), KQU( 2217806727199715993),
+	KQU(12627067369242845138), KQU( 4598965364035438158),
+	KQU(  150923352751318171), KQU(14274109544442257283),
+	KQU( 4696661475093863031), KQU( 1505764114384654516),
+	KQU(10699185831891495147), KQU( 2392353847713620519),
+	KQU( 3652870166711788383), KQU( 8640653276221911108),
+	KQU( 3894077592275889704), KQU( 4918592872135964845),
+	KQU(16379121273281400789), KQU(12058465483591683656),
+	KQU(11250106829302924945), KQU( 1147537556296983005),
+	KQU( 6376342756004613268), KQU(14967128191709280506),
+	KQU(18007449949790627628), KQU( 9497178279316537841),
+	KQU( 7920174844809394893), KQU(10037752595255719907),
+	KQU(15875342784985217697), KQU(15311615921712850696),
+	KQU( 9552902652110992950), KQU(14054979450099721140),
+	KQU( 5998709773566417349), KQU(18027910339276320187),
+	KQU( 8223099053868585554), KQU( 7842270354824999767),
+	KQU( 4896315688770080292), KQU(12969320296569787895),
+	KQU( 2674321489185759961), KQU( 4053615936864718439),
+	KQU(11349775270588617578), KQU( 4743019256284553975),
+	KQU( 5602100217469723769), KQU(14398995691411527813),
+	KQU( 7412170493796825470), KQU(  836262406131744846),
+	KQU( 8231086633845153022), KQU( 5161377920438552287),
+	KQU( 8828731196169924949), KQU(16211142246465502680),
+	KQU( 3307990879253687818), KQU( 5193405406899782022),
+	KQU( 8510842117467566693), KQU( 6070955181022405365),
+	KQU(14482950231361409799), KQU(12585159371331138077),
+	KQU( 3511537678933588148), KQU( 2041849474531116417),
+	KQU(10944936685095345792), KQU(18303116923079107729),
+	KQU( 2720566371239725320), KQU( 4958672473562397622),
+	KQU( 3032326668253243412), KQU(13689418691726908338),
+	KQU( 1895205511728843996), KQU( 8146303515271990527),
+	KQU(16507343500056113480), KQU(  473996939105902919),
+	KQU( 9897686885246881481), KQU(14606433762712790575),
+	KQU( 6732796251605566368), KQU( 1399778120855368916),
+	KQU(  935023885182833777), KQU(16066282816186753477),
+	KQU( 7291270991820612055), KQU(17530230393129853844),
+	KQU(10223493623477451366), KQU(15841725630495676683),
+	KQU(17379567246435515824), KQU( 8588251429375561971),
+	KQU(18339511210887206423), KQU(17349587430725976100),
+	KQU(12244876521394838088), KQU( 6382187714147161259),
+	KQU(12335807181848950831), KQU(16948885622305460665),
+	KQU(13755097796371520506), KQU(14806740373324947801),
+	KQU( 4828699633859287703), KQU( 8209879281452301604),
+	KQU(12435716669553736437), KQU(13970976859588452131),
+	KQU( 6233960842566773148), KQU(12507096267900505759),
+	KQU( 1198713114381279421), KQU(14989862731124149015),
+	KQU(15932189508707978949), KQU( 2526406641432708722),
+	KQU(   29187427817271982), KQU( 1499802773054556353),
+	KQU(10816638187021897173), KQU( 5436139270839738132),
+	KQU( 6659882287036010082), KQU( 2154048955317173697),
+	KQU(10887317019333757642), KQU(16281091802634424955),
+	KQU(10754549879915384901), KQU(10760611745769249815),
+	KQU( 2161505946972504002), KQU( 5243132808986265107),
+	KQU(10129852179873415416), KQU(  710339480008649081),
+	KQU( 7802129453068808528), KQU(17967213567178907213),
+	KQU(15730859124668605599), KQU(13058356168962376502),
+	KQU( 3701224985413645909), KQU(14464065869149109264),
+	KQU( 9959272418844311646), KQU(10157426099515958752),
+	KQU(14013736814538268528), KQU(17797456992065653951),
+	KQU(17418878140257344806), KQU(15457429073540561521),
+	KQU( 2184426881360949378), KQU( 2062193041154712416),
+	KQU( 8553463347406931661), KQU( 4913057625202871854),
+	KQU( 2668943682126618425), KQU(17064444737891172288),
+	KQU( 4997115903913298637), KQU(12019402608892327416),
+	KQU(17603584559765897352), KQU(11367529582073647975),
+	KQU( 8211476043518436050), KQU( 8676849804070323674),
+	KQU(18431829230394475730), KQU(10490177861361247904),
+	KQU( 9508720602025651349), KQU( 7409627448555722700),
+	KQU( 5804047018862729008), KQU(11943858176893142594),
+	KQU(11908095418933847092), KQU( 5415449345715887652),
+	KQU( 1554022699166156407), KQU( 9073322106406017161),
+	KQU( 7080630967969047082), KQU(18049736940860732943),
+	KQU(12748714242594196794), KQU( 1226992415735156741),
+	KQU(17900981019609531193), KQU(11720739744008710999),
+	KQU( 3006400683394775434), KQU(11347974011751996028),
+	KQU( 3316999628257954608), KQU( 8384484563557639101),
+	KQU(18117794685961729767), KQU( 1900145025596618194),
+	KQU(17459527840632892676), KQU( 5634784101865710994),
+	KQU( 7918619300292897158), KQU( 3146577625026301350),
+	KQU( 9955212856499068767), KQU( 1873995843681746975),
+	KQU( 1561487759967972194), KQU( 8322718804375878474),
+	KQU(11300284215327028366), KQU( 4667391032508998982),
+	KQU( 9820104494306625580), KQU(17922397968599970610),
+	KQU( 1784690461886786712), KQU(14940365084341346821),
+	KQU( 5348719575594186181), KQU(10720419084507855261),
+	KQU(14210394354145143274), KQU( 2426468692164000131),
+	KQU(16271062114607059202), KQU(14851904092357070247),
+	KQU( 6524493015693121897), KQU( 9825473835127138531),
+	KQU(14222500616268569578), KQU(15521484052007487468),
+	KQU(14462579404124614699), KQU(11012375590820665520),
+	KQU(11625327350536084927), KQU(14452017765243785417),
+	KQU( 9989342263518766305), KQU( 3640105471101803790),
+	KQU( 4749866455897513242), KQU(13963064946736312044),
+	KQU(10007416591973223791), KQU(18314132234717431115),
+	KQU( 3286596588617483450), KQU( 7726163455370818765),
+	KQU( 7575454721115379328), KQU( 5308331576437663422),
+	KQU(18288821894903530934), KQU( 8028405805410554106),
+	KQU(15744019832103296628), KQU(  149765559630932100),
+	KQU( 6137705557200071977), KQU(14513416315434803615),
+	KQU(11665702820128984473), KQU(  218926670505601386),
+	KQU( 6868675028717769519), KQU(15282016569441512302),
+	KQU( 5707000497782960236), KQU( 6671120586555079567),
+	KQU( 2194098052618985448), KQU(16849577895477330978),
+	KQU(12957148471017466283), KQU( 1997805535404859393),
+	KQU( 1180721060263860490), KQU(13206391310193756958),
+	KQU(12980208674461861797), KQU( 3825967775058875366),
+	KQU(17543433670782042631), KQU( 1518339070120322730),
+	KQU(16344584340890991669), KQU( 2611327165318529819),
+	KQU(11265022723283422529), KQU( 4001552800373196817),
+	KQU(14509595890079346161), KQU( 3528717165416234562),
+	KQU(18153222571501914072), KQU( 9387182977209744425),
+	KQU(10064342315985580021), KQU(11373678413215253977),
+	KQU( 2308457853228798099), KQU( 9729042942839545302),
+	KQU( 7833785471140127746), KQU( 6351049900319844436),
+	KQU(14454610627133496067), KQU(12533175683634819111),
+	KQU(15570163926716513029), KQU(13356980519185762498)
 };
 
 TEST_BEGIN(test_gen_rand_32)
diff --git a/src/jemalloc/test/unit/hash.c b/src/jemalloc/test/unit/hash.c
index abb394ac07719e1a9365ffa1cce527cb20223f04..77a8cede92ad8567d56c62edeac089e7a0df741f 100644
--- a/src/jemalloc/test/unit/hash.c
+++ b/src/jemalloc/test/unit/hash.c
@@ -64,8 +64,8 @@ hash_variant_verify(hash_variant_t variant)
 {
 	const size_t hashbytes = hash_variant_bits(variant) / 8;
 	uint8_t key[256];
-	uint8_t hashes[hashbytes * 256];
-	uint8_t final[hashbytes];
+	VARIABLE_ARRAY(uint8_t, hashes, hashbytes * 256);
+	VARIABLE_ARRAY(uint8_t, final, hashbytes);
 	unsigned i;
 	uint32_t computed, expected;
 
diff --git a/src/jemalloc/test/unit/junk.c b/src/jemalloc/test/unit/junk.c
index 85bbf9e2bd35a082462fa7fa1c11d96de3ccf1f4..301428f2cb119eacb6d1bc0c134572a0199a520c 100644
--- a/src/jemalloc/test/unit/junk.c
+++ b/src/jemalloc/test/unit/junk.c
@@ -92,12 +92,9 @@ test_junk(size_t sz_min, size_t sz_max)
 			s = (char *)rallocx(s, sz+1, 0);
 			assert_ptr_not_null((void *)s,
 			    "Unexpected rallocx() failure");
-			if (!config_mremap || sz+1 <= arena_maxclass) {
-				assert_ptr_eq(most_recently_junked, junked,
-				    "Expected region of size %zu to be "
-				    "junk-filled",
-				    sz);
-			}
+			assert_ptr_eq(most_recently_junked, junked,
+			    "Expected region of size %zu to be junk-filled",
+			    sz);
 		}
 	}
 
diff --git a/src/jemalloc/test/unit/mallctl.c b/src/jemalloc/test/unit/mallctl.c
index 31fb81057641fe1d6cea0bb3b9ea12258e2e2fdc..9c064bddc6cd28d839b7ca567f6d3883cab83303 100644
--- a/src/jemalloc/test/unit/mallctl.c
+++ b/src/jemalloc/test/unit/mallctl.c
@@ -101,16 +101,32 @@ TEST_END
 
 TEST_BEGIN(test_mallctlnametomib_short_mib)
 {
-	size_t mib[4];
+	size_t mib[6];
 	size_t miblen;
+	void *mem;
+	pool_t *pool;
+	unsigned npools;
+	size_t sz = sizeof(npools);
 
-	miblen = 3;
-	mib[3] = 42;
-	assert_d_eq(mallctlnametomib("arenas.bin.0.nregs", mib, &miblen), 0,
+	mem = calloc(1, POOL_MINIMAL_SIZE);
+	assert_ptr_ne(mem, NULL, "Unexpected calloc() failure");
+	pool = je_pool_create(mem, POOL_MINIMAL_SIZE, 1);
+
+	assert_ptr_ne((void*)pool, NULL, "Unexpected je_pool_create() failure");
+	assert_d_eq(mallctl("pools.npools", &npools, &sz, NULL, 0), 0,
+	    "Unexpected mallctl() failure");
+	assert_u_eq(npools, 2, "Unexpected number of pools");
+
+	miblen = 5;
+	mib[5] = 42;
+	assert_d_eq(mallctlnametomib("pool.1.arenas.bin.0.nregs", mib, &miblen), 0,
 	    "Unexpected mallctlnametomib() failure");
-	assert_zu_eq(miblen, 3, "Unexpected mib output length");
-	assert_zu_eq(mib[3], 42,
+	assert_zu_eq(miblen, 5, "Unexpected mib output length");
+	assert_zu_eq(mib[5], 42,
 	    "mallctlnametomib() wrote past the end of the input mib");
+
+	je_pool_delete(pool);
+	free(mem);
 }
 TEST_END
 
@@ -127,10 +143,8 @@ TEST_BEGIN(test_mallctl_config)
 } while (0)
 
 	TEST_MALLCTL_CONFIG(debug);
-	TEST_MALLCTL_CONFIG(dss);
 	TEST_MALLCTL_CONFIG(fill);
 	TEST_MALLCTL_CONFIG(lazy_lock);
-	TEST_MALLCTL_CONFIG(mremap);
 	TEST_MALLCTL_CONFIG(munmap);
 	TEST_MALLCTL_CONFIG(prof);
 	TEST_MALLCTL_CONFIG(prof_libgcc);
@@ -171,7 +185,6 @@ TEST_BEGIN(test_mallctl_opt)
 	TEST_MALLCTL_OPT(bool, redzone, fill);
 	TEST_MALLCTL_OPT(bool, zero, fill);
 	TEST_MALLCTL_OPT(bool, utrace, utrace);
-	TEST_MALLCTL_OPT(bool, valgrind, valgrind);
 	TEST_MALLCTL_OPT(bool, xmalloc, xmalloc);
 	TEST_MALLCTL_OPT(bool, tcache, tcache);
 	TEST_MALLCTL_OPT(size_t, lg_tcache_max, tcache);
@@ -189,23 +202,74 @@ TEST_BEGIN(test_mallctl_opt)
 }
 TEST_END
 
+
+/*
+ * create a couple of pools and check their size
+ * using mib feature
+ */
+TEST_BEGIN(test_mallctl_with_multiple_pools)
+{
+#define NPOOLS 4
+	pool_t *pools[NPOOLS];
+	void *mem;
+	unsigned npools;
+	int i;
+	size_t sz = sizeof(npools);
+	size_t mib[4], miblen;
+
+	mem = calloc(NPOOLS, POOL_MINIMAL_SIZE);
+	assert_ptr_ne(mem, NULL, "Unexpected calloc() failure");
+
+	for (i = 0; i < NPOOLS; ++i) {
+		pools[i] = je_pool_create( mem + (i*POOL_MINIMAL_SIZE), POOL_MINIMAL_SIZE, 1);
+		assert_ptr_ne( (void*)pools[i], NULL, "Unexpected je_pool_create() failure");
+	}
+
+	assert_d_eq(mallctl("pools.npools", &npools, &sz, NULL, 0), 0,
+	    "Unexpected mallctl() failure");
+	assert_u_eq(npools, NPOOLS+1, "Unexpected number of pools");
+
+	miblen = 4;
+	assert_d_eq(mallctlnametomib("pool.0.arenas.narenas", mib, &miblen), 0,
+	    "Unexpected mallctlnametomib() failure");
+
+	/*
+	 * This loop does not use local variable pools.
+	 * Moreover we ommit pool[0].
+	 */
+	for (i = 1; i <= NPOOLS; ++i) {
+		unsigned narenas;
+		mib[1] = i;
+		sz = sizeof(narenas);
+		assert_d_eq(mallctlbymib(mib, miblen, &narenas, &sz, NULL, 0),
+		    0, "Unexpected mallctlbymib() failure");
+	}
+
+	for (i = 0; i < NPOOLS; ++i) {
+		je_pool_delete( pools[i]);
+	}
+	free(mem);
+#undef NPOOLS
+}
+TEST_END
+
 TEST_BEGIN(test_manpage_example)
 {
 	unsigned nbins, i;
-	size_t mib[4];
+	size_t mib[6];
 	size_t len, miblen;
 
 	len = sizeof(nbins);
-	assert_d_eq(mallctl("arenas.nbins", &nbins, &len, NULL, 0), 0,
+	assert_d_eq(mallctl("pool.0.arenas.nbins", &nbins, &len, NULL, 0), 0,
 	    "Unexpected mallctl() failure");
 
-	miblen = 4;
-	assert_d_eq(mallctlnametomib("arenas.bin.0.size", mib, &miblen), 0,
+	miblen = 6;
+	assert_d_eq(mallctlnametomib("pool.0.arenas.bin.0.size", mib, &miblen), 0,
 	    "Unexpected mallctlnametomib() failure");
 	for (i = 0; i < nbins; i++) {
 		size_t bin_size;
 
-		mib[2] = i;
+		mib[4] = i;
 		len = sizeof(bin_size);
 		assert_d_eq(mallctlbymib(mib, miblen, &bin_size, &len, NULL, 0),
 		    0, "Unexpected mallctlbymib() failure");
@@ -219,14 +283,14 @@ TEST_BEGIN(test_thread_arena)
 	unsigned arena_old, arena_new, narenas;
 	size_t sz = sizeof(unsigned);
 
-	assert_d_eq(mallctl("arenas.narenas", &narenas, &sz, NULL, 0), 0,
+	assert_d_eq(mallctl("pool.0.arenas.narenas", &narenas, &sz, NULL, 0), 0,
 	    "Unexpected mallctl() failure");
 	assert_u_eq(narenas, opt_narenas, "Number of arenas incorrect");
 	arena_new = narenas - 1;
-	assert_d_eq(mallctl("thread.arena", &arena_old, &sz, &arena_new,
+	assert_d_eq(mallctl("thread.pool.0.arena", &arena_old, &sz, &arena_new,
 	    sizeof(unsigned)), 0, "Unexpected mallctl() failure");
 	arena_new = 0;
-	assert_d_eq(mallctl("thread.arena", &arena_old, &sz, &arena_new,
+	assert_d_eq(mallctl("thread.pool.0.arena", &arena_old, &sz, &arena_new,
 	    sizeof(unsigned)), 0, "Unexpected mallctl() failure");
 }
 TEST_END
@@ -234,20 +298,35 @@ TEST_END
 TEST_BEGIN(test_arena_i_purge)
 {
 	unsigned narenas;
+	unsigned npools;
 	size_t sz = sizeof(unsigned);
-	size_t mib[3];
-	size_t miblen = 3;
+	size_t mib[5];
+	size_t miblen = 5;
+	void *mem;
+	pool_t *pool;
 
-	assert_d_eq(mallctl("arena.0.purge", NULL, NULL, NULL, 0), 0,
+	mem = calloc(1, POOL_MINIMAL_SIZE);
+	assert_ptr_ne(mem, NULL, "Unexpected calloc() failure");
+	pool = je_pool_create(mem, POOL_MINIMAL_SIZE, 1);
+
+	assert_ptr_ne( (void*)pool, NULL, "Unexpected je_pool_create() failure");
+	assert_d_eq(mallctl("pools.npools", &npools, &sz, NULL, 0), 0,
 	    "Unexpected mallctl() failure");
+	assert_u_eq(npools, 2, "Unexpected number of pools");
 
-	assert_d_eq(mallctl("arenas.narenas", &narenas, &sz, NULL, 0), 0,
+	assert_d_eq(mallctl("pool.1.arena.0.purge", NULL, NULL, NULL, 0), 0,
+	    "Unexpected mallctl() failure");
+	assert_d_eq(mallctl("pool.1.arenas.narenas", &narenas, &sz, NULL, 0), 0,
 	    "Unexpected mallctl() failure");
-	assert_d_eq(mallctlnametomib("arena.0.purge", mib, &miblen), 0,
+
+	assert_d_eq(mallctlnametomib("pool.1.arena.0.purge", mib, &miblen), 0,
 	    "Unexpected mallctlnametomib() failure");
-	mib[1] = narenas;
+	mib[3] = narenas;
 	assert_d_eq(mallctlbymib(mib, miblen, NULL, NULL, NULL, 0), 0,
 	    "Unexpected mallctlbymib() failure");
+
+	je_pool_delete(pool);
+	free(mem);
 }
 TEST_END
 
@@ -255,27 +334,28 @@ TEST_BEGIN(test_arena_i_dss)
 {
 	const char *dss_prec_old, *dss_prec_new;
 	size_t sz = sizeof(dss_prec_old);
+	size_t mib[5];
+	size_t miblen;
 
-	dss_prec_new = "primary";
-	assert_d_eq(mallctl("arena.0.dss", &dss_prec_old, &sz, &dss_prec_new,
+	miblen = sizeof(mib)/sizeof(size_t);
+	assert_d_eq(mallctlnametomib("pool.0.arena.0.dss", mib, &miblen), 0,
+	    "Unexpected mallctlnametomib() error");
+
+	dss_prec_new = "disabled";
+	assert_d_eq(mallctlbymib(mib, miblen, &dss_prec_old, &sz, &dss_prec_new,
 	    sizeof(dss_prec_new)), 0, "Unexpected mallctl() failure");
 	assert_str_ne(dss_prec_old, "primary",
 	    "Unexpected default for dss precedence");
 
-	assert_d_eq(mallctl("arena.0.dss", &dss_prec_new, &sz, &dss_prec_old,
+	assert_d_eq(mallctlbymib(mib, miblen, &dss_prec_new, &sz, &dss_prec_old,
 	    sizeof(dss_prec_old)), 0, "Unexpected mallctl() failure");
-}
-TEST_END
-
-TEST_BEGIN(test_arenas_purge)
-{
-	unsigned arena = 0;
-
-	assert_d_eq(mallctl("arenas.purge", NULL, NULL, &arena, sizeof(arena)),
-	    0, "Unexpected mallctl() failure");
 
-	assert_d_eq(mallctl("arenas.purge", NULL, NULL, NULL, 0), 0,
-	    "Unexpected mallctl() failure");
+	mib[3] = narenas_total_get(pools[0]);
+	dss_prec_new = "disabled";
+	assert_d_eq(mallctlbymib(mib, miblen, &dss_prec_old, &sz, &dss_prec_new,
+	    sizeof(dss_prec_new)), 0, "Unexpected mallctl() failure");
+	assert_str_ne(dss_prec_old, "primary",
+	    "Unexpected default for dss precedence");
 }
 TEST_END
 
@@ -284,13 +364,13 @@ TEST_BEGIN(test_arenas_initialized)
 	unsigned narenas;
 	size_t sz = sizeof(narenas);
 
-	assert_d_eq(mallctl("arenas.narenas", &narenas, &sz, NULL, 0), 0,
+	assert_d_eq(mallctl("pool.0.arenas.narenas", &narenas, &sz, NULL, 0), 0,
 	    "Unexpected mallctl() failure");
 	{
-		bool initialized[narenas];
+		VARIABLE_ARRAY(bool, initialized, narenas);
 
 		sz = narenas * sizeof(bool);
-		assert_d_eq(mallctl("arenas.initialized", initialized, &sz,
+		assert_d_eq(mallctl("pool.0.arenas.initialized", initialized, &sz,
 		    NULL, 0), 0, "Unexpected mallctl() failure");
 	}
 }
@@ -302,7 +382,7 @@ TEST_BEGIN(test_arenas_constants)
 #define	TEST_ARENAS_CONSTANT(t, name, expected) do {			\
 	t name;								\
 	size_t sz = sizeof(t);						\
-	assert_d_eq(mallctl("arenas."#name, &name, &sz, NULL, 0), 0,	\
+	assert_d_eq(mallctl("pool.0.arenas."#name, &name, &sz, NULL, 0), 0,	\
 	    "Unexpected mallctl() failure");				\
 	assert_zu_eq(name, expected, "Incorrect "#name" size");		\
 } while (0)
@@ -322,11 +402,10 @@ TEST_BEGIN(test_arenas_bin_constants)
 #define	TEST_ARENAS_BIN_CONSTANT(t, name, expected) do {		\
 	t name;								\
 	size_t sz = sizeof(t);						\
-	assert_d_eq(mallctl("arenas.bin.0."#name, &name, &sz, NULL, 0),	\
+	assert_d_eq(mallctl("pool.0.arenas.bin.0."#name, &name, &sz, NULL, 0),	\
 	    0, "Unexpected mallctl() failure");				\
 	assert_zu_eq(name, expected, "Incorrect "#name" size");		\
 } while (0)
-
 	TEST_ARENAS_BIN_CONSTANT(size_t, size, arena_bin_info[0].reg_size);
 	TEST_ARENAS_BIN_CONSTANT(uint32_t, nregs, arena_bin_info[0].nregs);
 	TEST_ARENAS_BIN_CONSTANT(size_t, run_size, arena_bin_info[0].run_size);
@@ -341,32 +420,71 @@ TEST_BEGIN(test_arenas_lrun_constants)
 #define	TEST_ARENAS_LRUN_CONSTANT(t, name, expected) do {		\
 	t name;								\
 	size_t sz = sizeof(t);						\
-	assert_d_eq(mallctl("arenas.lrun.0."#name, &name, &sz, NULL,	\
+	assert_d_eq(mallctl("pool.0.arenas.lrun.0."#name, &name, &sz, NULL,	\
 	    0), 0, "Unexpected mallctl() failure");			\
 	assert_zu_eq(name, expected, "Incorrect "#name" size");		\
 } while (0)
-
 	TEST_ARENAS_LRUN_CONSTANT(size_t, size, (1 << LG_PAGE));
 
 #undef TEST_ARENAS_LRUN_CONSTANT
 }
 TEST_END
 
+/*
+ * create a couple of pools and extend their arenas
+ */
 TEST_BEGIN(test_arenas_extend)
 {
-	unsigned narenas_before, arena, narenas_after;
-	size_t sz = sizeof(unsigned);
+#define NPOOLS 4
+	pool_t *pools[NPOOLS];
+	void *mem;
+	unsigned npools, narenas_before, arena, narenas_after;
+	int i;
+	size_t mib_narenas[4],
+	       mib_extend[4],
+	       miblen	= sizeof(mib_narenas),
+	       sz	= sizeof(unsigned);
+
+	mem = calloc(NPOOLS, POOL_MINIMAL_SIZE);
+	assert_ptr_ne(mem, NULL, "Unexpected calloc() failure");
+
+	for (i = 0; i < NPOOLS; ++i) {
+		pools[i] = je_pool_create(mem + (i*POOL_MINIMAL_SIZE), POOL_MINIMAL_SIZE, 0);
+		assert_ptr_ne((void *)pools[i], NULL, "Unexpected je_pool_create() failure");
+	}
 
-	assert_d_eq(mallctl("arenas.narenas", &narenas_before, &sz, NULL, 0), 0,
-	    "Unexpected mallctl() failure");
-	assert_d_eq(mallctl("arenas.extend", &arena, &sz, NULL, 0), 0,
-	    "Unexpected mallctl() failure");
-	assert_d_eq(mallctl("arenas.narenas", &narenas_after, &sz, NULL, 0), 0,
+	assert_d_eq(mallctl("pools.npools", &npools, &sz, NULL, 0), 0,
 	    "Unexpected mallctl() failure");
+	assert_u_eq(npools, NPOOLS+1, "Unexpected number of pools");
+
+	assert_d_eq(mallctlnametomib("pool.0.arenas.narenas", mib_narenas, &miblen), 0,
+	    "Unexpected mallctlnametomib() failure");
+	assert_d_eq(mallctlnametomib("pool.0.arenas.extend", mib_extend, &miblen), 0,
+	    "Unexpected mallctlnametomib() failure");
 
-	assert_u_eq(narenas_before+1, narenas_after,
-	    "Unexpected number of arenas before versus after extension");
-	assert_u_eq(arena, narenas_after-1, "Unexpected arena index");
+	/*
+	 * This loop does not use local variable pools.
+	 * Moreover we ommit pool[0].
+	 */
+	for (i = 1; i <= NPOOLS; ++i) {
+		mib_narenas[1] = i;
+		mib_extend[1] = i;
+		assert_d_eq(mallctlbymib(mib_narenas, miblen, &narenas_before, &sz, NULL, 0),
+		    0, "Unexpected mallctlbymib() failure");
+		assert_d_eq(mallctlbymib(mib_extend, miblen, &arena, &sz, NULL, 0),
+		    0, "Unexpected mallctlbymib() failure");
+		assert_d_eq(mallctlbymib(mib_narenas, miblen, &narenas_after, &sz, NULL, 0),
+		    0, "Unexpected mallctlbymib() failure");
+
+		assert_u_eq(narenas_before+1, narenas_after,
+		    "Unexpected number of arenas before versus after extension");
+		assert_u_eq(arena, narenas_after-1, "Unexpected arena index");
+	}
+	for (i = 0; i < NPOOLS; ++i) {
+		je_pool_delete( pools[i]);
+	}
+	free(mem);
+#undef NPOOLS
 }
 TEST_END
 
@@ -376,7 +494,7 @@ TEST_BEGIN(test_stats_arenas)
 #define	TEST_STATS_ARENAS(t, name) do {					\
 	t name;								\
 	size_t sz = sizeof(t);						\
-	assert_d_eq(mallctl("stats.arenas.0."#name, &name, &sz, NULL,	\
+	assert_d_eq(mallctl("pool.0.stats.arenas.0."#name, &name, &sz, NULL,	\
 	    0), 0, "Unexpected mallctl() failure");			\
 } while (0)
 
@@ -401,11 +519,11 @@ main(void)
 	    test_mallctlnametomib_short_mib,
 	    test_mallctl_config,
 	    test_mallctl_opt,
+	    test_mallctl_with_multiple_pools,
 	    test_manpage_example,
 	    test_thread_arena,
 	    test_arena_i_purge,
 	    test_arena_i_dss,
-	    test_arenas_purge,
 	    test_arenas_initialized,
 	    test_arenas_constants,
 	    test_arenas_bin_constants,
diff --git a/src/jemalloc/test/unit/math.c b/src/jemalloc/test/unit/math.c
index a1b288ea19c08c45e30c17c1d6eb400871387475..ebec77a62d52c54cb104383e20952ac6c9275f03 100644
--- a/src/jemalloc/test/unit/math.c
+++ b/src/jemalloc/test/unit/math.c
@@ -3,6 +3,12 @@
 #define	MAX_REL_ERR 1.0e-9
 #define	MAX_ABS_ERR 1.0e-9
 
+#include <float.h>
+
+#ifndef INFINITY
+#define	INFINITY (DBL_MAX + DBL_MAX)
+#endif
+
 static bool
 double_eq_rel(double a, double b, double max_rel_err, double max_abs_err)
 {
diff --git a/src/jemalloc/test/unit/mq.c b/src/jemalloc/test/unit/mq.c
index f57e96af1cb42d59d445018e3ba49ffa5990b097..bd289c54d6b86800580c0ce5e67edec3a9c0faa0 100644
--- a/src/jemalloc/test/unit/mq.c
+++ b/src/jemalloc/test/unit/mq.c
@@ -54,7 +54,7 @@ thd_sender_start(void *arg)
 		mq_msg_t *msg;
 		void *p;
 		p = mallocx(sizeof(mq_msg_t), 0);
-		assert_ptr_not_null(p, "Unexpected allocm() failure");
+		assert_ptr_not_null(p, "Unexpected mallocx() failure");
 		msg = (mq_msg_t *)p;
 		mq_put(mq, msg);
 	}
diff --git a/src/jemalloc/test/unit/pool.h b/src/jemalloc/test/unit/pool.h
new file mode 100644
index 0000000000000000000000000000000000000000..8e3a8be4ba840e06c34d9df464d97dfd2da382e0
--- /dev/null
+++ b/src/jemalloc/test/unit/pool.h
@@ -0,0 +1,448 @@
+#include "test/jemalloc_test.h"
+
+#define TEST_POOL_SIZE (16L * 1024L * 1024L)
+#define TEST_TOO_SMALL_POOL_SIZE (2L * 1024L * 1024L)
+#define TEST_VALUE 123456
+#define TEST_MALLOC_FREE_LOOPS 2
+#define TEST_MALLOC_SIZE 1024
+#define TEST_ALLOCS_SIZE (TEST_POOL_SIZE / 8)
+#define TEST_BUFFOR_CMP_SIZE (4L * 1024L * 1024L)
+
+static char mem_pool[TEST_POOL_SIZE];
+static char mem_extend_ok[TEST_POOL_SIZE];
+static void* allocs[TEST_ALLOCS_SIZE];
+
+static int custom_allocs;
+static int exp_base_pool;
+
+TEST_BEGIN(test_pool_create_errors) {
+	pool_t *pool;
+	memset(mem_pool, 1, TEST_POOL_SIZE);
+	pool = pool_create(mem_pool, 0, 0);
+	assert_ptr_null(pool, "pool_create() should return NULL for size 0");
+
+	pool = pool_create(NULL, TEST_POOL_SIZE, 0);
+	assert_ptr_null(pool, "pool_create() should return NULL for input addr NULL");
+}
+TEST_END
+
+TEST_BEGIN(test_pool_create) {
+	pool_t *pool;
+	custom_allocs = 0;
+	memset(mem_pool, 0, TEST_POOL_SIZE);
+	pool = pool_create(mem_pool, TEST_POOL_SIZE, 1);
+	assert_ptr_eq(pool, mem_pool, "pool_create() should return addr with valid input");
+	pool_delete(pool);
+
+	assert_d_eq(custom_allocs, 0, "memory leak when use custom allocator");
+	if (exp_base_pool) {
+		assert_ptr_not_null(pools[0], "not create base pool");
+	} else {
+		assert_ptr_null(pools[0], "create base pool");
+	}
+}
+TEST_END
+
+TEST_BEGIN(test_pool_malloc) {
+	pool_t *pool;
+	custom_allocs = 0;
+	memset(mem_pool, 0, TEST_POOL_SIZE);
+	pool = pool_create(mem_pool, TEST_POOL_SIZE, 1);
+
+	int *test = pool_malloc(pool, sizeof(int));
+	assert_ptr_not_null(test, "pool_malloc should return valid ptr");
+
+	*test = TEST_VALUE;
+	assert_x_eq(*test, TEST_VALUE, "ptr should be usable");
+
+	assert_lu_gt((uintptr_t)test, (uintptr_t)mem_pool,
+		"pool_malloc() should return pointer to memory from pool");
+	assert_lu_lt((uintptr_t)test, (uintptr_t)mem_pool+TEST_POOL_SIZE,
+		"pool_malloc() should return pointer to memory from pool");
+
+	pool_free(pool, test);
+
+	pool_delete(pool);
+
+	assert_d_eq(custom_allocs, 0, "memory leak when use custom allocator");
+	if (exp_base_pool) {
+		assert_ptr_not_null(pools[0], "not create base pool");
+	} else {
+		assert_ptr_null(pools[0], "create base pool");
+	}
+}
+TEST_END
+
+TEST_BEGIN(test_pool_free) {
+	pool_t *pool;
+	int i, j, s = 0, prev_s = 0;
+	int allocs = TEST_POOL_SIZE/TEST_MALLOC_SIZE;
+	void *arr[allocs];
+	custom_allocs = 0;
+	memset(mem_pool, 0, TEST_POOL_SIZE);
+	pool = pool_create(mem_pool, TEST_POOL_SIZE, 1);
+
+	for (i = 0; i < TEST_MALLOC_FREE_LOOPS; ++i) {
+		for (j = 0; j < allocs; ++j) {
+			arr[j] = pool_malloc(pool, TEST_MALLOC_SIZE);
+			if (arr[j] != NULL) {
+				s++;
+			}
+		}
+		for (j = 0; j < allocs; ++j) {
+			if (arr[j] != NULL) {
+				pool_free(pool, arr[j]);
+			}
+		}
+		if (prev_s != 0) {
+			assert_x_eq(s, prev_s,
+				"pool_free() should record back used chunks");
+		}
+
+		prev_s = s;
+		s = 0;
+	}
+
+	pool_delete(pool);
+
+	assert_d_eq(custom_allocs, 0, "memory leak when use custom allocator");
+	if (exp_base_pool) {
+		assert_ptr_not_null(pools[0], "not create base pool");
+	} else {
+		assert_ptr_null(pools[0], "create base pool");
+	}
+}
+TEST_END
+
+TEST_BEGIN(test_pool_calloc) {
+	pool_t *pool;
+	custom_allocs = 0;
+	memset(mem_pool, 1, TEST_POOL_SIZE);
+	pool = pool_create(mem_pool, TEST_POOL_SIZE, 0);
+
+	int *test = pool_calloc(pool, 1, sizeof(int));
+	assert_ptr_not_null(test, "pool_calloc should return valid ptr");
+
+	assert_x_eq(*test, 0, "pool_calloc should return zeroed memory");
+
+	pool_free(pool, test);
+
+	pool_delete(pool);
+
+	assert_d_eq(custom_allocs, 0, "memory leak when use custom allocator");
+	if (exp_base_pool) {
+		assert_ptr_not_null(pools[0], "not create base pool");
+	} else {
+		assert_ptr_null(pools[0], "create base pool");
+	}
+}
+TEST_END
+
+TEST_BEGIN(test_pool_realloc) {
+	pool_t *pool;
+	custom_allocs = 0;
+	memset(mem_pool, 0, TEST_POOL_SIZE);
+	pool = pool_create(mem_pool, TEST_POOL_SIZE, 1);
+
+	int *test = pool_ralloc(pool, NULL, sizeof(int));
+	assert_ptr_not_null(test, "pool_ralloc with NULL addr should return valid ptr");
+
+	int *test2 = pool_ralloc(pool, test, sizeof(int)*2);
+	assert_ptr_not_null(test, "pool_ralloc should return valid ptr");
+	test2[0] = TEST_VALUE;
+	test2[1] = TEST_VALUE;
+
+	assert_x_eq(test[1], TEST_VALUE, "ptr should be usable");
+
+	pool_free(pool, test2);
+
+	pool_delete(pool);
+
+	assert_d_eq(custom_allocs, 0, "memory leak when use custom allocator");
+	if (exp_base_pool) {
+		assert_ptr_not_null(pools[0], "not create base pool");
+	} else {
+		assert_ptr_null(pools[0], "create base pool");
+	}
+}
+TEST_END
+
+TEST_BEGIN(test_pool_aligned_alloc) {
+	pool_t *pool;
+	custom_allocs = 0;
+	memset(mem_pool, 0, TEST_POOL_SIZE);
+	pool = pool_create(mem_pool, TEST_POOL_SIZE, 1);
+
+	int *test = pool_aligned_alloc(pool, 1024, 1024);
+	assert_ptr_not_null(test, "pool_aligned_alloc should return valid ptr");
+	assert_x_eq(((uintptr_t)(test) & 1023), 0, "ptr should be aligned");
+
+	assert_lu_gt((uintptr_t)test, (uintptr_t)mem_pool,
+		"pool_aligned_alloc() should return pointer to memory from pool");
+	assert_lu_lt((uintptr_t)test, (uintptr_t)mem_pool+TEST_POOL_SIZE,
+		"pool_aligned_alloc() should return pointer to memory from pool");
+
+	*test = TEST_VALUE;
+	assert_x_eq(*test, TEST_VALUE, "ptr should be usable");
+
+	pool_free(pool, test);
+
+	pool_delete(pool);
+
+	assert_d_eq(custom_allocs, 0, "memory leak when use custom allocator");
+	if (exp_base_pool) {
+		assert_ptr_not_null(pools[0], "not create base pool");
+	} else {
+		assert_ptr_null(pools[0], "create base pool");
+	}
+}
+TEST_END
+
+TEST_BEGIN(test_pool_reuse_pool) {
+	pool_t *pool;
+	size_t  pool_num = 0;
+	custom_allocs = 0;
+
+	/* create and destroy pool multiple times */
+	for (; pool_num<100; ++pool_num) {
+		pool = pool_create(mem_pool, TEST_POOL_SIZE, 0);
+		assert_ptr_not_null(pool, "Can not create pool!!!");
+		if (pool == NULL) {
+			break;
+		}
+
+		void *prev = NULL;
+		size_t i = 0;
+
+		/* allocate memory from pool */
+		for (; i<100; ++i) {
+			void **next = pool_malloc(pool, sizeof (void *));
+
+			assert_lu_gt((uintptr_t)next, (uintptr_t)mem_pool,
+				"pool_malloc() should return pointer to memory from pool");
+			assert_lu_lt((uintptr_t)next, (uintptr_t)mem_pool+TEST_POOL_SIZE,
+				"pool_malloc() should return pointer to memory from pool");
+
+			*next = prev;
+			prev = next;
+		}
+
+		/* free all allocated memory from pool */
+		while (prev != NULL) {
+			void **act = prev;
+			prev = *act;
+			pool_free(pool, act);
+		}
+		pool_delete(pool);
+	}
+
+	assert_d_eq(custom_allocs, 0, "memory leak when use custom allocator");
+	if (exp_base_pool) {
+		assert_ptr_not_null(pools[0], "not create base pool");
+	} else {
+		assert_ptr_null(pools[0], "create base pool");
+	}
+}
+TEST_END
+
+TEST_BEGIN(test_pool_check_memory) {
+	pool_t *pool;
+	size_t pool_size = POOL_MINIMAL_SIZE;
+	assert_lu_lt(POOL_MINIMAL_SIZE, TEST_POOL_SIZE, "Too small pool size");
+
+	size_t object_size;
+	size_t size_allocated;
+	size_t i;
+	size_t j;
+
+	for (object_size = 8; object_size <= TEST_BUFFOR_CMP_SIZE ; object_size *= 2) {
+		custom_allocs = 0;
+		pool = pool_create(mem_pool, pool_size, 0);
+		assert_ptr_not_null(pool, "Can not create pool!!!");
+		size_allocated = 0;
+		memset(allocs, 0, TEST_ALLOCS_SIZE);
+
+		for (i = 0; i < TEST_ALLOCS_SIZE;++i) {
+			allocs[i] = pool_malloc(pool, object_size);
+			if (allocs[i] == NULL) {
+				/* out of memory in pool */
+				break;
+			}
+			assert_lu_gt((uintptr_t)allocs[i], (uintptr_t)mem_pool,
+					"pool_malloc() should return pointer to memory from pool");
+			assert_lu_lt((uintptr_t)allocs[i], (uintptr_t)mem_pool+pool_size,
+				"pool_malloc() should return pointer to memory from pool");
+
+			size_allocated += object_size;
+
+			/* fill each allocation with a unique value */
+			memset(allocs[i], (char)i, object_size);
+		}
+
+		assert_ptr_not_null(allocs[0], "pool_malloc should return valid ptr");
+		assert_lu_lt(i + 1, TEST_ALLOCS_SIZE, "All memory should be used");
+
+		/* check for unexpected modifications of prepare data */
+		for (i = 0; i < TEST_ALLOCS_SIZE && allocs[i] != NULL; ++i) {
+			char *buffer = allocs[i];
+			for (j = 0; j < object_size; ++j)
+				if (buffer[j] != (char)i) {
+					assert_true(0, "Content of data object was modified unexpectedly"
+						" for object size: %zu, id: %zu", object_size, j);
+					break;
+			}
+		}
+
+		pool_delete(pool);
+
+		assert_d_eq(custom_allocs, 0, "memory leak when use custom allocator");
+		if (exp_base_pool) {
+			assert_ptr_not_null(pools[0], "not create base pool");
+		} else {
+			assert_ptr_null(pools[0], "create base pool");
+		}
+	}
+
+}
+TEST_END
+
+TEST_BEGIN(test_pool_use_all_memory) {
+	pool_t *pool;
+	size_t size = 0;
+	size_t pool_size = POOL_MINIMAL_SIZE;
+	assert_lu_lt(POOL_MINIMAL_SIZE, TEST_POOL_SIZE, "Too small pool size");
+	custom_allocs = 0;
+	pool = pool_create(mem_pool, pool_size, 0);
+	assert_ptr_not_null(pool, "Can not create pool!!!");
+
+	void *prev = NULL;
+	for (;;) {
+		void **next = pool_malloc(pool, sizeof (void *));
+		if (next == NULL) {
+			/* Out of memory in pool, test end */
+			break;
+		}
+		size += sizeof (void *);
+
+		assert_ptr_not_null(next, "pool_malloc should return valid ptr");
+
+		assert_lu_gt((uintptr_t)next, (uintptr_t)mem_pool,
+				"pool_malloc() should return pointer to memory from pool");
+		assert_lu_lt((uintptr_t)next, (uintptr_t)mem_pool+pool_size,
+			"pool_malloc() should return pointer to memory from pool");
+
+		*next = prev;
+		assert_x_eq((uintptr_t)(*next), (uintptr_t)(prev), "ptr should be usable");
+		prev = next;
+
+	}
+
+	assert_lu_gt(size, 0, "Can not alloc any memory from pool");
+
+	/* Free all allocated memory from pool */
+	while (prev != NULL) {
+		void **act = prev;
+		prev = *act;
+		pool_free(pool, act);
+	}
+
+	pool_delete(pool);
+
+	assert_d_eq(custom_allocs, 0, "memory leak when use custom allocator");
+	if (exp_base_pool) {
+		assert_ptr_not_null(pools[0], "not create base pool");
+	} else {
+		assert_ptr_null(pools[0], "create base pool");
+	}
+}
+TEST_END
+
+TEST_BEGIN(test_pool_extend_errors) {
+	pool_t *pool;
+	custom_allocs = 0;
+	memset(mem_pool, 0, TEST_POOL_SIZE);
+	pool = pool_create(mem_pool, TEST_POOL_SIZE, 1);
+
+	memset(mem_extend_ok, 0, TEST_TOO_SMALL_POOL_SIZE);
+	size_t usable_size = pool_extend(pool, mem_extend_ok, TEST_TOO_SMALL_POOL_SIZE, 0);
+
+	assert_zu_eq(usable_size, 0, "pool_extend() should return 0"
+		" when provided with memory size smaller then chunksize");
+
+	pool_delete(pool);
+
+	assert_d_eq(custom_allocs, 0, "memory leak when use custom allocator");
+	if (exp_base_pool) {
+		assert_ptr_not_null(pools[0], "not create base pool");
+	} else {
+		assert_ptr_null(pools[0], "create base pool");
+	}
+}
+TEST_END
+
+TEST_BEGIN(test_pool_extend) {
+	pool_t *pool;
+	custom_allocs = 0;
+	memset(mem_pool, 0, TEST_POOL_SIZE);
+	pool = pool_create(mem_pool, TEST_POOL_SIZE, 1);
+
+	memset(mem_extend_ok, 0, TEST_POOL_SIZE);
+	size_t usable_size = pool_extend(pool, mem_extend_ok, TEST_POOL_SIZE, 0);
+
+	assert_zu_ne(usable_size, 0, "pool_extend() should return value"
+		" after alignment when provided with enough memory");
+
+	pool_delete(pool);
+
+	assert_d_eq(custom_allocs, 0, "memory leak when use custom allocator");
+	if (exp_base_pool) {
+		assert_ptr_not_null(pools[0], "not create base pool");
+	} else {
+		assert_ptr_null(pools[0], "create base pool");
+	}
+}
+TEST_END
+
+TEST_BEGIN(test_pool_extend_after_out_of_memory) {
+	pool_t *pool;
+	custom_allocs = 0;
+	memset(mem_pool, 0, TEST_POOL_SIZE);
+	pool = pool_create(mem_pool, TEST_POOL_SIZE, 1);
+
+	/* use the all memory from pool and from base allocator */
+	while (pool_malloc(pool, sizeof (void *)));
+	pool->base_next_addr = pool->base_past_addr;
+
+	memset(mem_extend_ok, 0, TEST_POOL_SIZE);
+	size_t usable_size = pool_extend(pool, mem_extend_ok, TEST_POOL_SIZE, 0);
+
+	assert_zu_ne(usable_size, 0, "pool_extend() should return value"
+		" after alignment when provided with enough memory");
+
+	pool_delete(pool);
+
+	assert_d_eq(custom_allocs, 0, "memory leak when use custom allocator");
+	if (exp_base_pool) {
+		assert_ptr_not_null(pools[0], "not create base pool");
+	} else {
+		assert_ptr_null(pools[0], "create base pool");
+	}
+}
+TEST_END
+
+#define	POOL_TEST_CASES\
+	test_pool_create_errors,	\
+	test_pool_create,	\
+	test_pool_malloc,	\
+	test_pool_free,	\
+	test_pool_calloc,	\
+	test_pool_realloc,	\
+	test_pool_aligned_alloc,	\
+	test_pool_reuse_pool,	\
+	test_pool_check_memory,	\
+	test_pool_use_all_memory,	\
+	test_pool_extend_errors,	\
+	test_pool_extend,	\
+	test_pool_extend_after_out_of_memory
+
+
diff --git a/src/jemalloc/test/unit/pool_base_alloc.c b/src/jemalloc/test/unit/pool_base_alloc.c
new file mode 100644
index 0000000000000000000000000000000000000000..80913ccaf21d476da730f60a18c5e268f515332a
--- /dev/null
+++ b/src/jemalloc/test/unit/pool_base_alloc.c
@@ -0,0 +1,9 @@
+#include "pool.h"
+
+int
+main(void)
+{
+	exp_base_pool = 1;
+
+	return test_not_init(POOL_TEST_CASES);
+}
diff --git a/src/jemalloc/test/unit/pool_custom_alloc.c b/src/jemalloc/test/unit/pool_custom_alloc.c
new file mode 100644
index 0000000000000000000000000000000000000000..fbda621163cf39b60446a24eb0abe293a571b131
--- /dev/null
+++ b/src/jemalloc/test/unit/pool_custom_alloc.c
@@ -0,0 +1,29 @@
+#include "pool.h"
+
+static char buff_alloc[4*1024];
+static char *buff_ptr = buff_alloc;
+
+void *
+malloc_test(size_t size) {
+	custom_allocs++;
+	void *ret = buff_ptr;
+	buff_ptr = buff_ptr + size;
+	return ret;
+}
+
+void
+free_test(void *ptr) {
+	custom_allocs--;
+	if(custom_allocs == 0) {
+		buff_ptr = buff_alloc;
+	}
+}
+
+int
+main(void)
+{
+	exp_base_pool = 0;
+	je_pool_set_alloc_funcs(malloc_test, free_test);
+
+	return test_not_init(POOL_TEST_CASES);
+}
diff --git a/src/jemalloc/test/unit/pool_custom_alloc_internal.c b/src/jemalloc/test/unit/pool_custom_alloc_internal.c
new file mode 100644
index 0000000000000000000000000000000000000000..fd47da0f699cf7ea21621209051cde0e4b2ea4ee
--- /dev/null
+++ b/src/jemalloc/test/unit/pool_custom_alloc_internal.c
@@ -0,0 +1,30 @@
+#include "pool.h"
+
+void *
+malloc_test(size_t size) {
+	custom_allocs++;
+	return malloc(size);
+}
+
+void
+free_test(void *ptr) {
+	custom_allocs--;
+	free(ptr);
+}
+
+int
+main(void)
+{
+	/*
+	 * Initialize custom allocator who call malloc from jemalloc.
+	 */
+	if (nallocx(1, 0) == 0) {
+		malloc_printf("Initialization error");
+		return (test_status_fail);
+	}
+
+	exp_base_pool = 1;
+	je_pool_set_alloc_funcs(malloc_test, free_test);
+
+	return test_not_init(POOL_TEST_CASES);
+}
diff --git a/src/jemalloc/test/unit/rtree.c b/src/jemalloc/test/unit/rtree.c
index 5463055fe92a4cbd8c4b5447deff8ee874aef550..a59c7e9917d24c806529392a3c9eb4e6d1fbc2ed 100644
--- a/src/jemalloc/test/unit/rtree.c
+++ b/src/jemalloc/test/unit/rtree.c
@@ -1,11 +1,23 @@
 #include "test/jemalloc_test.h"
 
+void *
+rtree_malloc(pool_t *pool, size_t size)
+{
+	return imalloc(size);
+}
+
+void
+rtree_free(pool_t *pool, void *ptr)
+{
+	return idalloc(ptr);
+}
+
 TEST_BEGIN(test_rtree_get_empty)
 {
 	unsigned i;
 
 	for (i = 1; i <= (sizeof(uintptr_t) << 3); i++) {
-		rtree_t *rtree = rtree_new(i, imalloc, idalloc);
+		rtree_t *rtree = rtree_new(i, rtree_malloc, rtree_free, pools[0]);
 		assert_u_eq(rtree_get(rtree, 0), 0,
 		    "rtree_get() should return NULL for empty tree");
 		rtree_delete(rtree);
@@ -18,7 +30,7 @@ TEST_BEGIN(test_rtree_extrema)
 	unsigned i;
 
 	for (i = 1; i <= (sizeof(uintptr_t) << 3); i++) {
-		rtree_t *rtree = rtree_new(i, imalloc, idalloc);
+		rtree_t *rtree = rtree_new(i, rtree_malloc, rtree_free, pools[0]);
 
 		rtree_set(rtree, 0, 1);
 		assert_u_eq(rtree_get(rtree, 0), 1,
@@ -40,7 +52,7 @@ TEST_BEGIN(test_rtree_bits)
 	for (i = 1; i < (sizeof(uintptr_t) << 3); i++) {
 		uintptr_t keys[] = {0, 1,
 		    (((uintptr_t)1) << (sizeof(uintptr_t)*8-i)) - 1};
-		rtree_t *rtree = rtree_new(i, imalloc, idalloc);
+		rtree_t *rtree = rtree_new(i, rtree_malloc, rtree_free, pools[0]);
 
 		for (j = 0; j < sizeof(keys)/sizeof(uintptr_t); j++) {
 			rtree_set(rtree, keys[j], 1);
@@ -73,7 +85,7 @@ TEST_BEGIN(test_rtree_random)
 
 	sfmt = init_gen_rand(SEED);
 	for (i = 1; i <= (sizeof(uintptr_t) << 3); i++) {
-		rtree_t *rtree = rtree_new(i, imalloc, idalloc);
+		rtree_t *rtree = rtree_new(i, rtree_malloc, rtree_free, pools[0]);
 		uintptr_t keys[NSET];
 		unsigned j;
 
diff --git a/src/jemalloc/test/unit/stats.c b/src/jemalloc/test/unit/stats.c
index 03a55c7fdce911ee109f73fd8bf2d82489a23e26..0105c4ba06c2eb199ccc10104a4a2071145ece73 100644
--- a/src/jemalloc/test/unit/stats.c
+++ b/src/jemalloc/test/unit/stats.c
@@ -7,15 +7,15 @@ TEST_BEGIN(test_stats_summary)
 	int expected = config_stats ? 0 : ENOENT;
 
 	sz = sizeof(cactive);
-	assert_d_eq(mallctl("stats.cactive", &cactive, &sz, NULL, 0), expected,
+	assert_d_eq(mallctl("pool.0.stats.cactive", &cactive, &sz, NULL, 0), expected,
 	    "Unexpected mallctl() result");
 
 	sz = sizeof(size_t);
-	assert_d_eq(mallctl("stats.allocated", &allocated, &sz, NULL, 0),
+	assert_d_eq(mallctl("pool.0.stats.allocated", &allocated, &sz, NULL, 0),
 	    expected, "Unexpected mallctl() result");
-	assert_d_eq(mallctl("stats.active", &active, &sz, NULL, 0), expected,
+	assert_d_eq(mallctl("pool.0.stats.active", &active, &sz, NULL, 0), expected,
 	    "Unexpected mallctl() result");
-	assert_d_eq(mallctl("stats.mapped", &mapped, &sz, NULL, 0), expected,
+	assert_d_eq(mallctl("pool.0.stats.mapped", &mapped, &sz, NULL, 0), expected,
 	    "Unexpected mallctl() result");
 
 	if (config_stats) {
@@ -37,13 +37,13 @@ TEST_BEGIN(test_stats_chunks)
 	int expected = config_stats ? 0 : ENOENT;
 
 	sz = sizeof(size_t);
-	assert_d_eq(mallctl("stats.chunks.current", &current, &sz, NULL, 0),
+	assert_d_eq(mallctl("pool.0.stats.chunks.current", &current, &sz, NULL, 0),
 	    expected, "Unexpected mallctl() result");
 	sz = sizeof(uint64_t);
-	assert_d_eq(mallctl("stats.chunks.total", &total, &sz, NULL, 0),
+	assert_d_eq(mallctl("pool.0.stats.chunks.total", &total, &sz, NULL, 0),
 	    expected, "Unexpected mallctl() result");
 	sz = sizeof(size_t);
-	assert_d_eq(mallctl("stats.chunks.high", &high, &sz, NULL, 0), expected,
+	assert_d_eq(mallctl("pool.0.stats.chunks.high", &high, &sz, NULL, 0), expected,
 	    "Unexpected mallctl() result");
 
 	if (config_stats) {
@@ -60,7 +60,7 @@ TEST_BEGIN(test_stats_huge)
 	void *p;
 	uint64_t epoch;
 	size_t allocated;
-	uint64_t nmalloc, ndalloc;
+	uint64_t nmalloc, ndalloc, nrequests;
 	size_t sz;
 	int expected = config_stats ? 0 : ENOENT;
 
@@ -71,19 +71,23 @@ TEST_BEGIN(test_stats_huge)
 	    "Unexpected mallctl() failure");
 
 	sz = sizeof(size_t);
-	assert_d_eq(mallctl("stats.huge.allocated", &allocated, &sz, NULL, 0),
-	    expected, "Unexpected mallctl() result");
+	assert_d_eq(mallctl("pool.0.stats.arenas.0.huge.allocated", &allocated, &sz,
+	    NULL, 0), expected, "Unexpected mallctl() result");
 	sz = sizeof(uint64_t);
-	assert_d_eq(mallctl("stats.huge.nmalloc", &nmalloc, &sz, NULL, 0),
-	    expected, "Unexpected mallctl() result");
-	assert_d_eq(mallctl("stats.huge.ndalloc", &ndalloc, &sz, NULL, 0),
-	    expected, "Unexpected mallctl() result");
+	assert_d_eq(mallctl("pool.0.stats.arenas.0.huge.nmalloc", &nmalloc, &sz, NULL,
+	    0), expected, "Unexpected mallctl() result");
+	assert_d_eq(mallctl("pool.0.stats.arenas.0.huge.ndalloc", &ndalloc, &sz, NULL,
+	    0), expected, "Unexpected mallctl() result");
+	assert_d_eq(mallctl("pool.0.stats.arenas.0.huge.nrequests", &nrequests, &sz,
+	    NULL, 0), expected, "Unexpected mallctl() result");
 
 	if (config_stats) {
 		assert_zu_gt(allocated, 0,
 		    "allocated should be greater than zero");
 		assert_u64_ge(nmalloc, ndalloc,
 		    "nmalloc should be at least as large as ndalloc");
+		assert_u64_le(nmalloc, nrequests,
+		    "nmalloc should no larger than nrequests");
 	}
 
 	dallocx(p, 0);
@@ -93,7 +97,7 @@ TEST_END
 TEST_BEGIN(test_stats_arenas_summary)
 {
 	unsigned arena;
-	void *small, *large;
+	void *little, *large;
 	uint64_t epoch;
 	size_t sz;
 	int expected = config_stats ? 0 : ENOENT;
@@ -101,29 +105,29 @@ TEST_BEGIN(test_stats_arenas_summary)
 	uint64_t npurge, nmadvise, purged;
 
 	arena = 0;
-	assert_d_eq(mallctl("thread.arena", NULL, NULL, &arena, sizeof(arena)),
+	assert_d_eq(mallctl("thread.pool.0.arena", NULL, NULL, &arena, sizeof(arena)),
 	    0, "Unexpected mallctl() failure");
 
-	small = mallocx(SMALL_MAXCLASS, 0);
-	assert_ptr_not_null(small, "Unexpected mallocx() failure");
+	little = mallocx(SMALL_MAXCLASS, 0);
+	assert_ptr_not_null(little, "Unexpected mallocx() failure");
 	large = mallocx(arena_maxclass, 0);
 	assert_ptr_not_null(large, "Unexpected mallocx() failure");
 
-	assert_d_eq(mallctl("arena.0.purge", NULL, NULL, NULL, 0), 0,
+	assert_d_eq(mallctl("pool.0.arena.0.purge", NULL, NULL, NULL, 0), 0,
 	    "Unexpected mallctl() failure");
 
 	assert_d_eq(mallctl("epoch", NULL, NULL, &epoch, sizeof(epoch)), 0,
 	    "Unexpected mallctl() failure");
 
 	sz = sizeof(size_t);
-	assert_d_eq(mallctl("stats.arenas.0.mapped", &mapped, &sz, NULL, 0),
+	assert_d_eq(mallctl("pool.0.stats.arenas.0.mapped", &mapped, &sz, NULL, 0),
 	    expected, "Unexepected mallctl() result");
 	sz = sizeof(uint64_t);
-	assert_d_eq(mallctl("stats.arenas.0.npurge", &npurge, &sz, NULL, 0),
+	assert_d_eq(mallctl("pool.0.stats.arenas.0.npurge", &npurge, &sz, NULL, 0),
 	    expected, "Unexepected mallctl() result");
-	assert_d_eq(mallctl("stats.arenas.0.nmadvise", &nmadvise, &sz, NULL, 0),
+	assert_d_eq(mallctl("pool.0.stats.arenas.0.nmadvise", &nmadvise, &sz, NULL, 0),
 	    expected, "Unexepected mallctl() result");
-	assert_d_eq(mallctl("stats.arenas.0.purged", &purged, &sz, NULL, 0),
+	assert_d_eq(mallctl("pool.0.stats.arenas.0.purged", &purged, &sz, NULL, 0),
 	    expected, "Unexepected mallctl() result");
 
 	if (config_stats) {
@@ -133,7 +137,7 @@ TEST_BEGIN(test_stats_arenas_summary)
 		    "nmadvise should be no greater than purged");
 	}
 
-	dallocx(small, 0);
+	dallocx(little, 0);
 	dallocx(large, 0);
 }
 TEST_END
@@ -165,7 +169,7 @@ TEST_BEGIN(test_stats_arenas_small)
 	no_lazy_lock(); /* Lazy locking would dodge tcache testing. */
 
 	arena = 0;
-	assert_d_eq(mallctl("thread.arena", NULL, NULL, &arena, sizeof(arena)),
+	assert_d_eq(mallctl("thread.pool.0.arena", NULL, NULL, &arena, sizeof(arena)),
 	    0, "Unexpected mallctl() failure");
 
 	p = mallocx(SMALL_MAXCLASS, 0);
@@ -178,14 +182,14 @@ TEST_BEGIN(test_stats_arenas_small)
 	    "Unexpected mallctl() failure");
 
 	sz = sizeof(size_t);
-	assert_d_eq(mallctl("stats.arenas.0.small.allocated", &allocated, &sz,
+	assert_d_eq(mallctl("pool.0.stats.arenas.0.small.allocated", &allocated, &sz,
 	    NULL, 0), expected, "Unexpected mallctl() result");
 	sz = sizeof(uint64_t);
-	assert_d_eq(mallctl("stats.arenas.0.small.nmalloc", &nmalloc, &sz,
+	assert_d_eq(mallctl("pool.0.stats.arenas.0.small.nmalloc", &nmalloc, &sz,
 	    NULL, 0), expected, "Unexpected mallctl() result");
-	assert_d_eq(mallctl("stats.arenas.0.small.ndalloc", &ndalloc, &sz,
+	assert_d_eq(mallctl("pool.0.stats.arenas.0.small.ndalloc", &ndalloc, &sz,
 	    NULL, 0), expected, "Unexpected mallctl() result");
-	assert_d_eq(mallctl("stats.arenas.0.small.nrequests", &nrequests, &sz,
+	assert_d_eq(mallctl("pool.0.stats.arenas.0.small.nrequests", &nrequests, &sz,
 	    NULL, 0), expected, "Unexpected mallctl() result");
 
 	if (config_stats) {
@@ -212,7 +216,7 @@ TEST_BEGIN(test_stats_arenas_large)
 	int expected = config_stats ? 0 : ENOENT;
 
 	arena = 0;
-	assert_d_eq(mallctl("thread.arena", NULL, NULL, &arena, sizeof(arena)),
+	assert_d_eq(mallctl("thread.pool.0.arena", NULL, NULL, &arena, sizeof(arena)),
 	    0, "Unexpected mallctl() failure");
 
 	p = mallocx(arena_maxclass, 0);
@@ -222,14 +226,14 @@ TEST_BEGIN(test_stats_arenas_large)
 	    "Unexpected mallctl() failure");
 
 	sz = sizeof(size_t);
-	assert_d_eq(mallctl("stats.arenas.0.large.allocated", &allocated, &sz,
+	assert_d_eq(mallctl("pool.0.stats.arenas.0.large.allocated", &allocated, &sz,
 	    NULL, 0), expected, "Unexpected mallctl() result");
 	sz = sizeof(uint64_t);
-	assert_d_eq(mallctl("stats.arenas.0.large.nmalloc", &nmalloc, &sz,
+	assert_d_eq(mallctl("pool.0.stats.arenas.0.large.nmalloc", &nmalloc, &sz,
 	    NULL, 0), expected, "Unexpected mallctl() result");
-	assert_d_eq(mallctl("stats.arenas.0.large.ndalloc", &ndalloc, &sz,
+	assert_d_eq(mallctl("pool.0.stats.arenas.0.large.ndalloc", &ndalloc, &sz,
 	    NULL, 0), expected, "Unexpected mallctl() result");
-	assert_d_eq(mallctl("stats.arenas.0.large.nrequests", &nrequests, &sz,
+	assert_d_eq(mallctl("pool.0.stats.arenas.0.large.nrequests", &nrequests, &sz,
 	    NULL, 0), expected, "Unexpected mallctl() result");
 
 	if (config_stats) {
@@ -257,7 +261,7 @@ TEST_BEGIN(test_stats_arenas_bins)
 	int expected = config_stats ? 0 : ENOENT;
 
 	arena = 0;
-	assert_d_eq(mallctl("thread.arena", NULL, NULL, &arena, sizeof(arena)),
+	assert_d_eq(mallctl("thread.pool.0.arena", NULL, NULL, &arena, sizeof(arena)),
 	    0, "Unexpected mallctl() failure");
 
 	p = mallocx(arena_bin_info[0].reg_size, 0);
@@ -270,29 +274,29 @@ TEST_BEGIN(test_stats_arenas_bins)
 	    "Unexpected mallctl() failure");
 
 	sz = sizeof(size_t);
-	assert_d_eq(mallctl("stats.arenas.0.bins.0.allocated", &allocated, &sz,
+	assert_d_eq(mallctl("pool.0.stats.arenas.0.bins.0.allocated", &allocated, &sz,
 	    NULL, 0), expected, "Unexpected mallctl() result");
 	sz = sizeof(uint64_t);
-	assert_d_eq(mallctl("stats.arenas.0.bins.0.nmalloc", &nmalloc, &sz,
+	assert_d_eq(mallctl("pool.0.stats.arenas.0.bins.0.nmalloc", &nmalloc, &sz,
 	    NULL, 0), expected, "Unexpected mallctl() result");
-	assert_d_eq(mallctl("stats.arenas.0.bins.0.ndalloc", &ndalloc, &sz,
+	assert_d_eq(mallctl("pool.0.stats.arenas.0.bins.0.ndalloc", &ndalloc, &sz,
 	    NULL, 0), expected, "Unexpected mallctl() result");
-	assert_d_eq(mallctl("stats.arenas.0.bins.0.nrequests", &nrequests, &sz,
+	assert_d_eq(mallctl("pool.0.stats.arenas.0.bins.0.nrequests", &nrequests, &sz,
 	    NULL, 0), expected, "Unexpected mallctl() result");
 
-	assert_d_eq(mallctl("stats.arenas.0.bins.0.nfills", &nfills, &sz,
+	assert_d_eq(mallctl("pool.0.stats.arenas.0.bins.0.nfills", &nfills, &sz,
 	    NULL, 0), config_tcache ? expected : ENOENT,
 	    "Unexpected mallctl() result");
-	assert_d_eq(mallctl("stats.arenas.0.bins.0.nflushes", &nflushes, &sz,
+	assert_d_eq(mallctl("pool.0.stats.arenas.0.bins.0.nflushes", &nflushes, &sz,
 	    NULL, 0), config_tcache ? expected : ENOENT,
 	    "Unexpected mallctl() result");
 
-	assert_d_eq(mallctl("stats.arenas.0.bins.0.nruns", &nruns, &sz,
+	assert_d_eq(mallctl("pool.0.stats.arenas.0.bins.0.nruns", &nruns, &sz,
 	    NULL, 0), expected, "Unexpected mallctl() result");
-	assert_d_eq(mallctl("stats.arenas.0.bins.0.nreruns", &nreruns, &sz,
+	assert_d_eq(mallctl("pool.0.stats.arenas.0.bins.0.nreruns", &nreruns, &sz,
 	    NULL, 0), expected, "Unexpected mallctl() result");
 	sz = sizeof(size_t);
-	assert_d_eq(mallctl("stats.arenas.0.bins.0.curruns", &curruns, &sz,
+	assert_d_eq(mallctl("pool.0.stats.arenas.0.bins.0.curruns", &curruns, &sz,
 	    NULL, 0), expected, "Unexpected mallctl() result");
 
 	if (config_stats) {
@@ -329,7 +333,7 @@ TEST_BEGIN(test_stats_arenas_lruns)
 	int expected = config_stats ? 0 : ENOENT;
 
 	arena = 0;
-	assert_d_eq(mallctl("thread.arena", NULL, NULL, &arena, sizeof(arena)),
+	assert_d_eq(mallctl("thread.pool.0.arena", NULL, NULL, &arena, sizeof(arena)),
 	    0, "Unexpected mallctl() failure");
 
 	p = mallocx(SMALL_MAXCLASS+1, 0);
@@ -339,14 +343,14 @@ TEST_BEGIN(test_stats_arenas_lruns)
 	    "Unexpected mallctl() failure");
 
 	sz = sizeof(uint64_t);
-	assert_d_eq(mallctl("stats.arenas.0.lruns.0.nmalloc", &nmalloc, &sz,
+	assert_d_eq(mallctl("pool.0.stats.arenas.0.lruns.0.nmalloc", &nmalloc, &sz,
 	    NULL, 0), expected, "Unexpected mallctl() result");
-	assert_d_eq(mallctl("stats.arenas.0.lruns.0.ndalloc", &ndalloc, &sz,
+	assert_d_eq(mallctl("pool.0.stats.arenas.0.lruns.0.ndalloc", &ndalloc, &sz,
 	    NULL, 0), expected, "Unexpected mallctl() result");
-	assert_d_eq(mallctl("stats.arenas.0.lruns.0.nrequests", &nrequests, &sz,
+	assert_d_eq(mallctl("pool.0.stats.arenas.0.lruns.0.nrequests", &nrequests, &sz,
 	    NULL, 0), expected, "Unexpected mallctl() result");
 	sz = sizeof(size_t);
-	assert_d_eq(mallctl("stats.arenas.0.lruns.0.curruns", &curruns, &sz,
+	assert_d_eq(mallctl("pool.0.stats.arenas.0.lruns.0.curruns", &curruns, &sz,
 	    NULL, 0), expected, "Unexpected mallctl() result");
 
 	if (config_stats) {
diff --git a/src/jemalloc/test/unit/util.c b/src/jemalloc/test/unit/util.c
index dc3cfe8a9db14ffcbd34f7519559938c32f61390..8ab39a4581935ba391ade45059dbb50d2cf48673 100644
--- a/src/jemalloc/test/unit/util.c
+++ b/src/jemalloc/test/unit/util.c
@@ -52,8 +52,8 @@ TEST_BEGIN(test_malloc_strtoumax)
 		const char *expected_errno_name;
 		uintmax_t expected_x;
 	};
-#define	ERR(e)	e, #e
-#define	UMAX(x)	((uintmax_t)x##ULL)
+#define	ERR(e)		e, #e
+#define	KUMAX(x)	((uintmax_t)x##ULL)
 	struct test_s tests[] = {
 		{"0",		"0",	-1,	ERR(EINVAL),	UINTMAX_MAX},
 		{"0",		"0",	1,	ERR(EINVAL),	UINTMAX_MAX},
@@ -64,51 +64,51 @@ TEST_BEGIN(test_malloc_strtoumax)
 		{"++3",		"++3",	0,	ERR(EINVAL),	UINTMAX_MAX},
 		{"-",		"-",	0,	ERR(EINVAL),	UINTMAX_MAX},
 
-		{"42",		"",	0,	ERR(0),		UMAX(42)},
-		{"+42",		"",	0,	ERR(0),		UMAX(42)},
-		{"-42",		"",	0,	ERR(0),		UMAX(-42)},
-		{"042",		"",	0,	ERR(0),		UMAX(042)},
-		{"+042",	"",	0,	ERR(0),		UMAX(042)},
-		{"-042",	"",	0,	ERR(0),		UMAX(-042)},
-		{"0x42",	"",	0,	ERR(0),		UMAX(0x42)},
-		{"+0x42",	"",	0,	ERR(0),		UMAX(0x42)},
-		{"-0x42",	"",	0,	ERR(0),		UMAX(-0x42)},
-
-		{"0",		"",	0,	ERR(0),		UMAX(0)},
-		{"1",		"",	0,	ERR(0),		UMAX(1)},
-
-		{"42",		"",	0,	ERR(0),		UMAX(42)},
-		{" 42",		"",	0,	ERR(0),		UMAX(42)},
-		{"42 ",		" ",	0,	ERR(0),		UMAX(42)},
-		{"0x",		"x",	0,	ERR(0),		UMAX(0)},
-		{"42x",		"x",	0,	ERR(0),		UMAX(42)},
-
-		{"07",		"",	0,	ERR(0),		UMAX(7)},
-		{"010",		"",	0,	ERR(0),		UMAX(8)},
-		{"08",		"8",	0,	ERR(0),		UMAX(0)},
-		{"0_",		"_",	0,	ERR(0),		UMAX(0)},
-
-		{"0x",		"x",	0,	ERR(0),		UMAX(0)},
-		{"0X",		"X",	0,	ERR(0),		UMAX(0)},
-		{"0xg",		"xg",	0,	ERR(0),		UMAX(0)},
-		{"0XA",		"",	0,	ERR(0),		UMAX(10)},
-
-		{"010",		"",	10,	ERR(0),		UMAX(10)},
-		{"0x3",		"x3",	10,	ERR(0),		UMAX(0)},
-
-		{"12",		"2",	2,	ERR(0),		UMAX(1)},
-		{"78",		"8",	8,	ERR(0),		UMAX(7)},
-		{"9a",		"a",	10,	ERR(0),		UMAX(9)},
-		{"9A",		"A",	10,	ERR(0),		UMAX(9)},
-		{"fg",		"g",	16,	ERR(0),		UMAX(15)},
-		{"FG",		"G",	16,	ERR(0),		UMAX(15)},
-		{"0xfg",	"g",	16,	ERR(0),		UMAX(15)},
-		{"0XFG",	"G",	16,	ERR(0),		UMAX(15)},
-		{"z_",		"_",	36,	ERR(0),		UMAX(35)},
-		{"Z_",		"_",	36,	ERR(0),		UMAX(35)}
+		{"42",		"",	0,	ERR(0),		KUMAX(42)},
+		{"+42",		"",	0,	ERR(0),		KUMAX(42)},
+		{"-42",		"",	0,	ERR(0),		KUMAX(-42)},
+		{"042",		"",	0,	ERR(0),		KUMAX(042)},
+		{"+042",	"",	0,	ERR(0),		KUMAX(042)},
+		{"-042",	"",	0,	ERR(0),		KUMAX(-042)},
+		{"0x42",	"",	0,	ERR(0),		KUMAX(0x42)},
+		{"+0x42",	"",	0,	ERR(0),		KUMAX(0x42)},
+		{"-0x42",	"",	0,	ERR(0),		KUMAX(-0x42)},
+
+		{"0",		"",	0,	ERR(0),		KUMAX(0)},
+		{"1",		"",	0,	ERR(0),		KUMAX(1)},
+
+		{"42",		"",	0,	ERR(0),		KUMAX(42)},
+		{" 42",		"",	0,	ERR(0),		KUMAX(42)},
+		{"42 ",		" ",	0,	ERR(0),		KUMAX(42)},
+		{"0x",		"x",	0,	ERR(0),		KUMAX(0)},
+		{"42x",		"x",	0,	ERR(0),		KUMAX(42)},
+
+		{"07",		"",	0,	ERR(0),		KUMAX(7)},
+		{"010",		"",	0,	ERR(0),		KUMAX(8)},
+		{"08",		"8",	0,	ERR(0),		KUMAX(0)},
+		{"0_",		"_",	0,	ERR(0),		KUMAX(0)},
+
+		{"0x",		"x",	0,	ERR(0),		KUMAX(0)},
+		{"0X",		"X",	0,	ERR(0),		KUMAX(0)},
+		{"0xg",		"xg",	0,	ERR(0),		KUMAX(0)},
+		{"0XA",		"",	0,	ERR(0),		KUMAX(10)},
+
+		{"010",		"",	10,	ERR(0),		KUMAX(10)},
+		{"0x3",		"x3",	10,	ERR(0),		KUMAX(0)},
+
+		{"12",		"2",	2,	ERR(0),		KUMAX(1)},
+		{"78",		"8",	8,	ERR(0),		KUMAX(7)},
+		{"9a",		"a",	10,	ERR(0),		KUMAX(9)},
+		{"9A",		"A",	10,	ERR(0),		KUMAX(9)},
+		{"fg",		"g",	16,	ERR(0),		KUMAX(15)},
+		{"FG",		"G",	16,	ERR(0),		KUMAX(15)},
+		{"0xfg",	"g",	16,	ERR(0),		KUMAX(15)},
+		{"0XFG",	"G",	16,	ERR(0),		KUMAX(15)},
+		{"z_",		"_",	36,	ERR(0),		KUMAX(35)},
+		{"Z_",		"_",	36,	ERR(0),		KUMAX(35)}
 	};
 #undef ERR
-#undef UMAX
+#undef KUMAX
 	unsigned i;
 
 	for (i = 0; i < sizeof(tests)/sizeof(struct test_s); i++) {
@@ -141,8 +141,8 @@ TEST_BEGIN(test_malloc_snprintf_truncated)
 	char buf[BUFLEN];
 	int result;
 	size_t len;
-#define TEST(expected_str_untruncated, fmt...) do {			\
-	result = malloc_snprintf(buf, len, fmt);			\
+#define TEST(expected_str_untruncated, ...) do {			\
+	result = malloc_snprintf(buf, len, __VA_ARGS__);		\
 	assert_d_eq(strncmp(buf, expected_str_untruncated, len-1), 0,	\
 	    "Unexpected string inequality (\"%s\" vs \"%s\")",		\
 	    buf, expected_str_untruncated);		\
@@ -173,8 +173,8 @@ TEST_BEGIN(test_malloc_snprintf)
 #define	BUFLEN	128
 	char buf[BUFLEN];
 	int result;
-#define	TEST(expected_str, fmt...) do {					\
-	result = malloc_snprintf(buf, sizeof(buf), fmt);		\
+#define	TEST(expected_str, ...) do {					\
+	result = malloc_snprintf(buf, sizeof(buf), __VA_ARGS__);	\
 	assert_str_eq(buf, expected_str, "Unexpected output");		\
 	assert_d_eq(result, strlen(expected_str), "Unexpected result");	\
 } while (0)
diff --git a/src/libpmem.c b/src/libpmem.c
new file mode 100644
index 0000000000000000000000000000000000000000..6fedae7eed502600026feb4bd2713ba1048bc75e
--- /dev/null
+++ b/src/libpmem.c
@@ -0,0 +1,145 @@
+/*
+ * Copyright (c) 2014, Intel Corporation
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ *     * Redistributions of source code must retain the above copyright
+ *       notice, this list of conditions and the following disclaimer.
+ *
+ *     * Redistributions in binary form must reproduce the above copyright
+ *       notice, this list of conditions and the following disclaimer in
+ *       the documentation and/or other materials provided with the
+ *       distribution.
+ *
+ *     * Neither the name of Intel Corporation nor the names of its
+ *       contributors may be used to endorse or promote products derived
+ *       from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+/*
+ * libpmem.c -- basic libpmem functions
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <sys/types.h>
+#include <sys/mman.h>
+#include <unistd.h>
+#include <stdint.h>
+#include <libpmem.h>
+#include "pmem.h"
+#include "util.h"
+#include "out.h"
+
+/*
+ * libpmem_init -- load-time initialization for libpmem
+ *
+ * Called automatically by the run-time loader.
+ */
+__attribute__((constructor))
+static void
+libpmem_init(void)
+{
+	out_init(LOG_PREFIX, LOG_LEVEL_VAR, LOG_FILE_VAR);
+	LOG(3, NULL);
+	util_init();
+}
+
+/*
+ * pmem_check_version -- see if library meets application version requirements
+ */
+const char *
+pmem_check_version(unsigned major_required, unsigned minor_required)
+{
+	LOG(3, "major_required %u minor_required %u",
+			major_required, minor_required);
+
+	static char errstr[] =
+		"libpmem major version mismatch (need XXXX, found YYYY)";
+
+	if (major_required != PMEM_MAJOR_VERSION) {
+		sprintf(errstr,
+			"libpmem major version mismatch (need %d, found %d)",
+			major_required, PMEM_MAJOR_VERSION);
+		LOG(1, "%s", errstr);
+		return errstr;
+	}
+
+	if (minor_required > PMEM_MINOR_VERSION) {
+		sprintf(errstr,
+			"libpmem minor version mismatch (need %d, found %d)",
+			minor_required, PMEM_MINOR_VERSION);
+		LOG(1, "%s", errstr);
+		return errstr;
+	}
+
+	return NULL;
+}
+
+/*
+ * pmem_set_funcs -- allow overriding libpmem's call to malloc, etc.
+ */
+void
+pmem_set_funcs(
+		void *(*malloc_func)(size_t size),
+		void (*free_func)(void *ptr),
+		void *(*realloc_func)(void *ptr, size_t size),
+		char *(*strdup_func)(const char *s),
+		void (*print_func)(const char *s),
+		void (*persist_func)(void *addr, size_t len, int flags))
+{
+	LOG(3, NULL);
+
+	util_set_alloc_funcs(malloc_func, free_func,
+			realloc_func, strdup_func);
+	out_set_print_func(print_func);
+	pmem_set_persist_func(persist_func);
+}
+
+/*
+ * libpmem_persist -- libpmem's central routine for flushing to persistence
+ *
+ * This routine calls msync() or Persist(), depending on the is_pmem flag.
+ */
+void
+libpmem_persist(int is_pmem, void *addr, size_t len)
+{
+	LOG(5, "is_pmem %d addr %p len %zu", is_pmem, addr, len);
+
+	if (is_pmem) {
+		Persist(addr, len, 0);
+		return;
+	}
+
+	uintptr_t uptr;
+
+	/*
+	 * msync requires len to be a multiple of pagesize, so
+	 * adjust addr and len to represent the full 4k chunks
+	 * covering the given range.
+	 */
+
+	/* increase len by the amount we gain when we round addr down */
+	len += (uintptr_t)addr & (Pagesize - 1);
+
+	/* round addr down to page boundary */
+	uptr = (uintptr_t)addr & ~(Pagesize - 1);
+
+	if (msync((void *)uptr, len, MS_SYNC) < 0)
+		LOG(1, "!msync");
+}
diff --git a/src/libpmem.map b/src/libpmem.map
new file mode 100644
index 0000000000000000000000000000000000000000..7734ab817dc55c78b00ad2c2fc0ea9dd2e1d02e5
--- /dev/null
+++ b/src/libpmem.map
@@ -0,0 +1,68 @@
+#
+# Copyright (c) 2014, Intel Corporation
+#
+# Redistribution and use in source and binary forms, with or without
+# modification, are permitted provided that the following conditions
+# are met:
+#
+#     * Redistributions of source code must retain the above copyright
+#       notice, this list of conditions and the following disclaimer.
+#
+#     * Redistributions in binary form must reproduce the above copyright
+#       notice, this list of conditions and the following disclaimer in
+#       the documentation and/or other materials provided with the
+#       distribution.
+#
+#     * Neither the name of Intel Corporation nor the names of its
+#       contributors may be used to endorse or promote products derived
+#       from this software without specific prior written permission.
+#
+# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+#
+#
+# src/libpmem.map -- linker map file for libpmem
+#
+libpmem.so {
+	global:
+		pmem_is_pmem;
+		pmem_persist;
+		pmem_flush;
+		pmem_fence;
+		pmem_drain;
+		pmemtrn_map;
+		pmemtrn_unmap;
+		# XXX rest of pmemtrn API goes here
+		pmemblk_map;
+		pmemblk_unmap;
+		pmemblk_nblock;
+		pmemblk_read;
+		pmemblk_write;
+		pmemblk_set_zero;
+		pmemblk_set_error;
+		pmemlog_map;
+		pmemlog_unmap;
+		pmemlog_nbyte;
+		pmemlog_append;
+		pmemlog_appendv;
+		pmemlog_tell;
+		pmemlog_rewind;
+		pmemlog_walk;
+		pmem_check_version;
+		pmem_set_funcs;
+		pmemtrn_check;
+		pmemblk_check;
+		pmemlog_check;
+
+	local:
+		*;
+};
diff --git a/src/libvmem.c b/src/libvmem.c
new file mode 100644
index 0000000000000000000000000000000000000000..bc8825e9920d315a96f848e49d202176b3975e9a
--- /dev/null
+++ b/src/libvmem.c
@@ -0,0 +1,113 @@
+/*
+ * Copyright (c) 2014, Intel Corporation
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ *     * Redistributions of source code must retain the above copyright
+ *       notice, this list of conditions and the following disclaimer.
+ *
+ *     * Redistributions in binary form must reproduce the above copyright
+ *       notice, this list of conditions and the following disclaimer in
+ *       the documentation and/or other materials provided with the
+ *       distribution.
+ *
+ *     * Neither the name of Intel Corporation nor the names of its
+ *       contributors may be used to endorse or promote products derived
+ *       from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+/*
+ * libvmem.c -- basic libvmem functions
+ */
+
+#include <stdbool.h>
+#include <stdint.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <sys/types.h>
+#include <unistd.h>
+#include <libvmem.h>
+#include "jemalloc.h"
+#include "util.h"
+#include "out.h"
+#include "vmem.h"
+
+
+/*
+ * libvmem_init -- load-time initialization for libvmem
+ *
+ * Called automatically by the run-time loader.
+ */
+__attribute__((constructor))
+static void
+libvmem_init(void)
+{
+	out_init(LOG_PREFIX, LOG_LEVEL_VAR, LOG_FILE_VAR);
+	LOG(3, NULL);
+	util_init();
+}
+
+/*
+ * vmem_check_version -- see if library meets application version requirements
+ */
+const char *
+vmem_check_version(unsigned major_required, unsigned minor_required)
+{
+	LOG(3, "major_required %u minor_required %u",
+			major_required, minor_required);
+
+	static char errstr[] =
+		"libvmem major version mismatch (need XXXX, found YYYY)";
+
+	if (major_required != VMEM_MAJOR_VERSION) {
+		sprintf(errstr,
+			"libvmem major version mismatch (need %d, found %d)",
+			major_required, VMEM_MAJOR_VERSION);
+		LOG(1, "%s", errstr);
+		return errstr;
+	}
+
+	if (minor_required > VMEM_MINOR_VERSION) {
+		sprintf(errstr,
+			"libvmem minor version mismatch (need %d, found %d)",
+			minor_required, VMEM_MINOR_VERSION);
+		LOG(1, "%s", errstr);
+		return errstr;
+	}
+
+	return NULL;
+}
+
+/*
+ * vmem_set_funcs -- allow overriding libvmem's call to malloc, etc.
+ */
+void
+vmem_set_funcs(
+		void *(*malloc_func)(size_t size),
+		void (*free_func)(void *ptr),
+		void *(*realloc_func)(void *ptr, size_t size),
+		char *(*strdup_func)(const char *s),
+		void (*print_func)(const char *s))
+{
+	LOG(3, NULL);
+
+	util_set_alloc_funcs(malloc_func, free_func,
+			realloc_func, strdup_func);
+	out_set_print_func(print_func);
+	je_vmem_pool_set_alloc_funcs(malloc_func, free_func);
+}
diff --git a/src/libvmem.map b/src/libvmem.map
new file mode 100644
index 0000000000000000000000000000000000000000..1853d1a13361739252d8bd3b649229aea67b7c3e
--- /dev/null
+++ b/src/libvmem.map
@@ -0,0 +1,54 @@
+#
+# Copyright (c) 2014, Intel Corporation
+#
+# Redistribution and use in source and binary forms, with or without
+# modification, are permitted provided that the following conditions
+# are met:
+#
+#     * Redistributions of source code must retain the above copyright
+#       notice, this list of conditions and the following disclaimer.
+#
+#     * Redistributions in binary form must reproduce the above copyright
+#       notice, this list of conditions and the following disclaimer in
+#       the documentation and/or other materials provided with the
+#       distribution.
+#
+#     * Neither the name of Intel Corporation nor the names of its
+#       contributors may be used to endorse or promote products derived
+#       from this software without specific prior written permission.
+#
+# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+#
+#
+# src/libvmem.map -- linker map file for libvmem
+#
+libvmem.so {
+	global:
+		vmem_pool_create;
+		vmem_pool_create_in_region;
+		vmem_pool_delete;
+		vmem_pool_check;
+		vmem_pool_freespace;
+		vmem_pool_stats_print;
+		vmem_malloc;
+		vmem_free;
+		vmem_calloc;
+		vmem_realloc;
+		vmem_aligned_alloc;
+		vmem_strdup;
+		vmem_check_version;
+		vmem_set_funcs;
+
+	local:
+		*;
+};
diff --git a/src/log.c b/src/log.c
new file mode 100644
index 0000000000000000000000000000000000000000..fe16888e8cea04ce32dd7502975f9f6bfd3de6bd
--- /dev/null
+++ b/src/log.c
@@ -0,0 +1,637 @@
+/*
+ * Copyright (c) 2014, Intel Corporation
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ *     * Redistributions of source code must retain the above copyright
+ *       notice, this list of conditions and the following disclaimer.
+ *
+ *     * Redistributions in binary form must reproduce the above copyright
+ *       notice, this list of conditions and the following disclaimer in
+ *       the documentation and/or other materials provided with the
+ *       distribution.
+ *
+ *     * Neither the name of Intel Corporation nor the names of its
+ *       contributors may be used to endorse or promote products derived
+ *       from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY LOG OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+/*
+ * log.c -- log memory pool entry points for libpmem
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <sys/types.h>
+#include <sys/param.h>
+#include <sys/stat.h>
+#include <signal.h>
+#include <fcntl.h>
+#include <unistd.h>
+#include <errno.h>
+#include <time.h>
+#include <stdint.h>
+#include <pthread.h>
+#include <uuid/uuid.h>
+#include <endian.h>
+#include <libpmem.h>
+
+#include "pmem.h"
+#include "util.h"
+#include "out.h"
+#include "log.h"
+
+/*
+ * log_init -- load-time initialization for log
+ *
+ * Called automatically by the run-time loader.
+ */
+__attribute__((constructor))
+static void
+log_init(void)
+{
+	out_init(LOG_PREFIX, LOG_LEVEL_VAR, LOG_FILE_VAR);
+	LOG(3, NULL);
+	util_init();
+}
+
+/*
+ * pmemlog_map_common -- (internal) map a log memory pool
+ *
+ * This routine does all the work, but takes a rdonly flag so internal
+ * calls can map a read-only pool if required.
+ */
+static PMEMlog *
+pmemlog_map_common(int fd, int rdonly)
+{
+	LOG(3, "fd %d rdonly %d", fd, rdonly);
+
+	struct stat stbuf;
+	if (fstat(fd, &stbuf) < 0) {
+		LOG(1, "!fstat");
+		return NULL;
+	}
+
+	if (stbuf.st_size < PMEMLOG_MIN_POOL) {
+		LOG(1, "size %zu smaller than %zu",
+				stbuf.st_size, PMEMLOG_MIN_POOL);
+		errno = EINVAL;
+		return NULL;
+	}
+
+	void *addr;
+	if ((addr = util_map(fd, stbuf.st_size, rdonly)) == NULL)
+		return NULL;	/* util_map() set errno, called LOG */
+
+	/* check if the mapped region is located in persistent memory */
+	int is_pmem = pmem_is_pmem(addr, stbuf.st_size);
+
+	/* opaque info lives at the beginning of mapped memory pool */
+	struct pmemlog *plp = addr;
+	struct pool_hdr hdr;
+
+	memcpy(&hdr, &plp->hdr, sizeof (hdr));
+
+	if (util_convert_hdr(&hdr)) {
+		/*
+		 * valid header found
+		 */
+		if (strncmp(hdr.signature, LOG_HDR_SIG, POOL_HDR_SIG_LEN)) {
+			LOG(1, "wrong pool type: \"%s\"", hdr.signature);
+			errno = EINVAL;
+			goto err;
+		}
+
+		if (hdr.major != LOG_FORMAT_MAJOR) {
+			LOG(1, "log pool version %d (library expects %d)",
+				hdr.major, LOG_FORMAT_MAJOR);
+			errno = EINVAL;
+			goto err;
+		}
+
+		uint64_t hdr_start = le64toh(plp->start_offset);
+		uint64_t hdr_end = le64toh(plp->end_offset);
+		uint64_t hdr_write = le64toh(plp->write_offset);
+
+		if ((hdr_start != roundup(sizeof (*plp),
+					LOG_FORMAT_DATA_ALIGN)) ||
+			(hdr_end != stbuf.st_size) || (hdr_start > hdr_end)) {
+			LOG(1, "wrong start/end offsets (start: %zu end: %zu), "
+				"pool size %zu",
+				hdr_start, hdr_end, stbuf.st_size);
+			errno = EINVAL;
+			goto err;
+		}
+
+		if ((hdr_write > hdr_end) || (hdr_write < hdr_start)) {
+			LOG(1, "wrong write offset "
+				"(start: %zu end: %zu write: %zu)",
+				hdr_start, hdr_end, hdr_write);
+			errno = EINVAL;
+			goto err;
+		}
+
+		LOG(3, "start: %zu, end: %zu, write: %zu",
+			hdr_start, hdr_end, hdr_write);
+
+		int retval = util_feature_check(&hdr, LOG_FORMAT_INCOMPAT,
+							LOG_FORMAT_RO_COMPAT,
+							LOG_FORMAT_COMPAT);
+		if (retval < 0)
+		    goto err;
+		else if (retval == 0)
+		    rdonly = 1;
+	} else {
+		/*
+		 * no valid header was found
+		 */
+		if (rdonly) {
+			LOG(1, "read-only and no header found");
+			errno = EROFS;
+			goto err;
+		}
+		LOG(3, "creating new log memory pool");
+
+		struct pool_hdr *hdrp = &plp->hdr;
+
+		memset(hdrp, '\0', sizeof (*hdrp));
+		strncpy(hdrp->signature, LOG_HDR_SIG, POOL_HDR_SIG_LEN);
+		hdrp->major = htole32(LOG_FORMAT_MAJOR);
+		hdrp->compat_features = htole32(LOG_FORMAT_COMPAT);
+		hdrp->incompat_features = htole32(LOG_FORMAT_INCOMPAT);
+		hdrp->ro_compat_features = htole32(LOG_FORMAT_RO_COMPAT);
+		uuid_generate(hdrp->uuid);
+		hdrp->crtime = htole64((uint64_t)time(NULL));
+		util_checksum(hdrp, sizeof (*hdrp), &hdrp->checksum, 1);
+		hdrp->checksum = htole64(hdrp->checksum);
+
+		/* store pool's header */
+		libpmem_persist(is_pmem, hdrp, sizeof (*hdrp));
+
+		/* create rest of required metadata */
+		plp->start_offset = htole64(roundup(sizeof (*plp),
+						LOG_FORMAT_DATA_ALIGN));
+		plp->end_offset = htole64(stbuf.st_size);
+		plp->write_offset = plp->start_offset;
+
+		/* store non-volatile part of pool's descriptor */
+		libpmem_persist(is_pmem, &plp->start_offset,
+							3 * sizeof (uint64_t));
+	}
+
+	/*
+	 * Use some of the memory pool area for run-time info.  This
+	 * run-time state is never loaded from the file, it is always
+	 * created here, so no need to worry about byte-order.
+	 */
+	plp->addr = addr;
+	plp->size = stbuf.st_size;
+	plp->rdonly = rdonly;
+	plp->is_pmem = is_pmem;
+
+	if ((plp->rwlockp = Malloc(sizeof (*plp->rwlockp))) == NULL) {
+		LOG(1, "!Malloc for a RW lock");
+		goto err;
+	}
+
+	if (pthread_rwlock_init(plp->rwlockp, NULL)) {
+		LOG(1, "!pthread_rwlock_init");
+		goto err_free;
+	}
+
+	/*
+	 * If possible, turn off all permissions on the pool header page.
+	 *
+	 * The prototype PMFS doesn't allow this when large pages are in
+	 * use not it is not considered an error if this fails.
+	 */
+	util_range_none(addr, sizeof (struct pool_hdr));
+
+	/* the rest should be kept read-only (debug version only) */
+	RANGE_RO(addr + sizeof (struct pool_hdr),
+			stbuf.st_size - sizeof (struct pool_hdr));
+
+	LOG(3, "plp %p", plp);
+	return plp;
+
+err_free:
+	Free((void *)plp->rwlockp);
+err:
+	LOG(4, "error clean up");
+	int oerrno = errno;
+	util_unmap(addr, stbuf.st_size);
+	errno = oerrno;
+	return NULL;
+}
+
+/*
+ * pmemlog_map -- map a log memory pool
+ */
+PMEMlog *
+pmemlog_map(int fd)
+{
+	LOG(3, "fd %d", fd);
+
+	return pmemlog_map_common(fd, 0);
+}
+
+/*
+ * pmemlog_unmap -- unmap a log memory pool
+ */
+void
+pmemlog_unmap(PMEMlog *plp)
+{
+	LOG(3, "plp %p", plp);
+
+	if (pthread_rwlock_destroy(plp->rwlockp))
+		LOG(1, "!pthread_rwlock_destroy");
+	Free((void *)plp->rwlockp);
+	util_unmap(plp->addr, plp->size);
+}
+
+/*
+ * pmemlog_nbyte -- return usable size of a log memory pool
+ */
+size_t
+pmemlog_nbyte(PMEMlog *plp)
+{
+	LOG(3, "plp %p", plp);
+
+	if (pthread_rwlock_rdlock(plp->rwlockp)) {
+		LOG(1, "!pthread_rwlock_rdlock");
+		return (size_t)-1;
+	}
+
+	size_t size = le64toh(plp->end_offset) - le64toh(plp->start_offset);
+	LOG(4, "plp %p nbyte %zu", plp, size);
+
+	if (pthread_rwlock_unlock(plp->rwlockp))
+		LOG(1, "!pthread_rwlock_unlock");
+
+	return size;
+}
+
+/*
+ * pmemlog_persist -- (internal) persist data, then metadata
+ *
+ * On entry, the write lock should be held.
+ */
+static void
+pmemlog_persist(PMEMlog *plp, uint64_t new_write_offset)
+{
+	uint64_t old_write_offset = le64toh(plp->write_offset);
+	size_t length = new_write_offset - old_write_offset;
+
+	/* unprotect the log space range (debug version only) */
+	RANGE_RW(plp->addr + old_write_offset, length);
+
+	/* persist the data */
+	libpmem_persist(plp->is_pmem, plp->addr + old_write_offset, length);
+
+	/* protect the log space range (debug version only) */
+	RANGE_RO(plp->addr + old_write_offset, length);
+
+	/* unprotect the pool descriptor (debug version only) */
+	RANGE_RW(plp->addr + sizeof (struct pool_hdr), LOG_FORMAT_DATA_ALIGN);
+
+	/* write the metadata */
+	plp->write_offset = htole64(new_write_offset);
+
+	/* persist the metadata */
+	libpmem_persist(plp->is_pmem, &plp->write_offset,
+			sizeof (plp->write_offset));
+
+	/* set the write-protection again (debug version only) */
+	RANGE_RO(plp->addr + sizeof (struct pool_hdr), LOG_FORMAT_DATA_ALIGN);
+}
+
+/*
+ * pmemlog_append -- add data to a log memory pool
+ */
+int
+pmemlog_append(PMEMlog *plp, const void *buf, size_t count)
+{
+	int ret = 0;
+
+	LOG(3, "plp %p buf %p count %zu", plp, buf, count);
+
+	if (plp->rdonly) {
+		LOG(1, "can't append to read-only log");
+		errno = EROFS;
+		return -1;
+	}
+
+	if (pthread_rwlock_wrlock(plp->rwlockp)) {
+		LOG(1, "!pthread_rwlock_wrlock");
+		return -1;
+	}
+
+	/* get the current values */
+	uint64_t end_offset = le64toh(plp->end_offset);
+	uint64_t write_offset = le64toh(plp->write_offset);
+
+	if (write_offset >= end_offset) {
+		/* no space left */
+		errno = ENOSPC;
+		ret = -1;
+	} else {
+		/* make sure we don't write past the available space */
+		if (count > (end_offset - write_offset)) {
+			errno = ENOSPC;
+			ret = -1;
+		} else {
+			char *data = plp->addr;
+
+			/*
+			 * unprotect the log space range,
+			 * where the new data will be stored
+			 * (debug version only)
+			 */
+			RANGE_RW(&data[write_offset], count);
+
+			memcpy(&data[write_offset], buf, count);
+
+			/* protect the log space range (debug version only) */
+			RANGE_RO(&data[write_offset], count);
+
+			write_offset += count;
+		}
+	}
+
+	/* persist the data and the metadata only if there was no error */
+	if (ret == 0)
+		pmemlog_persist(plp, write_offset);
+
+	int oerrno = errno;
+	if (pthread_rwlock_unlock(plp->rwlockp))
+		LOG(1, "!pthread_rwlock_unlock");
+	errno = oerrno;
+
+	return ret;
+}
+
+/*
+ * pmemlog_appendv -- add gathered data to a log memory pool
+ */
+int
+pmemlog_appendv(PMEMlog *plp, const struct iovec *iov, int iovcnt)
+{
+	LOG(3, "plp %p iovec %p iovcnt %d", plp, iov, iovcnt);
+
+	int ret = 0; // success
+	int i;
+
+	if (plp->rdonly) {
+		LOG(1, "can't append to read-only log");
+		errno = EROFS;
+		return -1;
+	}
+
+	if (pthread_rwlock_wrlock(plp->rwlockp)) {
+		LOG(1, "!pthread_rwlock_wrlock");
+		return -1;
+	}
+
+	/* get the current values */
+	uint64_t end_offset = le64toh(plp->end_offset);
+	uint64_t write_offset = le64toh(plp->write_offset);
+
+	if (write_offset >= end_offset) {
+		/* no space left */
+		errno = ENOSPC;
+		ret = -1;
+	} else {
+		char *data = plp->addr;
+		uint64_t count = 0;
+		char *buf;
+
+		/* calculate required space */
+		for (i = 0; i < iovcnt; ++i)
+			count += iov[i].iov_len;
+
+		/* check if there is enough free space */
+		if (count > (end_offset - write_offset)) {
+			errno = ENOSPC;
+			ret = -1;
+		} else {
+			/* append the data */
+			for (i = 0; i < iovcnt; ++i) {
+				buf = iov[i].iov_base;
+				count = iov[i].iov_len;
+
+				/*
+				 * unprotect the log space range,
+				 * where the new data will be stored
+				 * (debug version only)
+				 */
+				RANGE_RW(&data[write_offset], count);
+
+				memcpy(&data[write_offset], buf, count);
+
+				/*
+				 * protect the log space range
+				 * (debug version only)
+				 */
+				RANGE_RO(&data[write_offset], count);
+
+				write_offset += count;
+			}
+		}
+	}
+
+	/* persist the data and the metadata only if there was no error */
+	if (ret == 0)
+		pmemlog_persist(plp, write_offset);
+
+	int oerrno = errno;
+	if (pthread_rwlock_unlock(plp->rwlockp))
+		LOG(1, "!pthread_rwlock_unlock");
+	errno = oerrno;
+
+	return ret;
+}
+
+/*
+ * pmemlog_tell -- return current write point in a log memory pool
+ */
+off_t
+pmemlog_tell(PMEMlog *plp)
+{
+	LOG(3, "plp %p", plp);
+
+	if (pthread_rwlock_rdlock(plp->rwlockp)) {
+		LOG(1, "!pthread_rwlock_rdlock");
+		return (off_t)-1;
+	}
+
+	off_t wp = le64toh(plp->write_offset) - le64toh(plp->start_offset);
+	LOG(4, "write offset %zu", wp);
+
+	if (pthread_rwlock_unlock(plp->rwlockp))
+		LOG(1, "!pthread_rwlock_unlock");
+
+	return wp;
+}
+
+/*
+ * pmemlog_rewind -- discard all data, resetting a log memory pool to empty
+ */
+void
+pmemlog_rewind(PMEMlog *plp)
+{
+	LOG(3, "plp %p", plp);
+
+	if (plp->rdonly) {
+		LOG(1, "can't rewind read-only log");
+		errno = EROFS;
+		return;
+	}
+
+	if (pthread_rwlock_wrlock(plp->rwlockp)) {
+		LOG(1, "!pthread_rwlock_wrlock");
+		return;
+	}
+
+	/* unprotect the pool descriptor (debug version only) */
+	RANGE_RW(plp->addr + sizeof (struct pool_hdr), LOG_FORMAT_DATA_ALIGN);
+
+	plp->write_offset = plp->start_offset;
+	libpmem_persist(plp->is_pmem, &plp->write_offset, sizeof (uint64_t));
+
+	/* set the write-protection again (debug version only) */
+	RANGE_RO(plp->addr + sizeof (struct pool_hdr), LOG_FORMAT_DATA_ALIGN);
+
+	if (pthread_rwlock_unlock(plp->rwlockp))
+		LOG(1, "!pthread_rwlock_unlock");
+}
+
+/*
+ * pmemlog_walk -- walk through all data in a log memory pool
+ *
+ * chunksize of 0 means process_chunk gets called once for all data
+ * as a single chunk.
+ */
+void
+pmemlog_walk(PMEMlog *plp, size_t chunksize,
+	int (*process_chunk)(const void *buf, size_t len, void *arg), void *arg)
+{
+	LOG(3, "plp %p chunksize %zu", plp, chunksize);
+
+	/*
+	 * We are assuming that the walker doesn't change the data it's reading
+	 * in place. We prevent everyone from changing the data behind our back
+	 * until we are done with processing it.
+	 */
+	if (pthread_rwlock_rdlock(plp->rwlockp)) {
+		LOG(1, "!pthread_rwlock_rdlock");
+		return;
+	}
+
+	char *data = plp->addr;
+	uint64_t write_offset = le64toh(plp->write_offset);
+	uint64_t data_offset = le64toh(plp->start_offset);
+	size_t len;
+
+	if (chunksize == 0) {
+		/* most common case: process everything at once */
+		len = write_offset - data_offset;
+		LOG(3, "length %zu", len);
+		(*process_chunk)(&data[data_offset], len, arg);
+	} else {
+		/*
+		 * Walk through the complete record, chunk by chunk.
+		 * The callback returns 0 to terminate the walk.
+		 */
+		while (data_offset < write_offset) {
+			len = MIN(chunksize, write_offset - data_offset);
+			if (!(*process_chunk)(&data[data_offset], len, arg))
+				break;
+			data_offset += chunksize;
+		}
+	}
+
+	if (pthread_rwlock_unlock(plp->rwlockp))
+		LOG(1, "!pthread_rwlock_unlock");
+}
+
+/*
+ * pmemlog_check -- log memory pool consistency check
+ *
+ * Returns true if consistent, zero if inconsistent, -1/error if checking
+ * cannot happen due to other errors.
+ */
+int
+pmemlog_check(const char *path)
+{
+	LOG(3, "path \"%s\"", path);
+
+	int fd = open(path, O_RDWR);
+
+	if (fd < 0) {
+		LOG(1, "!open");
+		return -1;
+	}
+
+	/* open the pool read-only */
+	PMEMlog *plp = pmemlog_map_common(fd, 1);
+	int oerrno = errno;
+	close(fd);
+	errno = oerrno;
+
+	if (plp == NULL)
+		return -1;	/* errno set by pmemlog_map_common() */
+
+	int consistent = 1;
+
+	/* validate pool descriptor */
+	uint64_t hdr_start = le64toh(plp->start_offset);
+	uint64_t hdr_end = le64toh(plp->end_offset);
+	uint64_t hdr_write = le64toh(plp->write_offset);
+
+	if (hdr_start != roundup(sizeof (*plp), LOG_FORMAT_DATA_ALIGN)) {
+		LOG(1, "wrong value of start_offset");
+		consistent = 0;
+	}
+
+	if (hdr_end != plp->size) {
+		LOG(1, "wrong value of end_offset");
+		consistent = 0;
+	}
+
+	if (hdr_start > hdr_end) {
+		LOG(1, "start_offset greater than end_offset");
+		consistent = 0;
+	}
+
+	if (hdr_start > hdr_write) {
+		LOG(1, "start_offset greater than write_offset");
+		consistent = 0;
+	}
+
+	if (hdr_write > hdr_end) {
+		LOG(1, "write_offset greater than end_offset");
+		consistent = 0;
+	}
+
+	pmemlog_unmap(plp);
+
+	if (consistent)
+		LOG(4, "pool consistency check OK");
+
+	return consistent;
+}
diff --git a/src/log.h b/src/log.h
new file mode 100644
index 0000000000000000000000000000000000000000..f1ea5f72d9d14b80815d4032440d6ac45c672261
--- /dev/null
+++ b/src/log.h
@@ -0,0 +1,61 @@
+/*
+ * Copyright (c) 2014, Intel Corporation
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ *     * Redistributions of source code must retain the above copyright
+ *       notice, this list of conditions and the following disclaimer.
+ *
+ *     * Redistributions in binary form must reproduce the above copyright
+ *       notice, this list of conditions and the following disclaimer in
+ *       the documentation and/or other materials provided with the
+ *       distribution.
+ *
+ *     * Neither the name of Intel Corporation nor the names of its
+ *       contributors may be used to endorse or promote products derived
+ *       from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+/*
+ * log.h -- internal definitions for libpmem log module
+ */
+
+/* attributes of the log memory pool format for the pool header */
+#define	LOG_HDR_SIG "PMEMLOG"	/* must be 8 bytes including '\0' */
+#define	LOG_FORMAT_MAJOR 1
+#define	LOG_FORMAT_COMPAT 0x0000
+#define	LOG_FORMAT_INCOMPAT 0x0000
+#define	LOG_FORMAT_RO_COMPAT 0x0000
+
+struct pmemlog {
+	struct pool_hdr hdr;	/* memory pool header */
+
+	/* root info for on-media format... */
+	uint64_t start_offset;	/* start offset of the usable log space */
+	uint64_t end_offset;	/* maximum offset of the usable log space */
+	uint64_t write_offset;	/* current write point for the log */
+
+	/* some run-time state, allocated out of memory pool... */
+	void *addr;			/* mapped region */
+	size_t size;			/* size of mapped region */
+	int is_pmem;			/* true if pool is PMEM */
+	int rdonly;			/* true if pool is opened read-only */
+	pthread_rwlock_t *rwlockp;	/* pointer to RW lock */
+};
+
+/* data area starts at this alignement after the struct pmemlog above */
+#define	LOG_FORMAT_DATA_ALIGN 4096
diff --git a/src/nondebug/Makefile b/src/nondebug/Makefile
new file mode 100644
index 0000000000000000000000000000000000000000..b29e373e0aee15615b51f1de87d51496a0ed6fce
--- /dev/null
+++ b/src/nondebug/Makefile
@@ -0,0 +1,37 @@
+#
+# Copyright (c) 2014, Intel Corporation
+#
+# Redistribution and use in source and binary forms, with or without
+# modification, are permitted provided that the following conditions
+# are met:
+#
+#     * Redistributions of source code must retain the above copyright
+#       notice, this list of conditions and the following disclaimer.
+#
+#     * Redistributions in binary form must reproduce the above copyright
+#       notice, this list of conditions and the following disclaimer in
+#       the documentation and/or other materials provided with the
+#       distribution.
+#
+#     * Neither the name of Intel Corporation nor the names of its
+#       contributors may be used to endorse or promote products derived
+#       from this software without specific prior written permission.
+#
+# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+#
+
+#
+# src/nondebug/Makefile -- build the nondebug versions of the NVM Library
+#
+
+include ../Makefile.inc
diff --git a/src/nondebug/README b/src/nondebug/README
new file mode 100644
index 0000000000000000000000000000000000000000..df58b8a9591c235297948ad9beb41714e020e0d9
--- /dev/null
+++ b/src/nondebug/README
@@ -0,0 +1,9 @@
+Linux NVM Library
+
+This is src/nondebug/README.
+
+This directory is where nondebug versions of the object files and
+the targets end up.  To build just the nondebug version of the
+library, use "make all" from this directory.  To build both
+the debug and nondebug version, use "make all" from the parent
+directory.
diff --git a/src/out.c b/src/out.c
new file mode 100644
index 0000000000000000000000000000000000000000..8c3664c5e8af423fbdde2cf4c3dfa5df8f14fad5
--- /dev/null
+++ b/src/out.c
@@ -0,0 +1,263 @@
+/*
+ * Copyright (c) 2014, Intel Corporation
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ *     * Redistributions of source code must retain the above copyright
+ *       notice, this list of conditions and the following disclaimer.
+ *
+ *     * Redistributions in binary form must reproduce the above copyright
+ *       notice, this list of conditions and the following disclaimer in
+ *       the documentation and/or other materials provided with the
+ *       distribution.
+ *
+ *     * Neither the name of Intel Corporation nor the names of its
+ *       contributors may be used to endorse or promote products derived
+ *       from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+/*
+ * out.c -- support for logging, tracing, and assertion output
+ *
+ * Macros like LOG(), OUT, ASSERT(), etc. end up here.
+ */
+
+#include <stdio.h>
+#include <stdarg.h>
+#include <stdlib.h>
+#include <sys/types.h>
+#include <unistd.h>
+#include <dirent.h>
+#include <string.h>
+#include <errno.h>
+#include <libvmem.h>
+#include "out.h"
+
+char nvml_src_version[] = "SRCVERSION:" SRCVERSION;
+
+static const char *Log_prefix;
+static int Log_level;
+static FILE *Out_fp;
+
+#ifdef	DEBUG
+/*
+ * getexecname -- return name of current executable
+ *
+ * This function is only used when logging is enabled, to make
+ * it more clear in the log which program was running.
+ */
+static const char *
+getexecname(void)
+{
+	char procpath[PATH_MAX];
+	static char namepath[PATH_MAX];
+	int cc;
+
+	snprintf(procpath, PATH_MAX, "/proc/%d/exe", getpid());
+
+	if ((cc = readlink(procpath, namepath, PATH_MAX)) < 0)
+		strcpy(namepath, "unknown");
+	else
+		namepath[cc] = '\0';
+
+	return namepath;
+}
+#endif	/* DEBUG */
+
+/*
+ * out_init -- initialize the log
+ *
+ * This is called from the library initialization code.
+ */
+void
+out_init(const char *log_prefix, const char *log_level_var,
+		const char *log_file_var)
+{
+	static int once;
+
+	/* only need to initialize the out module once */
+	if (once)
+		return;
+	once++;
+
+	Log_prefix = log_prefix;
+
+#ifdef	DEBUG
+	char *log_level;
+	char *log_file;
+
+	if ((log_level = getenv(log_level_var)) != NULL) {
+		Log_level = atoi(log_level);
+		if (Log_level < 0) {
+			Log_level = 0;
+		}
+	}
+
+	if ((log_file = getenv(log_file_var)) != NULL &&
+				((Out_fp = fopen(log_file, "w")) == NULL)) {
+		fprintf(stderr, "Error: %s=%s: %s\n",
+				log_file_var, log_file, strerror(errno));
+		exit(1);
+	}
+#endif	/* DEBUG */
+
+	if (Out_fp == NULL)
+		Out_fp = stderr;
+	else
+		setlinebuf(Out_fp);
+
+	LOG(1, "pid %d: program: %s", getpid(), getexecname());
+	LOG(1, "version %d.%d",	VMEM_MAJOR_VERSION, VMEM_MINOR_VERSION);
+	LOG(1, "src version %s", nvml_src_version);
+}
+
+/*
+ * out_fini -- close the log file
+ *
+ * This is called to close log file before process stop.
+ */
+void
+out_fini()
+{
+	if (Out_fp != NULL && Out_fp != stderr) {
+		fclose(Out_fp);
+		Out_fp = stderr;
+	}
+}
+
+/*
+ * out_print_func -- default print_func, goes to stderr or Out_fp
+ */
+static void
+out_print_func(const char *s)
+{
+	fputs(s, Out_fp);
+}
+
+/*
+ * calling Print(s) calls the current print_func...
+ */
+typedef void (*Print_func)(const char *s);
+static Print_func Print = out_print_func;
+
+/*
+ * out_set_print_func -- allow override of print_func used by out module
+ */
+void
+out_set_print_func(void (*print_func)(const char *s))
+{
+	LOG(3, "print %p", print_func);
+
+	Print = (print_func == NULL) ? out_print_func : print_func;
+}
+
+/*
+ * out_common -- common output code, all output goes through here
+ */
+#define	MAXPRINT 8192	/* maximum expected log line */
+static void
+out_common(const char *file, int line, const char *func, int level,
+		const char *suffix, const char *fmt, va_list ap)
+{
+	int oerrno = errno;
+	char buf[MAXPRINT];
+	int cc = 0;
+	const char *sep = "";
+	const char *errstr = "";
+
+	if (file)
+		cc += snprintf(&buf[cc], MAXPRINT - cc,
+				"<%s>: <%d> [%s:%d %s] ",
+				Log_prefix, level, file, line, func);
+
+	if (fmt) {
+		if (*fmt == '!') {
+			fmt++;
+			sep = ": ";
+			errstr = strerror(errno);
+		}
+		cc += vsnprintf(&buf[cc], MAXPRINT - cc, fmt, ap);
+	}
+
+	snprintf(&buf[cc], MAXPRINT - cc, "%s%s%s", sep, errstr, suffix);
+
+	Print(buf);
+	errno = oerrno;
+}
+
+/*
+ * out -- output a line, newline added automatically
+ */
+void
+out(const char *fmt, ...)
+{
+	va_list ap;
+	va_start(ap, fmt);
+
+	out_common(NULL, 0, NULL, 0, "\n", fmt, ap);
+
+	va_end(ap);
+}
+
+/*
+ * out_nonl -- output a line, no newline added automatically
+ */
+void
+out_nonl(int level, const char *fmt, ...)
+{
+	va_list ap;
+	va_start(ap, fmt);
+
+	out_common(NULL, 0, NULL, level, "", fmt, ap);
+
+	va_end(ap);
+}
+
+/*
+ * out_log -- output a log line if Log_level >= level
+ */
+void
+out_log(const char *file, int line, const char *func, int level,
+		const char *fmt, ...)
+{
+	va_list ap;
+
+	if (Log_level < level)
+			return;
+
+	va_start(ap, fmt);
+	out_common(file, line, func, level, "\n", fmt, ap);
+
+	va_end(ap);
+}
+
+/*
+ * out_fatal -- output a fatal error & die (i.e. assertion failure)
+ */
+void
+out_fatal(const char *file, int line, const char *func,
+		const char *fmt, ...)
+{
+	va_list ap;
+	va_start(ap, fmt);
+
+	out_common(file, line, func, 1, "\n", fmt, ap);
+
+	va_end(ap);
+
+	exit(1);
+}
diff --git a/src/out.h b/src/out.h
new file mode 100644
index 0000000000000000000000000000000000000000..59d56811bcbab90168ab7d6ed0307f79faabe961
--- /dev/null
+++ b/src/out.h
@@ -0,0 +1,102 @@
+/*
+ * Copyright (c) 2014, Intel Corporation
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ *     * Redistributions of source code must retain the above copyright
+ *       notice, this list of conditions and the following disclaimer.
+ *
+ *     * Redistributions in binary form must reproduce the above copyright
+ *       notice, this list of conditions and the following disclaimer in
+ *       the documentation and/or other materials provided with the
+ *       distribution.
+ *
+ *     * Neither the name of Intel Corporation nor the names of its
+ *       contributors may be used to endorse or promote products derived
+ *       from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+/*
+ * out.h -- definitions for "out" module
+ */
+
+#ifdef	DEBUG
+
+/* produce debug/trace output */
+#define	LOG(level, ...)\
+	out_log(__FILE__, __LINE__, __func__, level, __VA_ARGS__)
+
+/* produce debug/trace output without prefix and new line */
+#define	LOG_NONL(level, ...)\
+	out_nonl(level, __VA_ARGS__)
+
+/* produce output and exit */
+#define	FATAL(...)\
+	out_fatal(__FILE__, __LINE__, __func__, __VA_ARGS__)
+
+/* assert a condition is true */
+#define	ASSERT(cnd)\
+	((void)((cnd) || (out_fatal(__FILE__, __LINE__, __func__,\
+	"assertion failure: %s", #cnd), 0)))
+
+/* assertion with extra info printed if assertion fails */
+#define	ASSERTinfo(cnd, info)\
+	((void)((cnd) || (out_fatal(__FILE__, __LINE__, __func__,\
+	"assertion failure: %s (%s = %s)", #cnd, #info, info), 0)))
+
+/* assert two integer values are equal */
+#define	ASSERTeq(lhs, rhs)\
+	((void)(((lhs) == (rhs)) || (out_fatal(__FILE__, __LINE__, __func__,\
+	"assertion failure: %s (0x%llx) == %s (0x%llx)", #lhs,\
+	(unsigned long long)(lhs), #rhs, (unsigned long long)(rhs)), 0)))
+
+/* assert two integer values are not equal */
+#define	ASSERTne(lhs, rhs)\
+	((void)(((lhs) != (rhs)) || (out_fatal(__FILE__, __LINE__, __func__,\
+	"assertion failure: %s (0x%llx) != %s (0x%llx)", #lhs,\
+	(unsigned long long)(lhs), #rhs, (unsigned long long)(rhs)), 0)))
+
+#else
+
+/*
+ * nondebug versions...
+ */
+#define	LOG(level, ...)
+#define	LOG_NONL(level, ...)
+#define	ASSERT(cnd)
+#define	ASSERTinfo(cnd, info)
+#define	ASSERTeq(lhs, rhs)
+#define	ASSERTne(lhs, rhs)
+
+/* shouldn't get called, but if it does, don't continue to run */
+#define	FATAL(...) abort()
+
+#endif	/* DEBUG */
+
+void out_init(const char *log_prefix, const char *log_level_var,
+		const char *log_file_var);
+void out_fini();
+void out(const char *fmt, ...) __attribute__((format(printf, 1, 2)));
+void out_nonl(int level, const char *fmt,
+	...) __attribute__((format(printf, 2, 3)));
+void out_log(const char *file, int line, const char *func, int level,
+	const char *fmt, ...)
+	__attribute__((format(printf, 5, 6)));
+void out_fatal(const char *file, int line, const char *func,
+	const char *fmt, ...)
+	__attribute__((format(printf, 4, 5)));
+void out_set_print_func(void (*print_func)(const char *s));
diff --git a/src/pmem.c b/src/pmem.c
new file mode 100644
index 0000000000000000000000000000000000000000..da99d28d293808e9b83fb737fe7891aa0d8bbbdd
--- /dev/null
+++ b/src/pmem.c
@@ -0,0 +1,265 @@
+/*
+ * Copyright (c) 2013, Intel Corporation
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ *     * Redistributions of source code must retain the above copyright
+ *       notice, this list of conditions and the following disclaimer.
+ *
+ *     * Redistributions in binary form must reproduce the above copyright
+ *       notice, this list of conditions and the following disclaimer in
+ *       the documentation and/or other materials provided with the
+ *       distribution.
+ *
+ *     * Neither the name of Intel Corporation nor the names of its
+ *       contributors may be used to endorse or promote products derived
+ *       from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+/*
+ * pmem.c -- pmem entry points for libpmem
+ */
+
+#include <sys/types.h>
+#include <sys/mman.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <stdint.h>
+#include <string.h>
+
+#include "libpmem.h"
+#include "pmem.h"
+#include "util.h"
+#include "out.h"
+
+#define	FLUSH_ALIGN 64
+
+/* default persist function is pmem_persist() */
+Persist_func Persist = pmem_persist;
+
+/*
+ * pmem_set_persist_func -- allow override of persist_func used libpmem
+ */
+void
+pmem_set_persist_func(void (*persist_func)(void *addr, size_t len, int flags))
+{
+	LOG(3, "persist %p", persist_func);
+
+	Persist = (persist_func == NULL) ? pmem_persist : persist_func;
+}
+
+/*
+ * pmem_drain -- wait for any PM stores to drain from HW buffers
+ */
+void
+pmem_drain(void)
+{
+	/*
+	 * Nothing to do here -- assumes an auto-drain feature like ADR.
+	 *
+	 * XXX handle drain for other platforms
+	 */
+}
+
+/*
+ * pmem_flush -- flush processor cache for the given range
+ */
+void
+pmem_flush(void *addr, size_t len, int flags)
+{
+	uintptr_t uptr;
+
+	/* loop through 64B-aligned chunks covering the given range */
+	for (uptr = (uintptr_t)addr & ~(FLUSH_ALIGN - 1);
+			uptr < (uintptr_t)addr + len; uptr += 64)
+		__builtin_ia32_clflush((void *)uptr);
+}
+
+/*
+ * pmem_persist -- make any cached changes to a range of PMEM persistent
+ */
+void
+pmem_persist(void *addr, size_t len, int flags)
+{
+	pmem_flush(addr, len, flags);
+	__builtin_ia32_sfence();
+	pmem_drain();
+}
+
+/*
+ * is_pmem_always -- debug/test version of pmem_is_pmem(), always true
+ */
+static int
+is_pmem_always(void *addr, size_t len)
+{
+	LOG(3, "always true");
+	return 1;
+}
+
+/*
+ * is_pmem_never -- debug/test version of pmem_is_pmem(), never true
+ */
+static int
+is_pmem_never(void *addr, size_t len)
+{
+	LOG(3, "never true");
+	return 0;
+}
+
+/*
+ * is_pmem_proc -- use /proc to implement pmem_is_pmem()
+ *
+ * This function returns true only if the entire range can be confirmed
+ * as being direct access persistent memory.  Finding any part of the
+ * range is not direct access, or failing to look up the information
+ * because it is unmapped or because any sort of error happens, just
+ * results in returning false.
+ *
+ * This function works by lookup up the range in /proc/self/smaps and
+ * verifying the "mixed map" vmflag is set for that range.  While this
+ * isn't exactly the same as direct access, there is no DAX flag in
+ * the vmflags and the mixed map flag is only true on regular files when
+ * DAX is in-use, so it serves the purpose.
+ *
+ * The range passed in may overlap with multiple entries in the smaps list
+ * so this function loops through the smaps entries until the entire range
+ * is verified as direct access, or until it is clear the answer is false
+ * in which case it stops the loop and returns immediately.
+ */
+static int
+is_pmem_proc(void *addr, size_t len)
+{
+	char *caddr = addr;
+
+	FILE *fp;
+	if ((fp = fopen("/proc/self/smaps", "r")) == NULL) {
+		LOG(1, "!/proc/self/smaps");
+		return 0;
+	}
+
+	int retval = 0;		/* assume false until proven otherwise */
+	char *line = NULL;	/* for getline() */
+	size_t linelen;		/* for getline() */
+	char *lo = NULL;	/* beginning of current range in smaps file */
+	char *hi = NULL;	/* end of current range in smaps file */
+	int needmm = 0;		/* looking for mm flag for current range */
+	while (getline(&line, &linelen, fp) != -1) {
+		static const char vmflags[] = "VmFlags:";
+		static const char mm[] = " mm";
+
+		/* check for range line */
+		if (sscanf(line, "%p-%p", &lo, &hi) == 2) {
+			if (needmm) {
+				/* last range matched, but no mm flag found */
+				LOG(4, "never found mm flag");
+				break;
+			} else if (caddr < lo) {
+				/* never found the range for caddr */
+				LOG(4, "no match for addr %p", caddr);
+				break;
+			} else if (caddr < hi) {
+				/* start address is in this range */
+				size_t rangelen = hi - caddr;
+
+				/* remember that matching has started */
+				needmm = 1;
+
+				/* calculate remaining range to search for */
+				if (len > rangelen) {
+					len -= rangelen;
+					caddr += rangelen;
+					LOG(4, "matched %zu bytes in range "
+							"%p-%p, %zu left over",
+							rangelen, lo, hi, len);
+				} else {
+					len = 0;
+					LOG(4, "matched all bytes in range "
+							"%p-%p", lo, hi);
+				}
+			}
+		} else if (needmm && strncmp(line, vmflags,
+					sizeof (vmflags) - 1) == 0) {
+			if (strstr(&line[sizeof (vmflags) - 1], mm) != NULL) {
+				LOG(4, "mm flag found");
+				if (len == 0) {
+					/* entire range matched */
+					retval = 1;
+					break;
+				}
+				needmm = 0;	/* saw what was needed */
+			} else {
+				/* mm flag not set for some or all of range */
+				LOG(4, "range has no mm flag");
+				break;
+			}
+		}
+	}
+
+	Free(line);
+	fclose(fp);
+
+	LOG(3, "returning %d", retval);
+	return retval;
+}
+
+/* pmem_is_pmem() calls this function to do the work */
+static int (*is_pmem_func)(void *addr, size_t len) = is_pmem_proc;
+
+/*
+ * pmem_init -- load-time initialization for pmem.c
+ *
+ * Called automatically by the run-time loader.
+ */
+__attribute__((constructor))
+static void
+pmem_init(void)
+{
+	out_init(LOG_PREFIX, LOG_LEVEL_VAR, LOG_FILE_VAR);
+	LOG(3, NULL);
+	util_init();
+
+	/*
+	 * For debugging/testing, allow pmem_is_pmem() to be forced
+	 * to always true or never true using environment variable
+	 * PMEM_IS_PMEM_FORCE values of zero or one.
+	 *
+	 * This isn't #ifdef DEBUG because it has a trivial performance
+	 * impact and it may turn out to be useful as a "chicken bit" for
+	 * systems where pmem_is_pmem() isn't correctly detecting true
+	 * persistent memory.
+	 */
+	char *ptr = getenv("PMEM_IS_PMEM_FORCE");
+	if (ptr) {
+		int val = atoi(ptr);
+
+		if (val == 0)
+			is_pmem_func = is_pmem_never;
+		else if (val == 1)
+			is_pmem_func = is_pmem_always;
+	}
+}
+
+/*
+ * pmem_is_pmem -- return true if entire range is persistent Memory
+ */
+int
+pmem_is_pmem(void *addr, size_t len)
+{
+	LOG(3, "addr %p len %zu", addr, len);
+
+	return (*is_pmem_func)(addr, len);
+}
diff --git a/src/pmem.h b/src/pmem.h
new file mode 100644
index 0000000000000000000000000000000000000000..dfaf817f79511792cae5932db516a5c031e46bbd
--- /dev/null
+++ b/src/pmem.h
@@ -0,0 +1,50 @@
+/*
+ * Copyright (c) 2014, Intel Corporation
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ *     * Redistributions of source code must retain the above copyright
+ *       notice, this list of conditions and the following disclaimer.
+ *
+ *     * Redistributions in binary form must reproduce the above copyright
+ *       notice, this list of conditions and the following disclaimer in
+ *       the documentation and/or other materials provided with the
+ *       distribution.
+ *
+ *     * Neither the name of Intel Corporation nor the names of its
+ *       contributors may be used to endorse or promote products derived
+ *       from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+/*
+ * pmem.h -- internal definitions for libpmem
+ */
+
+#define	LOG_PREFIX "libpmem"
+#define	LOG_LEVEL_VAR "PMEM_LOG_LEVEL"
+#define	LOG_FILE_VAR "PMEM_LOG_FILE"
+
+extern unsigned long Pagesize;
+
+typedef void (*Persist_func)(void *addr, size_t len, int flags);
+
+Persist_func Persist;
+
+void pmem_set_persist_func(void (*persist_func)(void *addr,
+			size_t len, int flags));
+
+void libpmem_persist(int is_pmem, void *addr, size_t len);
diff --git a/src/test/.gitignore b/src/test/.gitignore
new file mode 100644
index 0000000000000000000000000000000000000000..f34c476ebd95a91d93c2391ff86d229f2ba82b2f
--- /dev/null
+++ b/src/test/.gitignore
@@ -0,0 +1,9 @@
+# testconfig.sh should not be checked into git  .it describes the configuration
+# of the local machine where the local copy of the source tree is being tested.
+testconfig.sh
+# ignore files generated during test runs (left around for analysis)
+*.log
+testfile*
+# ignore static binaries generated for testing
+*.static-debug
+*.static-nondebug
diff --git a/src/test/Makefile b/src/test/Makefile
new file mode 100644
index 0000000000000000000000000000000000000000..9f127cbbca6c4148a5a5a6435642f647d1149c0d
--- /dev/null
+++ b/src/test/Makefile
@@ -0,0 +1,84 @@
+#
+# Copyright (c) 2014, Intel Corporation
+#
+# Redistribution and use in source and binary forms, with or without
+# modification, are permitted provided that the following conditions
+# are met:
+#
+#     * Redistributions of source code must retain the above copyright
+#       notice, this list of conditions and the following disclaimer.
+#
+#     * Redistributions in binary form must reproduce the above copyright
+#       notice, this list of conditions and the following disclaimer in
+#       the documentation and/or other materials provided with the
+#       distribution.
+#
+#     * Neither the name of Intel Corporation nor the names of its
+#       contributors may be used to endorse or promote products derived
+#       from this software without specific prior written permission.
+#
+# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+#
+
+#
+# src/test/Makefile -- build all unit tests
+#
+# Makefile -- build all unit tests
+#
+TEST = blk_nblock\
+       blk_recovery\
+       blk_rw\
+       blk_rw_mt\
+       checksum\
+       log_basic\
+       log_recovery\
+       log_walker\
+       scope\
+       traces\
+       traces_custom_function\
+       pmem_is_pmem\
+       pmem_is_pmem_proc\
+       pmem_map\
+       vmem_check_version\
+       vmem_custom_alloc\
+       vmem_malloc\
+       vmem_calloc\
+       vmem_realloc\
+       vmem_aligned_alloc\
+       vmem_mix_allocations\
+       vmem_strdup\
+       vmem_multiple_pools\
+       vmem_out_of_memory\
+       vmem_check_allocations\
+       vmem_pool_create_error\
+       vmem_pool_create\
+       vmem_pool_create_in_region\
+       vmem_valgrind\
+       vmem_stats
+
+
+all     : TARGET = all
+clean   : TARGET = clean
+clobber : TARGET = clobber
+test    : TARGET = test
+cstyle  : TARGET = cstyle
+
+all clean clobber test cstyle: $(TEST)
+
+$(TEST): unittest
+	$(MAKE) -C $@ $(TARGET)
+
+unittest:
+	$(MAKE) -C $@ $(TARGET)
+
+.PHONY: all clean clobber test cstyle unittest $(TEST)
diff --git a/src/test/Makefile.inc b/src/test/Makefile.inc
new file mode 100644
index 0000000000000000000000000000000000000000..1383facbf8a5c0e396f7e4945306c0bc1588d883
--- /dev/null
+++ b/src/test/Makefile.inc
@@ -0,0 +1,66 @@
+#
+# Copyright (c) 2014, Intel Corporation
+#
+# Redistribution and use in source and binary forms, with or without
+# modification, are permitted provided that the following conditions
+# are met:
+#
+#     * Redistributions of source code must retain the above copyright
+#       notice, this list of conditions and the following disclaimer.
+#
+#     * Redistributions in binary form must reproduce the above copyright
+#       notice, this list of conditions and the following disclaimer in
+#       the documentation and/or other materials provided with the
+#       distribution.
+#
+#     * Neither the name of Intel Corporation nor the names of its
+#       contributors may be used to endorse or promote products derived
+#       from this software without specific prior written permission.
+#
+# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+#
+
+#
+# src/test/Makefile.inc -- common Makefile defs for unit tests
+#
+# These defaults apply to most unit tests.  The individual Makefile
+# for each unit test overrides the defaults as necessary.
+#
+LIBS = ../unittest/libut.a -L../../debug -luuid -pthread
+STATIC_DEBUG_LIBS = ../unittest/libut.a ../../debug/libpmem.a -luuid -pthread
+STATIC_NONDEBUG_LIBS = ../unittest/libut.a ../../nondebug/libpmem.a -luuid -pthread
+INCS = -I../unittest -I../../include
+CFLAGS = -ggdb -Wall -Werror -std=gnu99
+
+all: $(TARGET)
+
+$(TARGET): $(OBJS)
+	$(CC) -o $@ $(OBJS) $(LIBS)
+	$(CC) -o $@.static-debug $(OBJS) $(STATIC_DEBUG_LIBS)
+	$(CC) -o $@.static-nondebug $(OBJS) $(STATIC_NONDEBUG_LIBS)
+
+.c.o:
+	$(CC) -c $(CFLAGS) $(INCS) $< -o $@
+
+clean:
+	$(RM) *.o */*.o core a.out *.log testfile*
+
+clobber: clean
+	$(RM) $(TARGET) $(TARGET).static-debug $(TARGET).static-nondebug
+
+cstyle:
+	../../../utils/cstyle -pP *.c
+
+.PHONY: all clean clobber cstyle
+
+$(OBJS): ../unittest/unittest.h
diff --git a/src/test/README b/src/test/README
new file mode 100644
index 0000000000000000000000000000000000000000..0d3a18738f42038cb8992f0aca457146174abea4
--- /dev/null
+++ b/src/test/README
@@ -0,0 +1,221 @@
+Linux NVM Library
+
+This is src/test/README.
+
+This directory contains the unit tests for the NVM Library.
+
+Unit tests require a config file, testconfig.sh, to exist in this directory.
+That file describes the local machine configuration (where to find persistent
+memory, for example) and must be created by hand in each repo as it makes no
+sense to check in that configuration description to the main repo.
+
+testconfig.sh.example provides more detail.  The script RUNTESTS, when run with
+no arguments, will run all unit tests through all the combinations of fs-types
+and build-types, running the "check" level test.
+
+
+DETAILS ON HOW TO RUN UNIT TESTS
+
+See the top-level README for instructions on building, installing, running
+tests for the entire tree.  Here are some additional details on running tests.
+
+Once the libraries are built, tests may be built from this directory using:
+	$ make test
+
+A testconfig.sh must exist to run these tests!
+	$ cp testconfig.sh.example testconfig.sh
+	$ ...edit testconfig.sh and modify as appropriate...
+
+Tests may be run using the RUNTESTS script:
+	$ RUNTESTS		(runs them all)
+	$ RUNTESTS testname	(runs just the named test)
+
+Each test script (named something like "TEST0") is potentially run multiple
+times with a different set of environment variables so run the test with
+different target file systems or different versions of the libraries.  To see
+how RUNTESTS will run a test, use the -n option.  For example:
+
+	$ RUNTESTS -n blk_nblock
+	RUNTESTS: test-type: check
+	(in ./blk_nblock) TEST=check FS=local BUILD=debug ./TEST0
+	(in ./blk_nblock) TEST=check FS=local BUILD=nondebug ./TEST0
+	(in ./blk_nblock) TEST=check FS=local BUILD=static-debug ./TEST0
+	(in ./blk_nblock) TEST=check FS=local BUILD=static-nondebug ./TEST0
+	(in ./blk_nblock) TEST=check FS=pmem BUILD=debug ./TEST0
+	(in ./blk_nblock) TEST=check FS=pmem BUILD=nondebug ./TEST0
+	(in ./blk_nblock) TEST=check FS=pmem BUILD=static-debug ./TEST0
+	(in ./blk_nblock) TEST=check FS=pmem BUILD=static-nondebug ./TEST0
+	(in ./blk_nblock) TEST=check FS=non-pmem BUILD=debug ./TEST0
+	(in ./blk_nblock) TEST=check FS=non-pmem BUILD=nondebug ./TEST0
+	(in ./blk_nblock) TEST=check FS=non-pmem BUILD=static-debug ./TEST0
+	(in ./blk_nblock) TEST=check FS=non-pmem BUILD=static-nondebug ./TEST0
+
+Notice how the TEST0 script is run repeatedly with different settings for
+the three environment variables TEST, FS, and BUILD, providing the test type,
+file system type, and build type to test.
+
+RUNTESTS takes options to limit what it runs.  The usage is:
+
+ RUNTEST [ -nv ] [ -b build-type ] [ -t test-type ] [ -f fs-type ] [test...]
+
+ Build types are: debug, nondebug, static-debug, static-nondebug, all (default)
+ Test types are: check (default), short, long
+ File system types are: local, pmem, non-pmem, all (default)
+
+For example:
+
+	$ RUNTESTS -b debug blk_nblock
+	RUNTESTS: test-type: check
+	blk_nblock/TEST0: SETUP (check/local/debug)
+	blk_nblock/TEST0: START: blk_nblock
+	blk_nblock/TEST0: PASS
+	blk_nblock/TEST0: SKIP fs-type pmem (not configured)
+	blk_nblock/TEST0: SKIP fs-type non-pmem (local required)
+	RUNTESTS: No failures.
+
+Since the "-b debug" option was given, the RUNTESTS run above only executes
+the test for the debug version of the library and skips the other variants.
+
+Running the TEST* scripts directly is also common, especially when debugging
+an issue.  Just running the script, like this:
+
+	$ cd blk_nblock
+	$ ./TEST0
+
+will use default values for the environment, namely:
+
+	TEST=check FS=local BUILD=debug
+
+these defaults can be overridden on the command line:
+
+	$ cd blk_nblock
+	$ TEST=check FS=local BUILD=nondebug ./TEST0
+
+The above example runs TEST0 with the nondebug library, just as using
+RUNTESTS with "-b nondebug" would from the parent directory.
+
+In addition to overriding TEST, FS, and BUILD environment variables, the
+unit test framework also looks for several other variables:
+
+	For tests that run a local program, insert the word "echo" in front
+	of the program execution so the full command being run is displayed.
+	This is useful to modify the command for debugging.
+
+		$ ECHO=echo ./TEST0
+
+	Insert the word "strace" in front of the local command execution:
+
+		$ TRACE=strace ./TEST0
+
+	Override the LD_LIBRARY_PATH provided by the unit test framework.  This
+	is useful for running a test against another source tree or against the
+	libraries installed on the system:
+
+		$ TEST_LD_LIBRARY_PATH=/usr/lib ./TEST0
+
+
+DETAILS ON HOW TO WRITE UNIT TESTS
+
+A minimal unit test consists of a sub-directory here with an executable called
+TEST0 in it that exits normally when the test passes.  Mosts tests, however,
+source the file unittest/unittest.sh to use the utility functions for setting
+up and checking tests.  Additionally, most unit tests build a local test
+program and call it from the TEST* scripts.
+
+In additional to TEST0, there can be as many TEST<num> scripts as desired, and
+RUNTESTS will execute them in numeric order for each of the test runs it
+executes.
+
+If a test only makes sense using the local directory, meaning it does not need
+an external file system or persistent memory, the script uses this line:
+
+	require_fs_type local
+
+Similarly, if the test only makes sense for pmem or non-pmem:
+
+	require_fs_type pmem
+		or
+	require_fs_type non-pmem
+
+The above two are often combined to indicate the test should run once for pmem
+and once for non-pmem, but never with the local directory:
+
+	require_fs_type pmem non-pmem
+
+Similar to the above, tests can require a specific build types:
+
+	require_build_type debug
+
+Most tests are short "make check" tests, designed to run quickly when
+smoke-checking a build.  Two other test types are available: short and long.  A
+test script can indicate it should only run during a long test run, for
+example, using:
+
+	require_test_type long
+
+Using the unittest library, the C programs run during unit testing get their
+output and tracing information logged to various files.  These are named with
+the test number embedded in them, so a script called TEST0 would commonly
+produce:
+
+	err0.log	log of stderr
+	out0.log	log of stdout
+	trace0.log	trace points from unittest library
+	pmem0.log	trace from libpmem (PMEM_LOG_FILE points here)
+	vmem0.log	trace from libvmem (VMEM_LOG_FILE points here)
+
+Although the above log files are the common case, the TEST* scripts are free to
+create any files.  It is recommended, however, that the script creates files
+that are listed in .gitignore so they don't accidentally get committed to the
+repo.
+
+The TEST* scripts typically use the shell function "check" to check their
+results.  That function calls the perl script "match" for any .match files
+found.  For example, to check out0.log contains the expected output, the test
+author creates a file called out0.log.match and commits that into the repo.
+The match script provides several pattern-matching macros that allow for normal
+variation in the test output:
+
+ 	$(N)	an integer (i.e. one or more decimal digits)
+ 	$(FP)	a floating point number
+	$(S)	ascii string
+	$(X)	hex number
+	$(W)	whitespace
+	$(*)	any string
+ 	$(DD)	output of a "dd" run
+	$(OPT)	the entire line is optional
+
+The small C programs used for unit testing are designed to not worry about the
+return values for things not under test.  This is done with the all-caps
+versions of many common libc calls, for example:
+
+	fd = OPEN(fname, O_RDRW);
+
+The above call is just like calling open(2), expect the framework checks for
+unexpected errors and halts the unit test if those happen.  The result is
+usually a very short, compact unit test where most of the code is the
+interesting code under test.  A full list of unit test macros is in
+unittest/inittest.h.
+
+The best way to create a new unit test is to start with an existing one.  The
+test:
+
+	blk_rw
+
+makes an excellent starting point for new tests.  It illustrates the common
+idioms used in the TEST* scripts, how the small C program is usually
+command-line driven to create multiple cases, and the use of unit test macros
+like START, OUT, FATAL, and DONE.  Every case is different, but a common
+pattern for creating new unit tests is to follow steps like these:
+
+	$ cp blk_rw new_test_name
+	$ ...edit Makefile to add new_test_name to TEST list...
+	$ cd new_test_name
+	$ mv blk_rw.c to new_test_name.c
+	$ ...edit .gitignore, README, Makefile, new_test_name.c...
+	$ ...edit TEST0 to create first test case & get it working...
+	$ ...add more TEST* scripts as appropriate...
+
+When a "check" type test is run (the default), each test should try to limit
+the real execution time to a couple minutes or less.  "short" and "long"
+versions of the tests are encourages, especially for stress testing.
diff --git a/src/test/RUNTESTS b/src/test/RUNTESTS
new file mode 100755
index 0000000000000000000000000000000000000000..93cd170f9a85da2b624beabf941ce854361a7a6f
--- /dev/null
+++ b/src/test/RUNTESTS
@@ -0,0 +1,231 @@
+#!/bin/sh
+#
+# Copyright (c) 2014, Intel Corporation
+#
+# Redistribution and use in source and binary forms, with or without
+# modification, are permitted provided that the following conditions
+# are met:
+#
+#     * Redistributions of source code must retain the above copyright
+#       notice, this list of conditions and the following disclaimer.
+#
+#     * Redistributions in binary form must reproduce the above copyright
+#       notice, this list of conditions and the following disclaimer in
+#       the documentation and/or other materials provided with the
+#       distribution.
+#
+#     * Neither the name of Intel Corporation nor the names of its
+#       contributors may be used to endorse or promote products derived
+#       from this software without specific prior written permission.
+#
+# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+#
+
+#
+# RUNTESTS -- setup the environment and run each test
+#
+
+# make sure we have a well defined locale for string operations here
+export LC_ALL="C"
+
+#
+# usage -- print usage message and exit
+#
+usage()
+{
+	[ "$1" ] && echo Error: $1
+	cat <<EOF
+Usage: $0 [ -nv ] [ -b build-type ] [ -t test-type ] [ -f fs-type ] [tests...]
+    build-types: debug, nondebug, static-debug, static-nondebug, all (default)
+     test-types: check (default), short, long
+       fs-types: local, pmem, non-pmem, all (default)
+EOF
+	exit 1
+}
+
+#
+# runtest -- given the test directory name, run tests found inside it
+#
+runtest() {
+	export UNITTEST_QUIET=1
+	[ -x "$1/TEST0" ] || {
+		echo FAIL: $1: test not found.
+		exit 1
+	}
+
+	cd $1
+
+	#
+	# make list of fs-types and build-types to test
+	#
+	fss=$fstype
+	[ "$fss" = all ] && fss="local pmem non-pmem"
+	builds=$buildtype
+	[ "$builds" = all ] && builds="debug nondebug static-debug static-nondebug"
+
+	# for each fs-type being tested...
+	for fs in $fss
+	do
+		# don't bother trying when fs-type isn't available...
+		[ "$fs" = local -a -z "$LOCAL_FS_DIR" ] && {
+			local_skip=1
+			continue
+		}
+		[ "$fs" = pmem -a -z "$PMEM_FS_DIR" ] && {
+			pmem_skip=1
+			continue
+		}
+		[ "$fs" = non-pmem -a -z "$NON_PMEM_FS_DIR" ] && {
+			non_pmem_skip=1
+			continue
+		}
+
+		[ "$verbose"] && echo RUNTESTS: Testing fs-type: $fs...
+		# for each build-type being tested...
+		for build in $builds
+		do
+			[ "$verbose"] && echo RUNTESTS: Testing build-type: $build...
+			# for each TEST script found...
+			for runscript in `ls -1 TEST* | sort -V`
+			do
+				if [ "$dryrun" ]
+				then
+					echo "(in ./$1) TEST=$testtype FS=$fs BUILD=$build ./$runscript"
+				else
+					[ "$verbose"] && echo "RUNTESTS: Running: (in ./$1) TEST=$testtype FS=$fs BUILD=$build ./$runscript"
+					TEST=$testtype FS=$fs BUILD=$build ./$runscript
+				fi
+
+				[ $? != 0 ] && {
+					echo RUNTESTS: stopping:
+					echo "    $1/$runscript failed"
+					echo "    TEST=$testtype FS=$fs BUILD=$build"
+					exit 1
+				}
+			done
+		done
+	done
+
+	cd ..
+}
+
+[ -f testconfig.sh ] || {
+	cat <<EOF
+RUNTESTS: stopping because no testconfig.sh is found.
+          to create one:
+               cp testconfig.sh.example testconfig.sh
+          and edit testconfig.sh to describe the local machine configuration.
+EOF
+	exit 1
+}
+
+. ./testconfig.sh
+
+#
+# defaults...
+#
+buildtype=all
+testtype=check
+fstype=all
+
+#
+# command-line argument processing...
+#
+args=`getopt nvb:t:f: $*`
+[ $? != 0 ] && usage
+set -- $args
+for arg
+do
+	case "$arg"
+	in
+
+	-n)
+		dryrun=1
+		shift
+		;;
+	-v)
+		verbose=1
+		shift
+		;;
+	-b)
+		buildtype="$2"
+		shift 2
+		case "$buildtype"
+		in
+		debug|nondebug|static-debug|static-nondebug|all)
+			;;
+		*)
+			usage "bad build-type: $buildtype"
+			;;
+		esac
+		;;
+	-t)
+		testtype="$2"
+		shift 2
+		case "$testtype"
+		in
+		check|short|long)
+			;;
+		*)
+			usage "bad test-type: $testtype"
+			;;
+		esac
+		;;
+	-f)
+		fstype="$2"
+		shift 2
+		case "$fstype"
+		in
+		local|pmem|non-pmem|all)
+			;;
+		*)
+			usage "bad fs-type: $fstype"
+			;;
+		esac
+		;;
+	--)
+		shift
+		break
+		;;
+	esac
+done
+[ "$verbose" ] && {
+	echo -n Options:
+	[ "$dryrun" ] && echo -n ' -n'
+	[ "$verbose" ] && echo -n ' -v'
+	echo
+	echo "    build-type: $buildtype"
+	echo "    test-type: $testtype"
+	echo "    fs-type: $fstype"
+	echo Tests: $*
+}
+
+echo RUNTESTS: test-type: $testtype
+
+if [ "$1" ]; then
+	for test in $*
+	do
+		runtest $test
+	done
+else
+	# no arguments means run them all
+	for testdir in */TEST0
+	do
+		runtest `dirname $testdir`
+	done
+fi
+[ "$local_skip" ] && echo "SKIPPED fs-type \"local\" runs: testconfig.sh doesn't set LOCAL_FS_DIR"
+[ "$pmem_skip" ] && echo "SKIPPED fs-type \"pmem\" runs: testconfig.sh doesn't set PMEM_FS_DIR"
+[ "$non_pmem_skip" ] && echo "SKIPPED fs-type \"non-pmem\" runs: testconfig.sh doesn't set NON_PMEM_FS_DIR"
+[ "$dryrun" ] || echo RUNTESTS: No failures.
+exit 0
diff --git a/src/test/blk_nblock/.gitignore b/src/test/blk_nblock/.gitignore
new file mode 100644
index 0000000000000000000000000000000000000000..c87f12a90443a27dbc001bdb32e8236cb4d5730e
--- /dev/null
+++ b/src/test/blk_nblock/.gitignore
@@ -0,0 +1 @@
+blk_nblock
diff --git a/src/test/blk_nblock/Makefile b/src/test/blk_nblock/Makefile
new file mode 100644
index 0000000000000000000000000000000000000000..a029aaba0546afcaec2a07fc20303d1915fd56d4
--- /dev/null
+++ b/src/test/blk_nblock/Makefile
@@ -0,0 +1,45 @@
+#
+# Copyright (c) 2014, Intel Corporation
+#
+# Redistribution and use in source and binary forms, with or without
+# modification, are permitted provided that the following conditions
+# are met:
+#
+#     * Redistributions of source code must retain the above copyright
+#       notice, this list of conditions and the following disclaimer.
+#
+#     * Redistributions in binary form must reproduce the above copyright
+#       notice, this list of conditions and the following disclaimer in
+#       the documentation and/or other materials provided with the
+#       distribution.
+#
+#     * Neither the name of Intel Corporation nor the names of its
+#       contributors may be used to endorse or promote products derived
+#       from this software without specific prior written permission.
+#
+# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+#
+
+#
+# src/test/blk_nblock/Makefile -- build blk_nblock unit test
+#
+TARGET = blk_nblock
+OBJS = blk_nblock.o
+
+include ../Makefile.inc
+
+LIBS += -lpmem -lpthread -ldl
+STATIC_DEBUG_LIBS += -ldl
+STATIC_NONDEBUG_LIBS += -ldl
+
+blk_nblock.o: blk_nblock.c
diff --git a/src/test/blk_nblock/README b/src/test/blk_nblock/README
new file mode 100644
index 0000000000000000000000000000000000000000..3ae26b1644abbc867230119f369dc850623069af
--- /dev/null
+++ b/src/test/blk_nblock/README
@@ -0,0 +1,13 @@
+Linux NVM Library
+
+This is src/test/blk_nblock/README.
+
+This directory contains a unit test for pmemblk_nblock().
+
+The program in blk_nblock.c takes a list of block size file pairs.
+For example:
+
+	./blk_nblock 4096:file1
+
+this will call pmemblk_map() on file1 and then report what pmemblk_nblock()
+reports back as the usable size.
diff --git a/src/test/blk_nblock/TEST0 b/src/test/blk_nblock/TEST0
new file mode 100755
index 0000000000000000000000000000000000000000..4b32f70f51a5fc55c9df6fffa8624364e5b14593
--- /dev/null
+++ b/src/test/blk_nblock/TEST0
@@ -0,0 +1,129 @@
+#!/bin/bash -e
+#
+# Copyright (c) 2014, Intel Corporation
+#
+# Redistribution and use in source and binary forms, with or without
+# modification, are permitted provided that the following conditions
+# are met:
+#
+#     * Redistributions of source code must retain the above copyright
+#       notice, this list of conditions and the following disclaimer.
+#
+#     * Redistributions in binary form must reproduce the above copyright
+#       notice, this list of conditions and the following disclaimer in
+#       the documentation and/or other materials provided with the
+#       distribution.
+#
+#     * Neither the name of Intel Corporation nor the names of its
+#       contributors may be used to endorse or promote products derived
+#       from this software without specific prior written permission.
+#
+# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+#
+
+#
+# src/test/blk_nblock/TEST0 -- unit test for pmemblk_nblock
+#
+export UNITTEST_NAME=blk_nblock/TEST0
+export UNITTEST_NUM=0
+
+# standard unit test setup
+. ../unittest/unittest.sh
+
+require_fs_type local
+
+setup
+
+#
+# Create a gajillion files, each file size created
+# has six versions for the six block sizes being tested.
+# Except for testfile1, since that should fail because
+# it is too small.
+#
+# These are holey files, so they actually don't take up
+# any significant space.
+#
+rm -f $DIR/testfile1
+truncate -s 2M $DIR/testfile1
+truncate -s 2G $DIR/testfile2.512
+truncate -s 2G $DIR/testfile2.520
+truncate -s 2G $DIR/testfile2.528
+truncate -s 2G $DIR/testfile2.4096
+truncate -s 2G $DIR/testfile2.4160
+truncate -s 2G $DIR/testfile2.4224
+truncate -s 512G $DIR/testfile3.512
+truncate -s 512G $DIR/testfile3.520
+truncate -s 512G $DIR/testfile3.528
+truncate -s 512G $DIR/testfile3.4096
+truncate -s 512G $DIR/testfile3.4160
+truncate -s 512G $DIR/testfile3.4224
+truncate -s 549755822080 $DIR/testfile4.512
+truncate -s 549755822080 $DIR/testfile4.520
+truncate -s 549755822080 $DIR/testfile4.528
+truncate -s 549755822080 $DIR/testfile4.4096
+truncate -s 549755822080 $DIR/testfile4.4160
+truncate -s 549755822080 $DIR/testfile4.4224
+truncate -s 513G $DIR/testfile5.512
+truncate -s 513G $DIR/testfile5.520
+truncate -s 513G $DIR/testfile5.528
+truncate -s 513G $DIR/testfile5.4096
+truncate -s 513G $DIR/testfile5.4160
+truncate -s 513G $DIR/testfile5.4224
+truncate -s 514G $DIR/testfile6.512
+truncate -s 514G $DIR/testfile6.520
+truncate -s 514G $DIR/testfile6.528
+truncate -s 514G $DIR/testfile6.4096
+truncate -s 514G $DIR/testfile6.4160
+truncate -s 514G $DIR/testfile6.4224
+
+# should fail:
+#	512:$DIR/testfile1 (file is too small)
+#	4096:$DIR/testfile2.512 (bsize doesn't match pool)
+expect_normal_exit ./blk_nblock$EXESUFFIX\
+	512:$DIR/testfile1\
+	512:$DIR/testfile2.512\
+	4096:$DIR/testfile2.512\
+	520:$DIR/testfile2.520\
+	528:$DIR/testfile2.528\
+	4096:$DIR/testfile2.4096\
+	4160:$DIR/testfile2.4160\
+	4224:$DIR/testfile2.4224\
+	512:$DIR/testfile3.512\
+	520:$DIR/testfile3.520\
+	528:$DIR/testfile3.528\
+	4096:$DIR/testfile3.4096\
+	4160:$DIR/testfile3.4160\
+	4224:$DIR/testfile3.4224\
+	512:$DIR/testfile4.512\
+	520:$DIR/testfile4.520\
+	528:$DIR/testfile4.528\
+	4096:$DIR/testfile4.4096\
+	4160:$DIR/testfile4.4160\
+	4224:$DIR/testfile4.4224\
+	512:$DIR/testfile5.512\
+	520:$DIR/testfile5.520\
+	528:$DIR/testfile5.528\
+	4096:$DIR/testfile5.4096\
+	4160:$DIR/testfile5.4160\
+	4224:$DIR/testfile5.4224\
+	512:$DIR/testfile6.512\
+	520:$DIR/testfile6.520\
+	528:$DIR/testfile6.528\
+	4096:$DIR/testfile6.4096\
+	4160:$DIR/testfile6.4160\
+	4224:$DIR/testfile6.4224
+rm $DIR/testfile1 $DIR/testfile[23456].*
+
+check
+
+pass
diff --git a/src/test/blk_nblock/blk_nblock.c b/src/test/blk_nblock/blk_nblock.c
new file mode 100644
index 0000000000000000000000000000000000000000..38b319519745f4e9a960081fb1996d4a8d121db1
--- /dev/null
+++ b/src/test/blk_nblock/blk_nblock.c
@@ -0,0 +1,159 @@
+/*
+ * Copyright (c) 2014, Intel Corporation
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ *     * Redistributions of source code must retain the above copyright
+ *       notice, this list of conditions and the following disclaimer.
+ *
+ *     * Redistributions in binary form must reproduce the above copyright
+ *       notice, this list of conditions and the following disclaimer in
+ *       the documentation and/or other materials provided with the
+ *       distribution.
+ *
+ *     * Neither the name of Intel Corporation nor the names of its
+ *       contributors may be used to endorse or promote products derived
+ *       from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+/*
+ * blk_nblock.c -- unit test for pmemblk_nblock()
+ *
+ * usage: blk_nblock bsize:file...
+ *
+ */
+#define	_GNU_SOURCE
+#include "unittest.h"
+#include <dlfcn.h>
+
+#define	MMAP_MAX_SIZE (1024L * 1024L * 1024L)
+
+static void *mapped_addr;
+static size_t mapped_size;
+static uint64_t min_addr;
+static uint64_t max_addr;
+
+/*
+ * mmap -- interpose on libc mmap()
+ *
+ * This catches mmap and reduces mapped size up to 1GB.
+ * Code under test doesn’t actually write outside first 1GB of mapped region.
+ * This limit is necessary to work on machines without overcommit.
+ */
+void *
+mmap(void *addr, size_t len, int prot, int flags, int fildes, off_t off)
+{
+	static void *(*mmap_ptr)(void *addr, size_t len, int prot, int flags,
+		int fildes, off_t off);
+	if (mmap_ptr == NULL)
+		mmap_ptr = dlsym(RTLD_NEXT, "mmap");
+
+	if (len > MMAP_MAX_SIZE)
+		len = MMAP_MAX_SIZE;
+
+	ASSERTeq(mapped_addr, NULL);
+	mapped_addr = mmap_ptr(addr, len, prot, flags, fildes, off);
+	mapped_size = len;
+	min_addr = (uint64_t)(mapped_addr);
+	max_addr = (uint64_t)(mapped_addr + len);
+	return mapped_addr;
+}
+
+/*
+ * munmap -- interpose on libc munmap()
+ *
+ * This catches munmap and changes length to size used inside interpose mmap.
+ */
+int
+munmap(void *addr, size_t len)
+{
+	static int(*munmap_ptr)(void *addr, size_t len);
+	if (munmap_ptr == NULL)
+		munmap_ptr = dlsym(RTLD_NEXT, "munmap");
+
+	if (addr == mapped_addr) {
+		len = mapped_size;
+		mapped_addr = NULL;
+	}
+
+	return munmap_ptr(addr, len);
+}
+
+/*
+ * mprotect -- interpose on libc mprotect()
+ *
+ * This catches mprotect and adjusts length to max_addr
+ * set inside interposed mmap.
+ */
+int
+mprotect(void *addr, size_t len, int prot)
+{
+	static int (*mprotect_ptr)(void *addr, size_t len, int prot);
+	uint64_t addr_int = (uint64_t)addr;
+
+	if (mprotect_ptr == NULL)
+		mprotect_ptr = dlsym(RTLD_NEXT, "mprotect");
+
+	if (addr_int >= min_addr && addr_int <= max_addr &&
+	    addr_int + len > max_addr) {
+
+		/* unit tests are not supposed to write beyond the 1GB range */
+		ASSERTeq(prot & PROT_WRITE, 0);
+
+		len = max_addr - addr_int;
+	}
+
+	return mprotect_ptr(addr, len, prot);
+}
+
+int
+main(int argc, char *argv[])
+{
+	START(argc, argv, "blk_nblock");
+
+	if (argc < 2)
+		FATAL("usage: %s bsize:file...", argv[0]);
+
+	/* map each file argument with the given map type */
+	for (int arg = 1; arg < argc; arg++) {
+		char *fname;
+		size_t bsize = strtoul(argv[arg], &fname, 0);
+		if (bsize == 0 || *fname != ':')
+			FATAL("usage: %s bsize:file...", argv[0]);
+		fname++;
+
+		int fd = OPEN(fname, O_RDWR);
+
+		PMEMblk *handle;
+		if ((handle = pmemblk_map(fd, bsize)) == NULL)
+			OUT("!%s: pmemblk_map", fname);
+		else {
+			OUT("%s: block size %zu usable blocks: %zu",
+					fname, bsize, pmemblk_nblock(handle));
+			pmemblk_unmap(handle);
+			int result = pmemblk_check(fname);
+			if (result < 0)
+				OUT("!%s: pmemblk_check", fname);
+			else if (result == 0)
+				OUT("%s: pmemblk_check: not consistent", fname);
+		}
+
+		close(fd);
+	}
+
+	DONE(NULL);
+}
diff --git a/src/test/blk_nblock/err0.log.match b/src/test/blk_nblock/err0.log.match
new file mode 100644
index 0000000000000000000000000000000000000000..e69de29bb2d1d6434b8b29ae775ad8c2e48c5391
diff --git a/src/test/blk_nblock/out0.log.match b/src/test/blk_nblock/out0.log.match
new file mode 100644
index 0000000000000000000000000000000000000000..f9bf1030dafb423d3c7690b7cc194083d82df18a
--- /dev/null
+++ b/src/test/blk_nblock/out0.log.match
@@ -0,0 +1,35 @@
+blk_nblock/TEST0: START: blk_nblock
+ ./blk_nblock$(*) 512:$(*)/testfile1 512:$(*)/testfile2.512 4096:$(*)/testfile2.512 520:$(*)/testfile2.520 528:$(*)/testfile2.528 4096:$(*)/testfile2.4096 4160:$(*)/testfile2.4160 4224:$(*)/testfile2.4224 512:$(*)/testfile3.512 520:$(*)/testfile3.520 528:$(*)/testfile3.528 4096:$(*)/testfile3.4096 4160:$(*)/testfile3.4160 4224:$(*)/testfile3.4224 512:$(*)/testfile4.512 520:$(*)/testfile4.520 528:$(*)/testfile4.528 4096:$(*)/testfile4.4096 4160:$(*)/testfile4.4160 4224:$(*)/testfile4.4224 512:$(*)/testfile5.512 520:$(*)/testfile5.520 528:$(*)/testfile5.528 4096:$(*)/testfile5.4096 4160:$(*)/testfile5.4160 4224:$(*)/testfile5.4224 512:$(*)/testfile6.512 520:$(*)/testfile6.520 528:$(*)/testfile6.528 4096:$(*)/testfile6.4096 4160:$(*)/testfile6.4160 4224:$(*)/testfile6.4224
+$(*)/testfile1: pmemblk_map: Invalid argument
+$(*)/testfile2.512: block size 512 usable blocks: 4161478
+$(*)/testfile2.512: pmemblk_map: Invalid argument
+$(*)/testfile2.520: block size 520 usable blocks: 2781421
+$(*)/testfile2.528: block size 528 usable blocks: 2781421
+$(*)/testfile2.4096: block size 4096 usable blocks: 523513
+$(*)/testfile2.4160: block size 4160 usable blocks: 492731
+$(*)/testfile2.4224: block size 4224 usable blocks: 492731
+$(*)/testfile3.512: block size 512 usable blocks: 1065417932
+$(*)/testfile3.520: block size 520 usable blocks: 712118636
+$(*)/testfile3.528: block size 528 usable blocks: 712118636
+$(*)/testfile3.4096: block size 4096 usable blocks: 134086520
+$(*)/testfile3.4160: block size 4160 usable blocks: 126206306
+$(*)/testfile3.4224: block size 4224 usable blocks: 126206306
+$(*)/testfile4.512: block size 512 usable blocks: 1065417948
+$(*)/testfile4.520: block size 520 usable blocks: 712118647
+$(*)/testfile4.528: block size 528 usable blocks: 712118647
+$(*)/testfile4.4096: block size 4096 usable blocks: 134086522
+$(*)/testfile4.4160: block size 4160 usable blocks: 126206308
+$(*)/testfile4.4224: block size 4224 usable blocks: 126206308
+$(*)/testfile5.512: block size 512 usable blocks: 1067498531
+$(*)/testfile5.520: block size 520 usable blocks: 713509211
+$(*)/testfile5.528: block size 528 usable blocks: 713509211
+$(*)/testfile5.4096: block size 4096 usable blocks: 134348147
+$(*)/testfile5.4160: block size 4160 usable blocks: 126452542
+$(*)/testfile5.4224: block size 4224 usable blocks: 126452542
+$(*)/testfile6.512: block size 512 usable blocks: 1069579426
+$(*)/testfile6.520: block size 520 usable blocks: 714900068
+$(*)/testfile6.528: block size 528 usable blocks: 714900068
+$(*)/testfile6.4096: block size 4096 usable blocks: 134610035
+$(*)/testfile6.4160: block size 4160 usable blocks: 126699039
+$(*)/testfile6.4224: block size 4224 usable blocks: 126699039
+blk_nblock/TEST0: Done
diff --git a/src/test/blk_recovery/.gitignore b/src/test/blk_recovery/.gitignore
new file mode 100644
index 0000000000000000000000000000000000000000..4431b0205e3b5472aa2ea0b307697c785ef2041a
--- /dev/null
+++ b/src/test/blk_recovery/.gitignore
@@ -0,0 +1 @@
+blk_recovery
diff --git a/src/test/blk_recovery/Makefile b/src/test/blk_recovery/Makefile
new file mode 100644
index 0000000000000000000000000000000000000000..e061f366de9f4c909348992ea6a33428aa74894d
--- /dev/null
+++ b/src/test/blk_recovery/Makefile
@@ -0,0 +1,45 @@
+#
+# Copyright (c) 2014, Intel Corporation
+#
+# Redistribution and use in source and binary forms, with or without
+# modification, are permitted provided that the following conditions
+# are met:
+#
+#     * Redistributions of source code must retain the above copyright
+#       notice, this list of conditions and the following disclaimer.
+#
+#     * Redistributions in binary form must reproduce the above copyright
+#       notice, this list of conditions and the following disclaimer in
+#       the documentation and/or other materials provided with the
+#       distribution.
+#
+#     * Neither the name of Intel Corporation nor the names of its
+#       contributors may be used to endorse or promote products derived
+#       from this software without specific prior written permission.
+#
+# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+#
+
+#
+# src/test/blk_recovery/Makefile -- build blk_recovery unit test
+#
+vpath %.h ../..
+TARGET = blk_recovery
+OBJS = blk_recovery.o
+
+include ../Makefile.inc
+CFLAGS += -I../..
+
+LIBS += -lpmem -lpthread
+
+blk_recovery.o: blk_recovery.c
diff --git a/src/test/blk_recovery/README b/src/test/blk_recovery/README
new file mode 100644
index 0000000000000000000000000000000000000000..2152eb65ae8849404874ce4b45bd5f1cc29fad33
--- /dev/null
+++ b/src/test/blk_recovery/README
@@ -0,0 +1,22 @@
+Linux NVM Library
+
+This is src/test/blk_recovery/README.
+
+This directory contains a unit test for pmemblk recovery
+
+The program in blk_recovery.c takes a block size, file and two LBAs.
+A write to the first LBA is performed, then the arena map data structure
+protections are modified to be read-only, then the remaining LBA is written.
+
+For example:
+
+	./blk_recovery 4096 file1 5 10
+
+this will call pmemblk_map() on file1, call pmemblk_write() for LBA 5
+(causing all the layout to be written), then it will change the memory
+protection on the arean map area to read-only.  Next, pmemblk_write()
+is called for for LBA 10 and SIGSEGV is caught and reported.  Finally,
+pmemblk_check() is called.
+
+This is not a perfect simulation of a system interruption, but does allow
+creating a file where a write was interrupted before updating the map.
diff --git a/src/test/blk_recovery/TEST0 b/src/test/blk_recovery/TEST0
new file mode 100755
index 0000000000000000000000000000000000000000..0a2c2e12691eddf3cfbea584bc5f212111b675c2
--- /dev/null
+++ b/src/test/blk_recovery/TEST0
@@ -0,0 +1,61 @@
+#!/bin/bash -e
+#
+# Copyright (c) 2014, Intel Corporation
+#
+# Redistribution and use in source and binary forms, with or without
+# modification, are permitted provided that the following conditions
+# are met:
+#
+#     * Redistributions of source code must retain the above copyright
+#       notice, this list of conditions and the following disclaimer.
+#
+#     * Redistributions in binary form must reproduce the above copyright
+#       notice, this list of conditions and the following disclaimer in
+#       the documentation and/or other materials provided with the
+#       distribution.
+#
+#     * Neither the name of Intel Corporation nor the names of its
+#       contributors may be used to endorse or promote products derived
+#       from this software without specific prior written permission.
+#
+# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+#
+
+#
+# src/test/blk_recovery/TEST0 -- unit test for pmemblk recovery
+#
+export UNITTEST_NAME=blk_recovery/TEST0
+export UNITTEST_NUM=0
+
+# standard unit test setup
+. ../unittest/unittest.sh
+
+# doesn't make sense to run in local directory
+require_fs_type pmem non-pmem
+
+setup
+
+# single arena case
+rm -f $DIR/testfile1
+truncate -s 2G $DIR/testfile1
+
+#
+# Simple case, one write interrupted.  pmemblk_check() should note
+# that testfile1 is consistent (after recovery steps were taken).
+#
+expect_normal_exit ./blk_recovery$EXESUFFIX 4096 $DIR/testfile1 5 10
+rm $DIR/testfile1
+
+check
+
+pass
diff --git a/src/test/blk_recovery/blk_recovery.c b/src/test/blk_recovery/blk_recovery.c
new file mode 100644
index 0000000000000000000000000000000000000000..65091b78eed0f954d03a2e08af49ebc513658151
--- /dev/null
+++ b/src/test/blk_recovery/blk_recovery.c
@@ -0,0 +1,168 @@
+/*
+ * Copyright (c) 2014, Intel Corporation
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ *     * Redistributions of source code must retain the above copyright
+ *       notice, this list of conditions and the following disclaimer.
+ *
+ *     * Redistributions in binary form must reproduce the above copyright
+ *       notice, this list of conditions and the following disclaimer in
+ *       the documentation and/or other materials provided with the
+ *       distribution.
+ *
+ *     * Neither the name of Intel Corporation nor the names of its
+ *       contributors may be used to endorse or promote products derived
+ *       from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+/*
+ * blk_recovery.c -- unit test for pmemblk recovery
+ *
+ * usage: blk_recovery bsize file first_lba lba
+ *
+ */
+
+#include "unittest.h"
+
+#include <sys/param.h>
+
+#include "util.h"
+#include "blk.h"
+#include "btt_layout.h"
+
+size_t Bsize;
+
+/*
+ * construct -- build a buffer for writing
+ */
+void
+construct(unsigned char *buf)
+{
+	static int ord = 1;
+
+	for (int i = 0; i < Bsize; i++)
+		buf[i] = ord;
+
+	ord++;
+
+	if (ord > 255)
+		ord = 1;
+}
+
+/*
+ * ident -- identify what a buffer holds
+ */
+char *
+ident(unsigned char *buf)
+{
+	static char descr[100];
+	unsigned val = *buf;
+
+	for (int i = 1; i < Bsize; i++)
+		if (buf[i] != val) {
+			sprintf(descr, "{%u} TORN at byte %d", val, i);
+			return descr;
+		}
+
+	sprintf(descr, "{%u}", val);
+	return descr;
+}
+
+sigjmp_buf Jmp;
+
+/*
+ * signal_handler -- called on SIGSEGV
+ */
+void
+signal_handler(int sig)
+{
+	OUT("signal: %s", strsignal(sig));
+
+	siglongjmp(Jmp, 1);
+}
+
+int
+main(int argc, char *argv[])
+{
+	START(argc, argv, "blk_recovery");
+
+	if (argc != 5)
+		FATAL("usage: %s bsize file first_lba lba", argv[0]);
+
+	Bsize = strtoul(argv[1], NULL, 0);
+
+	int fd = OPEN(argv[2], O_RDWR);
+
+	PMEMblk *handle;
+	if ((handle = pmemblk_map(fd, Bsize)) == NULL)
+		FATAL("!%s: pmemblk_map", argv[2]);
+
+	close(fd);
+
+	OUT("%s block size %zu usable blocks %zu",
+			argv[1], Bsize, pmemblk_nblock(handle));
+
+	/* write the first lba */
+	off_t lba = strtoul(argv[3], NULL, 0);
+	unsigned char buf[Bsize];
+
+	construct(buf);
+	if (pmemblk_write(handle, buf, lba) < 0)
+		FATAL("!write     lba %zu", lba);
+
+	OUT("write     lba %zu: %s", lba, ident(buf));
+
+	/* reach into the layout and write-protect the map */
+	struct btt_info *infop = (void *)handle +
+		roundup(sizeof (struct pmemblk), BLK_FORMAT_DATA_ALIGN);
+
+	void *mapaddr = (void *)infop + le32toh(infop->mapoff);
+	void *flogaddr = (void *)infop + le32toh(infop->flogoff);
+
+	OUT("write-protecting map, length %zu", (size_t)(flogaddr - mapaddr));
+	MPROTECT(mapaddr, (size_t)(flogaddr - mapaddr), PROT_READ);
+
+	/* arrange to catch SEGV */
+	struct sigvec v = { 0 };
+	v.sv_handler = signal_handler;
+	SIGVEC(SIGSEGV, &v, NULL);
+
+	/* map each file argument with the given map type */
+	lba = strtoul(argv[4], NULL, 0);
+
+	construct(buf);
+
+	if (!sigsetjmp(Jmp, 1)) {
+		if (pmemblk_write(handle, buf, lba) < 0)
+			FATAL("!write     lba %zu", lba);
+		else
+			FATAL("write     lba %zu: %s", lba, ident(buf));
+	}
+
+	pmemblk_unmap(handle);
+
+	int result = pmemblk_check(argv[2]);
+	if (result < 0)
+		OUT("!%s: pmemblk_check", argv[2]);
+	else if (result == 0)
+		OUT("%s: pmemblk_check: not consistent", argv[2]);
+	else
+		OUT("%s: consistent", argv[2]);
+
+	DONE(NULL);
+}
diff --git a/src/test/blk_recovery/out0.log.match b/src/test/blk_recovery/out0.log.match
new file mode 100644
index 0000000000000000000000000000000000000000..3e907fd6f330d0ffdd6fa299cf228653513b8cf9
--- /dev/null
+++ b/src/test/blk_recovery/out0.log.match
@@ -0,0 +1,8 @@
+blk_recovery/TEST0: START: blk_recovery
+ ./blk_recovery$(*) 4096 $(*)/testfile1 5 10
+4096 block size 4096 usable blocks 523513
+write     lba 5: {1}
+write-protecting map, length 2097152
+signal: Segmentation fault
+$(*)/testfile1: consistent
+blk_recovery/TEST0: Done
diff --git a/src/test/blk_rw/.gitignore b/src/test/blk_rw/.gitignore
new file mode 100644
index 0000000000000000000000000000000000000000..25eb07ae885bf0b198ed665587a0b7d8fe084793
--- /dev/null
+++ b/src/test/blk_rw/.gitignore
@@ -0,0 +1 @@
+blk_rw
diff --git a/src/test/blk_rw/Makefile b/src/test/blk_rw/Makefile
new file mode 100644
index 0000000000000000000000000000000000000000..c40f87fc2c3714c25c9927cd7a56a9937cc029f9
--- /dev/null
+++ b/src/test/blk_rw/Makefile
@@ -0,0 +1,45 @@
+#
+# Copyright (c) 2014, Intel Corporation
+#
+# Redistribution and use in source and binary forms, with or without
+# modification, are permitted provided that the following conditions
+# are met:
+#
+#     * Redistributions of source code must retain the above copyright
+#       notice, this list of conditions and the following disclaimer.
+#
+#     * Redistributions in binary form must reproduce the above copyright
+#       notice, this list of conditions and the following disclaimer in
+#       the documentation and/or other materials provided with the
+#       distribution.
+#
+#     * Neither the name of Intel Corporation nor the names of its
+#       contributors may be used to endorse or promote products derived
+#       from this software without specific prior written permission.
+#
+# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+#
+
+#
+# src/test/blk_rw/Makefile -- build blk_rw unit test
+#
+TARGET = blk_rw
+OBJS = blk_rw.o
+
+include ../Makefile.inc
+
+LIBS += -lpmem -lpthread -ldl
+STATIC_DEBUG_LIBS += -ldl
+STATIC_NONDEBUG_LIBS += -ldl
+
+blk_rw.o: blk_rw.c
diff --git a/src/test/blk_rw/README b/src/test/blk_rw/README
new file mode 100644
index 0000000000000000000000000000000000000000..373918f4a4a3f5656dee272b17e6deee0f91a7b4
--- /dev/null
+++ b/src/test/blk_rw/README
@@ -0,0 +1,19 @@
+Linux NVM Library
+
+This is src/test/blk_rw/README.
+
+This directory contains a unit test for pmemblk_read/write/set_zero/set_error.
+
+The program in blk_rw.c takes a block size, file and a list of
+operation:LBA pairs.  For example:
+
+	./blk_rw 4096 file1 r:0 w:5 z:9 e:100
+
+this will call pmemblk_map() on file1 and then pmemblk_read() for LBA 0,
+pmemblk_write() for LBA 5, pmemblk_set_zero() for LBA 9, and pmem_set_error()
+for LAB 100.
+
+Each block written is filled up with the ordinal number of the write
+operation (a block full of 8-bit 1s, then a block filled with 8-bit 2s,
+etc.).  When a block is read, the number it was filled with is reported
+(and the program verifies the entire block is filled with that number).
diff --git a/src/test/blk_rw/TEST0 b/src/test/blk_rw/TEST0
new file mode 100755
index 0000000000000000000000000000000000000000..e8aefc5e90d134fdf5521f01cb63b3499091fc61
--- /dev/null
+++ b/src/test/blk_rw/TEST0
@@ -0,0 +1,62 @@
+#!/bin/bash -e
+#
+# Copyright (c) 2014, Intel Corporation
+#
+# Redistribution and use in source and binary forms, with or without
+# modification, are permitted provided that the following conditions
+# are met:
+#
+#     * Redistributions of source code must retain the above copyright
+#       notice, this list of conditions and the following disclaimer.
+#
+#     * Redistributions in binary form must reproduce the above copyright
+#       notice, this list of conditions and the following disclaimer in
+#       the documentation and/or other materials provided with the
+#       distribution.
+#
+#     * Neither the name of Intel Corporation nor the names of its
+#       contributors may be used to endorse or promote products derived
+#       from this software without specific prior written permission.
+#
+# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+#
+
+#
+# src/test/blk_rw/TEST0 -- unit test for pmemblk_read/write/set_zero/set_error
+#
+export UNITTEST_NAME=blk_rw/TEST0
+export UNITTEST_NUM=0
+
+# standard unit test setup
+. ../unittest/unittest.sh
+
+# doesn't make sense to run in local directory
+require_fs_type pmem non-pmem
+
+setup
+
+# single arena case
+rm -f $DIR/testfile1
+truncate -s 2G $DIR/testfile1
+#
+# All reads to an unwritten block pool should return zeros.
+# Block 4161478 is out of range and should return EINVAL.
+# Attempts to zero uninitialized blocks are nops (should succeed).
+#
+expect_normal_exit ./blk_rw$EXESUFFIX 512 $DIR/testfile1\
+	r:0 r:1 r:4161477 r:4161478 z:0 z:1 r:0
+rm $DIR/testfile1
+
+check
+
+pass
diff --git a/src/test/blk_rw/TEST1 b/src/test/blk_rw/TEST1
new file mode 100755
index 0000000000000000000000000000000000000000..2832edabd4cfd4878ea21e0e9d5cde371c6997c0
--- /dev/null
+++ b/src/test/blk_rw/TEST1
@@ -0,0 +1,62 @@
+#!/bin/bash -e
+#
+# Copyright (c) 2014, Intel Corporation
+#
+# Redistribution and use in source and binary forms, with or without
+# modification, are permitted provided that the following conditions
+# are met:
+#
+#     * Redistributions of source code must retain the above copyright
+#       notice, this list of conditions and the following disclaimer.
+#
+#     * Redistributions in binary form must reproduce the above copyright
+#       notice, this list of conditions and the following disclaimer in
+#       the documentation and/or other materials provided with the
+#       distribution.
+#
+#     * Neither the name of Intel Corporation nor the names of its
+#       contributors may be used to endorse or promote products derived
+#       from this software without specific prior written permission.
+#
+# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+#
+
+#
+# src/test/blk_rw/TEST1 -- unit test for pmemblk_read/write/set_zero/set_error
+#
+export UNITTEST_NAME=blk_rw/TEST1
+export UNITTEST_NUM=1
+
+# standard unit test setup
+. ../unittest/unittest.sh
+
+# doesn't make sense to run in local directory
+require_fs_type pmem non-pmem
+
+setup
+
+# multi-arena case
+rm -f $DIR/testfile1
+truncate -s 1026G $DIR/testfile1
+#
+# All reads to an unwritten block pool should return zeros.
+# Block 2134997374 is out of range and should return EINVAL.
+# Attempts to zero uninitialized blocks are nops (should succeed).
+#
+expect_normal_exit ./blk_rw$EXESUFFIX 512 $DIR/testfile1\
+	r:0 r:1 r:4161480 r:2134997373 r:2134997374 z:0 z:4161480
+rm $DIR/testfile1
+
+check
+
+pass
diff --git a/src/test/blk_rw/TEST2 b/src/test/blk_rw/TEST2
new file mode 100755
index 0000000000000000000000000000000000000000..fa494e960fcf5fe9e2621bcf1779328d31859f20
--- /dev/null
+++ b/src/test/blk_rw/TEST2
@@ -0,0 +1,62 @@
+#!/bin/bash -e
+#
+# Copyright (c) 2014, Intel Corporation
+#
+# Redistribution and use in source and binary forms, with or without
+# modification, are permitted provided that the following conditions
+# are met:
+#
+#     * Redistributions of source code must retain the above copyright
+#       notice, this list of conditions and the following disclaimer.
+#
+#     * Redistributions in binary form must reproduce the above copyright
+#       notice, this list of conditions and the following disclaimer in
+#       the documentation and/or other materials provided with the
+#       distribution.
+#
+#     * Neither the name of Intel Corporation nor the names of its
+#       contributors may be used to endorse or promote products derived
+#       from this software without specific prior written permission.
+#
+# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+#
+
+#
+# src/test/blk_rw/TEST2 -- unit test for pmemblk_read/write/set_zero/set_error
+#
+export UNITTEST_NAME=blk_rw/TEST2
+export UNITTEST_NUM=2
+
+# standard unit test setup
+. ../unittest/unittest.sh
+
+# doesn't make sense to run in local directory
+require_fs_type pmem non-pmem
+
+setup
+
+# multi-arena case
+rm -f $DIR/testfile1
+truncate -s 1026G $DIR/testfile1
+#
+# All reads to an unwritten block pool should return zeros.
+# Block 268696557 is out of range and should return EINVAL.
+# Attempts to zero uninitialized blocks are nops (should succeed).
+#
+expect_normal_exit ./blk_rw$EXESUFFIX 4096 $DIR/testfile1\
+	r:0 r:1 r:4161480 r:268696556 r:268696557 z:0 z:4161480
+rm $DIR/testfile1
+
+check
+
+pass
diff --git a/src/test/blk_rw/TEST3 b/src/test/blk_rw/TEST3
new file mode 100755
index 0000000000000000000000000000000000000000..e72333332a21ecede03ce47265b07ce950e253f4
--- /dev/null
+++ b/src/test/blk_rw/TEST3
@@ -0,0 +1,56 @@
+#!/bin/bash -e
+#
+# Copyright (c) 2014, Intel Corporation
+#
+# Redistribution and use in source and binary forms, with or without
+# modification, are permitted provided that the following conditions
+# are met:
+#
+#     * Redistributions of source code must retain the above copyright
+#       notice, this list of conditions and the following disclaimer.
+#
+#     * Redistributions in binary form must reproduce the above copyright
+#       notice, this list of conditions and the following disclaimer in
+#       the documentation and/or other materials provided with the
+#       distribution.
+#
+#     * Neither the name of Intel Corporation nor the names of its
+#       contributors may be used to endorse or promote products derived
+#       from this software without specific prior written permission.
+#
+# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+#
+
+#
+# src/test/blk_rw/TEST3 -- unit test for pmemblk_read/write/set_zero/set_error
+#
+export UNITTEST_NAME=blk_rw/TEST3
+export UNITTEST_NUM=3
+
+# standard unit test setup
+. ../unittest/unittest.sh
+
+# doesn't make sense to run in local directory
+require_fs_type pmem non-pmem
+
+setup
+
+# single arena write case
+rm -f $DIR/testfile1
+truncate -s 1G $DIR/testfile1
+expect_normal_exit ./blk_rw$EXESUFFIX 512 $DIR/testfile1 w:0 r:1 r:0 w:1 r:0 r:1 r:2
+rm $DIR/testfile1
+
+check
+
+pass
diff --git a/src/test/blk_rw/TEST4 b/src/test/blk_rw/TEST4
new file mode 100755
index 0000000000000000000000000000000000000000..d11de6bb4a426b83753272bfcc8c1989e64be58b
--- /dev/null
+++ b/src/test/blk_rw/TEST4
@@ -0,0 +1,59 @@
+#!/bin/bash -e
+#
+# Copyright (c) 2014, Intel Corporation
+#
+# Redistribution and use in source and binary forms, with or without
+# modification, are permitted provided that the following conditions
+# are met:
+#
+#     * Redistributions of source code must retain the above copyright
+#       notice, this list of conditions and the following disclaimer.
+#
+#     * Redistributions in binary form must reproduce the above copyright
+#       notice, this list of conditions and the following disclaimer in
+#       the documentation and/or other materials provided with the
+#       distribution.
+#
+#     * Neither the name of Intel Corporation nor the names of its
+#       contributors may be used to endorse or promote products derived
+#       from this software without specific prior written permission.
+#
+# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+#
+
+#
+# src/test/blk_rw/TEST4 -- unit test for pmemblk_read/write/set_zero/set_error
+#
+export UNITTEST_NAME=blk_rw/TEST4
+export UNITTEST_NUM=4
+
+# standard unit test setup
+. ../unittest/unittest.sh
+
+# doesn't make sense to run in local directory
+require_fs_type pmem non-pmem
+
+setup
+
+# write re-use test case
+rm -f $DIR/testfile1
+truncate -s 1G $DIR/testfile1
+expect_normal_exit ./blk_rw$EXESUFFIX 512 $DIR/testfile1\
+	w:0 w:1 w:2 w:3 w:4 r:4 r:3 r:2 r:1 r:0
+expect_normal_exit ./blk_rw$EXESUFFIX 512 $DIR/testfile1\
+	w:0 r:4 r:3 r:2 r:1 r:0 w:0 r:0
+rm $DIR/testfile1
+
+check
+
+pass
diff --git a/src/test/blk_rw/TEST5 b/src/test/blk_rw/TEST5
new file mode 100755
index 0000000000000000000000000000000000000000..efbfac3421ae59dd29b8d47a1a48b2bb2b3b0ff8
--- /dev/null
+++ b/src/test/blk_rw/TEST5
@@ -0,0 +1,62 @@
+#!/bin/bash -e
+#
+# Copyright (c) 2014, Intel Corporation
+#
+# Redistribution and use in source and binary forms, with or without
+# modification, are permitted provided that the following conditions
+# are met:
+#
+#     * Redistributions of source code must retain the above copyright
+#       notice, this list of conditions and the following disclaimer.
+#
+#     * Redistributions in binary form must reproduce the above copyright
+#       notice, this list of conditions and the following disclaimer in
+#       the documentation and/or other materials provided with the
+#       distribution.
+#
+#     * Neither the name of Intel Corporation nor the names of its
+#       contributors may be used to endorse or promote products derived
+#       from this software without specific prior written permission.
+#
+# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+#
+
+#
+# src/test/blk_rw/TEST5 -- unit test for pmemblk_read/write/set_zero/set_error
+#
+export UNITTEST_NAME=blk_rw/TEST5
+export UNITTEST_NUM=5
+
+# standard unit test setup
+. ../unittest/unittest.sh
+
+# doesn't make sense to run in local directory
+require_fs_type pmem non-pmem
+
+setup
+
+# mix writes with set_zero and set_error and check results
+rm -f $DIR/testfile1
+truncate -s 1G $DIR/testfile1
+expect_normal_exit ./blk_rw$EXESUFFIX 512 $DIR/testfile1\
+	w:100 w:200 w:300 w:400\
+	r:100 r:200 r:300 r:400\
+	w:100 z:200 w:300 z:400\
+	r:100 r:200 r:300 r:400\
+	e:100 w:200 e:300 w:400\
+	r:100 r:200 r:300 r:400
+rm $DIR/testfile1
+
+check
+
+pass
diff --git a/src/test/blk_rw/blk_rw.c b/src/test/blk_rw/blk_rw.c
new file mode 100644
index 0000000000000000000000000000000000000000..fde46db7cfaab8f2a0bd32db9a46562d275fd9ea
--- /dev/null
+++ b/src/test/blk_rw/blk_rw.c
@@ -0,0 +1,232 @@
+/*
+ * Copyright (c) 2014, Intel Corporation
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ *     * Redistributions of source code must retain the above copyright
+ *       notice, this list of conditions and the following disclaimer.
+ *
+ *     * Redistributions in binary form must reproduce the above copyright
+ *       notice, this list of conditions and the following disclaimer in
+ *       the documentation and/or other materials provided with the
+ *       distribution.
+ *
+ *     * Neither the name of Intel Corporation nor the names of its
+ *       contributors may be used to endorse or promote products derived
+ *       from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+/*
+ * blk_rw.c -- unit test for pmemblk_read/write/set_zero/set_error
+ *
+ * usage: blk_rw bsize file operation:lba...
+ *
+ * operations are 'r' or 'w' or 'z' or 'e'
+ *
+ */
+#define	_GNU_SOURCE
+#include "unittest.h"
+#include <dlfcn.h>
+
+#define	MMAP_MAX_SIZE (1024L * 1024L * 1024L)
+
+size_t Bsize;
+static void *mapped_addr;
+static size_t mapped_size;
+static uint64_t min_addr;
+static uint64_t max_addr;
+
+/*
+ * mmap -- interpose on libc mmap()
+ *
+ * This catches mmap and reduces mapped size up to 1GB.
+ * Code under test doesn’t actually write outside first 1GB of mapped region.
+ * This limit is necessary to work on machines without overcommit.
+ */
+void *
+mmap(void *addr, size_t len, int prot, int flags, int fildes, off_t off)
+{
+	static void *(*mmap_ptr)(void *addr, size_t len, int prot, int flags,
+		int fildes, off_t off);
+	if (mmap_ptr == NULL)
+		mmap_ptr = dlsym(RTLD_NEXT, "mmap");
+
+	if (len > MMAP_MAX_SIZE)
+		len = MMAP_MAX_SIZE;
+
+	ASSERTeq(mapped_addr, NULL);
+	mapped_addr = mmap_ptr(addr, len, prot, flags, fildes, off);
+	mapped_size = len;
+	min_addr = (uint64_t)(mapped_addr);
+	max_addr = (uint64_t)(mapped_addr + len);
+	return mapped_addr;
+}
+
+/*
+ * munmap -- interpose on libc munmap()
+ *
+ * This catches munmap and changes length to size used inside interpose mmap.
+ */
+int
+munmap(void *addr, size_t len)
+{
+	static int(*munmap_ptr)(void *addr, size_t len);
+	if (munmap_ptr == NULL)
+		munmap_ptr = dlsym(RTLD_NEXT, "munmap");
+
+	if (addr == mapped_addr) {
+		len = mapped_size;
+		mapped_addr = NULL;
+	}
+
+	return munmap_ptr(addr, len);
+}
+
+/*
+ * mprotect -- interpose on libc mprotect()
+ *
+ * This catches mprotect and adjusts length to max_addr
+ * set inside interposed mmap.
+ */
+int
+mprotect(void *addr, size_t len, int prot)
+{
+	static int (*mprotect_ptr)(void *addr, size_t len, int prot);
+	uint64_t addr_int = (uint64_t)addr;
+
+	if (mprotect_ptr == NULL)
+		mprotect_ptr = dlsym(RTLD_NEXT, "mprotect");
+
+	if (addr_int >= min_addr && addr_int <= max_addr &&
+	    addr_int + len > max_addr) {
+
+		/* unit tests are not supposed to write beyond the 1GB range */
+		ASSERTeq(prot & PROT_WRITE, 0);
+
+		len = max_addr - addr_int;
+	}
+
+	return mprotect_ptr(addr, len, prot);
+}
+
+/*
+ * construct -- build a buffer for writing
+ */
+void
+construct(unsigned char *buf)
+{
+	static int ord = 1;
+
+	for (int i = 0; i < Bsize; i++)
+		buf[i] = ord;
+
+	ord++;
+
+	if (ord > 255)
+		ord = 1;
+}
+
+/*
+ * ident -- identify what a buffer holds
+ */
+char *
+ident(unsigned char *buf)
+{
+	static char descr[100];
+	unsigned val = *buf;
+
+	for (int i = 1; i < Bsize; i++)
+		if (buf[i] != val) {
+			sprintf(descr, "{%u} TORN at byte %d", val, i);
+			return descr;
+		}
+
+	sprintf(descr, "{%u}", val);
+	return descr;
+}
+
+int
+main(int argc, char *argv[])
+{
+	START(argc, argv, "blk_rw");
+
+	if (argc < 4)
+		FATAL("usage: %s bsize file op:lba...", argv[0]);
+
+	Bsize = strtoul(argv[1], NULL, 0);
+
+	int fd = OPEN(argv[2], O_RDWR);
+
+	PMEMblk *handle;
+	if ((handle = pmemblk_map(fd, Bsize)) == NULL)
+		FATAL("!%s: pmemblk_map", argv[2]);
+
+	close(fd);
+
+	OUT("%s block size %zu usable blocks %zu",
+			argv[1], Bsize, pmemblk_nblock(handle));
+
+	/* map each file argument with the given map type */
+	for (int arg = 3; arg < argc; arg++) {
+		if (strchr("rwze", argv[arg][0]) == NULL || argv[arg][1] != ':')
+			FATAL("op must be r: or w: or z: or e:");
+		off_t lba = strtoul(&argv[arg][2], NULL, 0);
+
+		unsigned char buf[Bsize];
+
+		switch (argv[arg][0]) {
+		case 'r':
+			if (pmemblk_read(handle, buf, lba) < 0)
+				OUT("!read      lba %zu", lba);
+			else
+				OUT("read      lba %zu: %s", lba, ident(buf));
+			break;
+
+		case 'w':
+			construct(buf);
+			if (pmemblk_write(handle, buf, lba) < 0)
+				OUT("!write     lba %zu", lba);
+			else
+				OUT("write     lba %zu: %s", lba, ident(buf));
+			break;
+
+		case 'z':
+			if (pmemblk_set_zero(handle, lba) < 0)
+				OUT("!set_zero  lba %zu", lba);
+			else
+				OUT("set_zero  lba %zu", lba);
+			break;
+
+		case 'e':
+			if (pmemblk_set_error(handle, lba) < 0)
+				OUT("!set_error lba %zu", lba);
+			else
+				OUT("set_error lba %zu", lba);
+			break;
+		}
+	}
+
+	pmemblk_unmap(handle);
+
+	int result = pmemblk_check(argv[2]);
+	if (result < 0)
+		OUT("!%s: pmemblk_check", argv[2]);
+	else if (result == 0)
+		OUT("%s: pmemblk_check: not consistent", argv[2]);
+
+	DONE(NULL);
+}
diff --git a/src/test/blk_rw/err0.log.match b/src/test/blk_rw/err0.log.match
new file mode 100644
index 0000000000000000000000000000000000000000..e69de29bb2d1d6434b8b29ae775ad8c2e48c5391
diff --git a/src/test/blk_rw/err1.log.match b/src/test/blk_rw/err1.log.match
new file mode 100644
index 0000000000000000000000000000000000000000..e69de29bb2d1d6434b8b29ae775ad8c2e48c5391
diff --git a/src/test/blk_rw/err2.log.match b/src/test/blk_rw/err2.log.match
new file mode 100644
index 0000000000000000000000000000000000000000..e69de29bb2d1d6434b8b29ae775ad8c2e48c5391
diff --git a/src/test/blk_rw/err3.log.match b/src/test/blk_rw/err3.log.match
new file mode 100644
index 0000000000000000000000000000000000000000..e69de29bb2d1d6434b8b29ae775ad8c2e48c5391
diff --git a/src/test/blk_rw/err4.log.match b/src/test/blk_rw/err4.log.match
new file mode 100644
index 0000000000000000000000000000000000000000..e69de29bb2d1d6434b8b29ae775ad8c2e48c5391
diff --git a/src/test/blk_rw/err5.log.match b/src/test/blk_rw/err5.log.match
new file mode 100644
index 0000000000000000000000000000000000000000..e69de29bb2d1d6434b8b29ae775ad8c2e48c5391
diff --git a/src/test/blk_rw/out0.log.match b/src/test/blk_rw/out0.log.match
new file mode 100644
index 0000000000000000000000000000000000000000..f2bf377e9ff846a88c55f1af95dad99d0daa5d7a
--- /dev/null
+++ b/src/test/blk_rw/out0.log.match
@@ -0,0 +1,11 @@
+blk_rw/TEST0: START: blk_rw
+ ./blk_rw$(*) 512 $(*)/testfile1 r:0 r:1 r:4161477 r:4161478 z:0 z:1 r:0
+512 block size 512 usable blocks 4161478
+read      lba 0: {0}
+read      lba 1: {0}
+read      lba 4161477: {0}
+read      lba 4161478: Invalid argument
+set_zero  lba 0
+set_zero  lba 1
+read      lba 0: {0}
+blk_rw/TEST0: Done
diff --git a/src/test/blk_rw/out2.log.match b/src/test/blk_rw/out2.log.match
new file mode 100644
index 0000000000000000000000000000000000000000..61ae6272be97713e901497aa3c19f10e9bb87cb9
--- /dev/null
+++ b/src/test/blk_rw/out2.log.match
@@ -0,0 +1,11 @@
+blk_rw/TEST2: START: blk_rw
+ ./blk_rw$(*) 4096 $(*)/testfile1 r:0 r:1 r:4161480 r:268696556 r:268696557 z:0 z:4161480
+4096 block size 4096 usable blocks 268696557
+read      lba 0: {0}
+read      lba 1: {0}
+read      lba 4161480: {0}
+read      lba 268696556: {0}
+read      lba 268696557: Invalid argument
+set_zero  lba 0
+set_zero  lba 4161480
+blk_rw/TEST2: Done
diff --git a/src/test/blk_rw/out3.log.match b/src/test/blk_rw/out3.log.match
new file mode 100644
index 0000000000000000000000000000000000000000..b5093801cecb32d0b1df6d897fb0fd9c982d2a10
--- /dev/null
+++ b/src/test/blk_rw/out3.log.match
@@ -0,0 +1,11 @@
+blk_rw/TEST3: START: blk_rw
+ ./blk_rw$(*) 512 $(*)/testfile1 w:0 r:1 r:0 w:1 r:0 r:1 r:2
+512 block size 512 usable blocks 2080583
+write     lba 0: {1}
+read      lba 1: {0}
+read      lba 0: {1}
+write     lba 1: {2}
+read      lba 0: {1}
+read      lba 1: {2}
+read      lba 2: {0}
+blk_rw/TEST3: Done
diff --git a/src/test/blk_rw/out4.log.match b/src/test/blk_rw/out4.log.match
new file mode 100644
index 0000000000000000000000000000000000000000..5d56181b0c915e36a97d47e8b897015c6074def6
--- /dev/null
+++ b/src/test/blk_rw/out4.log.match
@@ -0,0 +1,12 @@
+blk_rw/TEST4: START: blk_rw
+ ./blk_rw$(*) 512 $(*)/testfile1 w:0 r:4 r:3 r:2 r:1 r:0 w:0 r:0
+512 block size 512 usable blocks 2080583
+write     lba 0: {1}
+read      lba 4: {5}
+read      lba 3: {4}
+read      lba 2: {3}
+read      lba 1: {2}
+read      lba 0: {1}
+write     lba 0: {2}
+read      lba 0: {2}
+blk_rw/TEST4: Done
diff --git a/src/test/blk_rw/out5.log.match b/src/test/blk_rw/out5.log.match
new file mode 100644
index 0000000000000000000000000000000000000000..b8dfaa7da86532f6568474a1c89165c088306931
--- /dev/null
+++ b/src/test/blk_rw/out5.log.match
@@ -0,0 +1,28 @@
+blk_rw/TEST5: START: blk_rw
+ ./blk_rw$(*) 512 $(*)/testfile1 w:100 w:200 w:300 w:400 r:100 r:200 r:300 r:400 w:100 z:200 w:300 z:400 r:100 r:200 r:300 r:400 e:100 w:200 e:300 w:400 r:100 r:200 r:300 r:400
+512 block size 512 usable blocks 2080583
+write     lba 100: {1}
+write     lba 200: {2}
+write     lba 300: {3}
+write     lba 400: {4}
+read      lba 100: {1}
+read      lba 200: {2}
+read      lba 300: {3}
+read      lba 400: {4}
+write     lba 100: {5}
+set_zero  lba 200
+write     lba 300: {6}
+set_zero  lba 400
+read      lba 100: {5}
+read      lba 200: {0}
+read      lba 300: {6}
+read      lba 400: {0}
+set_error lba 100
+write     lba 200: {7}
+set_error lba 300
+write     lba 400: {8}
+read      lba 100: Input/output error
+read      lba 200: {7}
+read      lba 300: Input/output error
+read      lba 400: {8}
+blk_rw/TEST5: Done
diff --git a/src/test/blk_rw_mt/.gitignore b/src/test/blk_rw_mt/.gitignore
new file mode 100644
index 0000000000000000000000000000000000000000..c9a111b2e56f70f19e1fe2267358249ac1c91b86
--- /dev/null
+++ b/src/test/blk_rw_mt/.gitignore
@@ -0,0 +1 @@
+blk_rw_mt
diff --git a/src/test/blk_rw_mt/Makefile b/src/test/blk_rw_mt/Makefile
new file mode 100644
index 0000000000000000000000000000000000000000..b54e2756971385556be1180d54b99242ec697452
--- /dev/null
+++ b/src/test/blk_rw_mt/Makefile
@@ -0,0 +1,43 @@
+#
+# Copyright (c) 2014, Intel Corporation
+#
+# Redistribution and use in source and binary forms, with or without
+# modification, are permitted provided that the following conditions
+# are met:
+#
+#     * Redistributions of source code must retain the above copyright
+#       notice, this list of conditions and the following disclaimer.
+#
+#     * Redistributions in binary form must reproduce the above copyright
+#       notice, this list of conditions and the following disclaimer in
+#       the documentation and/or other materials provided with the
+#       distribution.
+#
+#     * Neither the name of Intel Corporation nor the names of its
+#       contributors may be used to endorse or promote products derived
+#       from this software without specific prior written permission.
+#
+# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+#
+
+#
+# src/test/blk_rw_mt/Makefile -- build blk_rw_mt unit test
+#
+TARGET = blk_rw_mt
+OBJS = blk_rw_mt.o
+
+include ../Makefile.inc
+
+LIBS += -lpmem -lpthread
+
+blk_rw_mt.o: blk_rw_mt.c
diff --git a/src/test/blk_rw_mt/README b/src/test/blk_rw_mt/README
new file mode 100644
index 0000000000000000000000000000000000000000..1808350658c482d9be63053cc56ad581cf22defa
--- /dev/null
+++ b/src/test/blk_rw_mt/README
@@ -0,0 +1,14 @@
+Linux NVM Library
+
+This is src/test/blk_rw_mt/README.
+
+This directory contains a unit test for MT reads & writes.
+
+The program in blk_rw_mt.c takes a block size, a file, a random number
+generator seed (to make the results repeatable), a thread count, and the
+numer of I/Os to do per thread.  For example:
+
+	./blk_rw_mt 4096 file1 123 300 500
+
+this will create a pool in file1 with block size 4096, fork 300 threads,
+and each thread will do 500 random I/Os (50/50 reads/writes).
diff --git a/src/test/blk_rw_mt/TEST0 b/src/test/blk_rw_mt/TEST0
new file mode 100755
index 0000000000000000000000000000000000000000..3d9909e75dd72a9161974a96092d0a6acacfd0cc
--- /dev/null
+++ b/src/test/blk_rw_mt/TEST0
@@ -0,0 +1,56 @@
+#!/bin/bash -e
+#
+# Copyright (c) 2014, Intel Corporation
+#
+# Redistribution and use in source and binary forms, with or without
+# modification, are permitted provided that the following conditions
+# are met:
+#
+#     * Redistributions of source code must retain the above copyright
+#       notice, this list of conditions and the following disclaimer.
+#
+#     * Redistributions in binary form must reproduce the above copyright
+#       notice, this list of conditions and the following disclaimer in
+#       the documentation and/or other materials provided with the
+#       distribution.
+#
+#     * Neither the name of Intel Corporation nor the names of its
+#       contributors may be used to endorse or promote products derived
+#       from this software without specific prior written permission.
+#
+# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+#
+
+#
+# src/test/blk_rw_mt/TEST0 -- unit test for MT I/O on blk pool
+#
+export UNITTEST_NAME=blk_rw_mt/TEST0
+export UNITTEST_NUM=0
+
+# standard unit test setup
+. ../unittest/unittest.sh
+
+# doesn't make sense to run in local directory
+require_fs_type pmem non-pmem
+
+setup
+
+rm -f $DIR/testfile1
+truncate -s 1G $DIR/testfile1
+# 5 threads, each doing 80 random I/Os
+expect_normal_exit ./blk_rw_mt$EXESUFFIX 4096 $DIR/testfile1 123 5 80
+rm $DIR/testfile1
+
+check
+
+pass
diff --git a/src/test/blk_rw_mt/TEST1 b/src/test/blk_rw_mt/TEST1
new file mode 100755
index 0000000000000000000000000000000000000000..b842897e00129350db09ca4f4dd549d94a25b8a7
--- /dev/null
+++ b/src/test/blk_rw_mt/TEST1
@@ -0,0 +1,59 @@
+#!/bin/bash -e
+#
+# Copyright (c) 2014, Intel Corporation
+#
+# Redistribution and use in source and binary forms, with or without
+# modification, are permitted provided that the following conditions
+# are met:
+#
+#     * Redistributions of source code must retain the above copyright
+#       notice, this list of conditions and the following disclaimer.
+#
+#     * Redistributions in binary form must reproduce the above copyright
+#       notice, this list of conditions and the following disclaimer in
+#       the documentation and/or other materials provided with the
+#       distribution.
+#
+#     * Neither the name of Intel Corporation nor the names of its
+#       contributors may be used to endorse or promote products derived
+#       from this software without specific prior written permission.
+#
+# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+#
+
+#
+# src/test/blk_rw_mt/TEST1 -- unit test for MT I/O on blk pool
+#
+export UNITTEST_NAME=blk_rw_mt/TEST1
+export UNITTEST_NUM=1
+
+# standard unit test setup
+. ../unittest/unittest.sh
+
+# this is the short version of the test
+require_test_type short
+
+# doesn't make sense to run in local directory
+require_fs_type pmem non-pmem
+
+setup
+
+rm -f $DIR/testfile1
+truncate -s 1G $DIR/testfile1
+# 100 threads, each doing 100 random I/Os
+expect_normal_exit ./blk_rw_mt$EXESUFFIX 4096 $DIR/testfile1 456 100 100
+rm $DIR/testfile1
+
+check
+
+pass
diff --git a/src/test/blk_rw_mt/TEST2 b/src/test/blk_rw_mt/TEST2
new file mode 100755
index 0000000000000000000000000000000000000000..11b5dca8391bf9b9561461b4cca1d60453fde7c8
--- /dev/null
+++ b/src/test/blk_rw_mt/TEST2
@@ -0,0 +1,59 @@
+#!/bin/bash -e
+#
+# Copyright (c) 2014, Intel Corporation
+#
+# Redistribution and use in source and binary forms, with or without
+# modification, are permitted provided that the following conditions
+# are met:
+#
+#     * Redistributions of source code must retain the above copyright
+#       notice, this list of conditions and the following disclaimer.
+#
+#     * Redistributions in binary form must reproduce the above copyright
+#       notice, this list of conditions and the following disclaimer in
+#       the documentation and/or other materials provided with the
+#       distribution.
+#
+#     * Neither the name of Intel Corporation nor the names of its
+#       contributors may be used to endorse or promote products derived
+#       from this software without specific prior written permission.
+#
+# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+#
+
+#
+# src/test/blk_rw_mt/TEST2 -- unit test for MT I/O on blk pool
+#
+export UNITTEST_NAME=blk_rw_mt/TEST2
+export UNITTEST_NUM=2
+
+# standard unit test setup
+. ../unittest/unittest.sh
+
+# this is the long version of the test
+require_test_type long
+
+# doesn't make sense to run in local directory
+require_fs_type pmem non-pmem
+
+setup
+
+rm -f $DIR/testfile1
+truncate -s 1G $DIR/testfile1
+# 300 threads, each doing 100000 random I/Os
+expect_normal_exit ./blk_rw_mt$EXESUFFIX 4096 $DIR/testfile1 789 300 100000
+rm $DIR/testfile1
+
+check
+
+pass
diff --git a/src/test/blk_rw_mt/blk_rw_mt.c b/src/test/blk_rw_mt/blk_rw_mt.c
new file mode 100644
index 0000000000000000000000000000000000000000..184325f6d8062d9f5fac0b94da28cd1026c6efbe
--- /dev/null
+++ b/src/test/blk_rw_mt/blk_rw_mt.c
@@ -0,0 +1,155 @@
+/*
+ * Copyright (c) 2014, Intel Corporation
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ *     * Redistributions of source code must retain the above copyright
+ *       notice, this list of conditions and the following disclaimer.
+ *
+ *     * Redistributions in binary form must reproduce the above copyright
+ *       notice, this list of conditions and the following disclaimer in
+ *       the documentation and/or other materials provided with the
+ *       distribution.
+ *
+ *     * Neither the name of Intel Corporation nor the names of its
+ *       contributors may be used to endorse or promote products derived
+ *       from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+/*
+ * blk_rw_mt.c -- unit test for multi-threaded random I/O
+ *
+ * usage: blk_rw_mt bsize file seed nthread nops
+ *
+ */
+
+#include "unittest.h"
+
+size_t Bsize;
+size_t Nblock = 100;	/* all I/O below this LBA (increases collisions) */
+unsigned Seed;
+unsigned Nthread;
+unsigned Nops;
+PMEMblk *Handle;
+
+/*
+ * construct -- build a buffer for writing
+ */
+void
+construct(int *ordp, unsigned char *buf)
+{
+	for (int i = 0; i < Bsize; i++)
+		buf[i] = *ordp;
+
+	(*ordp)++;
+
+	if (*ordp > 255)
+		*ordp = 1;
+}
+
+/*
+ * check -- check for torn buffers
+ */
+void
+check(unsigned char *buf)
+{
+	unsigned val = *buf;
+
+	for (int i = 1; i < Bsize; i++)
+		if (buf[i] != val) {
+			OUT("{%u} TORN at byte %d", val, i);
+			break;
+		}
+}
+
+/*
+ * worker -- the work each thread performs
+ */
+void *
+worker(void *arg)
+{
+	long mytid = (long)arg;
+	unsigned myseed = Seed + mytid;
+	unsigned char buf[Bsize];
+	int ord = 1;
+
+	for (int i = 0; i < Nops; i++) {
+		off_t lba = rand_r(&myseed) % Nblock;
+
+		if (rand_r(&myseed) % 2) {
+			/* read */
+			if (pmemblk_read(Handle, buf, lba) < 0)
+				OUT("!read      lba %zu", lba);
+			else
+				check(buf);
+		} else {
+			/* write */
+			construct(&ord, buf);
+			if (pmemblk_write(Handle, buf, lba) < 0)
+				OUT("!write     lba %zu", lba);
+		}
+	}
+
+	return NULL;
+}
+
+int
+main(int argc, char *argv[])
+{
+	START(argc, argv, "blk_rw_mt");
+
+	if (argc != 6)
+		FATAL("usage: %s bsize file seed nthread nops", argv[0]);
+
+	Bsize = strtoul(argv[1], NULL, 0);
+
+	int fd = OPEN(argv[2], O_RDWR);
+
+	if ((Handle = pmemblk_map(fd, Bsize)) == NULL)
+		FATAL("!%s: pmemblk_map", argv[2]);
+
+	close(fd);
+
+	if (Nblock == 0)
+		Nblock = pmemblk_nblock(Handle);
+	Seed = strtoul(argv[3], NULL, 0);
+	Nthread = strtoul(argv[4], NULL, 0);
+	Nops = strtoul(argv[5], NULL, 0);
+
+	OUT("%s block size %zu usable blocks %zu", argv[1], Bsize, Nblock);
+
+	pthread_t threads[Nthread];
+
+	/* kick off nthread threads */
+	for (int i = 0; i < Nthread; i++)
+		PTHREAD_CREATE(&threads[i], NULL, worker, (void *)(long)i);
+
+	/* wait for all the threads to complete */
+	for (int i = 0; i < Nthread; i++)
+		PTHREAD_JOIN(threads[i], NULL);
+
+	pmemblk_unmap(Handle);
+
+	/* XXX not ready to pass this part of the test yet */
+	int result = pmemblk_check(argv[2]);
+	if (result < 0)
+		OUT("!%s: pmemblk_check", argv[2]);
+	else if (result == 0)
+		OUT("%s: pmemblk_check: not consistent", argv[2]);
+
+	DONE(NULL);
+}
diff --git a/src/test/blk_rw_mt/err0.log.match b/src/test/blk_rw_mt/err0.log.match
new file mode 100644
index 0000000000000000000000000000000000000000..e69de29bb2d1d6434b8b29ae775ad8c2e48c5391
diff --git a/src/test/blk_rw_mt/err1.log.match b/src/test/blk_rw_mt/err1.log.match
new file mode 100644
index 0000000000000000000000000000000000000000..e69de29bb2d1d6434b8b29ae775ad8c2e48c5391
diff --git a/src/test/blk_rw_mt/err2.log.match b/src/test/blk_rw_mt/err2.log.match
new file mode 100644
index 0000000000000000000000000000000000000000..e69de29bb2d1d6434b8b29ae775ad8c2e48c5391
diff --git a/src/test/blk_rw_mt/out0.log.match b/src/test/blk_rw_mt/out0.log.match
new file mode 100644
index 0000000000000000000000000000000000000000..0c5231edab9d88a52e8d9471ac9bc6b056adfa08
--- /dev/null
+++ b/src/test/blk_rw_mt/out0.log.match
@@ -0,0 +1,4 @@
+blk_rw_mt/TEST0: START: blk_rw_mt
+ ./blk_rw_mt$(*) 4096 $(*)/testfile1 123 5 80
+4096 block size 4096 usable blocks 100
+blk_rw_mt/TEST0: Done
diff --git a/src/test/blk_rw_mt/out1.log.match b/src/test/blk_rw_mt/out1.log.match
new file mode 100644
index 0000000000000000000000000000000000000000..9e57646f44f783f55a11a3ccf50272b114b4cd1d
--- /dev/null
+++ b/src/test/blk_rw_mt/out1.log.match
@@ -0,0 +1,4 @@
+blk_rw_mt/TEST1: START: blk_rw_mt
+ ./blk_rw_mt$(*) 4096 $(*)/testfile1 456 100 100
+4096 block size 4096 usable blocks 100
+blk_rw_mt/TEST1: Done
diff --git a/src/test/blk_rw_mt/out2.log.match b/src/test/blk_rw_mt/out2.log.match
new file mode 100644
index 0000000000000000000000000000000000000000..3db5383c55bf81eb4e5decc237de2eabaf8133a0
--- /dev/null
+++ b/src/test/blk_rw_mt/out2.log.match
@@ -0,0 +1,4 @@
+blk_rw_mt/TEST2: START: blk_rw_mt
+ ./blk_rw_mt$(*) 4096 $(*)/testfile1 789 300 100000
+4096 block size 4096 usable blocks 100
+blk_rw_mt/TEST2: Done
diff --git a/src/test/checksum/.gitignore b/src/test/checksum/.gitignore
new file mode 100644
index 0000000000000000000000000000000000000000..c5c2772a3214061ef7a4382b4c6b11ea961c9c53
--- /dev/null
+++ b/src/test/checksum/.gitignore
@@ -0,0 +1 @@
+checksum
diff --git a/src/test/checksum/Makefile b/src/test/checksum/Makefile
new file mode 100644
index 0000000000000000000000000000000000000000..66fdfcf81b75f83dae39af6bc0d7d5990b02f662
--- /dev/null
+++ b/src/test/checksum/Makefile
@@ -0,0 +1,50 @@
+#
+# Copyright (c) 2014, Intel Corporation
+#
+# Redistribution and use in source and binary forms, with or without
+# modification, are permitted provided that the following conditions
+# are met:
+#
+#     * Redistributions of source code must retain the above copyright
+#       notice, this list of conditions and the following disclaimer.
+#
+#     * Redistributions in binary form must reproduce the above copyright
+#       notice, this list of conditions and the following disclaimer in
+#       the documentation and/or other materials provided with the
+#       distribution.
+#
+#     * Neither the name of Intel Corporation nor the names of its
+#       contributors may be used to endorse or promote products derived
+#       from this software without specific prior written permission.
+#
+# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+#
+
+#
+# src/test/checksum/Makefile -- build checksum unit test
+#
+vpath %.c ../..
+vpath %.h ../.. ../../include
+TARGET = checksum
+OBJS = checksum.o util.o out.o
+
+out.o: CFLAGS += -DSRCVERSION=\"utversion\"
+
+include ../Makefile.inc
+INCS += -I../.. -I../../include
+
+checksum.o: checksum.c util.h out.h
+
+util.o: util.c util.h out.h
+
+out.o: out.c out.h
diff --git a/src/test/checksum/TEST0 b/src/test/checksum/TEST0
new file mode 100755
index 0000000000000000000000000000000000000000..02d6321ce7588d905bf9f2431e798de90f5944a7
--- /dev/null
+++ b/src/test/checksum/TEST0
@@ -0,0 +1,51 @@
+#!/bin/bash -e
+#
+# Copyright (c) 2014, Intel Corporation
+#
+# Redistribution and use in source and binary forms, with or without
+# modification, are permitted provided that the following conditions
+# are met:
+#
+#     * Redistributions of source code must retain the above copyright
+#       notice, this list of conditions and the following disclaimer.
+#
+#     * Redistributions in binary form must reproduce the above copyright
+#       notice, this list of conditions and the following disclaimer in
+#       the documentation and/or other materials provided with the
+#       distribution.
+#
+#     * Neither the name of Intel Corporation nor the names of its
+#       contributors may be used to endorse or promote products derived
+#       from this software without specific prior written permission.
+#
+# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+#
+
+#
+# src/test/checksum/TEST0 -- unit test for checksum
+#
+export UNITTEST_NAME=checksum/TEST0
+export UNITTEST_NUM=0
+
+# standard unit test setup
+. ../unittest/unittest.sh
+
+require_fs_type local
+
+setup
+
+expect_normal_exit ./checksum$EXESUFFIX ./file?
+
+check
+
+pass
diff --git a/src/test/checksum/checksum.c b/src/test/checksum/checksum.c
new file mode 100644
index 0000000000000000000000000000000000000000..d6c9666580f7ed34f1060ad5a8f61e79068988f7
--- /dev/null
+++ b/src/test/checksum/checksum.c
@@ -0,0 +1,140 @@
+/*
+ * Copyright (c) 2014, Intel Corporation
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ *     * Redistributions of source code must retain the above copyright
+ *       notice, this list of conditions and the following disclaimer.
+ *
+ *     * Redistributions in binary form must reproduce the above copyright
+ *       notice, this list of conditions and the following disclaimer in
+ *       the documentation and/or other materials provided with the
+ *       distribution.
+ *
+ *     * Neither the name of Intel Corporation nor the names of its
+ *       contributors may be used to endorse or promote products derived
+ *       from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+/*
+ * checksum.c -- unit test for library internal checksum routine
+ *
+ * usage: checksum files...
+ */
+
+#include "unittest.h"
+
+#include "util.h"
+
+/*
+ * fletcher64 -- compute a Fletcher64 checksum
+ *
+ * Gold standard implementation used to compare to the
+ * util_checksum() being unit tested.
+ */
+uint64_t
+fletcher64(void *addr, size_t len)
+{
+	uint32_t *p32 = addr;
+	uint32_t *p32end = addr + len;
+	uint32_t lo32 = 0;
+	uint32_t hi32 = 0;
+
+	while (p32 < p32end) {
+		lo32 += *p32++;
+		hi32 += lo32;
+	}
+
+	return (uint64_t)hi32 << 32 | lo32;
+}
+
+int
+main(int argc, char *argv[])
+{
+	START(argc, argv, "checksum");
+
+	if (argc < 2)
+		FATAL("usage: %s files...", argv[0]);
+
+	for (int arg = 1; arg < argc; arg++) {
+		int fd = OPEN(argv[arg], O_RDONLY);
+
+		struct stat stbuf;
+		FSTAT(fd, &stbuf);
+
+		void *addr =
+			MMAP(0, stbuf.st_size, PROT_READ|PROT_WRITE,
+					MAP_PRIVATE, fd, 0);
+
+		close(fd);
+
+		uint64_t *ptr = addr;
+
+		/*
+		 * Loop through, selecting successive locations
+		 * where the checksum lives in this block, and
+		 * let util_checksum() insert it so it can be
+		 * verified against the gold standard fletcher64
+		 * routine in this file.
+		 */
+		while ((void *)(ptr + 1) < addr + stbuf.st_size) {
+			/* save whatever was at *ptr */
+			uint64_t oldval = *ptr;
+
+			/* mess with it */
+			*ptr = 0x123;
+
+			/*
+			 * calc a checksum and have it installed
+			 */
+			util_checksum(addr, stbuf.st_size, ptr, 1);
+
+			uint64_t csum = *ptr;
+
+			/*
+			 * verify inserted checksum checks out
+			 */
+			ASSERT(util_checksum(addr, stbuf.st_size, ptr, 0));
+
+			/* put a zero where the checksum was installed */
+			*ptr = 0;
+
+			/* calculate a checksum */
+			uint64_t gold_csum = fletcher64(addr, stbuf.st_size);
+
+			/* put the old value back */
+			*ptr = oldval;
+
+			/*
+			 * verify checksum now fails
+			 */
+			ASSERT(!util_checksum(addr, stbuf.st_size, ptr, 0));
+
+			/*
+			 * verify the checksum matched the gold version
+			 */
+			ASSERTeq(csum, gold_csum);
+
+			OUT("%s:%lu 0x%lx", argv[arg],
+				(void *)ptr - addr, csum);
+
+			ptr++;
+		}
+	}
+
+	DONE(NULL);
+}
diff --git a/src/test/checksum/err0.log.match b/src/test/checksum/err0.log.match
new file mode 100644
index 0000000000000000000000000000000000000000..e69de29bb2d1d6434b8b29ae775ad8c2e48c5391
diff --git a/src/test/checksum/file1 b/src/test/checksum/file1
new file mode 100644
index 0000000000000000000000000000000000000000..afadc1197b01d8390dd62d62ca739d53b3f5bfd8
--- /dev/null
+++ b/src/test/checksum/file1
@@ -0,0 +1,2 @@
+Hello.  This is a simple text file with a known checksum.
+The checksum unit test is run on this file to check for regressions.
diff --git a/src/test/checksum/file2 b/src/test/checksum/file2
new file mode 100644
index 0000000000000000000000000000000000000000..b1098e404119cecd4c21e5cfdb0f2ee6c916ca2e
--- /dev/null
+++ b/src/test/checksum/file2
@@ -0,0 +1,2 @@
+Iello.  This is a simple text file with a known checksum.
+The checksum unit test is run on this file to check for regressions.
diff --git a/src/test/checksum/file3 b/src/test/checksum/file3
new file mode 100644
index 0000000000000000000000000000000000000000..abf394bb384d017112227e0cd2c1944a5d0d72b3
--- /dev/null
+++ b/src/test/checksum/file3
@@ -0,0 +1,2 @@
+Hello.  This is a simple text file with a known checksum.
+The checksum unit test is run on this file to check for regressions/
diff --git a/src/test/checksum/file4 b/src/test/checksum/file4
new file mode 100644
index 0000000000000000000000000000000000000000..9736630dc7cd5d2c1851d4d9a311d1f8d650985c
Binary files /dev/null and b/src/test/checksum/file4 differ
diff --git a/src/test/checksum/file5 b/src/test/checksum/file5
new file mode 100644
index 0000000000000000000000000000000000000000..959b118626907fa8644dd3281a88ccf1ff4b6f48
Binary files /dev/null and b/src/test/checksum/file5 differ
diff --git a/src/test/checksum/out0.log.match b/src/test/checksum/out0.log.match
new file mode 100644
index 0000000000000000000000000000000000000000..51126218b9d1d4e1cf9fcfab407463e7f8a3a152
--- /dev/null
+++ b/src/test/checksum/out0.log.match
@@ -0,0 +1,1582 @@
+checksum/TEST0: START: checksum
+ ./checksum$(*) ./file1 ./file2 ./file3 ./file4 ./file5
+./file1:0 0xe8f920bff5e5614
+./file1:8 0x4c94b804f80e1857
+./file1:16 0x44fa7461bd0b58fd
+./file1:24 0xfabae3e8aa1f5537
+./file1:32 0x6b95e2edf4620ff6
+./file1:40 0x59bd460bfd1151fb
+./file1:48 0x9c5e21cfbb100dfd
+./file1:56 0x3b83fc8bbb33bf38
+./file1:64 0x6c653a51a35f18f1
+./file1:72 0xcfc7ef94f7031ae9
+./file1:80 0x95d9e1164b090b39
+./file1:88 0xd2aed57ef75711f4
+./file1:96 0x7192626c060f0c45
+./file1:104 0xfea2c613b91f60fd
+./file1:112 0x9009017fb31356f2
+./file2:0 0xe8f920bff5e5614
+./file2:8 0x4c94b824f80e1858
+./file2:16 0x44fa7481bd0b58fe
+./file2:24 0xfabae408aa1f5538
+./file2:32 0x6b95e30df4620ff7
+./file2:40 0x59bd462bfd1151fc
+./file2:48 0x9c5e21efbb100dfe
+./file2:56 0x3b83fcabbb33bf39
+./file2:64 0x6c653a71a35f18f2
+./file2:72 0xcfc7efb4f7031aea
+./file2:80 0x95d9e1364b090b3a
+./file2:88 0xd2aed59ef75711f5
+./file2:96 0x7192628c060f0c46
+./file2:104 0xfea2c633b91f60fe
+./file2:112 0x9009019fb31356f3
+./file3:0 0xe8f930bff5e5714
+./file3:8 0x4c94b904f80e1957
+./file3:16 0x44fa7561bd0b59fd
+./file3:24 0xfabae4e8aa1f5637
+./file3:32 0x6b95e3edf46210f6
+./file3:40 0x59bd470bfd1152fb
+./file3:48 0x9c5e22cfbb100efd
+./file3:56 0x3b83fd8bbb33c038
+./file3:64 0x6c653b51a35f19f1
+./file3:72 0xcfc7f094f7031be9
+./file3:80 0x95d9e2164b090c39
+./file3:88 0xd2aed67ef75712f4
+./file3:96 0x7192636c060f0d45
+./file3:104 0xfea2c713b91f61fd
+./file3:112 0x9009027fb31357f2
+./file4:0 0x2561ad3cf87a50ce
+./file4:8 0x8edb19ce24a063e0
+./file4:16 0x7f1970877964c0af
+./file4:24 0x54e98c05652d0546
+./file4:32 0x575e710add2ba5c
+./file4:40 0x9650a602f50c7dfa
+./file4:48 0xc172efa8a33676f4
+./file4:56 0xabc0022b1ea13cd2
+./file4:64 0x4848cfbb59b955cb
+./file4:72 0xd931ee5fc956cb8e
+./file4:80 0xa4d7779d5bb7eb42
+./file4:88 0xd0529e5aa11956a6
+./file4:96 0xf6f9d075125a6c5d
+./file4:104 0x4c34f03ea0de829b
+./file4:112 0x4779f4055c85f790
+./file4:120 0x61c0edaa55b1ab3e
+./file4:128 0x560eeb74cc447437
+./file4:136 0xc3ebd96f43342752
+./file4:144 0x373008b2bd3c45fd
+./file4:152 0xf150801f877746c4
+./file4:160 0x26baeadd2dfc143b
+./file4:168 0x324bf9758f9d0f88
+./file4:176 0x9167168029b30a43
+./file4:184 0x38c559629a484230
+./file4:192 0x31d7c7fe1c49de57
+./file4:200 0xa8e9ed8b4e62440f
+./file4:208 0xcfdc63aeb9e5e1c1
+./file4:216 0xadc43abf0dc765bc
+./file4:224 0x5ad799b39539a4d0
+./file4:232 0x38a77e3e9d4e5714
+./file4:240 0x80c276769d7652aa
+./file4:248 0xd49554961c120fa0
+./file4:256 0x97b845201a38588b
+./file4:264 0xbc9840a145f96ec2
+./file4:272 0x3d859068ca328a35
+./file4:280 0x834ae784ceeb684b
+./file4:288 0xe0b0eadd2d00bbfa
+./file4:296 0x776492824c0bc45a
+./file4:304 0xe8a232bdce16222e
+./file4:312 0xadc10a6b6f1fff56
+./file4:320 0x6393d4d7076e264d
+./file4:328 0x2826a70eaf2d172e
+./file4:336 0xfe05c4481cdba323
+./file4:344 0xfdf1e3f8b29074f1
+./file4:352 0xa80e16be305affed
+./file4:360 0xb0c0a95ff763fd99
+./file4:368 0x3015d880e53de748
+./file4:376 0x5fff3fd9cb1c7b5a
+./file4:384 0xb0576a16c695e2f5
+./file4:392 0x51ae125168e7d448
+./file4:400 0x319ce8f3cc06a03e
+./file4:408 0x1f87f7ec1ed57107
+./file4:416 0x5ff31ea32c67fe70
+./file4:424 0x475827e8530e2aff
+./file4:432 0x80c4213292402e1
+./file4:440 0xdbb6a2a0adb1eab2
+./file4:448 0x28c2e3dd95b73d90
+./file4:456 0x2d50afeaabc5095a
+./file4:464 0xbd99f80597995f74
+./file4:472 0xd29f167b0230b28
+./file4:480 0xe42c835e9fc09418
+./file4:488 0xeac82037973b218b
+./file4:496 0xb58957a39b3c85c9
+./file4:504 0xb415a67034c7a40f
+./file4:512 0xeb0a7ec1334d926f
+./file4:520 0xe8df60a8d80c1e39
+./file4:528 0xe217276915bfa72b
+./file4:536 0xe15a06fd6a92d663
+./file4:544 0x8e68a547d6dea130
+./file4:552 0x8750422e14292697
+./file4:560 0xa243063069d0eb1f
+./file4:568 0x3f18d75b0f9752dd
+./file4:576 0x12c1e976c9ec5b54
+./file4:584 0x28e8c165b20320ae
+./file4:592 0x4ee0a609ce81a14c
+./file4:600 0xc1f567b752e7be82
+./file4:608 0x7f1fe9676b06f67e
+./file4:616 0xa5cfd147695aea6b
+./file4:624 0x1882a45cd9c643cc
+./file4:632 0x36e7a7d8545c4f89
+./file4:640 0x4f00168b9f990d9
+./file4:648 0xfd1bde0b92eb6830
+./file4:656 0x5a3fb5fe14efa63c
+./file4:664 0x98b2f1b5c668329a
+./file4:672 0xd43c4804401c4613
+./file4:680 0xd10d3bc5c8a29915
+./file4:688 0x663abf2c448150cc
+./file4:696 0xa9430b288a3735b4
+./file4:704 0x6c7a3481518a6e5c
+./file4:712 0x86845fdbeadd1dd
+./file4:720 0x80bef6c3f1fe150f
+./file4:728 0x5887a47b5da2eb01
+./file4:736 0x28b62145423358f9
+./file4:744 0xbeebb4a6799c7fb5
+./file4:752 0x3d5e80d41856f517
+./file4:760 0x172748b51323a265
+./file4:768 0xe095b813ebe9261e
+./file4:776 0xd185b0038c0ad9f0
+./file4:784 0x90e7376078599618
+./file4:792 0xf052469a1b537650
+./file4:800 0x166f7ead4d96e48a
+./file4:808 0xcd1a417a44c59d81
+./file4:816 0x184f0382d0420bd8
+./file4:824 0x8bb915d1c2361703
+./file4:832 0x5bd3f67159c8ecd1
+./file4:840 0xb618cd51dd184098
+./file4:848 0x6fd183a8eda46d2c
+./file4:856 0x632b5698e7e6799c
+./file4:864 0x520c652d39f70dfd
+./file4:872 0x64504ac8cc6a8517
+./file4:880 0xed2e03dc8e51528c
+./file4:888 0x6a3cb8310a6dc600
+./file4:896 0xaa748e669f9489bd
+./file4:904 0xb9f3630ccb519542
+./file4:912 0x6f32638d94ab9220
+./file4:920 0xb1e8708350787ef
+./file4:928 0x9fe3c7d8d406a1a2
+./file4:936 0x8250a20fb0e6f10a
+./file4:944 0x2a7fb2d89b04f6bc
+./file4:952 0x605bfa2d8a035a79
+./file4:960 0x731a05f5f6e29da6
+./file4:968 0xf4f07c378bedf96
+./file4:976 0xc2b65810208c8c33
+./file4:984 0x3e815a4cc7b46e10
+./file4:992 0xbc91513fe81f58e0
+./file4:1000 0xd03eac3eb276e020
+./file4:1008 0x32454164d84a6112
+./file4:1016 0xfc45cd5d805b7727
+./file4:1024 0x653fc959cd0e5c6d
+./file4:1032 0xe47c7b39ece7b70c
+./file4:1040 0xda311bd25e59576f
+./file4:1048 0x1602c539ba0ce49c
+./file4:1056 0xeabad19f49b6e723
+./file4:1064 0xaea55636b2736368
+./file4:1072 0xb026532f1d034c4c
+./file4:1080 0x5b9684541e8b9ba0
+./file4:1088 0x9b9f4d94053da74b
+./file4:1096 0xb649bded4d811866
+./file4:1104 0xd6a47a4ce461b5fd
+./file4:1112 0x38c6b45f94e66e20
+./file4:1120 0xc55f44f9469be49a
+./file4:1128 0xb5ab46b0dffce05a
+./file4:1136 0x3a8a83e0acdf7465
+./file4:1144 0x52065d529926e9d8
+./file4:1152 0xe44f8538ae630def
+./file4:1160 0x4a6851abf3ac1ef3
+./file4:1168 0x1cf9fac709fcfd9b
+./file4:1176 0x179ffbfd295f744e
+./file4:1184 0x2bf44768040cfd80
+./file4:1192 0x7d05d1946a55ba9d
+./file4:1200 0xeca9727a2886a8a
+./file4:1208 0xdb8ce1cdf8ded080
+./file4:1216 0x7ac7236b250ce8c4
+./file4:1224 0xbd759832273cff1c
+./file4:1232 0x8b4c6e899a33a7df
+./file4:1240 0x18daa9852d978408
+./file4:1248 0x7567948a7d72a06a
+./file4:1256 0xcf5b54534519faa0
+./file4:1264 0xd8e4a617bdfced6f
+./file4:1272 0x174827be07babf8d
+./file4:1280 0x79ed16baf1cc57ba
+./file4:1288 0x2d65f648be7b2a0e
+./file4:1296 0x33d210dd29ad1380
+./file4:1304 0xe2efa49375cb7bf5
+./file4:1312 0x898af3cfe98ed89d
+./file4:1320 0x658c7de6b53fe839
+./file4:1328 0xa43973f179032876
+./file4:1336 0x3d196ec7bd8916a1
+./file4:1344 0x8707718bd35c8479
+./file4:1352 0x1d9e46167d62d783
+./file4:1360 0xfc854e74d8bbbd03
+./file4:1368 0x77526e84a397a2b0
+./file4:1376 0xb73612f24240f791
+./file4:1384 0x7e498274f63e7678
+./file4:1392 0x15a74a9447da3b8b
+./file4:1400 0x88d176f4452f7dc8
+./file4:1408 0x7acb712582f70295
+./file4:1416 0x5edacd41c3f22c1b
+./file4:1424 0xd5371b0c28b39c6c
+./file4:1432 0xc952316c52a3ca33
+./file4:1440 0xadc8cf4282f1e0cb
+./file4:1448 0x3f382e98bbc08179
+./file4:1456 0x2f138d53da1467bd
+./file4:1464 0xc0df1218ecb52481
+./file4:1472 0x85368a7b77b383e1
+./file4:1480 0x4495014398c85ac7
+./file4:1488 0xd9540524a566057c
+./file4:1496 0xa925b940688c2506
+./file4:1504 0x93b08cfe6889910b
+./file4:1512 0xf778decebb55d40a
+./file4:1520 0xb167d8b46347372a
+./file4:1528 0xf18f08c437be523d
+./file4:1536 0x840d88edb5842f5b
+./file4:1544 0x65eeaf6e74142720
+./file4:1552 0xa450713698f4f658
+./file4:1560 0x2fc45d42521e64ec
+./file4:1568 0x6ed7e574c06e507f
+./file4:1576 0x5ed7b4c749c7c124
+./file4:1584 0x59eb47945351218f
+./file4:1592 0x6ebec54db928d838
+./file4:1600 0x354409aacd6dd46
+./file4:1608 0x1799795d193ad873
+./file4:1616 0x9aada3e436ed20d9
+./file4:1624 0xfc63ff8e0bc05ab3
+./file4:1632 0x4b6852084df285d3
+./file4:1640 0xcf4563c8cdfdd1d1
+./file4:1648 0x3ac5bb2799c4680c
+./file4:1656 0xfd8a870e4cf41382
+./file4:1664 0x2eb295f902ca87f2
+./file4:1672 0x336d1901eac6e181
+./file4:1680 0x98b8d710054e2787
+./file4:1688 0x72a0ad0262e3340
+./file4:1696 0x35732d36b1861725
+./file4:1704 0x9d53c44898b83116
+./file4:1712 0x5f022d2b356d5a60
+./file4:1720 0xb42298f15953856a
+./file4:1728 0xc9f6e20365b32c37
+./file4:1736 0x2c16ae69b54a2ff5
+./file4:1744 0x633d22bef1f3ef86
+./file4:1752 0xb0c54b0fcd968b15
+./file4:1760 0x6a1a035893bc1c
+./file4:1768 0xa1ce6f501f9b2117
+./file4:1776 0xebe7e253e7ba3dd6
+./file4:1784 0x8c15a12ce0506109
+./file4:1792 0x2e3dcad1597d1234
+./file4:1800 0x484b632b13b6692b
+./file4:1808 0xe25fb1021fba0f3f
+./file4:1816 0x928c49ddb60f470e
+./file4:1824 0xc57633f286018f2e
+./file4:1832 0x38ccbe5d518110ae
+./file4:1840 0x95495188afe975aa
+./file4:1848 0x207f8e222e8641da
+./file4:1856 0xf96fa24cafac1962
+./file4:1864 0xbc2d6723a98840e6
+./file4:1872 0x10d8d488380c2ff4
+./file4:1880 0x44b63aae94e4d7cc
+./file4:1888 0xae5265b76d02a36c
+./file4:1896 0xed4c7e03108e92c
+./file4:1904 0xe815d0a62722e72d
+./file4:1912 0xbd8c6d1adb20fd95
+./file4:1920 0x8df0adb258085599
+./file4:1928 0x88a50a33666f064
+./file4:1936 0xc7d24fe026d8120a
+./file4:1944 0x553523aa95c762d
+./file4:1952 0x54bc3ed67964ab5a
+./file4:1960 0x4463ec1c2c660997
+./file4:1968 0xfa1f1a15510a48b2
+./file4:1976 0x687c991acfa5fc0e
+./file4:1984 0x4bab0d8c1f67d512
+./file4:1992 0x49b29cf0af23a2f0
+./file4:2000 0xd100f0f5089e5814
+./file4:2008 0x5fb60d2474aa95
+./file4:2016 0x1a67f652585c4280
+./file4:2024 0xde0a3fd51e115520
+./file4:2032 0xcaec44329ecb5cfa
+./file4:2040 0x59e9f108d49bae9
+./file4:2048 0xc8e244272224742e
+./file4:2056 0xa83d585bae11b02b
+./file4:2064 0x73af688d27bf0178
+./file4:2072 0xe576d1afeed3d5b0
+./file4:2080 0xf766a5aac5d6d335
+./file4:2088 0x6b487383aaf517e4
+./file4:2096 0x4bd08725a0723b33
+./file4:2104 0x3573c97227b01d54
+./file4:2112 0xe69b7672e86ada5b
+./file4:2120 0x938eea56f73381b7
+./file4:2128 0x2f74d5afc2994d7
+./file4:2136 0xbf2738c3825ebedf
+./file4:2144 0x685d74314b9a87ae
+./file4:2152 0x30fe4dba8f1396fb
+./file4:2160 0x15c261ae3a46bd9c
+./file4:2168 0xe41e7dfb25fa9991
+./file4:2176 0xa5ba578848cc6115
+./file4:2184 0x1e461d940ae8f517
+./file4:2192 0xd78c5bc8c802e07e
+./file4:2200 0x8f31ab99cd20830a
+./file4:2208 0x2de0355d47b155c9
+./file4:2216 0x1d989049090eaa6c
+./file4:2224 0x68b34686109a88ac
+./file4:2232 0x69ab35a7d6ec226d
+./file4:2240 0x9a424c7777eb130e
+./file4:2248 0x40ffec491621ee12
+./file4:2256 0x1025f738c0607631
+./file4:2264 0x11056c64bb12272
+./file4:2272 0x83dc086f38992422
+./file4:2280 0x1ad8ff6c0b0ff8b4
+./file4:2288 0x11372c8ed8665ae1
+./file4:2296 0xa6843c5580e948a8
+./file4:2304 0xd208737130f70fc6
+./file4:2312 0x98163e9fb4f438bd
+./file4:2320 0x628d7ef832a8fda9
+./file4:2328 0x7f4e20b22e21ee0d
+./file4:2336 0xcb0d239f530edd29
+./file4:2344 0xda778e8795e9ca7e
+./file4:2352 0x23e1d506e26c9bdb
+./file4:2360 0x64c12ad96f0e3acf
+./file4:2368 0x62cc3de62ee86f12
+./file4:2376 0xb455ab747c601400
+./file4:2384 0xa5630a8be8be0f7
+./file4:2392 0xd173f2b1c04ee85d
+./file4:2400 0xec88927dd4d00499
+./file4:2408 0xe87d8b589316107f
+./file4:2416 0xf55e1a011966dea7
+./file4:2424 0x4b52f729ac167355
+./file4:2432 0xd8e1a73bfab5ad81
+./file4:2440 0x5a4c39ae0e3e576e
+./file4:2448 0x5b44609fdcbdeb30
+./file4:2456 0xf71846c557012893
+./file4:2464 0xdd92b34e6d2751ef
+./file4:2472 0xcfa76fa58823440f
+./file4:2480 0x5ec337ee82726987
+./file4:2488 0xf3b4e7fc0af51b7
+./file4:2496 0xa156bd02654d5a4f
+./file4:2504 0x5955299e6d0cb4af
+./file4:2512 0x9dd741e4ba67e5d1
+./file4:2520 0xb89f994fd5d515a0
+./file4:2528 0x39a61c066b50bca1
+./file4:2536 0x204d9711c09d4e9
+./file4:2544 0xa41df6dd1cdab0ea
+./file4:2552 0xb73dc0cde3fa4411
+./file4:2560 0xdfcf3f71b76265c6
+./file4:2568 0x5eaf16449362f2f9
+./file4:2576 0x70ee3610912d4f10
+./file4:2584 0x334114ba3029ef31
+./file4:2592 0x54f200ca129f201c
+./file4:2600 0xf3ea66d3212dc231
+./file4:2608 0x939231850cad1d52
+./file4:2616 0x66d7ce6e4dd3e613
+./file4:2624 0xe8baa57cf3a959e
+./file4:2632 0xc4a0671351701e6f
+./file4:2640 0x8a6b86749302c4fa
+./file4:2648 0xe872bb845019a349
+./file4:2656 0xd91c3bd299eb6e0b
+./file4:2664 0x749ad075193d3650
+./file4:2672 0xc82e7fff7492098
+./file4:2680 0x6a12bdbe67bc5867
+./file4:2688 0x4a66bf6197f2651a
+./file4:2696 0x48c1a03214a23c2d
+./file4:2704 0xef30baf23ab12816
+./file4:2712 0x8526ebedf30f6524
+./file4:2720 0x273579806915f52
+./file4:2728 0xf3ad8aca36f053eb
+./file4:2736 0x58eb5cc576af690
+./file4:2744 0x5f2aa6ff9c57f194
+./file4:2752 0xe3b6ae284a50b2d4
+./file4:2760 0xe1838b83d3aed8c5
+./file4:2768 0x548c6e7026d017c1
+./file4:2776 0x975639db4c483b5d
+./file4:2784 0xc56f8849687b2c0e
+./file4:2792 0xed33269a623bed5a
+./file4:2800 0x216587ca7ce0664d
+./file4:2808 0xc9e71ce50cfc6f3c
+./file4:2816 0xcff97d78109f6376
+./file4:2824 0xd3f756ec1497194c
+./file4:2832 0x1701ea2fe911f4d9
+./file4:2840 0x74d18b1c0439d813
+./file4:2848 0xfca8a710c286d6da
+./file4:2856 0x9a07a57ddb70f932
+./file4:2864 0xa4a0c51fd2438d11
+./file4:2872 0xef857b94339999da
+./file4:2880 0x5c012d54d5f01fde
+./file4:2888 0x817671d641916027
+./file4:2896 0x7207b54241a4c55c
+./file4:2904 0x256505ecde0a042e
+./file4:2912 0x3756ae337c9139b5
+./file4:2920 0x77a137c1d145693f
+./file4:2928 0x4c3790307036ebcf
+./file4:2936 0x3ef92e07bb00cd20
+./file4:2944 0x9e39d5d0d8d14f2a
+./file4:2952 0x26931030f32d4d3b
+./file4:2960 0x8fa4fb819a972a78
+./file4:2968 0x9e6ae96ce56706e5
+./file4:2976 0xe5b647d182d3934a
+./file4:2984 0x7ba80ec14bf23992
+./file4:2992 0x702e0f360a9ecf8c
+./file4:3000 0x28af93eaa48e5bf8
+./file4:3008 0x9cd95c87f6bd90d6
+./file4:3016 0xcc119668de2ecb4c
+./file4:3024 0x6d40530d498ae768
+./file4:3032 0x9462d2796c4e7729
+./file4:3040 0xc20bfea2ce6ba994
+./file4:3048 0x8a820d72e8200ec4
+./file4:3056 0xe176b4089fdbfdd8
+./file4:3064 0xd888cab9123ce3f0
+./file4:3072 0xaf353679d065fd8c
+./file4:3080 0x5cb35856f4e78c74
+./file4:3088 0xec3754d7f272b470
+./file4:3096 0x9f49e0fbbb4ab151
+./file4:3104 0x2f46497ad9098bc5
+./file4:3112 0xc4c903bd8a467670
+./file4:3120 0x81c370c2c7e69b5d
+./file4:3128 0xa7bec1ef355a6567
+./file4:3136 0x64f9889ee6ad47e1
+./file4:3144 0x9f394b647ac98d88
+./file4:3152 0x6717be501d11d713
+./file4:3160 0xf52de0c01a2bf5b4
+./file4:3168 0x77cc9a5b7e0d56e1
+./file4:3176 0x2a2fb006ebf5f8cf
+./file4:3184 0xd31b24ea4d68ed53
+./file4:3192 0xfbedc6a320810f2e
+./file4:3200 0xa65634d272487fb2
+./file4:3208 0xe00700998211e3a7
+./file4:3216 0x7d151d8e89da5610
+./file4:3224 0x2204a5cfb2106e40
+./file4:3232 0x4ef3c0c005ef96d6
+./file4:3240 0xf8f14b853932f93
+./file4:3248 0xeabea58efa57a5e7
+./file4:3256 0x407c91b1a0904c19
+./file4:3264 0x1419a70e60674c6a
+./file4:3272 0x7ed48febb72004ef
+./file4:3280 0x71c44d3ec01cb706
+./file4:3288 0x3c8c7bcfca0f38ab
+./file4:3296 0x7f033faf7d789429
+./file4:3304 0x57899e656023a177
+./file4:3312 0xe18a69a1781cac84
+./file4:3320 0x3e4849f59a69c51c
+./file4:3328 0x8d7f238f0a46df62
+./file4:3336 0x626a30165eba869d
+./file4:3344 0x2d2c8aa245591841
+./file4:3352 0x789324faacd60043
+./file4:3360 0xbfcada1ca647c47
+./file4:3368 0xae707fe874b1f1e
+./file4:3376 0xe62381f797b8271e
+./file4:3384 0xf36e7165c324d560
+./file4:3392 0xcc8691113e694c77
+./file4:3400 0x9235282a5e00bae4
+./file4:3408 0xa95ca398487c2c33
+./file4:3416 0x16e735030ce3ade4
+./file4:3424 0x85d33080d84476ba
+./file4:3432 0xed039be2e0315eaa
+./file4:3440 0x32e6e3f23331f778
+./file4:3448 0x2fa694bfbb96c862
+./file4:3456 0x77e591839e21f6c8
+./file4:3464 0xdc6e98e37c2c9dad
+./file4:3472 0x8bc8636979ad1e2b
+./file4:3480 0xe904e6cd6836d141
+./file4:3488 0xc19d5153c7331c40
+./file4:3496 0x2971ba9de45e4ae7
+./file4:3504 0x423bba68818c73b6
+./file4:3512 0x98011ed03c826f64
+./file4:3520 0x5b6a802b7b1caeb6
+./file4:3528 0x672236e6c58d9e2
+./file4:3536 0x8e7eedae30e3fdf9
+./file4:3544 0xc4076e5cba0eebbb
+./file4:3552 0xb918429db58f1156
+./file4:3560 0x418e04ac97d7b385
+./file4:3568 0x80ff2d732ea8294e
+./file4:3576 0x66f0f566128afd0
+./file4:3584 0xbf1863ad435bd0fc
+./file4:3592 0x114ed2834d90e780
+./file4:3600 0x9b7a309c8c9493ec
+./file4:3608 0x69dca39efa8d84fd
+./file4:3616 0x55f12613443b5c32
+./file4:3624 0xbedd50c4de0607a
+./file4:3632 0x9d020d58d61a3d85
+./file4:3640 0xb8f24704bbb4485f
+./file4:3648 0x5581075080078215
+./file4:3656 0x4e1d30158ef16570
+./file4:3664 0xb86e1c5ed4468513
+./file4:3672 0x2277230da6134fc5
+./file4:3680 0xde28cafdf91693d0
+./file4:3688 0xa871cc8b7631a18d
+./file4:3696 0xbbd31a3b9967a562
+./file4:3704 0x90f44722dc137d65
+./file4:3712 0xfdb5bf16499c300c
+./file4:3720 0x70caf67fa9145fa7
+./file4:3728 0x848f632f82c75a02
+./file4:3736 0xef3e815b760c1ba
+./file4:3744 0x3a158ec30574c6ce
+./file4:3752 0x4eadc505497d419f
+./file4:3760 0x6f1bdda85db3865b
+./file4:3768 0x1309b624a0ef93b9
+./file4:3776 0x77e3551ea4277635
+./file4:3784 0xca478ce26e0ec677
+./file4:3792 0xafbd4b4842c8c2ce
+./file4:3800 0xe45c2c76b2c9cd64
+./file4:3808 0xef01896d693c2cfc
+./file4:3816 0x524a2faef87c3dda
+./file4:3824 0x526e758f2460900b
+./file4:3832 0x8b685afbc02d10f6
+./file4:3840 0xa577aaa5509a3ea8
+./file4:3848 0x9509db27663a3977
+./file4:3856 0x9b1482295be011ec
+./file4:3864 0x46a837a9e2d80d07
+./file4:3872 0x23395cbc4d527120
+./file4:3880 0x9a141da17afd0c81
+./file4:3888 0x869b9c91897e0ffb
+./file4:3896 0x7b44b4874f1601d0
+./file4:3904 0xba53b10e526b9a6e
+./file4:3912 0xe4e3bc3273c162d1
+./file4:3920 0xc6b983f2c0d10ef9
+./file4:3928 0x34c85743c980ee51
+./file4:3936 0x79b5ec4e95326a15
+./file4:3944 0x72409df55806ae44
+./file4:3952 0x68ca9c3506531f76
+./file4:3960 0x8c7fef5f347d0d1e
+./file4:3968 0xc90bb738a136e41
+./file4:3976 0x903051c3baeca817
+./file4:3984 0xec316f76c269409b
+./file4:3992 0x1808c782c7fa2cf5
+./file4:4000 0xd7ad09c63858a06a
+./file4:4008 0xef246ed72a68cc05
+./file4:4016 0x6cfd8aeee337df6f
+./file4:4024 0x6e1d17b297c97200
+./file4:4032 0xcb983fd775f0a790
+./file4:4040 0x9bada27956e652b9
+./file4:4048 0xa00f0b8d6fc97014
+./file4:4056 0x2e074b618bc71877
+./file4:4064 0xf9241400c6f8e0c0
+./file4:4072 0xae27a55e0b7eee50
+./file4:4080 0xdbccac4364d30d28
+./file5:0 0x699e38778f3ef3ba
+./file5:8 0xf059add994b795bb
+./file5:16 0x5d660f6fcbf7a8c9
+./file5:24 0xe3bf0d5eab830623
+./file5:32 0x6762e4ddd8db9d61
+./file5:40 0xc166cd61691ef20
+./file5:48 0xc48517402e71a5e1
+./file5:56 0x468cbee9a7bf165b
+./file5:64 0x5c0ec6cdd770e86b
+./file5:72 0x80709502787617cf
+./file5:80 0xa277dbe7fd1273f0
+./file5:88 0x533756395aa7c8a7
+./file5:96 0x745917c2c62e072f
+./file5:104 0x95e6798e4ecdd92c
+./file5:112 0x285d19051a690a83
+./file5:120 0xbe9b0baff26734d7
+./file5:128 0x290336b5ef28cf9c
+./file5:136 0x5193b5ab80dc0e19
+./file5:144 0xbce1b986b22e39d9
+./file5:152 0x3c3b324553a0b80a
+./file5:160 0xbebc9ec7b7e4b53a
+./file5:168 0x84164052759e1835
+./file5:176 0xb3bc4901b2c3d32d
+./file5:184 0x388c555111c50b07
+./file5:192 0x1baad97ff05fb0ce
+./file5:200 0x9f1577dea1702611
+./file5:208 0x42ebb3b29e5c4573
+./file5:216 0xa0f54848f74fde5d
+./file5:224 0x3c045e5ebdba553a
+./file5:232 0x5fef4d4abce8e312
+./file5:240 0xd2d33241e4fe483b
+./file5:248 0x4631568659dca419
+./file5:256 0x8a4fe6d521c42d4f
+./file5:264 0xa46210c35d2e6fc8
+./file5:272 0x86d84b21e320fb31
+./file5:280 0xa93cc8f6354fb4be
+./file5:288 0x73ebf38e6a41911a
+./file5:296 0x9a9de51f9f29f9a4
+./file5:304 0x7bf4041b5e89a711
+./file5:312 0x3ec169d6d935771b
+./file5:320 0x8e6e1d4a08805d6d
+./file5:328 0x360dd8cd50184e70
+./file5:336 0x3ab4e9421244e4db
+./file5:344 0xd229d58ce714a8a0
+./file5:352 0x71f72d56dad342c0
+./file5:360 0xf608748aed95d219
+./file5:368 0xf5f53c1d7c04698c
+./file5:376 0x7db60764955b1443
+./file5:384 0x4b1985bf2786017b
+./file5:392 0x912bd9c3ead3f31c
+./file5:400 0x5c2ddf875afcf064
+./file5:408 0xcda540c6c5b1a283
+./file5:416 0xc62e4859afa5e2c
+./file5:424 0xf4c348522efad2de
+./file5:432 0x59c4354945c4e744
+./file5:440 0xf2dc8915bd97e1a8
+./file5:448 0x3992db927d218861
+./file5:456 0xb730204e6d115898
+./file5:464 0xe39695eb9e06309
+./file5:472 0x4748d76b9c37489e
+./file5:480 0x1e4e23f97723d683
+./file5:488 0xe564f5e9ebdf6beb
+./file5:496 0x411cc15b1812ac53
+./file5:504 0xfc86b704fd9d9497
+./file5:512 0xe7e86f4445b99697
+./file5:520 0xd613a855020a1bd9
+./file5:528 0x124de973f03f087f
+./file5:536 0x2d38fdd6d5b387b0
+./file5:544 0xa88ff12ea4abb0b8
+./file5:552 0xcd18adfadd0dd6e8
+./file5:560 0xc6a7bae97f197d57
+./file5:568 0x66fcb7926a6fb0cf
+./file5:576 0x7f9e8691e6852c4e
+./file5:584 0x6ce3f230f10c993a
+./file5:592 0x2d94705667834d5b
+./file5:600 0x5c98ffab74d63592
+./file5:608 0x8e919d0daf50f530
+./file5:616 0x7c9312b1ee9ffbc9
+./file5:624 0xe6ec6076be8f38a8
+./file5:632 0x5d22cefb87a8f364
+./file5:640 0xe508fbcc2a2b130d
+./file5:648 0x54727149baa4a3c0
+./file5:656 0xd8247802dbe86912
+./file5:664 0x2d49dab1d2eb4c9c
+./file5:672 0xc16baea2fb9a925a
+./file5:680 0x8db68762ec33d948
+./file5:688 0xb331c64b4c6e81f0
+./file5:696 0xa29988fba06f8992
+./file5:704 0x6f95693fa919c4c8
+./file5:712 0x511b77ad8c450d1c
+./file5:720 0xe174ed2eff5c07e6
+./file5:728 0xb6fcc990b3e79b19
+./file5:736 0xf2ab711f7ee43ec1
+./file5:744 0xb8cd0d8d0ab7c306
+./file5:752 0x7a749195e925c912
+./file5:760 0xb4b6cffbe32c0f2c
+./file5:768 0x265934aabda98500
+./file5:776 0x17d1cd19b4e33b6c
+./file5:784 0x5cd8709a67702b2
+./file5:792 0x668e136615f588a9
+./file5:800 0xd9772f6fc9ce857
+./file5:808 0xbc16100958613427
+./file5:816 0xbcbf11a59b6dc902
+./file5:824 0xc4d639ba80a315d8
+./file5:832 0x168d1587e3452e9c
+./file5:840 0x1704147fe224a174
+./file5:848 0x2b17cee262f0db4d
+./file5:856 0xb23a0db0f7ec2975
+./file5:864 0xa6ae815602a88df8
+./file5:872 0xcb20a65512c541a5
+./file5:880 0x15e67b7a96873f3b
+./file5:888 0xb499043af2fa4df0
+./file5:896 0x75076dd3f6262a96
+./file5:904 0x5feef6870dd1a94d
+./file5:912 0x28501fff0b82aa25
+./file5:920 0x52fcacdca39f3e0b
+./file5:928 0x8dd5e673bb867db5
+./file5:936 0xd1a0a409286aacdc
+./file5:944 0xb9a1f62e0d147ae3
+./file5:952 0x3c64474307a752e3
+./file5:960 0xc39953e5d39de643
+./file5:968 0xcc892a98b36fa13f
+./file5:976 0x84cd8208f3171e63
+./file5:984 0x4d6bbd25777ee73c
+./file5:992 0x60112f7ea8f3380f
+./file5:1000 0xe41dcbcb158faf36
+./file5:1008 0xa2d22d2515c6f9ac
+./file5:1016 0x70557529d94cd79
+./file5:1024 0xa9f771c31be4bfca
+./file5:1032 0xe13f6cf3f7c1387e
+./file5:1040 0x4a3dcee1a78ba6b8
+./file5:1048 0xcad6abecca0982b4
+./file5:1056 0xd28581e24ca866bd
+./file5:1064 0x2569941c281c9a34
+./file5:1072 0xe99c4b798c69cb74
+./file5:1080 0x3feefaee327fc875
+./file5:1088 0x7ff1ffb82373d071
+./file5:1096 0x630dddc7eb95bf3c
+./file5:1104 0x3eaef151dc64c91d
+./file5:1112 0xf935708c263b4c98
+./file5:1120 0xa4b52da5d604ba83
+./file5:1128 0x1956bf7ca228eccc
+./file5:1136 0xfa6ee1863e06069f
+./file5:1144 0xfcbd8025d5825010
+./file5:1152 0xf70fc0ffdfedc069
+./file5:1160 0xd08948a486d6619d
+./file5:1168 0x8c5e340f27eb85f
+./file5:1176 0x4aa8688df8d4231e
+./file5:1184 0x884622a52f98b3c1
+./file5:1192 0xd3422895caad095a
+./file5:1200 0x4c9a8bf6ec447db0
+./file5:1208 0xbbf83ecfb9156fc5
+./file5:1216 0xe585bef252f8cadd
+./file5:1224 0x55025e954db65e86
+./file5:1232 0xde23f060bb1f0dfc
+./file5:1240 0xda16c98d8a5f1786
+./file5:1248 0x6cad83eacd74392a
+./file5:1256 0x8d4e3869c96b8f2c
+./file5:1264 0x6905ed6af73757cc
+./file5:1272 0x74a6235d2ccfc4f2
+./file5:1280 0xc51d533186785c71
+./file5:1288 0xbf469dc9aad28268
+./file5:1296 0xc52b23fabc4ab4ab
+./file5:1304 0xf9c6a158fe740a7f
+./file5:1312 0xb06db9fc162f6623
+./file5:1320 0x88c4d07699c8404d
+./file5:1328 0x486d760c690b656b
+./file5:1336 0x143452846ed16152
+./file5:1344 0x72ea0cd2ab4e863
+./file5:1352 0x5e1a3081fe583e9e
+./file5:1360 0x2d34f4a0674c6175
+./file5:1368 0x17671f8c00bd4ee5
+./file5:1376 0x3b440d2032b8612c
+./file5:1384 0xa86706193d6a4bc1
+./file5:1392 0x1ba4f5238a2a1492
+./file5:1400 0x299836d6b024fda5
+./file5:1408 0xdbd58668635f5339
+./file5:1416 0xed6c6d3bfd30409
+./file5:1424 0x966d049da01fed27
+./file5:1432 0xbbcd16c15d4987b9
+./file5:1440 0xa7ae6cc592f2aee3
+./file5:1448 0x5a9450f273870e38
+./file5:1456 0x59b0f75b22fa4ebb
+./file5:1464 0x38cac5e38fee8039
+./file5:1472 0xdb93c54b760d4303
+./file5:1480 0x4d31e5b4703ad043
+./file5:1488 0x2401e9c24838a0fa
+./file5:1496 0xad3030cb3998a436
+./file5:1504 0x826d05b47dc2c48
+./file5:1512 0x99112c0efd3a780b
+./file5:1520 0x26e8a70760a5551c
+./file5:1528 0xa515948d490aaf5
+./file5:1536 0x72ca477024ec8f4c
+./file5:1544 0xcf1236679c1fbf35
+./file5:1552 0x98c71fdbc63570d2
+./file5:1560 0xfce57878eb41dd04
+./file5:1568 0x9d95d2d0b5f4bbd9
+./file5:1576 0xdc62871e3acc2cce
+./file5:1584 0x2741c7ff4d6df954
+./file5:1592 0xae42314a9f059404
+./file5:1600 0x942b600fbf7c142f
+./file5:1608 0xd87fc76db5ef9fc9
+./file5:1616 0xf413ddee1bf31f75
+./file5:1624 0xc8ccc1215e71322d
+./file5:1632 0x6e51651e608dea03
+./file5:1640 0xaf4e2aeb24735803
+./file5:1648 0x23aa19e21c5b1eca
+./file5:1656 0x1edcdfc75878bd8e
+./file5:1664 0xe24e932930e488c
+./file5:1672 0x29c57a30ce08c6b5
+./file5:1680 0x4a66957e32c22726
+./file5:1688 0xc01a2f94a0e1d12d
+./file5:1696 0x193967879dadec8c
+./file5:1704 0xae174ab28fd5b7fc
+./file5:1712 0x63b944fa056dce75
+./file5:1720 0xac0580bf7074763
+./file5:1728 0x9dd1790bddc4639b
+./file5:1736 0x37b0b210051e579d
+./file5:1744 0x9a59415bb5c76826
+./file5:1752 0xc1678c37469180c9
+./file5:1760 0x489709125e1e81d4
+./file5:1768 0xdc699f5f0193c43
+./file5:1776 0x423b799009d651d
+./file5:1784 0x5389e5295f61d333
+./file5:1792 0xc463c4ba6f40427c
+./file5:1800 0xc43dd1c243752d87
+./file5:1808 0x3e2872ebd67ec7b8
+./file5:1816 0x1645a49c99bd34cf
+./file5:1824 0x8c66e5994c484459
+./file5:1832 0x4aced71ac0d14d0c
+./file5:1840 0x6c131c9fa431ce92
+./file5:1848 0xb33cb58ddf2655be
+./file5:1856 0xeb15788d0147c20
+./file5:1864 0x5c72bb1600649094
+./file5:1872 0x9c0d4497d55c12e8
+./file5:1880 0xd19a9fa0ee1d8608
+./file5:1888 0x482a546c71df5002
+./file5:1896 0x27efdd3691b957f8
+./file5:1904 0xc4f7d48f0be179be
+./file5:1912 0x3a29197f8410eb67
+./file5:1920 0xee9719184807f779
+./file5:1928 0x9b0fa145c4d261d0
+./file5:1936 0x1c64d1c6e99ade31
+./file5:1944 0xc14d2388a8211b2f
+./file5:1952 0xdfb1aacd1f24b973
+./file5:1960 0xb85b970d488c4be3
+./file5:1968 0xc3f95e50174ab298
+./file5:1976 0x3f95011b2516dbd3
+./file5:1984 0xcfea911fcd424da1
+./file5:1992 0x7abcd12817683e8e
+./file5:2000 0x1ddee5f0a8d986bc
+./file5:2008 0xa16a29165766109e
+./file5:2016 0x3b158f69bd47a5e0
+./file5:2024 0xb7cee6673f28fe1
+./file5:2032 0xdc95ddd1b6f59d8a
+./file5:2040 0x2ab601ea2b692d65
+./file5:2048 0x234f0dcaf4defd1b
+./file5:2056 0x1310e1d653289424
+./file5:2064 0xe3be030ed8b16cd6
+./file5:2072 0xee178a0706f02289
+./file5:2080 0xbb4038182cd2007b
+./file5:2088 0x87bd1f669f5547e6
+./file5:2096 0xbf0a6132258aab16
+./file5:2104 0xf8da20a6c0ff902e
+./file5:2112 0x30d6b27bac5f8cec
+./file5:2120 0x476491f7d393c678
+./file5:2128 0x49e964f74fd503cd
+./file5:2136 0x23b9c22bda2f2e4f
+./file5:2144 0xd3f6b29ec70fc9d6
+./file5:2152 0xdcc7c390bbad9177
+./file5:2160 0xec2dcc51a674a38b
+./file5:2168 0x3b77dd2ce1adcccd
+./file5:2176 0xb49bfea2bcfca662
+./file5:2184 0x3cd3c516d807de0e
+./file5:2192 0x33e4c155926fbc9b
+./file5:2200 0x5e8d8181bbe5ecfb
+./file5:2208 0xb3291a5452637acf
+./file5:2216 0xd115838ba2b7c916
+./file5:2224 0x39a32260f9806265
+./file5:2232 0x3135cee466f06c7c
+./file5:2240 0xf7dd403094a272
+./file5:2248 0x7e8a8a52297afd23
+./file5:2256 0x8bff5d70691ea1fd
+./file5:2264 0x81f8942773993e60
+./file5:2272 0x8e883ff76284fdce
+./file5:2280 0xa3bdc6ea71a2e2e4
+./file5:2288 0x57d974f20e5022b2
+./file5:2296 0xa5f831dabb8e2d88
+./file5:2304 0xb6c62121b4306498
+./file5:2312 0xa3a73468c6f7c1c0
+./file5:2320 0x55f7a979da067440
+./file5:2328 0xe245257416aa57f2
+./file5:2336 0xa1f8bc61b27ea37
+./file5:2344 0xea6aa45ba2f3e0ac
+./file5:2352 0x4528f196c27fd5c1
+./file5:2360 0x53a712e134670b68
+./file5:2368 0x28f4bee119836a3a
+./file5:2376 0x7840be017d72c636
+./file5:2384 0xb7eb40831cc6419
+./file5:2392 0x192c90222e29cb6a
+./file5:2400 0xd6794d2a71b1f4bf
+./file5:2408 0x6c6550b418c0e7b4
+./file5:2416 0xf0e3a890247af748
+./file5:2424 0xebcd1aa9c9dab12a
+./file5:2432 0x38fb56ebdfa669a2
+./file5:2440 0xfa1b5d6bb618b336
+./file5:2448 0x2cd852706fb82978
+./file5:2456 0xbd00997eebc8f1b1
+./file5:2464 0x4a13bcf44112c5c4
+./file5:2472 0x32a9a8a59a6caea0
+./file5:2480 0xd07b6aa758a2df51
+./file5:2488 0x4924bd9b4545671d
+./file5:2496 0x43c4d542d21ed71d
+./file5:2504 0xfef6b7191ca4ad86
+./file5:2512 0x50e61d850886d6ef
+./file5:2520 0xb5daef44fffd5e25
+./file5:2528 0xde4eebeeb0d216bc
+./file5:2536 0x8cce38a5f836ff0d
+./file5:2544 0x4a998686125ad28a
+./file5:2552 0x965f76deabaac3b3
+./file5:2560 0x49c2db520d9c596e
+./file5:2568 0xfa8c7f8bf647ac43
+./file5:2576 0x8c384cbce5b71363
+./file5:2584 0x6ac9e6dbd677ed40
+./file5:2592 0x8da3bdbcbebcb2d7
+./file5:2600 0x8a9ab1af9afb2fc
+./file5:2608 0x14c020c6261040aa
+./file5:2616 0x4f089589ef6177f
+./file5:2624 0x76256f0585200743
+./file5:2632 0x4f2fbd4e90718c99
+./file5:2640 0x152c1a893267a690
+./file5:2648 0x373d3381649608de
+./file5:2656 0xa8d4014c8f6cb163
+./file5:2664 0x849bf2fc316cecb9
+./file5:2672 0x21b7f0bac620862d
+./file5:2680 0xb9e9983614d8e0b7
+./file5:2688 0xa62ff4a9710ce28b
+./file5:2696 0x4392fa92bc069278
+./file5:2704 0xbaee27e23de46185
+./file5:2712 0x76108e1f35d2a5ba
+./file5:2720 0x85dc7b59c213bf63
+./file5:2728 0x1dd4fc8e008a3096
+./file5:2736 0xb56286d9a523c06e
+./file5:2744 0xedaad2aafa39eb91
+./file5:2752 0xf34dd8fa9b89832
+./file5:2760 0x5b6f97131de4993f
+./file5:2768 0x39d1df4667cd703f
+./file5:2776 0x487be471445d416b
+./file5:2784 0x319ca18747dd8e93
+./file5:2792 0xadb0cdc1c5e80938
+./file5:2800 0x42cc53b288f15d2e
+./file5:2808 0xe3c7b6656ffe179
+./file5:2816 0xafe19bb8341e7844
+./file5:2824 0xbec9bc92a704086d
+./file5:2832 0x99d35a5a342835eb
+./file5:2840 0xa8cac18e23de182b
+./file5:2848 0xfd47b0870e7e011b
+./file5:2856 0xf080a6f6a0c2ce7
+./file5:2864 0x5b9548584ed7213c
+./file5:2872 0x944cdb328f617cee
+./file5:2880 0x8dc793f171e6a5d8
+./file5:2888 0x3308de98fda1a07e
+./file5:2896 0xccb1ebea2e1ccb7a
+./file5:2904 0xcb72d50c71a2421b
+./file5:2912 0x3b5895101fa18df5
+./file5:2920 0xb0c64d250e39884e
+./file5:2928 0x9170a914a728f7ac
+./file5:2936 0x3718b6c6f1db6a7d
+./file5:2944 0x416746d6df3e1359
+./file5:2952 0x2ee79568e76d9678
+./file5:2960 0xfa0586f9dd551c1c
+./file5:2968 0xb1c540642ffd0ed7
+./file5:2976 0xe079aa02ab87ef34
+./file5:2984 0x4b1a6f49b10a2cc4
+./file5:2992 0xf35ca412f5c12457
+./file5:3000 0x6ba020cab63cd028
+./file5:3008 0xa84e033020904fa2
+./file5:3016 0x7bc09486db54a9d7
+./file5:3024 0x637a763e671e6f54
+./file5:3032 0x94b935129c09395a
+./file5:3040 0x44ee9e52cf39e190
+./file5:3048 0x78d8d314238f8394
+./file5:3056 0x9bdaafd5afd7dab0
+./file5:3064 0x6d0f3dc4baa3f8b
+./file5:3072 0x58c7f79ca6b26fd6
+./file5:3080 0x2db497cb72a59b3a
+./file5:3088 0xba82aad0bd83a69b
+./file5:3096 0x83ee8c4a2a27b5f7
+./file5:3104 0x7d05509b83755e48
+./file5:3112 0x86d54d54548f0364
+./file5:3120 0x749da894837a3fa
+./file5:3128 0x310450dbe5f4015e
+./file5:3136 0x95c994a5a47a98d9
+./file5:3144 0x87325ea2185cbf50
+./file5:3152 0x629b9d1690b4bdb6
+./file5:3160 0xffdbc6c60cf3b1cd
+./file5:3168 0x6704f4ee44d8888b
+./file5:3176 0xd229447b47a2adbe
+./file5:3184 0xc85bf76da376a7f0
+./file5:3192 0xcd4829046859d60d
+./file5:3200 0x5699d6464de6581a
+./file5:3208 0x79f15f05cef68ca
+./file5:3216 0x6b0e2b25a1cff976
+./file5:3224 0x3f7df3484933749b
+./file5:3232 0x30430c3e24ac7b9c
+./file5:3240 0x910252093d0a7e01
+./file5:3248 0x524d715061a98dab
+./file5:3256 0x1ed7c6258c6c2ec9
+./file5:3264 0xe47334042ee697dc
+./file5:3272 0x8b7dc2eda4eca14
+./file5:3280 0xcecb8eac77b00cdf
+./file5:3288 0xced4a11f46561a11
+./file5:3296 0xb641ca59a2278c14
+./file5:3304 0x8d364dd8241eec6c
+./file5:3312 0x8f94973d6d9a2422
+./file5:3320 0x71a14cec067eb8b2
+./file5:3328 0x42c647824f5c1f8c
+./file5:3336 0xce0b0d1f02d7af55
+./file5:3344 0x35e1ac79f175e4cf
+./file5:3352 0x2ca5c1405df53030
+./file5:3360 0x5bc3e6b8fa2a28d6
+./file5:3368 0x4b38eabbbfe61b4c
+./file5:3376 0x2efdb930afdd89c3
+./file5:3384 0x84163e4688c72ae5
+./file5:3392 0xa17407476d5eda23
+./file5:3400 0x2da07b2bd6c0bac5
+./file5:3408 0xe04337a60d0ef93d
+./file5:3416 0xf04342a37cf07514
+./file5:3424 0x7afe92c1ea35582c
+./file5:3432 0x8d2ceb5c5b94185a
+./file5:3440 0x5cd0a334171eff0f
+./file5:3448 0x7b7627636d870bf8
+./file5:3456 0xd33ed6b491bbb521
+./file5:3464 0x54efb3793401b77
+./file5:3472 0x2681ca607463ecd7
+./file5:3480 0x3ab142d2e60a6193
+./file5:3488 0x2138e4d5814d4619
+./file5:3496 0x37aa0bb7c7071198
+./file5:3504 0x4147685a6e8c201c
+./file5:3512 0x24ce785f1b08de43
+./file5:3520 0xec6736d9f11daa4e
+./file5:3528 0xa2e6302f81886753
+./file5:3536 0xbeaf049ac9faf452
+./file5:3544 0xd1f028b8d65dfc3a
+./file5:3552 0x20080369f352c603
+./file5:3560 0x400713ddd7e761f3
+./file5:3568 0x6ef7afc96025a6fc
+./file5:3576 0x8d5ae3ba1e04c86c
+./file5:3584 0x618781fdd7e7de01
+./file5:3592 0xae46a420dcfe721f
+./file5:3600 0xda198664f40657c5
+./file5:3608 0xc471f061b1b4816d
+./file5:3616 0x40dc34a96c20d6fd
+./file5:3624 0x445ad7eab1e3a577
+./file5:3632 0x38ee74b94dde6ff6
+./file5:3640 0xf1f06f6f5f84a84b
+./file5:3648 0x8b551145b57c93dd
+./file5:3656 0x4b84b34fded09101
+./file5:3664 0xb938cb68511a9a69
+./file5:3672 0xa39ed1d5fcbef83b
+./file5:3680 0xd49b810aaaaaa136
+./file5:3688 0x9f914e41bbd39032
+./file5:3696 0x3ee9126b9925dd42
+./file5:3704 0x8866e844ab298591
+./file5:3712 0xea0586008d3616ed
+./file5:3720 0xdfe7ba9c428d070f
+./file5:3728 0x98e6189bfa80bd30
+./file5:3736 0xb2b3df58c745d841
+./file5:3744 0x80b68393ec1b9a70
+./file5:3752 0xefdfb8719e789ecc
+./file5:3760 0x43ac58b5d372933b
+./file5:3768 0xe074077aadc68fe9
+./file5:3776 0x49a8f8e6f9e150ce
+./file5:3784 0xfbce5a5450cd52c5
+./file5:3792 0x9045345161c530d
+./file5:3800 0x82559f9d767457ad
+./file5:3808 0xecbc371e1f014120
+./file5:3816 0xbcea789a42cf37b
+./file5:3824 0xc86d87197ef1ea3d
+./file5:3832 0xe4479e1c77c5b9ca
+./file5:3840 0x739177a7c45cd604
+./file5:3848 0xe00dc6dd18e9aab
+./file5:3856 0xe9b843132832a43f
+./file5:3864 0x5becdee6f5dafaa6
+./file5:3872 0x2ea956d9ce1d0384
+./file5:3880 0x85e563249bd0ecf
+./file5:3888 0x32882273489a0024
+./file5:3896 0xb15fbb8cbad95558
+./file5:3904 0x6477e2f26f3e6178
+./file5:3912 0xc13e6ce478d2f540
+./file5:3920 0x5b79fd712ce6c140
+./file5:3928 0xa76c951d7b196c0e
+./file5:3936 0xd7e0de08008d6930
+./file5:3944 0x4c6e33f32c0a6400
+./file5:3952 0x43fb36b85b38d1f3
+./file5:3960 0xf06c82643d16097a
+./file5:3968 0x84b4a98131dcf314
+./file5:3976 0x5cad55f2e744c7b8
+./file5:3984 0xabf3f1abf734bbd3
+./file5:3992 0xa52a0137c7b075e7
+./file5:4000 0x1cb96e6d3c2849e2
+./file5:4008 0xfdd8dda810625f27
+./file5:4016 0x2bce6864df693ba7
+./file5:4024 0x36140d9f996f6c16
+./file5:4032 0xc2444927102d9801
+./file5:4040 0x4d8b759a87d24634
+./file5:4048 0xc5b3ad865f63f477
+./file5:4056 0xedb95fe6605a35d6
+./file5:4064 0x8702022a0eb511e5
+./file5:4072 0xe98d106834d8a7f5
+./file5:4080 0xdbc17373b20f0bf7
+./file5:4088 0xc0a1f9ae83b44b36
+./file5:4096 0xf1e70387c908b610
+./file5:4104 0xe7884cf2bc494996
+./file5:4112 0xee6bdcc2b928a133
+./file5:4120 0xfaed60a336cace04
+./file5:4128 0xd0a873feab20a441
+./file5:4136 0xe335e25661b91e9
+./file5:4144 0xd7ad304e62df3bb0
+./file5:4152 0xbd741e2b455b7189
+./file5:4160 0xb3dc1bdc4a49ff6b
+./file5:4168 0x1816f8b14a841240
+./file5:4176 0xa0cb7a3299d06375
+./file5:4184 0x7eef7ab957a0af59
+./file5:4192 0xf6786c70ff35e596
+./file5:4200 0x29737a4943d8a3c
+./file5:4208 0x9c055fd45c72560c
+./file5:4216 0xcc51ae755b04bab1
+./file5:4224 0xd76ed03a66b83d7c
+./file5:4232 0x3805e761d9dc25e3
+./file5:4240 0xb4b54993e7ded488
+./file5:4248 0x5b9423356407bce3
+./file5:4256 0xa51df1aaa01934b2
+./file5:4264 0xd5ce0933d5b5c244
+./file5:4272 0xfa08efc81a9a170b
+./file5:4280 0x18bfcc0bd3a943f6
+./file5:4288 0xecbfefdd65803e25
+./file5:4296 0xdbf7bfdbd02fc10f
+./file5:4304 0x459748ec7a6c34ad
+./file5:4312 0xef6e2af8a5de10b5
+./file5:4320 0x33f907423b8646fd
+./file5:4328 0xb6408e7a9c887192
+./file5:4336 0xf9a245728fb3040d
+./file5:4344 0x639f677ad8b85073
+./file5:4352 0xa2dfd5863045dc05
+./file5:4360 0x4b85de2d8adea985
+./file5:4368 0x3632a81e79d7f427
+./file5:4376 0x8f9879a1bc94c47b
+./file5:4384 0x44ab711398a37c62
+./file5:4392 0x92435f1132957e24
+./file5:4400 0x36efb745bf83a2ba
+./file5:4408 0x619465353ff1b670
+./file5:4416 0x65ad462763faebe1
+./file5:4424 0xd37e943dac793a2a
+./file5:4432 0xb59055ddd461f18
+./file5:4440 0x2586951cb7383189
+./file5:4448 0xfb7b6e167f144f1
+./file5:4456 0xa5066621cc209a97
+./file5:4464 0x29d6c6467aa88934
+./file5:4472 0x71dad1291c61b2e5
+./file5:4480 0xc6a6acf3791a18f8
+./file5:4488 0xc0fe30df72973bc9
+./file5:4496 0x7655d1a718ab0b37
+./file5:4504 0x794745f1983d7672
+./file5:4512 0x584f68a7ee4f78ea
+./file5:4520 0x7d9862e4002dd5e9
+./file5:4528 0xd0b48eb9557e918c
+./file5:4536 0xde39c9d793ba1281
+./file5:4544 0xf00f79b3806988ee
+./file5:4552 0x2eb0ecb661184d2c
+./file5:4560 0x131b89374cabfbef
+./file5:4568 0x7901438f8795fb65
+./file5:4576 0x72ce7b63e4fb4e9b
+./file5:4584 0x6113cf89dec583bd
+./file5:4592 0xba51b110b97b6ec9
+./file5:4600 0xc7a23fc5611a0231
+./file5:4608 0xb05b922708252a43
+./file5:4616 0x387cade774079990
+./file5:4624 0x3b4e2c9520ca95
+./file5:4632 0xe8ceedc2105aab88
+./file5:4640 0xd5e8bdc709b23f61
+./file5:4648 0xe9e17b207d533a09
+./file5:4656 0xc669f436979af94e
+./file5:4664 0xd8579e34b0b198d9
+./file5:4672 0x2af241cb4eda0e74
+./file5:4680 0x9be766df4b54efc3
+./file5:4688 0x39f34b6059cbf50e
+./file5:4696 0xc3584db7bc55c9d0
+./file5:4704 0x4dd10e1974b5d808
+./file5:4712 0x2db72895ebbc152c
+./file5:4720 0xbf3fd4052033c31e
+./file5:4728 0xd3d19545ca7c9dff
+./file5:4736 0xfcad8e29cc23c989
+./file5:4744 0xe1c530adabebe0dd
+./file5:4752 0xd406b893b9d64f8d
+./file5:4760 0x78bef35ffa66a454
+./file5:4768 0x8d1d4adc3916775a
+./file5:4776 0xf190f2421ecbc9fc
+./file5:4784 0x8c2625721514a792
+./file5:4792 0xe441a1ffebe9cc72
+./file5:4800 0x9a356c9266423313
+./file5:4808 0xcdc5ce8fa6649a69
+./file5:4816 0x6a9f205be8f06c56
+./file5:4824 0xc4f4558e615f893c
+./file5:4832 0x1c7b7e9fa9dc7df1
+./file5:4840 0xfbdba6c6421b0c6d
+./file5:4848 0xac2ca2d5576369f1
+./file5:4856 0x525e665b7262d731
+./file5:4864 0xdc1ca0a2cc75e8a1
+./file5:4872 0x605bbde985b8efd
+./file5:4880 0xcbbeb694d0687e57
+./file5:4888 0x8e15640f02c9fdaa
+./file5:4896 0x3a9a6dcc4f07629d
+./file5:4904 0x7cd4b18b8a8982b3
+./file5:4912 0xf2059838337f5887
+./file5:4920 0x649e1e2460cab66f
+./file5:4928 0x71bd8d8a7c779e49
+./file5:4936 0x3a3a448f0bb327c
+./file5:4944 0x7e251ca02d5b30eb
+./file5:4952 0x33ad9e7758a1c707
+./file5:4960 0xc179f07104a93871
+./file5:4968 0xf3178fb4f84239d
+./file5:4976 0x96b67fb567adc60
+./file5:4984 0x31ed86bf4d275133
+./file5:4992 0xe263147e1195ba90
+./file5:5000 0xe90080df83f585a3
+./file5:5008 0xd3a24478a4c95337
+./file5:5016 0x10fbbc69a6cf5a44
+./file5:5024 0x6c49209368649300
+./file5:5032 0x1db1eb5249aaefaa
+./file5:5040 0x352034b816e6a1ff
+./file5:5048 0x94dd2e3bbc4f6929
+./file5:5056 0x9561781a12a27b73
+./file5:5064 0x370bfa5b195ea2ed
+./file5:5072 0x82124cc4025f83cb
+./file5:5080 0xab40463a8533d481
+./file5:5088 0xd88a6dec53ec2b0c
+./file5:5096 0x2adbece6447150dc
+./file5:5104 0x7b504e10632fc7f8
+./file5:5112 0x484cf8dda77286e8
+./file5:5120 0xf46662b5d23c63db
+./file5:5128 0xae805bfddec168e7
+./file5:5136 0xadc46afd945521c0
+./file5:5144 0x804b7b8e7a034324
+./file5:5152 0xb0f960d7f12ba67e
+./file5:5160 0x45fff74c7d9ac48c
+./file5:5168 0xf4025a404b3e190e
+./file5:5176 0xcb32be8e0c3a6f9b
+./file5:5184 0x1f00157bd35494b8
+./file5:5192 0x487133726be43292
+./file5:5200 0x9faca015c603ea0c
+./file5:5208 0x7a06e464dfcc51f0
+./file5:5216 0x4844301960d79370
+./file5:5224 0x73684469a9ff35d8
+./file5:5232 0xad266c1c7874c450
+./file5:5240 0xfeb1aab6489a9d08
+./file5:5248 0x9d7579a5bfebbed6
+./file5:5256 0x507dbaa92f136ca5
+./file5:5264 0x6d0c8bd04de31559
+./file5:5272 0x4f5820e946e06264
+./file5:5280 0x7775726f40876267
+./file5:5288 0x54e586464314a65d
+./file5:5296 0x4b47b5dfcff179bb
+./file5:5304 0x7b2c9b87ae4f4db2
+./file5:5312 0x8e7fe8e87780a324
+./file5:5320 0xf92a7697cd694ac3
+./file5:5328 0x158ab2c3c2d602a4
+./file5:5336 0x7fec4a05562be79f
+./file5:5344 0xbee0c35bb6413591
+./file5:5352 0x3c51842240569e93
+./file5:5360 0xd2895af7e8bcae20
+./file5:5368 0x70d2135a01f12913
+./file5:5376 0xdc831b7b0d38fb75
+./file5:5384 0x62df401087339562
+./file5:5392 0x3e5e670ce5b12e8c
+./file5:5400 0x588ed2f2cb81431
+./file5:5408 0xc1a12cd40975f867
+./file5:5416 0x5c16b023d9502315
+./file5:5424 0xe6b567ef43ced83a
+./file5:5432 0x7872e8ca5733e719
+./file5:5440 0xc0d0a64fa86ba77e
+./file5:5448 0x333e4a47b07c62b5
+./file5:5456 0x96356a8e687491df
+./file5:5464 0xc4b98b37cad666d7
+./file5:5472 0x32aa246f50bdb750
+./file5:5480 0x47ba410c07e6431d
+./file5:5488 0x202464b12483e7d3
+./file5:5496 0x4d86bd075ea430d4
+./file5:5504 0x6242e74ebca069ea
+./file5:5512 0xc770ac771fdbb94
+./file5:5520 0x4ad02a33c4d5dd03
+./file5:5528 0x18756d4c096a2996
+./file5:5536 0xbfe55e00ca71acd
+./file5:5544 0xd172126c1635ffc
+./file5:5552 0x4a74bbaeee58d9b2
+./file5:5560 0x5b533ce4c828393c
+./file5:5568 0x85cbec1786043013
+./file5:5576 0xf3f3f50b2e7b3441
+./file5:5584 0x3cf554ebd29a0347
+./file5:5592 0x88ed518ac8833500
+./file5:5600 0x1b76685785a0d167
+./file5:5608 0xf991dc7869a8db78
+./file5:5616 0xbdc08dbeb8673c0d
+./file5:5624 0x17a0120f9ef6cf4e
+./file5:5632 0xc07ff8d2d24ddef1
+./file5:5640 0x88af9eeee01aea2c
+./file5:5648 0xf67ef58b35395161
+./file5:5656 0x5a2f88e929457339
+./file5:5664 0xbc2049a5f2f88f12
+./file5:5672 0x63a744ab2ae516d9
+./file5:5680 0x98db27147f2a1138
+./file5:5688 0x4a9a92cd857485bb
+./file5:5696 0x31ecbc960266b4d4
+./file5:5704 0x5eea24117c3cddea
+./file5:5712 0x7d7c47912fbe5081
+./file5:5720 0x8b250fd183ff2482
+./file5:5728 0xb4ebd4acf0de4d5d
+./file5:5736 0x53bc85903b06f288
+./file5:5744 0x8d44ea25e67cfd66
+./file5:5752 0xce0a56ecd19feb6d
+./file5:5760 0x158469ea48b99706
+./file5:5768 0x55dc4b8cb69125d1
+./file5:5776 0xd812747a97d10d1c
+./file5:5784 0x8db6403f355884b7
+./file5:5792 0xae42f079d363ebf0
+./file5:5800 0x3cdac3a543930941
+./file5:5808 0x50498c6d0e46dd1f
+./file5:5816 0x9804703a3f93a882
+./file5:5824 0x47b1a2364997c528
+./file5:5832 0x607612b3edb17320
+./file5:5840 0xcbc5ef825951e054
+./file5:5848 0xaa6e2b08dd5bbd2e
+./file5:5856 0x3066d78c4ee7bc91
+./file5:5864 0x1e4d1a998fc46b93
+./file5:5872 0x638f4929c362ed81
+./file5:5880 0x492e0084052478a9
+./file5:5888 0x3427adbf74047973
+./file5:5896 0x347f1ffbe450b1af
+./file5:5904 0x64d87aca2ddf071d
+./file5:5912 0xb0c6dd300cca78d7
+./file5:5920 0xe37db96cd1c0885a
+./file5:5928 0x31acf651cf5791b5
+./file5:5936 0x7088d8504c42cbc4
+./file5:5944 0x463416f05d20e410
+./file5:5952 0x8d1090a191246fa5
+./file5:5960 0xfae40d0ae309b6cb
+./file5:5968 0x2824a79d0c5e73b2
+./file5:5976 0x85096d8c6f8d44eb
+./file5:5984 0x38251b534c2448f4
+./file5:5992 0xcf7231bdf7cf28db
+./file5:6000 0x43a5f18110ede9ce
+./file5:6008 0xb51583ce3ccec3ef
+./file5:6016 0xfba1c52311e377e8
+./file5:6024 0xda85782b90a852f5
+./file5:6032 0x2ee6ad3846913057
+./file5:6040 0xaf091f046977c868
+./file5:6048 0x5eed96004c9f1892
+./file5:6056 0x4523faecf2d8b7bc
+./file5:6064 0xaf9496b29a29a546
+./file5:6072 0xa32b507f7986886f
+./file5:6080 0xeecf7f8f01b048b7
+./file5:6088 0x866002e79a9a33ba
+./file5:6096 0xf0e6b6e8b09ea0cf
+./file5:6104 0xe3859ff7013ca097
+./file5:6112 0x87612c1cd1896ae3
+./file5:6120 0xca65c510e2183d8
+./file5:6128 0xab3cecd624dea6f7
+./file5:6136 0x45c3702308cfa963
+./file5:6144 0x2b889972acd046ca
+./file5:6152 0x7f0e4d740fc3e0f6
+./file5:6160 0xce0214442b2b8802
+./file5:6168 0x3f7307014621c292
+./file5:6176 0x7d1c5562f3785e36
+./file5:6184 0xaff4bc08f5b34813
+./file5:6192 0x70d6065467429167
+./file5:6200 0x6649f0b450763544
+./file5:6208 0x6b59b82523360c21
+./file5:6216 0x256bb58b8d02dc86
+./file5:6224 0x3e120fba0be2407
+./file5:6232 0x54828005678c50e8
+./file5:6240 0xada9489b8826204b
+./file5:6248 0x71eb79ccd1b909bf
+./file5:6256 0xd65ee28a0f6f8fbb
+./file5:6264 0x8db6f7c04f24592f
+./file5:6272 0xa615d41828aeb90c
+./file5:6280 0x9b3f148a3dfe3b9d
+./file5:6288 0x16f82c38dd4870e2
+./file5:6296 0x50ce1c9c5333837c
+./file5:6304 0xe52f80ddd782c6b6
+./file5:6312 0x11d0cd14fb43f327
+./file5:6320 0xefd9b85a82b90a3a
+./file5:6328 0x4363c12532f4b354
+./file5:6336 0x8d687a088896519
+./file5:6344 0x1dd001cf1648dc2f
+./file5:6352 0xa114dffd4272cdad
+./file5:6360 0x1d7f39793471b95
+./file5:6368 0x62b0c221413286c0
+./file5:6376 0x14c6609a1445d43d
+./file5:6384 0xfe5606d08b4cb7be
+./file5:6392 0xded4f18791391fe4
+./file5:6400 0x9907f104febeeaf8
+./file5:6408 0xf76af82fc6882b44
+./file5:6416 0x5e2b113ada90d9f7
+./file5:6424 0xb2a813215061c0ae
+./file5:6432 0xba2c73bf6da9a6d7
+./file5:6440 0x1eb4594d3ca0245c
+./file5:6448 0x8bbee3bb7739d880
+./file5:6456 0x2530b6dcbdc146fa
+./file5:6464 0xd1817c2100c7db6b
+./file5:6472 0xcc0a4ebf148c1b2e
+./file5:6480 0xa32491a25deab4f
+./file5:6488 0x93e277883f1b6eb
+./file5:6496 0xada0947542ddd181
+./file5:6504 0xed4c3ee7d61de70b
+./file5:6512 0x2c7a12ddbc0e9a
+./file5:6520 0xe296bd0e0e2b6da5
+./file5:6528 0xb92a3e7cbfd7a0d9
+./file5:6536 0x2cee7b14a85313b3
+./file5:6544 0xba5e9f5450175052
+./file5:6552 0x854860b60da58643
+./file5:6560 0x428546123da32641
+./file5:6568 0xa1c374833dd105a5
+./file5:6576 0x861a90d77e5f5cf7
+./file5:6584 0x9093567be142399d
+./file5:6592 0x6c185be7d192ec48
+./file5:6600 0xabcaf8f29bb0fd2e
+./file5:6608 0x3e32f6b640359e88
+./file5:6616 0xc712a5f514db467c
+./file5:6624 0xcfc994cde120311
+./file5:6632 0xeea3f899f8c4da1d
+./file5:6640 0xd6f3f39a7acdb85c
+./file5:6648 0x542917827163ee86
+./file5:6656 0xde4c26c0aea6a6e8
+./file5:6664 0xdaa935d612f44fa2
+./file5:6672 0x7e860d97bdcd0c1c
+./file5:6680 0x28c43be683edadc5
+./file5:6688 0x37e4b6ba84c8d4f7
+./file5:6696 0xd76839b77963c0d6
+./file5:6704 0xbff01bbedb1e14f2
+./file5:6712 0xa89912c20d378fd6
+./file5:6720 0x71fce32992979801
+./file5:6728 0x738632b56644737b
+./file5:6736 0x4c0a32b4a155e81d
+./file5:6744 0x47e47944f12ecc14
+./file5:6752 0xf3346d603a5cf410
+./file5:6760 0x2cd5c764a3c1896b
+./file5:6768 0x799b174f424f1355
+./file5:6776 0x636522da53de0ed9
+./file5:6784 0xd5984de60f2776c7
+./file5:6792 0x919bef1217f6b81a
+./file5:6800 0xc24525fffb790b29
+./file5:6808 0xc9035a1ab0001323
+./file5:6816 0x732220792265cef4
+./file5:6824 0xf4a27fc64a7cd076
+./file5:6832 0x43f551573c0c7ac6
+./file5:6840 0x8a9e27f0ae6a2e6d
+./file5:6848 0x1336482e6e4fec2b
+./file5:6856 0x38d93be5f58a2d7b
+./file5:6864 0x32221bfb94cc089f
+./file5:6872 0x3eff3a215ed0be92
+./file5:6880 0xb5d03019a41c4f4f
+./file5:6888 0xf28343fbe52c974e
+./file5:6896 0xfc7eb500cdaf4f3
+./file5:6904 0xe916bbcebed713cb
+./file5:6912 0xb0131acaa9b201a1
+./file5:6920 0xdfcd6b014d2ecf0d
+./file5:6928 0x8e85aa99c1d10e51
+./file5:6936 0x9fc2e1c1824a0c69
+./file5:6944 0x11e6d953ce004d43
+./file5:6952 0xe18aa994ab22674f
+./file5:6960 0x2a800a966583e6b7
+./file5:6968 0x56c4bc647051ddd7
+./file5:6976 0x3d2d61969a85663e
+./file5:6984 0xed86c0e6903f9f6
+./file5:6992 0x790c12c1b6e14608
+./file5:7000 0x4530b07e86dba71a
+./file5:7008 0x7df79eb462f328c0
+./file5:7016 0x20e8cf57e2c77820
+./file5:7024 0x101f18234fc99da8
+./file5:7032 0x2d2b1749266a3a58
+./file5:7040 0x77c6dd9dd4b822e1
+./file5:7048 0xc27e9a51acaf2c3f
+./file5:7056 0x591da459d61704ea
+./file5:7064 0x3e733aae77450d26
+./file5:7072 0xe494c31f4b17f1f8
+./file5:7080 0xc114074cb4fdbd94
+./file5:7088 0xa50ccd7690ffe525
+./file5:7096 0x2a1f74d1df4e929a
+./file5:7104 0x8702a904aba23f04
+./file5:7112 0x85882656725790ea
+./file5:7120 0xe48b2ea4dd73625b
+./file5:7128 0xbdc92cf738a27050
+./file5:7136 0x67be68d8470ce948
+./file5:7144 0x4ee5f57d4bf48e9d
+./file5:7152 0x665156ca15c52659
+./file5:7160 0x9dd39d9db61fc4cd
+./file5:7168 0x65ff0475bc0b3926
+./file5:7176 0xccd72cb6e90f1b95
+./file5:7184 0x1cb1c8ada74d1cd
+./file5:7192 0x62708b19f30e1d41
+./file5:7200 0x7c6cd623ae820dc8
+./file5:7208 0x4c3e42d9b71aeb75
+./file5:7216 0xb6e9af8aa8c0ae72
+./file5:7224 0xb2a2560c8385b0df
+./file5:7232 0x8cb6084c4f088f37
+./file5:7240 0x7791ebf66ed54bc8
+./file5:7248 0xf638aa71f6665d72
+./file5:7256 0xc443953cb3977d39
+./file5:7264 0x4fae24f0c4876210
+./file5:7272 0x37f790ab10daffaf
+./file5:7280 0xd437430b17245ff6
+./file5:7288 0x8931b60d766760e8
+./file5:7296 0x1885db4fec214c1f
+./file5:7304 0xb1265e06aa329a55
+./file5:7312 0x75fe0e6becea07ae
+./file5:7320 0xbf30d61e0bb9bbbd
+./file5:7328 0xe17bc278433a4979
+./file5:7336 0xb04a6b649d854529
+./file5:7344 0xd7a1a84f8ba79f84
+./file5:7352 0x9b098eb1f3eb4789
+./file5:7360 0x988c950b8e1fc006
+./file5:7368 0x60d5ceef074f05da
+./file5:7376 0x812c2965ded15cff
+./file5:7384 0xd6a630f400cfb3c1
+./file5:7392 0xac1e42b3ccc77948
+./file5:7400 0x4dc8627409ac45e5
+./file5:7408 0xe719584cec2c9c39
+./file5:7416 0x3001a5ad05cac003
+./file5:7424 0xd36372390269eeb7
+./file5:7432 0xd10cd8a7b0342d8f
+./file5:7440 0xd2662f99a061c58a
+./file5:7448 0xb3bcaad5d243d60d
+./file5:7456 0xeab6e0f6ed495ad8
+./file5:7464 0x70efe962594757cd
+./file5:7472 0x1f8f7d38ebe84b17
+./file5:7480 0x7d434f8a3f3f1b14
+./file5:7488 0x8143ff1dd778e27e
+./file5:7496 0xd42663b3f612b34
+./file5:7504 0x4f1e649460b0c846
+./file5:7512 0x41d165d5f1fea17e
+./file5:7520 0xc5b6192670b81aec
+./file5:7528 0x9c6d9792da84a62f
+./file5:7536 0x75f7fe5a52b5ed04
+./file5:7544 0xac80bb39adea8a8a
+./file5:7552 0x929d981c0d0180be
+./file5:7560 0x40cb5768f96834a3
+./file5:7568 0x3e0069c4335b5fd5
+./file5:7576 0x8ccc31e07d120b80
+./file5:7584 0x78bb1cbe8f0dfadc
+./file5:7592 0x292a97fcf1d040ec
+./file5:7600 0x64fe1ed1cf97c00c
+./file5:7608 0xbc456588e43e923a
+./file5:7616 0x8044681921e7c1b9
+./file5:7624 0x504d065297868779
+./file5:7632 0x58dd67e07e4a4773
+./file5:7640 0x33478fc73f996ae8
+./file5:7648 0x20faf62a43a03420
+./file5:7656 0xee539201708f5963
+./file5:7664 0x2b5419c56217db97
+./file5:7672 0xad259abbc31889ec
+./file5:7680 0x41471f3e402bf510
+./file5:7688 0x36e59a7a797b5d3b
+./file5:7696 0xd7057dded397b46a
+./file5:7704 0xa3d7c86704329f76
+./file5:7712 0x6b6d6131616dbebb
+./file5:7720 0x75207cd3f2a46d66
+./file5:7728 0x42c6022c6da52c57
+./file5:7736 0xb029506293c8cec7
+./file5:7744 0xd73b2c5297d7caa7
+./file5:7752 0xb90381caaf2866bf
+./file5:7760 0xd941f0f8c84492be
+./file5:7768 0x22ce06a90ab83093
+./file5:7776 0xe9b3b1ca4b6f013
+./file5:7784 0x21072492c3440575
+./file5:7792 0x2a2b6fe696952fc5
+./file5:7800 0xbed481736fea7c49
+./file5:7808 0xb837c0f4e7a7aac4
+./file5:7816 0x88c4713724380553
+./file5:7824 0x865ebfa874814741
+./file5:7832 0x7534b82f7c990094
+./file5:7840 0xe454e0131e971381
+./file5:7848 0x54229db5a96fa5d0
+./file5:7856 0x4202496fe3c60574
+./file5:7864 0xa37263eb57e84ddf
+./file5:7872 0x3da52022361e3c50
+./file5:7880 0x1f01f59c8c60c123
+./file5:7888 0xa3a80fc6d3d18334
+./file5:7896 0x1b6fbe7fa74f9678
+./file5:7904 0x66e20e8a7c3d3876
+./file5:7912 0xaf4be10f02e4795c
+./file5:7920 0x35e97f1a765dc9ca
+./file5:7928 0xcd9946edc280315c
+./file5:7936 0x8ea4674c6f95e09e
+./file5:7944 0xe42604dddcfb92e6
+./file5:7952 0xfc288c7f748baf7a
+./file5:7960 0xa17f0d86a87f912b
+./file5:7968 0xa569337f19111442
+./file5:7976 0x11820a665d6bbbf4
+./file5:7984 0x2227a771ec80f81a
+./file5:7992 0xa74e7589940bf36b
+./file5:8000 0x27cbe8f5cfb5b965
+./file5:8008 0x9d257015248849c9
+./file5:8016 0xad524c05a244c608
+./file5:8024 0x27e3f92527763937
+./file5:8032 0xc44342fe75a183ff
+./file5:8040 0xb5a586ef23907543
+./file5:8048 0xe0cdf945a2bb1d3d
+./file5:8056 0xadf3227374bd75e3
+./file5:8064 0x5d0e533328d77d38
+./file5:8072 0x7c02bff0cc7a0abd
+./file5:8080 0x8b0c32d2496d0326
+./file5:8088 0x10e9227436cae1e8
+./file5:8096 0x970aed6e47c0093d
+./file5:8104 0xc6d11123e5e7433c
+./file5:8112 0x833ff8f14da59671
+./file5:8120 0x21b0365e2824cf4c
+./file5:8128 0xd77b0a554efa2206
+./file5:8136 0xe20630e758c21625
+./file5:8144 0x8b7cf773d263c075
+./file5:8152 0xd0bc479bbb9427f1
+./file5:8160 0x5700267143f12756
+./file5:8168 0xbba39237fce953d9
+./file5:8176 0x1af59e6d6d05f49d
+checksum/TEST0: Done
diff --git a/src/test/log_basic/.gitignore b/src/test/log_basic/.gitignore
new file mode 100644
index 0000000000000000000000000000000000000000..260ef90418a63d11356ec2e5fb08ba113e41a075
--- /dev/null
+++ b/src/test/log_basic/.gitignore
@@ -0,0 +1 @@
+log_basic
diff --git a/src/test/log_basic/Makefile b/src/test/log_basic/Makefile
new file mode 100644
index 0000000000000000000000000000000000000000..c62008130d37720bc7ea79d0a7b70d5e48448271
--- /dev/null
+++ b/src/test/log_basic/Makefile
@@ -0,0 +1,43 @@
+#
+# Copyright (c) 2014, Intel Corporation
+#
+# Redistribution and use in source and binary forms, with or without
+# modification, are permitted provided that the following conditions
+# are met:
+#
+#     * Redistributions of source code must retain the above copyright
+#       notice, this list of conditions and the following disclaimer.
+#
+#     * Redistributions in binary form must reproduce the above copyright
+#       notice, this list of conditions and the following disclaimer in
+#       the documentation and/or other materials provided with the
+#       distribution.
+#
+#     * Neither the name of Intel Corporation nor the names of its
+#       contributors may be used to endorse or promote products derived
+#       from this software without specific prior written permission.
+#
+# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+#
+
+#
+# src/test/log_basic/Makefile -- build log_basic unit test
+#
+TARGET = log_basic
+OBJS = log_basic.o
+
+include ../Makefile.inc
+
+LIBS += -lpmem -lpthread
+
+log_basic.o: log_basic.c
diff --git a/src/test/log_basic/README b/src/test/log_basic/README
new file mode 100644
index 0000000000000000000000000000000000000000..5f9b9895835fb390c688f208efa94af0be828c2c
--- /dev/null
+++ b/src/test/log_basic/README
@@ -0,0 +1,34 @@
+Linux NVM Library
+
+This is src/test/log_basic/README.
+
+This directory contains a unit test for:
+- pmemlog_map
+- pmemlog_unmap
+- pmemlog_nbyte
+- pmemlog_append
+- pmemlog_appendv
+- pmemlog_tell
+- pmemlog_rewind
+- pmemlog_walk
+- pmemlog_check
+
+
+The program in pmemlog.c takes a filename and a list of
+operations encoded as characters as arugments. For example:
+
+	./log_basic file1 a v r w t n
+
+this will call a series of log iterations with some hardcoded arguments
+as described in the table below:
+
+	a - pmemlog_append
+	v - pmemlog_appendv
+	t - pmemlog_tell
+	r - pmemlog_rewind
+	w - pmemlog_walk
+	n - pmemlog_nbyte
+
+
+
+
diff --git a/src/test/log_basic/TEST0 b/src/test/log_basic/TEST0
new file mode 100755
index 0000000000000000000000000000000000000000..744bf864eb54bee60912b5139645430100f01f6d
--- /dev/null
+++ b/src/test/log_basic/TEST0
@@ -0,0 +1,62 @@
+#!/bin/bash -e
+#
+# Copyright (c) 2014, Intel Corporation
+#
+# Redistribution and use in source and binary forms, with or without
+# modification, are permitted provided that the following conditions
+# are met:
+#
+#     * Redistributions of source code must retain the above copyright
+#       notice, this list of conditions and the following disclaimer.
+#
+#     * Redistributions in binary form must reproduce the above copyright
+#       notice, this list of conditions and the following disclaimer in
+#       the documentation and/or other materials provided with the
+#       distribution.
+#
+#     * Neither the name of Intel Corporation nor the names of its
+#       contributors may be used to endorse or promote products derived
+#       from this software without specific prior written permission.
+#
+# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+#
+
+#
+# src/test/log_basic/TEST0 -- unit test for:
+# - pmemlog_nbyte
+# - pmemlog_tell
+# - pmemlog_walk
+# - pmemlog_rewind
+# in case of empty pool and:
+# - pmemlog_check
+# - pmemlog_map
+# - pmemlog_unmap
+#
+export UNITTEST_NAME=log_basic/TEST0
+export UNITTEST_NUM=0
+
+# standard unit test setup
+. ../unittest/unittest.sh
+
+setup
+
+rm -f $DIR/testfile1
+touch $DIR/testfile1
+
+expect_normal_exit ./log_basic$EXESUFFIX $DIR/testfile1 n t w r
+
+rm $DIR/testfile1
+
+check
+
+pass
diff --git a/src/test/log_basic/TEST1 b/src/test/log_basic/TEST1
new file mode 100755
index 0000000000000000000000000000000000000000..a97587fa6681a5421aa4129abfd9365c4f8745b6
--- /dev/null
+++ b/src/test/log_basic/TEST1
@@ -0,0 +1,65 @@
+#!/bin/bash -e
+#
+# Copyright (c) 2014, Intel Corporation
+#
+# Redistribution and use in source and binary forms, with or without
+# modification, are permitted provided that the following conditions
+# are met:
+#
+#     * Redistributions of source code must retain the above copyright
+#       notice, this list of conditions and the following disclaimer.
+#
+#     * Redistributions in binary form must reproduce the above copyright
+#       notice, this list of conditions and the following disclaimer in
+#       the documentation and/or other materials provided with the
+#       distribution.
+#
+#     * Neither the name of Intel Corporation nor the names of its
+#       contributors may be used to endorse or promote products derived
+#       from this software without specific prior written permission.
+#
+# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+#
+
+#
+# src/test/log_basic/TEST1 -- unit test for:
+# - pmemlog_append
+# and:
+# - pmemlog_nbyte
+# - pmemlog_tell
+# - pmemlog_walk
+# - pmemlog_rewind
+# in case of non-empty pool and
+# - pmemlog_check
+# - pmemlog_map
+# - pmemlog_unmap
+#
+export UNITTEST_NAME=log_basic/TEST1
+export UNITTEST_NUM=1
+
+# standard unit test setup
+. ../unittest/unittest.sh
+
+setup
+
+rm -f $DIR/testfile1
+touch $DIR/testfile1
+
+expect_normal_exit ./log_basic$EXESUFFIX $DIR/testfile1 a n t w r t w
+
+rm $DIR/testfile1
+
+check
+
+pass
+
diff --git a/src/test/log_basic/TEST2 b/src/test/log_basic/TEST2
new file mode 100755
index 0000000000000000000000000000000000000000..5f813c192307d0642b22e610c01dc859e5a9403d
--- /dev/null
+++ b/src/test/log_basic/TEST2
@@ -0,0 +1,65 @@
+#!/bin/bash -e
+#
+# Copyright (c) 2014, Intel Corporation
+#
+# Redistribution and use in source and binary forms, with or without
+# modification, are permitted provided that the following conditions
+# are met:
+#
+#     * Redistributions of source code must retain the above copyright
+#       notice, this list of conditions and the following disclaimer.
+#
+#     * Redistributions in binary form must reproduce the above copyright
+#       notice, this list of conditions and the following disclaimer in
+#       the documentation and/or other materials provided with the
+#       distribution.
+#
+#     * Neither the name of Intel Corporation nor the names of its
+#       contributors may be used to endorse or promote products derived
+#       from this software without specific prior written permission.
+#
+# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+#
+
+#
+# src/test/log_basic/TEST2 -- unit test for:
+# - pmemlog_appendv
+# and:
+# - pmemlog_nbyte
+# - pmemlog_tell
+# - pmemlog_walk
+# - pmemlog_rewind
+# in case of non-empty pool and
+# - pmemlog_check
+# - pmemlog_map
+# - pmemlog_unmap
+#
+export UNITTEST_NAME=log_basic/TEST2
+export UNITTEST_NUM=2
+
+# standard unit test setup
+. ../unittest/unittest.sh
+
+setup
+
+rm -f $DIR/testfile1
+touch $DIR/testfile1
+
+expect_normal_exit ./log_basic$EXESUFFIX $DIR/testfile1 v n t w r t w
+
+rm $DIR/testfile1
+
+check
+
+pass
+
diff --git a/src/test/log_basic/TEST3 b/src/test/log_basic/TEST3
new file mode 100755
index 0000000000000000000000000000000000000000..e4c504fb92c04932a3764e482951b021e021f4c1
--- /dev/null
+++ b/src/test/log_basic/TEST3
@@ -0,0 +1,66 @@
+#!/bin/bash -e
+#
+# Copyright (c) 2014, Intel Corporation
+#
+# Redistribution and use in source and binary forms, with or without
+# modification, are permitted provided that the following conditions
+# are met:
+#
+#     * Redistributions of source code must retain the above copyright
+#       notice, this list of conditions and the following disclaimer.
+#
+#     * Redistributions in binary form must reproduce the above copyright
+#       notice, this list of conditions and the following disclaimer in
+#       the documentation and/or other materials provided with the
+#       distribution.
+#
+#     * Neither the name of Intel Corporation nor the names of its
+#       contributors may be used to endorse or promote products derived
+#       from this software without specific prior written permission.
+#
+# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+#
+
+#
+# src/test/log_basic/TEST3 -- unit test for:
+# - pmemlog_append
+# - pmemlog_appendv
+# and:
+# - pmemlog_nbyte
+# - pmemlog_tell
+# - pmemlog_walk
+# - pmemlog_rewind
+# in case of non-empty pool and
+# - pmemlog_check
+# - pmemlog_map
+# - pmemlog_unmap
+#
+export UNITTEST_NAME=log_basic/TEST3
+export UNITTEST_NUM=3
+
+# standard unit test setup
+. ../unittest/unittest.sh
+
+setup
+
+rm -f $DIR/testfile1
+touch $DIR/testfile1
+
+expect_normal_exit ./log_basic$EXESUFFIX $DIR/testfile1 a n t w r t w v n t w r t w
+
+rm $DIR/testfile1
+
+check
+
+pass
+
diff --git a/src/test/log_basic/log_basic.c b/src/test/log_basic/log_basic.c
new file mode 100644
index 0000000000000000000000000000000000000000..3c16fc8444454aab85c815856c690112f93b2bf8
--- /dev/null
+++ b/src/test/log_basic/log_basic.c
@@ -0,0 +1,269 @@
+/*
+ * Copyright (c) 2014, Intel Corporation
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ *     * Redistributions of source code must retain the above copyright
+ *       notice, this list of conditions and the following disclaimer.
+ *
+ *     * Redistributions in binary form must reproduce the above copyright
+ *       notice, this list of conditions and the following disclaimer in
+ *       the documentation and/or other materials provided with the
+ *       distribution.
+ *
+ *     * Neither the name of Intel Corporation nor the names of its
+ *       contributors may be used to endorse or promote products derived
+ *       from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+/*
+ * log_basic.c -- unit test for pmemlog_*
+ *
+ * usage: log_basic file operation:...
+ *
+ * operations are 'n' or 'a' or 'v' or 't' or 'r' or 'w'
+ *
+ */
+
+#include "unittest.h"
+
+/*
+ * do_nbyte -- call pmemlog_nbyte() & print result
+ */
+void
+do_nbyte(PMEMlog *plp)
+{
+	size_t nbyte = pmemlog_nbyte(plp);
+	OUT("usable size: %zu", nbyte);
+}
+
+/*
+ * do_append -- call pmemlog_append() & print result
+ */
+void
+do_append(PMEMlog *plp)
+{
+	const char *str[6] = {
+		"1st test string\n",
+		"2nd test string\n",
+		"3rd test string\n",
+		"4th test string\n",
+		"5th test string\n",
+		"6th test string\n"
+	};
+
+	for (int i = 0; i < 6; ++i) {
+		int rv = pmemlog_append(plp, str[i], strlen(str[i]));
+		switch (rv) {
+		case 0:
+			OUT("append   str[%i] %s", i, str[i]);
+			break;
+		case -1:
+			OUT("!append   str[%i] %s", i, str[i]);
+			break;
+		default:
+			OUT("!append: wrong return value");
+			break;
+		}
+	}
+}
+
+/*
+ * do_appendv -- call pmemlog_appendv() & print result
+ */
+void
+do_appendv(PMEMlog *plp)
+{
+	struct iovec iov[9] = {
+		{
+			.iov_base = "1st test string\n",
+			.iov_len = 16
+		},
+		{
+			.iov_base = "2nd test string\n",
+			.iov_len = 16
+		},
+		{
+			.iov_base = "3rd test string\n",
+			.iov_len = 16
+		},
+		{
+			.iov_base = "4th test string\n",
+			.iov_len = 16
+		},
+		{
+			.iov_base = "5th test string\n",
+			.iov_len = 16
+		},
+		{
+			.iov_base = "6th test string\n",
+			.iov_len = 16
+		},
+		{
+			.iov_base = "7th test string\n",
+			.iov_len = 16
+		},
+		{
+			.iov_base = "8th test string\n",
+			.iov_len = 16
+		},
+		{
+			.iov_base = "9th test string\n",
+			.iov_len = 16
+		}
+	};
+
+	int rv = pmemlog_appendv(plp, iov, 9);
+	switch (rv) {
+	case 0:
+		OUT("appendv");
+		break;
+	case -1:
+		OUT("!appendv");
+		break;
+	default:
+		OUT("!appendv: wrong return value");
+		break;
+	}
+}
+
+/*
+ * do_tell -- call pmemlog_tell() & print result
+ */
+void
+do_tell(PMEMlog *plp)
+{
+	off_t tell = pmemlog_tell(plp);
+	OUT("tell %zu", tell);
+}
+
+/*
+ * do_rewind -- call pmemlog_rewind() & print result
+ */
+void
+do_rewind(PMEMlog *plp)
+{
+	pmemlog_rewind(plp);
+	OUT("rewind");
+}
+
+/*
+ * printit -- print out the 'buf' of length 'len'.
+ *
+ * It is a walker function for pmemlog_walk
+ */
+int
+printit(const void *buf, size_t len, void *arg)
+{
+	char *str = alloca(len + 1);
+
+	strncpy(str, buf, len);
+	str[len] = '\0';
+	OUT("%s", str);
+
+	return 1;
+}
+
+/*
+ * do_walk -- call pmemlog_walk() & print result
+ *
+ * pmemlog_walk() is called twice: for chunk size 0 and 16
+ */
+void
+do_walk(PMEMlog *plp)
+{
+	pmemlog_walk(plp, 0, printit, NULL);
+	OUT("walk all at once");
+	pmemlog_walk(plp, 16, printit, NULL);
+	OUT("walk by 16");
+}
+
+int
+main(int argc, char *argv[])
+{
+	PMEMlog *plp;
+	int result;
+
+	START(argc, argv, "log_basic");
+
+	if (argc < 3)
+		FATAL("usage: %s file-name op:n|a|v|t|r|w", argv[0]);
+
+	/* check consistency */
+	result = pmemlog_check(argv[1]);
+	if (result < 0)
+		OUT("!%s: pmemlog_check", argv[1]);
+	else if (result == 0)
+		OUT("%s: pmemlog_check: not consistent", argv[1]);
+
+	int fd = OPEN(argv[1], O_RDWR);
+
+	/* pre-allocate 2MB of persistent memory */
+	errno = posix_fallocate(fd, (off_t)0, (size_t)(2 * 1024 * 1024));
+	if (errno != 0)
+		FATAL("!posix_fallocate");
+
+	if ((plp = pmemlog_map(fd)) == NULL)
+		FATAL("!pmemlog_map: %s", argv[1]);
+
+	close(fd);
+
+	/* go through all arguments one by one */
+	for (int arg = 2; arg < argc; arg++) {
+		/* Scan the character of each argument. */
+		if (strchr("navtrw", argv[arg][0]) == NULL ||
+				argv[arg][1] != '\0')
+			FATAL("op must be n or a or v or t or r or w");
+
+		switch (argv[arg][0]) {
+		case 'n':
+			do_nbyte(plp);
+			break;
+
+		case 'a':
+			do_append(plp);
+			break;
+
+		case 'v':
+			do_appendv(plp);
+			break;
+
+		case 't':
+			do_tell(plp);
+			break;
+
+		case 'r':
+			do_rewind(plp);
+			break;
+
+		case 'w':
+			do_walk(plp);
+			break;
+		}
+	}
+
+	pmemlog_unmap(plp);
+
+	/* check consistency again */
+	result = pmemlog_check(argv[1]);
+	if (result < 0)
+		OUT("!%s: pmemlog_check", argv[1]);
+	else if (result == 0)
+		OUT("%s: pmemlog_check: not consistent", argv[1]);
+
+	DONE(NULL);
+}
diff --git a/src/test/log_basic/out0.log.match b/src/test/log_basic/out0.log.match
new file mode 100644
index 0000000000000000000000000000000000000000..b21758a451415d1e153a8e1405f41455ee0f1fe3
--- /dev/null
+++ b/src/test/log_basic/out0.log.match
@@ -0,0 +1,10 @@
+log_basic/TEST0: START: log_basic
+ ./log_basic$(*) $(*)/testfile1 n t w r
+$(*)/testfile1: pmemlog_check: Invalid argument
+usable size: 2088960
+tell 0
+
+walk all at once
+walk by 16
+rewind
+log_basic/TEST0: Done
diff --git a/src/test/log_basic/out1.log.match b/src/test/log_basic/out1.log.match
new file mode 100644
index 0000000000000000000000000000000000000000..57ddee3aa7105a0b54eba06b2af57cb090f7f799
--- /dev/null
+++ b/src/test/log_basic/out1.log.match
@@ -0,0 +1,44 @@
+log_basic/TEST1: START: log_basic
+ ./log_basic$(*) $(*)/testfile1 a n t w r t w
+$(*)/testfile1: pmemlog_check: Invalid argument
+append   str[0] 1st test string
+
+append   str[1] 2nd test string
+
+append   str[2] 3rd test string
+
+append   str[3] 4th test string
+
+append   str[4] 5th test string
+
+append   str[5] 6th test string
+
+usable size: 2088960
+tell 96
+1st test string
+2nd test string
+3rd test string
+4th test string
+5th test string
+6th test string
+
+walk all at once
+1st test string
+
+2nd test string
+
+3rd test string
+
+4th test string
+
+5th test string
+
+6th test string
+
+walk by 16
+rewind
+tell 0
+
+walk all at once
+walk by 16
+log_basic/TEST1: Done
diff --git a/src/test/log_basic/out2.log.match b/src/test/log_basic/out2.log.match
new file mode 100644
index 0000000000000000000000000000000000000000..ac8e1fb835ca3822c7ffddf73e2bc602c7382653
--- /dev/null
+++ b/src/test/log_basic/out2.log.match
@@ -0,0 +1,42 @@
+log_basic/TEST2: START: log_basic
+ ./log_basic$(*) $(*)/testfile1 v n t w r t w
+$(*)/testfile1: pmemlog_check: Invalid argument
+appendv
+usable size: 2088960
+tell 144
+1st test string
+2nd test string
+3rd test string
+4th test string
+5th test string
+6th test string
+7th test string
+8th test string
+9th test string
+
+walk all at once
+1st test string
+
+2nd test string
+
+3rd test string
+
+4th test string
+
+5th test string
+
+6th test string
+
+7th test string
+
+8th test string
+
+9th test string
+
+walk by 16
+rewind
+tell 0
+
+walk all at once
+walk by 16
+log_basic/TEST2: Done
diff --git a/src/test/log_basic/out3.log.match b/src/test/log_basic/out3.log.match
new file mode 100644
index 0000000000000000000000000000000000000000..d05683a077a503d79660506db4861cae913b55c0
--- /dev/null
+++ b/src/test/log_basic/out3.log.match
@@ -0,0 +1,82 @@
+log_basic/TEST3: START: log_basic
+ ./log_basic$(*) $(*)/testfile1 a n t w r t w v n t w r t w
+$(*)/testfile1: pmemlog_check: Invalid argument
+append   str[0] 1st test string
+
+append   str[1] 2nd test string
+
+append   str[2] 3rd test string
+
+append   str[3] 4th test string
+
+append   str[4] 5th test string
+
+append   str[5] 6th test string
+
+usable size: 2088960
+tell 96
+1st test string
+2nd test string
+3rd test string
+4th test string
+5th test string
+6th test string
+
+walk all at once
+1st test string
+
+2nd test string
+
+3rd test string
+
+4th test string
+
+5th test string
+
+6th test string
+
+walk by 16
+rewind
+tell 0
+
+walk all at once
+walk by 16
+appendv
+usable size: 2088960
+tell 144
+1st test string
+2nd test string
+3rd test string
+4th test string
+5th test string
+6th test string
+7th test string
+8th test string
+9th test string
+
+walk all at once
+1st test string
+
+2nd test string
+
+3rd test string
+
+4th test string
+
+5th test string
+
+6th test string
+
+7th test string
+
+8th test string
+
+9th test string
+
+walk by 16
+rewind
+tell 0
+
+walk all at once
+walk by 16
+log_basic/TEST3: Done
diff --git a/src/test/log_recovery/.gitignore b/src/test/log_recovery/.gitignore
new file mode 100644
index 0000000000000000000000000000000000000000..af57d6618b0051494647c5d6451249f202b5e544
--- /dev/null
+++ b/src/test/log_recovery/.gitignore
@@ -0,0 +1 @@
+log_recovery
diff --git a/src/test/log_recovery/Makefile b/src/test/log_recovery/Makefile
new file mode 100644
index 0000000000000000000000000000000000000000..820df40fcbe2266db99c663ec87e6100fdf1dc6b
--- /dev/null
+++ b/src/test/log_recovery/Makefile
@@ -0,0 +1,45 @@
+#
+# Copyright (c) 2014, Intel Corporation
+#
+# Redistribution and use in source and binary forms, with or without
+# modification, are permitted provided that the following conditions
+# are met:
+#
+#     * Redistributions of source code must retain the above copyright
+#       notice, this list of conditions and the following disclaimer.
+#
+#     * Redistributions in binary form must reproduce the above copyright
+#       notice, this list of conditions and the following disclaimer in
+#       the documentation and/or other materials provided with the
+#       distribution.
+#
+#     * Neither the name of Intel Corporation nor the names of its
+#       contributors may be used to endorse or promote products derived
+#       from this software without specific prior written permission.
+#
+# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+#
+
+#
+# src/test/log_recovery/Makefile -- build log_recovery unit test
+#
+vpath %.h ../..
+TARGET = log_recovery
+OBJS = log_recovery.o
+
+include ../Makefile.inc
+CFLAGS += -I../..
+
+LIBS += -lpmem -lpthread
+
+log_recovery.o: log_recovery.c
diff --git a/src/test/log_recovery/README b/src/test/log_recovery/README
new file mode 100644
index 0000000000000000000000000000000000000000..56ee83115b14e0f57495b58092681b6bce89e6ec
--- /dev/null
+++ b/src/test/log_recovery/README
@@ -0,0 +1,20 @@
+Linux NVM Library
+
+This is src/test/log_recovery/README.
+
+This directory contains a unit test for pmemlog recovery. It works only
+in non-debug mode.
+
+The program in log_recovery.c takes a filename and an operation as arugments.
+An operation is encoded as a character 'a' or 'v'. The first one means that
+pmemlog_append() will be used to append data and the second one means that
+pmemlog_appendv() will be used to do that. For example:
+
+	./log_recovery file1 a
+
+this will call pmemlog_map() on file1, call pmemlog_append() to append
+six strings to the log and pmemlog_tell() to check the current write point,
+then it will change the memory protection on the metadata area to read-only.
+Next, pmemlog_append() is called again and SIGSEGV is caught and reported.
+Finally, pmemblk_check() and pmemlog_tell() are called to make sure
+there are no partial log entries.
diff --git a/src/test/log_recovery/TEST0 b/src/test/log_recovery/TEST0
new file mode 100755
index 0000000000000000000000000000000000000000..e001eef3d1033e3c8bac74f130155a1947c021bc
--- /dev/null
+++ b/src/test/log_recovery/TEST0
@@ -0,0 +1,57 @@
+#!/bin/bash -e
+#
+# Copyright (c) 2014, Intel Corporation
+#
+# Redistribution and use in source and binary forms, with or without
+# modification, are permitted provided that the following conditions
+# are met:
+#
+#     * Redistributions of source code must retain the above copyright
+#       notice, this list of conditions and the following disclaimer.
+#
+#     * Redistributions in binary form must reproduce the above copyright
+#       notice, this list of conditions and the following disclaimer in
+#       the documentation and/or other materials provided with the
+#       distribution.
+#
+#     * Neither the name of Intel Corporation nor the names of its
+#       contributors may be used to endorse or promote products derived
+#       from this software without specific prior written permission.
+#
+# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+#
+
+#
+# src/test/log_recovery/TEST0 -- unit test for pmemlog recovery
+#                                pmemlog_append() is used to append data
+#
+export UNITTEST_NAME=log_recovery/TEST0
+export UNITTEST_NUM=0
+
+# standard unit test setup
+. ../unittest/unittest.sh
+
+require_build_type nondebug static-nondebug
+
+setup
+
+rm -f $DIR/testfile1
+touch $DIR/testfile1
+
+expect_normal_exit ./log_recovery$EXESUFFIX $DIR/testfile1 a
+
+rm $DIR/testfile1
+
+check
+
+pass
diff --git a/src/test/log_recovery/TEST1 b/src/test/log_recovery/TEST1
new file mode 100755
index 0000000000000000000000000000000000000000..4dc8757f408c97e5d2b31af3acf3dc95326a422f
--- /dev/null
+++ b/src/test/log_recovery/TEST1
@@ -0,0 +1,57 @@
+#!/bin/bash -e
+#
+# Copyright (c) 2014, Intel Corporation
+#
+# Redistribution and use in source and binary forms, with or without
+# modification, are permitted provided that the following conditions
+# are met:
+#
+#     * Redistributions of source code must retain the above copyright
+#       notice, this list of conditions and the following disclaimer.
+#
+#     * Redistributions in binary form must reproduce the above copyright
+#       notice, this list of conditions and the following disclaimer in
+#       the documentation and/or other materials provided with the
+#       distribution.
+#
+#     * Neither the name of Intel Corporation nor the names of its
+#       contributors may be used to endorse or promote products derived
+#       from this software without specific prior written permission.
+#
+# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+#
+
+#
+# src/test/log_recovery/TEST0 -- unit test for pmemlog recovery
+#                                pmemlog_appendv() is used to append data
+#
+export UNITTEST_NAME=log_recovery/TEST1
+export UNITTEST_NUM=1
+
+# standard unit test setup
+. ../unittest/unittest.sh
+
+require_build_type nondebug static-nondebug
+
+setup
+
+rm -f $DIR/testfile1
+touch $DIR/testfile1
+
+expect_normal_exit ./log_recovery$EXESUFFIX $DIR/testfile1 v
+
+rm $DIR/testfile1
+
+check
+
+pass
diff --git a/src/test/log_recovery/log_recovery.c b/src/test/log_recovery/log_recovery.c
new file mode 100644
index 0000000000000000000000000000000000000000..be9818cd453679f5d0dea70f5d81ec1a2f2d3514
--- /dev/null
+++ b/src/test/log_recovery/log_recovery.c
@@ -0,0 +1,263 @@
+/*
+ * Copyright (c) 2014, Intel Corporation
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ *     * Redistributions of source code must retain the above copyright
+ *       notice, this list of conditions and the following disclaimer.
+ *
+ *     * Redistributions in binary form must reproduce the above copyright
+ *       notice, this list of conditions and the following disclaimer in
+ *       the documentation and/or other materials provided with the
+ *       distribution.
+ *
+ *     * Neither the name of Intel Corporation nor the names of its
+ *       contributors may be used to endorse or promote products derived
+ *       from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+/*
+ * log_recovery.c -- unit test for pmemlog recovery
+ *
+ * usage: log_recovery file operation:...
+ *
+ * operation has to be 'a' or 'v'
+ *
+ */
+
+#include <sys/param.h>
+#include "unittest.h"
+#include "util.h"
+#include "log.h"
+
+/*
+ * do_append -- call pmemlog_append() & print result
+ */
+void
+do_append(PMEMlog *plp)
+{
+	const char *str[6] = {
+		"1st append string\n",
+		"2nd append string\n",
+		"3rd append string\n",
+		"4th append string\n",
+		"5th append string\n",
+		"6th append string\n"
+	};
+
+	for (int i = 0; i < 6; ++i) {
+		int rv = pmemlog_append(plp, str[i], strlen(str[i]));
+		switch (rv) {
+		case 0:
+			OUT("append   str[%i] %s", i, str[i]);
+			break;
+		case -1:
+			OUT("!append   str[%i] %s", i, str[i]);
+			break;
+		default:
+			OUT("!append: wrong return value");
+			break;
+		}
+	}
+}
+
+/*
+ * do_appendv -- call pmemlog_appendv() & print result
+ */
+void
+do_appendv(PMEMlog *plp)
+{
+	struct iovec iov[9] = {
+		{
+			.iov_base = "1st appendv string\n",
+			.iov_len = 19
+		},
+		{
+			.iov_base = "2nd appendv string\n",
+			.iov_len = 19
+		},
+		{
+			.iov_base = "3rd appendv string\n",
+			.iov_len = 19
+		},
+		{
+			.iov_base = "4th appendv string\n",
+			.iov_len = 19
+		},
+		{
+			.iov_base = "5th appendv string\n",
+			.iov_len = 19
+		},
+		{
+			.iov_base = "6th appendv string\n",
+			.iov_len = 19
+		},
+		{
+			.iov_base = "7th appendv string\n",
+			.iov_len = 19
+		},
+		{
+			.iov_base = "8th appendv string\n",
+			.iov_len = 19
+		},
+		{
+			.iov_base = "9th appendv string\n",
+			.iov_len = 19
+		}
+	};
+
+	int rv = pmemlog_appendv(plp, iov, 9);
+	switch (rv) {
+	case 0:
+		OUT("appendv");
+		break;
+	case -1:
+		OUT("!appendv");
+		break;
+	default:
+		OUT("!appendv: wrong return value");
+		break;
+	}
+}
+
+/*
+ * do_tell -- call pmemlog_tell() & print result
+ */
+void
+do_tell(PMEMlog *plp)
+{
+	off_t tell = pmemlog_tell(plp);
+	OUT("tell %zu", tell);
+}
+
+/*
+ * printit -- print out the 'buf' of length 'len'.
+ *
+ * It is a walker function for pmemlog_walk
+ */
+int
+printit(const void *buf, size_t len, void *arg)
+{
+	char *str = alloca(len + 1);
+
+	strncpy(str, buf, len);
+	str[len] = '\0';
+	OUT("%s", str);
+
+	return 0;
+}
+
+/*
+ * do_walk -- call pmemlog_walk() & print result
+ */
+void
+do_walk(PMEMlog *plp)
+{
+	pmemlog_walk(plp, 0, printit, NULL);
+	OUT("walk all at once");
+}
+
+sigjmp_buf Jmp;
+
+/*
+ * signal_handler -- called on SIGSEGV
+ */
+void
+signal_handler(int sig)
+{
+	OUT("signal: %s", strsignal(sig));
+
+	siglongjmp(Jmp, 1);
+}
+
+int
+main(int argc, char *argv[])
+{
+	PMEMlog *plp;
+	int result;
+
+	START(argc, argv, "log_recovery");
+
+	if (argc != 3)
+		FATAL("usage: %s file-name op:a|v", argv[0]);
+
+	if (strchr("av", argv[2][0]) == NULL || argv[2][1] != '\0')
+		FATAL("op must be a or v");
+
+	int fd = OPEN(argv[1], O_RDWR);
+
+	/* pre-allocate 2MB of persistent memory */
+	errno = posix_fallocate(fd, (off_t)0, (size_t)(2 * 1024 * 1024));
+	if (errno != 0)
+		FATAL("!posix_fallocate");
+
+	if ((plp = pmemlog_map(fd)) == NULL)
+		FATAL("!pmemlog_map: %s", argv[1]);
+
+	/* append some data */
+	if (argv[2][0] == 'a')
+		do_append(plp);
+	else
+		do_appendv(plp);
+
+	/* print out current write point */
+	do_tell(plp);
+
+	size_t len = roundup(sizeof (*plp), LOG_FORMAT_DATA_ALIGN);
+	OUT("write-protecting the metadata, length %zu", len);
+	MPROTECT(plp, len, PROT_READ);
+
+	/* arrange to catch SEGV */
+	struct sigvec v = { 0 };
+	v.sv_handler = signal_handler;
+	SIGVEC(SIGSEGV, &v, NULL);
+
+	if (!sigsetjmp(Jmp, 1)) {
+		/* try to append more data */
+		if (argv[2][0] == 'a')
+			do_append(plp);
+		else
+			do_appendv(plp);
+	}
+
+	pmemlog_unmap(plp);
+
+	/* check consistency */
+	result = pmemlog_check(argv[1]);
+	if (result < 0)
+		OUT("!%s: pmemlog_check", argv[1]);
+	else if (result == 0)
+		OUT("%s: pmemlog_check: not consistent", argv[1]);
+	else
+		OUT("%s: consistent", argv[1]);
+
+	/* map again to print out whole log */
+	if ((plp = pmemlog_map(fd)) == NULL)
+		FATAL("!pmemlog_map: %s", argv[1]);
+
+	/* print out current write point */
+	do_tell(plp);
+
+	/* print out whole log */
+	do_walk(plp);
+
+	pmemlog_unmap(plp);
+
+	close(fd);
+
+	DONE(NULL);
+}
diff --git a/src/test/log_recovery/out0.log.match b/src/test/log_recovery/out0.log.match
new file mode 100644
index 0000000000000000000000000000000000000000..f64def65485df74bb1a2264914bb931ff2c4a89f
--- /dev/null
+++ b/src/test/log_recovery/out0.log.match
@@ -0,0 +1,28 @@
+log_recovery/TEST0: START: log_recovery
+ ./log_recovery$(*) $(*)/testfile1 a
+append   str[0] 1st append string
+
+append   str[1] 2nd append string
+
+append   str[2] 3rd append string
+
+append   str[3] 4th append string
+
+append   str[4] 5th append string
+
+append   str[5] 6th append string
+
+tell 108
+write-protecting the metadata, length 8192
+signal: Segmentation fault
+$(*)/testfile1: consistent
+tell 108
+1st append string
+2nd append string
+3rd append string
+4th append string
+5th append string
+6th append string
+
+walk all at once
+log_recovery/TEST0: Done
diff --git a/src/test/log_recovery/out1.log.match b/src/test/log_recovery/out1.log.match
new file mode 100644
index 0000000000000000000000000000000000000000..9f6dbf2af51762845ff2c26e1f4bef8eabbed0a7
--- /dev/null
+++ b/src/test/log_recovery/out1.log.match
@@ -0,0 +1,20 @@
+log_recovery/TEST1: START: log_recovery
+ ./log_recovery$(*) $(*)/testfile1 v
+appendv
+tell 171
+write-protecting the metadata, length 8192
+signal: Segmentation fault
+$(*)/testfile1: consistent
+tell 171
+1st appendv string
+2nd appendv string
+3rd appendv string
+4th appendv string
+5th appendv string
+6th appendv string
+7th appendv string
+8th appendv string
+9th appendv string
+
+walk all at once
+log_recovery/TEST1: Done
diff --git a/src/test/log_walker/.gitignore b/src/test/log_walker/.gitignore
new file mode 100644
index 0000000000000000000000000000000000000000..110dbec30b559de8b98f9f63d320a27b971747ca
--- /dev/null
+++ b/src/test/log_walker/.gitignore
@@ -0,0 +1 @@
+log_walker
diff --git a/src/test/log_walker/Makefile b/src/test/log_walker/Makefile
new file mode 100644
index 0000000000000000000000000000000000000000..09b8b112b79dae92a6e60e8a2d63e8b876c634de
--- /dev/null
+++ b/src/test/log_walker/Makefile
@@ -0,0 +1,43 @@
+#
+# Copyright (c) 2014, Intel Corporation
+#
+# Redistribution and use in source and binary forms, with or without
+# modification, are permitted provided that the following conditions
+# are met:
+#
+#     * Redistributions of source code must retain the above copyright
+#       notice, this list of conditions and the following disclaimer.
+#
+#     * Redistributions in binary form must reproduce the above copyright
+#       notice, this list of conditions and the following disclaimer in
+#       the documentation and/or other materials provided with the
+#       distribution.
+#
+#     * Neither the name of Intel Corporation nor the names of its
+#       contributors may be used to endorse or promote products derived
+#       from this software without specific prior written permission.
+#
+# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+#
+
+#
+# src/test/log_walker/Makefile -- build log_walker unit test
+#
+TARGET = log_walker
+OBJS = log_walker.o
+
+include ../Makefile.inc
+
+LIBS += -lpmem -lpthread
+
+log_walker.o: log_walker.c
diff --git a/src/test/log_walker/README b/src/test/log_walker/README
new file mode 100644
index 0000000000000000000000000000000000000000..86ebebb99aa19a9bde78c0daaa23617ca63501bc
--- /dev/null
+++ b/src/test/log_walker/README
@@ -0,0 +1,14 @@
+Linux NVM Library
+
+This is src/test/log_walker/README.
+
+This directory contains a unit test to verify pool's write-protection
+in debug mode. It works only in debug mode.
+
+The program in log_walker.c takes only a filename as an arugment. For example:
+
+	./log_walker file1
+
+this calls pmemlog_map() on file1 and pmemlog_append() to append six strings
+to the log. Next pmemlog_walk() is called and the walk handler tries to store
+to the buffer and SIGSEGV is caught and reported.
diff --git a/src/test/log_walker/TEST0 b/src/test/log_walker/TEST0
new file mode 100755
index 0000000000000000000000000000000000000000..5d6165bf8acff1cd288e72edf5ab31259132491b
--- /dev/null
+++ b/src/test/log_walker/TEST0
@@ -0,0 +1,57 @@
+#!/bin/bash -e
+#
+# Copyright (c) 2014, Intel Corporation
+#
+# Redistribution and use in source and binary forms, with or without
+# modification, are permitted provided that the following conditions
+# are met:
+#
+#     * Redistributions of source code must retain the above copyright
+#       notice, this list of conditions and the following disclaimer.
+#
+#     * Redistributions in binary form must reproduce the above copyright
+#       notice, this list of conditions and the following disclaimer in
+#       the documentation and/or other materials provided with the
+#       distribution.
+#
+#     * Neither the name of Intel Corporation nor the names of its
+#       contributors may be used to endorse or promote products derived
+#       from this software without specific prior written permission.
+#
+# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+#
+
+#
+# src/test/log_walker/TEST0 -- unit test to verify pool's write-protection
+#                              in debug mode
+#
+export UNITTEST_NAME=log_walker/TEST0
+export UNITTEST_NUM=0
+
+# standard unit test setup
+. ../unittest/unittest.sh
+
+require_build_type debug static-debug
+
+setup
+
+rm -f $DIR/testfile1
+touch $DIR/testfile1
+
+expect_normal_exit ./log_walker$EXESUFFIX $DIR/testfile1
+
+rm $DIR/testfile1
+
+check
+
+pass
diff --git a/src/test/log_walker/log_walker.c b/src/test/log_walker/log_walker.c
new file mode 100644
index 0000000000000000000000000000000000000000..a685167f51f23c3eee5c49e24c6c682ad521015a
--- /dev/null
+++ b/src/test/log_walker/log_walker.c
@@ -0,0 +1,146 @@
+/*
+ * Copyright (c) 2014, Intel Corporation
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ *     * Redistributions of source code must retain the above copyright
+ *       notice, this list of conditions and the following disclaimer.
+ *
+ *     * Redistributions in binary form must reproduce the above copyright
+ *       notice, this list of conditions and the following disclaimer in
+ *       the documentation and/or other materials provided with the
+ *       distribution.
+ *
+ *     * Neither the name of Intel Corporation nor the names of its
+ *       contributors may be used to endorse or promote products derived
+ *       from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+/*
+ * log_walker.c -- unit test to verify pool's write-protection in debug mode
+ *
+ * usage: log_walker file
+ *
+ */
+
+#include <sys/param.h>
+#include "unittest.h"
+
+/*
+ * do_append -- call pmemlog_append() & print result
+ */
+void
+do_append(PMEMlog *plp)
+{
+	const char *str[6] = {
+		"1st append string\n",
+		"2nd append string\n",
+		"3rd append string\n",
+		"4th append string\n",
+		"5th append string\n",
+		"6th append string\n"
+	};
+
+	for (int i = 0; i < 6; ++i) {
+		int rv = pmemlog_append(plp, str[i], strlen(str[i]));
+		switch (rv) {
+		case 0:
+			OUT("append   str[%i] %s", i, str[i]);
+			break;
+		case -1:
+			OUT("!append   str[%i] %s", i, str[i]);
+			break;
+		default:
+			OUT("!append: wrong return value");
+			break;
+		}
+	}
+}
+
+/*
+ * try_to_store -- try to store to the buffer 'buf'
+ *
+ * It is a walker function for pmemlog_walk
+ */
+int
+try_to_store(const void *buf, size_t len, void *arg)
+{
+	memset((void *)buf, 0, len);
+	return 0;
+}
+
+/*
+ * do_walk -- call pmemlog_walk() & print result
+ */
+void
+do_walk(PMEMlog *plp)
+{
+	pmemlog_walk(plp, 0, try_to_store, NULL);
+	OUT("walk all at once");
+}
+
+sigjmp_buf Jmp;
+
+/*
+ * signal_handler -- called on SIGSEGV
+ */
+void
+signal_handler(int sig)
+{
+	OUT("signal: %s", strsignal(sig));
+
+	siglongjmp(Jmp, 1);
+}
+
+int
+main(int argc, char *argv[])
+{
+	PMEMlog *plp;
+
+	START(argc, argv, "log_walker");
+
+	if (argc != 2)
+		FATAL("usage: %s file-name", argv[0]);
+
+	int fd = OPEN(argv[1], O_RDWR);
+
+	/* pre-allocate 2MB of persistent memory */
+	errno = posix_fallocate(fd, (off_t)0, (size_t)(2 * 1024 * 1024));
+	if (errno != 0)
+		FATAL("!posix_fallocate");
+
+	if ((plp = pmemlog_map(fd)) == NULL)
+		FATAL("!pmemlog_map: %s", argv[1]);
+
+	close(fd);
+
+	/* append some data */
+	do_append(plp);
+
+	/* arrange to catch SEGV */
+	struct sigvec v = { 0 };
+	v.sv_handler = signal_handler;
+	SIGVEC(SIGSEGV, &v, NULL);
+
+	if (!sigsetjmp(Jmp, 1)) {
+		do_walk(plp);
+	}
+
+	pmemlog_unmap(plp);
+
+	DONE(NULL);
+}
diff --git a/src/test/log_walker/out0.log.match b/src/test/log_walker/out0.log.match
new file mode 100644
index 0000000000000000000000000000000000000000..a15b486ec09df3f0bedebc138b60a8e002533137
--- /dev/null
+++ b/src/test/log_walker/out0.log.match
@@ -0,0 +1,16 @@
+log_walker/TEST0: START: log_walker
+ ./log_walker$(*) $(*)/testfile1
+append   str[0] 1st append string
+
+append   str[1] 2nd append string
+
+append   str[2] 3rd append string
+
+append   str[3] 4th append string
+
+append   str[4] 5th append string
+
+append   str[5] 6th append string
+
+signal: Segmentation fault
+log_walker/TEST0: Done
diff --git a/src/test/match b/src/test/match
new file mode 100755
index 0000000000000000000000000000000000000000..64f8d300f62a51381564842f3d19991f88071e4f
--- /dev/null
+++ b/src/test/match
@@ -0,0 +1,200 @@
+#!/usr/bin/perl -w
+#
+# Copyright (c) 2014, Intel Corporation
+#
+# Redistribution and use in source and binary forms, with or without
+# modification, are permitted provided that the following conditions
+# are met:
+#
+#     * Redistributions of source code must retain the above copyright
+#       notice, this list of conditions and the following disclaimer.
+#
+#     * Redistributions in binary form must reproduce the above copyright
+#       notice, this list of conditions and the following disclaimer in
+#       the documentation and/or other materials provided with the
+#       distribution.
+#
+#     * Neither the name of Intel Corporation nor the names of its
+#       contributors may be used to endorse or promote products derived
+#       from this software without specific prior written permission.
+#
+# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+#
+
+#
+# match -- compare an output file with expected results
+#
+# usage: match [-adqv] [match-file]...
+#
+# this script compares the output from a test run, stored in a file, with
+# the expected output.  comparison is done line-by-line until either all
+# lines compare correctly (exit code 0) or a miscompare is found (exit
+# code nonzero).
+#
+# expected output is stored in a ".match" file, which contains a copy of
+# the expected output with embedded tokens for things that should not be
+# exact matches.  the supported tokens are:
+#
+#	$(N)	an integer (i.e. one or more decimal digits)
+#	$(FP)	a floating point number
+#	$(S)	ascii string
+#	$(X)	hex number
+#	$(W)	whitespace
+#	$(*)	any string
+#	$(DD)	output of a "dd" run
+#	$(OPT)	line is optional (may be missing, matched if found)
+#
+# arguments are:
+#
+#	-a	find all files of the form "X.match" in the current
+#		directory and match them again the corresponding file "X".
+#
+#	-d	debug -- show lots of debug output
+#
+#	-q	don't print any output on mismatch (just exit with result code)
+#
+#	-v	verbose -- show every line as it is being matched
+#
+
+use strict;
+use Getopt::Std;
+
+my $Me = $0;
+$Me =~ s,.*/,,;
+
+our ($opt_a, $opt_d, $opt_q, $opt_v);
+
+$SIG{HUP} = $SIG{INT} = $SIG{TERM} = $SIG{__DIE__} = sub {
+	die @_ if $^S;
+	my $errstr = shift;
+	die "FAIL: $Me: $errstr";
+};
+
+sub usage {
+	my $msg = shift;
+
+	warn "$Me: $msg\n" if $msg;
+	warn "Usage: $Me [-adqv] [match-file]...\n";
+	exit 1;
+}
+
+getopts('adqv') or usage;
+
+my %match2file;
+
+if ($opt_a) {
+	usage("-a and filename arguments are mutually exclusive")
+		if $#ARGV != -1;
+	opendir(DIR, '.') or die "opendir: .: $!\n";
+	my @matchfiles = grep { /(.*)\.match$/ && -f $1 } readdir(DIR);
+	closedir(DIR);
+	die "no files found to process\n" unless @matchfiles;
+	foreach my $mfile (@matchfiles)  {
+		die "$mfile: $!\n" unless open(F, $mfile);
+		close(F);
+		my $ofile = $mfile;
+		$ofile =~ s/\.match$//;
+		die "$mfile found but cannot open $ofile: $!\n"
+			unless open(F, $ofile);
+		close(F);
+		$match2file{$mfile} = $ofile;
+	}
+} else {
+	usage("no match-file arguments found") if $#ARGV == -1;
+
+	# to improve the failure case, check all filename args exist and
+	# are provided in pairs now, before going through and processing them
+	foreach my $mfile (@ARGV) {
+		my $ofile = $mfile;
+		usage("$mfile: not a .match file") unless
+			$ofile =~ s/\.match$//;
+		usage("$mfile: $!") unless open(F, $mfile);
+		close(F);
+		usage("$ofile: $!") unless open(F, $ofile);
+		close(F);
+		$match2file{$mfile} = $ofile;
+	}
+}
+
+my $mfile;
+my $ofile;
+print "Files to be processed:\n" if $opt_v;
+foreach $mfile (sort keys %match2file) {
+	$ofile = $match2file{$mfile};
+	print "        match-file \"$mfile\" output-file \"$ofile\"\n"
+		if $opt_v;
+	match($mfile, $ofile);
+}
+
+exit 0;
+
+#
+# match -- process a match-file, output-file pair
+#
+sub match {
+	my ($mfile, $ofile) = @_;
+	my $pat;
+	my $output = snarf($ofile);
+	my $line = 0;
+	my $opt = 0;
+
+	open(F, $mfile) or die "$mfile: $!\n";
+	while (<F>) {
+		$pat = $_;
+		$line++;
+		s/([*+?|{}.\\^\$\[()])/\\$1/g;
+		s/\\\$\\\(FP\\\)/[-+]?\\d*\\.?\\d+([eE][-+]?\\d+)?/g;
+		s/\\\$\\\(N\\\)/\\d+/g;
+		s/\\\$\\\(\\\*\\\)/.*/g;
+		s/\\\$\\\(S\\\)/\\P{IsC}+/g;
+		s/\\\$\\\(X\\\)/\\p{IsXDigit}+/g;
+		s/\\\$\\\(W\\\)/\\s*[^\n]/g;
+		s/\\\$\\\(DD\\\)/\\d+\\+\\d+ records in\n\\d+\\+\\d+ records out\n\\d+ bytes \\\(\\d+ .B\\\) copied, [.0-9e-]+[^,]*, [.0-9]+ .B.s/g;
+		if (s/\\\$\\\(OPT\\\)//) {
+			$opt = 1;
+		}
+		print "$mfile:$line matching /$pat/\n" if $opt_v;
+		print " => /$_/\n" if $opt_d;
+		print " [$output]\n" if $opt_d;
+		unless ($output =~ s/^$_//) {
+			if ($opt) {
+				print "$mfile:$line skipping optional /$pat/\n" if $opt_v;
+				$opt = 0;
+			} else {
+				die "$mfile:$line did not match pattern: /$pat/\n";
+			}
+		}
+	}
+
+	if ($output ne '') {
+		# make it a little more print-friendly...
+		$output =~ s/\n/\\n/g;
+		die "line $line: unexpected output: \"$output\"\n";
+	}
+}
+
+
+#
+# snarf -- slurp an entire file into memory
+#
+sub snarf {
+	my ($fname) = @_;
+	local $/;
+	my $contents;
+
+	open(R, $fname) or die "$fname: $!\n";
+	$contents = <R>;
+	close(R);
+
+	return $contents;
+}
diff --git a/src/test/pmem_is_pmem/.gitignore b/src/test/pmem_is_pmem/.gitignore
new file mode 100644
index 0000000000000000000000000000000000000000..7f0a40cb8990126e0aca484e33eaf56c21ebaea0
--- /dev/null
+++ b/src/test/pmem_is_pmem/.gitignore
@@ -0,0 +1 @@
+pmem_is_pmem
diff --git a/src/test/pmem_is_pmem/Makefile b/src/test/pmem_is_pmem/Makefile
new file mode 100644
index 0000000000000000000000000000000000000000..46a323f121abc3377c129cd281b0f94527f05462
--- /dev/null
+++ b/src/test/pmem_is_pmem/Makefile
@@ -0,0 +1,43 @@
+#
+# Copyright (c) 2014, Intel Corporation
+#
+# Redistribution and use in source and binary forms, with or without
+# modification, are permitted provided that the following conditions
+# are met:
+#
+#     * Redistributions of source code must retain the above copyright
+#       notice, this list of conditions and the following disclaimer.
+#
+#     * Redistributions in binary form must reproduce the above copyright
+#       notice, this list of conditions and the following disclaimer in
+#       the documentation and/or other materials provided with the
+#       distribution.
+#
+#     * Neither the name of Intel Corporation nor the names of its
+#       contributors may be used to endorse or promote products derived
+#       from this software without specific prior written permission.
+#
+# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+#
+
+#
+# src/test/pmem_is_pmem/Makefile -- build pmem_is_pmem unit test
+#
+TARGET = pmem_is_pmem
+OBJS = pmem_is_pmem.o
+
+include ../Makefile.inc
+
+LIBS += -lpmem
+
+pmem_is_pmem.o: pmem_is_pmem.c
diff --git a/src/test/pmem_is_pmem/README b/src/test/pmem_is_pmem/README
new file mode 100644
index 0000000000000000000000000000000000000000..423a9200594dbc434d77ee59bbc9f3d2edd0ad95
--- /dev/null
+++ b/src/test/pmem_is_pmem/README
@@ -0,0 +1,14 @@
+Linux NVM Library
+
+This is src/test/pmem_is_pmem/README.
+
+This directory contains a unit test for pmem_is_pmem().
+
+The program in pmem_is_pmem.c takes a file as an argument, memory
+maps that file, and prints out the return value from pmem_is_pmem()
+on the resulting range.  For true persistent memory, 1 is the expected
+output.  0 is the expected output for everything else.
+
+The tests in this directory also check that the PMEM_IS_PMEM_FORCE
+environment variable can be used to force a specific return value
+from pmem_is_pmem().
diff --git a/src/test/pmem_is_pmem/TEST0 b/src/test/pmem_is_pmem/TEST0
new file mode 100755
index 0000000000000000000000000000000000000000..b078038b84521efef323a3ee3cf483c3f00b457b
--- /dev/null
+++ b/src/test/pmem_is_pmem/TEST0
@@ -0,0 +1,54 @@
+#!/bin/bash -e
+#
+# Copyright (c) 2014, Intel Corporation
+#
+# Redistribution and use in source and binary forms, with or without
+# modification, are permitted provided that the following conditions
+# are met:
+#
+#     * Redistributions of source code must retain the above copyright
+#       notice, this list of conditions and the following disclaimer.
+#
+#     * Redistributions in binary form must reproduce the above copyright
+#       notice, this list of conditions and the following disclaimer in
+#       the documentation and/or other materials provided with the
+#       distribution.
+#
+#     * Neither the name of Intel Corporation nor the names of its
+#       contributors may be used to endorse or promote products derived
+#       from this software without specific prior written permission.
+#
+# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+#
+
+#
+# src/test/pmem_is_pmem/TEST0 -- unit test for pmem_is_pmem
+#
+export UNITTEST_NAME=pmem_is_pmem/TEST0
+export UNITTEST_NUM=0
+
+# standard unit test setup
+. ../unittest/unittest.sh
+
+require_fs_type non-pmem
+
+setup
+
+rm -f $DIR/testfile1
+truncate -s 2G $DIR/testfile1
+expect_normal_exit ./pmem_is_pmem$EXESUFFIX $DIR/testfile1
+rm $DIR/testfile1
+
+check
+
+pass
diff --git a/src/test/pmem_is_pmem/TEST1 b/src/test/pmem_is_pmem/TEST1
new file mode 100755
index 0000000000000000000000000000000000000000..0f1f41c1da5da3070dd6905925649329270aebce
--- /dev/null
+++ b/src/test/pmem_is_pmem/TEST1
@@ -0,0 +1,54 @@
+#!/bin/bash -e
+#
+# Copyright (c) 2014, Intel Corporation
+#
+# Redistribution and use in source and binary forms, with or without
+# modification, are permitted provided that the following conditions
+# are met:
+#
+#     * Redistributions of source code must retain the above copyright
+#       notice, this list of conditions and the following disclaimer.
+#
+#     * Redistributions in binary form must reproduce the above copyright
+#       notice, this list of conditions and the following disclaimer in
+#       the documentation and/or other materials provided with the
+#       distribution.
+#
+#     * Neither the name of Intel Corporation nor the names of its
+#       contributors may be used to endorse or promote products derived
+#       from this software without specific prior written permission.
+#
+# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+#
+
+#
+# src/test/pmem_is_pmem/TEST1 -- unit test for pmem_is_pmem
+#
+export UNITTEST_NAME=pmem_is_pmem/TEST1
+export UNITTEST_NUM=1
+
+# standard unit test setup
+. ../unittest/unittest.sh
+
+require_fs_type pmem
+
+setup
+
+rm -f $DIR/testfile1
+truncate -s 2G $DIR/testfile1
+expect_normal_exit ./pmem_is_pmem$EXESUFFIX $DIR/testfile1
+rm $DIR/testfile1
+
+check
+
+pass
diff --git a/src/test/pmem_is_pmem/TEST2 b/src/test/pmem_is_pmem/TEST2
new file mode 100755
index 0000000000000000000000000000000000000000..582e8196fd51b7ab35706ddde63a2d8889d152a0
--- /dev/null
+++ b/src/test/pmem_is_pmem/TEST2
@@ -0,0 +1,55 @@
+#!/bin/bash -e
+#
+# Copyright (c) 2014, Intel Corporation
+#
+# Redistribution and use in source and binary forms, with or without
+# modification, are permitted provided that the following conditions
+# are met:
+#
+#     * Redistributions of source code must retain the above copyright
+#       notice, this list of conditions and the following disclaimer.
+#
+#     * Redistributions in binary form must reproduce the above copyright
+#       notice, this list of conditions and the following disclaimer in
+#       the documentation and/or other materials provided with the
+#       distribution.
+#
+#     * Neither the name of Intel Corporation nor the names of its
+#       contributors may be used to endorse or promote products derived
+#       from this software without specific prior written permission.
+#
+# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+#
+
+#
+# src/test/pmem_is_pmem/TEST2 -- unit test for pmem_is_pmem
+#
+export UNITTEST_NAME=pmem_is_pmem/TEST2
+export UNITTEST_NUM=2
+
+# standard unit test setup
+. ../unittest/unittest.sh
+
+require_fs_type non-pmem
+
+setup
+
+rm -f $DIR/testfile1
+truncate -s 2G $DIR/testfile1
+export PMEM_IS_PMEM_FORCE=1
+expect_normal_exit ./pmem_is_pmem$EXESUFFIX $DIR/testfile1
+rm $DIR/testfile1
+
+check
+
+pass
diff --git a/src/test/pmem_is_pmem/TEST3 b/src/test/pmem_is_pmem/TEST3
new file mode 100755
index 0000000000000000000000000000000000000000..98ce9434a31e3110cdbfd66b0e0657d643d58e88
--- /dev/null
+++ b/src/test/pmem_is_pmem/TEST3
@@ -0,0 +1,55 @@
+#!/bin/bash -e
+#
+# Copyright (c) 2014, Intel Corporation
+#
+# Redistribution and use in source and binary forms, with or without
+# modification, are permitted provided that the following conditions
+# are met:
+#
+#     * Redistributions of source code must retain the above copyright
+#       notice, this list of conditions and the following disclaimer.
+#
+#     * Redistributions in binary form must reproduce the above copyright
+#       notice, this list of conditions and the following disclaimer in
+#       the documentation and/or other materials provided with the
+#       distribution.
+#
+#     * Neither the name of Intel Corporation nor the names of its
+#       contributors may be used to endorse or promote products derived
+#       from this software without specific prior written permission.
+#
+# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+#
+
+#
+# src/test/pmem_is_pmem/TEST3 -- unit test for pmem_is_pmem
+#
+export UNITTEST_NAME=pmem_is_pmem/TEST3
+export UNITTEST_NUM=3
+
+# standard unit test setup
+. ../unittest/unittest.sh
+
+require_fs_type pmem
+
+setup
+
+rm -f $DIR/testfile1
+truncate -s 2G $DIR/testfile1
+export PMEM_IS_PMEM_FORCE=0
+expect_normal_exit ./pmem_is_pmem$EXESUFFIX $DIR/testfile1
+rm $DIR/testfile1
+
+check
+
+pass
diff --git a/src/test/pmem_is_pmem/err0.log.match b/src/test/pmem_is_pmem/err0.log.match
new file mode 100644
index 0000000000000000000000000000000000000000..e69de29bb2d1d6434b8b29ae775ad8c2e48c5391
diff --git a/src/test/pmem_is_pmem/err1.log.match b/src/test/pmem_is_pmem/err1.log.match
new file mode 100644
index 0000000000000000000000000000000000000000..e69de29bb2d1d6434b8b29ae775ad8c2e48c5391
diff --git a/src/test/pmem_is_pmem/err2.log.match b/src/test/pmem_is_pmem/err2.log.match
new file mode 100644
index 0000000000000000000000000000000000000000..e69de29bb2d1d6434b8b29ae775ad8c2e48c5391
diff --git a/src/test/pmem_is_pmem/err3.log.match b/src/test/pmem_is_pmem/err3.log.match
new file mode 100644
index 0000000000000000000000000000000000000000..e69de29bb2d1d6434b8b29ae775ad8c2e48c5391
diff --git a/src/test/pmem_is_pmem/out0.log.match b/src/test/pmem_is_pmem/out0.log.match
new file mode 100644
index 0000000000000000000000000000000000000000..883bd4807db3b39a2888ec03e080a3fab4df366e
--- /dev/null
+++ b/src/test/pmem_is_pmem/out0.log.match
@@ -0,0 +1,4 @@
+pmem_is_pmem/TEST0: START: pmem_is_pmem
+ ./pmem_is_pmem$(*) $(*)/testfile1
+0
+pmem_is_pmem/TEST0: Done
diff --git a/src/test/pmem_is_pmem/out1.log.match b/src/test/pmem_is_pmem/out1.log.match
new file mode 100644
index 0000000000000000000000000000000000000000..fa90d11ff99b947b8c297d997321af3e9713d01f
--- /dev/null
+++ b/src/test/pmem_is_pmem/out1.log.match
@@ -0,0 +1,4 @@
+pmem_is_pmem/TEST1: START: pmem_is_pmem
+ ./pmem_is_pmem$(*) $(*)/testfile1
+1
+pmem_is_pmem/TEST1: Done
diff --git a/src/test/pmem_is_pmem/out2.log.match b/src/test/pmem_is_pmem/out2.log.match
new file mode 100644
index 0000000000000000000000000000000000000000..3aeb0b58189a2408099c9dfda3527e72674adf99
--- /dev/null
+++ b/src/test/pmem_is_pmem/out2.log.match
@@ -0,0 +1,4 @@
+pmem_is_pmem/TEST2: START: pmem_is_pmem
+ ./pmem_is_pmem$(*) $(*)/testfile1
+1
+pmem_is_pmem/TEST2: Done
diff --git a/src/test/pmem_is_pmem/out3.log.match b/src/test/pmem_is_pmem/out3.log.match
new file mode 100644
index 0000000000000000000000000000000000000000..ce4d0b7046051c571f46dfd421d536595cca1e99
--- /dev/null
+++ b/src/test/pmem_is_pmem/out3.log.match
@@ -0,0 +1,4 @@
+pmem_is_pmem/TEST3: START: pmem_is_pmem
+ ./pmem_is_pmem$(*) $(*)/testfile1
+0
+pmem_is_pmem/TEST3: Done
diff --git a/src/test/pmem_is_pmem/pmem_is_pmem.c b/src/test/pmem_is_pmem/pmem_is_pmem.c
new file mode 100644
index 0000000000000000000000000000000000000000..c20c4f2956cde498b8441c444110e086ce82140c
--- /dev/null
+++ b/src/test/pmem_is_pmem/pmem_is_pmem.c
@@ -0,0 +1,62 @@
+/*
+ * Copyright (c) 2014, Intel Corporation
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ *     * Redistributions of source code must retain the above copyright
+ *       notice, this list of conditions and the following disclaimer.
+ *
+ *     * Redistributions in binary form must reproduce the above copyright
+ *       notice, this list of conditions and the following disclaimer in
+ *       the documentation and/or other materials provided with the
+ *       distribution.
+ *
+ *     * Neither the name of Intel Corporation nor the names of its
+ *       contributors may be used to endorse or promote products derived
+ *       from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+/*
+ * pmem_is_pmem.c -- unit test for pmem_is_pmem()
+ *
+ * usage: pmem_is_pmem file
+ */
+
+#include "unittest.h"
+
+int
+main(int argc, char *argv[])
+{
+	START(argc, argv, "pmem_is_pmem");
+
+	if (argc !=  2)
+		FATAL("usage: %s file", argv[0]);
+
+	int fd = OPEN(argv[1], O_RDWR);
+
+	struct stat stbuf;
+	FSTAT(fd, &stbuf);
+
+	void *addr =
+		MMAP(0, stbuf.st_size, PROT_READ|PROT_WRITE, MAP_SHARED, fd, 0);
+
+	close(fd);
+
+	OUT("%d", pmem_is_pmem(addr, stbuf.st_size));
+
+	DONE(NULL);
+}
diff --git a/src/test/pmem_is_pmem_proc/.gitignore b/src/test/pmem_is_pmem_proc/.gitignore
new file mode 100644
index 0000000000000000000000000000000000000000..807dc9d798d07a04e9cc6a4737b72d2712c86971
--- /dev/null
+++ b/src/test/pmem_is_pmem_proc/.gitignore
@@ -0,0 +1 @@
+pmem_is_pmem_proc
diff --git a/src/test/pmem_is_pmem_proc/Makefile b/src/test/pmem_is_pmem_proc/Makefile
new file mode 100644
index 0000000000000000000000000000000000000000..c3e3d6f203940babb146bfcb83432bfb6f6c6e26
--- /dev/null
+++ b/src/test/pmem_is_pmem_proc/Makefile
@@ -0,0 +1,45 @@
+#
+# Copyright (c) 2014, Intel Corporation
+#
+# Redistribution and use in source and binary forms, with or without
+# modification, are permitted provided that the following conditions
+# are met:
+#
+#     * Redistributions of source code must retain the above copyright
+#       notice, this list of conditions and the following disclaimer.
+#
+#     * Redistributions in binary form must reproduce the above copyright
+#       notice, this list of conditions and the following disclaimer in
+#       the documentation and/or other materials provided with the
+#       distribution.
+#
+#     * Neither the name of Intel Corporation nor the names of its
+#       contributors may be used to endorse or promote products derived
+#       from this software without specific prior written permission.
+#
+# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+#
+
+#
+# src/test/pmem_is_pmem_proc/Makefile -- build pmem_is_pmem_proc unit test
+#
+TARGET = pmem_is_pmem_proc
+OBJS = pmem_is_pmem_proc.o
+
+include ../Makefile.inc
+
+LIBS += -lpmem -ldl
+STATIC_DEBUG_LIBS += -ldl
+STATIC_NONDEBUG_LIBS += -ldl
+
+pmem_is_pmem_proc.o: pmem_is_pmem_proc.c
diff --git a/src/test/pmem_is_pmem_proc/README b/src/test/pmem_is_pmem_proc/README
new file mode 100644
index 0000000000000000000000000000000000000000..101fe8b7a6825e444373e0b737394d138f276183
--- /dev/null
+++ b/src/test/pmem_is_pmem_proc/README
@@ -0,0 +1,14 @@
+Linux NVM Library
+
+This is src/test/pmem_is_pmem_proc/README.
+
+This directory contains a unit test for pmem_is_pmem().
+
+The program in pmem_is_pmem_proc.c takes a fake /proc/self/smaps file
+as an argument, along with an address and a length.  It arranges for
+pmem_is_pmem() to open the fake /proc file when looking up the range.
+
+	usage: pmem_is_pmem_proc smaps-file addr len [addr len]...
+
+addr is interpreted as a hex value, len as a decimal value unless it
+starts with 0x.  Each addr/len pair is tested against the given smaps-file.
diff --git a/src/test/pmem_is_pmem_proc/TEST0 b/src/test/pmem_is_pmem_proc/TEST0
new file mode 100755
index 0000000000000000000000000000000000000000..fa530f960626bfad299edf00b5b0fbc9162d32bc
--- /dev/null
+++ b/src/test/pmem_is_pmem_proc/TEST0
@@ -0,0 +1,66 @@
+#!/bin/bash -e
+#
+# Copyright (c) 2014, Intel Corporation
+#
+# Redistribution and use in source and binary forms, with or without
+# modification, are permitted provided that the following conditions
+# are met:
+#
+#     * Redistributions of source code must retain the above copyright
+#       notice, this list of conditions and the following disclaimer.
+#
+#     * Redistributions in binary form must reproduce the above copyright
+#       notice, this list of conditions and the following disclaimer in
+#       the documentation and/or other materials provided with the
+#       distribution.
+#
+#     * Neither the name of Intel Corporation nor the names of its
+#       contributors may be used to endorse or promote products derived
+#       from this software without specific prior written permission.
+#
+# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+#
+
+#
+# src/test/pmem_is_pmem_proc/TEST0 -- unit test for pmem_is_pmem /proc parsing
+#
+export UNITTEST_NAME=pmem_is_pmem_proc/TEST0
+export UNITTEST_NUM=0
+
+# standard unit test setup
+. ../unittest/unittest.sh
+
+require_fs_type local
+
+setup
+
+# 7fff77424000 2147479552
+#	exactly matches smaps second mm entry, should produce: 1
+# 7fff77424000 2147479553
+#	extends past smaps second mm entry, should produce: 0
+# 7fff77424000 8192
+#	entirely encompassed by smaps second mm entry, should produce: 1
+# 7fff77423000 8192
+#	start at smaps first mm entry, extends into second: should produce: 1
+# 7fff77423000 2147483648
+#	exactly matches sum of both mm entries: should produce 1
+expect_normal_exit ./pmem_is_pmem_proc$EXESUFFIX smaps_mm_both\
+	7fff77424000 2147479552\
+	7fff77424000 2147479553\
+	7fff77424000 8192\
+	7fff77423000 8192\
+	7fff77423000 2147483648
+
+check
+
+pass
diff --git a/src/test/pmem_is_pmem_proc/TEST1 b/src/test/pmem_is_pmem_proc/TEST1
new file mode 100755
index 0000000000000000000000000000000000000000..65387da1cbbad6fe8377647199c9df579aac45a9
--- /dev/null
+++ b/src/test/pmem_is_pmem_proc/TEST1
@@ -0,0 +1,60 @@
+#!/bin/bash -e
+#
+# Copyright (c) 2014, Intel Corporation
+#
+# Redistribution and use in source and binary forms, with or without
+# modification, are permitted provided that the following conditions
+# are met:
+#
+#     * Redistributions of source code must retain the above copyright
+#       notice, this list of conditions and the following disclaimer.
+#
+#     * Redistributions in binary form must reproduce the above copyright
+#       notice, this list of conditions and the following disclaimer in
+#       the documentation and/or other materials provided with the
+#       distribution.
+#
+#     * Neither the name of Intel Corporation nor the names of its
+#       contributors may be used to endorse or promote products derived
+#       from this software without specific prior written permission.
+#
+# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+#
+
+#
+# src/test/pmem_is_pmem_proc/TEST1 -- unit test for pmem_is_pmem /proc parsing
+#
+export UNITTEST_NAME=pmem_is_pmem_proc/TEST1
+export UNITTEST_NUM=1
+
+# standard unit test setup
+. ../unittest/unittest.sh
+
+require_fs_type local
+
+setup
+
+# 7fff77424000 2147479552
+#	exactly matches smaps second non-mm entry, should produce: 0
+# 7fff77423000 8192
+#	start at smaps first mm entry, extends into second: should produce: 0
+# 7fff77423000 4096
+#	exactly matches smaps first mm entry, should produce: 1
+expect_normal_exit ./pmem_is_pmem_proc$EXESUFFIX smaps_mm_first\
+	7fff77424000 2147479552\
+	7fff77423000 8192\
+	7fff77423000 4096
+
+check
+
+pass
diff --git a/src/test/pmem_is_pmem_proc/TEST2 b/src/test/pmem_is_pmem_proc/TEST2
new file mode 100755
index 0000000000000000000000000000000000000000..aa1237126b6d0365ea83c90be0d34e235eee2d68
--- /dev/null
+++ b/src/test/pmem_is_pmem_proc/TEST2
@@ -0,0 +1,63 @@
+#!/bin/bash -e
+#
+# Copyright (c) 2014, Intel Corporation
+#
+# Redistribution and use in source and binary forms, with or without
+# modification, are permitted provided that the following conditions
+# are met:
+#
+#     * Redistributions of source code must retain the above copyright
+#       notice, this list of conditions and the following disclaimer.
+#
+#     * Redistributions in binary form must reproduce the above copyright
+#       notice, this list of conditions and the following disclaimer in
+#       the documentation and/or other materials provided with the
+#       distribution.
+#
+#     * Neither the name of Intel Corporation nor the names of its
+#       contributors may be used to endorse or promote products derived
+#       from this software without specific prior written permission.
+#
+# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+#
+
+#
+# src/test/pmem_is_pmem_proc/TEST2 -- unit test for pmem_is_pmem /proc parsing
+#
+export UNITTEST_NAME=pmem_is_pmem_proc/TEST2
+export UNITTEST_NUM=2
+
+# standard unit test setup
+. ../unittest/unittest.sh
+
+require_fs_type local
+
+setup
+
+# 7fff77424000 2147479552
+#	exactly matches smaps second mm entry, should produce: 1
+# 7fff77428000 10240
+#	subset of smaps second mm entry, should produce: 1
+# 7fff77424000 2147479553
+#	extends past smaps second mm entry, should produce: 0
+# 7fff77423000 8192
+#	start at smaps first mm entry, extends into second: should produce: 0
+expect_normal_exit ./pmem_is_pmem_proc$EXESUFFIX smaps_mm_second\
+	7fff77424000 2147479552\
+	7fff77428000 10240\
+	7fff77424000 2147479553\
+	7fff77423000 8192
+
+check
+
+pass
diff --git a/src/test/pmem_is_pmem_proc/TEST3 b/src/test/pmem_is_pmem_proc/TEST3
new file mode 100755
index 0000000000000000000000000000000000000000..ade862e4d56878b7a131255acc07597a25494a8f
--- /dev/null
+++ b/src/test/pmem_is_pmem_proc/TEST3
@@ -0,0 +1,63 @@
+#!/bin/bash -e
+#
+# Copyright (c) 2014, Intel Corporation
+#
+# Redistribution and use in source and binary forms, with or without
+# modification, are permitted provided that the following conditions
+# are met:
+#
+#     * Redistributions of source code must retain the above copyright
+#       notice, this list of conditions and the following disclaimer.
+#
+#     * Redistributions in binary form must reproduce the above copyright
+#       notice, this list of conditions and the following disclaimer in
+#       the documentation and/or other materials provided with the
+#       distribution.
+#
+#     * Neither the name of Intel Corporation nor the names of its
+#       contributors may be used to endorse or promote products derived
+#       from this software without specific prior written permission.
+#
+# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+#
+
+#
+# src/test/pmem_is_pmem_proc/TEST3 -- unit test for pmem_is_pmem /proc parsing
+#
+export UNITTEST_NAME=pmem_is_pmem_proc/TEST3
+export UNITTEST_NUM=3
+
+# standard unit test setup
+. ../unittest/unittest.sh
+
+require_fs_type local
+
+setup
+
+# 7fff77424000 2147479552
+#	exactly matches smaps second mm entry, should produce: 0
+# 7fff77424000 8192
+#	entirely encompassed by smaps second mm entry, should produce: 0
+# 7fff77423000 8192
+#	start at smaps first mm entry, extends into second: should produce: 0
+# 7fff77423000 4096
+#	exactly matches smaps first mm entry, should produce: 0
+expect_normal_exit ./pmem_is_pmem_proc$EXESUFFIX smaps_no_mm\
+	7fff77424000 2147479552\
+	7fff77424000 8192\
+	7fff77423000 8192\
+	7fff77423000 4096
+
+check
+
+pass
diff --git a/src/test/pmem_is_pmem_proc/TEST4 b/src/test/pmem_is_pmem_proc/TEST4
new file mode 100755
index 0000000000000000000000000000000000000000..1da91154a52b76ead291c37e9e44ef2144d6f76b
--- /dev/null
+++ b/src/test/pmem_is_pmem_proc/TEST4
@@ -0,0 +1,63 @@
+#!/bin/bash -e
+#
+# Copyright (c) 2014, Intel Corporation
+#
+# Redistribution and use in source and binary forms, with or without
+# modification, are permitted provided that the following conditions
+# are met:
+#
+#     * Redistributions of source code must retain the above copyright
+#       notice, this list of conditions and the following disclaimer.
+#
+#     * Redistributions in binary form must reproduce the above copyright
+#       notice, this list of conditions and the following disclaimer in
+#       the documentation and/or other materials provided with the
+#       distribution.
+#
+#     * Neither the name of Intel Corporation nor the names of its
+#       contributors may be used to endorse or promote products derived
+#       from this software without specific prior written permission.
+#
+# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+#
+
+#
+# src/test/pmem_is_pmem_proc/TEST4 -- unit test for pmem_is_pmem /proc parsing
+#
+export UNITTEST_NAME=pmem_is_pmem_proc/TEST4
+export UNITTEST_NUM=4
+
+# standard unit test setup
+. ../unittest/unittest.sh
+
+require_fs_type local
+
+setup
+
+# 7fff77424000 2147479552
+#	exactly matches smaps second mm entry, should produce: 0
+# 7fff77424000 8192
+#	entirely encompassed by smaps second mm entry, should produce: 0
+# 7fff77423000 8192
+#	start at smaps first mm entry, extends into second: should produce: 0
+# 7fff77423000 4096
+#	exactly matches smaps first mm entry, should produce: 0
+expect_normal_exit ./pmem_is_pmem_proc$EXESUFFIX smaps_no_vmflags\
+	7fff77424000 2147479552\
+	7fff77424000 8192\
+	7fff77423000 8192\
+	7fff77423000 4096
+
+check
+
+pass
diff --git a/src/test/pmem_is_pmem_proc/TEST5 b/src/test/pmem_is_pmem_proc/TEST5
new file mode 100755
index 0000000000000000000000000000000000000000..7261abd07af7ac2879b7e3431185f9f4ce5ee348
--- /dev/null
+++ b/src/test/pmem_is_pmem_proc/TEST5
@@ -0,0 +1,63 @@
+#!/bin/bash -e
+#
+# Copyright (c) 2014, Intel Corporation
+#
+# Redistribution and use in source and binary forms, with or without
+# modification, are permitted provided that the following conditions
+# are met:
+#
+#     * Redistributions of source code must retain the above copyright
+#       notice, this list of conditions and the following disclaimer.
+#
+#     * Redistributions in binary form must reproduce the above copyright
+#       notice, this list of conditions and the following disclaimer in
+#       the documentation and/or other materials provided with the
+#       distribution.
+#
+#     * Neither the name of Intel Corporation nor the names of its
+#       contributors may be used to endorse or promote products derived
+#       from this software without specific prior written permission.
+#
+# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+#
+
+#
+# src/test/pmem_is_pmem_proc/TEST5 -- unit test for pmem_is_pmem /proc parsing
+#
+export UNITTEST_NAME=pmem_is_pmem_proc/TEST5
+export UNITTEST_NUM=5
+
+# standard unit test setup
+. ../unittest/unittest.sh
+
+require_fs_type local
+
+setup
+
+# 7fff77424000 2147479552
+#	exactly matches smaps second mm entry, should produce: 1
+# 7fff77424000 8192
+#	entirely encompassed by smaps second mm entry, should produce: 1
+# 7fff77423000 8192
+#	start at smaps first mm entry, extends into second: should produce: 0
+# 7fff77423000 4096
+#	exactly matches smaps first mm entry, should produce: 0
+expect_normal_exit ./pmem_is_pmem_proc$EXESUFFIX smaps_unexp_vmflags\
+	7fff77424000 2147479552\
+	7fff77424000 8192\
+	7fff77423000 8192\
+	7fff77423000 4096
+
+check
+
+pass
diff --git a/src/test/pmem_is_pmem_proc/err0.log.match b/src/test/pmem_is_pmem_proc/err0.log.match
new file mode 100644
index 0000000000000000000000000000000000000000..e69de29bb2d1d6434b8b29ae775ad8c2e48c5391
diff --git a/src/test/pmem_is_pmem_proc/err1.log.match b/src/test/pmem_is_pmem_proc/err1.log.match
new file mode 100644
index 0000000000000000000000000000000000000000..e69de29bb2d1d6434b8b29ae775ad8c2e48c5391
diff --git a/src/test/pmem_is_pmem_proc/err2.log.match b/src/test/pmem_is_pmem_proc/err2.log.match
new file mode 100644
index 0000000000000000000000000000000000000000..e69de29bb2d1d6434b8b29ae775ad8c2e48c5391
diff --git a/src/test/pmem_is_pmem_proc/err3.log.match b/src/test/pmem_is_pmem_proc/err3.log.match
new file mode 100644
index 0000000000000000000000000000000000000000..e69de29bb2d1d6434b8b29ae775ad8c2e48c5391
diff --git a/src/test/pmem_is_pmem_proc/err4.log.match b/src/test/pmem_is_pmem_proc/err4.log.match
new file mode 100644
index 0000000000000000000000000000000000000000..e69de29bb2d1d6434b8b29ae775ad8c2e48c5391
diff --git a/src/test/pmem_is_pmem_proc/err5.log.match b/src/test/pmem_is_pmem_proc/err5.log.match
new file mode 100644
index 0000000000000000000000000000000000000000..e69de29bb2d1d6434b8b29ae775ad8c2e48c5391
diff --git a/src/test/pmem_is_pmem_proc/out0.log.match b/src/test/pmem_is_pmem_proc/out0.log.match
new file mode 100644
index 0000000000000000000000000000000000000000..db4a821242739e8ad6ad5f8d5014a5ae164c3947
--- /dev/null
+++ b/src/test/pmem_is_pmem_proc/out0.log.match
@@ -0,0 +1,13 @@
+pmem_is_pmem_proc/TEST0: START: pmem_is_pmem_proc
+ ./pmem_is_pmem_proc$(*) smaps_mm_both 7fff77424000 2147479552 7fff77424000 2147479553 7fff77424000 8192 7fff77423000 8192 7fff77423000 2147483648
+redirecting /proc/self/smaps to smaps_mm_both
+addr 0x7fff77424000, len 2147479552: 1
+redirecting /proc/self/smaps to smaps_mm_both
+addr 0x7fff77424000, len 2147479553: 0
+redirecting /proc/self/smaps to smaps_mm_both
+addr 0x7fff77424000, len 8192: 1
+redirecting /proc/self/smaps to smaps_mm_both
+addr 0x7fff77423000, len 8192: 1
+redirecting /proc/self/smaps to smaps_mm_both
+addr 0x7fff77423000, len 2147483648: 1
+pmem_is_pmem_proc/TEST0: Done
diff --git a/src/test/pmem_is_pmem_proc/out1.log.match b/src/test/pmem_is_pmem_proc/out1.log.match
new file mode 100644
index 0000000000000000000000000000000000000000..8260536e4067df7783396f58b05fdad6a5ba8767
--- /dev/null
+++ b/src/test/pmem_is_pmem_proc/out1.log.match
@@ -0,0 +1,9 @@
+pmem_is_pmem_proc/TEST1: START: pmem_is_pmem_proc
+ ./pmem_is_pmem_proc$(*) smaps_mm_first 7fff77424000 2147479552 7fff77423000 8192 7fff77423000 4096
+redirecting /proc/self/smaps to smaps_mm_first
+addr 0x7fff77424000, len 2147479552: 0
+redirecting /proc/self/smaps to smaps_mm_first
+addr 0x7fff77423000, len 8192: 0
+redirecting /proc/self/smaps to smaps_mm_first
+addr 0x7fff77423000, len 4096: 1
+pmem_is_pmem_proc/TEST1: Done
diff --git a/src/test/pmem_is_pmem_proc/out2.log.match b/src/test/pmem_is_pmem_proc/out2.log.match
new file mode 100644
index 0000000000000000000000000000000000000000..970f6ff4689f3223224bf7e4f9f6ed12e54ffe22
--- /dev/null
+++ b/src/test/pmem_is_pmem_proc/out2.log.match
@@ -0,0 +1,11 @@
+pmem_is_pmem_proc/TEST2: START: pmem_is_pmem_proc
+ ./pmem_is_pmem_proc$(*) smaps_mm_second 7fff77424000 2147479552 7fff77428000 10240 7fff77424000 2147479553 7fff77423000 8192
+redirecting /proc/self/smaps to smaps_mm_second
+addr 0x7fff77424000, len 2147479552: 1
+redirecting /proc/self/smaps to smaps_mm_second
+addr 0x7fff77428000, len 10240: 1
+redirecting /proc/self/smaps to smaps_mm_second
+addr 0x7fff77424000, len 2147479553: 0
+redirecting /proc/self/smaps to smaps_mm_second
+addr 0x7fff77423000, len 8192: 0
+pmem_is_pmem_proc/TEST2: Done
diff --git a/src/test/pmem_is_pmem_proc/out3.log.match b/src/test/pmem_is_pmem_proc/out3.log.match
new file mode 100644
index 0000000000000000000000000000000000000000..678df21bc7f8e3a2711576d0b7d89d0d89e25082
--- /dev/null
+++ b/src/test/pmem_is_pmem_proc/out3.log.match
@@ -0,0 +1,11 @@
+pmem_is_pmem_proc/TEST3: START: pmem_is_pmem_proc
+ ./pmem_is_pmem_proc$(*) smaps_no_mm 7fff77424000 2147479552 7fff77424000 8192 7fff77423000 8192 7fff77423000 4096
+redirecting /proc/self/smaps to smaps_no_mm
+addr 0x7fff77424000, len 2147479552: 0
+redirecting /proc/self/smaps to smaps_no_mm
+addr 0x7fff77424000, len 8192: 0
+redirecting /proc/self/smaps to smaps_no_mm
+addr 0x7fff77423000, len 8192: 0
+redirecting /proc/self/smaps to smaps_no_mm
+addr 0x7fff77423000, len 4096: 0
+pmem_is_pmem_proc/TEST3: Done
diff --git a/src/test/pmem_is_pmem_proc/out4.log.match b/src/test/pmem_is_pmem_proc/out4.log.match
new file mode 100644
index 0000000000000000000000000000000000000000..261ccee7db35df8037e9ec1f8905069887ef8b9a
--- /dev/null
+++ b/src/test/pmem_is_pmem_proc/out4.log.match
@@ -0,0 +1,11 @@
+pmem_is_pmem_proc/TEST4: START: pmem_is_pmem_proc
+ ./pmem_is_pmem_proc$(*) smaps_no_vmflags 7fff77424000 2147479552 7fff77424000 8192 7fff77423000 8192 7fff77423000 4096
+redirecting /proc/self/smaps to smaps_no_vmflags
+addr 0x7fff77424000, len 2147479552: 0
+redirecting /proc/self/smaps to smaps_no_vmflags
+addr 0x7fff77424000, len 8192: 0
+redirecting /proc/self/smaps to smaps_no_vmflags
+addr 0x7fff77423000, len 8192: 0
+redirecting /proc/self/smaps to smaps_no_vmflags
+addr 0x7fff77423000, len 4096: 0
+pmem_is_pmem_proc/TEST4: Done
diff --git a/src/test/pmem_is_pmem_proc/out5.log.match b/src/test/pmem_is_pmem_proc/out5.log.match
new file mode 100644
index 0000000000000000000000000000000000000000..289a73340d7ed8b94d9a64159aba9686b236512e
--- /dev/null
+++ b/src/test/pmem_is_pmem_proc/out5.log.match
@@ -0,0 +1,11 @@
+pmem_is_pmem_proc/TEST5: START: pmem_is_pmem_proc
+ ./pmem_is_pmem_proc$(*) smaps_unexp_vmflags 7fff77424000 2147479552 7fff77424000 8192 7fff77423000 8192 7fff77423000 4096
+redirecting /proc/self/smaps to smaps_unexp_vmflags
+addr 0x7fff77424000, len 2147479552: 1
+redirecting /proc/self/smaps to smaps_unexp_vmflags
+addr 0x7fff77424000, len 8192: 1
+redirecting /proc/self/smaps to smaps_unexp_vmflags
+addr 0x7fff77423000, len 8192: 0
+redirecting /proc/self/smaps to smaps_unexp_vmflags
+addr 0x7fff77423000, len 4096: 0
+pmem_is_pmem_proc/TEST5: Done
diff --git a/src/test/pmem_is_pmem_proc/pmem_is_pmem_proc.c b/src/test/pmem_is_pmem_proc/pmem_is_pmem_proc.c
new file mode 100644
index 0000000000000000000000000000000000000000..80bc291ec590c7fc48bd6039b84965fb9561eaae
--- /dev/null
+++ b/src/test/pmem_is_pmem_proc/pmem_is_pmem_proc.c
@@ -0,0 +1,88 @@
+/*
+ * Copyright (c) 2014, Intel Corporation
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ *     * Redistributions of source code must retain the above copyright
+ *       notice, this list of conditions and the following disclaimer.
+ *
+ *     * Redistributions in binary form must reproduce the above copyright
+ *       notice, this list of conditions and the following disclaimer in
+ *       the documentation and/or other materials provided with the
+ *       distribution.
+ *
+ *     * Neither the name of Intel Corporation nor the names of its
+ *       contributors may be used to endorse or promote products derived
+ *       from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+/*
+ * pmem_is_pmem_proc.c -- unit test for pmem_is_pmem() /proc parsing
+ *
+ * usage: pmem_is_pmem_proc file addr len [addr len]...
+ */
+
+#define	_GNU_SOURCE
+#include "unittest.h"
+
+#include <dlfcn.h>
+
+char *Sfile;
+
+/*
+ * fopen -- interpose on libc fopen()
+ *
+ * This catches opens to /proc/self/smaps and sends them to the fake smaps
+ * file being tested.
+ */
+FILE *
+fopen(const char *path, const char *mode)
+{
+	static FILE *(*fopen_ptr)(const char *path, const char *mode);
+
+	if (strcmp(path, "/proc/self/smaps") == 0) {
+		OUT("redirecting /proc/self/smaps to %s", Sfile);
+		path = Sfile;
+	}
+
+	if (fopen_ptr == NULL)
+		fopen_ptr = dlsym(RTLD_NEXT, "fopen");
+
+	return (*fopen_ptr)(path, mode);
+}
+
+int
+main(int argc, char *argv[])
+{
+	START(argc, argv, "pmem_is_pmem_proc");
+
+	if (argc < 4 || argc % 2)
+		FATAL("usage: %s file addr len [addr len]...", argv[0]);
+
+	Sfile = argv[1];
+
+	for (int arg = 2; arg < argc; arg += 2) {
+		void *addr;
+		size_t len;
+
+		addr = (void *)strtoull(argv[arg], NULL, 16);
+		len = (size_t)strtoull(argv[arg + 1], NULL, 10);
+		OUT("addr %p, len %zu: %d", addr, len, pmem_is_pmem(addr, len));
+	}
+
+	DONE(NULL);
+}
diff --git a/src/test/pmem_is_pmem_proc/smaps_mm_both b/src/test/pmem_is_pmem_proc/smaps_mm_both
new file mode 100644
index 0000000000000000000000000000000000000000..85c1a3551fa44df80b80aea9c968e9e5811cac22
--- /dev/null
+++ b/src/test/pmem_is_pmem_proc/smaps_mm_both
@@ -0,0 +1,482 @@
+00400000-00406000 r-xp 00000000 08:01 2366593                            /some/path/src/test/pmem_map/pmem_map
+Size:                 24 kB
+Rss:                  20 kB
+Pss:                  20 kB
+Shared_Clean:          0 kB
+Shared_Dirty:          0 kB
+Private_Clean:        16 kB
+Private_Dirty:         4 kB
+Referenced:           20 kB
+Anonymous:             4 kB
+AnonHugePages:         0 kB
+Swap:                  0 kB
+KernelPageSize:        4 kB
+MMUPageSize:           4 kB
+Locked:                0 kB
+00605000-00606000 rw-p 00005000 08:01 2366593                            /some/path/src/test/pmem_map/pmem_map
+Size:                  4 kB
+Rss:                   4 kB
+Pss:                   4 kB
+Shared_Clean:          0 kB
+Shared_Dirty:          0 kB
+Private_Clean:         0 kB
+Private_Dirty:         4 kB
+Referenced:            4 kB
+Anonymous:             4 kB
+AnonHugePages:         0 kB
+Swap:                  0 kB
+KernelPageSize:        4 kB
+MMUPageSize:           4 kB
+Locked:                0 kB
+00606000-00627000 rw-p 00000000 00:00 0                                  [heap]
+Size:                132 kB
+Rss:                   8 kB
+Pss:                   8 kB
+Shared_Clean:          0 kB
+Shared_Dirty:          0 kB
+Private_Clean:         0 kB
+Private_Dirty:         8 kB
+Referenced:            8 kB
+Anonymous:             8 kB
+AnonHugePages:         0 kB
+Swap:                  0 kB
+KernelPageSize:        4 kB
+MMUPageSize:           4 kB
+Locked:                0 kB
+7fff77423000-7fff77424000 ---s 00000000 08:01 2366604                    /some/path/src/test/pmem_map/testfile1
+Size:                  4 kB
+Rss:                   4 kB
+Pss:                   4 kB
+Shared_Clean:          0 kB
+Shared_Dirty:          0 kB
+Private_Clean:         4 kB
+Private_Dirty:         0 kB
+Referenced:            4 kB
+Anonymous:             0 kB
+AnonHugePages:         0 kB
+Swap:                  0 kB
+KernelPageSize:        4 kB
+MMUPageSize:           4 kB
+Locked:                0 kB
+VmFlags: rd ex mm mr mw me dw sd 
+7fff77424000-7ffff7423000 r--s 00001000 08:01 2366604                    /some/path/src/test/pmem_map/testfile1
+Size:            2097148 kB
+Rss:                   4 kB
+Pss:                   4 kB
+Shared_Clean:          0 kB
+Shared_Dirty:          0 kB
+Private_Clean:         4 kB
+Private_Dirty:         0 kB
+Referenced:            4 kB
+Anonymous:             0 kB
+AnonHugePages:         0 kB
+Swap:                  0 kB
+KernelPageSize:        4 kB
+MMUPageSize:           4 kB
+Locked:                0 kB
+VmFlags: rd ex mm mr mw me dw sd 
+7ffff7423000-7ffff75a5000 r-xp 00000000 08:01 1844444                    /lib/x86_64-linux-gnu/libc-2.13.so
+Size:               1544 kB
+Rss:                 364 kB
+Pss:                  53 kB
+Shared_Clean:        360 kB
+Shared_Dirty:          0 kB
+Private_Clean:         0 kB
+Private_Dirty:         4 kB
+Referenced:          364 kB
+Anonymous:             4 kB
+AnonHugePages:         0 kB
+Swap:                  0 kB
+KernelPageSize:        4 kB
+MMUPageSize:           4 kB
+Locked:                0 kB
+7ffff75a5000-7ffff77a4000 ---p 00182000 08:01 1844444                    /lib/x86_64-linux-gnu/libc-2.13.so
+Size:               2044 kB
+Rss:                   0 kB
+Pss:                   0 kB
+Shared_Clean:          0 kB
+Shared_Dirty:          0 kB
+Private_Clean:         0 kB
+Private_Dirty:         0 kB
+Referenced:            0 kB
+Anonymous:             0 kB
+AnonHugePages:         0 kB
+Swap:                  0 kB
+KernelPageSize:        4 kB
+MMUPageSize:           4 kB
+Locked:                0 kB
+7ffff77a4000-7ffff77a8000 r--p 00181000 08:01 1844444                    /lib/x86_64-linux-gnu/libc-2.13.so
+Size:                 16 kB
+Rss:                  16 kB
+Pss:                  16 kB
+Shared_Clean:          0 kB
+Shared_Dirty:          0 kB
+Private_Clean:         0 kB
+Private_Dirty:        16 kB
+Referenced:           16 kB
+Anonymous:            16 kB
+AnonHugePages:         0 kB
+Swap:                  0 kB
+KernelPageSize:        4 kB
+MMUPageSize:           4 kB
+Locked:                0 kB
+7ffff77a8000-7ffff77a9000 rw-p 00185000 08:01 1844444                    /lib/x86_64-linux-gnu/libc-2.13.so
+Size:                  4 kB
+Rss:                   4 kB
+Pss:                   4 kB
+Shared_Clean:          0 kB
+Shared_Dirty:          0 kB
+Private_Clean:         0 kB
+Private_Dirty:         4 kB
+Referenced:            4 kB
+Anonymous:             4 kB
+AnonHugePages:         0 kB
+Swap:                  0 kB
+KernelPageSize:        4 kB
+MMUPageSize:           4 kB
+Locked:                0 kB
+7ffff77a9000-7ffff77ae000 rw-p 00000000 00:00 0 
+Size:                 20 kB
+Rss:                  16 kB
+Pss:                  16 kB
+Shared_Clean:          0 kB
+Shared_Dirty:          0 kB
+Private_Clean:         0 kB
+Private_Dirty:        16 kB
+Referenced:           16 kB
+Anonymous:            16 kB
+AnonHugePages:         0 kB
+Swap:                  0 kB
+KernelPageSize:        4 kB
+MMUPageSize:           4 kB
+Locked:                0 kB
+7ffff77ae000-7ffff77c5000 r-xp 00000000 08:01 1845832                    /lib/x86_64-linux-gnu/libpthread-2.13.so
+Size:                 92 kB
+Rss:                  52 kB
+Pss:                  14 kB
+Shared_Clean:         44 kB
+Shared_Dirty:          0 kB
+Private_Clean:         0 kB
+Private_Dirty:         8 kB
+Referenced:           52 kB
+Anonymous:             8 kB
+AnonHugePages:         0 kB
+Swap:                  0 kB
+KernelPageSize:        4 kB
+MMUPageSize:           4 kB
+Locked:                0 kB
+7ffff77c5000-7ffff79c4000 ---p 00017000 08:01 1845832                    /lib/x86_64-linux-gnu/libpthread-2.13.so
+Size:               2044 kB
+Rss:                   0 kB
+Pss:                   0 kB
+Shared_Clean:          0 kB
+Shared_Dirty:          0 kB
+Private_Clean:         0 kB
+Private_Dirty:         0 kB
+Referenced:            0 kB
+Anonymous:             0 kB
+AnonHugePages:         0 kB
+Swap:                  0 kB
+KernelPageSize:        4 kB
+MMUPageSize:           4 kB
+Locked:                0 kB
+7ffff79c4000-7ffff79c5000 r--p 00016000 08:01 1845832                    /lib/x86_64-linux-gnu/libpthread-2.13.so
+Size:                  4 kB
+Rss:                   4 kB
+Pss:                   4 kB
+Shared_Clean:          0 kB
+Shared_Dirty:          0 kB
+Private_Clean:         0 kB
+Private_Dirty:         4 kB
+Referenced:            4 kB
+Anonymous:             4 kB
+AnonHugePages:         0 kB
+Swap:                  0 kB
+KernelPageSize:        4 kB
+MMUPageSize:           4 kB
+Locked:                0 kB
+7ffff79c5000-7ffff79c6000 rw-p 00017000 08:01 1845832                    /lib/x86_64-linux-gnu/libpthread-2.13.so
+Size:                  4 kB
+Rss:                   4 kB
+Pss:                   4 kB
+Shared_Clean:          0 kB
+Shared_Dirty:          0 kB
+Private_Clean:         0 kB
+Private_Dirty:         4 kB
+Referenced:            4 kB
+Anonymous:             4 kB
+AnonHugePages:         0 kB
+Swap:                  0 kB
+KernelPageSize:        4 kB
+MMUPageSize:           4 kB
+Locked:                0 kB
+7ffff79c6000-7ffff79ca000 rw-p 00000000 00:00 0 
+Size:                 16 kB
+Rss:                   4 kB
+Pss:                   4 kB
+Shared_Clean:          0 kB
+Shared_Dirty:          0 kB
+Private_Clean:         0 kB
+Private_Dirty:         4 kB
+Referenced:            4 kB
+Anonymous:             4 kB
+AnonHugePages:         0 kB
+Swap:                  0 kB
+KernelPageSize:        4 kB
+MMUPageSize:           4 kB
+Locked:                0 kB
+7ffff79ca000-7ffff79d7000 r-xp 00000000 08:01 2366292                    /some/path/src/debug/libpmem.so
+Size:                 52 kB
+Rss:                  28 kB
+Pss:                  28 kB
+Shared_Clean:          0 kB
+Shared_Dirty:          0 kB
+Private_Clean:        28 kB
+Private_Dirty:         0 kB
+Referenced:           28 kB
+Anonymous:             0 kB
+AnonHugePages:         0 kB
+Swap:                  0 kB
+KernelPageSize:        4 kB
+MMUPageSize:           4 kB
+Locked:                0 kB
+7ffff79d7000-7ffff7bd6000 ---p 0000d000 08:01 2366292                    /some/path/src/debug/libpmem.so
+Size:               2044 kB
+Rss:                   0 kB
+Pss:                   0 kB
+Shared_Clean:          0 kB
+Shared_Dirty:          0 kB
+Private_Clean:         0 kB
+Private_Dirty:         0 kB
+Referenced:            0 kB
+Anonymous:             0 kB
+AnonHugePages:         0 kB
+Swap:                  0 kB
+KernelPageSize:        4 kB
+MMUPageSize:           4 kB
+Locked:                0 kB
+7ffff7bd6000-7ffff7bd7000 rw-p 0000c000 08:01 2366292                    /some/path/src/debug/libpmem.so
+Size:                  4 kB
+Rss:                   4 kB
+Pss:                   4 kB
+Shared_Clean:          0 kB
+Shared_Dirty:          0 kB
+Private_Clean:         0 kB
+Private_Dirty:         4 kB
+Referenced:            4 kB
+Anonymous:             4 kB
+AnonHugePages:         0 kB
+Swap:                  0 kB
+KernelPageSize:        4 kB
+MMUPageSize:           4 kB
+Locked:                0 kB
+7ffff7bd7000-7ffff7bd8000 rw-p 00000000 00:00 0 
+Size:                  4 kB
+Rss:                   4 kB
+Pss:                   4 kB
+Shared_Clean:          0 kB
+Shared_Dirty:          0 kB
+Private_Clean:         0 kB
+Private_Dirty:         4 kB
+Referenced:            4 kB
+Anonymous:             4 kB
+AnonHugePages:         0 kB
+Swap:                  0 kB
+KernelPageSize:        4 kB
+MMUPageSize:           4 kB
+Locked:                0 kB
+7ffff7bd8000-7ffff7bdc000 r-xp 00000000 08:01 1835968                    /lib/x86_64-linux-gnu/libuuid.so.1.3.0
+Size:                 16 kB
+Rss:                  12 kB
+Pss:                  12 kB
+Shared_Clean:          0 kB
+Shared_Dirty:          0 kB
+Private_Clean:        12 kB
+Private_Dirty:         0 kB
+Referenced:           12 kB
+Anonymous:             0 kB
+AnonHugePages:         0 kB
+Swap:                  0 kB
+KernelPageSize:        4 kB
+MMUPageSize:           4 kB
+Locked:                0 kB
+7ffff7bdc000-7ffff7ddb000 ---p 00004000 08:01 1835968                    /lib/x86_64-linux-gnu/libuuid.so.1.3.0
+Size:               2044 kB
+Rss:                   0 kB
+Pss:                   0 kB
+Shared_Clean:          0 kB
+Shared_Dirty:          0 kB
+Private_Clean:         0 kB
+Private_Dirty:         0 kB
+Referenced:            0 kB
+Anonymous:             0 kB
+AnonHugePages:         0 kB
+Swap:                  0 kB
+KernelPageSize:        4 kB
+MMUPageSize:           4 kB
+Locked:                0 kB
+7ffff7ddb000-7ffff7ddc000 r--p 00003000 08:01 1835968                    /lib/x86_64-linux-gnu/libuuid.so.1.3.0
+Size:                  4 kB
+Rss:                   4 kB
+Pss:                   4 kB
+Shared_Clean:          0 kB
+Shared_Dirty:          0 kB
+Private_Clean:         0 kB
+Private_Dirty:         4 kB
+Referenced:            4 kB
+Anonymous:             4 kB
+AnonHugePages:         0 kB
+Swap:                  0 kB
+KernelPageSize:        4 kB
+MMUPageSize:           4 kB
+Locked:                0 kB
+7ffff7ddc000-7ffff7ddd000 rw-p 00004000 08:01 1835968                    /lib/x86_64-linux-gnu/libuuid.so.1.3.0
+Size:                  4 kB
+Rss:                   4 kB
+Pss:                   4 kB
+Shared_Clean:          0 kB
+Shared_Dirty:          0 kB
+Private_Clean:         0 kB
+Private_Dirty:         4 kB
+Referenced:            4 kB
+Anonymous:             4 kB
+AnonHugePages:         0 kB
+Swap:                  0 kB
+KernelPageSize:        4 kB
+MMUPageSize:           4 kB
+Locked:                0 kB
+7ffff7ddd000-7ffff7dfd000 r-xp 00000000 08:01 1844132                    /lib/x86_64-linux-gnu/ld-2.13.so
+Size:                128 kB
+Rss:                 108 kB
+Pss:                  33 kB
+Shared_Clean:        104 kB
+Shared_Dirty:          0 kB
+Private_Clean:         0 kB
+Private_Dirty:         4 kB
+Referenced:          108 kB
+Anonymous:             4 kB
+AnonHugePages:         0 kB
+Swap:                  0 kB
+KernelPageSize:        4 kB
+MMUPageSize:           4 kB
+Locked:                0 kB
+7ffff7fe3000-7ffff7fe7000 rw-p 00000000 00:00 0 
+Size:                 16 kB
+Rss:                  16 kB
+Pss:                  16 kB
+Shared_Clean:          0 kB
+Shared_Dirty:          0 kB
+Private_Clean:         0 kB
+Private_Dirty:        16 kB
+Referenced:           16 kB
+Anonymous:            16 kB
+AnonHugePages:         0 kB
+Swap:                  0 kB
+KernelPageSize:        4 kB
+MMUPageSize:           4 kB
+Locked:                0 kB
+7ffff7ff6000-7ffff7ffb000 rw-p 00000000 00:00 0 
+Size:                 20 kB
+Rss:                  20 kB
+Pss:                  20 kB
+Shared_Clean:          0 kB
+Shared_Dirty:          0 kB
+Private_Clean:         0 kB
+Private_Dirty:        20 kB
+Referenced:           20 kB
+Anonymous:            20 kB
+AnonHugePages:         0 kB
+Swap:                  0 kB
+KernelPageSize:        4 kB
+MMUPageSize:           4 kB
+Locked:                0 kB
+7ffff7ffb000-7ffff7ffc000 r-xp 00000000 00:00 0                          [vdso]
+Size:                  4 kB
+Rss:                   4 kB
+Pss:                   0 kB
+Shared_Clean:          4 kB
+Shared_Dirty:          0 kB
+Private_Clean:         0 kB
+Private_Dirty:         0 kB
+Referenced:            4 kB
+Anonymous:             0 kB
+AnonHugePages:         0 kB
+Swap:                  0 kB
+KernelPageSize:        4 kB
+MMUPageSize:           4 kB
+Locked:                0 kB
+7ffff7ffc000-7ffff7ffd000 r--p 0001f000 08:01 1844132                    /lib/x86_64-linux-gnu/ld-2.13.so
+Size:                  4 kB
+Rss:                   4 kB
+Pss:                   4 kB
+Shared_Clean:          0 kB
+Shared_Dirty:          0 kB
+Private_Clean:         0 kB
+Private_Dirty:         4 kB
+Referenced:            4 kB
+Anonymous:             4 kB
+AnonHugePages:         0 kB
+Swap:                  0 kB
+KernelPageSize:        4 kB
+MMUPageSize:           4 kB
+Locked:                0 kB
+7ffff7ffd000-7ffff7ffe000 rw-p 00020000 08:01 1844132                    /lib/x86_64-linux-gnu/ld-2.13.so
+Size:                  4 kB
+Rss:                   4 kB
+Pss:                   4 kB
+Shared_Clean:          0 kB
+Shared_Dirty:          0 kB
+Private_Clean:         0 kB
+Private_Dirty:         4 kB
+Referenced:            4 kB
+Anonymous:             4 kB
+AnonHugePages:         0 kB
+Swap:                  0 kB
+KernelPageSize:        4 kB
+MMUPageSize:           4 kB
+Locked:                0 kB
+7ffff7ffe000-7ffff7fff000 rw-p 00000000 00:00 0 
+Size:                  4 kB
+Rss:                   4 kB
+Pss:                   4 kB
+Shared_Clean:          0 kB
+Shared_Dirty:          0 kB
+Private_Clean:         0 kB
+Private_Dirty:         4 kB
+Referenced:            4 kB
+Anonymous:             4 kB
+AnonHugePages:         0 kB
+Swap:                  0 kB
+KernelPageSize:        4 kB
+MMUPageSize:           4 kB
+Locked:                0 kB
+7ffffffde000-7ffffffff000 rw-p 00000000 00:00 0                          [stack]
+Size:                136 kB
+Rss:                  24 kB
+Pss:                  24 kB
+Shared_Clean:          0 kB
+Shared_Dirty:          0 kB
+Private_Clean:         0 kB
+Private_Dirty:        24 kB
+Referenced:           24 kB
+Anonymous:            24 kB
+AnonHugePages:         0 kB
+Swap:                  0 kB
+KernelPageSize:        4 kB
+MMUPageSize:           4 kB
+Locked:                0 kB
+ffffffffff600000-ffffffffff601000 r-xp 00000000 00:00 0                  [vsyscall]
+Size:                  4 kB
+Rss:                   0 kB
+Pss:                   0 kB
+Shared_Clean:          0 kB
+Shared_Dirty:          0 kB
+Private_Clean:         0 kB
+Private_Dirty:         0 kB
+Referenced:            0 kB
+Anonymous:             0 kB
+AnonHugePages:         0 kB
+Swap:                  0 kB
+KernelPageSize:        4 kB
+MMUPageSize:           4 kB
+Locked:                0 kB
diff --git a/src/test/pmem_is_pmem_proc/smaps_mm_first b/src/test/pmem_is_pmem_proc/smaps_mm_first
new file mode 100644
index 0000000000000000000000000000000000000000..e9e385982ab8b61d2754057c35f43a0b745ee7ff
--- /dev/null
+++ b/src/test/pmem_is_pmem_proc/smaps_mm_first
@@ -0,0 +1,482 @@
+00400000-00406000 r-xp 00000000 08:01 2366593                            /some/path/src/test/pmem_map/pmem_map
+Size:                 24 kB
+Rss:                  20 kB
+Pss:                  20 kB
+Shared_Clean:          0 kB
+Shared_Dirty:          0 kB
+Private_Clean:        16 kB
+Private_Dirty:         4 kB
+Referenced:           20 kB
+Anonymous:             4 kB
+AnonHugePages:         0 kB
+Swap:                  0 kB
+KernelPageSize:        4 kB
+MMUPageSize:           4 kB
+Locked:                0 kB
+00605000-00606000 rw-p 00005000 08:01 2366593                            /some/path/src/test/pmem_map/pmem_map
+Size:                  4 kB
+Rss:                   4 kB
+Pss:                   4 kB
+Shared_Clean:          0 kB
+Shared_Dirty:          0 kB
+Private_Clean:         0 kB
+Private_Dirty:         4 kB
+Referenced:            4 kB
+Anonymous:             4 kB
+AnonHugePages:         0 kB
+Swap:                  0 kB
+KernelPageSize:        4 kB
+MMUPageSize:           4 kB
+Locked:                0 kB
+00606000-00627000 rw-p 00000000 00:00 0                                  [heap]
+Size:                132 kB
+Rss:                   8 kB
+Pss:                   8 kB
+Shared_Clean:          0 kB
+Shared_Dirty:          0 kB
+Private_Clean:         0 kB
+Private_Dirty:         8 kB
+Referenced:            8 kB
+Anonymous:             8 kB
+AnonHugePages:         0 kB
+Swap:                  0 kB
+KernelPageSize:        4 kB
+MMUPageSize:           4 kB
+Locked:                0 kB
+7fff77423000-7fff77424000 ---s 00000000 08:01 2366604                    /some/path/src/test/pmem_map/testfile1
+Size:                  4 kB
+Rss:                   4 kB
+Pss:                   4 kB
+Shared_Clean:          0 kB
+Shared_Dirty:          0 kB
+Private_Clean:         4 kB
+Private_Dirty:         0 kB
+Referenced:            4 kB
+Anonymous:             0 kB
+AnonHugePages:         0 kB
+Swap:                  0 kB
+KernelPageSize:        4 kB
+MMUPageSize:           4 kB
+Locked:                0 kB
+VmFlags: rd ex mm mr mw me dw sd 
+7fff77424000-7ffff7423000 r--s 00001000 08:01 2366604                    /some/path/src/test/pmem_map/testfile1
+Size:            2097148 kB
+Rss:                   4 kB
+Pss:                   4 kB
+Shared_Clean:          0 kB
+Shared_Dirty:          0 kB
+Private_Clean:         4 kB
+Private_Dirty:         0 kB
+Referenced:            4 kB
+Anonymous:             0 kB
+AnonHugePages:         0 kB
+Swap:                  0 kB
+KernelPageSize:        4 kB
+MMUPageSize:           4 kB
+Locked:                0 kB
+VmFlags: rd ex mr mw me dw sd 
+7ffff7423000-7ffff75a5000 r-xp 00000000 08:01 1844444                    /lib/x86_64-linux-gnu/libc-2.13.so
+Size:               1544 kB
+Rss:                 364 kB
+Pss:                  53 kB
+Shared_Clean:        360 kB
+Shared_Dirty:          0 kB
+Private_Clean:         0 kB
+Private_Dirty:         4 kB
+Referenced:          364 kB
+Anonymous:             4 kB
+AnonHugePages:         0 kB
+Swap:                  0 kB
+KernelPageSize:        4 kB
+MMUPageSize:           4 kB
+Locked:                0 kB
+7ffff75a5000-7ffff77a4000 ---p 00182000 08:01 1844444                    /lib/x86_64-linux-gnu/libc-2.13.so
+Size:               2044 kB
+Rss:                   0 kB
+Pss:                   0 kB
+Shared_Clean:          0 kB
+Shared_Dirty:          0 kB
+Private_Clean:         0 kB
+Private_Dirty:         0 kB
+Referenced:            0 kB
+Anonymous:             0 kB
+AnonHugePages:         0 kB
+Swap:                  0 kB
+KernelPageSize:        4 kB
+MMUPageSize:           4 kB
+Locked:                0 kB
+7ffff77a4000-7ffff77a8000 r--p 00181000 08:01 1844444                    /lib/x86_64-linux-gnu/libc-2.13.so
+Size:                 16 kB
+Rss:                  16 kB
+Pss:                  16 kB
+Shared_Clean:          0 kB
+Shared_Dirty:          0 kB
+Private_Clean:         0 kB
+Private_Dirty:        16 kB
+Referenced:           16 kB
+Anonymous:            16 kB
+AnonHugePages:         0 kB
+Swap:                  0 kB
+KernelPageSize:        4 kB
+MMUPageSize:           4 kB
+Locked:                0 kB
+7ffff77a8000-7ffff77a9000 rw-p 00185000 08:01 1844444                    /lib/x86_64-linux-gnu/libc-2.13.so
+Size:                  4 kB
+Rss:                   4 kB
+Pss:                   4 kB
+Shared_Clean:          0 kB
+Shared_Dirty:          0 kB
+Private_Clean:         0 kB
+Private_Dirty:         4 kB
+Referenced:            4 kB
+Anonymous:             4 kB
+AnonHugePages:         0 kB
+Swap:                  0 kB
+KernelPageSize:        4 kB
+MMUPageSize:           4 kB
+Locked:                0 kB
+7ffff77a9000-7ffff77ae000 rw-p 00000000 00:00 0 
+Size:                 20 kB
+Rss:                  16 kB
+Pss:                  16 kB
+Shared_Clean:          0 kB
+Shared_Dirty:          0 kB
+Private_Clean:         0 kB
+Private_Dirty:        16 kB
+Referenced:           16 kB
+Anonymous:            16 kB
+AnonHugePages:         0 kB
+Swap:                  0 kB
+KernelPageSize:        4 kB
+MMUPageSize:           4 kB
+Locked:                0 kB
+7ffff77ae000-7ffff77c5000 r-xp 00000000 08:01 1845832                    /lib/x86_64-linux-gnu/libpthread-2.13.so
+Size:                 92 kB
+Rss:                  52 kB
+Pss:                  14 kB
+Shared_Clean:         44 kB
+Shared_Dirty:          0 kB
+Private_Clean:         0 kB
+Private_Dirty:         8 kB
+Referenced:           52 kB
+Anonymous:             8 kB
+AnonHugePages:         0 kB
+Swap:                  0 kB
+KernelPageSize:        4 kB
+MMUPageSize:           4 kB
+Locked:                0 kB
+7ffff77c5000-7ffff79c4000 ---p 00017000 08:01 1845832                    /lib/x86_64-linux-gnu/libpthread-2.13.so
+Size:               2044 kB
+Rss:                   0 kB
+Pss:                   0 kB
+Shared_Clean:          0 kB
+Shared_Dirty:          0 kB
+Private_Clean:         0 kB
+Private_Dirty:         0 kB
+Referenced:            0 kB
+Anonymous:             0 kB
+AnonHugePages:         0 kB
+Swap:                  0 kB
+KernelPageSize:        4 kB
+MMUPageSize:           4 kB
+Locked:                0 kB
+7ffff79c4000-7ffff79c5000 r--p 00016000 08:01 1845832                    /lib/x86_64-linux-gnu/libpthread-2.13.so
+Size:                  4 kB
+Rss:                   4 kB
+Pss:                   4 kB
+Shared_Clean:          0 kB
+Shared_Dirty:          0 kB
+Private_Clean:         0 kB
+Private_Dirty:         4 kB
+Referenced:            4 kB
+Anonymous:             4 kB
+AnonHugePages:         0 kB
+Swap:                  0 kB
+KernelPageSize:        4 kB
+MMUPageSize:           4 kB
+Locked:                0 kB
+7ffff79c5000-7ffff79c6000 rw-p 00017000 08:01 1845832                    /lib/x86_64-linux-gnu/libpthread-2.13.so
+Size:                  4 kB
+Rss:                   4 kB
+Pss:                   4 kB
+Shared_Clean:          0 kB
+Shared_Dirty:          0 kB
+Private_Clean:         0 kB
+Private_Dirty:         4 kB
+Referenced:            4 kB
+Anonymous:             4 kB
+AnonHugePages:         0 kB
+Swap:                  0 kB
+KernelPageSize:        4 kB
+MMUPageSize:           4 kB
+Locked:                0 kB
+7ffff79c6000-7ffff79ca000 rw-p 00000000 00:00 0 
+Size:                 16 kB
+Rss:                   4 kB
+Pss:                   4 kB
+Shared_Clean:          0 kB
+Shared_Dirty:          0 kB
+Private_Clean:         0 kB
+Private_Dirty:         4 kB
+Referenced:            4 kB
+Anonymous:             4 kB
+AnonHugePages:         0 kB
+Swap:                  0 kB
+KernelPageSize:        4 kB
+MMUPageSize:           4 kB
+Locked:                0 kB
+7ffff79ca000-7ffff79d7000 r-xp 00000000 08:01 2366292                    /some/path/src/debug/libpmem.so
+Size:                 52 kB
+Rss:                  28 kB
+Pss:                  28 kB
+Shared_Clean:          0 kB
+Shared_Dirty:          0 kB
+Private_Clean:        28 kB
+Private_Dirty:         0 kB
+Referenced:           28 kB
+Anonymous:             0 kB
+AnonHugePages:         0 kB
+Swap:                  0 kB
+KernelPageSize:        4 kB
+MMUPageSize:           4 kB
+Locked:                0 kB
+7ffff79d7000-7ffff7bd6000 ---p 0000d000 08:01 2366292                    /some/path/src/debug/libpmem.so
+Size:               2044 kB
+Rss:                   0 kB
+Pss:                   0 kB
+Shared_Clean:          0 kB
+Shared_Dirty:          0 kB
+Private_Clean:         0 kB
+Private_Dirty:         0 kB
+Referenced:            0 kB
+Anonymous:             0 kB
+AnonHugePages:         0 kB
+Swap:                  0 kB
+KernelPageSize:        4 kB
+MMUPageSize:           4 kB
+Locked:                0 kB
+7ffff7bd6000-7ffff7bd7000 rw-p 0000c000 08:01 2366292                    /some/path/src/debug/libpmem.so
+Size:                  4 kB
+Rss:                   4 kB
+Pss:                   4 kB
+Shared_Clean:          0 kB
+Shared_Dirty:          0 kB
+Private_Clean:         0 kB
+Private_Dirty:         4 kB
+Referenced:            4 kB
+Anonymous:             4 kB
+AnonHugePages:         0 kB
+Swap:                  0 kB
+KernelPageSize:        4 kB
+MMUPageSize:           4 kB
+Locked:                0 kB
+7ffff7bd7000-7ffff7bd8000 rw-p 00000000 00:00 0 
+Size:                  4 kB
+Rss:                   4 kB
+Pss:                   4 kB
+Shared_Clean:          0 kB
+Shared_Dirty:          0 kB
+Private_Clean:         0 kB
+Private_Dirty:         4 kB
+Referenced:            4 kB
+Anonymous:             4 kB
+AnonHugePages:         0 kB
+Swap:                  0 kB
+KernelPageSize:        4 kB
+MMUPageSize:           4 kB
+Locked:                0 kB
+7ffff7bd8000-7ffff7bdc000 r-xp 00000000 08:01 1835968                    /lib/x86_64-linux-gnu/libuuid.so.1.3.0
+Size:                 16 kB
+Rss:                  12 kB
+Pss:                  12 kB
+Shared_Clean:          0 kB
+Shared_Dirty:          0 kB
+Private_Clean:        12 kB
+Private_Dirty:         0 kB
+Referenced:           12 kB
+Anonymous:             0 kB
+AnonHugePages:         0 kB
+Swap:                  0 kB
+KernelPageSize:        4 kB
+MMUPageSize:           4 kB
+Locked:                0 kB
+7ffff7bdc000-7ffff7ddb000 ---p 00004000 08:01 1835968                    /lib/x86_64-linux-gnu/libuuid.so.1.3.0
+Size:               2044 kB
+Rss:                   0 kB
+Pss:                   0 kB
+Shared_Clean:          0 kB
+Shared_Dirty:          0 kB
+Private_Clean:         0 kB
+Private_Dirty:         0 kB
+Referenced:            0 kB
+Anonymous:             0 kB
+AnonHugePages:         0 kB
+Swap:                  0 kB
+KernelPageSize:        4 kB
+MMUPageSize:           4 kB
+Locked:                0 kB
+7ffff7ddb000-7ffff7ddc000 r--p 00003000 08:01 1835968                    /lib/x86_64-linux-gnu/libuuid.so.1.3.0
+Size:                  4 kB
+Rss:                   4 kB
+Pss:                   4 kB
+Shared_Clean:          0 kB
+Shared_Dirty:          0 kB
+Private_Clean:         0 kB
+Private_Dirty:         4 kB
+Referenced:            4 kB
+Anonymous:             4 kB
+AnonHugePages:         0 kB
+Swap:                  0 kB
+KernelPageSize:        4 kB
+MMUPageSize:           4 kB
+Locked:                0 kB
+7ffff7ddc000-7ffff7ddd000 rw-p 00004000 08:01 1835968                    /lib/x86_64-linux-gnu/libuuid.so.1.3.0
+Size:                  4 kB
+Rss:                   4 kB
+Pss:                   4 kB
+Shared_Clean:          0 kB
+Shared_Dirty:          0 kB
+Private_Clean:         0 kB
+Private_Dirty:         4 kB
+Referenced:            4 kB
+Anonymous:             4 kB
+AnonHugePages:         0 kB
+Swap:                  0 kB
+KernelPageSize:        4 kB
+MMUPageSize:           4 kB
+Locked:                0 kB
+7ffff7ddd000-7ffff7dfd000 r-xp 00000000 08:01 1844132                    /lib/x86_64-linux-gnu/ld-2.13.so
+Size:                128 kB
+Rss:                 108 kB
+Pss:                  33 kB
+Shared_Clean:        104 kB
+Shared_Dirty:          0 kB
+Private_Clean:         0 kB
+Private_Dirty:         4 kB
+Referenced:          108 kB
+Anonymous:             4 kB
+AnonHugePages:         0 kB
+Swap:                  0 kB
+KernelPageSize:        4 kB
+MMUPageSize:           4 kB
+Locked:                0 kB
+7ffff7fe3000-7ffff7fe7000 rw-p 00000000 00:00 0 
+Size:                 16 kB
+Rss:                  16 kB
+Pss:                  16 kB
+Shared_Clean:          0 kB
+Shared_Dirty:          0 kB
+Private_Clean:         0 kB
+Private_Dirty:        16 kB
+Referenced:           16 kB
+Anonymous:            16 kB
+AnonHugePages:         0 kB
+Swap:                  0 kB
+KernelPageSize:        4 kB
+MMUPageSize:           4 kB
+Locked:                0 kB
+7ffff7ff6000-7ffff7ffb000 rw-p 00000000 00:00 0 
+Size:                 20 kB
+Rss:                  20 kB
+Pss:                  20 kB
+Shared_Clean:          0 kB
+Shared_Dirty:          0 kB
+Private_Clean:         0 kB
+Private_Dirty:        20 kB
+Referenced:           20 kB
+Anonymous:            20 kB
+AnonHugePages:         0 kB
+Swap:                  0 kB
+KernelPageSize:        4 kB
+MMUPageSize:           4 kB
+Locked:                0 kB
+7ffff7ffb000-7ffff7ffc000 r-xp 00000000 00:00 0                          [vdso]
+Size:                  4 kB
+Rss:                   4 kB
+Pss:                   0 kB
+Shared_Clean:          4 kB
+Shared_Dirty:          0 kB
+Private_Clean:         0 kB
+Private_Dirty:         0 kB
+Referenced:            4 kB
+Anonymous:             0 kB
+AnonHugePages:         0 kB
+Swap:                  0 kB
+KernelPageSize:        4 kB
+MMUPageSize:           4 kB
+Locked:                0 kB
+7ffff7ffc000-7ffff7ffd000 r--p 0001f000 08:01 1844132                    /lib/x86_64-linux-gnu/ld-2.13.so
+Size:                  4 kB
+Rss:                   4 kB
+Pss:                   4 kB
+Shared_Clean:          0 kB
+Shared_Dirty:          0 kB
+Private_Clean:         0 kB
+Private_Dirty:         4 kB
+Referenced:            4 kB
+Anonymous:             4 kB
+AnonHugePages:         0 kB
+Swap:                  0 kB
+KernelPageSize:        4 kB
+MMUPageSize:           4 kB
+Locked:                0 kB
+7ffff7ffd000-7ffff7ffe000 rw-p 00020000 08:01 1844132                    /lib/x86_64-linux-gnu/ld-2.13.so
+Size:                  4 kB
+Rss:                   4 kB
+Pss:                   4 kB
+Shared_Clean:          0 kB
+Shared_Dirty:          0 kB
+Private_Clean:         0 kB
+Private_Dirty:         4 kB
+Referenced:            4 kB
+Anonymous:             4 kB
+AnonHugePages:         0 kB
+Swap:                  0 kB
+KernelPageSize:        4 kB
+MMUPageSize:           4 kB
+Locked:                0 kB
+7ffff7ffe000-7ffff7fff000 rw-p 00000000 00:00 0 
+Size:                  4 kB
+Rss:                   4 kB
+Pss:                   4 kB
+Shared_Clean:          0 kB
+Shared_Dirty:          0 kB
+Private_Clean:         0 kB
+Private_Dirty:         4 kB
+Referenced:            4 kB
+Anonymous:             4 kB
+AnonHugePages:         0 kB
+Swap:                  0 kB
+KernelPageSize:        4 kB
+MMUPageSize:           4 kB
+Locked:                0 kB
+7ffffffde000-7ffffffff000 rw-p 00000000 00:00 0                          [stack]
+Size:                136 kB
+Rss:                  24 kB
+Pss:                  24 kB
+Shared_Clean:          0 kB
+Shared_Dirty:          0 kB
+Private_Clean:         0 kB
+Private_Dirty:        24 kB
+Referenced:           24 kB
+Anonymous:            24 kB
+AnonHugePages:         0 kB
+Swap:                  0 kB
+KernelPageSize:        4 kB
+MMUPageSize:           4 kB
+Locked:                0 kB
+ffffffffff600000-ffffffffff601000 r-xp 00000000 00:00 0                  [vsyscall]
+Size:                  4 kB
+Rss:                   0 kB
+Pss:                   0 kB
+Shared_Clean:          0 kB
+Shared_Dirty:          0 kB
+Private_Clean:         0 kB
+Private_Dirty:         0 kB
+Referenced:            0 kB
+Anonymous:             0 kB
+AnonHugePages:         0 kB
+Swap:                  0 kB
+KernelPageSize:        4 kB
+MMUPageSize:           4 kB
+Locked:                0 kB
diff --git a/src/test/pmem_is_pmem_proc/smaps_mm_second b/src/test/pmem_is_pmem_proc/smaps_mm_second
new file mode 100644
index 0000000000000000000000000000000000000000..41240eb25c65248fe63601361e331c99ceaff6ab
--- /dev/null
+++ b/src/test/pmem_is_pmem_proc/smaps_mm_second
@@ -0,0 +1,482 @@
+00400000-00406000 r-xp 00000000 08:01 2366593                            /some/path/src/test/pmem_map/pmem_map
+Size:                 24 kB
+Rss:                  20 kB
+Pss:                  20 kB
+Shared_Clean:          0 kB
+Shared_Dirty:          0 kB
+Private_Clean:        16 kB
+Private_Dirty:         4 kB
+Referenced:           20 kB
+Anonymous:             4 kB
+AnonHugePages:         0 kB
+Swap:                  0 kB
+KernelPageSize:        4 kB
+MMUPageSize:           4 kB
+Locked:                0 kB
+00605000-00606000 rw-p 00005000 08:01 2366593                            /some/path/src/test/pmem_map/pmem_map
+Size:                  4 kB
+Rss:                   4 kB
+Pss:                   4 kB
+Shared_Clean:          0 kB
+Shared_Dirty:          0 kB
+Private_Clean:         0 kB
+Private_Dirty:         4 kB
+Referenced:            4 kB
+Anonymous:             4 kB
+AnonHugePages:         0 kB
+Swap:                  0 kB
+KernelPageSize:        4 kB
+MMUPageSize:           4 kB
+Locked:                0 kB
+00606000-00627000 rw-p 00000000 00:00 0                                  [heap]
+Size:                132 kB
+Rss:                   8 kB
+Pss:                   8 kB
+Shared_Clean:          0 kB
+Shared_Dirty:          0 kB
+Private_Clean:         0 kB
+Private_Dirty:         8 kB
+Referenced:            8 kB
+Anonymous:             8 kB
+AnonHugePages:         0 kB
+Swap:                  0 kB
+KernelPageSize:        4 kB
+MMUPageSize:           4 kB
+Locked:                0 kB
+7fff77423000-7fff77424000 ---s 00000000 08:01 2366604                    /some/path/src/test/pmem_map/testfile1
+Size:                  4 kB
+Rss:                   4 kB
+Pss:                   4 kB
+Shared_Clean:          0 kB
+Shared_Dirty:          0 kB
+Private_Clean:         4 kB
+Private_Dirty:         0 kB
+Referenced:            4 kB
+Anonymous:             0 kB
+AnonHugePages:         0 kB
+Swap:                  0 kB
+KernelPageSize:        4 kB
+MMUPageSize:           4 kB
+Locked:                0 kB
+VmFlags: rd ex mr mw me dw sd 
+7fff77424000-7ffff7423000 r--s 00001000 08:01 2366604                    /some/path/src/test/pmem_map/testfile1
+Size:            2097148 kB
+Rss:                   4 kB
+Pss:                   4 kB
+Shared_Clean:          0 kB
+Shared_Dirty:          0 kB
+Private_Clean:         4 kB
+Private_Dirty:         0 kB
+Referenced:            4 kB
+Anonymous:             0 kB
+AnonHugePages:         0 kB
+Swap:                  0 kB
+KernelPageSize:        4 kB
+MMUPageSize:           4 kB
+Locked:                0 kB
+VmFlags: rd ex mm mr mw me dw sd 
+7ffff7423000-7ffff75a5000 r-xp 00000000 08:01 1844444                    /lib/x86_64-linux-gnu/libc-2.13.so
+Size:               1544 kB
+Rss:                 364 kB
+Pss:                  53 kB
+Shared_Clean:        360 kB
+Shared_Dirty:          0 kB
+Private_Clean:         0 kB
+Private_Dirty:         4 kB
+Referenced:          364 kB
+Anonymous:             4 kB
+AnonHugePages:         0 kB
+Swap:                  0 kB
+KernelPageSize:        4 kB
+MMUPageSize:           4 kB
+Locked:                0 kB
+7ffff75a5000-7ffff77a4000 ---p 00182000 08:01 1844444                    /lib/x86_64-linux-gnu/libc-2.13.so
+Size:               2044 kB
+Rss:                   0 kB
+Pss:                   0 kB
+Shared_Clean:          0 kB
+Shared_Dirty:          0 kB
+Private_Clean:         0 kB
+Private_Dirty:         0 kB
+Referenced:            0 kB
+Anonymous:             0 kB
+AnonHugePages:         0 kB
+Swap:                  0 kB
+KernelPageSize:        4 kB
+MMUPageSize:           4 kB
+Locked:                0 kB
+7ffff77a4000-7ffff77a8000 r--p 00181000 08:01 1844444                    /lib/x86_64-linux-gnu/libc-2.13.so
+Size:                 16 kB
+Rss:                  16 kB
+Pss:                  16 kB
+Shared_Clean:          0 kB
+Shared_Dirty:          0 kB
+Private_Clean:         0 kB
+Private_Dirty:        16 kB
+Referenced:           16 kB
+Anonymous:            16 kB
+AnonHugePages:         0 kB
+Swap:                  0 kB
+KernelPageSize:        4 kB
+MMUPageSize:           4 kB
+Locked:                0 kB
+7ffff77a8000-7ffff77a9000 rw-p 00185000 08:01 1844444                    /lib/x86_64-linux-gnu/libc-2.13.so
+Size:                  4 kB
+Rss:                   4 kB
+Pss:                   4 kB
+Shared_Clean:          0 kB
+Shared_Dirty:          0 kB
+Private_Clean:         0 kB
+Private_Dirty:         4 kB
+Referenced:            4 kB
+Anonymous:             4 kB
+AnonHugePages:         0 kB
+Swap:                  0 kB
+KernelPageSize:        4 kB
+MMUPageSize:           4 kB
+Locked:                0 kB
+7ffff77a9000-7ffff77ae000 rw-p 00000000 00:00 0 
+Size:                 20 kB
+Rss:                  16 kB
+Pss:                  16 kB
+Shared_Clean:          0 kB
+Shared_Dirty:          0 kB
+Private_Clean:         0 kB
+Private_Dirty:        16 kB
+Referenced:           16 kB
+Anonymous:            16 kB
+AnonHugePages:         0 kB
+Swap:                  0 kB
+KernelPageSize:        4 kB
+MMUPageSize:           4 kB
+Locked:                0 kB
+7ffff77ae000-7ffff77c5000 r-xp 00000000 08:01 1845832                    /lib/x86_64-linux-gnu/libpthread-2.13.so
+Size:                 92 kB
+Rss:                  52 kB
+Pss:                  14 kB
+Shared_Clean:         44 kB
+Shared_Dirty:          0 kB
+Private_Clean:         0 kB
+Private_Dirty:         8 kB
+Referenced:           52 kB
+Anonymous:             8 kB
+AnonHugePages:         0 kB
+Swap:                  0 kB
+KernelPageSize:        4 kB
+MMUPageSize:           4 kB
+Locked:                0 kB
+7ffff77c5000-7ffff79c4000 ---p 00017000 08:01 1845832                    /lib/x86_64-linux-gnu/libpthread-2.13.so
+Size:               2044 kB
+Rss:                   0 kB
+Pss:                   0 kB
+Shared_Clean:          0 kB
+Shared_Dirty:          0 kB
+Private_Clean:         0 kB
+Private_Dirty:         0 kB
+Referenced:            0 kB
+Anonymous:             0 kB
+AnonHugePages:         0 kB
+Swap:                  0 kB
+KernelPageSize:        4 kB
+MMUPageSize:           4 kB
+Locked:                0 kB
+7ffff79c4000-7ffff79c5000 r--p 00016000 08:01 1845832                    /lib/x86_64-linux-gnu/libpthread-2.13.so
+Size:                  4 kB
+Rss:                   4 kB
+Pss:                   4 kB
+Shared_Clean:          0 kB
+Shared_Dirty:          0 kB
+Private_Clean:         0 kB
+Private_Dirty:         4 kB
+Referenced:            4 kB
+Anonymous:             4 kB
+AnonHugePages:         0 kB
+Swap:                  0 kB
+KernelPageSize:        4 kB
+MMUPageSize:           4 kB
+Locked:                0 kB
+7ffff79c5000-7ffff79c6000 rw-p 00017000 08:01 1845832                    /lib/x86_64-linux-gnu/libpthread-2.13.so
+Size:                  4 kB
+Rss:                   4 kB
+Pss:                   4 kB
+Shared_Clean:          0 kB
+Shared_Dirty:          0 kB
+Private_Clean:         0 kB
+Private_Dirty:         4 kB
+Referenced:            4 kB
+Anonymous:             4 kB
+AnonHugePages:         0 kB
+Swap:                  0 kB
+KernelPageSize:        4 kB
+MMUPageSize:           4 kB
+Locked:                0 kB
+7ffff79c6000-7ffff79ca000 rw-p 00000000 00:00 0 
+Size:                 16 kB
+Rss:                   4 kB
+Pss:                   4 kB
+Shared_Clean:          0 kB
+Shared_Dirty:          0 kB
+Private_Clean:         0 kB
+Private_Dirty:         4 kB
+Referenced:            4 kB
+Anonymous:             4 kB
+AnonHugePages:         0 kB
+Swap:                  0 kB
+KernelPageSize:        4 kB
+MMUPageSize:           4 kB
+Locked:                0 kB
+7ffff79ca000-7ffff79d7000 r-xp 00000000 08:01 2366292                    /some/path/src/debug/libpmem.so
+Size:                 52 kB
+Rss:                  28 kB
+Pss:                  28 kB
+Shared_Clean:          0 kB
+Shared_Dirty:          0 kB
+Private_Clean:        28 kB
+Private_Dirty:         0 kB
+Referenced:           28 kB
+Anonymous:             0 kB
+AnonHugePages:         0 kB
+Swap:                  0 kB
+KernelPageSize:        4 kB
+MMUPageSize:           4 kB
+Locked:                0 kB
+7ffff79d7000-7ffff7bd6000 ---p 0000d000 08:01 2366292                    /some/path/src/debug/libpmem.so
+Size:               2044 kB
+Rss:                   0 kB
+Pss:                   0 kB
+Shared_Clean:          0 kB
+Shared_Dirty:          0 kB
+Private_Clean:         0 kB
+Private_Dirty:         0 kB
+Referenced:            0 kB
+Anonymous:             0 kB
+AnonHugePages:         0 kB
+Swap:                  0 kB
+KernelPageSize:        4 kB
+MMUPageSize:           4 kB
+Locked:                0 kB
+7ffff7bd6000-7ffff7bd7000 rw-p 0000c000 08:01 2366292                    /some/path/src/debug/libpmem.so
+Size:                  4 kB
+Rss:                   4 kB
+Pss:                   4 kB
+Shared_Clean:          0 kB
+Shared_Dirty:          0 kB
+Private_Clean:         0 kB
+Private_Dirty:         4 kB
+Referenced:            4 kB
+Anonymous:             4 kB
+AnonHugePages:         0 kB
+Swap:                  0 kB
+KernelPageSize:        4 kB
+MMUPageSize:           4 kB
+Locked:                0 kB
+7ffff7bd7000-7ffff7bd8000 rw-p 00000000 00:00 0 
+Size:                  4 kB
+Rss:                   4 kB
+Pss:                   4 kB
+Shared_Clean:          0 kB
+Shared_Dirty:          0 kB
+Private_Clean:         0 kB
+Private_Dirty:         4 kB
+Referenced:            4 kB
+Anonymous:             4 kB
+AnonHugePages:         0 kB
+Swap:                  0 kB
+KernelPageSize:        4 kB
+MMUPageSize:           4 kB
+Locked:                0 kB
+7ffff7bd8000-7ffff7bdc000 r-xp 00000000 08:01 1835968                    /lib/x86_64-linux-gnu/libuuid.so.1.3.0
+Size:                 16 kB
+Rss:                  12 kB
+Pss:                  12 kB
+Shared_Clean:          0 kB
+Shared_Dirty:          0 kB
+Private_Clean:        12 kB
+Private_Dirty:         0 kB
+Referenced:           12 kB
+Anonymous:             0 kB
+AnonHugePages:         0 kB
+Swap:                  0 kB
+KernelPageSize:        4 kB
+MMUPageSize:           4 kB
+Locked:                0 kB
+7ffff7bdc000-7ffff7ddb000 ---p 00004000 08:01 1835968                    /lib/x86_64-linux-gnu/libuuid.so.1.3.0
+Size:               2044 kB
+Rss:                   0 kB
+Pss:                   0 kB
+Shared_Clean:          0 kB
+Shared_Dirty:          0 kB
+Private_Clean:         0 kB
+Private_Dirty:         0 kB
+Referenced:            0 kB
+Anonymous:             0 kB
+AnonHugePages:         0 kB
+Swap:                  0 kB
+KernelPageSize:        4 kB
+MMUPageSize:           4 kB
+Locked:                0 kB
+7ffff7ddb000-7ffff7ddc000 r--p 00003000 08:01 1835968                    /lib/x86_64-linux-gnu/libuuid.so.1.3.0
+Size:                  4 kB
+Rss:                   4 kB
+Pss:                   4 kB
+Shared_Clean:          0 kB
+Shared_Dirty:          0 kB
+Private_Clean:         0 kB
+Private_Dirty:         4 kB
+Referenced:            4 kB
+Anonymous:             4 kB
+AnonHugePages:         0 kB
+Swap:                  0 kB
+KernelPageSize:        4 kB
+MMUPageSize:           4 kB
+Locked:                0 kB
+7ffff7ddc000-7ffff7ddd000 rw-p 00004000 08:01 1835968                    /lib/x86_64-linux-gnu/libuuid.so.1.3.0
+Size:                  4 kB
+Rss:                   4 kB
+Pss:                   4 kB
+Shared_Clean:          0 kB
+Shared_Dirty:          0 kB
+Private_Clean:         0 kB
+Private_Dirty:         4 kB
+Referenced:            4 kB
+Anonymous:             4 kB
+AnonHugePages:         0 kB
+Swap:                  0 kB
+KernelPageSize:        4 kB
+MMUPageSize:           4 kB
+Locked:                0 kB
+7ffff7ddd000-7ffff7dfd000 r-xp 00000000 08:01 1844132                    /lib/x86_64-linux-gnu/ld-2.13.so
+Size:                128 kB
+Rss:                 108 kB
+Pss:                  33 kB
+Shared_Clean:        104 kB
+Shared_Dirty:          0 kB
+Private_Clean:         0 kB
+Private_Dirty:         4 kB
+Referenced:          108 kB
+Anonymous:             4 kB
+AnonHugePages:         0 kB
+Swap:                  0 kB
+KernelPageSize:        4 kB
+MMUPageSize:           4 kB
+Locked:                0 kB
+7ffff7fe3000-7ffff7fe7000 rw-p 00000000 00:00 0 
+Size:                 16 kB
+Rss:                  16 kB
+Pss:                  16 kB
+Shared_Clean:          0 kB
+Shared_Dirty:          0 kB
+Private_Clean:         0 kB
+Private_Dirty:        16 kB
+Referenced:           16 kB
+Anonymous:            16 kB
+AnonHugePages:         0 kB
+Swap:                  0 kB
+KernelPageSize:        4 kB
+MMUPageSize:           4 kB
+Locked:                0 kB
+7ffff7ff6000-7ffff7ffb000 rw-p 00000000 00:00 0 
+Size:                 20 kB
+Rss:                  20 kB
+Pss:                  20 kB
+Shared_Clean:          0 kB
+Shared_Dirty:          0 kB
+Private_Clean:         0 kB
+Private_Dirty:        20 kB
+Referenced:           20 kB
+Anonymous:            20 kB
+AnonHugePages:         0 kB
+Swap:                  0 kB
+KernelPageSize:        4 kB
+MMUPageSize:           4 kB
+Locked:                0 kB
+7ffff7ffb000-7ffff7ffc000 r-xp 00000000 00:00 0                          [vdso]
+Size:                  4 kB
+Rss:                   4 kB
+Pss:                   0 kB
+Shared_Clean:          4 kB
+Shared_Dirty:          0 kB
+Private_Clean:         0 kB
+Private_Dirty:         0 kB
+Referenced:            4 kB
+Anonymous:             0 kB
+AnonHugePages:         0 kB
+Swap:                  0 kB
+KernelPageSize:        4 kB
+MMUPageSize:           4 kB
+Locked:                0 kB
+7ffff7ffc000-7ffff7ffd000 r--p 0001f000 08:01 1844132                    /lib/x86_64-linux-gnu/ld-2.13.so
+Size:                  4 kB
+Rss:                   4 kB
+Pss:                   4 kB
+Shared_Clean:          0 kB
+Shared_Dirty:          0 kB
+Private_Clean:         0 kB
+Private_Dirty:         4 kB
+Referenced:            4 kB
+Anonymous:             4 kB
+AnonHugePages:         0 kB
+Swap:                  0 kB
+KernelPageSize:        4 kB
+MMUPageSize:           4 kB
+Locked:                0 kB
+7ffff7ffd000-7ffff7ffe000 rw-p 00020000 08:01 1844132                    /lib/x86_64-linux-gnu/ld-2.13.so
+Size:                  4 kB
+Rss:                   4 kB
+Pss:                   4 kB
+Shared_Clean:          0 kB
+Shared_Dirty:          0 kB
+Private_Clean:         0 kB
+Private_Dirty:         4 kB
+Referenced:            4 kB
+Anonymous:             4 kB
+AnonHugePages:         0 kB
+Swap:                  0 kB
+KernelPageSize:        4 kB
+MMUPageSize:           4 kB
+Locked:                0 kB
+7ffff7ffe000-7ffff7fff000 rw-p 00000000 00:00 0 
+Size:                  4 kB
+Rss:                   4 kB
+Pss:                   4 kB
+Shared_Clean:          0 kB
+Shared_Dirty:          0 kB
+Private_Clean:         0 kB
+Private_Dirty:         4 kB
+Referenced:            4 kB
+Anonymous:             4 kB
+AnonHugePages:         0 kB
+Swap:                  0 kB
+KernelPageSize:        4 kB
+MMUPageSize:           4 kB
+Locked:                0 kB
+7ffffffde000-7ffffffff000 rw-p 00000000 00:00 0                          [stack]
+Size:                136 kB
+Rss:                  24 kB
+Pss:                  24 kB
+Shared_Clean:          0 kB
+Shared_Dirty:          0 kB
+Private_Clean:         0 kB
+Private_Dirty:        24 kB
+Referenced:           24 kB
+Anonymous:            24 kB
+AnonHugePages:         0 kB
+Swap:                  0 kB
+KernelPageSize:        4 kB
+MMUPageSize:           4 kB
+Locked:                0 kB
+ffffffffff600000-ffffffffff601000 r-xp 00000000 00:00 0                  [vsyscall]
+Size:                  4 kB
+Rss:                   0 kB
+Pss:                   0 kB
+Shared_Clean:          0 kB
+Shared_Dirty:          0 kB
+Private_Clean:         0 kB
+Private_Dirty:         0 kB
+Referenced:            0 kB
+Anonymous:             0 kB
+AnonHugePages:         0 kB
+Swap:                  0 kB
+KernelPageSize:        4 kB
+MMUPageSize:           4 kB
+Locked:                0 kB
diff --git a/src/test/pmem_is_pmem_proc/smaps_no_mm b/src/test/pmem_is_pmem_proc/smaps_no_mm
new file mode 100644
index 0000000000000000000000000000000000000000..b05a0825e3eb70de90812ed4f262c8e018c7fae0
--- /dev/null
+++ b/src/test/pmem_is_pmem_proc/smaps_no_mm
@@ -0,0 +1,482 @@
+00400000-00406000 r-xp 00000000 08:01 2366593                            /some/path/src/test/pmem_map/pmem_map
+Size:                 24 kB
+Rss:                  20 kB
+Pss:                  20 kB
+Shared_Clean:          0 kB
+Shared_Dirty:          0 kB
+Private_Clean:        16 kB
+Private_Dirty:         4 kB
+Referenced:           20 kB
+Anonymous:             4 kB
+AnonHugePages:         0 kB
+Swap:                  0 kB
+KernelPageSize:        4 kB
+MMUPageSize:           4 kB
+Locked:                0 kB
+00605000-00606000 rw-p 00005000 08:01 2366593                            /some/path/src/test/pmem_map/pmem_map
+Size:                  4 kB
+Rss:                   4 kB
+Pss:                   4 kB
+Shared_Clean:          0 kB
+Shared_Dirty:          0 kB
+Private_Clean:         0 kB
+Private_Dirty:         4 kB
+Referenced:            4 kB
+Anonymous:             4 kB
+AnonHugePages:         0 kB
+Swap:                  0 kB
+KernelPageSize:        4 kB
+MMUPageSize:           4 kB
+Locked:                0 kB
+00606000-00627000 rw-p 00000000 00:00 0                                  [heap]
+Size:                132 kB
+Rss:                   8 kB
+Pss:                   8 kB
+Shared_Clean:          0 kB
+Shared_Dirty:          0 kB
+Private_Clean:         0 kB
+Private_Dirty:         8 kB
+Referenced:            8 kB
+Anonymous:             8 kB
+AnonHugePages:         0 kB
+Swap:                  0 kB
+KernelPageSize:        4 kB
+MMUPageSize:           4 kB
+Locked:                0 kB
+7fff77423000-7fff77424000 ---s 00000000 08:01 2366604                    /some/path/src/test/pmem_map/testfile1
+Size:                  4 kB
+Rss:                   4 kB
+Pss:                   4 kB
+Shared_Clean:          0 kB
+Shared_Dirty:          0 kB
+Private_Clean:         4 kB
+Private_Dirty:         0 kB
+Referenced:            4 kB
+Anonymous:             0 kB
+AnonHugePages:         0 kB
+Swap:                  0 kB
+KernelPageSize:        4 kB
+MMUPageSize:           4 kB
+Locked:                0 kB
+VmFlags: rd ex mr mw me dw sd 
+7fff77424000-7ffff7423000 r--s 00001000 08:01 2366604                    /some/path/src/test/pmem_map/testfile1
+Size:            2097148 kB
+Rss:                   4 kB
+Pss:                   4 kB
+Shared_Clean:          0 kB
+Shared_Dirty:          0 kB
+Private_Clean:         4 kB
+Private_Dirty:         0 kB
+Referenced:            4 kB
+Anonymous:             0 kB
+AnonHugePages:         0 kB
+Swap:                  0 kB
+KernelPageSize:        4 kB
+MMUPageSize:           4 kB
+Locked:                0 kB
+VmFlags: rd ex mr mw me dw sd 
+7ffff7423000-7ffff75a5000 r-xp 00000000 08:01 1844444                    /lib/x86_64-linux-gnu/libc-2.13.so
+Size:               1544 kB
+Rss:                 364 kB
+Pss:                  53 kB
+Shared_Clean:        360 kB
+Shared_Dirty:          0 kB
+Private_Clean:         0 kB
+Private_Dirty:         4 kB
+Referenced:          364 kB
+Anonymous:             4 kB
+AnonHugePages:         0 kB
+Swap:                  0 kB
+KernelPageSize:        4 kB
+MMUPageSize:           4 kB
+Locked:                0 kB
+7ffff75a5000-7ffff77a4000 ---p 00182000 08:01 1844444                    /lib/x86_64-linux-gnu/libc-2.13.so
+Size:               2044 kB
+Rss:                   0 kB
+Pss:                   0 kB
+Shared_Clean:          0 kB
+Shared_Dirty:          0 kB
+Private_Clean:         0 kB
+Private_Dirty:         0 kB
+Referenced:            0 kB
+Anonymous:             0 kB
+AnonHugePages:         0 kB
+Swap:                  0 kB
+KernelPageSize:        4 kB
+MMUPageSize:           4 kB
+Locked:                0 kB
+7ffff77a4000-7ffff77a8000 r--p 00181000 08:01 1844444                    /lib/x86_64-linux-gnu/libc-2.13.so
+Size:                 16 kB
+Rss:                  16 kB
+Pss:                  16 kB
+Shared_Clean:          0 kB
+Shared_Dirty:          0 kB
+Private_Clean:         0 kB
+Private_Dirty:        16 kB
+Referenced:           16 kB
+Anonymous:            16 kB
+AnonHugePages:         0 kB
+Swap:                  0 kB
+KernelPageSize:        4 kB
+MMUPageSize:           4 kB
+Locked:                0 kB
+7ffff77a8000-7ffff77a9000 rw-p 00185000 08:01 1844444                    /lib/x86_64-linux-gnu/libc-2.13.so
+Size:                  4 kB
+Rss:                   4 kB
+Pss:                   4 kB
+Shared_Clean:          0 kB
+Shared_Dirty:          0 kB
+Private_Clean:         0 kB
+Private_Dirty:         4 kB
+Referenced:            4 kB
+Anonymous:             4 kB
+AnonHugePages:         0 kB
+Swap:                  0 kB
+KernelPageSize:        4 kB
+MMUPageSize:           4 kB
+Locked:                0 kB
+7ffff77a9000-7ffff77ae000 rw-p 00000000 00:00 0 
+Size:                 20 kB
+Rss:                  16 kB
+Pss:                  16 kB
+Shared_Clean:          0 kB
+Shared_Dirty:          0 kB
+Private_Clean:         0 kB
+Private_Dirty:        16 kB
+Referenced:           16 kB
+Anonymous:            16 kB
+AnonHugePages:         0 kB
+Swap:                  0 kB
+KernelPageSize:        4 kB
+MMUPageSize:           4 kB
+Locked:                0 kB
+7ffff77ae000-7ffff77c5000 r-xp 00000000 08:01 1845832                    /lib/x86_64-linux-gnu/libpthread-2.13.so
+Size:                 92 kB
+Rss:                  52 kB
+Pss:                  14 kB
+Shared_Clean:         44 kB
+Shared_Dirty:          0 kB
+Private_Clean:         0 kB
+Private_Dirty:         8 kB
+Referenced:           52 kB
+Anonymous:             8 kB
+AnonHugePages:         0 kB
+Swap:                  0 kB
+KernelPageSize:        4 kB
+MMUPageSize:           4 kB
+Locked:                0 kB
+7ffff77c5000-7ffff79c4000 ---p 00017000 08:01 1845832                    /lib/x86_64-linux-gnu/libpthread-2.13.so
+Size:               2044 kB
+Rss:                   0 kB
+Pss:                   0 kB
+Shared_Clean:          0 kB
+Shared_Dirty:          0 kB
+Private_Clean:         0 kB
+Private_Dirty:         0 kB
+Referenced:            0 kB
+Anonymous:             0 kB
+AnonHugePages:         0 kB
+Swap:                  0 kB
+KernelPageSize:        4 kB
+MMUPageSize:           4 kB
+Locked:                0 kB
+7ffff79c4000-7ffff79c5000 r--p 00016000 08:01 1845832                    /lib/x86_64-linux-gnu/libpthread-2.13.so
+Size:                  4 kB
+Rss:                   4 kB
+Pss:                   4 kB
+Shared_Clean:          0 kB
+Shared_Dirty:          0 kB
+Private_Clean:         0 kB
+Private_Dirty:         4 kB
+Referenced:            4 kB
+Anonymous:             4 kB
+AnonHugePages:         0 kB
+Swap:                  0 kB
+KernelPageSize:        4 kB
+MMUPageSize:           4 kB
+Locked:                0 kB
+7ffff79c5000-7ffff79c6000 rw-p 00017000 08:01 1845832                    /lib/x86_64-linux-gnu/libpthread-2.13.so
+Size:                  4 kB
+Rss:                   4 kB
+Pss:                   4 kB
+Shared_Clean:          0 kB
+Shared_Dirty:          0 kB
+Private_Clean:         0 kB
+Private_Dirty:         4 kB
+Referenced:            4 kB
+Anonymous:             4 kB
+AnonHugePages:         0 kB
+Swap:                  0 kB
+KernelPageSize:        4 kB
+MMUPageSize:           4 kB
+Locked:                0 kB
+7ffff79c6000-7ffff79ca000 rw-p 00000000 00:00 0 
+Size:                 16 kB
+Rss:                   4 kB
+Pss:                   4 kB
+Shared_Clean:          0 kB
+Shared_Dirty:          0 kB
+Private_Clean:         0 kB
+Private_Dirty:         4 kB
+Referenced:            4 kB
+Anonymous:             4 kB
+AnonHugePages:         0 kB
+Swap:                  0 kB
+KernelPageSize:        4 kB
+MMUPageSize:           4 kB
+Locked:                0 kB
+7ffff79ca000-7ffff79d7000 r-xp 00000000 08:01 2366292                    /some/path/src/debug/libpmem.so
+Size:                 52 kB
+Rss:                  28 kB
+Pss:                  28 kB
+Shared_Clean:          0 kB
+Shared_Dirty:          0 kB
+Private_Clean:        28 kB
+Private_Dirty:         0 kB
+Referenced:           28 kB
+Anonymous:             0 kB
+AnonHugePages:         0 kB
+Swap:                  0 kB
+KernelPageSize:        4 kB
+MMUPageSize:           4 kB
+Locked:                0 kB
+7ffff79d7000-7ffff7bd6000 ---p 0000d000 08:01 2366292                    /some/path/src/debug/libpmem.so
+Size:               2044 kB
+Rss:                   0 kB
+Pss:                   0 kB
+Shared_Clean:          0 kB
+Shared_Dirty:          0 kB
+Private_Clean:         0 kB
+Private_Dirty:         0 kB
+Referenced:            0 kB
+Anonymous:             0 kB
+AnonHugePages:         0 kB
+Swap:                  0 kB
+KernelPageSize:        4 kB
+MMUPageSize:           4 kB
+Locked:                0 kB
+7ffff7bd6000-7ffff7bd7000 rw-p 0000c000 08:01 2366292                    /some/path/src/debug/libpmem.so
+Size:                  4 kB
+Rss:                   4 kB
+Pss:                   4 kB
+Shared_Clean:          0 kB
+Shared_Dirty:          0 kB
+Private_Clean:         0 kB
+Private_Dirty:         4 kB
+Referenced:            4 kB
+Anonymous:             4 kB
+AnonHugePages:         0 kB
+Swap:                  0 kB
+KernelPageSize:        4 kB
+MMUPageSize:           4 kB
+Locked:                0 kB
+7ffff7bd7000-7ffff7bd8000 rw-p 00000000 00:00 0 
+Size:                  4 kB
+Rss:                   4 kB
+Pss:                   4 kB
+Shared_Clean:          0 kB
+Shared_Dirty:          0 kB
+Private_Clean:         0 kB
+Private_Dirty:         4 kB
+Referenced:            4 kB
+Anonymous:             4 kB
+AnonHugePages:         0 kB
+Swap:                  0 kB
+KernelPageSize:        4 kB
+MMUPageSize:           4 kB
+Locked:                0 kB
+7ffff7bd8000-7ffff7bdc000 r-xp 00000000 08:01 1835968                    /lib/x86_64-linux-gnu/libuuid.so.1.3.0
+Size:                 16 kB
+Rss:                  12 kB
+Pss:                  12 kB
+Shared_Clean:          0 kB
+Shared_Dirty:          0 kB
+Private_Clean:        12 kB
+Private_Dirty:         0 kB
+Referenced:           12 kB
+Anonymous:             0 kB
+AnonHugePages:         0 kB
+Swap:                  0 kB
+KernelPageSize:        4 kB
+MMUPageSize:           4 kB
+Locked:                0 kB
+7ffff7bdc000-7ffff7ddb000 ---p 00004000 08:01 1835968                    /lib/x86_64-linux-gnu/libuuid.so.1.3.0
+Size:               2044 kB
+Rss:                   0 kB
+Pss:                   0 kB
+Shared_Clean:          0 kB
+Shared_Dirty:          0 kB
+Private_Clean:         0 kB
+Private_Dirty:         0 kB
+Referenced:            0 kB
+Anonymous:             0 kB
+AnonHugePages:         0 kB
+Swap:                  0 kB
+KernelPageSize:        4 kB
+MMUPageSize:           4 kB
+Locked:                0 kB
+7ffff7ddb000-7ffff7ddc000 r--p 00003000 08:01 1835968                    /lib/x86_64-linux-gnu/libuuid.so.1.3.0
+Size:                  4 kB
+Rss:                   4 kB
+Pss:                   4 kB
+Shared_Clean:          0 kB
+Shared_Dirty:          0 kB
+Private_Clean:         0 kB
+Private_Dirty:         4 kB
+Referenced:            4 kB
+Anonymous:             4 kB
+AnonHugePages:         0 kB
+Swap:                  0 kB
+KernelPageSize:        4 kB
+MMUPageSize:           4 kB
+Locked:                0 kB
+7ffff7ddc000-7ffff7ddd000 rw-p 00004000 08:01 1835968                    /lib/x86_64-linux-gnu/libuuid.so.1.3.0
+Size:                  4 kB
+Rss:                   4 kB
+Pss:                   4 kB
+Shared_Clean:          0 kB
+Shared_Dirty:          0 kB
+Private_Clean:         0 kB
+Private_Dirty:         4 kB
+Referenced:            4 kB
+Anonymous:             4 kB
+AnonHugePages:         0 kB
+Swap:                  0 kB
+KernelPageSize:        4 kB
+MMUPageSize:           4 kB
+Locked:                0 kB
+7ffff7ddd000-7ffff7dfd000 r-xp 00000000 08:01 1844132                    /lib/x86_64-linux-gnu/ld-2.13.so
+Size:                128 kB
+Rss:                 108 kB
+Pss:                  33 kB
+Shared_Clean:        104 kB
+Shared_Dirty:          0 kB
+Private_Clean:         0 kB
+Private_Dirty:         4 kB
+Referenced:          108 kB
+Anonymous:             4 kB
+AnonHugePages:         0 kB
+Swap:                  0 kB
+KernelPageSize:        4 kB
+MMUPageSize:           4 kB
+Locked:                0 kB
+7ffff7fe3000-7ffff7fe7000 rw-p 00000000 00:00 0 
+Size:                 16 kB
+Rss:                  16 kB
+Pss:                  16 kB
+Shared_Clean:          0 kB
+Shared_Dirty:          0 kB
+Private_Clean:         0 kB
+Private_Dirty:        16 kB
+Referenced:           16 kB
+Anonymous:            16 kB
+AnonHugePages:         0 kB
+Swap:                  0 kB
+KernelPageSize:        4 kB
+MMUPageSize:           4 kB
+Locked:                0 kB
+7ffff7ff6000-7ffff7ffb000 rw-p 00000000 00:00 0 
+Size:                 20 kB
+Rss:                  20 kB
+Pss:                  20 kB
+Shared_Clean:          0 kB
+Shared_Dirty:          0 kB
+Private_Clean:         0 kB
+Private_Dirty:        20 kB
+Referenced:           20 kB
+Anonymous:            20 kB
+AnonHugePages:         0 kB
+Swap:                  0 kB
+KernelPageSize:        4 kB
+MMUPageSize:           4 kB
+Locked:                0 kB
+7ffff7ffb000-7ffff7ffc000 r-xp 00000000 00:00 0                          [vdso]
+Size:                  4 kB
+Rss:                   4 kB
+Pss:                   0 kB
+Shared_Clean:          4 kB
+Shared_Dirty:          0 kB
+Private_Clean:         0 kB
+Private_Dirty:         0 kB
+Referenced:            4 kB
+Anonymous:             0 kB
+AnonHugePages:         0 kB
+Swap:                  0 kB
+KernelPageSize:        4 kB
+MMUPageSize:           4 kB
+Locked:                0 kB
+7ffff7ffc000-7ffff7ffd000 r--p 0001f000 08:01 1844132                    /lib/x86_64-linux-gnu/ld-2.13.so
+Size:                  4 kB
+Rss:                   4 kB
+Pss:                   4 kB
+Shared_Clean:          0 kB
+Shared_Dirty:          0 kB
+Private_Clean:         0 kB
+Private_Dirty:         4 kB
+Referenced:            4 kB
+Anonymous:             4 kB
+AnonHugePages:         0 kB
+Swap:                  0 kB
+KernelPageSize:        4 kB
+MMUPageSize:           4 kB
+Locked:                0 kB
+7ffff7ffd000-7ffff7ffe000 rw-p 00020000 08:01 1844132                    /lib/x86_64-linux-gnu/ld-2.13.so
+Size:                  4 kB
+Rss:                   4 kB
+Pss:                   4 kB
+Shared_Clean:          0 kB
+Shared_Dirty:          0 kB
+Private_Clean:         0 kB
+Private_Dirty:         4 kB
+Referenced:            4 kB
+Anonymous:             4 kB
+AnonHugePages:         0 kB
+Swap:                  0 kB
+KernelPageSize:        4 kB
+MMUPageSize:           4 kB
+Locked:                0 kB
+7ffff7ffe000-7ffff7fff000 rw-p 00000000 00:00 0 
+Size:                  4 kB
+Rss:                   4 kB
+Pss:                   4 kB
+Shared_Clean:          0 kB
+Shared_Dirty:          0 kB
+Private_Clean:         0 kB
+Private_Dirty:         4 kB
+Referenced:            4 kB
+Anonymous:             4 kB
+AnonHugePages:         0 kB
+Swap:                  0 kB
+KernelPageSize:        4 kB
+MMUPageSize:           4 kB
+Locked:                0 kB
+7ffffffde000-7ffffffff000 rw-p 00000000 00:00 0                          [stack]
+Size:                136 kB
+Rss:                  24 kB
+Pss:                  24 kB
+Shared_Clean:          0 kB
+Shared_Dirty:          0 kB
+Private_Clean:         0 kB
+Private_Dirty:        24 kB
+Referenced:           24 kB
+Anonymous:            24 kB
+AnonHugePages:         0 kB
+Swap:                  0 kB
+KernelPageSize:        4 kB
+MMUPageSize:           4 kB
+Locked:                0 kB
+ffffffffff600000-ffffffffff601000 r-xp 00000000 00:00 0                  [vsyscall]
+Size:                  4 kB
+Rss:                   0 kB
+Pss:                   0 kB
+Shared_Clean:          0 kB
+Shared_Dirty:          0 kB
+Private_Clean:         0 kB
+Private_Dirty:         0 kB
+Referenced:            0 kB
+Anonymous:             0 kB
+AnonHugePages:         0 kB
+Swap:                  0 kB
+KernelPageSize:        4 kB
+MMUPageSize:           4 kB
+Locked:                0 kB
diff --git a/src/test/pmem_is_pmem_proc/smaps_no_vmflags b/src/test/pmem_is_pmem_proc/smaps_no_vmflags
new file mode 100644
index 0000000000000000000000000000000000000000..c2727741ee9452ce4473ec2b551810323869fa4a
--- /dev/null
+++ b/src/test/pmem_is_pmem_proc/smaps_no_vmflags
@@ -0,0 +1,480 @@
+00400000-00406000 r-xp 00000000 08:01 2366593                            /some/path/src/test/pmem_map/pmem_map
+Size:                 24 kB
+Rss:                  20 kB
+Pss:                  20 kB
+Shared_Clean:          0 kB
+Shared_Dirty:          0 kB
+Private_Clean:        16 kB
+Private_Dirty:         4 kB
+Referenced:           20 kB
+Anonymous:             4 kB
+AnonHugePages:         0 kB
+Swap:                  0 kB
+KernelPageSize:        4 kB
+MMUPageSize:           4 kB
+Locked:                0 kB
+00605000-00606000 rw-p 00005000 08:01 2366593                            /some/path/src/test/pmem_map/pmem_map
+Size:                  4 kB
+Rss:                   4 kB
+Pss:                   4 kB
+Shared_Clean:          0 kB
+Shared_Dirty:          0 kB
+Private_Clean:         0 kB
+Private_Dirty:         4 kB
+Referenced:            4 kB
+Anonymous:             4 kB
+AnonHugePages:         0 kB
+Swap:                  0 kB
+KernelPageSize:        4 kB
+MMUPageSize:           4 kB
+Locked:                0 kB
+00606000-00627000 rw-p 00000000 00:00 0                                  [heap]
+Size:                132 kB
+Rss:                   8 kB
+Pss:                   8 kB
+Shared_Clean:          0 kB
+Shared_Dirty:          0 kB
+Private_Clean:         0 kB
+Private_Dirty:         8 kB
+Referenced:            8 kB
+Anonymous:             8 kB
+AnonHugePages:         0 kB
+Swap:                  0 kB
+KernelPageSize:        4 kB
+MMUPageSize:           4 kB
+Locked:                0 kB
+7fff77423000-7fff77424000 ---s 00000000 08:01 2366604                    /some/path/src/test/pmem_map/testfile1
+Size:                  4 kB
+Rss:                   4 kB
+Pss:                   4 kB
+Shared_Clean:          0 kB
+Shared_Dirty:          0 kB
+Private_Clean:         4 kB
+Private_Dirty:         0 kB
+Referenced:            4 kB
+Anonymous:             0 kB
+AnonHugePages:         0 kB
+Swap:                  0 kB
+KernelPageSize:        4 kB
+MMUPageSize:           4 kB
+Locked:                0 kB
+7fff77424000-7ffff7423000 r--s 00001000 08:01 2366604                    /some/path/src/test/pmem_map/testfile1
+Size:            2097148 kB
+Rss:                   4 kB
+Pss:                   4 kB
+Shared_Clean:          0 kB
+Shared_Dirty:          0 kB
+Private_Clean:         4 kB
+Private_Dirty:         0 kB
+Referenced:            4 kB
+Anonymous:             0 kB
+AnonHugePages:         0 kB
+Swap:                  0 kB
+KernelPageSize:        4 kB
+MMUPageSize:           4 kB
+Locked:                0 kB
+7ffff7423000-7ffff75a5000 r-xp 00000000 08:01 1844444                    /lib/x86_64-linux-gnu/libc-2.13.so
+Size:               1544 kB
+Rss:                 364 kB
+Pss:                  53 kB
+Shared_Clean:        360 kB
+Shared_Dirty:          0 kB
+Private_Clean:         0 kB
+Private_Dirty:         4 kB
+Referenced:          364 kB
+Anonymous:             4 kB
+AnonHugePages:         0 kB
+Swap:                  0 kB
+KernelPageSize:        4 kB
+MMUPageSize:           4 kB
+Locked:                0 kB
+7ffff75a5000-7ffff77a4000 ---p 00182000 08:01 1844444                    /lib/x86_64-linux-gnu/libc-2.13.so
+Size:               2044 kB
+Rss:                   0 kB
+Pss:                   0 kB
+Shared_Clean:          0 kB
+Shared_Dirty:          0 kB
+Private_Clean:         0 kB
+Private_Dirty:         0 kB
+Referenced:            0 kB
+Anonymous:             0 kB
+AnonHugePages:         0 kB
+Swap:                  0 kB
+KernelPageSize:        4 kB
+MMUPageSize:           4 kB
+Locked:                0 kB
+7ffff77a4000-7ffff77a8000 r--p 00181000 08:01 1844444                    /lib/x86_64-linux-gnu/libc-2.13.so
+Size:                 16 kB
+Rss:                  16 kB
+Pss:                  16 kB
+Shared_Clean:          0 kB
+Shared_Dirty:          0 kB
+Private_Clean:         0 kB
+Private_Dirty:        16 kB
+Referenced:           16 kB
+Anonymous:            16 kB
+AnonHugePages:         0 kB
+Swap:                  0 kB
+KernelPageSize:        4 kB
+MMUPageSize:           4 kB
+Locked:                0 kB
+7ffff77a8000-7ffff77a9000 rw-p 00185000 08:01 1844444                    /lib/x86_64-linux-gnu/libc-2.13.so
+Size:                  4 kB
+Rss:                   4 kB
+Pss:                   4 kB
+Shared_Clean:          0 kB
+Shared_Dirty:          0 kB
+Private_Clean:         0 kB
+Private_Dirty:         4 kB
+Referenced:            4 kB
+Anonymous:             4 kB
+AnonHugePages:         0 kB
+Swap:                  0 kB
+KernelPageSize:        4 kB
+MMUPageSize:           4 kB
+Locked:                0 kB
+7ffff77a9000-7ffff77ae000 rw-p 00000000 00:00 0 
+Size:                 20 kB
+Rss:                  16 kB
+Pss:                  16 kB
+Shared_Clean:          0 kB
+Shared_Dirty:          0 kB
+Private_Clean:         0 kB
+Private_Dirty:        16 kB
+Referenced:           16 kB
+Anonymous:            16 kB
+AnonHugePages:         0 kB
+Swap:                  0 kB
+KernelPageSize:        4 kB
+MMUPageSize:           4 kB
+Locked:                0 kB
+7ffff77ae000-7ffff77c5000 r-xp 00000000 08:01 1845832                    /lib/x86_64-linux-gnu/libpthread-2.13.so
+Size:                 92 kB
+Rss:                  52 kB
+Pss:                  14 kB
+Shared_Clean:         44 kB
+Shared_Dirty:          0 kB
+Private_Clean:         0 kB
+Private_Dirty:         8 kB
+Referenced:           52 kB
+Anonymous:             8 kB
+AnonHugePages:         0 kB
+Swap:                  0 kB
+KernelPageSize:        4 kB
+MMUPageSize:           4 kB
+Locked:                0 kB
+7ffff77c5000-7ffff79c4000 ---p 00017000 08:01 1845832                    /lib/x86_64-linux-gnu/libpthread-2.13.so
+Size:               2044 kB
+Rss:                   0 kB
+Pss:                   0 kB
+Shared_Clean:          0 kB
+Shared_Dirty:          0 kB
+Private_Clean:         0 kB
+Private_Dirty:         0 kB
+Referenced:            0 kB
+Anonymous:             0 kB
+AnonHugePages:         0 kB
+Swap:                  0 kB
+KernelPageSize:        4 kB
+MMUPageSize:           4 kB
+Locked:                0 kB
+7ffff79c4000-7ffff79c5000 r--p 00016000 08:01 1845832                    /lib/x86_64-linux-gnu/libpthread-2.13.so
+Size:                  4 kB
+Rss:                   4 kB
+Pss:                   4 kB
+Shared_Clean:          0 kB
+Shared_Dirty:          0 kB
+Private_Clean:         0 kB
+Private_Dirty:         4 kB
+Referenced:            4 kB
+Anonymous:             4 kB
+AnonHugePages:         0 kB
+Swap:                  0 kB
+KernelPageSize:        4 kB
+MMUPageSize:           4 kB
+Locked:                0 kB
+7ffff79c5000-7ffff79c6000 rw-p 00017000 08:01 1845832                    /lib/x86_64-linux-gnu/libpthread-2.13.so
+Size:                  4 kB
+Rss:                   4 kB
+Pss:                   4 kB
+Shared_Clean:          0 kB
+Shared_Dirty:          0 kB
+Private_Clean:         0 kB
+Private_Dirty:         4 kB
+Referenced:            4 kB
+Anonymous:             4 kB
+AnonHugePages:         0 kB
+Swap:                  0 kB
+KernelPageSize:        4 kB
+MMUPageSize:           4 kB
+Locked:                0 kB
+7ffff79c6000-7ffff79ca000 rw-p 00000000 00:00 0 
+Size:                 16 kB
+Rss:                   4 kB
+Pss:                   4 kB
+Shared_Clean:          0 kB
+Shared_Dirty:          0 kB
+Private_Clean:         0 kB
+Private_Dirty:         4 kB
+Referenced:            4 kB
+Anonymous:             4 kB
+AnonHugePages:         0 kB
+Swap:                  0 kB
+KernelPageSize:        4 kB
+MMUPageSize:           4 kB
+Locked:                0 kB
+7ffff79ca000-7ffff79d7000 r-xp 00000000 08:01 2366292                    /some/path/src/debug/libpmem.so
+Size:                 52 kB
+Rss:                  28 kB
+Pss:                  28 kB
+Shared_Clean:          0 kB
+Shared_Dirty:          0 kB
+Private_Clean:        28 kB
+Private_Dirty:         0 kB
+Referenced:           28 kB
+Anonymous:             0 kB
+AnonHugePages:         0 kB
+Swap:                  0 kB
+KernelPageSize:        4 kB
+MMUPageSize:           4 kB
+Locked:                0 kB
+7ffff79d7000-7ffff7bd6000 ---p 0000d000 08:01 2366292                    /some/path/src/debug/libpmem.so
+Size:               2044 kB
+Rss:                   0 kB
+Pss:                   0 kB
+Shared_Clean:          0 kB
+Shared_Dirty:          0 kB
+Private_Clean:         0 kB
+Private_Dirty:         0 kB
+Referenced:            0 kB
+Anonymous:             0 kB
+AnonHugePages:         0 kB
+Swap:                  0 kB
+KernelPageSize:        4 kB
+MMUPageSize:           4 kB
+Locked:                0 kB
+7ffff7bd6000-7ffff7bd7000 rw-p 0000c000 08:01 2366292                    /some/path/src/debug/libpmem.so
+Size:                  4 kB
+Rss:                   4 kB
+Pss:                   4 kB
+Shared_Clean:          0 kB
+Shared_Dirty:          0 kB
+Private_Clean:         0 kB
+Private_Dirty:         4 kB
+Referenced:            4 kB
+Anonymous:             4 kB
+AnonHugePages:         0 kB
+Swap:                  0 kB
+KernelPageSize:        4 kB
+MMUPageSize:           4 kB
+Locked:                0 kB
+7ffff7bd7000-7ffff7bd8000 rw-p 00000000 00:00 0 
+Size:                  4 kB
+Rss:                   4 kB
+Pss:                   4 kB
+Shared_Clean:          0 kB
+Shared_Dirty:          0 kB
+Private_Clean:         0 kB
+Private_Dirty:         4 kB
+Referenced:            4 kB
+Anonymous:             4 kB
+AnonHugePages:         0 kB
+Swap:                  0 kB
+KernelPageSize:        4 kB
+MMUPageSize:           4 kB
+Locked:                0 kB
+7ffff7bd8000-7ffff7bdc000 r-xp 00000000 08:01 1835968                    /lib/x86_64-linux-gnu/libuuid.so.1.3.0
+Size:                 16 kB
+Rss:                  12 kB
+Pss:                  12 kB
+Shared_Clean:          0 kB
+Shared_Dirty:          0 kB
+Private_Clean:        12 kB
+Private_Dirty:         0 kB
+Referenced:           12 kB
+Anonymous:             0 kB
+AnonHugePages:         0 kB
+Swap:                  0 kB
+KernelPageSize:        4 kB
+MMUPageSize:           4 kB
+Locked:                0 kB
+7ffff7bdc000-7ffff7ddb000 ---p 00004000 08:01 1835968                    /lib/x86_64-linux-gnu/libuuid.so.1.3.0
+Size:               2044 kB
+Rss:                   0 kB
+Pss:                   0 kB
+Shared_Clean:          0 kB
+Shared_Dirty:          0 kB
+Private_Clean:         0 kB
+Private_Dirty:         0 kB
+Referenced:            0 kB
+Anonymous:             0 kB
+AnonHugePages:         0 kB
+Swap:                  0 kB
+KernelPageSize:        4 kB
+MMUPageSize:           4 kB
+Locked:                0 kB
+7ffff7ddb000-7ffff7ddc000 r--p 00003000 08:01 1835968                    /lib/x86_64-linux-gnu/libuuid.so.1.3.0
+Size:                  4 kB
+Rss:                   4 kB
+Pss:                   4 kB
+Shared_Clean:          0 kB
+Shared_Dirty:          0 kB
+Private_Clean:         0 kB
+Private_Dirty:         4 kB
+Referenced:            4 kB
+Anonymous:             4 kB
+AnonHugePages:         0 kB
+Swap:                  0 kB
+KernelPageSize:        4 kB
+MMUPageSize:           4 kB
+Locked:                0 kB
+7ffff7ddc000-7ffff7ddd000 rw-p 00004000 08:01 1835968                    /lib/x86_64-linux-gnu/libuuid.so.1.3.0
+Size:                  4 kB
+Rss:                   4 kB
+Pss:                   4 kB
+Shared_Clean:          0 kB
+Shared_Dirty:          0 kB
+Private_Clean:         0 kB
+Private_Dirty:         4 kB
+Referenced:            4 kB
+Anonymous:             4 kB
+AnonHugePages:         0 kB
+Swap:                  0 kB
+KernelPageSize:        4 kB
+MMUPageSize:           4 kB
+Locked:                0 kB
+7ffff7ddd000-7ffff7dfd000 r-xp 00000000 08:01 1844132                    /lib/x86_64-linux-gnu/ld-2.13.so
+Size:                128 kB
+Rss:                 108 kB
+Pss:                  33 kB
+Shared_Clean:        104 kB
+Shared_Dirty:          0 kB
+Private_Clean:         0 kB
+Private_Dirty:         4 kB
+Referenced:          108 kB
+Anonymous:             4 kB
+AnonHugePages:         0 kB
+Swap:                  0 kB
+KernelPageSize:        4 kB
+MMUPageSize:           4 kB
+Locked:                0 kB
+7ffff7fe3000-7ffff7fe7000 rw-p 00000000 00:00 0 
+Size:                 16 kB
+Rss:                  16 kB
+Pss:                  16 kB
+Shared_Clean:          0 kB
+Shared_Dirty:          0 kB
+Private_Clean:         0 kB
+Private_Dirty:        16 kB
+Referenced:           16 kB
+Anonymous:            16 kB
+AnonHugePages:         0 kB
+Swap:                  0 kB
+KernelPageSize:        4 kB
+MMUPageSize:           4 kB
+Locked:                0 kB
+7ffff7ff6000-7ffff7ffb000 rw-p 00000000 00:00 0 
+Size:                 20 kB
+Rss:                  20 kB
+Pss:                  20 kB
+Shared_Clean:          0 kB
+Shared_Dirty:          0 kB
+Private_Clean:         0 kB
+Private_Dirty:        20 kB
+Referenced:           20 kB
+Anonymous:            20 kB
+AnonHugePages:         0 kB
+Swap:                  0 kB
+KernelPageSize:        4 kB
+MMUPageSize:           4 kB
+Locked:                0 kB
+7ffff7ffb000-7ffff7ffc000 r-xp 00000000 00:00 0                          [vdso]
+Size:                  4 kB
+Rss:                   4 kB
+Pss:                   0 kB
+Shared_Clean:          4 kB
+Shared_Dirty:          0 kB
+Private_Clean:         0 kB
+Private_Dirty:         0 kB
+Referenced:            4 kB
+Anonymous:             0 kB
+AnonHugePages:         0 kB
+Swap:                  0 kB
+KernelPageSize:        4 kB
+MMUPageSize:           4 kB
+Locked:                0 kB
+7ffff7ffc000-7ffff7ffd000 r--p 0001f000 08:01 1844132                    /lib/x86_64-linux-gnu/ld-2.13.so
+Size:                  4 kB
+Rss:                   4 kB
+Pss:                   4 kB
+Shared_Clean:          0 kB
+Shared_Dirty:          0 kB
+Private_Clean:         0 kB
+Private_Dirty:         4 kB
+Referenced:            4 kB
+Anonymous:             4 kB
+AnonHugePages:         0 kB
+Swap:                  0 kB
+KernelPageSize:        4 kB
+MMUPageSize:           4 kB
+Locked:                0 kB
+7ffff7ffd000-7ffff7ffe000 rw-p 00020000 08:01 1844132                    /lib/x86_64-linux-gnu/ld-2.13.so
+Size:                  4 kB
+Rss:                   4 kB
+Pss:                   4 kB
+Shared_Clean:          0 kB
+Shared_Dirty:          0 kB
+Private_Clean:         0 kB
+Private_Dirty:         4 kB
+Referenced:            4 kB
+Anonymous:             4 kB
+AnonHugePages:         0 kB
+Swap:                  0 kB
+KernelPageSize:        4 kB
+MMUPageSize:           4 kB
+Locked:                0 kB
+7ffff7ffe000-7ffff7fff000 rw-p 00000000 00:00 0 
+Size:                  4 kB
+Rss:                   4 kB
+Pss:                   4 kB
+Shared_Clean:          0 kB
+Shared_Dirty:          0 kB
+Private_Clean:         0 kB
+Private_Dirty:         4 kB
+Referenced:            4 kB
+Anonymous:             4 kB
+AnonHugePages:         0 kB
+Swap:                  0 kB
+KernelPageSize:        4 kB
+MMUPageSize:           4 kB
+Locked:                0 kB
+7ffffffde000-7ffffffff000 rw-p 00000000 00:00 0                          [stack]
+Size:                136 kB
+Rss:                  24 kB
+Pss:                  24 kB
+Shared_Clean:          0 kB
+Shared_Dirty:          0 kB
+Private_Clean:         0 kB
+Private_Dirty:        24 kB
+Referenced:           24 kB
+Anonymous:            24 kB
+AnonHugePages:         0 kB
+Swap:                  0 kB
+KernelPageSize:        4 kB
+MMUPageSize:           4 kB
+Locked:                0 kB
+ffffffffff600000-ffffffffff601000 r-xp 00000000 00:00 0                  [vsyscall]
+Size:                  4 kB
+Rss:                   0 kB
+Pss:                   0 kB
+Shared_Clean:          0 kB
+Shared_Dirty:          0 kB
+Private_Clean:         0 kB
+Private_Dirty:         0 kB
+Referenced:            0 kB
+Anonymous:             0 kB
+AnonHugePages:         0 kB
+Swap:                  0 kB
+KernelPageSize:        4 kB
+MMUPageSize:           4 kB
+Locked:                0 kB
diff --git a/src/test/pmem_is_pmem_proc/smaps_unexp_vmflags b/src/test/pmem_is_pmem_proc/smaps_unexp_vmflags
new file mode 100644
index 0000000000000000000000000000000000000000..6c683aa2d5277cdcbe46818f0176f88ae1af1b3d
--- /dev/null
+++ b/src/test/pmem_is_pmem_proc/smaps_unexp_vmflags
@@ -0,0 +1,481 @@
+00400000-00406000 r-xp 00000000 08:01 2366593                            /some/path/src/test/pmem_map/pmem_map
+Size:                 24 kB
+Rss:                  20 kB
+Pss:                  20 kB
+Shared_Clean:          0 kB
+Shared_Dirty:          0 kB
+Private_Clean:        16 kB
+Private_Dirty:         4 kB
+Referenced:           20 kB
+Anonymous:             4 kB
+AnonHugePages:         0 kB
+Swap:                  0 kB
+KernelPageSize:        4 kB
+MMUPageSize:           4 kB
+Locked:                0 kB
+00605000-00606000 rw-p 00005000 08:01 2366593                            /some/path/src/test/pmem_map/pmem_map
+Size:                  4 kB
+Rss:                   4 kB
+Pss:                   4 kB
+Shared_Clean:          0 kB
+Shared_Dirty:          0 kB
+Private_Clean:         0 kB
+Private_Dirty:         4 kB
+Referenced:            4 kB
+Anonymous:             4 kB
+AnonHugePages:         0 kB
+Swap:                  0 kB
+KernelPageSize:        4 kB
+MMUPageSize:           4 kB
+Locked:                0 kB
+00606000-00627000 rw-p 00000000 00:00 0                                  [heap]
+Size:                132 kB
+Rss:                   8 kB
+Pss:                   8 kB
+Shared_Clean:          0 kB
+Shared_Dirty:          0 kB
+Private_Clean:         0 kB
+Private_Dirty:         8 kB
+Referenced:            8 kB
+Anonymous:             8 kB
+AnonHugePages:         0 kB
+Swap:                  0 kB
+KernelPageSize:        4 kB
+MMUPageSize:           4 kB
+Locked:                0 kB
+7fff77423000-7fff77424000 ---s 00000000 08:01 2366604                    /some/path/src/test/pmem_map/testfile1
+Size:                  4 kB
+Rss:                   4 kB
+Pss:                   4 kB
+Shared_Clean:          0 kB
+Shared_Dirty:          0 kB
+Private_Clean:         4 kB
+Private_Dirty:         0 kB
+Referenced:            4 kB
+Anonymous:             0 kB
+AnonHugePages:         0 kB
+Swap:                  0 kB
+KernelPageSize:        4 kB
+MMUPageSize:           4 kB
+Locked:                0 kB
+7fff77424000-7ffff7423000 r--s 00001000 08:01 2366604                    /some/path/src/test/pmem_map/testfile1
+Size:            2097148 kB
+Rss:                   4 kB
+Pss:                   4 kB
+Shared_Clean:          0 kB
+Shared_Dirty:          0 kB
+Private_Clean:         4 kB
+Private_Dirty:         0 kB
+Referenced:            4 kB
+Anonymous:             0 kB
+AnonHugePages:         0 kB
+Swap:                  0 kB
+KernelPageSize:        4 kB
+MMUPageSize:           4 kB
+Locked:                0 kB
+VmFlags: rd ex mm mr mw me dw sd 
+7ffff7423000-7ffff75a5000 r-xp 00000000 08:01 1844444                    /lib/x86_64-linux-gnu/libc-2.13.so
+Size:               1544 kB
+Rss:                 364 kB
+Pss:                  53 kB
+Shared_Clean:        360 kB
+Shared_Dirty:          0 kB
+Private_Clean:         0 kB
+Private_Dirty:         4 kB
+Referenced:          364 kB
+Anonymous:             4 kB
+AnonHugePages:         0 kB
+Swap:                  0 kB
+KernelPageSize:        4 kB
+MMUPageSize:           4 kB
+Locked:                0 kB
+7ffff75a5000-7ffff77a4000 ---p 00182000 08:01 1844444                    /lib/x86_64-linux-gnu/libc-2.13.so
+Size:               2044 kB
+Rss:                   0 kB
+Pss:                   0 kB
+Shared_Clean:          0 kB
+Shared_Dirty:          0 kB
+Private_Clean:         0 kB
+Private_Dirty:         0 kB
+Referenced:            0 kB
+Anonymous:             0 kB
+AnonHugePages:         0 kB
+Swap:                  0 kB
+KernelPageSize:        4 kB
+MMUPageSize:           4 kB
+Locked:                0 kB
+7ffff77a4000-7ffff77a8000 r--p 00181000 08:01 1844444                    /lib/x86_64-linux-gnu/libc-2.13.so
+Size:                 16 kB
+Rss:                  16 kB
+Pss:                  16 kB
+Shared_Clean:          0 kB
+Shared_Dirty:          0 kB
+Private_Clean:         0 kB
+Private_Dirty:        16 kB
+Referenced:           16 kB
+Anonymous:            16 kB
+AnonHugePages:         0 kB
+Swap:                  0 kB
+KernelPageSize:        4 kB
+MMUPageSize:           4 kB
+Locked:                0 kB
+7ffff77a8000-7ffff77a9000 rw-p 00185000 08:01 1844444                    /lib/x86_64-linux-gnu/libc-2.13.so
+Size:                  4 kB
+Rss:                   4 kB
+Pss:                   4 kB
+Shared_Clean:          0 kB
+Shared_Dirty:          0 kB
+Private_Clean:         0 kB
+Private_Dirty:         4 kB
+Referenced:            4 kB
+Anonymous:             4 kB
+AnonHugePages:         0 kB
+Swap:                  0 kB
+KernelPageSize:        4 kB
+MMUPageSize:           4 kB
+Locked:                0 kB
+7ffff77a9000-7ffff77ae000 rw-p 00000000 00:00 0 
+Size:                 20 kB
+Rss:                  16 kB
+Pss:                  16 kB
+Shared_Clean:          0 kB
+Shared_Dirty:          0 kB
+Private_Clean:         0 kB
+Private_Dirty:        16 kB
+Referenced:           16 kB
+Anonymous:            16 kB
+AnonHugePages:         0 kB
+Swap:                  0 kB
+KernelPageSize:        4 kB
+MMUPageSize:           4 kB
+Locked:                0 kB
+7ffff77ae000-7ffff77c5000 r-xp 00000000 08:01 1845832                    /lib/x86_64-linux-gnu/libpthread-2.13.so
+Size:                 92 kB
+Rss:                  52 kB
+Pss:                  14 kB
+Shared_Clean:         44 kB
+Shared_Dirty:          0 kB
+Private_Clean:         0 kB
+Private_Dirty:         8 kB
+Referenced:           52 kB
+Anonymous:             8 kB
+AnonHugePages:         0 kB
+Swap:                  0 kB
+KernelPageSize:        4 kB
+MMUPageSize:           4 kB
+Locked:                0 kB
+7ffff77c5000-7ffff79c4000 ---p 00017000 08:01 1845832                    /lib/x86_64-linux-gnu/libpthread-2.13.so
+Size:               2044 kB
+Rss:                   0 kB
+Pss:                   0 kB
+Shared_Clean:          0 kB
+Shared_Dirty:          0 kB
+Private_Clean:         0 kB
+Private_Dirty:         0 kB
+Referenced:            0 kB
+Anonymous:             0 kB
+AnonHugePages:         0 kB
+Swap:                  0 kB
+KernelPageSize:        4 kB
+MMUPageSize:           4 kB
+Locked:                0 kB
+7ffff79c4000-7ffff79c5000 r--p 00016000 08:01 1845832                    /lib/x86_64-linux-gnu/libpthread-2.13.so
+Size:                  4 kB
+Rss:                   4 kB
+Pss:                   4 kB
+Shared_Clean:          0 kB
+Shared_Dirty:          0 kB
+Private_Clean:         0 kB
+Private_Dirty:         4 kB
+Referenced:            4 kB
+Anonymous:             4 kB
+AnonHugePages:         0 kB
+Swap:                  0 kB
+KernelPageSize:        4 kB
+MMUPageSize:           4 kB
+Locked:                0 kB
+7ffff79c5000-7ffff79c6000 rw-p 00017000 08:01 1845832                    /lib/x86_64-linux-gnu/libpthread-2.13.so
+Size:                  4 kB
+Rss:                   4 kB
+Pss:                   4 kB
+Shared_Clean:          0 kB
+Shared_Dirty:          0 kB
+Private_Clean:         0 kB
+Private_Dirty:         4 kB
+Referenced:            4 kB
+Anonymous:             4 kB
+AnonHugePages:         0 kB
+Swap:                  0 kB
+KernelPageSize:        4 kB
+MMUPageSize:           4 kB
+Locked:                0 kB
+7ffff79c6000-7ffff79ca000 rw-p 00000000 00:00 0 
+Size:                 16 kB
+Rss:                   4 kB
+Pss:                   4 kB
+Shared_Clean:          0 kB
+Shared_Dirty:          0 kB
+Private_Clean:         0 kB
+Private_Dirty:         4 kB
+Referenced:            4 kB
+Anonymous:             4 kB
+AnonHugePages:         0 kB
+Swap:                  0 kB
+KernelPageSize:        4 kB
+MMUPageSize:           4 kB
+Locked:                0 kB
+7ffff79ca000-7ffff79d7000 r-xp 00000000 08:01 2366292                    /some/path/src/debug/libpmem.so
+Size:                 52 kB
+Rss:                  28 kB
+Pss:                  28 kB
+Shared_Clean:          0 kB
+Shared_Dirty:          0 kB
+Private_Clean:        28 kB
+Private_Dirty:         0 kB
+Referenced:           28 kB
+Anonymous:             0 kB
+AnonHugePages:         0 kB
+Swap:                  0 kB
+KernelPageSize:        4 kB
+MMUPageSize:           4 kB
+Locked:                0 kB
+7ffff79d7000-7ffff7bd6000 ---p 0000d000 08:01 2366292                    /some/path/src/debug/libpmem.so
+Size:               2044 kB
+Rss:                   0 kB
+Pss:                   0 kB
+Shared_Clean:          0 kB
+Shared_Dirty:          0 kB
+Private_Clean:         0 kB
+Private_Dirty:         0 kB
+Referenced:            0 kB
+Anonymous:             0 kB
+AnonHugePages:         0 kB
+Swap:                  0 kB
+KernelPageSize:        4 kB
+MMUPageSize:           4 kB
+Locked:                0 kB
+7ffff7bd6000-7ffff7bd7000 rw-p 0000c000 08:01 2366292                    /some/path/src/debug/libpmem.so
+Size:                  4 kB
+Rss:                   4 kB
+Pss:                   4 kB
+Shared_Clean:          0 kB
+Shared_Dirty:          0 kB
+Private_Clean:         0 kB
+Private_Dirty:         4 kB
+Referenced:            4 kB
+Anonymous:             4 kB
+AnonHugePages:         0 kB
+Swap:                  0 kB
+KernelPageSize:        4 kB
+MMUPageSize:           4 kB
+Locked:                0 kB
+7ffff7bd7000-7ffff7bd8000 rw-p 00000000 00:00 0 
+Size:                  4 kB
+Rss:                   4 kB
+Pss:                   4 kB
+Shared_Clean:          0 kB
+Shared_Dirty:          0 kB
+Private_Clean:         0 kB
+Private_Dirty:         4 kB
+Referenced:            4 kB
+Anonymous:             4 kB
+AnonHugePages:         0 kB
+Swap:                  0 kB
+KernelPageSize:        4 kB
+MMUPageSize:           4 kB
+Locked:                0 kB
+7ffff7bd8000-7ffff7bdc000 r-xp 00000000 08:01 1835968                    /lib/x86_64-linux-gnu/libuuid.so.1.3.0
+Size:                 16 kB
+Rss:                  12 kB
+Pss:                  12 kB
+Shared_Clean:          0 kB
+Shared_Dirty:          0 kB
+Private_Clean:        12 kB
+Private_Dirty:         0 kB
+Referenced:           12 kB
+Anonymous:             0 kB
+AnonHugePages:         0 kB
+Swap:                  0 kB
+KernelPageSize:        4 kB
+MMUPageSize:           4 kB
+Locked:                0 kB
+7ffff7bdc000-7ffff7ddb000 ---p 00004000 08:01 1835968                    /lib/x86_64-linux-gnu/libuuid.so.1.3.0
+Size:               2044 kB
+Rss:                   0 kB
+Pss:                   0 kB
+Shared_Clean:          0 kB
+Shared_Dirty:          0 kB
+Private_Clean:         0 kB
+Private_Dirty:         0 kB
+Referenced:            0 kB
+Anonymous:             0 kB
+AnonHugePages:         0 kB
+Swap:                  0 kB
+KernelPageSize:        4 kB
+MMUPageSize:           4 kB
+Locked:                0 kB
+7ffff7ddb000-7ffff7ddc000 r--p 00003000 08:01 1835968                    /lib/x86_64-linux-gnu/libuuid.so.1.3.0
+Size:                  4 kB
+Rss:                   4 kB
+Pss:                   4 kB
+Shared_Clean:          0 kB
+Shared_Dirty:          0 kB
+Private_Clean:         0 kB
+Private_Dirty:         4 kB
+Referenced:            4 kB
+Anonymous:             4 kB
+AnonHugePages:         0 kB
+Swap:                  0 kB
+KernelPageSize:        4 kB
+MMUPageSize:           4 kB
+Locked:                0 kB
+7ffff7ddc000-7ffff7ddd000 rw-p 00004000 08:01 1835968                    /lib/x86_64-linux-gnu/libuuid.so.1.3.0
+Size:                  4 kB
+Rss:                   4 kB
+Pss:                   4 kB
+Shared_Clean:          0 kB
+Shared_Dirty:          0 kB
+Private_Clean:         0 kB
+Private_Dirty:         4 kB
+Referenced:            4 kB
+Anonymous:             4 kB
+AnonHugePages:         0 kB
+Swap:                  0 kB
+KernelPageSize:        4 kB
+MMUPageSize:           4 kB
+Locked:                0 kB
+7ffff7ddd000-7ffff7dfd000 r-xp 00000000 08:01 1844132                    /lib/x86_64-linux-gnu/ld-2.13.so
+Size:                128 kB
+Rss:                 108 kB
+Pss:                  33 kB
+Shared_Clean:        104 kB
+Shared_Dirty:          0 kB
+Private_Clean:         0 kB
+Private_Dirty:         4 kB
+Referenced:          108 kB
+Anonymous:             4 kB
+AnonHugePages:         0 kB
+Swap:                  0 kB
+KernelPageSize:        4 kB
+MMUPageSize:           4 kB
+Locked:                0 kB
+7ffff7fe3000-7ffff7fe7000 rw-p 00000000 00:00 0 
+Size:                 16 kB
+Rss:                  16 kB
+Pss:                  16 kB
+Shared_Clean:          0 kB
+Shared_Dirty:          0 kB
+Private_Clean:         0 kB
+Private_Dirty:        16 kB
+Referenced:           16 kB
+Anonymous:            16 kB
+AnonHugePages:         0 kB
+Swap:                  0 kB
+KernelPageSize:        4 kB
+MMUPageSize:           4 kB
+Locked:                0 kB
+7ffff7ff6000-7ffff7ffb000 rw-p 00000000 00:00 0 
+Size:                 20 kB
+Rss:                  20 kB
+Pss:                  20 kB
+Shared_Clean:          0 kB
+Shared_Dirty:          0 kB
+Private_Clean:         0 kB
+Private_Dirty:        20 kB
+Referenced:           20 kB
+Anonymous:            20 kB
+AnonHugePages:         0 kB
+Swap:                  0 kB
+KernelPageSize:        4 kB
+MMUPageSize:           4 kB
+Locked:                0 kB
+7ffff7ffb000-7ffff7ffc000 r-xp 00000000 00:00 0                          [vdso]
+Size:                  4 kB
+Rss:                   4 kB
+Pss:                   0 kB
+Shared_Clean:          4 kB
+Shared_Dirty:          0 kB
+Private_Clean:         0 kB
+Private_Dirty:         0 kB
+Referenced:            4 kB
+Anonymous:             0 kB
+AnonHugePages:         0 kB
+Swap:                  0 kB
+KernelPageSize:        4 kB
+MMUPageSize:           4 kB
+Locked:                0 kB
+7ffff7ffc000-7ffff7ffd000 r--p 0001f000 08:01 1844132                    /lib/x86_64-linux-gnu/ld-2.13.so
+Size:                  4 kB
+Rss:                   4 kB
+Pss:                   4 kB
+Shared_Clean:          0 kB
+Shared_Dirty:          0 kB
+Private_Clean:         0 kB
+Private_Dirty:         4 kB
+Referenced:            4 kB
+Anonymous:             4 kB
+AnonHugePages:         0 kB
+Swap:                  0 kB
+KernelPageSize:        4 kB
+MMUPageSize:           4 kB
+Locked:                0 kB
+7ffff7ffd000-7ffff7ffe000 rw-p 00020000 08:01 1844132                    /lib/x86_64-linux-gnu/ld-2.13.so
+Size:                  4 kB
+Rss:                   4 kB
+Pss:                   4 kB
+Shared_Clean:          0 kB
+Shared_Dirty:          0 kB
+Private_Clean:         0 kB
+Private_Dirty:         4 kB
+Referenced:            4 kB
+Anonymous:             4 kB
+AnonHugePages:         0 kB
+Swap:                  0 kB
+KernelPageSize:        4 kB
+MMUPageSize:           4 kB
+Locked:                0 kB
+7ffff7ffe000-7ffff7fff000 rw-p 00000000 00:00 0 
+Size:                  4 kB
+Rss:                   4 kB
+Pss:                   4 kB
+Shared_Clean:          0 kB
+Shared_Dirty:          0 kB
+Private_Clean:         0 kB
+Private_Dirty:         4 kB
+Referenced:            4 kB
+Anonymous:             4 kB
+AnonHugePages:         0 kB
+Swap:                  0 kB
+KernelPageSize:        4 kB
+MMUPageSize:           4 kB
+Locked:                0 kB
+7ffffffde000-7ffffffff000 rw-p 00000000 00:00 0                          [stack]
+Size:                136 kB
+Rss:                  24 kB
+Pss:                  24 kB
+Shared_Clean:          0 kB
+Shared_Dirty:          0 kB
+Private_Clean:         0 kB
+Private_Dirty:        24 kB
+Referenced:           24 kB
+Anonymous:            24 kB
+AnonHugePages:         0 kB
+Swap:                  0 kB
+KernelPageSize:        4 kB
+MMUPageSize:           4 kB
+Locked:                0 kB
+ffffffffff600000-ffffffffff601000 r-xp 00000000 00:00 0                  [vsyscall]
+Size:                  4 kB
+Rss:                   0 kB
+Pss:                   0 kB
+Shared_Clean:          0 kB
+Shared_Dirty:          0 kB
+Private_Clean:         0 kB
+Private_Dirty:         0 kB
+Referenced:            0 kB
+Anonymous:             0 kB
+AnonHugePages:         0 kB
+Swap:                  0 kB
+KernelPageSize:        4 kB
+MMUPageSize:           4 kB
+Locked:                0 kB
diff --git a/src/test/pmem_map/.gitignore b/src/test/pmem_map/.gitignore
new file mode 100644
index 0000000000000000000000000000000000000000..e293c6e0ab8be8d21bae243c60a5af6674620946
--- /dev/null
+++ b/src/test/pmem_map/.gitignore
@@ -0,0 +1 @@
+pmem_map
diff --git a/src/test/pmem_map/Makefile b/src/test/pmem_map/Makefile
new file mode 100644
index 0000000000000000000000000000000000000000..745925fa46c0e8d1535dee79686bdbe785437e11
--- /dev/null
+++ b/src/test/pmem_map/Makefile
@@ -0,0 +1,43 @@
+#
+# Copyright (c) 2014, Intel Corporation
+#
+# Redistribution and use in source and binary forms, with or without
+# modification, are permitted provided that the following conditions
+# are met:
+#
+#     * Redistributions of source code must retain the above copyright
+#       notice, this list of conditions and the following disclaimer.
+#
+#     * Redistributions in binary form must reproduce the above copyright
+#       notice, this list of conditions and the following disclaimer in
+#       the documentation and/or other materials provided with the
+#       distribution.
+#
+#     * Neither the name of Intel Corporation nor the names of its
+#       contributors may be used to endorse or promote products derived
+#       from this software without specific prior written permission.
+#
+# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+#
+
+#
+# src/test/pmem_map/Makefile -- build pmem_map unit test
+#
+TARGET = pmem_map
+OBJS = pmem_map.o
+
+include ../Makefile.inc
+
+LIBS += -lpmem
+
+pmem_map.o: pmem_map.c
diff --git a/src/test/pmem_map/README b/src/test/pmem_map/README
new file mode 100644
index 0000000000000000000000000000000000000000..9a623e2d658f49569fcdcdbeaf4532dc5167c2fd
--- /dev/null
+++ b/src/test/pmem_map/README
@@ -0,0 +1,33 @@
+Linux NVM Library
+
+This is src/test/pmem_map/README.
+
+This directory contains a unit test for pmem{trn,blk,log}_map().
+
+The program in pmem_map.c takes a list of files with a pool type
+prefix on them.  For example:
+
+	./pmem_map t:file1 b:file2 l:file3
+
+will call pmemtrn_map() on file1, pmemblk_map() on file2, and
+pmemlog_map() on file3.
+
+The first 4k of the file is captured before and after the map calls
+are done, and the program reports if the first 4k changed.  This can
+be used to determine if a new memory pool was created (so the header
+was generated and the program reports a change), or an existing pool
+was found (so the header was left alone and the program reports no
+change).
+
+Finally, the program then tried to dereference the opaque pool handle
+and prints a message is a SEGV signal results (which it should).
+
+By passing the same file multiple times, more interesting scenarios
+can be tested.  For example:
+
+	./pmem_map t:file1 t:file1 b:file1
+
+can be used to test that the first argument causes a new pool to be
+created, the second argument causes an existing pool to be found, and
+the third argument causes EINVAL due to opening a pmemtrn pool with
+pmemblk_map().
diff --git a/src/test/pmem_map/TEST0 b/src/test/pmem_map/TEST0
new file mode 100755
index 0000000000000000000000000000000000000000..0feb956037ea03160fa03cc61aca3147c5951a7f
--- /dev/null
+++ b/src/test/pmem_map/TEST0
@@ -0,0 +1,64 @@
+#!/bin/bash -e
+#
+# Copyright (c) 2014, Intel Corporation
+#
+# Redistribution and use in source and binary forms, with or without
+# modification, are permitted provided that the following conditions
+# are met:
+#
+#     * Redistributions of source code must retain the above copyright
+#       notice, this list of conditions and the following disclaimer.
+#
+#     * Redistributions in binary form must reproduce the above copyright
+#       notice, this list of conditions and the following disclaimer in
+#       the documentation and/or other materials provided with the
+#       distribution.
+#
+#     * Neither the name of Intel Corporation nor the names of its
+#       contributors may be used to endorse or promote products derived
+#       from this software without specific prior written permission.
+#
+# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+#
+
+#
+# src/test/pmem_map/TEST0 -- unit test for pmem{trn,blk,log}_map
+#
+export UNITTEST_NAME=pmem_map/TEST0
+export UNITTEST_NUM=0
+
+# standard unit test setup
+. ../unittest/unittest.sh
+
+require_fs_type local
+
+setup
+
+rm -f $DIR/testfile1
+truncate -s 2G $DIR/testfile1
+#
+# pass the same file multiple times
+#	the first time the file is new, so the pool is created
+#	(and the test program will report the first 4k changed)
+#	the second time the file has a pool in it
+#	(and the test program will report the first 4k didn't change)
+#	the third time we pass the pool to the wrong map function
+#	(and the test program will report the map function failed)
+#
+expect_normal_exit ./pmem_map$EXESUFFIX\
+	t:$DIR/testfile1 t:$DIR/testfile1 b:$DIR/testfile1
+rm $DIR/testfile1
+
+check
+
+pass
diff --git a/src/test/pmem_map/TEST1 b/src/test/pmem_map/TEST1
new file mode 100755
index 0000000000000000000000000000000000000000..b17cd9be4bab34b85c32ad25f92bc7e7e12c3743
--- /dev/null
+++ b/src/test/pmem_map/TEST1
@@ -0,0 +1,64 @@
+#!/bin/bash -e
+#
+# Copyright (c) 2014, Intel Corporation
+#
+# Redistribution and use in source and binary forms, with or without
+# modification, are permitted provided that the following conditions
+# are met:
+#
+#     * Redistributions of source code must retain the above copyright
+#       notice, this list of conditions and the following disclaimer.
+#
+#     * Redistributions in binary form must reproduce the above copyright
+#       notice, this list of conditions and the following disclaimer in
+#       the documentation and/or other materials provided with the
+#       distribution.
+#
+#     * Neither the name of Intel Corporation nor the names of its
+#       contributors may be used to endorse or promote products derived
+#       from this software without specific prior written permission.
+#
+# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+#
+
+#
+# src/test/pmem_map/TEST1 -- unit test for pmem{trn,blk,log}_map
+#
+export UNITTEST_NAME=pmem_map/TEST1
+export UNITTEST_NUM=1
+
+# standard unit test setup
+. ../unittest/unittest.sh
+
+require_fs_type local
+
+setup
+
+rm -f $DIR/testfile1
+truncate -s 2G $DIR/testfile1
+#
+# pass the same file multiple times
+#	the first time the file is new, so the pool is created
+#	(and the test program will report the first 4k changed)
+#	the second time the file has a pool in it
+#	(and the test program will report the first 4k didn't change)
+#	the third time we pass the pool to the wrong map function
+#	(and the test program will report the map function failed)
+#
+expect_normal_exit ./pmem_map$EXESUFFIX\
+	b:$DIR/testfile1 b:$DIR/testfile1 l:$DIR/testfile1
+rm $DIR/testfile1
+
+check
+
+pass
diff --git a/src/test/pmem_map/TEST2 b/src/test/pmem_map/TEST2
new file mode 100755
index 0000000000000000000000000000000000000000..adb82dd13c53b3ad7376152118c24232042d1761
--- /dev/null
+++ b/src/test/pmem_map/TEST2
@@ -0,0 +1,64 @@
+#!/bin/bash -e
+#
+# Copyright (c) 2014, Intel Corporation
+#
+# Redistribution and use in source and binary forms, with or without
+# modification, are permitted provided that the following conditions
+# are met:
+#
+#     * Redistributions of source code must retain the above copyright
+#       notice, this list of conditions and the following disclaimer.
+#
+#     * Redistributions in binary form must reproduce the above copyright
+#       notice, this list of conditions and the following disclaimer in
+#       the documentation and/or other materials provided with the
+#       distribution.
+#
+#     * Neither the name of Intel Corporation nor the names of its
+#       contributors may be used to endorse or promote products derived
+#       from this software without specific prior written permission.
+#
+# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+#
+
+#
+# src/test/pmem_map/TEST2 -- unit test for pmem{trn,blk,log}_map
+#
+export UNITTEST_NAME=pmem_map/TEST2
+export UNITTEST_NUM=2
+
+# standard unit test setup
+. ../unittest/unittest.sh
+
+require_fs_type local
+
+setup
+
+rm -f $DIR/testfile1
+truncate -s 2G $DIR/testfile1
+#
+# pass the same file multiple times
+#	the first time the file is new, so the pool is created
+#	(and the test program will report the first 4k changed)
+#	the second time the file has a pool in it
+#	(and the test program will report the first 4k didn't change)
+#	the third time we pass the pool to the wrong map function
+#	(and the test program will report the map function failed)
+#
+expect_normal_exit ./pmem_map$EXESUFFIX\
+	l:$DIR/testfile1 l:$DIR/testfile1 t:$DIR/testfile1
+rm $DIR/testfile1
+
+check
+
+pass
diff --git a/src/test/pmem_map/err0.log.match b/src/test/pmem_map/err0.log.match
new file mode 100644
index 0000000000000000000000000000000000000000..e69de29bb2d1d6434b8b29ae775ad8c2e48c5391
diff --git a/src/test/pmem_map/err1.log.match b/src/test/pmem_map/err1.log.match
new file mode 100644
index 0000000000000000000000000000000000000000..e69de29bb2d1d6434b8b29ae775ad8c2e48c5391
diff --git a/src/test/pmem_map/err2.log.match b/src/test/pmem_map/err2.log.match
new file mode 100644
index 0000000000000000000000000000000000000000..e69de29bb2d1d6434b8b29ae775ad8c2e48c5391
diff --git a/src/test/pmem_map/out0.log.match b/src/test/pmem_map/out0.log.match
new file mode 100644
index 0000000000000000000000000000000000000000..eadc5cd1e8ce025204865d715b341e79c25786b5
--- /dev/null
+++ b/src/test/pmem_map/out0.log.match
@@ -0,0 +1,9 @@
+pmem_map/TEST0: START: pmem_map
+ ./pmem_map$(*) t:$(*)/testfile1 t:$(*)/testfile1 b:$(*)/testfile1
+t:$(*)/testfile1: first 4096 bytes changed during map
+signal: Segmentation fault
+t:$(*)/testfile1: first 4096 bytes unchanged during map
+signal: Segmentation fault
+b:$(*)/testfile1: first 4096 bytes unchanged during map
+pmemblk_map: Invalid argument
+pmem_map/TEST0: Done
diff --git a/src/test/pmem_map/out1.log.match b/src/test/pmem_map/out1.log.match
new file mode 100644
index 0000000000000000000000000000000000000000..15a110af9d8ca125f23803a80d4a6fe4d9424ffc
--- /dev/null
+++ b/src/test/pmem_map/out1.log.match
@@ -0,0 +1,9 @@
+pmem_map/TEST1: START: pmem_map
+ ./pmem_map$(*) b:$(*)/testfile1 b:$(*)/testfile1 l:$(*)/testfile1
+b:$(*)/testfile1: first 4096 bytes changed during map
+signal: Segmentation fault
+b:$(*)/testfile1: first 4096 bytes unchanged during map
+signal: Segmentation fault
+l:$(*)/testfile1: first 4096 bytes unchanged during map
+pmemlog_map: Invalid argument
+pmem_map/TEST1: Done
diff --git a/src/test/pmem_map/out2.log.match b/src/test/pmem_map/out2.log.match
new file mode 100644
index 0000000000000000000000000000000000000000..f2ae5c2ce492fd523f65876c7f1134c366463216
--- /dev/null
+++ b/src/test/pmem_map/out2.log.match
@@ -0,0 +1,9 @@
+pmem_map/TEST2: START: pmem_map
+ ./pmem_map$(*) l:$(*)/testfile1 l:$(*)/testfile1 t:$(*)/testfile1
+l:$(*)/testfile1: first 4096 bytes changed during map
+signal: Segmentation fault
+l:$(*)/testfile1: first 4096 bytes unchanged during map
+signal: Segmentation fault
+t:$(*)/testfile1: first 4096 bytes unchanged during map
+pmemtrn_map: Invalid argument
+pmem_map/TEST2: Done
diff --git a/src/test/pmem_map/pmem_map.c b/src/test/pmem_map/pmem_map.c
new file mode 100644
index 0000000000000000000000000000000000000000..b1b5543284f1cc427f3e43ed238b8689b9bdac6b
--- /dev/null
+++ b/src/test/pmem_map/pmem_map.c
@@ -0,0 +1,162 @@
+/*
+ * Copyright (c) 2014, Intel Corporation
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ *     * Redistributions of source code must retain the above copyright
+ *       notice, this list of conditions and the following disclaimer.
+ *
+ *     * Redistributions in binary form must reproduce the above copyright
+ *       notice, this list of conditions and the following disclaimer in
+ *       the documentation and/or other materials provided with the
+ *       distribution.
+ *
+ *     * Neither the name of Intel Corporation nor the names of its
+ *       contributors may be used to endorse or promote products derived
+ *       from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+/*
+ * pmem_map.c -- unit test for mapping different types of pmem pools
+ *
+ * usage: pmem_map <type>:file ...
+ *
+ * each file is mapped with:
+ * 	pmemtrn_map() if the filename starts with t:
+ * 	pmemblk_map() if the filename starts with b:
+ * 	pmemlog_map() if the filename starts with l:
+ * and the handle returned is dereferenced to force a SEGV.
+ */
+
+#include "unittest.h"
+
+#define	CHECK_BYTES 4096	/* bytes to compare before/after map call */
+
+sigjmp_buf Jmp;
+
+/*
+ * signal_handler -- called on SIGSEGV
+ */
+void
+signal_handler(int sig)
+{
+	OUT("signal: %s", strsignal(sig));
+
+	siglongjmp(Jmp, 1);
+}
+
+int
+main(int argc, char *argv[])
+{
+	START(argc, argv, "pmem_map");
+
+	if (argc < 2)
+		FATAL("usage: %s <type>:file ...", argv[0]);
+
+	/* arrange to catch SEGV */
+	struct sigvec v = { 0 };
+	v.sv_handler = signal_handler;
+	SIGVEC(SIGSEGV, &v, NULL);
+
+	/* map each file argument with the given map type */
+	for (int arg = 1; arg < argc; arg++) {
+		if (strchr("tbl", argv[arg][0]) == NULL || argv[arg][1] != ':')
+			FATAL("type must be t: or b: or l:");
+
+		int fd = OPEN(&argv[arg][2], O_RDWR);
+
+		char before[CHECK_BYTES];
+		char after[CHECK_BYTES];
+
+		READ(fd, before, CHECK_BYTES);
+
+		void *handle = NULL;
+		switch (argv[arg][0]) {
+		case 't':
+			handle = pmemtrn_map(fd);
+			break;
+
+		case 'b':
+			handle = pmemblk_map(fd, 4096);
+			break;
+
+		case 'l':
+			handle = pmemlog_map(fd);
+			break;
+
+		default:
+			FATAL(NULL);	/* can't happen */
+		}
+
+		LSEEK(fd, (off_t)0, SEEK_SET);
+
+		if (READ(fd, after, CHECK_BYTES) == CHECK_BYTES) {
+			if (memcmp(before, after, CHECK_BYTES))
+				OUT("%s: first %d bytes changed during map",
+					argv[arg], CHECK_BYTES);
+			else
+				OUT("%s: first %d bytes unchanged during map",
+					argv[arg], CHECK_BYTES);
+		}
+
+		close(fd);
+
+		if (handle == NULL) {
+			switch (argv[arg][0]) {
+			case 't':
+				OUT("!pmemtrn_map");
+				break;
+
+			case 'b':
+				OUT("!pmemblk_map");
+				break;
+
+			case 'l':
+				OUT("!pmemlog_map");
+				break;
+
+			default:
+				FATAL(NULL);	/* can't happen */
+			}
+		} else if (!sigsetjmp(Jmp, 1)) {
+			/* try to deref the opaque handle */
+			char x = *(char *)handle;
+
+			OUT("x = %c", x);	/* shouldn't get here */
+		} else {
+			/* back from signal handler, unmap the pool */
+			switch (argv[arg][0]) {
+			case 't':
+				pmemtrn_unmap(handle);
+				break;
+
+			case 'b':
+				pmemblk_unmap(handle);
+				break;
+
+			case 'l':
+				pmemlog_unmap(handle);
+				break;
+
+			default:
+				FATAL(NULL);	/* can't happen */
+			}
+		}
+	}
+
+	DONE(NULL);
+}
diff --git a/src/test/scope/Makefile b/src/test/scope/Makefile
new file mode 100644
index 0000000000000000000000000000000000000000..effaac5488b9c65a25d42bb2ba301172c72b15cf
--- /dev/null
+++ b/src/test/scope/Makefile
@@ -0,0 +1,47 @@
+#
+# Copyright (c) 2014, Intel Corporation
+#
+# Redistribution and use in source and binary forms, with or without
+# modification, are permitted provided that the following conditions
+# are met:
+#
+#     * Redistributions of source code must retain the above copyright
+#       notice, this list of conditions and the following disclaimer.
+#
+#     * Redistributions in binary form must reproduce the above copyright
+#       notice, this list of conditions and the following disclaimer in
+#       the documentation and/or other materials provided with the
+#       distribution.
+#
+#     * Neither the name of Intel Corporation nor the names of its
+#       contributors may be used to endorse or promote products derived
+#       from this software without specific prior written permission.
+#
+# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+#
+
+#
+# src/test/scope/Makefile -- build scope unit test
+#
+# This Makefile doesn't use ../Makefile.inc since there's no C to build.
+#
+all:
+
+clean:
+	$(RM) *.o */*.o core a.out *.log testfile*
+
+clobber: clean
+
+cstyle:
+
+.PHONY: all clean clobber
diff --git a/src/test/scope/TEST0 b/src/test/scope/TEST0
new file mode 100755
index 0000000000000000000000000000000000000000..75be0fa43bc792fe6d0c9dc90d20bfbe171544c2
--- /dev/null
+++ b/src/test/scope/TEST0
@@ -0,0 +1,54 @@
+#!/bin/bash -e
+#
+# Copyright (c) 2014, Intel Corporation
+#
+# Redistribution and use in source and binary forms, with or without
+# modification, are permitted provided that the following conditions
+# are met:
+#
+#     * Redistributions of source code must retain the above copyright
+#       notice, this list of conditions and the following disclaimer.
+#
+#     * Redistributions in binary form must reproduce the above copyright
+#       notice, this list of conditions and the following disclaimer in
+#       the documentation and/or other materials provided with the
+#       distribution.
+#
+#     * Neither the name of Intel Corporation nor the names of its
+#       contributors may be used to endorse or promote products derived
+#       from this software without specific prior written permission.
+#
+# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+#
+
+#
+# src/test/scope/TEST0 -- scope test to check libpmem symbols
+#
+export UNITTEST_NAME=scope/TEST0
+export UNITTEST_NUM=0
+
+# standard unit test setup
+. ../unittest/unittest.sh
+
+require_fs_type local
+require_build_type debug
+
+setup
+
+(nm -g ../../debug/libpmem.so |\
+	perl -ne 'print if s/^[0-9a-z]+ T (\w+)/$1/' |\
+	sort > out0.log) 2> err0.log
+
+check
+
+pass
diff --git a/src/test/scope/TEST1 b/src/test/scope/TEST1
new file mode 100755
index 0000000000000000000000000000000000000000..c861ef43364b25eef16e5983aaf8931287c13b75
--- /dev/null
+++ b/src/test/scope/TEST1
@@ -0,0 +1,54 @@
+#!/bin/bash -e
+#
+# Copyright (c) 2014, Intel Corporation
+#
+# Redistribution and use in source and binary forms, with or without
+# modification, are permitted provided that the following conditions
+# are met:
+#
+#     * Redistributions of source code must retain the above copyright
+#       notice, this list of conditions and the following disclaimer.
+#
+#     * Redistributions in binary form must reproduce the above copyright
+#       notice, this list of conditions and the following disclaimer in
+#       the documentation and/or other materials provided with the
+#       distribution.
+#
+#     * Neither the name of Intel Corporation nor the names of its
+#       contributors may be used to endorse or promote products derived
+#       from this software without specific prior written permission.
+#
+# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+#
+
+#
+# src/test/scope/TEST1 -- scope test to check libvmem symbols
+#
+export UNITTEST_NAME=scope/TEST1
+export UNITTEST_NUM=1
+
+# standard unit test setup
+. ../unittest/unittest.sh
+
+require_fs_type local
+require_build_type debug
+
+setup
+
+(nm -g ../../debug/libvmem.so |\
+	perl -ne 'print if s/^[0-9a-z]+ T (\w+)/$1/' |\
+	sort > out1.log) 2> err1.log
+
+check
+
+pass
diff --git a/src/test/scope/TEST2 b/src/test/scope/TEST2
new file mode 100755
index 0000000000000000000000000000000000000000..d032ab07ef0ea30c94d585e25e07e5c470725761
--- /dev/null
+++ b/src/test/scope/TEST2
@@ -0,0 +1,54 @@
+#!/bin/bash -e
+#
+# Copyright (c) 2014, Intel Corporation
+#
+# Redistribution and use in source and binary forms, with or without
+# modification, are permitted provided that the following conditions
+# are met:
+#
+#     * Redistributions of source code must retain the above copyright
+#       notice, this list of conditions and the following disclaimer.
+#
+#     * Redistributions in binary form must reproduce the above copyright
+#       notice, this list of conditions and the following disclaimer in
+#       the documentation and/or other materials provided with the
+#       distribution.
+#
+#     * Neither the name of Intel Corporation nor the names of its
+#       contributors may be used to endorse or promote products derived
+#       from this software without specific prior written permission.
+#
+# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+#
+
+#
+# src/test/scope/TEST2 -- scope test to check libpmem symbols (nondebug)
+#
+export UNITTEST_NAME=scope/TEST2
+export UNITTEST_NUM=2
+
+# standard unit test setup
+. ../unittest/unittest.sh
+
+require_fs_type local
+require_build_type nondebug
+
+setup
+
+(nm -g ../../nondebug/libpmem.so |\
+	perl -ne 'print if s/^[0-9a-z]+ T (\w+)/$1/' |\
+	sort > out2.log) 2> err2.log
+
+check
+
+pass
diff --git a/src/test/scope/TEST3 b/src/test/scope/TEST3
new file mode 100755
index 0000000000000000000000000000000000000000..802099b9f4ac70bfc50f67d9249d745f3c83a45e
--- /dev/null
+++ b/src/test/scope/TEST3
@@ -0,0 +1,54 @@
+#!/bin/bash -e
+#
+# Copyright (c) 2014, Intel Corporation
+#
+# Redistribution and use in source and binary forms, with or without
+# modification, are permitted provided that the following conditions
+# are met:
+#
+#     * Redistributions of source code must retain the above copyright
+#       notice, this list of conditions and the following disclaimer.
+#
+#     * Redistributions in binary form must reproduce the above copyright
+#       notice, this list of conditions and the following disclaimer in
+#       the documentation and/or other materials provided with the
+#       distribution.
+#
+#     * Neither the name of Intel Corporation nor the names of its
+#       contributors may be used to endorse or promote products derived
+#       from this software without specific prior written permission.
+#
+# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+#
+
+#
+# src/test/scope/TEST3 -- scope test to check libvmem symbols (nondebug)
+#
+export UNITTEST_NAME=scope/TEST3
+export UNITTEST_NUM=3
+
+# standard unit test setup
+. ../unittest/unittest.sh
+
+require_fs_type local
+require_build_type nondebug
+
+setup
+
+(nm -g ../../nondebug/libvmem.so |\
+	perl -ne 'print if s/^[0-9a-z]+ T (\w+)/$1/' |\
+	sort > out3.log) 2> err3.log
+
+check
+
+pass
diff --git a/src/test/scope/TEST4 b/src/test/scope/TEST4
new file mode 100755
index 0000000000000000000000000000000000000000..9b1586dca818a83af91db7227b6a524153650d93
--- /dev/null
+++ b/src/test/scope/TEST4
@@ -0,0 +1,54 @@
+#!/bin/bash -e
+#
+# Copyright (c) 2014, Intel Corporation
+#
+# Redistribution and use in source and binary forms, with or without
+# modification, are permitted provided that the following conditions
+# are met:
+#
+#     * Redistributions of source code must retain the above copyright
+#       notice, this list of conditions and the following disclaimer.
+#
+#     * Redistributions in binary form must reproduce the above copyright
+#       notice, this list of conditions and the following disclaimer in
+#       the documentation and/or other materials provided with the
+#       distribution.
+#
+#     * Neither the name of Intel Corporation nor the names of its
+#       contributors may be used to endorse or promote products derived
+#       from this software without specific prior written permission.
+#
+# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+#
+
+#
+# src/test/scope/TEST4 -- scope test to check libpmem symbols
+#
+export UNITTEST_NAME=scope/TEST4
+export UNITTEST_NUM=4
+
+# standard unit test setup
+. ../unittest/unittest.sh
+
+require_fs_type local
+require_build_type debug
+
+setup
+
+(nm -g ../../debug/libpmem.a |\
+	perl -ne 'print if s/^[0-9a-z]+ T (\w+)/$1/' |\
+	sort > out4.log) 2> err4.log
+
+check
+
+pass
diff --git a/src/test/scope/TEST5 b/src/test/scope/TEST5
new file mode 100755
index 0000000000000000000000000000000000000000..21eeb9d18668eb84790f23a68cd2d0876e3276a4
--- /dev/null
+++ b/src/test/scope/TEST5
@@ -0,0 +1,54 @@
+#!/bin/bash -e
+#
+# Copyright (c) 2014, Intel Corporation
+#
+# Redistribution and use in source and binary forms, with or without
+# modification, are permitted provided that the following conditions
+# are met:
+#
+#     * Redistributions of source code must retain the above copyright
+#       notice, this list of conditions and the following disclaimer.
+#
+#     * Redistributions in binary form must reproduce the above copyright
+#       notice, this list of conditions and the following disclaimer in
+#       the documentation and/or other materials provided with the
+#       distribution.
+#
+#     * Neither the name of Intel Corporation nor the names of its
+#       contributors may be used to endorse or promote products derived
+#       from this software without specific prior written permission.
+#
+# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+#
+
+#
+# src/test/scope/TEST5 -- scope test to check libvmem symbols
+#
+export UNITTEST_NAME=scope/TEST5
+export UNITTEST_NUM=5
+
+# standard unit test setup
+. ../unittest/unittest.sh
+
+require_fs_type local
+require_build_type debug
+
+setup
+
+(nm -g ../../debug/libvmem.a |\
+	perl -ne 'print if s/^[0-9a-z]+ T (\w+)/$1/' |\
+	sort > out5.log) 2> err5.log
+
+check
+
+pass
diff --git a/src/test/scope/TEST6 b/src/test/scope/TEST6
new file mode 100755
index 0000000000000000000000000000000000000000..702377e0feefe45ffa5e96e62eec56eea0c026a2
--- /dev/null
+++ b/src/test/scope/TEST6
@@ -0,0 +1,54 @@
+#!/bin/bash -e
+#
+# Copyright (c) 2014, Intel Corporation
+#
+# Redistribution and use in source and binary forms, with or without
+# modification, are permitted provided that the following conditions
+# are met:
+#
+#     * Redistributions of source code must retain the above copyright
+#       notice, this list of conditions and the following disclaimer.
+#
+#     * Redistributions in binary form must reproduce the above copyright
+#       notice, this list of conditions and the following disclaimer in
+#       the documentation and/or other materials provided with the
+#       distribution.
+#
+#     * Neither the name of Intel Corporation nor the names of its
+#       contributors may be used to endorse or promote products derived
+#       from this software without specific prior written permission.
+#
+# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+#
+
+#
+# src/test/scope/TEST6 -- scope test to check libpmem symbols (nondebug)
+#
+export UNITTEST_NAME=scope/TEST6
+export UNITTEST_NUM=6
+
+# standard unit test setup
+. ../unittest/unittest.sh
+
+require_fs_type local
+require_build_type nondebug
+
+setup
+
+(nm -g ../../nondebug/libpmem.a |\
+	perl -ne 'print if s/^[0-9a-z]+ T (\w+)/$1/' |\
+	sort > out6.log) 2> err6.log
+
+check
+
+pass
diff --git a/src/test/scope/TEST7 b/src/test/scope/TEST7
new file mode 100755
index 0000000000000000000000000000000000000000..cd80b4c0b39c9021d2d674916abdd5407b0998d1
--- /dev/null
+++ b/src/test/scope/TEST7
@@ -0,0 +1,54 @@
+#!/bin/bash -e
+#
+# Copyright (c) 2014, Intel Corporation
+#
+# Redistribution and use in source and binary forms, with or without
+# modification, are permitted provided that the following conditions
+# are met:
+#
+#     * Redistributions of source code must retain the above copyright
+#       notice, this list of conditions and the following disclaimer.
+#
+#     * Redistributions in binary form must reproduce the above copyright
+#       notice, this list of conditions and the following disclaimer in
+#       the documentation and/or other materials provided with the
+#       distribution.
+#
+#     * Neither the name of Intel Corporation nor the names of its
+#       contributors may be used to endorse or promote products derived
+#       from this software without specific prior written permission.
+#
+# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+#
+
+#
+# src/test/scope/TEST7 -- scope test to check libvmem symbols (nondebug)
+#
+export UNITTEST_NAME=scope/TEST7
+export UNITTEST_NUM=7
+
+# standard unit test setup
+. ../unittest/unittest.sh
+
+require_fs_type local
+require_build_type nondebug
+
+setup
+
+(nm -g ../../nondebug/libvmem.a |\
+	perl -ne 'print if s/^[0-9a-z]+ T (\w+)/$1/' |\
+	sort > out7.log) 2> err7.log
+
+check
+
+pass
diff --git a/src/test/scope/err0.log.match b/src/test/scope/err0.log.match
new file mode 100644
index 0000000000000000000000000000000000000000..e69de29bb2d1d6434b8b29ae775ad8c2e48c5391
diff --git a/src/test/scope/err1.log.match b/src/test/scope/err1.log.match
new file mode 100644
index 0000000000000000000000000000000000000000..e69de29bb2d1d6434b8b29ae775ad8c2e48c5391
diff --git a/src/test/scope/err2.log.match b/src/test/scope/err2.log.match
new file mode 100644
index 0000000000000000000000000000000000000000..e69de29bb2d1d6434b8b29ae775ad8c2e48c5391
diff --git a/src/test/scope/err3.log.match b/src/test/scope/err3.log.match
new file mode 100644
index 0000000000000000000000000000000000000000..e69de29bb2d1d6434b8b29ae775ad8c2e48c5391
diff --git a/src/test/scope/err4.log.match b/src/test/scope/err4.log.match
new file mode 100644
index 0000000000000000000000000000000000000000..e69de29bb2d1d6434b8b29ae775ad8c2e48c5391
diff --git a/src/test/scope/err5.log.match b/src/test/scope/err5.log.match
new file mode 100644
index 0000000000000000000000000000000000000000..e69de29bb2d1d6434b8b29ae775ad8c2e48c5391
diff --git a/src/test/scope/err6.log.match b/src/test/scope/err6.log.match
new file mode 100644
index 0000000000000000000000000000000000000000..e69de29bb2d1d6434b8b29ae775ad8c2e48c5391
diff --git a/src/test/scope/err7.log.match b/src/test/scope/err7.log.match
new file mode 100644
index 0000000000000000000000000000000000000000..e69de29bb2d1d6434b8b29ae775ad8c2e48c5391
diff --git a/src/test/scope/out0.log.match b/src/test/scope/out0.log.match
new file mode 100644
index 0000000000000000000000000000000000000000..bbd5d0d4c45274adc5c52edacd8686c407908599
--- /dev/null
+++ b/src/test/scope/out0.log.match
@@ -0,0 +1,26 @@
+pmem_check_version
+pmem_drain
+pmem_flush
+pmem_is_pmem
+pmem_persist
+pmem_set_funcs
+pmemblk_check
+pmemblk_map
+pmemblk_nblock
+pmemblk_read
+pmemblk_set_error
+pmemblk_set_zero
+pmemblk_unmap
+pmemblk_write
+pmemlog_append
+pmemlog_appendv
+pmemlog_check
+pmemlog_map
+pmemlog_nbyte
+pmemlog_rewind
+pmemlog_tell
+pmemlog_unmap
+pmemlog_walk
+pmemtrn_check
+pmemtrn_map
+pmemtrn_unmap
diff --git a/src/test/scope/out1.log.match b/src/test/scope/out1.log.match
new file mode 100644
index 0000000000000000000000000000000000000000..723c105c692af66385e7cca2d75cca14720ceae3
--- /dev/null
+++ b/src/test/scope/out1.log.match
@@ -0,0 +1,14 @@
+vmem_aligned_alloc
+vmem_calloc
+vmem_check_version
+vmem_free
+vmem_malloc
+vmem_pool_check
+vmem_pool_create
+vmem_pool_create_in_region
+vmem_pool_delete
+vmem_pool_freespace
+vmem_pool_stats_print
+vmem_realloc
+vmem_set_funcs
+vmem_strdup
diff --git a/src/test/scope/out4.log.match b/src/test/scope/out4.log.match
new file mode 100644
index 0000000000000000000000000000000000000000..bbd5d0d4c45274adc5c52edacd8686c407908599
--- /dev/null
+++ b/src/test/scope/out4.log.match
@@ -0,0 +1,26 @@
+pmem_check_version
+pmem_drain
+pmem_flush
+pmem_is_pmem
+pmem_persist
+pmem_set_funcs
+pmemblk_check
+pmemblk_map
+pmemblk_nblock
+pmemblk_read
+pmemblk_set_error
+pmemblk_set_zero
+pmemblk_unmap
+pmemblk_write
+pmemlog_append
+pmemlog_appendv
+pmemlog_check
+pmemlog_map
+pmemlog_nbyte
+pmemlog_rewind
+pmemlog_tell
+pmemlog_unmap
+pmemlog_walk
+pmemtrn_check
+pmemtrn_map
+pmemtrn_unmap
diff --git a/src/test/scope/out5.log.match b/src/test/scope/out5.log.match
new file mode 100644
index 0000000000000000000000000000000000000000..723c105c692af66385e7cca2d75cca14720ceae3
--- /dev/null
+++ b/src/test/scope/out5.log.match
@@ -0,0 +1,14 @@
+vmem_aligned_alloc
+vmem_calloc
+vmem_check_version
+vmem_free
+vmem_malloc
+vmem_pool_check
+vmem_pool_create
+vmem_pool_create_in_region
+vmem_pool_delete
+vmem_pool_freespace
+vmem_pool_stats_print
+vmem_realloc
+vmem_set_funcs
+vmem_strdup
diff --git a/src/test/testconfig.sh.example b/src/test/testconfig.sh.example
new file mode 100644
index 0000000000000000000000000000000000000000..01533eeba7c30ee55381f616a288a6f2f12297ee
--- /dev/null
+++ b/src/test/testconfig.sh.example
@@ -0,0 +1,28 @@
+#
+# src/test/testconfig.sh -- local configuration for unit tests
+#
+# This file tells the script unittest/unittest.sh which file system
+# locations are to be used for testing.
+#
+
+#
+# For tests that use trivial space and don't care what type of file system,
+# just putting the files in the same directory as the test is usually most
+# convenient.  But if there's some reason to put these small testfiles
+# elsewhere, set the path here.
+#
+LOCAL_FS_DIR=.
+
+#
+# For tests that require true persistent memory, set the path to a directory
+# on a PMEM-aware file system here.  Comment this line out if there's no
+# actual persistent memory available on this system.
+#
+#PMEM_FS_DIR=/mnt/pmem
+
+#
+# For tests that require true a non-persitent memory aware file system (i.e.
+# to verify something works on traditional page-cache based memory-mapped
+# files) set the path to a directory on a normal file system here.
+#
+NON_PMEM_FS_DIR=/tmp
diff --git a/src/test/traces/.gitignore b/src/test/traces/.gitignore
new file mode 100644
index 0000000000000000000000000000000000000000..9f58dd630b40f862d9f8b56b802091d02b527487
--- /dev/null
+++ b/src/test/traces/.gitignore
@@ -0,0 +1 @@
+traces
diff --git a/src/test/traces/Makefile b/src/test/traces/Makefile
new file mode 100644
index 0000000000000000000000000000000000000000..12c59e58965aa961f14070c7205dc410c94789f4
--- /dev/null
+++ b/src/test/traces/Makefile
@@ -0,0 +1,51 @@
+#
+# Copyright (c) 2014, Intel Corporation
+#
+# Redistribution and use in source and binary forms, with or without
+# modification, are permitted provided that the following conditions
+# are met:
+#
+#     * Redistributions of source code must retain the above copyright
+#       notice, this list of conditions and the following disclaimer.
+#
+#     * Redistributions in binary form must reproduce the above copyright
+#       notice, this list of conditions and the following disclaimer in
+#       the documentation and/or other materials provided with the
+#       distribution.
+#
+#     * Neither the name of Intel Corporation nor the names of its
+#       contributors may be used to endorse or promote products derived
+#       from this software without specific prior written permission.
+#
+# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+#
+
+#
+# src/test/traces/Makefile -- build traces unit test
+#
+vpath %.c ../..
+vpath %.h ../..
+
+TARGET = traces
+OBJS = traces.o out.o
+
+out.o: CFLAGS += -DSRCVERSION=\"utversion\"
+
+include ../Makefile.inc
+
+#Test debug output
+CFLAGS += -DDEBUG -I../..
+
+traces.o: traces.c
+
+out.o: out.c
diff --git a/src/test/traces/TEST0 b/src/test/traces/TEST0
new file mode 100755
index 0000000000000000000000000000000000000000..f703d2b3f821555383fb45177715f72bbb711e35
--- /dev/null
+++ b/src/test/traces/TEST0
@@ -0,0 +1,55 @@
+#!/bin/bash -e
+#
+# Copyright (c) 2014, Intel Corporation
+#
+# Redistribution and use in source and binary forms, with or without
+# modification, are permitted provided that the following conditions
+# are met:
+#
+#     * Redistributions of source code must retain the above copyright
+#       notice, this list of conditions and the following disclaimer.
+#
+#     * Redistributions in binary form must reproduce the above copyright
+#       notice, this list of conditions and the following disclaimer in
+#       the documentation and/or other materials provided with the
+#       distribution.
+#
+#     * Neither the name of Intel Corporation nor the names of its
+#       contributors may be used to endorse or promote products derived
+#       from this software without specific prior written permission.
+#
+# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+#
+
+#
+# src/test/traces/TEST0 -- unit test for traces
+#
+export UNITTEST_NAME=traces/TEST0
+export UNITTEST_NUM=0
+
+# standard unit test setup
+. ../unittest/unittest.sh
+
+require_fs_type local
+require_build_type debug
+
+setup
+
+export TRACE_LOG_LEVEL=4
+export TRACE_LOG_FILE=./custom_file.log
+expect_normal_exit ./traces$EXESUFFIX
+
+# check results
+../match custom_file.log.match
+
+pass
diff --git a/src/test/traces/TEST1 b/src/test/traces/TEST1
new file mode 100755
index 0000000000000000000000000000000000000000..fb6ea154d2d4fee5182478967129287c9b9178d8
--- /dev/null
+++ b/src/test/traces/TEST1
@@ -0,0 +1,54 @@
+#!/bin/bash -e
+#
+# Copyright (c) 2014, Intel Corporation
+#
+# Redistribution and use in source and binary forms, with or without
+# modification, are permitted provided that the following conditions
+# are met:
+#
+#     * Redistributions of source code must retain the above copyright
+#       notice, this list of conditions and the following disclaimer.
+#
+#     * Redistributions in binary form must reproduce the above copyright
+#       notice, this list of conditions and the following disclaimer in
+#       the documentation and/or other materials provided with the
+#       distribution.
+#
+#     * Neither the name of Intel Corporation nor the names of its
+#       contributors may be used to endorse or promote products derived
+#       from this software without specific prior written permission.
+#
+# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+#
+
+#
+# src/test/traces/TEST1 -- unit test for traces
+#
+export UNITTEST_NAME=traces/TEST1
+export UNITTEST_NUM=1
+
+# standard unit test setup
+. ../unittest/unittest.sh
+
+require_fs_type local
+require_build_type debug
+
+setup
+
+export TRACE_LOG_LEVEL=0
+expect_normal_exit ./traces$EXESUFFIX 2>redir_stderr$UNITTEST_NUM.log
+
+# check results
+../match redir_stderr$UNITTEST_NUM.log.match
+
+pass
diff --git a/src/test/traces/TEST2 b/src/test/traces/TEST2
new file mode 100755
index 0000000000000000000000000000000000000000..17e193e4559522f64fc2b8b7fb2f88b4b2be57bd
--- /dev/null
+++ b/src/test/traces/TEST2
@@ -0,0 +1,54 @@
+#!/bin/bash -e
+#
+# Copyright (c) 2014, Intel Corporation
+#
+# Redistribution and use in source and binary forms, with or without
+# modification, are permitted provided that the following conditions
+# are met:
+#
+#     * Redistributions of source code must retain the above copyright
+#       notice, this list of conditions and the following disclaimer.
+#
+#     * Redistributions in binary form must reproduce the above copyright
+#       notice, this list of conditions and the following disclaimer in
+#       the documentation and/or other materials provided with the
+#       distribution.
+#
+#     * Neither the name of Intel Corporation nor the names of its
+#       contributors may be used to endorse or promote products derived
+#       from this software without specific prior written permission.
+#
+# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+#
+
+#
+# src/test/traces/TEST2 -- unit test for traces
+#
+export UNITTEST_NAME=traces/TEST2
+export UNITTEST_NUM=2
+
+# standard unit test setup
+. ../unittest/unittest.sh
+
+require_fs_type local
+require_build_type debug
+
+setup
+
+export TRACE_LOG_LEVEL=1
+expect_normal_exit ./traces$EXESUFFIX 2>redir_stderr$UNITTEST_NUM.log
+
+# check results
+../match redir_stderr$UNITTEST_NUM.log.match
+
+pass
diff --git a/src/test/traces/TEST3 b/src/test/traces/TEST3
new file mode 100755
index 0000000000000000000000000000000000000000..50b9c9b7b6666f5c4b2d99b0b4ce7cdd809e3818
--- /dev/null
+++ b/src/test/traces/TEST3
@@ -0,0 +1,54 @@
+#!/bin/bash -e
+#
+# Copyright (c) 2014, Intel Corporation
+#
+# Redistribution and use in source and binary forms, with or without
+# modification, are permitted provided that the following conditions
+# are met:
+#
+#     * Redistributions of source code must retain the above copyright
+#       notice, this list of conditions and the following disclaimer.
+#
+#     * Redistributions in binary form must reproduce the above copyright
+#       notice, this list of conditions and the following disclaimer in
+#       the documentation and/or other materials provided with the
+#       distribution.
+#
+#     * Neither the name of Intel Corporation nor the names of its
+#       contributors may be used to endorse or promote products derived
+#       from this software without specific prior written permission.
+#
+# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+#
+
+#
+# src/test/traces/TEST3 -- unit test for traces
+#
+export UNITTEST_NAME=traces/TEST3
+export UNITTEST_NUM=3
+
+# standard unit test setup
+. ../unittest/unittest.sh
+
+require_fs_type local
+require_build_type debug
+
+setup
+
+export TRACE_LOG_LEVEL=2
+expect_normal_exit ./traces$EXESUFFIX 2>redir_stderr$UNITTEST_NUM.log
+
+# check results
+../match redir_stderr$UNITTEST_NUM.log.match
+
+pass
diff --git a/src/test/traces/TEST4 b/src/test/traces/TEST4
new file mode 100755
index 0000000000000000000000000000000000000000..4108e12882d6be7587761e2f35c7183aff0f51dd
--- /dev/null
+++ b/src/test/traces/TEST4
@@ -0,0 +1,54 @@
+#!/bin/bash -e
+#
+# Copyright (c) 2014, Intel Corporation
+#
+# Redistribution and use in source and binary forms, with or without
+# modification, are permitted provided that the following conditions
+# are met:
+#
+#     * Redistributions of source code must retain the above copyright
+#       notice, this list of conditions and the following disclaimer.
+#
+#     * Redistributions in binary form must reproduce the above copyright
+#       notice, this list of conditions and the following disclaimer in
+#       the documentation and/or other materials provided with the
+#       distribution.
+#
+#     * Neither the name of Intel Corporation nor the names of its
+#       contributors may be used to endorse or promote products derived
+#       from this software without specific prior written permission.
+#
+# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+#
+
+#
+# src/test/traces/TEST4 -- unit test for traces
+#
+export UNITTEST_NAME=traces/TEST4
+export UNITTEST_NUM=4
+
+# standard unit test setup
+. ../unittest/unittest.sh
+
+require_fs_type local
+require_build_type debug
+
+setup
+
+export TRACE_LOG_LEVEL=3
+expect_normal_exit ./traces$EXESUFFIX 2>redir_stderr$UNITTEST_NUM.log
+
+# check results
+../match redir_stderr$UNITTEST_NUM.log.match
+
+pass
diff --git a/src/test/traces/TEST5 b/src/test/traces/TEST5
new file mode 100755
index 0000000000000000000000000000000000000000..7cfee0c54dcb09a1d716366e41e03a6e56dd6afd
--- /dev/null
+++ b/src/test/traces/TEST5
@@ -0,0 +1,54 @@
+#!/bin/bash -e
+#
+# Copyright (c) 2014, Intel Corporation
+#
+# Redistribution and use in source and binary forms, with or without
+# modification, are permitted provided that the following conditions
+# are met:
+#
+#     * Redistributions of source code must retain the above copyright
+#       notice, this list of conditions and the following disclaimer.
+#
+#     * Redistributions in binary form must reproduce the above copyright
+#       notice, this list of conditions and the following disclaimer in
+#       the documentation and/or other materials provided with the
+#       distribution.
+#
+#     * Neither the name of Intel Corporation nor the names of its
+#       contributors may be used to endorse or promote products derived
+#       from this software without specific prior written permission.
+#
+# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+#
+
+#
+# src/test/traces/TEST5 -- unit test for traces
+#
+export UNITTEST_NAME=traces/TEST5
+export UNITTEST_NUM=5
+
+# standard unit test setup
+. ../unittest/unittest.sh
+
+require_fs_type local
+require_build_type debug
+
+setup
+
+export TRACE_LOG_LEVEL=4
+expect_normal_exit ./traces$EXESUFFIX 2>redir_stderr$UNITTEST_NUM.log
+
+# check results
+../match redir_stderr$UNITTEST_NUM.log.match
+
+pass
diff --git a/src/test/traces/TEST6 b/src/test/traces/TEST6
new file mode 100755
index 0000000000000000000000000000000000000000..1d348c99d4fcd3a811014d1caa7d057f7205ff35
--- /dev/null
+++ b/src/test/traces/TEST6
@@ -0,0 +1,54 @@
+#!/bin/bash -e
+#
+# Copyright (c) 2014, Intel Corporation
+#
+# Redistribution and use in source and binary forms, with or without
+# modification, are permitted provided that the following conditions
+# are met:
+#
+#     * Redistributions of source code must retain the above copyright
+#       notice, this list of conditions and the following disclaimer.
+#
+#     * Redistributions in binary form must reproduce the above copyright
+#       notice, this list of conditions and the following disclaimer in
+#       the documentation and/or other materials provided with the
+#       distribution.
+#
+#     * Neither the name of Intel Corporation nor the names of its
+#       contributors may be used to endorse or promote products derived
+#       from this software without specific prior written permission.
+#
+# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+#
+
+#
+# src/test/traces/TEST6 -- unit test for traces
+#
+export UNITTEST_NAME=traces/TEST6
+export UNITTEST_NUM=6
+
+# standard unit test setup
+. ../unittest/unittest.sh
+
+require_fs_type local
+require_build_type debug
+
+setup
+
+export TRACE_LOG_LEVEL=4
+expect_normal_exit ./traces$EXESUFFIX 2>redir_stderr$UNITTEST_NUM.log
+
+# check results
+../match redir_stderr$UNITTEST_NUM.log.match
+
+pass
diff --git a/src/test/traces/custom_file.log.match b/src/test/traces/custom_file.log.match
new file mode 100644
index 0000000000000000000000000000000000000000..cdaca7d494cd943dbda5458be5172bb079182759
--- /dev/null
+++ b/src/test/traces/custom_file.log.match
@@ -0,0 +1,8 @@
+$(*)
+$(*)
+$(*)
+$(*)Log level NONE
+$(*)Log level ERROR
+$(*)Log level WARNING
+$(*)Log level INFO
+$(*)Log level DEBUG
diff --git a/src/test/traces/redir_stderr1.log.match b/src/test/traces/redir_stderr1.log.match
new file mode 100644
index 0000000000000000000000000000000000000000..3d739c871d840f4250bfa2f7d1a8244f5ae2d362
--- /dev/null
+++ b/src/test/traces/redir_stderr1.log.match
@@ -0,0 +1 @@
+$(*)Log level NONE
diff --git a/src/test/traces/redir_stderr2.log.match b/src/test/traces/redir_stderr2.log.match
new file mode 100644
index 0000000000000000000000000000000000000000..0dd45c902a00e1fa49c9568253dd8746ddfa19ff
--- /dev/null
+++ b/src/test/traces/redir_stderr2.log.match
@@ -0,0 +1,5 @@
+$(*)
+$(*)
+$(*)
+$(*)Log level NONE
+$(*)Log level ERROR
diff --git a/src/test/traces/redir_stderr3.log.match b/src/test/traces/redir_stderr3.log.match
new file mode 100644
index 0000000000000000000000000000000000000000..7d6fc0c11491b065bb309c0780e1c55fea60757d
--- /dev/null
+++ b/src/test/traces/redir_stderr3.log.match
@@ -0,0 +1,6 @@
+$(*)
+$(*)
+$(*)
+$(*)Log level NONE
+$(*)Log level ERROR
+$(*)Log level WARNING
diff --git a/src/test/traces/redir_stderr4.log.match b/src/test/traces/redir_stderr4.log.match
new file mode 100644
index 0000000000000000000000000000000000000000..833b18b0c8c77a560d5ebb0b29c381c7b30be22d
--- /dev/null
+++ b/src/test/traces/redir_stderr4.log.match
@@ -0,0 +1,7 @@
+$(*)
+$(*)
+$(*)
+$(*)Log level NONE
+$(*)Log level ERROR
+$(*)Log level WARNING
+$(*)Log level INFO
diff --git a/src/test/traces/redir_stderr5.log.match b/src/test/traces/redir_stderr5.log.match
new file mode 100644
index 0000000000000000000000000000000000000000..cdaca7d494cd943dbda5458be5172bb079182759
--- /dev/null
+++ b/src/test/traces/redir_stderr5.log.match
@@ -0,0 +1,8 @@
+$(*)
+$(*)
+$(*)
+$(*)Log level NONE
+$(*)Log level ERROR
+$(*)Log level WARNING
+$(*)Log level INFO
+$(*)Log level DEBUG
diff --git a/src/test/traces/redir_stderr6.log.match b/src/test/traces/redir_stderr6.log.match
new file mode 100644
index 0000000000000000000000000000000000000000..ddcd4f2cf55368ed36360f3144d658cd6becb5a4
--- /dev/null
+++ b/src/test/traces/redir_stderr6.log.match
@@ -0,0 +1,8 @@
+$(*)
+$(*)
+$(*)
+<trace>: <0> [traces.c:$(*) main] Log level NONE
+<trace>: <1> [traces.c:$(*) main] Log level ERROR
+<trace>: <2> [traces.c:$(*) main] Log level WARNING
+<trace>: <3> [traces.c:$(*) main] Log level INFO
+<trace>: <4> [traces.c:$(*) main] Log level DEBUG
diff --git a/src/test/traces/traces.c b/src/test/traces/traces.c
new file mode 100644
index 0000000000000000000000000000000000000000..fc65fbddcdb2a9179958616fa0d77b5c8e5901d1
--- /dev/null
+++ b/src/test/traces/traces.c
@@ -0,0 +1,66 @@
+/*
+ * Copyright (c) 2014, Intel Corporation
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ *     * Redistributions of source code must retain the above copyright
+ *       notice, this list of conditions and the following disclaimer.
+ *
+ *     * Redistributions in binary form must reproduce the above copyright
+ *       notice, this list of conditions and the following disclaimer in
+ *       the documentation and/or other materials provided with the
+ *       distribution.
+ *
+ *     * Neither the name of Intel Corporation nor the names of its
+ *       contributors may be used to endorse or promote products derived
+ *       from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+/*
+ * traces.c -- unit test for traces
+ */
+
+#define	LOG_PREFIX "trace"
+#define	LOG_LEVEL_VAR "TRACE_LOG_LEVEL"
+#define	LOG_FILE_VAR "TRACE_LOG_FILE"
+
+#include "out.h"
+#undef FATAL
+#undef ASSERT
+#undef ASSERTinfo
+#undef ASSERTeq
+#undef ASSERTne
+#include "unittest.h"
+
+int
+main(int argc, char *argv[])
+{
+	START(argc, argv, "traces");
+
+	/* Execute test */
+	out_init(LOG_PREFIX, LOG_LEVEL_VAR, LOG_FILE_VAR);
+	LOG(0, "Log level NONE");
+	LOG(1, "Log level ERROR");
+	LOG(2, "Log level WARNING");
+	LOG(3, "Log level INFO");
+	LOG(4, "Log level DEBUG");
+
+	/* Cleanup */
+	out_fini();
+
+	DONE(NULL);
+}
diff --git a/src/test/traces_custom_function/.gitignore b/src/test/traces_custom_function/.gitignore
new file mode 100644
index 0000000000000000000000000000000000000000..47a458e48921da7e98bf9e2e6d0c2f1c16b681fd
--- /dev/null
+++ b/src/test/traces_custom_function/.gitignore
@@ -0,0 +1 @@
+traces_custom_function
diff --git a/src/test/traces_custom_function/Makefile b/src/test/traces_custom_function/Makefile
new file mode 100644
index 0000000000000000000000000000000000000000..27c47ae18021fe18cd1b9c720a7af8a550c45aff
--- /dev/null
+++ b/src/test/traces_custom_function/Makefile
@@ -0,0 +1,51 @@
+#
+# Copyright (c) 2014, Intel Corporation
+#
+# Redistribution and use in source and binary forms, with or without
+# modification, are permitted provided that the following conditions
+# are met:
+#
+#     * Redistributions of source code must retain the above copyright
+#       notice, this list of conditions and the following disclaimer.
+#
+#     * Redistributions in binary form must reproduce the above copyright
+#       notice, this list of conditions and the following disclaimer in
+#       the documentation and/or other materials provided with the
+#       distribution.
+#
+#     * Neither the name of Intel Corporation nor the names of its
+#       contributors may be used to endorse or promote products derived
+#       from this software without specific prior written permission.
+#
+# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+#
+
+#
+# src/test/traces_custom_function/Makefile -- build traces unit test
+#
+vpath %.c ../..
+vpath %.h ../..
+
+TARGET = traces_custom_function
+OBJS = traces_custom_function.o out.o
+
+out.o: CFLAGS += -DSRCVERSION=\"utversion\"
+
+include ../Makefile.inc
+
+#Test debug output
+CFLAGS += -DDEBUG -I../..
+
+traces_custom_function.o: traces_custom_function.c
+
+out.o: out.c
diff --git a/src/test/traces_custom_function/TEST0 b/src/test/traces_custom_function/TEST0
new file mode 100755
index 0000000000000000000000000000000000000000..491a5c14dde8870350ffdaaafea75fe379b771db
--- /dev/null
+++ b/src/test/traces_custom_function/TEST0
@@ -0,0 +1,53 @@
+#!/bin/bash -e
+#
+# Copyright (c) 2014, Intel Corporation
+#
+# Redistribution and use in source and binary forms, with or without
+# modification, are permitted provided that the following conditions
+# are met:
+#
+#     * Redistributions of source code must retain the above copyright
+#       notice, this list of conditions and the following disclaimer.
+#
+#     * Redistributions in binary form must reproduce the above copyright
+#       notice, this list of conditions and the following disclaimer in
+#       the documentation and/or other materials provided with the
+#       distribution.
+#
+#     * Neither the name of Intel Corporation nor the names of its
+#       contributors may be used to endorse or promote products derived
+#       from this software without specific prior written permission.
+#
+# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+#
+
+#
+# src/test/traces_custom_function/TEST0 -- unit test for traces custom function
+#
+export UNITTEST_NAME=traces_custom_function/TEST0
+export UNITTEST_NUM=0
+
+# standard unit test setup
+. ../unittest/unittest.sh
+
+require_fs_type local
+require_build_type debug
+
+setup
+
+export TRACE_LOG_LEVEL=4
+expect_normal_exit ./traces_custom_function$EXESUFFIX
+
+check
+
+pass
diff --git a/src/test/traces_custom_function/out0.log.match b/src/test/traces_custom_function/out0.log.match
new file mode 100644
index 0000000000000000000000000000000000000000..38451d7c9405c705d2c52897fda5ef0b3958257e
--- /dev/null
+++ b/src/test/traces_custom_function/out0.log.match
@@ -0,0 +1,19 @@
+traces_custom_function/TEST0: START: traces_custom_function
+ ./traces_custom_function$(*)
+CUSTOM_PRINT:$(*)
+
+CUSTOM_PRINT:$(*)
+
+CUSTOM_PRINT:$(*)
+
+CUSTOM_PRINT:$(*)Log level NONE
+
+CUSTOM_PRINT:$(*)Log level ERROR
+
+CUSTOM_PRINT:$(*)Log level WARNING
+
+CUSTOM_PRINT:$(*)Log level INFO
+
+CUSTOM_PRINT:$(*)Log level DEBUG
+
+traces_custom_function/TEST0: Done
diff --git a/src/test/traces_custom_function/traces_custom_function.c b/src/test/traces_custom_function/traces_custom_function.c
new file mode 100644
index 0000000000000000000000000000000000000000..55de3841ceb7ec14946c18ac2fe22e58c758286f
--- /dev/null
+++ b/src/test/traces_custom_function/traces_custom_function.c
@@ -0,0 +1,84 @@
+/*
+ * Copyright (c) 2014, Intel Corporation
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ *     * Redistributions of source code must retain the above copyright
+ *       notice, this list of conditions and the following disclaimer.
+ *
+ *     * Redistributions in binary form must reproduce the above copyright
+ *       notice, this list of conditions and the following disclaimer in
+ *       the documentation and/or other materials provided with the
+ *       distribution.
+ *
+ *     * Neither the name of Intel Corporation nor the names of its
+ *       contributors may be used to endorse or promote products derived
+ *       from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+/*
+ * traces_custom_function.c -- unit test for traces with custom print function
+ */
+
+#define	LOG_PREFIX "trace_func"
+#define	LOG_LEVEL_VAR "TRACE_LOG_LEVEL"
+#define	LOG_FILE_VAR "TRACE_LOG_FILE"
+
+#include "out.h"
+#undef FATAL
+#undef ASSERT
+#undef ASSERTinfo
+#undef ASSERTeq
+#undef ASSERTne
+#include "unittest.h"
+
+/*
+ * print_custom_function -- Custom function to handle output
+ *
+ * This is called from the library to print text instead of output to stderr.
+ */
+void
+print_custom_function(const char *s)
+{
+	if (s) {
+		OUT("CUSTOM_PRINT: %s", s);
+	} else {
+		OUT("CUSTOM_PRINT(NULL)");
+	}
+}
+
+int
+main(int argc, char *argv[])
+{
+	START(argc, argv, "traces_custom_function");
+
+	/* Prepare environment */
+	out_set_print_func(print_custom_function);
+
+	/* Execute test */
+	out_init(LOG_PREFIX, LOG_LEVEL_VAR, LOG_FILE_VAR);
+	LOG(0, "Log level NONE");
+	LOG(1, "Log level ERROR");
+	LOG(2, "Log level WARNING");
+	LOG(3, "Log level INFO");
+	LOG(4, "Log level DEBUG");
+
+	/* Cleanup */
+	out_fini();
+
+	DONE(NULL);
+}
diff --git a/src/test/unittest/.gitignore b/src/test/unittest/.gitignore
new file mode 100644
index 0000000000000000000000000000000000000000..6a8058883039fb613fc9fcd76dc781a64aef509b
--- /dev/null
+++ b/src/test/unittest/.gitignore
@@ -0,0 +1 @@
+libut.a
diff --git a/src/test/unittest/Makefile b/src/test/unittest/Makefile
new file mode 100644
index 0000000000000000000000000000000000000000..426797120c4d3404f4f6853a2727b8097e5a726c
--- /dev/null
+++ b/src/test/unittest/Makefile
@@ -0,0 +1,67 @@
+#
+# Copyright (c) 2014, Intel Corporation
+#
+# Redistribution and use in source and binary forms, with or without
+# modification, are permitted provided that the following conditions
+# are met:
+#
+#     * Redistributions of source code must retain the above copyright
+#       notice, this list of conditions and the following disclaimer.
+#
+#     * Redistributions in binary form must reproduce the above copyright
+#       notice, this list of conditions and the following disclaimer in
+#       the documentation and/or other materials provided with the
+#       distribution.
+#
+#     * Neither the name of Intel Corporation nor the names of its
+#       contributors may be used to endorse or promote products derived
+#       from this software without specific prior written permission.
+#
+# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+#
+
+#
+# src/test/unittest/Makefile -- build unittest support library
+#
+TARGET = libut.a
+OBJS = ut.o ut_alloc.o ut_file.o ut_pthread.o ut_signal.o
+CFLAGS = -I../../include -ggdb -Wall -Werror -std=gnu99
+
+all test: $(TARGET)
+
+$(TARGET): $(OBJS)
+	$(AR) rv $@ $(OBJS)
+
+.c.o:
+	$(CC) -c $(CFLAGS) $(INCS) $(COMMONINCS) $< -o $@
+
+clean:
+	$(RM) *.o core a.out
+
+cstyle:
+	../../../utils/cstyle -pP *.c *.h
+
+clobber: clean
+	$(RM) $(TARGET)
+
+.PHONY: clean clobber
+
+ut.o: ut.c unittest.h
+
+ut_alloc.o: ut_alloc.c unittest.h
+
+ut_file.o: ut_file.c unittest.h
+
+ut_pthread.o: ut_pthread.c unittest.h
+
+ut_signal.o: ut_file.c unittest.h
diff --git a/src/test/unittest/README b/src/test/unittest/README
new file mode 100644
index 0000000000000000000000000000000000000000..6b174a34859b6422c6ce9a3b4d63256771ffd687
--- /dev/null
+++ b/src/test/unittest/README
@@ -0,0 +1,6 @@
+Linux NVM Library
+
+This is src/test/unittest/README.
+
+This directory contains the unit test framework used by
+the NVM Library unit tests.
diff --git a/src/test/unittest/unittest.h b/src/test/unittest/unittest.h
new file mode 100644
index 0000000000000000000000000000000000000000..08912f1e36ce49a588ab02333aa2f6ec9643ef35
--- /dev/null
+++ b/src/test/unittest/unittest.h
@@ -0,0 +1,469 @@
+/*
+ * Copyright (c) 2014, Intel Corporation
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ *     * Redistributions of source code must retain the above copyright
+ *       notice, this list of conditions and the following disclaimer.
+ *
+ *     * Redistributions in binary form must reproduce the above copyright
+ *       notice, this list of conditions and the following disclaimer in
+ *       the documentation and/or other materials provided with the
+ *       distribution.
+ *
+ *     * Neither the name of Intel Corporation nor the names of its
+ *       contributors may be used to endorse or promote products derived
+ *       from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+/*
+ * unittest.h -- the mundane stuff shared by all unit tests
+ *
+ * we want unit tests to be very thorough and check absolutely everything
+ * in order to nail down the test case as precisely as possible and flag
+ * anything at all unexpected.  as a result, most unit tests are 90% code
+ * checking stuff that isn't really interesting to what is being tested.
+ * to help address this, the macros defined here include all the boilerplate
+ * error checking which prints information and exits on unexpected errors.
+ *
+ * the result changes this code:
+ *
+ *	if ((buf = malloc(size)) == NULL) {
+ *		fprintf(stderr, "cannot allocate %d bytes for buf\n", size);
+ *		exit(1);
+ *	}
+ *
+ * into this code:
+ *
+ *	buf = MALLOC(size);
+ *
+ * and the error message includes the calling context information (file:line).
+ * in general, using the all-caps version of a call means you're using the
+ * unittest.h version which does the most common checking for you.  so
+ * calling VMEM_POOL_CREATE() instead of vmem_pool_create() returns the same
+ * thing, but can never return an error since the unit test library checks for
+ * it.  * for routines like vmem_pool_delete() there is no corresponding
+ * VMEM_POOL_DELETE() because there's no error to check for.
+ *
+ * all unit tests should use the same initialization:
+ *
+ *	START(argc, argv, "brief test description", ...);
+ *
+ * all unit tests should use these exit calls:
+ *
+ *	DONE("message", ...);
+ *	FATAL("message", ...);
+ *
+ * uniform stderr and stdout messages:
+ *
+ *	OUT("message", ...);
+ *	ERR("message", ...);
+ *
+ * in all cases above, the message is printf-like, taking variable args.
+ * the message can be NULL.  it can start with "!" in which case the "!" is
+ * skipped and the message gets the errno string appended to it, like this:
+ *
+ *	if (somesyscall(..) < 0)
+ *		FATAL("!my message");
+ */
+
+#ifndef	_UNITTEST_H
+#define	_UNITTEST_H 1
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <stdarg.h>
+#include <stdint.h>
+#include <string.h>
+#include <strings.h>
+#include <setjmp.h>
+#include <time.h>
+#include <sys/types.h>
+#include <sys/wait.h>
+#include <sys/stat.h>
+#include <sys/mman.h>
+#include <sys/file.h>
+#include <sys/mount.h>
+#include <uuid/uuid.h>
+#include <fcntl.h>
+#include <signal.h>
+#include <errno.h>
+#include <dirent.h>
+#include <pthread.h>
+
+#include <libpmem.h>
+#include <libvmem.h>
+
+
+/*
+ * unit test support...
+ */
+void ut_start(const char *file, int line, const char *func,
+	int argc, char * const argv[], const char *fmt, ...)
+	__attribute__((format(printf, 6, 7)));
+void ut_done(const char *file, int line, const char *func,
+	const char *fmt, ...)
+	__attribute__((format(printf, 4, 5)));
+void ut_fatal(const char *file, int line, const char *func,
+	const char *fmt, ...)
+	__attribute__((format(printf, 4, 5)));
+void ut_out(const char *file, int line, const char *func,
+	const char *fmt, ...)
+	__attribute__((format(printf, 4, 5)));
+void ut_err(const char *file, int line, const char *func,
+	const char *fmt, ...)
+	__attribute__((format(printf, 4, 5)));
+
+/* indicate the start of the test */
+#define	START(argc, argv, ...)\
+    ut_start(__FILE__, __LINE__, __func__, argc, argv, __VA_ARGS__)
+
+/* normal exit from test */
+#define	DONE(...)\
+    ut_done(__FILE__, __LINE__, __func__, __VA_ARGS__)
+
+/* fatal error detected */
+#define	FATAL(...)\
+    ut_fatal(__FILE__, __LINE__, __func__, __VA_ARGS__)
+
+/* normal output */
+#define	OUT(...)\
+    ut_out(__FILE__, __LINE__, __func__, __VA_ARGS__)
+
+/* error output */
+#define	ERR(...)\
+    ut_err(__FILE__, __LINE__, __func__, __VA_ARGS__)
+
+
+/*
+ * assertions...
+ */
+
+/* assert a condition is true */
+#define	ASSERT(cnd)\
+	((void)((cnd) || (ut_fatal(__FILE__, __LINE__, __func__,\
+	"assertion failure: %s", #cnd), 0)))
+
+/* assertion with extra info printed if assertion fails */
+#define	ASSERTinfo(cnd, info) \
+	((void)((cnd) || (ut_fatal(__FILE__, __LINE__, __func__,\
+	"assertion failure: %s (%s = %s)", #cnd, #info, info), 0)))
+
+/* assert two integer values are equal */
+#define	ASSERTeq(lhs, rhs)\
+	((void)(((lhs) == (rhs)) || (ut_fatal(__FILE__, __LINE__, __func__,\
+	"assertion failure: %s (0x%llx) == %s (0x%llx)", #lhs,\
+	(unsigned long long)(lhs), #rhs, (unsigned long long)(rhs)), 0)))
+
+/* assert two integer values are not equal */
+#define	ASSERTne(lhs, rhs)\
+	((void)(((lhs) != (rhs)) || (ut_fatal(__FILE__, __LINE__, __func__,\
+	"assertion failure: %s (0x%llx) != %s (0x%llx)", #lhs,\
+	(unsigned long long)(lhs), #rhs, (unsigned long long)(rhs)), 0)))
+
+/* assert pointer is fits range of [start, start + size) */
+#define	ASSERTrange(ptr, start, size)\
+	((void)(((uintptr_t)(ptr) >= (uintptr_t)(start) &&\
+	(uintptr_t)(ptr) < (uintptr_t)(start) + (uintptr_t)(size)) ||\
+	(ut_fatal(__FILE__, __LINE__, __func__,\
+	"assert failure: %s (%p) is outside range [%s (%p), %s (%p))", #ptr,\
+	(void *)(ptr), #start, (void *)(start), #start"+"#size,\
+	(void *)((uintptr_t)(start) + (uintptr_t)(size))), 0)))
+
+/*
+ * memory allocation...
+ */
+void *ut_malloc(const char *file, int line, const char *func, size_t size);
+void *ut_calloc(const char *file, int line, const char *func,
+    size_t nmemb, size_t size);
+void ut_free(const char *file, int line, const char *func, void *ptr);
+void *ut_realloc(const char *file, int line, const char *func,
+    void *ptr, size_t size);
+char *ut_strdup(const char *file, int line, const char *func,
+    const char *str);
+void *ut_pagealignmalloc(const char *file, int line, const char *func,
+    size_t size);
+void *ut_memalign(const char *file, int line, const char *func,
+    size_t alignment, size_t size);
+
+/* a malloc() that can't return NULL */
+#define	MALLOC(size)\
+    ut_malloc(__FILE__, __LINE__, __func__, size)
+
+/* a calloc() that can't return NULL */
+#define	CALLOC(nmemb, size)\
+    ut_calloc(__FILE__, __LINE__, __func__, nmemb, size)
+
+/* a malloc() of zeroed memory */
+#define	ZALLOC(size)\
+    ut_calloc(__FILE__, __LINE__, __func__, 1, size)
+
+#define	FREE(ptr)\
+    ut_free(__FILE__, __LINE__, __func__, ptr)
+
+/* a realloc() that can't return NULL */
+#define	REALLOC(ptr, size)\
+    ut_realloc(__FILE__, __LINE__, __func__, ptr, size)
+
+/* a strdup() that can't return NULL */
+#define	STRDUP(str)\
+    ut_strdup(__FILE__, __LINE__, __func__, str)
+
+/* a malloc() that only returns page aligned memory */
+#define	PAGEALIGNMALLOC(size)\
+    ut_pagealignmalloc(__FILE__, __LINE__, __func__, size)
+
+/* a malloc() that returns memory with given alignment */
+#define	MEMALIGN(alignment, size)\
+    ut_memalign(__FILE__, __LINE__, __func__, alignment, size)
+
+
+/*
+ * file operations
+ */
+int ut_open(const char *file, int line, const char *func, char *path,
+    int flags, ...);
+
+int ut_close(const char *file, int line, const char *func, int fd);
+
+int ut_unlink(const char *file, int line, const char *func, const char *path);
+
+int ut_access(const char *file, int line, const char *func, const char *path,
+    int mode);
+
+int ut_write(const char *file, int line, const char *func, int fd,
+    const void *buf, size_t len);
+
+int ut_read(const char *file, int line, const char *func, int fd,
+    void *buf, size_t len);
+
+int ut_readlink(const char *file, int line, const char *func, const char *path,
+    void *buf, size_t len);
+
+int ut_fcntl(const char *file, int line, const char *func, int fd,
+    int cmd, int num, ...);
+
+off_t ut_lseek(const char *file, int line, const char *func, int fd,
+    off_t offset, int whence);
+
+int ut_posix_fallocate(const char *file, int line, const char *func, int fd,
+    off_t offset, off_t len);
+
+int ut_stat(const char *file, int line, const char *func, const char *path,
+    struct stat *st_bufp);
+
+int ut_fstat(const char *file, int line, const char *func, int fd,
+    struct stat *st_bufp);
+
+int ut_flock(const char *file, int line, const char *func, int fd, int op);
+
+void *ut_mmap(const char *file, int line, const char *func, void *addr,
+    size_t length, int prot, int flags, int fd, off_t offset);
+
+int ut_munmap(const char *file, int line, const char *func, void *addr,
+    size_t length);
+
+int ut_mprotect(const char *file, int line, const char *func, void *addr,
+    size_t len, int prot);
+
+int ut_symlink(const char *file, int line, const char *func,
+    const char *oldpath, const char *newpath);
+
+int ut_link(const char *file, int line, const char *func,
+    const char *oldpath, const char *newpath);
+
+int ut_mkdir(const char *file, int line, const char *func,
+    const char *pathname, mode_t mode);
+
+int ut_rmdir(const char *file, int line, const char *func,
+    const char *pathname);
+
+int ut_rename(const char *file, int line, const char *func,
+    const char *oldpath, const char *newpath);
+
+int ut_mount(const char *file, int line, const char *func, const char *src,
+    const char *tar, const char *fstype, unsigned long flags,
+    const void *data);
+
+int ut_umount(const char *file, int line, const char *func, const char *tar);
+
+int ut_pselect(const char *file, int line, const char *func, int nfds,
+    fd_set *rfds, fd_set *wfds, fd_set *efds, const struct timespec *tv,
+    const sigset_t *sigmask);
+
+int ut_mknod(const char *file, int line, const char *func,
+    const char *pathname, mode_t mode, dev_t dev);
+
+int utstat(const char *file, int line, const char *func, const char *path,
+    struct stat *st_bufp);
+
+int ut_truncate(const char *file, int line, const char *func,
+    const char *path, off_t length);
+
+int ut_ftruncate(const char *file, int line, const char *func,
+    int fd, off_t length);
+
+int ut_chmod(const char *file, int line, const char *func,
+    const char *path, mode_t mode);
+
+DIR *ut_opendir(const char *file, int line, const char *func, const char *name);
+
+int ut_dirfd(const char *file, int line, const char *func, DIR *dirp);
+
+int ut_closedir(const char *file, int line, const char *func, DIR *dirp);
+
+/* an open() that can't return < 0 */
+#define	OPEN(path, ...)\
+    ut_open(__FILE__, __LINE__, __func__, path, __VA_ARGS__)
+
+/* a close() that can't return -1 */
+#define	CLOSE(fd)\
+    ut_close(__FILE__, __LINE__, __func__, fd)
+
+/* an unlink() that can't return -1 */
+#define	UNLINK(path)\
+    ut_unlink(__FILE__, __LINE__, __func__, path)
+
+/* an access() that can't return -1 */
+#define	ACCESS(path, mode)\
+    ut_access(__FILE__, __LINE__, __func__, path, mode)
+
+/* a write() that can't return -1 */
+#define	WRITE(fd, buf, len)\
+    ut_write(__FILE__, __LINE__, __func__, fd, buf, len)
+
+/* a read() that can't return -1 */
+#define	READ(fd, buf, len)\
+    ut_read(__FILE__, __LINE__, __func__, fd, buf, len)
+
+/* a readlink() that can't return -1 */
+#define	READLINK(path, buf, len)\
+    ut_readlink(__FILE__, __LINE__, __func__, path, buf, len)
+
+/* a lseek() that can't return -1 */
+#define	LSEEK(fd, offset, whence)\
+    ut_lseek(__FILE__, __LINE__, __func__, fd, offset, whence)
+/*
+ * The C Standard specifies that at least one argument must be passed to
+ * the ellipsis, to ensure that the macro does not resolve to an expression
+ * with a trailing comma. So, when calling this macro if num = 0
+ * pass in a 0 for the argument.
+ */
+#define	FCNTL(fd, cmd, num, ...)\
+	ut_fcntl(__FILE__, __LINE__, __func__, fd, cmd, num, __VA_ARGS__)
+
+#define	POSIX_FALLOCATE(fd, off, len)\
+    ut_posix_fallocate(__FILE__, __LINE__, __func__, fd, off, len)
+
+#define	FSTAT(fd, st_bufp)\
+    ut_fstat(__FILE__, __LINE__, __func__, fd, st_bufp)
+
+#define	FLOCK(fd, op)\
+    ut_flock(__FILE__, __LINE__, __func__, fd, op)
+
+/* a mmap() that can't return MAP_FAILED */
+#define	MMAP(addr, len, prot, flags, fd, offset)\
+    ut_mmap(__FILE__, __LINE__, __func__, addr, len, prot, flags, fd, offset);
+
+/* a munmap() that can't return -1 */
+#define	MUNMAP(addr, length)\
+    ut_munmap(__FILE__, __LINE__, __func__, addr, length);
+
+/* a mprotect() that can't return -1 */
+#define	MPROTECT(addr, len, prot)\
+    ut_mprotect(__FILE__, __LINE__, __func__, addr, len, prot);
+
+#define	STAT(path, st_bufp)\
+    ut_stat(__FILE__, __LINE__, __func__, path, st_bufp)
+
+#define	SYMLINK(oldpath, newpath)\
+    ut_symlink(__FILE__, __LINE__, __func__, oldpath, newpath)
+
+#define	LINK(oldpath, newpath)\
+    ut_link(__FILE__, __LINE__, __func__, oldpath, newpath)
+
+#define	MKDIR(pathname, mode)\
+    ut_mkdir(__FILE__, __LINE__, __func__, pathname, mode)
+
+#define	RMDIR(pathname)\
+    ut_rmdir(__FILE__, __LINE__, __func__, pathname)
+
+#define	RENAME(oldpath, newpath)\
+    ut_rename(__FILE__, __LINE__, __func__, oldpath, newpath)
+
+#define	MOUNT(src, tar, fstype, flags, data)\
+    ut_mount(__FILE__, __LINE__, __func__, src, tar, fstype, flags, data)
+
+#define	UMOUNT(tar)\
+    ut_umount(__FILE__, __LINE__, __func__, tar)
+
+#define	PSELECT(nfds, rfds, wfds, efds, tv, sigmask)\
+    ut_pselect(__FILE__, __LINE__, __func__, nfds, rfds, wfds, efds,\
+	tv, sigmask)
+
+#define	MKNOD(pathname, mode, dev)\
+    ut_mknod(__FILE__, __LINE__, __func__, pathname, mode, dev)
+
+#define	TRUNCATE(path, length)\
+    ut_truncate(__FILE__, __LINE__, __func__, path, length)
+
+#define	FTRUNCATE(fd, length)\
+    ut_ftruncate(__FILE__, __LINE__, __func__, fd, length)
+
+#define	CHMOD(path, mode)\
+    ut_chmod(__FILE__, __LINE__, __func__, path, mode)
+
+#define	OPENDIR(name)\
+    ut_opendir(__FILE__, __LINE__, __func__, name)
+
+#define	DIRFD(dirp)\
+    ut_dirfd(__FILE__, __LINE__, __func__, dirp)
+
+#define	CLOSEDIR(dirp)\
+    ut_closedir(__FILE__, __LINE__, __func__, dirp)
+
+/*
+ * signals...
+ */
+int ut_sigvec(const char *file, int line, const char *func,
+		int sig, struct sigvec *vec, struct sigvec *ovec);
+
+/* a sigvec() that can't return an error */
+#define	SIGVEC(sig, vec, ovec)\
+    ut_sigvec(__FILE__, __LINE__, __func__, sig, vec, ovec)
+
+/*
+ * pthreads...
+ */
+int ut_pthread_create(const char *file, int line, const char *func,
+    pthread_t *restrict thread,
+    const pthread_attr_t *restrict attr,
+    void *(*start_routine)(void *), void *restrict arg);
+int ut_pthread_join(const char *file, int line, const char *func,
+    pthread_t thread, void **value_ptr);
+
+/* a pthread_create() that can't return an error */
+#define	PTHREAD_CREATE(thread, attr, start_routine, arg)\
+    ut_pthread_create(__FILE__, __LINE__, __func__,\
+    thread, attr, start_routine, arg)
+
+/* a pthread_join() that can't return an error */
+#define	PTHREAD_JOIN(thread, value_ptr)\
+    ut_pthread_join(__FILE__, __LINE__, __func__, thread, value_ptr)
+
+#endif	/* unittest.h */
diff --git a/src/test/unittest/unittest.sh b/src/test/unittest/unittest.sh
new file mode 100644
index 0000000000000000000000000000000000000000..48d74eded6a107b29f8764b76681eb65f004771b
--- /dev/null
+++ b/src/test/unittest/unittest.sh
@@ -0,0 +1,215 @@
+#
+# Copyright (c) 2014, Intel Corporation
+#
+# Redistribution and use in source and binary forms, with or without
+# modification, are permitted provided that the following conditions
+# are met:
+#
+#     * Redistributions of source code must retain the above copyright
+#       notice, this list of conditions and the following disclaimer.
+#
+#     * Redistributions in binary form must reproduce the above copyright
+#       notice, this list of conditions and the following disclaimer in
+#       the documentation and/or other materials provided with the
+#       distribution.
+#
+#     * Neither the name of Intel Corporation nor the names of its
+#       contributors may be used to endorse or promote products derived
+#       from this software without specific prior written permission.
+#
+# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+#
+
+. ../testconfig.sh
+
+# defaults
+[ "$TEST" ] || export TEST=check
+[ "$FS" ] || export FS=local
+[ "$BUILD" ] || export BUILD=debug
+
+# force globs to fail if they don't match
+shopt -s failglob
+
+#
+# For non-static build testing, the variable TEST_LD_LIBRARY_PATH is
+# constructed so the test pulls in the appropriate library from this
+# source tree.  To override this behavior (i.e. to force the test to
+# use the libraries installed elsewhere on the system), set
+# TEST_LD_LIBRARY_PATH and this script will not override it.
+#
+# For example, in a test directory, run:
+#	TEST_LD_LIBRARY_PATH=/usr/lib ./TEST0
+#
+[ "$TEST_LD_LIBRARY_PATH" ] || {
+	case "$BUILD"
+	in
+	debug)
+		TEST_LD_LIBRARY_PATH=../../debug
+		;;
+	nondebug)
+		TEST_LD_LIBRARY_PATH=../../nondebug
+		;;
+	esac
+}
+
+#
+# When running static binary tests, append the build type to the binary
+#
+case "$BUILD"
+in
+	static-*)
+		EXESUFFIX=.$BUILD
+		;;
+esac
+
+#
+# The variable DIR is constructed so the test uss that directory when
+# constructing test files.  DIR is chosen based on the fs-type for
+# this test, and if the appropriate fs-type doesn't have a directory
+# defined in testconfig.sh, the test is skipped.
+#
+# This behavior can be overridden by setting DIR.  For example:
+#	DIR=/force/test/dir ./TEST0
+#
+[ "$DIR" ] || {
+	case "$FS"
+	in
+	local)
+		DIR=$LOCAL_FS_DIR
+		;;
+	pmem)
+		DIR=$PMEM_FS_DIR
+		;;
+	non-pmem)
+		DIR=$NON_PMEM_FS_DIR
+		;;
+	esac
+	[ "$DIR" ] || {
+		[ "$UNITTEST_QUIET" ] || echo "$UNITTEST_NAME: SKIP fs-type $FS (not configured)"
+		exit 0
+	}
+}
+
+#
+# The default is to turn on library logging to level 3 and save it to local files.
+# Tests that don't want it on, should override these environment variables.
+#
+export VMEM_LOG_LEVEL=3
+export VMEM_LOG_FILE=vmem$UNITTEST_NUM.log
+export PMEM_LOG_LEVEL=3
+export PMEM_LOG_FILE=pmem$UNITTEST_NUM.log
+
+#
+# create_file -- create zeroed out files of a given length in megs
+#
+# example, to create two files, each 1GB in size:
+#	create_file 1024 testfile1 testfile2
+#
+function create_file() {
+	size=$1
+	shift
+	for file in $*
+	do
+		dd if=/dev/zero of=$file bs=1M count=$size >> prep$UNITTEST_NUM.log
+	done
+}
+
+#
+# create_holey_file -- create holey files of a given length in megs
+#
+# example, to create two files, each 1GB in size:
+#	create_holey_file 1024 testfile1 testfile2
+#
+function create_holey_file() {
+	size=$1
+	shift
+	for file in $*
+	do
+		truncate -s ${size}M $file >> prep$UNITTEST_NUM.log
+	done
+}
+
+#
+# expect_normal_exit -- run a given command, expect it to exit 0
+#
+function expect_normal_exit() {
+	eval $ECHO LD_LIBRARY_PATH=$TEST_LD_LIBRARY_PATH \
+	$TRACE $*
+}
+
+#
+# expect_abnormal_exit -- run a given command, expect it to exit non-zero
+#
+function expect_abnormal_exit() {
+	set +e
+	eval $ECHO LD_LIBRARY_PATH=$TEST_LD_LIBRARY_PATH \
+	$TRACE $*
+	set -e
+}
+
+#
+# require_test_type -- only allow script to continue for a certain test type
+#
+function require_test_type() {
+	for type in $*
+	do
+		[ "$type" = "$TEST" ] && return
+	done
+	[ "$UNITTEST_QUIET" ] || echo "$UNITTEST_NAME: SKIP test-type $TEST ($* required)"
+	exit 0
+}
+
+#
+# require_fs_type -- only allow script to continue for a certain fs type
+#
+function require_fs_type() {
+	for type in $*
+	do
+		[ "$type" = "$FS" ] && return
+	done
+	[ "$UNITTEST_QUIET" ] || echo "$UNITTEST_NAME: SKIP fs-type $FS ($* required)"
+	exit 0
+}
+
+#
+# require_build_type -- only allow script to continue for a certain build type
+#
+function require_build_type() {
+	for type in $*
+	do
+		[ "$type" = "$BUILD" ] && return
+	done
+	[ "$UNITTEST_QUIET" ] || echo "$UNITTEST_NAME: SKIP build-type $BUILD ($* required)"
+	exit 0
+}
+
+#
+# setup -- print message that test setup is commencing
+#
+function setup() {
+	echo "$UNITTEST_NAME: SETUP ($TEST/$FS/$BUILD)"
+}
+
+#
+# check -- check test results (using .match files)
+#
+function check() {
+	../match *$UNITTEST_NUM.log.match
+}
+
+#
+# pass -- print message that the test has passed
+#
+function pass() {
+	echo $UNITTEST_NAME: PASS
+}
diff --git a/src/test/unittest/ut.c b/src/test/unittest/ut.c
new file mode 100644
index 0000000000000000000000000000000000000000..a6eb5cbc2b7ddc38fa77651331c99a35111d3a7e
--- /dev/null
+++ b/src/test/unittest/ut.c
@@ -0,0 +1,468 @@
+/*
+ * Copyright (c) 2014, Intel Corporation
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ *     * Redistributions of source code must retain the above copyright
+ *       notice, this list of conditions and the following disclaimer.
+ *
+ *     * Redistributions in binary form must reproduce the above copyright
+ *       notice, this list of conditions and the following disclaimer in
+ *       the documentation and/or other materials provided with the
+ *       distribution.
+ *
+ *     * Neither the name of Intel Corporation nor the names of its
+ *       contributors may be used to endorse or promote products derived
+ *       from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+/*
+ * ut.c -- unit test support routines
+ *
+ * some of these functions look at errno, but none of them
+ * change errno -- it is preserved across these calls.
+ *
+ * ut_done() and ut_fatal() never return.
+ */
+
+#include "unittest.h"
+
+/* RHEL5 seems to be missing decls, even though libc supports them */
+extern DIR *fdopendir(int fd);
+extern ssize_t readlinkat(int, const char *restrict, char *restrict, size_t);
+
+#define	MAXLOGNAME 100		/* maximum expected .log file name length */
+#define	MAXPRINT 8192		/* maximum expected single print length */
+
+/*
+ * output gets replicated to these files
+ */
+static FILE *Outfp;
+static FILE *Errfp;
+static FILE *Tracefp;
+
+static int Quiet;		/* set by UNITTEST_QUIET env variable */
+static char *Testname;		/* set by UNITTEST_NAME env variable */
+
+/*
+ * flags that control output
+ */
+#define	OF_NONL		1	/* do not append newline */
+#define	OF_ERR		2	/* output is error output */
+#define	OF_TRACE	4	/* output to trace file only */
+#define	OF_LOUD		8	/* output even in Quiet mode */
+#define	OF_NAME		16	/* include Testname in the output */
+
+/*
+ * vout -- common output code, all output happens here
+ */
+static void
+vout(int flags, const char *prepend, const char *fmt, va_list ap)
+{
+	char buf[MAXPRINT];
+	int cc = 0;
+	int quiet = Quiet;
+	const char *sep = "";
+	const char *errstr = "";
+	const char *nl = "\n";
+
+	if (flags & OF_LOUD)
+		quiet = 0;
+
+	if (flags & OF_NONL)
+		nl = "";
+
+	if (flags & OF_NAME && Testname)
+		cc += snprintf(&buf[cc], MAXPRINT - cc, "%s: ", Testname);
+
+	if (prepend) {
+		const char *colon = "";
+
+		if (fmt)
+			colon = ": ";
+
+		cc += snprintf(&buf[cc], MAXPRINT - cc, "%s%s", prepend, colon);
+	}
+
+	if (fmt) {
+		if (*fmt == '!') {
+			fmt++;
+			sep = ": ";
+			errstr = strerror(errno);
+		}
+		cc += vsnprintf(&buf[cc], MAXPRINT - cc, fmt, ap);
+	}
+
+	snprintf(&buf[cc], MAXPRINT - cc, "%s%s%s", sep, errstr, nl);
+
+	/* buf has the fully-baked output, send it everywhere it goes... */
+	fputs(buf, Tracefp);
+	if (flags & OF_ERR) {
+		fputs(buf, Errfp);
+		if (!quiet)
+			fputs(buf, stderr);
+	} else if ((flags & OF_TRACE) == 0) {
+		fputs(buf, Outfp);
+		if (!quiet)
+			fputs(buf, stdout);
+	}
+}
+
+/*
+ * out -- printf-like output controlled by flags
+ */
+static void
+out(int flags, const char *fmt, ...)
+{
+	va_list ap;
+	va_start(ap, fmt);
+
+	vout(flags, NULL, fmt, ap);
+
+	va_end(ap);
+}
+
+/*
+ * prefix -- emit the trace line prefix
+ */
+static void
+prefix(const char *file, int line, const char *func)
+{
+	out(OF_NONL|OF_TRACE, "{%s:%d %s} ", file, line, func);
+}
+
+/*
+ * lookup table for open files
+ */
+static struct fd_lut {
+	struct fd_lut *left;
+	struct fd_lut *right;
+	int fdnum;
+	char *fdfile;
+} *Fd_lut;
+int Fd_errcount;
+
+/*
+ * open_file_add -- add an open file to the lut
+ */
+static struct fd_lut *
+open_file_add(struct fd_lut *root, int fdnum, const char *fdfile)
+{
+	if (root == NULL) {
+		root = ZALLOC(sizeof (*root));
+		root->fdnum = fdnum;
+		root->fdfile = STRDUP(fdfile);
+	} else if (root->fdnum == fdnum)
+		FATAL("duplicate fdnum: %d", fdnum);
+	else if (root->fdnum < fdnum)
+		root->left = open_file_add(root->left, fdnum, fdfile);
+	else
+		root->right = open_file_add(root->right, fdnum, fdfile);
+	return root;
+}
+
+/*
+ * open_file_remove -- find exact match & remove it from lut
+ *
+ * prints error if exact match not found, increments Fd_errcount
+ */
+static void
+open_file_remove(struct fd_lut *root, int fdnum, const char *fdfile)
+{
+	if (root == NULL) {
+		ERR("unexpected open file: fd %d => \"%s\"", fdnum, fdfile);
+		Fd_errcount++;
+	} else if (root->fdnum == fdnum) {
+		if (root->fdfile == NULL) {
+			ERR("open file dup: fd %d => \"%s\"", fdnum, fdfile);
+			Fd_errcount++;
+		} else if (strcmp(root->fdfile, fdfile) == 0) {
+			/* found exact match */
+			FREE(root->fdfile);
+			root->fdfile = NULL;
+		} else {
+			ERR("open file changed: fd %d was \"%s\" now \"%s\"",
+			    fdnum, root->fdfile, fdfile);
+			Fd_errcount++;
+		}
+	} else if (root->fdnum < fdnum)
+		open_file_remove(root->left, fdnum, fdfile);
+	else
+		open_file_remove(root->right, fdnum, fdfile);
+}
+
+/*
+ * open_file_walk -- walk lut for any left-overs
+ *
+ * prints error if any found, increments Fd_errcount
+ */
+static void
+open_file_walk(struct fd_lut *root)
+{
+	if (root) {
+		open_file_walk(root->left);
+		if (root->fdfile) {
+			ERR("open file missing: fd %d => \"%s\"",
+			    root->fdnum, root->fdfile);
+			Fd_errcount++;
+		}
+		open_file_walk(root->right);
+	}
+}
+
+/*
+ * open_file_free -- free the lut
+ */
+static void
+open_file_free(struct fd_lut *root)
+{
+	if (root) {
+		open_file_free(root->left);
+		open_file_free(root->right);
+		if (root->fdfile)
+			FREE(root->fdfile);
+		FREE(root);
+	}
+}
+
+/*
+ * record_open_files -- make a list of open files (used at START() time)
+ */
+static void
+record_open_files()
+{
+	int dirfd;
+	DIR *dirp = NULL;
+	struct dirent *dp;
+
+	if ((dirfd = open("/proc/self/fd", O_RDONLY)) < 0 ||
+	    (dirp = fdopendir(dirfd)) == NULL)
+		FATAL("!/proc/self/fd");
+	while ((dp = readdir(dirp)) != NULL) {
+		int fdnum;
+		char fdfile[PATH_MAX];
+		int cc;
+
+		if (*dp->d_name == '.')
+			continue;
+		if ((cc = readlinkat(dirfd, dp->d_name, fdfile, PATH_MAX)) < 0)
+		    FATAL("!readlinkat: /proc/self/fd/%s", dp->d_name);
+		fdfile[cc] = '\0';
+		fdnum = atoi(dp->d_name);
+		if (dirfd == fdnum)
+			continue;
+		Fd_lut = open_file_add(Fd_lut, fdnum, fdfile);
+	}
+	closedir(dirp);
+}
+
+/*
+ * check_open_files -- verify open files match recorded open files
+ */
+static void
+check_open_files()
+{
+	int dirfd;
+	DIR *dirp = NULL;
+	struct dirent *dp;
+
+	if ((dirfd = open("/proc/self/fd", O_RDONLY)) < 0 ||
+	    (dirp = fdopendir(dirfd)) == NULL)
+		FATAL("!/proc/self/fd");
+	while ((dp = readdir(dirp)) != NULL) {
+		int fdnum;
+		char fdfile[PATH_MAX];
+		int cc;
+
+		if (*dp->d_name == '.')
+			continue;
+		if ((cc = readlinkat(dirfd, dp->d_name, fdfile, PATH_MAX)) < 0)
+		    FATAL("!readlinkat: /proc/self/fd/%s", dp->d_name);
+		fdfile[cc] = '\0';
+		fdnum = atoi(dp->d_name);
+		if (dirfd == fdnum)
+			continue;
+		open_file_remove(Fd_lut, fdnum, fdfile);
+	}
+	closedir(dirp);
+	open_file_walk(Fd_lut);
+	if (Fd_errcount)
+		FATAL("open file list changed between START() and DONE()");
+	open_file_free(Fd_lut);
+}
+
+/*
+ * ut_start -- initialize unit test framework, indicate test started
+ */
+void
+ut_start(const char *file, int line, const char *func,
+    int argc, char * const argv[], const char *fmt, ...)
+{
+	va_list ap;
+	int saveerrno = errno;
+	char logname[MAXLOGNAME];
+	char *logsuffix;
+
+	va_start(ap, fmt);
+
+	if (getenv("UNITTEST_QUIET") != NULL)
+		Quiet++;
+
+	Testname = getenv("UNITTEST_NAME");
+
+	if ((logsuffix = getenv("UNITTEST_NUM")) == NULL)
+		logsuffix = "";
+
+	snprintf(logname, MAXLOGNAME, "out%s.log", logsuffix);
+	if ((Outfp = fopen(logname, "w")) == NULL) {
+		perror(logname);
+		exit(1);
+	}
+
+	snprintf(logname, MAXLOGNAME, "err%s.log", logsuffix);
+	if ((Errfp = fopen(logname, "w")) == NULL) {
+		perror(logname);
+		exit(1);
+	}
+
+	snprintf(logname, MAXLOGNAME, "trace%s.log", logsuffix);
+	if ((Tracefp = fopen(logname, "w")) == NULL) {
+		perror(logname);
+		exit(1);
+	}
+
+	setlinebuf(Outfp);
+	setlinebuf(Errfp);
+	setlinebuf(Tracefp);
+	setlinebuf(stdout);
+
+	prefix(file, line, func);
+	vout(OF_LOUD|OF_NAME, "START", fmt, ap);
+
+	out(OF_NONL, 0, "     args:");
+	for (int i = 0; i < argc; i++)
+		out(OF_NONL, " %s", argv[i]);
+	out(0, NULL);
+
+	va_end(ap);
+
+	/* generate a uuid so the leaked fd gets recorded */
+	uuid_t u;
+	uuid_generate(u);
+
+	record_open_files();
+
+	errno = saveerrno;
+}
+
+/*
+ * ut_done -- indicate test is done, exit program
+ */
+void
+ut_done(const char *file, int line, const char *func,
+    const char *fmt, ...)
+{
+	va_list ap;
+
+	va_start(ap, fmt);
+
+	check_open_files();
+
+	prefix(file, line, func);
+	vout(OF_NAME, "Done", fmt, ap);
+
+	va_end(ap);
+
+	if (Outfp != NULL)
+		fclose(Outfp);
+
+	if (Errfp != NULL)
+		fclose(Errfp);
+
+	if (Tracefp != NULL)
+		fclose(Tracefp);
+
+	exit(0);
+}
+
+/*
+ * ut_fatal -- indicate fatal error, exit program
+ */
+void
+ut_fatal(const char *file, int line, const char *func,
+    const char *fmt, ...)
+{
+	va_list ap;
+
+	va_start(ap, fmt);
+
+	prefix(file, line, func);
+	vout(OF_ERR|OF_NAME, "Error", fmt, ap);
+
+	va_end(ap);
+
+	if (Outfp != NULL)
+		fclose(Outfp);
+
+	if (Errfp != NULL)
+		fclose(Errfp);
+
+	if (Tracefp != NULL)
+		fclose(Tracefp);
+
+	exit(1);
+}
+
+/*
+ * ut_out -- output to stdout
+ */
+void
+ut_out(const char *file, int line, const char *func,
+    const char *fmt, ...)
+{
+	va_list ap;
+	int saveerrno = errno;
+
+	va_start(ap, fmt);
+
+	prefix(file, line, func);
+	vout(0, NULL, fmt, ap);
+
+	va_end(ap);
+
+	errno = saveerrno;
+}
+
+/*
+ * ut_err -- output to stderr
+ */
+void
+ut_err(const char *file, int line, const char *func,
+    const char *fmt, ...)
+{
+	va_list ap;
+	int saveerrno = errno;
+
+	va_start(ap, fmt);
+
+	prefix(file, line, func);
+	vout(OF_ERR|OF_NAME, NULL, fmt, ap);
+
+	va_end(ap);
+
+	errno = saveerrno;
+}
diff --git a/src/test/unittest/ut_alloc.c b/src/test/unittest/ut_alloc.c
new file mode 100644
index 0000000000000000000000000000000000000000..649a98483b9b2ec3d096cd630d884baa73776a17
--- /dev/null
+++ b/src/test/unittest/ut_alloc.c
@@ -0,0 +1,140 @@
+/*
+ * Copyright (c) 2014, Intel Corporation
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ *     * Redistributions of source code must retain the above copyright
+ *       notice, this list of conditions and the following disclaimer.
+ *
+ *     * Redistributions in binary form must reproduce the above copyright
+ *       notice, this list of conditions and the following disclaimer in
+ *       the documentation and/or other materials provided with the
+ *       distribution.
+ *
+ *     * Neither the name of Intel Corporation nor the names of its
+ *       contributors may be used to endorse or promote products derived
+ *       from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+/*
+ * ut_alloc.c -- unit test memory allocation routines
+ */
+
+#include "unittest.h"
+
+/*
+ * ut_malloc -- a malloc that cannot return NULL
+ */
+void *
+ut_malloc(const char *file, int line, const char *func, size_t size)
+{
+	void *retval = malloc(size);
+
+	if (retval == NULL)
+		ut_fatal(file, line, func, "cannot malloc %zu bytes", size);
+
+	return retval;
+}
+
+/*
+ * ut_calloc -- a calloc that cannot return NULL
+ */
+void *
+ut_calloc(const char *file, int line, const char *func,
+    size_t nmemb, size_t size)
+{
+	void *retval = calloc(nmemb, size);
+
+	if (retval == NULL)
+		ut_fatal(file, line, func, "cannot calloc %zu bytes", size);
+
+	return retval;
+}
+
+/*
+ * ut_free -- wrapper for free
+ *
+ * technically we don't need to wrap free since there's no return to
+ * check.  using this wrapper to add memory allocation tracking later.
+ */
+void
+ut_free(const char *file, int line, const char *func, void *ptr)
+{
+	free(ptr);
+}
+
+/*
+ * ut_realloc -- a realloc that cannot return NULL
+ */
+void *
+ut_realloc(const char *file, int line, const char *func,
+    void *ptr, size_t size)
+{
+	void *retval = realloc(ptr, size);
+
+	if (retval == NULL)
+		ut_fatal(file, line, func, "cannot realloc %zu bytes", size);
+
+	return retval;
+}
+
+/*
+ * ut_strdup -- a strdup that cannot return NULL
+ */
+char *
+ut_strdup(const char *file, int line, const char *func,
+    const char *str)
+{
+	char *retval = strdup(str);
+
+	if (retval == NULL)
+		ut_fatal(file, line, func, "cannot strdup %zu bytes",
+		    strlen(str));
+
+	return retval;
+}
+
+/*
+ * ut_pagealignmalloc -- like malloc but page-aligned memory
+ */
+void *
+ut_pagealignmalloc(const char *file, int line, const char *func,
+    size_t size)
+{
+	static long pagesize;
+
+	if (pagesize == 0)
+		pagesize = sysconf(_SC_PAGESIZE);
+
+	return ut_memalign(file, line, func, (size_t)pagesize, size);
+}
+
+/*
+ * ut_memalign -- like malloc but page-aligned memory
+ */
+void *
+ut_memalign(const char *file, int line, const char *func, size_t alignment,
+    size_t size)
+{
+	void *retval;
+
+	if ((errno = posix_memalign(&retval, alignment, size)) != 0)
+		ut_fatal(file, line, func,
+		    "!memalign %zu bytes (%zu alignment)", size, alignment);
+
+	return retval;
+}
diff --git a/src/test/unittest/ut_file.c b/src/test/unittest/ut_file.c
new file mode 100644
index 0000000000000000000000000000000000000000..8e9352289f353b70b4856f29a4dbaa5aa9c79b08
--- /dev/null
+++ b/src/test/unittest/ut_file.c
@@ -0,0 +1,531 @@
+/*
+ * Copyright (c) 2014, Intel Corporation
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ *     * Redistributions of source code must retain the above copyright
+ *       notice, this list of conditions and the following disclaimer.
+ *
+ *     * Redistributions in binary form must reproduce the above copyright
+ *       notice, this list of conditions and the following disclaimer in
+ *       the documentation and/or other materials provided with the
+ *       distribution.
+ *
+ *     * Neither the name of Intel Corporation nor the names of its
+ *       contributors may be used to endorse or promote products derived
+ *       from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+/*
+ * ut_file.c -- unit test file operations
+ */
+
+#include "unittest.h"
+
+/*
+ * ut_open -- an open that cannot return < 0
+ */
+int
+ut_open(const char *file, int line, const char *func, char *path,
+    int flags, ...)
+{
+	va_list ap;
+	int mode;
+
+	va_start(ap, flags);
+	mode = va_arg(ap, int);
+	int retval = open(path, flags, mode);
+	va_end(ap);
+
+	if (retval < 0)
+		ut_fatal(file, line, func, "!open: %s", path);
+
+	return retval;
+}
+
+/*
+ * ut_close -- a close that cannot return -1
+ */
+int
+ut_close(const char *file, int line, const char *func, int fd)
+{
+	int retval = close(fd);
+
+	if (retval != 0)
+		ut_fatal(file, line, func, "!close: %d", fd);
+
+	return retval;
+}
+
+/*
+ * ut_unlink -- an unlink that cannot return -1
+ */
+int
+ut_unlink(const char *file, int line, const char *func, const char *path)
+{
+	int retval = unlink(path);
+
+	if (retval != 0)
+		ut_fatal(file, line, func, "!unlink: %s", path);
+
+	return retval;
+}
+
+/*
+ * ut_posix_fallocate -- a posix_fallocate that cannot return -1
+ */
+int
+ut_posix_fallocate(const char *file, int line, const char *func, int fd,
+    off_t offset, off_t len)
+{
+	int retval = posix_fallocate(fd, offset, len);
+
+	if (retval != 0) {
+		errno = retval;
+		ut_fatal(file, line, func,
+		    "!fallocate: fd %d offset 0x%llx len %llu",
+		    fd, (unsigned long long)offset, (unsigned long long)len);
+	}
+
+	return retval;
+}
+
+/*
+ * ut_access -- an access that cannot return -1
+ */
+int
+ut_access(const char *file, int line, const char *func, const char *path,
+    int mode)
+{
+	int retval = access(path, mode);
+
+	if (retval != 0)
+		ut_fatal(file, line, func, "!access: %s: %d", path, mode);
+
+	return retval;
+}
+
+/*
+ * ut_write -- a write that can't return -1
+ */
+int
+ut_write(const char *file, int line, const char *func, int fd,
+    const void *buf, size_t count)
+{
+	int retval = write(fd, buf, count);
+
+	if (retval < 0)
+		ut_fatal(file, line, func, "!write: %d", fd);
+
+	return retval;
+}
+
+/*
+ * ut_read -- a read that can't return -1
+ */
+int
+ut_read(const char *file, int line, const char *func, int fd,
+    void *buf, size_t count)
+{
+	int retval = read(fd, buf, count);
+
+	if (retval < 0)
+		ut_fatal(file, line, func, "!read: %d", fd);
+
+	return retval;
+}
+
+/*
+ * ut_readlink -- a readlink that can't return -1
+ */
+int
+ut_readlink(const char *file, int line, const char *func, const char *path,
+    void *buf, size_t count)
+{
+	int retval = readlink(path, buf, count);
+
+	if (retval < 0)
+		ut_fatal(file, line, func, "!readlink: %s", path);
+
+	return retval;
+}
+
+/*
+ * ut_lseek -- an lseek that can't return -1
+ */
+off_t
+ut_lseek(const char *file, int line, const char *func, int fd,
+    off_t offset, int whence)
+{
+	int retval = lseek(fd, offset, whence);
+
+	if (retval == (off_t)-1)
+		ut_fatal(file, line, func, "!lseek: %d", fd);
+
+	return retval;
+}
+
+int
+ut_fcntl(const char *file, int line, const char *func, int fd,
+	int cmd, int num, ...)
+{
+
+	int retval;
+	va_list args;
+	uint64_t arg = 0;
+
+	/*
+	 * In the case of fcntl, num is always 0 or 1
+	 */
+	if (num != 0) {
+		va_start(args, num);
+		arg = va_arg(args, uint64_t);
+		retval = fcntl(fd, cmd, arg);
+		va_end(args);
+	} else
+		retval = fcntl(fd, cmd);
+
+	if (retval < 0)
+		ut_fatal(file, line, func, "!fcntl: %d", fd);
+
+	return retval;
+}
+
+/*
+ * ut_fstat -- a fstat that cannot return -1
+ */
+int
+ut_fstat(const char *file, int line, const char *func, int fd,
+    struct stat *st_bufp)
+{
+	int retval = fstat(fd, st_bufp);
+
+	if (retval < 0)
+		ut_fatal(file, line, func, "!fstat: %d", fd);
+
+	return retval;
+}
+
+/*
+ * ut_flock -- a flock that cannot return -1
+ */
+int
+ut_flock(const char *file, int line, const char *func, int fd, int op)
+{
+	int retval = flock(fd, op);
+
+	if (retval != 0)
+		ut_fatal(file, line, func, "!flock: %d", fd);
+
+	return retval;
+}
+
+/*
+ * ut_stat -- a stat that cannot return -1
+ */
+int
+ut_stat(const char *file, int line, const char *func, const char *path,
+    struct stat *st_bufp)
+{
+	int retval = stat(path, st_bufp);
+
+	if (retval < 0)
+		ut_fatal(file, line, func, "!stat: %s", path);
+
+	return retval;
+}
+
+/*
+ * ut_mmap -- a mmap call that cannot return MAP_FAILED
+ */
+void *
+ut_mmap(const char *file, int line, const char *func, void *addr,
+    size_t length, int prot, int flags, int fd, off_t offset)
+{
+	void *ret_addr = mmap(addr, length, prot, flags, fd, offset);
+
+	if (ret_addr == MAP_FAILED)
+		ut_fatal(file, line, func,
+		    "!mmap: addr=0x%llx length=0x%zx prot=%d flags=%d fd=%d "
+		    "offset=0x%llx", (unsigned long long)addr,
+		    length, prot, flags, fd, (unsigned long long)offset);
+
+	return ret_addr;
+}
+
+/*
+ * ut_munmap -- a munmap call that cannot return -1
+ */
+int
+ut_munmap(const char *file, int line, const char *func, void *addr,
+    size_t length)
+{
+	int retval = munmap(addr, length);
+
+	if (retval < 0)
+		ut_fatal(file, line, func, "!munmap: addr=0x%llx length=0x%zx",
+		    (unsigned long long)addr, length);
+
+	return retval;
+}
+
+/*
+ * ut_mprotect -- a mprotect call that cannot return -1
+ */
+int
+ut_mprotect(const char *file, int line, const char *func, void *addr,
+    size_t len, int prot)
+{
+	int retval = mprotect(addr, len, prot);
+
+	if (retval < 0)
+		ut_fatal(file, line, func,
+		    "!mprotect: addr=0x%llx length=0x%zx prot=0x%x",
+		    (unsigned long long)addr, len, prot);
+
+	return retval;
+}
+
+/*
+ * ut_symlink -- a symlink that cannot return -1
+ */
+int
+ut_symlink(const char *file, int line, const char *func, const char *oldpath,
+    const char *newpath)
+{
+	int retval = symlink(oldpath, newpath);
+
+	if (retval < 0)
+		ut_fatal(file, line, func, "!symlink: %s %s", oldpath, newpath);
+
+	return retval;
+}
+
+/*
+ * ut_link -- a link that cannot return -1
+ */
+int
+ut_link(const char *file, int line, const char *func, const char *oldpath,
+    const char *newpath)
+{
+	int retval = link(oldpath, newpath);
+
+	if (retval < 0)
+		ut_fatal(file, line, func, "!link: %s %s", oldpath,
+		    newpath);
+
+	return retval;
+}
+
+/*
+ * ut_mkdir -- a mkdir that cannot return -1
+ */
+int
+ut_mkdir(const char *file, int line, const char *func,
+    const char *pathname, mode_t mode)
+{
+	int retval = mkdir(pathname, mode);
+
+	if (retval < 0)
+		ut_fatal(file, line, func, "!mkdir: %s", pathname);
+
+	return retval;
+}
+
+/*
+ * ut_rmdir -- a rmdir that cannot return -1
+ */
+int
+ut_rmdir(const char *file, int line, const char *func,
+    const char *pathname)
+{
+	int retval = rmdir(pathname);
+
+	if (retval < 0)
+		ut_fatal(file, line, func, "!rmdir: %s", pathname);
+
+	return retval;
+}
+
+/*
+ * ut_rename -- a rename that cannot return -1
+ */
+int
+ut_rename(const char *file, int line, const char *func,
+    const char *oldpath, const char *newpath)
+{
+	int retval = rename(oldpath, newpath);
+
+	if (retval < 0)
+		ut_fatal(file, line, func, "!rename: %s %s", oldpath, newpath);
+
+	return retval;
+}
+
+/*
+ * ut_mount -- a mount that cannot return -1
+ */
+int
+ut_mount(const char *file, int line, const char *func, const char *src,
+    const char *tar, const char *fstype, unsigned long flags,
+    const void *data)
+{
+	int retval = mount(src, tar, fstype, flags, data);
+
+	if (retval < 0)
+		ut_fatal(file, line, func, "!mount: %s %s %s %lx",
+		    src, tar, fstype, flags);
+
+	return retval;
+}
+
+/*
+ * ut_umount -- a umount that cannot return -1
+ */
+int
+ut_umount(const char *file, int line, const char *func, const char *tar)
+{
+	int retval = umount(tar);
+
+	if (retval < 0)
+		ut_fatal(file, line, func, "!umount: %s", tar);
+
+	return retval;
+}
+
+
+/*
+ * ut_truncate -- a truncate that cannot return -1
+ */
+int
+ut_truncate(const char *file, int line, const char *func, const char *path,
+    off_t length)
+{
+	int retval = truncate(path, length);
+
+	if (retval < 0)
+		ut_fatal(file, line, func, "!truncate: %s %llu",
+				path, (unsigned long long)length);
+
+	return retval;
+}
+
+/*
+ * ut_ftruncate -- a ftruncate that cannot return -1
+ */
+int
+ut_ftruncate(const char *file, int line, const char *func, int fd,
+    off_t length)
+{
+	int retval = ftruncate(fd, length);
+
+	if (retval < 0)
+		ut_fatal(file, line, func, "!ftruncate: %d %llu",
+				fd, (unsigned long long)length);
+
+	return retval;
+}
+
+/*
+ * ut_chmod -- a chmod that cannot return -1
+ */
+int
+ut_chmod(const char *file, int line, const char *func, const char *path,
+    mode_t mode)
+{
+	int retval = chmod(path, mode);
+
+	if (retval < 0)
+		ut_fatal(file, line, func, "!mode: %s %o", path, mode);
+
+	return retval;
+}
+
+/*
+ * ut_mknod -- a mknod that cannot return -1
+ */
+int
+ut_mknod(const char *file, int line, const char *func, const char *pathname,
+    mode_t mode, dev_t dev)
+{
+	int retval = mknod(pathname, mode, dev);
+
+	if (retval < 0)
+		ut_fatal(file, line, func, "!mknod: %s", pathname);
+
+	return retval;
+}
+
+/*
+ * ut_pselect -- a pselect that cannot return -1
+ */
+int
+ut_pselect(const char *file, int line, const char *func, int nfds,
+    fd_set *rfds, fd_set *wfds, fd_set *efds, const struct timespec *tv,
+    const sigset_t *sigmask)
+{
+	int retval = pselect(nfds, rfds, wfds, efds, tv, sigmask);
+
+	if (retval < 0)
+		ut_fatal(file, line, func, "!pselect");
+
+	return retval;
+}
+
+/*
+ * ut_opendir -- an opendir that cannot return NULL
+ */
+DIR *
+ut_opendir(const char *file, int line, const char *func,
+    const char *name)
+{
+	DIR *retval = opendir(name);
+
+	if (retval == NULL)
+		ut_fatal(file, line, func, "!opendir: %s", name);
+
+	return retval;
+}
+
+/*
+ * ut_dirfd -- a dirfd that cannot return -1
+ */
+int
+ut_dirfd(const char *file, int line, const char *func,
+    DIR *dirp)
+{
+	int retval = dirfd(dirp);
+
+	if (retval < 0)
+		ut_fatal(file, line, func, "!dirfd: %p", dirp);
+
+	return retval;
+}
+
+/*
+ * ut_closedir -- a closedir that cannot return -1
+ */
+int
+ut_closedir(const char *file, int line, const char *func, DIR *dirp)
+{
+	int retval = closedir(dirp);
+
+	if (retval < 0)
+		ut_fatal(file, line, func, "!closedir: %p", dirp);
+
+	return retval;
+}
diff --git a/src/test/unittest/ut_pthread.c b/src/test/unittest/ut_pthread.c
new file mode 100644
index 0000000000000000000000000000000000000000..68e534cf326a41588098cf5df382a21c686e3498
--- /dev/null
+++ b/src/test/unittest/ut_pthread.c
@@ -0,0 +1,65 @@
+/*
+ * Copyright (c) 2014, Intel Corporation
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ *     * Redistributions of source code must retain the above copyright
+ *       notice, this list of conditions and the following disclaimer.
+ *
+ *     * Redistributions in binary form must reproduce the above copyright
+ *       notice, this list of conditions and the following disclaimer in
+ *       the documentation and/or other materials provided with the
+ *       distribution.
+ *
+ *     * Neither the name of Intel Corporation nor the names of its
+ *       contributors may be used to endorse or promote products derived
+ *       from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+/*
+ * ut_pthread.c -- unit test wrappers for pthread routines
+ */
+
+#include "unittest.h"
+
+/*
+ * ut_pthread_create -- a pthread_create that cannot return an error
+ */
+int
+ut_pthread_create(const char *file, int line, const char *func,
+    pthread_t *restrict thread,
+    const pthread_attr_t *restrict attr,
+    void *(*start_routine)(void *), void *restrict arg)
+{
+	if ((errno = pthread_create(thread, attr, start_routine, arg)) != 0)
+		ut_fatal(file, line, func, "!pthread_create");
+
+	return 0;
+}
+
+/*
+ * ut_pthread_join -- a pthread_join that cannot return an error
+ */
+int
+ut_pthread_join(const char *file, int line, const char *func,
+    pthread_t thread, void **value_ptr)
+{
+	if ((errno = pthread_join(thread, value_ptr)) != 0)
+		ut_fatal(file, line, func, "!pthread_join");
+
+	return 0;
+}
diff --git a/src/test/unittest/ut_signal.c b/src/test/unittest/ut_signal.c
new file mode 100644
index 0000000000000000000000000000000000000000..17bd6760938dab7fd702a71205867acce23c102e
--- /dev/null
+++ b/src/test/unittest/ut_signal.c
@@ -0,0 +1,52 @@
+/*
+ * Copyright (c) 2014, Intel Corporation
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ *     * Redistributions of source code must retain the above copyright
+ *       notice, this list of conditions and the following disclaimer.
+ *
+ *     * Redistributions in binary form must reproduce the above copyright
+ *       notice, this list of conditions and the following disclaimer in
+ *       the documentation and/or other materials provided with the
+ *       distribution.
+ *
+ *     * Neither the name of Intel Corporation nor the names of its
+ *       contributors may be used to endorse or promote products derived
+ *       from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+/*
+ * ut_signal.c -- unit test signal operations
+ */
+
+#include "unittest.h"
+
+/*
+ * ut_sigvec -- a sigvec that cannot return < 0
+ */
+int
+ut_sigvec(const char *file, int line, const char *func,
+		int sig, struct sigvec *vec, struct sigvec *ovec)
+{
+	int retval = sigvec(sig, vec, ovec);
+
+	if (retval != 0)
+		ut_fatal(file, line, func, "!sigvec: %s", strsignal(sig));
+
+	return retval;
+}
diff --git a/src/test/vmem_aligned_alloc/.gitignore b/src/test/vmem_aligned_alloc/.gitignore
new file mode 100644
index 0000000000000000000000000000000000000000..ab9ed3eb38a68804fa810055ea6025f4e7c7eb50
--- /dev/null
+++ b/src/test/vmem_aligned_alloc/.gitignore
@@ -0,0 +1 @@
+vmem_aligned_alloc
diff --git a/src/test/vmem_aligned_alloc/Makefile b/src/test/vmem_aligned_alloc/Makefile
new file mode 100644
index 0000000000000000000000000000000000000000..1ee8040946b9ed3276d4f99748063831cbd470fc
--- /dev/null
+++ b/src/test/vmem_aligned_alloc/Makefile
@@ -0,0 +1,45 @@
+#
+# Copyright (c) 2014, Intel Corporation
+#
+# Redistribution and use in source and binary forms, with or without
+# modification, are permitted provided that the following conditions
+# are met:
+#
+#     * Redistributions of source code must retain the above copyright
+#       notice, this list of conditions and the following disclaimer.
+#
+#     * Redistributions in binary form must reproduce the above copyright
+#       notice, this list of conditions and the following disclaimer in
+#       the documentation and/or other materials provided with the
+#       distribution.
+#
+#     * Neither the name of Intel Corporation nor the names of its
+#       contributors may be used to endorse or promote products derived
+#       from this software without specific prior written permission.
+#
+# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+#
+
+#
+# src/test/vmem_aligned_alloc/Makefile -- build vmem_aligned_alloc unit test
+#
+TARGET = vmem_aligned_alloc
+OBJS = vmem_aligned_alloc.o
+
+include ../Makefile.inc
+STATIC_DEBUG_LIBS = ../unittest/libut.a ../../debug/libvmem.a -luuid -pthread
+STATIC_NONDEBUG_LIBS = ../unittest/libut.a ../../nondebug/libvmem.a -luuid -pthread
+
+LIBS += -lvmem
+
+vmem_aligned_alloc.o: vmem_aligned_alloc.c
diff --git a/src/test/vmem_aligned_alloc/TEST0 b/src/test/vmem_aligned_alloc/TEST0
new file mode 100755
index 0000000000000000000000000000000000000000..624b7f4bd1d6061d691561c019d059cd2cc96ed8
--- /dev/null
+++ b/src/test/vmem_aligned_alloc/TEST0
@@ -0,0 +1,51 @@
+#!/bin/bash -e
+#
+# Copyright (c) 2014, Intel Corporation
+#
+# Redistribution and use in source and binary forms, with or without
+# modification, are permitted provided that the following conditions
+# are met:
+#
+#     * Redistributions of source code must retain the above copyright
+#       notice, this list of conditions and the following disclaimer.
+#
+#     * Redistributions in binary form must reproduce the above copyright
+#       notice, this list of conditions and the following disclaimer in
+#       the documentation and/or other materials provided with the
+#       distribution.
+#
+#     * Neither the name of Intel Corporation nor the names of its
+#       contributors may be used to endorse or promote products derived
+#       from this software without specific prior written permission.
+#
+# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+#
+
+#
+# src/test/vmem_aligned_alloc/TEST0 -- unit test for vmem_aligned_alloc
+#
+export UNITTEST_NAME=vmem_aligned_alloc/TEST0
+export UNITTEST_NUM=0
+
+# standard unit test setup
+. ../unittest/unittest.sh
+
+require_fs_type local
+
+setup
+
+expect_normal_exit ./vmem_aligned_alloc$EXESUFFIX
+
+check
+
+pass
diff --git a/src/test/vmem_aligned_alloc/TEST1 b/src/test/vmem_aligned_alloc/TEST1
new file mode 100755
index 0000000000000000000000000000000000000000..f889608228c6a95ebd340d063133daca46f0d0bc
--- /dev/null
+++ b/src/test/vmem_aligned_alloc/TEST1
@@ -0,0 +1,51 @@
+#!/bin/bash -e
+#
+# Copyright (c) 2014, Intel Corporation
+#
+# Redistribution and use in source and binary forms, with or without
+# modification, are permitted provided that the following conditions
+# are met:
+#
+#     * Redistributions of source code must retain the above copyright
+#       notice, this list of conditions and the following disclaimer.
+#
+#     * Redistributions in binary form must reproduce the above copyright
+#       notice, this list of conditions and the following disclaimer in
+#       the documentation and/or other materials provided with the
+#       distribution.
+#
+#     * Neither the name of Intel Corporation nor the names of its
+#       contributors may be used to endorse or promote products derived
+#       from this software without specific prior written permission.
+#
+# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+#
+
+#
+# src/test/vmem_aligned_alloc/TEST1 -- unit test for vmem_aligned_alloc
+#
+export UNITTEST_NAME=vmem_aligned_alloc/TEST1
+export UNITTEST_NUM=1
+
+# standard unit test setup
+. ../unittest/unittest.sh
+
+require_fs_type pmem
+
+setup
+
+expect_normal_exit ./vmem_aligned_alloc$EXESUFFIX $DIR
+
+check
+
+pass
diff --git a/src/test/vmem_aligned_alloc/err0.log.match b/src/test/vmem_aligned_alloc/err0.log.match
new file mode 100644
index 0000000000000000000000000000000000000000..e69de29bb2d1d6434b8b29ae775ad8c2e48c5391
diff --git a/src/test/vmem_aligned_alloc/err1.log.match b/src/test/vmem_aligned_alloc/err1.log.match
new file mode 100644
index 0000000000000000000000000000000000000000..e69de29bb2d1d6434b8b29ae775ad8c2e48c5391
diff --git a/src/test/vmem_aligned_alloc/out0.log.match b/src/test/vmem_aligned_alloc/out0.log.match
new file mode 100644
index 0000000000000000000000000000000000000000..e329d2e1e40a66ff5c5fa6301e6f947d083afaab
--- /dev/null
+++ b/src/test/vmem_aligned_alloc/out0.log.match
@@ -0,0 +1,3 @@
+vmem_aligned_alloc/TEST0: START: vmem_aligned_alloc
+ ./vmem_aligned_alloc$(*)
+vmem_aligned_alloc/TEST0: Done
diff --git a/src/test/vmem_aligned_alloc/out1.log.match b/src/test/vmem_aligned_alloc/out1.log.match
new file mode 100644
index 0000000000000000000000000000000000000000..a994d1c2a5940d3572f9d198c3baccb4e3fc1a07
--- /dev/null
+++ b/src/test/vmem_aligned_alloc/out1.log.match
@@ -0,0 +1,3 @@
+vmem_aligned_alloc/TEST1: START: vmem_aligned_alloc
+ ./vmem_aligned_alloc$(*)
+vmem_aligned_alloc/TEST1: Done
diff --git a/src/test/vmem_aligned_alloc/vmem_aligned_alloc.c b/src/test/vmem_aligned_alloc/vmem_aligned_alloc.c
new file mode 100644
index 0000000000000000000000000000000000000000..275f18c9575400e1caa620bf9e12b10a434939c2
--- /dev/null
+++ b/src/test/vmem_aligned_alloc/vmem_aligned_alloc.c
@@ -0,0 +1,171 @@
+/*
+ * Copyright (c) 2014, Intel Corporation
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ *     * Redistributions of source code must retain the above copyright
+ *       notice, this list of conditions and the following disclaimer.
+ *
+ *     * Redistributions in binary form must reproduce the above copyright
+ *       notice, this list of conditions and the following disclaimer in
+ *       the documentation and/or other materials provided with the
+ *       distribution.
+ *
+ *     * Neither the name of Intel Corporation nor the names of its
+ *       contributors may be used to endorse or promote products derived
+ *       from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+/*
+ * vmem_aligned_alloc.c -- unit test for vmem_aligned_alloc
+ *
+ * usage: vmem_aligned_alloc [directory]
+ */
+
+#include "unittest.h"
+
+#define	MAX_ALLOCS (100)
+
+static char mem_pool[VMEM_MIN_POOL];
+
+
+static int custom_allocs;
+static int custom_alloc_calls;
+
+/*
+ * malloc_custom -- custom malloc function
+ *
+ * This function updates statistics about custom alloc functions,
+ * and returns allocated memory.
+ */
+void *
+malloc_custom(size_t size)
+{
+	++custom_alloc_calls;
+	++custom_allocs;
+	return malloc(size);
+}
+
+/*
+ * free_custom -- custom free function
+ *
+ * This function updates statistics about custom alloc functions,
+ * and frees allocated memory.
+ */
+void
+free_custom(void *ptr)
+{
+	++custom_alloc_calls;
+	--custom_allocs;
+	free(ptr);
+}
+
+/*
+ * realloc_custom -- custom realloc function
+ *
+ * This function updates statistics about custom alloc functions,
+ * and returns reallocated memory.
+ */
+void *
+realloc_custom(void *ptr, size_t size)
+{
+	++custom_alloc_calls;
+	return realloc(ptr, size);
+}
+
+/*
+ * strdup_custom -- custom strdup function
+ *
+ * This function updates statistics about custom alloc functions,
+ * and returns allocated memory with a duplicated string.
+ */
+char *
+strdup_custom(const char *s)
+{
+	++custom_alloc_calls;
+	++custom_allocs;
+	return strdup(s);
+}
+
+int
+main(int argc, char *argv[])
+{
+	const int test_value = 123456;
+	char *dir = NULL;
+	VMEM *vmp;
+	size_t alignment;
+	unsigned i;
+	int *ptr;
+
+	START(argc, argv, "vmem_aligned_alloc");
+
+	if (argc == 2) {
+		dir = argv[1];
+	} else if (argc > 2) {
+		FATAL("usage: %s [directory]", argv[0]);
+	}
+
+	/* use custom alloc functions to check for memory leaks */
+	vmem_set_funcs(malloc_custom, free_custom,
+		realloc_custom, strdup_custom, NULL);
+
+	/* test with address alignment from 2B to 4MB */
+	for (alignment = 2; alignment <= 4 * 1024 * 1024; alignment *= 2) {
+
+		custom_alloc_calls = 0;
+		if (dir == NULL) {
+			vmp = vmem_pool_create_in_region(mem_pool,
+				VMEM_MIN_POOL);
+			if (vmp == NULL)
+				FATAL("!vmem_pool_create_in_region");
+		} else {
+			vmp = vmem_pool_create(dir, VMEM_MIN_POOL);
+			if (vmp == NULL)
+				FATAL("!vmem_pool_create");
+		}
+
+		for (i = 0; i < MAX_ALLOCS; ++i) {
+			ptr = vmem_aligned_alloc(vmp, alignment, sizeof (int));
+
+			/* at least one allocation must succeed */
+			ASSERT(i != 0 || ptr != NULL);
+			if (ptr == NULL)
+				break;
+
+			/* ptr should be usable */
+			*ptr = test_value;
+			ASSERTeq(*ptr, test_value);
+
+			/* check for correct address alignment */
+			ASSERTeq((uintptr_t)(ptr) & (alignment - 1), 0);
+
+			/* check that pointer came from mem_pool */
+			if (dir == NULL) {
+				ASSERTrange(ptr, mem_pool, VMEM_MIN_POOL);
+			}
+		}
+
+		vmem_pool_delete(vmp);
+
+		/* check memory leaks */
+		ASSERTne(custom_alloc_calls, 0);
+		ASSERTeq(custom_allocs, 0);
+	}
+
+
+	DONE(NULL);
+}
diff --git a/src/test/vmem_calloc/.gitignore b/src/test/vmem_calloc/.gitignore
new file mode 100644
index 0000000000000000000000000000000000000000..47e8c1e79502e11f75c603632622cd0b54dd6202
--- /dev/null
+++ b/src/test/vmem_calloc/.gitignore
@@ -0,0 +1 @@
+vmem_calloc
diff --git a/src/test/vmem_calloc/Makefile b/src/test/vmem_calloc/Makefile
new file mode 100644
index 0000000000000000000000000000000000000000..93649ed8c9273c9d1fe7473d96f7f8efbb984f93
--- /dev/null
+++ b/src/test/vmem_calloc/Makefile
@@ -0,0 +1,45 @@
+#
+# Copyright (c) 2014, Intel Corporation
+#
+# Redistribution and use in source and binary forms, with or without
+# modification, are permitted provided that the following conditions
+# are met:
+#
+#     * Redistributions of source code must retain the above copyright
+#       notice, this list of conditions and the following disclaimer.
+#
+#     * Redistributions in binary form must reproduce the above copyright
+#       notice, this list of conditions and the following disclaimer in
+#       the documentation and/or other materials provided with the
+#       distribution.
+#
+#     * Neither the name of Intel Corporation nor the names of its
+#       contributors may be used to endorse or promote products derived
+#       from this software without specific prior written permission.
+#
+# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+#
+
+#
+# src/test/vmem_calloc/Makefile -- build vmem_calloc unit test
+#
+TARGET = vmem_calloc
+OBJS = vmem_calloc.o
+
+include ../Makefile.inc
+STATIC_DEBUG_LIBS = ../unittest/libut.a ../../debug/libvmem.a -luuid -pthread
+STATIC_NONDEBUG_LIBS = ../unittest/libut.a ../../nondebug/libvmem.a -luuid -pthread
+
+LIBS += -lvmem
+
+vmem_calloc.o: vmem_calloc.c
diff --git a/src/test/vmem_calloc/TEST0 b/src/test/vmem_calloc/TEST0
new file mode 100755
index 0000000000000000000000000000000000000000..a4ae3510853f48e58889815161fbb958bbff318c
--- /dev/null
+++ b/src/test/vmem_calloc/TEST0
@@ -0,0 +1,51 @@
+#!/bin/bash -e
+#
+# Copyright (c) 2014, Intel Corporation
+#
+# Redistribution and use in source and binary forms, with or without
+# modification, are permitted provided that the following conditions
+# are met:
+#
+#     * Redistributions of source code must retain the above copyright
+#       notice, this list of conditions and the following disclaimer.
+#
+#     * Redistributions in binary form must reproduce the above copyright
+#       notice, this list of conditions and the following disclaimer in
+#       the documentation and/or other materials provided with the
+#       distribution.
+#
+#     * Neither the name of Intel Corporation nor the names of its
+#       contributors may be used to endorse or promote products derived
+#       from this software without specific prior written permission.
+#
+# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+#
+
+#
+# src/test/vmem_calloc/TEST0 -- unit test for vmem_calloc
+#
+export UNITTEST_NAME=vmem_calloc/TEST0
+export UNITTEST_NUM=0
+
+# standard unit test setup
+. ../unittest/unittest.sh
+
+require_fs_type local
+
+setup
+
+expect_normal_exit ./vmem_calloc$EXESUFFIX
+
+check
+
+pass
diff --git a/src/test/vmem_calloc/TEST1 b/src/test/vmem_calloc/TEST1
new file mode 100755
index 0000000000000000000000000000000000000000..5e5a420cc84ba5564cd7e7d98727ad4bb2ffe358
--- /dev/null
+++ b/src/test/vmem_calloc/TEST1
@@ -0,0 +1,51 @@
+#!/bin/bash -e
+#
+# Copyright (c) 2014, Intel Corporation
+#
+# Redistribution and use in source and binary forms, with or without
+# modification, are permitted provided that the following conditions
+# are met:
+#
+#     * Redistributions of source code must retain the above copyright
+#       notice, this list of conditions and the following disclaimer.
+#
+#     * Redistributions in binary form must reproduce the above copyright
+#       notice, this list of conditions and the following disclaimer in
+#       the documentation and/or other materials provided with the
+#       distribution.
+#
+#     * Neither the name of Intel Corporation nor the names of its
+#       contributors may be used to endorse or promote products derived
+#       from this software without specific prior written permission.
+#
+# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+#
+
+#
+# src/test/vmem_calloc/TEST1 -- unit test for vmem_calloc
+#
+export UNITTEST_NAME=vmem_calloc/TEST1
+export UNITTEST_NUM=1
+
+# standard unit test setup
+. ../unittest/unittest.sh
+
+require_fs_type pmem
+
+setup
+
+expect_normal_exit ./vmem_calloc$EXESUFFIX $DIR
+
+check
+
+pass
diff --git a/src/test/vmem_calloc/err0.log.match b/src/test/vmem_calloc/err0.log.match
new file mode 100644
index 0000000000000000000000000000000000000000..e69de29bb2d1d6434b8b29ae775ad8c2e48c5391
diff --git a/src/test/vmem_calloc/err1.log.match b/src/test/vmem_calloc/err1.log.match
new file mode 100644
index 0000000000000000000000000000000000000000..e69de29bb2d1d6434b8b29ae775ad8c2e48c5391
diff --git a/src/test/vmem_calloc/out0.log.match b/src/test/vmem_calloc/out0.log.match
new file mode 100644
index 0000000000000000000000000000000000000000..fdb4c562f05bf135ff0c04ace83b3849fa246c02
--- /dev/null
+++ b/src/test/vmem_calloc/out0.log.match
@@ -0,0 +1,3 @@
+vmem_calloc/TEST0: START: vmem_calloc
+ ./vmem_calloc$(*)
+vmem_calloc/TEST0: Done
diff --git a/src/test/vmem_calloc/out1.log.match b/src/test/vmem_calloc/out1.log.match
new file mode 100644
index 0000000000000000000000000000000000000000..e09228590c8e5bf7433849ebeac11832db5cb7be
--- /dev/null
+++ b/src/test/vmem_calloc/out1.log.match
@@ -0,0 +1,3 @@
+vmem_calloc/TEST1: START: vmem_calloc
+ ./vmem_calloc$(*)
+vmem_calloc/TEST1: Done
diff --git a/src/test/vmem_calloc/vmem_calloc.c b/src/test/vmem_calloc/vmem_calloc.c
new file mode 100644
index 0000000000000000000000000000000000000000..36eff308a89266a360b164446b8e93ec3894dbe0
--- /dev/null
+++ b/src/test/vmem_calloc/vmem_calloc.c
@@ -0,0 +1,87 @@
+/*
+ * Copyright (c) 2014, Intel Corporation
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ *     * Redistributions of source code must retain the above copyright
+ *       notice, this list of conditions and the following disclaimer.
+ *
+ *     * Redistributions in binary form must reproduce the above copyright
+ *       notice, this list of conditions and the following disclaimer in
+ *       the documentation and/or other materials provided with the
+ *       distribution.
+ *
+ *     * Neither the name of Intel Corporation nor the names of its
+ *       contributors may be used to endorse or promote products derived
+ *       from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+/*
+ * vmem_calloc.c -- unit test for vmem_calloc
+ *
+ * usage: vmem_calloc [directory]
+ */
+
+#include "unittest.h"
+
+static char mem_pool[VMEM_MIN_POOL];
+
+int
+main(int argc, char *argv[])
+{
+	const int test_value = 123456;
+	char *dir = NULL;
+	VMEM *vmp;
+
+	START(argc, argv, "vmem_calloc");
+
+	if (argc == 2) {
+		dir = argv[1];
+	} else if (argc > 2) {
+		FATAL("usage: %s [directory]", argv[0]);
+	}
+
+	if (dir == NULL) {
+		vmp = vmem_pool_create_in_region(mem_pool, VMEM_MIN_POOL);
+		if (vmp == NULL)
+			FATAL("!vmem_pool_create_in_region");
+	} else {
+		vmp = vmem_pool_create(dir, VMEM_MIN_POOL);
+		if (vmp == NULL)
+			FATAL("!vmem_pool_create");
+	}
+
+	int *test = vmem_calloc(vmp, 1, sizeof (int));
+	ASSERTne(test, NULL);
+
+	/* pool_calloc should return zeroed memory */
+	ASSERTeq(*test, 0);
+
+	*test = test_value;
+	ASSERTeq(*test, test_value);
+
+	/* check that pointer came from mem_pool */
+	if (dir == NULL) {
+		ASSERTrange(test, mem_pool, VMEM_MIN_POOL);
+	}
+
+	vmem_free(vmp, test);
+
+	vmem_pool_delete(vmp);
+
+	DONE(NULL);
+}
diff --git a/src/test/vmem_check_allocations/.gitignore b/src/test/vmem_check_allocations/.gitignore
new file mode 100644
index 0000000000000000000000000000000000000000..aded80d9167adf30b5239e231515537de4757e05
--- /dev/null
+++ b/src/test/vmem_check_allocations/.gitignore
@@ -0,0 +1 @@
+vmem_check_allocations
diff --git a/src/test/vmem_check_allocations/Makefile b/src/test/vmem_check_allocations/Makefile
new file mode 100644
index 0000000000000000000000000000000000000000..18149fdba1d9f098ee28f58080645e89f6fad778
--- /dev/null
+++ b/src/test/vmem_check_allocations/Makefile
@@ -0,0 +1,45 @@
+#
+# Copyright (c) 2014, Intel Corporation
+#
+# Redistribution and use in source and binary forms, with or without
+# modification, are permitted provided that the following conditions
+# are met:
+#
+#     * Redistributions of source code must retain the above copyright
+#       notice, this list of conditions and the following disclaimer.
+#
+#     * Redistributions in binary form must reproduce the above copyright
+#       notice, this list of conditions and the following disclaimer in
+#       the documentation and/or other materials provided with the
+#       distribution.
+#
+#     * Neither the name of Intel Corporation nor the names of its
+#       contributors may be used to endorse or promote products derived
+#       from this software without specific prior written permission.
+#
+# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+#
+
+#
+# src/test/vmem_check_allocations/Makefile -- build vmem_check_allocations unit test
+#
+TARGET = vmem_check_allocations
+OBJS = vmem_check_allocations.o
+
+include ../Makefile.inc
+STATIC_DEBUG_LIBS = ../unittest/libut.a ../../debug/libvmem.a -luuid -pthread
+STATIC_NONDEBUG_LIBS = ../unittest/libut.a ../../nondebug/libvmem.a -luuid -pthread
+
+LIBS += -lvmem
+
+vmem_check_allocations.o: vmem_check_allocations.c
diff --git a/src/test/vmem_check_allocations/TEST0 b/src/test/vmem_check_allocations/TEST0
new file mode 100755
index 0000000000000000000000000000000000000000..160ac93ec0b910824efecc91eb6f62ac0c524f61
--- /dev/null
+++ b/src/test/vmem_check_allocations/TEST0
@@ -0,0 +1,55 @@
+#!/bin/bash -e
+#
+# Copyright (c) 2014, Intel Corporation
+#
+# Redistribution and use in source and binary forms, with or without
+# modification, are permitted provided that the following conditions
+# are met:
+#
+#     * Redistributions of source code must retain the above copyright
+#       notice, this list of conditions and the following disclaimer.
+#
+#     * Redistributions in binary form must reproduce the above copyright
+#       notice, this list of conditions and the following disclaimer in
+#       the documentation and/or other materials provided with the
+#       distribution.
+#
+#     * Neither the name of Intel Corporation nor the names of its
+#       contributors may be used to endorse or promote products derived
+#       from this software without specific prior written permission.
+#
+# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+#
+
+#
+# src/test/vmem_check_allocations/TEST0 -- unit test for vmem_check_allocations
+#
+export UNITTEST_NAME=vmem_check_allocations/TEST0
+export UNITTEST_NUM=0
+
+# standard unit test setup
+. ../unittest/unittest.sh
+
+require_fs_type local
+require_build_type debug nondebug
+
+setup
+
+#limit output for file vmem*.log to reduce time of execution test
+export VMEM_LOG_LEVEL=2
+
+expect_normal_exit ./vmem_check_allocations$EXESUFFIX
+
+check
+
+pass
diff --git a/src/test/vmem_check_allocations/TEST1 b/src/test/vmem_check_allocations/TEST1
new file mode 100755
index 0000000000000000000000000000000000000000..e92f6056409082600503b0af2905720de4a640ea
--- /dev/null
+++ b/src/test/vmem_check_allocations/TEST1
@@ -0,0 +1,55 @@
+#!/bin/bash -e
+#
+# Copyright (c) 2014, Intel Corporation
+#
+# Redistribution and use in source and binary forms, with or without
+# modification, are permitted provided that the following conditions
+# are met:
+#
+#     * Redistributions of source code must retain the above copyright
+#       notice, this list of conditions and the following disclaimer.
+#
+#     * Redistributions in binary form must reproduce the above copyright
+#       notice, this list of conditions and the following disclaimer in
+#       the documentation and/or other materials provided with the
+#       distribution.
+#
+#     * Neither the name of Intel Corporation nor the names of its
+#       contributors may be used to endorse or promote products derived
+#       from this software without specific prior written permission.
+#
+# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+#
+
+#
+# src/test/vmem_check_allocations/TEST1 -- unit test for vmem_check_allocations
+#
+export UNITTEST_NAME=vmem_check_allocations/TEST1
+export UNITTEST_NUM=1
+
+# standard unit test setup
+. ../unittest/unittest.sh
+
+require_fs_type pmem
+require_build_type debug nondebug
+
+setup
+
+#limit output for file vmem*.log to reduce time of test execution
+export VMEM_LOG_LEVEL=2
+
+expect_normal_exit ./vmem_check_allocations$EXESUFFIX $DIR
+
+check
+
+pass
diff --git a/src/test/vmem_check_allocations/err0.log.match b/src/test/vmem_check_allocations/err0.log.match
new file mode 100644
index 0000000000000000000000000000000000000000..e69de29bb2d1d6434b8b29ae775ad8c2e48c5391
diff --git a/src/test/vmem_check_allocations/err1.log.match b/src/test/vmem_check_allocations/err1.log.match
new file mode 100644
index 0000000000000000000000000000000000000000..e69de29bb2d1d6434b8b29ae775ad8c2e48c5391
diff --git a/src/test/vmem_check_allocations/out0.log.match b/src/test/vmem_check_allocations/out0.log.match
new file mode 100644
index 0000000000000000000000000000000000000000..53e996178da4c6e35d7f9be75c9a3480143dfb35
--- /dev/null
+++ b/src/test/vmem_check_allocations/out0.log.match
@@ -0,0 +1,3 @@
+vmem_check_allocations/TEST0: START: vmem_check_allocations
+ ./vmem_check_allocations$(*)
+vmem_check_allocations/TEST0: Done
diff --git a/src/test/vmem_check_allocations/out1.log.match b/src/test/vmem_check_allocations/out1.log.match
new file mode 100644
index 0000000000000000000000000000000000000000..a81b41e2e38cc9f67b9ed36b2778b9c9a7896617
--- /dev/null
+++ b/src/test/vmem_check_allocations/out1.log.match
@@ -0,0 +1,3 @@
+vmem_check_allocations/TEST1: START: vmem_check_allocations
+ ./vmem_check_allocations$(*)
+vmem_check_allocations/TEST1: Done
diff --git a/src/test/vmem_check_allocations/vmem_check_allocations.c b/src/test/vmem_check_allocations/vmem_check_allocations.c
new file mode 100644
index 0000000000000000000000000000000000000000..d9168a98d3e2fb375642923be0e57a6f3d933c3a
--- /dev/null
+++ b/src/test/vmem_check_allocations/vmem_check_allocations.c
@@ -0,0 +1,117 @@
+/*
+ * Copyright (c) 2014, Intel Corporation
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ *     * Redistributions of source code must retain the above copyright
+ *       notice, this list of conditions and the following disclaimer.
+ *
+ *     * Redistributions in binary form must reproduce the above copyright
+ *       notice, this list of conditions and the following disclaimer in
+ *       the documentation and/or other materials provided with the
+ *       distribution.
+ *
+ *     * Neither the name of Intel Corporation nor the names of its
+ *       contributors may be used to endorse or promote products derived
+ *       from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+/*
+ * vmem_check_allocations -- unit test for vmem_check_allocations
+ *
+ * usage: vmem_check_allocations [directory]
+ */
+
+#include "unittest.h"
+
+#define	TEST_MAX_ALLOCATION_SIZE (4L * 1024L * 1024L)
+#define	TEST_ALLOCS_SIZE (VMEM_MIN_POOL / 8)
+
+static char mem_pool[VMEM_MIN_POOL];
+
+/* buffer for all allocations */
+static void *allocs[TEST_ALLOCS_SIZE];
+
+int
+main(int argc, char *argv[])
+{
+	char *dir = NULL;
+	VMEM *vmp;
+
+	START(argc, argv, "vmem_check_allocations");
+
+	if (argc == 2) {
+		dir = argv[1];
+	} else if (argc > 2) {
+		FATAL("usage: %s [directory]", argv[0]);
+	}
+
+	size_t object_size;
+	for (object_size = 8; object_size <= TEST_MAX_ALLOCATION_SIZE;
+							object_size *= 2) {
+		size_t i;
+		size_t j;
+
+		if (dir == NULL) {
+			vmp = vmem_pool_create_in_region(mem_pool,
+				VMEM_MIN_POOL);
+			if (vmp == NULL)
+				FATAL("!vmem_pool_create_in_region");
+		} else {
+			vmp = vmem_pool_create(dir, VMEM_MIN_POOL);
+			if (vmp == NULL)
+				FATAL("!vmem_pool_create");
+		}
+
+		memset(allocs, 0, TEST_ALLOCS_SIZE);
+
+		for (i = 0; i < TEST_ALLOCS_SIZE; ++i) {
+			allocs[i] =  vmem_malloc(vmp, object_size);
+			if (allocs[i] == NULL) {
+				/* out of memory in pool */
+				break;
+			}
+
+			/* check that pointer came from mem_pool */
+			if (dir == NULL) {
+				ASSERTrange(allocs[i],
+					mem_pool, VMEM_MIN_POOL);
+			}
+
+			/* fill each allocation with a unique value */
+			memset(allocs[i], (char)i, object_size);
+		}
+
+		ASSERT((i > 0) && (i + 1 < TEST_MAX_ALLOCATION_SIZE));
+
+		/* check for unexpected modifications of the data */
+		for (i = 0; i < TEST_ALLOCS_SIZE && allocs[i] != NULL; ++i) {
+			char *buffer = allocs[i];
+			for (j = 0; j < object_size; ++j) {
+				if (buffer[j] != (char)i)
+					FATAL("Content of data object was "
+						"modified unexpectedly for "
+						"object size: %zu, id: %zu",
+						object_size, j);
+			}
+		}
+
+		vmem_pool_delete(vmp);
+	}
+
+	DONE(NULL);
+}
diff --git a/src/test/vmem_check_version/.gitignore b/src/test/vmem_check_version/.gitignore
new file mode 100644
index 0000000000000000000000000000000000000000..374742a23fec7196300b8695d42120d0ea27cbf2
--- /dev/null
+++ b/src/test/vmem_check_version/.gitignore
@@ -0,0 +1 @@
+vmem_check_version
diff --git a/src/test/vmem_check_version/Makefile b/src/test/vmem_check_version/Makefile
new file mode 100644
index 0000000000000000000000000000000000000000..4ea13af9d1a7a288489a0595d38b7dab596eb36c
--- /dev/null
+++ b/src/test/vmem_check_version/Makefile
@@ -0,0 +1,45 @@
+#
+# Copyright (c) 2014, Intel Corporation
+#
+# Redistribution and use in source and binary forms, with or without
+# modification, are permitted provided that the following conditions
+# are met:
+#
+#     * Redistributions of source code must retain the above copyright
+#       notice, this list of conditions and the following disclaimer.
+#
+#     * Redistributions in binary form must reproduce the above copyright
+#       notice, this list of conditions and the following disclaimer in
+#       the documentation and/or other materials provided with the
+#       distribution.
+#
+#     * Neither the name of Intel Corporation nor the names of its
+#       contributors may be used to endorse or promote products derived
+#       from this software without specific prior written permission.
+#
+# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+#
+
+#
+# src/test/vmem_check_version/Makefile -- build vmem_check_version unit test
+#
+TARGET = vmem_check_version
+OBJS = vmem_check_version.o
+
+include ../Makefile.inc
+STATIC_DEBUG_LIBS = ../unittest/libut.a ../../debug/libvmem.a -luuid -pthread
+STATIC_NONDEBUG_LIBS = ../unittest/libut.a ../../nondebug/libvmem.a -luuid -pthread
+
+LIBS += -lvmem
+
+vmem_check_version.o: vmem_check_version.c
diff --git a/src/test/vmem_check_version/TEST0 b/src/test/vmem_check_version/TEST0
new file mode 100755
index 0000000000000000000000000000000000000000..4fa99851899260b192dbf78999b06b67b4c0ea59
--- /dev/null
+++ b/src/test/vmem_check_version/TEST0
@@ -0,0 +1,51 @@
+#!/bin/bash -e
+#
+# Copyright (c) 2014, Intel Corporation
+#
+# Redistribution and use in source and binary forms, with or without
+# modification, are permitted provided that the following conditions
+# are met:
+#
+#     * Redistributions of source code must retain the above copyright
+#       notice, this list of conditions and the following disclaimer.
+#
+#     * Redistributions in binary form must reproduce the above copyright
+#       notice, this list of conditions and the following disclaimer in
+#       the documentation and/or other materials provided with the
+#       distribution.
+#
+#     * Neither the name of Intel Corporation nor the names of its
+#       contributors may be used to endorse or promote products derived
+#       from this software without specific prior written permission.
+#
+# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+#
+
+#
+# src/test/vmem_check_version/TEST0 -- unit test for vmem_check_version
+#
+export UNITTEST_NAME=vmem_check_version/TEST0
+export UNITTEST_NUM=0
+
+# standard unit test setup
+. ../unittest/unittest.sh
+
+require_fs_type local
+
+setup
+
+expect_normal_exit ./vmem_check_version$EXESUFFIX
+
+check
+
+pass
diff --git a/src/test/vmem_check_version/out0.log.match b/src/test/vmem_check_version/out0.log.match
new file mode 100644
index 0000000000000000000000000000000000000000..b39e92bb37fde329c5902983055176e0ef5788f5
--- /dev/null
+++ b/src/test/vmem_check_version/out0.log.match
@@ -0,0 +1,5 @@
+vmem_check_version/TEST0: START: vmem_check_version
+ ./vmem_check_version$(*)
+compile-time libvmem version is 1.0
+for major version 2, vmem_check_version returned: libvmem major version mismatch (need 2, found 1)
+vmem_check_version/TEST0: Done
diff --git a/src/test/vmem_check_version/vmem_check_version.c b/src/test/vmem_check_version/vmem_check_version.c
new file mode 100644
index 0000000000000000000000000000000000000000..b2054304c353be4bb6b0cb62fde61125f2166c54
--- /dev/null
+++ b/src/test/vmem_check_version/vmem_check_version.c
@@ -0,0 +1,60 @@
+/*
+ * Copyright (c) 2014, Intel Corporation
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ *     * Redistributions of source code must retain the above copyright
+ *       notice, this list of conditions and the following disclaimer.
+ *
+ *     * Redistributions in binary form must reproduce the above copyright
+ *       notice, this list of conditions and the following disclaimer in
+ *       the documentation and/or other materials provided with the
+ *       distribution.
+ *
+ *     * Neither the name of Intel Corporation nor the names of its
+ *       contributors may be used to endorse or promote products derived
+ *       from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+/*
+ * vmem_check_version.c -- unit test for vmem_check_version
+ */
+
+#include "unittest.h"
+
+int
+main(int argc, char *argv[])
+{
+	START(argc, argv, "vmem_check_version");
+
+	OUT("compile-time libvmem version is %d.%d",
+			VMEM_MAJOR_VERSION, VMEM_MINOR_VERSION);
+
+	const char *errstr = vmem_check_version(VMEM_MAJOR_VERSION,
+			VMEM_MINOR_VERSION);
+
+	ASSERTinfo(errstr == NULL, errstr);
+
+	errstr = vmem_check_version(VMEM_MAJOR_VERSION + 1, VMEM_MINOR_VERSION);
+
+	ASSERT(errstr != NULL);
+
+	OUT("for major version %d, vmem_check_version returned: %s",
+			VMEM_MAJOR_VERSION + 1, errstr);
+
+	DONE(NULL);
+}
diff --git a/src/test/vmem_custom_alloc/.gitignore b/src/test/vmem_custom_alloc/.gitignore
new file mode 100644
index 0000000000000000000000000000000000000000..fd421c1c7cde54e8ec9aa4a4bc813d8e17a195d9
--- /dev/null
+++ b/src/test/vmem_custom_alloc/.gitignore
@@ -0,0 +1 @@
+vmem_custom_alloc
diff --git a/src/test/vmem_custom_alloc/Makefile b/src/test/vmem_custom_alloc/Makefile
new file mode 100644
index 0000000000000000000000000000000000000000..f1617418b257a92cb45c6ab4c4fbd2ead6e700bc
--- /dev/null
+++ b/src/test/vmem_custom_alloc/Makefile
@@ -0,0 +1,45 @@
+#
+# Copyright (c) 2014, Intel Corporation
+#
+# Redistribution and use in source and binary forms, with or without
+# modification, are permitted provided that the following conditions
+# are met:
+#
+#     * Redistributions of source code must retain the above copyright
+#       notice, this list of conditions and the following disclaimer.
+#
+#     * Redistributions in binary form must reproduce the above copyright
+#       notice, this list of conditions and the following disclaimer in
+#       the documentation and/or other materials provided with the
+#       distribution.
+#
+#     * Neither the name of Intel Corporation nor the names of its
+#       contributors may be used to endorse or promote products derived
+#       from this software without specific prior written permission.
+#
+# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+#
+
+#
+# src/test/vmem_custom_alloc/Makefile -- build vmem_custom_alloc unit test
+#
+TARGET = vmem_custom_alloc
+OBJS = vmem_custom_alloc.o
+
+include ../Makefile.inc
+STATIC_DEBUG_LIBS = ../unittest/libut.a ../../debug/libvmem.a -luuid -pthread
+STATIC_NONDEBUG_LIBS = ../unittest/libut.a ../../nondebug/libvmem.a -luuid -pthread
+
+LIBS += -lvmem
+
+vmem_custom_alloc.o: vmem_custom_alloc.c
diff --git a/src/test/vmem_custom_alloc/TEST0 b/src/test/vmem_custom_alloc/TEST0
new file mode 100755
index 0000000000000000000000000000000000000000..9542a14560d9392085faa1210d432928db2c6cfb
--- /dev/null
+++ b/src/test/vmem_custom_alloc/TEST0
@@ -0,0 +1,49 @@
+#!/bin/bash -e
+#
+# Copyright (c) 2014, Intel Corporation
+#
+# Redistribution and use in source and binary forms, with or without
+# modification, are permitted provided that the following conditions
+# are met:
+#
+#     * Redistributions of source code must retain the above copyright
+#       notice, this list of conditions and the following disclaimer.
+#
+#     * Redistributions in binary form must reproduce the above copyright
+#       notice, this list of conditions and the following disclaimer in
+#       the documentation and/or other materials provided with the
+#       distribution.
+#
+#     * Neither the name of Intel Corporation nor the names of its
+#       contributors may be used to endorse or promote products derived
+#       from this software without specific prior written permission.
+#
+# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+#
+
+#
+# src/test/vmem_custom_alloc/TEST0 -- unit test for vmem_custom_alloc
+#
+export UNITTEST_NAME=vmem_custom_alloc/TEST0
+export UNITTEST_NUM=0
+
+# standard unit test setup
+. ../unittest/unittest.sh
+
+require_fs_type local
+
+setup
+
+expect_normal_exit ./vmem_custom_alloc$EXESUFFIX 0
+
+pass
diff --git a/src/test/vmem_custom_alloc/TEST1 b/src/test/vmem_custom_alloc/TEST1
new file mode 100755
index 0000000000000000000000000000000000000000..e09e463c8934af19ffa96f1a30bd2b5ce9915f02
--- /dev/null
+++ b/src/test/vmem_custom_alloc/TEST1
@@ -0,0 +1,49 @@
+#!/bin/bash -e
+#
+# Copyright (c) 2014, Intel Corporation
+#
+# Redistribution and use in source and binary forms, with or without
+# modification, are permitted provided that the following conditions
+# are met:
+#
+#     * Redistributions of source code must retain the above copyright
+#       notice, this list of conditions and the following disclaimer.
+#
+#     * Redistributions in binary form must reproduce the above copyright
+#       notice, this list of conditions and the following disclaimer in
+#       the documentation and/or other materials provided with the
+#       distribution.
+#
+#     * Neither the name of Intel Corporation nor the names of its
+#       contributors may be used to endorse or promote products derived
+#       from this software without specific prior written permission.
+#
+# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+#
+
+#
+# src/test/vmem_custom_alloc/TEST1 -- unit test for vmem_custom_alloc
+#
+export UNITTEST_NAME=vmem_custom_alloc/TEST1
+export UNITTEST_NUM=1
+
+# standard unit test setup
+. ../unittest/unittest.sh
+
+require_fs_type local
+
+setup
+
+expect_normal_exit ./vmem_custom_alloc$EXESUFFIX 1
+
+pass
diff --git a/src/test/vmem_custom_alloc/TEST2 b/src/test/vmem_custom_alloc/TEST2
new file mode 100755
index 0000000000000000000000000000000000000000..ccfc17e42feae2bfa25d0e49035b33af7aa5248f
--- /dev/null
+++ b/src/test/vmem_custom_alloc/TEST2
@@ -0,0 +1,49 @@
+#!/bin/bash -e
+#
+# Copyright (c) 2014, Intel Corporation
+#
+# Redistribution and use in source and binary forms, with or without
+# modification, are permitted provided that the following conditions
+# are met:
+#
+#     * Redistributions of source code must retain the above copyright
+#       notice, this list of conditions and the following disclaimer.
+#
+#     * Redistributions in binary form must reproduce the above copyright
+#       notice, this list of conditions and the following disclaimer in
+#       the documentation and/or other materials provided with the
+#       distribution.
+#
+#     * Neither the name of Intel Corporation nor the names of its
+#       contributors may be used to endorse or promote products derived
+#       from this software without specific prior written permission.
+#
+# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+#
+
+#
+# src/test/vmem_custom_alloc/TEST2 -- unit test for vmem_custom_alloc
+#
+export UNITTEST_NAME=vmem_custom_alloc/TEST2
+export UNITTEST_NUM=2
+
+# standard unit test setup
+. ../unittest/unittest.sh
+
+require_fs_type local
+
+setup
+
+expect_normal_exit ./vmem_custom_alloc$EXESUFFIX 2
+
+pass
diff --git a/src/test/vmem_custom_alloc/TEST3 b/src/test/vmem_custom_alloc/TEST3
new file mode 100755
index 0000000000000000000000000000000000000000..af01239f266969050a972820c7154e49b3dc4d48
--- /dev/null
+++ b/src/test/vmem_custom_alloc/TEST3
@@ -0,0 +1,49 @@
+#!/bin/bash -e
+#
+# Copyright (c) 2014, Intel Corporation
+#
+# Redistribution and use in source and binary forms, with or without
+# modification, are permitted provided that the following conditions
+# are met:
+#
+#     * Redistributions of source code must retain the above copyright
+#       notice, this list of conditions and the following disclaimer.
+#
+#     * Redistributions in binary form must reproduce the above copyright
+#       notice, this list of conditions and the following disclaimer in
+#       the documentation and/or other materials provided with the
+#       distribution.
+#
+#     * Neither the name of Intel Corporation nor the names of its
+#       contributors may be used to endorse or promote products derived
+#       from this software without specific prior written permission.
+#
+# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+#
+
+#
+# src/test/vmem_custom_alloc/TEST3 -- unit test for vmem_custom_alloc
+#
+export UNITTEST_NAME=vmem_custom_alloc/TEST3
+export UNITTEST_NUM=3
+
+# standard unit test setup
+. ../unittest/unittest.sh
+
+require_fs_type local
+
+setup
+
+expect_normal_exit ./vmem_custom_alloc$EXESUFFIX 0 $DIR
+
+pass
diff --git a/src/test/vmem_custom_alloc/TEST4 b/src/test/vmem_custom_alloc/TEST4
new file mode 100755
index 0000000000000000000000000000000000000000..cabdb521368a8b0952da2309064a8a0d37a88f13
--- /dev/null
+++ b/src/test/vmem_custom_alloc/TEST4
@@ -0,0 +1,49 @@
+#!/bin/bash -e
+#
+# Copyright (c) 2014, Intel Corporation
+#
+# Redistribution and use in source and binary forms, with or without
+# modification, are permitted provided that the following conditions
+# are met:
+#
+#     * Redistributions of source code must retain the above copyright
+#       notice, this list of conditions and the following disclaimer.
+#
+#     * Redistributions in binary form must reproduce the above copyright
+#       notice, this list of conditions and the following disclaimer in
+#       the documentation and/or other materials provided with the
+#       distribution.
+#
+#     * Neither the name of Intel Corporation nor the names of its
+#       contributors may be used to endorse or promote products derived
+#       from this software without specific prior written permission.
+#
+# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+#
+
+#
+# src/test/vmem_custom_alloc/TEST4 -- unit test for vmem_custom_alloc
+#
+export UNITTEST_NAME=vmem_custom_alloc/TEST4
+export UNITTEST_NUM=4
+
+# standard unit test setup
+. ../unittest/unittest.sh
+
+require_fs_type local
+
+setup
+
+expect_normal_exit ./vmem_custom_alloc$EXESUFFIX 1 $DIR
+
+pass
diff --git a/src/test/vmem_custom_alloc/TEST5 b/src/test/vmem_custom_alloc/TEST5
new file mode 100755
index 0000000000000000000000000000000000000000..94a511fefadd0274b9652cc26f732e6688744084
--- /dev/null
+++ b/src/test/vmem_custom_alloc/TEST5
@@ -0,0 +1,49 @@
+#!/bin/bash -e
+#
+# Copyright (c) 2014, Intel Corporation
+#
+# Redistribution and use in source and binary forms, with or without
+# modification, are permitted provided that the following conditions
+# are met:
+#
+#     * Redistributions of source code must retain the above copyright
+#       notice, this list of conditions and the following disclaimer.
+#
+#     * Redistributions in binary form must reproduce the above copyright
+#       notice, this list of conditions and the following disclaimer in
+#       the documentation and/or other materials provided with the
+#       distribution.
+#
+#     * Neither the name of Intel Corporation nor the names of its
+#       contributors may be used to endorse or promote products derived
+#       from this software without specific prior written permission.
+#
+# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+#
+
+#
+# src/test/vmem_custom_alloc/TEST5 -- unit test for vmem_custom_alloc
+#
+export UNITTEST_NAME=vmem_custom_alloc/TEST5
+export UNITTEST_NUM=5
+
+# standard unit test setup
+. ../unittest/unittest.sh
+
+require_fs_type local
+
+setup
+
+expect_normal_exit ./vmem_custom_alloc$EXESUFFIX 2 $DIR
+
+pass
diff --git a/src/test/vmem_custom_alloc/vmem_custom_alloc.c b/src/test/vmem_custom_alloc/vmem_custom_alloc.c
new file mode 100644
index 0000000000000000000000000000000000000000..2ab5b44bda82287f81a5f88fdb7b13e57841dafc
--- /dev/null
+++ b/src/test/vmem_custom_alloc/vmem_custom_alloc.c
@@ -0,0 +1,217 @@
+/*
+ * Copyright (c) 2014, Intel Corporation
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ *     * Redistributions of source code must retain the above copyright
+ *       notice, this list of conditions and the following disclaimer.
+ *
+ *     * Redistributions in binary form must reproduce the above copyright
+ *       notice, this list of conditions and the following disclaimer in
+ *       the documentation and/or other materials provided with the
+ *       distribution.
+ *
+ *     * Neither the name of Intel Corporation nor the names of its
+ *       contributors may be used to endorse or promote products derived
+ *       from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+/*
+ * vmem_custom_alloc.c -- unit test for vmem_custom_alloc
+ *
+ * usage: vmem_custom_alloc (0-2) [directory]
+ */
+
+#include "unittest.h"
+
+#define	TEST_STRING_VALUE "Some test text, to check memory"
+#define	TEST_REPEAT_CREATE_POOLS (20)
+
+static char mem_pool[VMEM_MIN_POOL];
+
+static int custom_allocs;
+static int custom_alloc_calls;
+static int expect_create_pool;
+
+/*
+ * malloc_null -- custom malloc function with error
+ *
+ * This function updates statistics about custom alloc functions,
+ * and returns NULL.
+ */
+void *
+malloc_null(size_t size)
+{
+	++custom_alloc_calls;
+	return NULL;
+}
+
+/*
+ * malloc_custom -- custom malloc function
+ *
+ * This function updates statistics about custom alloc functions,
+ * and returns allocated memory.
+ */
+void *
+malloc_custom(size_t size)
+{
+	++custom_alloc_calls;
+	++custom_allocs;
+	return malloc(size);
+}
+
+/*
+ * free_custom -- custom free function
+ *
+ * This function updates statistics about custom alloc functions,
+ * and frees allocated memory.
+ */
+void
+free_custom(void *ptr)
+{
+	++custom_alloc_calls;
+	--custom_allocs;
+	free(ptr);
+}
+
+/*
+ * realloc_custom -- custom realloc function
+ *
+ * This function updates statistics about custom alloc functions,
+ * and returns reallocated memory.
+ */
+void *
+realloc_custom(void *ptr, size_t size)
+{
+	++custom_alloc_calls;
+	return realloc(ptr, size);
+}
+
+/*
+ * strdup_custom -- custom strdup function
+ *
+ * This function updates statistics about custom alloc functions,
+ * and returns allocated memory with a duplicated string.
+ */
+char *
+strdup_custom(const char *s)
+{
+	++custom_alloc_calls;
+	++custom_allocs;
+	return strdup(s);
+}
+
+/*
+ * pool_test -- test pool
+ *
+ * This function creates a memory pool in a file (if dir is not NULL),
+ * or in RAM (if dir is NULL) and allocates memory for the test.
+ */
+void
+pool_test(const char *dir)
+{
+	VMEM *vmp = NULL;
+
+	if (dir != NULL) {
+		vmp = vmem_pool_create(dir, VMEM_MIN_POOL);
+	} else {
+		vmp = vmem_pool_create_in_region(mem_pool, VMEM_MIN_POOL);
+	}
+
+	if (expect_create_pool == 0) {
+		ASSERTeq(vmp, NULL);
+		DONE(NULL);
+	} else {
+		if (vmp == NULL) {
+			if (dir == NULL) {
+				FATAL("!vmem_pool_create_in_region");
+			} else {
+				FATAL("!vmem_pool_create");
+			}
+		}
+	}
+
+	char *test = vmem_malloc(vmp, strlen(TEST_STRING_VALUE) + 1);
+	ASSERTne(test, NULL);
+
+	strcpy(test, TEST_STRING_VALUE);
+	ASSERTeq(strcmp(test, TEST_STRING_VALUE), 0);
+
+	vmem_free(vmp, test);
+
+	vmem_pool_delete(vmp);
+}
+
+int
+main(int argc, char *argv[])
+{
+	int expect_custom_alloc = 0;
+
+	START(argc, argv, "vmem_custom_alloc");
+
+	if (argc < 2 || argc > 3 || strlen(argv[1]) != 1)
+		FATAL("usage: %s (0-2) [directory]", argv[0]);
+
+	switch (argv[1][0]) {
+		case '0': {
+			/* use default allocator */
+			expect_custom_alloc = 0;
+			expect_create_pool = 1;
+			break;
+		}
+		case '1': {
+			/* error in custom malloc function */
+			expect_custom_alloc = 1;
+			expect_create_pool = 0;
+			vmem_set_funcs(malloc_null, free_custom,
+				realloc_custom, strdup_custom, NULL);
+			break;
+		}
+		case '2': {
+			/* use custom alloc functions */
+			expect_custom_alloc = 1;
+			expect_create_pool = 1;
+			vmem_set_funcs(malloc_custom, free_custom,
+				realloc_custom, strdup_custom, NULL);
+			break;
+		}
+		default: {
+			FATAL("usage: %s (0-2) [directory]", argv[0]);
+			break;
+		}
+	}
+
+	if (argc == 3) {
+		pool_test(argv[2]);
+	} else {
+		int i;
+		/* repeat create pool */
+		for (i = 0; i < TEST_REPEAT_CREATE_POOLS; ++i)
+			pool_test(NULL);
+	}
+
+	/* check memory leak in custom allocator */
+	ASSERTeq(custom_allocs, 0);
+
+	if (expect_custom_alloc == 0) {
+		ASSERTeq(custom_alloc_calls, 0);
+	} else {
+		ASSERTne(custom_alloc_calls, 0);
+	}
+
+	DONE(NULL);
+}
diff --git a/src/test/vmem_malloc/.gitignore b/src/test/vmem_malloc/.gitignore
new file mode 100644
index 0000000000000000000000000000000000000000..50ae73f3c496bd9a627377a0c107925ac6b89bef
--- /dev/null
+++ b/src/test/vmem_malloc/.gitignore
@@ -0,0 +1 @@
+vmem_malloc
diff --git a/src/test/vmem_malloc/Makefile b/src/test/vmem_malloc/Makefile
new file mode 100644
index 0000000000000000000000000000000000000000..5f85a48f00030dcaa0ace94497893492e88b29b4
--- /dev/null
+++ b/src/test/vmem_malloc/Makefile
@@ -0,0 +1,45 @@
+#
+# Copyright (c) 2014, Intel Corporation
+#
+# Redistribution and use in source and binary forms, with or without
+# modification, are permitted provided that the following conditions
+# are met:
+#
+#     * Redistributions of source code must retain the above copyright
+#       notice, this list of conditions and the following disclaimer.
+#
+#     * Redistributions in binary form must reproduce the above copyright
+#       notice, this list of conditions and the following disclaimer in
+#       the documentation and/or other materials provided with the
+#       distribution.
+#
+#     * Neither the name of Intel Corporation nor the names of its
+#       contributors may be used to endorse or promote products derived
+#       from this software without specific prior written permission.
+#
+# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+#
+
+#
+# src/test/vmem_malloc/Makefile -- build vmem_malloc unit test
+#
+TARGET = vmem_malloc
+OBJS = vmem_malloc.o
+
+include ../Makefile.inc
+STATIC_DEBUG_LIBS = ../unittest/libut.a ../../debug/libvmem.a -luuid -pthread
+STATIC_NONDEBUG_LIBS = ../unittest/libut.a ../../nondebug/libvmem.a -luuid -pthread
+
+LIBS += -lvmem
+
+vmem_malloc.o: vmem_malloc.c
diff --git a/src/test/vmem_malloc/TEST0 b/src/test/vmem_malloc/TEST0
new file mode 100755
index 0000000000000000000000000000000000000000..67560fccc3b692ec9f13f1ee8f81335d98244b5f
--- /dev/null
+++ b/src/test/vmem_malloc/TEST0
@@ -0,0 +1,51 @@
+#!/bin/bash -e
+#
+# Copyright (c) 2014, Intel Corporation
+#
+# Redistribution and use in source and binary forms, with or without
+# modification, are permitted provided that the following conditions
+# are met:
+#
+#     * Redistributions of source code must retain the above copyright
+#       notice, this list of conditions and the following disclaimer.
+#
+#     * Redistributions in binary form must reproduce the above copyright
+#       notice, this list of conditions and the following disclaimer in
+#       the documentation and/or other materials provided with the
+#       distribution.
+#
+#     * Neither the name of Intel Corporation nor the names of its
+#       contributors may be used to endorse or promote products derived
+#       from this software without specific prior written permission.
+#
+# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+#
+
+#
+# src/test/vmem_malloc/TEST0 -- unit test for vmem_malloc
+#
+export UNITTEST_NAME=vmem_malloc/TEST0
+export UNITTEST_NUM=0
+
+# standard unit test setup
+. ../unittest/unittest.sh
+
+require_fs_type local
+
+setup
+
+expect_normal_exit ./vmem_malloc$EXESUFFIX
+
+check
+
+pass
diff --git a/src/test/vmem_malloc/TEST1 b/src/test/vmem_malloc/TEST1
new file mode 100755
index 0000000000000000000000000000000000000000..d187cb28e0bda265007f576026be23e0941014e5
--- /dev/null
+++ b/src/test/vmem_malloc/TEST1
@@ -0,0 +1,51 @@
+#!/bin/bash -e
+#
+# Copyright (c) 2014, Intel Corporation
+#
+# Redistribution and use in source and binary forms, with or without
+# modification, are permitted provided that the following conditions
+# are met:
+#
+#     * Redistributions of source code must retain the above copyright
+#       notice, this list of conditions and the following disclaimer.
+#
+#     * Redistributions in binary form must reproduce the above copyright
+#       notice, this list of conditions and the following disclaimer in
+#       the documentation and/or other materials provided with the
+#       distribution.
+#
+#     * Neither the name of Intel Corporation nor the names of its
+#       contributors may be used to endorse or promote products derived
+#       from this software without specific prior written permission.
+#
+# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+#
+
+#
+# src/test/vmem_malloc/TEST1 -- unit test for vmem_malloc
+#
+export UNITTEST_NAME=vmem_malloc/TEST1
+export UNITTEST_NUM=1
+
+# standard unit test setup
+. ../unittest/unittest.sh
+
+require_fs_type pmem
+
+setup
+
+expect_normal_exit ./vmem_malloc$EXESUFFIX $DIR
+
+check
+
+pass
diff --git a/src/test/vmem_malloc/err0.log.match b/src/test/vmem_malloc/err0.log.match
new file mode 100644
index 0000000000000000000000000000000000000000..e69de29bb2d1d6434b8b29ae775ad8c2e48c5391
diff --git a/src/test/vmem_malloc/err1.log.match b/src/test/vmem_malloc/err1.log.match
new file mode 100644
index 0000000000000000000000000000000000000000..e69de29bb2d1d6434b8b29ae775ad8c2e48c5391
diff --git a/src/test/vmem_malloc/out0.log.match b/src/test/vmem_malloc/out0.log.match
new file mode 100644
index 0000000000000000000000000000000000000000..e43c104a9487a8993869297c002d7935737535b7
--- /dev/null
+++ b/src/test/vmem_malloc/out0.log.match
@@ -0,0 +1,3 @@
+vmem_malloc/TEST0: START: vmem_malloc
+ ./vmem_malloc$(*)
+vmem_malloc/TEST0: Done
diff --git a/src/test/vmem_malloc/out1.log.match b/src/test/vmem_malloc/out1.log.match
new file mode 100644
index 0000000000000000000000000000000000000000..27636b7a9a5af055ee8a81db50a55f7a14fb3293
--- /dev/null
+++ b/src/test/vmem_malloc/out1.log.match
@@ -0,0 +1,3 @@
+vmem_malloc/TEST1: START: vmem_malloc
+ ./vmem_malloc$(*)
+vmem_malloc/TEST1: Done
diff --git a/src/test/vmem_malloc/vmem_malloc.c b/src/test/vmem_malloc/vmem_malloc.c
new file mode 100644
index 0000000000000000000000000000000000000000..0023afc3da8c343b6eed04008a403023badd1e19
--- /dev/null
+++ b/src/test/vmem_malloc/vmem_malloc.c
@@ -0,0 +1,83 @@
+/*
+ * Copyright (c) 2014, Intel Corporation
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ *     * Redistributions of source code must retain the above copyright
+ *       notice, this list of conditions and the following disclaimer.
+ *
+ *     * Redistributions in binary form must reproduce the above copyright
+ *       notice, this list of conditions and the following disclaimer in
+ *       the documentation and/or other materials provided with the
+ *       distribution.
+ *
+ *     * Neither the name of Intel Corporation nor the names of its
+ *       contributors may be used to endorse or promote products derived
+ *       from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+/*
+ * vmem_malloc.c -- unit test for vmem_malloc
+ *
+ * usage: vmem_malloc [directory]
+ */
+
+#include "unittest.h"
+
+static char mem_pool[VMEM_MIN_POOL];
+
+int
+main(int argc, char *argv[])
+{
+	const int test_value = 123456;
+	char *dir = NULL;
+	VMEM *vmp;
+
+	START(argc, argv, "vmem_malloc");
+
+	if (argc == 2) {
+		dir = argv[1];
+	} else if (argc > 2) {
+		FATAL("usage: %s [directory]", argv[0]);
+	}
+
+	if (dir == NULL) {
+		vmp = vmem_pool_create_in_region(mem_pool, VMEM_MIN_POOL);
+		if (vmp == NULL)
+			FATAL("!vmem_pool_create_in_region");
+	} else {
+		vmp = vmem_pool_create(dir, VMEM_MIN_POOL);
+		if (vmp == NULL)
+			FATAL("!vmem_pool_create");
+	}
+
+	int *test = vmem_malloc(vmp, sizeof (int));
+	ASSERTne(test, NULL);
+	*test = test_value;
+	ASSERTeq(*test, test_value);
+
+	/* check that pointer came from mem_pool */
+	if (dir == NULL) {
+		ASSERTrange(test, mem_pool, VMEM_MIN_POOL);
+	}
+
+	vmem_free(vmp, test);
+
+	vmem_pool_delete(vmp);
+
+	DONE(NULL);
+}
diff --git a/src/test/vmem_mix_allocations/.gitignore b/src/test/vmem_mix_allocations/.gitignore
new file mode 100644
index 0000000000000000000000000000000000000000..593aa0f5f7035e7b275891beb7053a33a6c9c7a5
--- /dev/null
+++ b/src/test/vmem_mix_allocations/.gitignore
@@ -0,0 +1 @@
+vmem_mix_allocations
diff --git a/src/test/vmem_mix_allocations/Makefile b/src/test/vmem_mix_allocations/Makefile
new file mode 100644
index 0000000000000000000000000000000000000000..779fc62faf18ac916f179f33b9e90ca2768fbf1f
--- /dev/null
+++ b/src/test/vmem_mix_allocations/Makefile
@@ -0,0 +1,45 @@
+#
+# Copyright (c) 2014, Intel Corporation
+#
+# Redistribution and use in source and binary forms, with or without
+# modification, are permitted provided that the following conditions
+# are met:
+#
+#     * Redistributions of source code must retain the above copyright
+#       notice, this list of conditions and the following disclaimer.
+#
+#     * Redistributions in binary form must reproduce the above copyright
+#       notice, this list of conditions and the following disclaimer in
+#       the documentation and/or other materials provided with the
+#       distribution.
+#
+#     * Neither the name of Intel Corporation nor the names of its
+#       contributors may be used to endorse or promote products derived
+#       from this software without specific prior written permission.
+#
+# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+#
+
+#
+# src/test/vmem_mix_allocations/Makefile -- build vmem_mix_allocations unit test
+#
+TARGET = vmem_mix_allocations
+OBJS = vmem_mix_allocations.o
+
+include ../Makefile.inc
+STATIC_DEBUG_LIBS = ../unittest/libut.a ../../debug/libvmem.a -luuid -pthread
+STATIC_NONDEBUG_LIBS = ../unittest/libut.a ../../nondebug/libvmem.a -luuid -pthread
+
+LIBS += -lvmem
+
+vmem_mix_allocations.o: vmem_mix_allocations.c
diff --git a/src/test/vmem_mix_allocations/TEST0 b/src/test/vmem_mix_allocations/TEST0
new file mode 100755
index 0000000000000000000000000000000000000000..ced26532158570af3009b53da6fed34982d632c4
--- /dev/null
+++ b/src/test/vmem_mix_allocations/TEST0
@@ -0,0 +1,52 @@
+#!/bin/bash -e
+#
+# Copyright (c) 2014, Intel Corporation
+#
+# Redistribution and use in source and binary forms, with or without
+# modification, are permitted provided that the following conditions
+# are met:
+#
+#     * Redistributions of source code must retain the above copyright
+#       notice, this list of conditions and the following disclaimer.
+#
+#     * Redistributions in binary form must reproduce the above copyright
+#       notice, this list of conditions and the following disclaimer in
+#       the documentation and/or other materials provided with the
+#       distribution.
+#
+#     * Neither the name of Intel Corporation nor the names of its
+#       contributors may be used to endorse or promote products derived
+#       from this software without specific prior written permission.
+#
+# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+#
+
+#
+# src/test/vmem_mix_allocations/TEST0 -- unit test for vmem_mix_allocations
+#
+export UNITTEST_NAME=vmem_mix_allocations/TEST0
+export UNITTEST_NUM=0
+
+# standard unit test setup
+. ../unittest/unittest.sh
+
+require_fs_type local
+require_build_type debug nondebug
+
+setup
+
+expect_normal_exit ./vmem_mix_allocations$EXESUFFIX
+
+check
+
+pass
diff --git a/src/test/vmem_mix_allocations/TEST1 b/src/test/vmem_mix_allocations/TEST1
new file mode 100755
index 0000000000000000000000000000000000000000..7114668c01a31d3d73e98da48a612621acbf450f
--- /dev/null
+++ b/src/test/vmem_mix_allocations/TEST1
@@ -0,0 +1,52 @@
+#!/bin/bash -e
+#
+# Copyright (c) 2014, Intel Corporation
+#
+# Redistribution and use in source and binary forms, with or without
+# modification, are permitted provided that the following conditions
+# are met:
+#
+#     * Redistributions of source code must retain the above copyright
+#       notice, this list of conditions and the following disclaimer.
+#
+#     * Redistributions in binary form must reproduce the above copyright
+#       notice, this list of conditions and the following disclaimer in
+#       the documentation and/or other materials provided with the
+#       distribution.
+#
+#     * Neither the name of Intel Corporation nor the names of its
+#       contributors may be used to endorse or promote products derived
+#       from this software without specific prior written permission.
+#
+# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+#
+
+#
+# src/test/vmem_mix_allocations/TEST1 -- unit test for vmem_mix_allocations
+#
+export UNITTEST_NAME=vmem_mix_allocations/TEST1
+export UNITTEST_NUM=1
+
+# standard unit test setup
+. ../unittest/unittest.sh
+
+require_fs_type pmem
+require_build_type debug nondebug
+
+setup
+
+expect_normal_exit ./vmem_mix_allocations$EXESUFFIX $DIR
+
+check
+
+pass
diff --git a/src/test/vmem_mix_allocations/err0.log.match b/src/test/vmem_mix_allocations/err0.log.match
new file mode 100644
index 0000000000000000000000000000000000000000..e69de29bb2d1d6434b8b29ae775ad8c2e48c5391
diff --git a/src/test/vmem_mix_allocations/err1.log.match b/src/test/vmem_mix_allocations/err1.log.match
new file mode 100644
index 0000000000000000000000000000000000000000..e69de29bb2d1d6434b8b29ae775ad8c2e48c5391
diff --git a/src/test/vmem_mix_allocations/out0.log.match b/src/test/vmem_mix_allocations/out0.log.match
new file mode 100644
index 0000000000000000000000000000000000000000..1d1d9a67987871e258433c0e5e0ed6a8435dac1e
--- /dev/null
+++ b/src/test/vmem_mix_allocations/out0.log.match
@@ -0,0 +1,3 @@
+vmem_mix_allocations/TEST0: START: vmem_mix_allocations
+ ./vmem_mix_allocations$(*)
+vmem_mix_allocations/TEST0: Done
diff --git a/src/test/vmem_mix_allocations/out1.log.match b/src/test/vmem_mix_allocations/out1.log.match
new file mode 100644
index 0000000000000000000000000000000000000000..17dc000014348a9239332baac8be20fee0e5898e
--- /dev/null
+++ b/src/test/vmem_mix_allocations/out1.log.match
@@ -0,0 +1,3 @@
+vmem_mix_allocations/TEST1: START: vmem_mix_allocations
+ ./vmem_mix_allocations$(*)
+vmem_mix_allocations/TEST1: Done
diff --git a/src/test/vmem_mix_allocations/vmem_mix_allocations.c b/src/test/vmem_mix_allocations/vmem_mix_allocations.c
new file mode 100644
index 0000000000000000000000000000000000000000..a6cba08939c7eceb057ee72bc32afc416d2c7864
--- /dev/null
+++ b/src/test/vmem_mix_allocations/vmem_mix_allocations.c
@@ -0,0 +1,92 @@
+/*
+ * Copyright (c) 2014, Intel Corporation
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ *     * Redistributions of source code must retain the above copyright
+ *       notice, this list of conditions and the following disclaimer.
+ *
+ *     * Redistributions in binary form must reproduce the above copyright
+ *       notice, this list of conditions and the following disclaimer in
+ *       the documentation and/or other materials provided with the
+ *       distribution.
+ *
+ *     * Neither the name of Intel Corporation nor the names of its
+ *       contributors may be used to endorse or promote products derived
+ *       from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+/*
+ * vmem_mix_allocations.c -- unit test for vmem_mix_allocations
+ *
+ * usage: vmem_mix_allocations [directory]
+ */
+
+#include "unittest.h"
+
+static char mem_pool[VMEM_MIN_POOL];
+
+int
+main(int argc, char *argv[])
+{
+	char *dir = NULL;
+	VMEM *vmp;
+	size_t object_size;
+	int *ptr;
+	size_t sum_alloc = 0;
+
+	START(argc, argv, "vmem_mix_allocations");
+
+	if (argc == 2) {
+		dir = argv[1];
+	} else if (argc > 2) {
+		FATAL("usage: %s [directory]", argv[0]);
+	}
+
+	if (dir == NULL) {
+		vmp = vmem_pool_create_in_region(mem_pool, VMEM_MIN_POOL);
+		if (vmp == NULL)
+			FATAL("!vmem_pool_create_in_region");
+	} else {
+		vmp = vmem_pool_create(dir, VMEM_MIN_POOL);
+		if (vmp == NULL)
+			FATAL("!vmem_pool_create");
+	}
+
+	/* test with multiple size of allocations from 4MB to 2B */
+	for (object_size = 4 * 1024 * 1024; object_size >= 4; object_size /= 2)
+		do {
+			ptr = vmem_malloc(vmp, object_size);
+
+			if (ptr == NULL)
+				break;
+
+			sum_alloc += object_size;
+
+			/* check that pointer came from mem_pool */
+			if (dir == NULL) {
+				ASSERTrange(ptr, mem_pool, VMEM_MIN_POOL);
+			}
+		} while (object_size == 2);
+
+	/* allocate more than half of pool size */
+	ASSERT(sum_alloc * 2 > VMEM_MIN_POOL);
+
+	vmem_pool_delete(vmp);
+
+	DONE(NULL);
+}
diff --git a/src/test/vmem_multiple_pools/.gitignore b/src/test/vmem_multiple_pools/.gitignore
new file mode 100644
index 0000000000000000000000000000000000000000..6030f2e823a66d4f45b733d8d28473c0b37ebeb6
--- /dev/null
+++ b/src/test/vmem_multiple_pools/.gitignore
@@ -0,0 +1 @@
+vmem_multiple_pools
diff --git a/src/test/vmem_multiple_pools/Makefile b/src/test/vmem_multiple_pools/Makefile
new file mode 100644
index 0000000000000000000000000000000000000000..a9e57e3fbe66586f9eefe541b63c4c6d2d15b4a1
--- /dev/null
+++ b/src/test/vmem_multiple_pools/Makefile
@@ -0,0 +1,45 @@
+#
+# Copyright (c) 2014, Intel Corporation
+#
+# Redistribution and use in source and binary forms, with or without
+# modification, are permitted provided that the following conditions
+# are met:
+#
+#     * Redistributions of source code must retain the above copyright
+#       notice, this list of conditions and the following disclaimer.
+#
+#     * Redistributions in binary form must reproduce the above copyright
+#       notice, this list of conditions and the following disclaimer in
+#       the documentation and/or other materials provided with the
+#       distribution.
+#
+#     * Neither the name of Intel Corporation nor the names of its
+#       contributors may be used to endorse or promote products derived
+#       from this software without specific prior written permission.
+#
+# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+#
+
+#
+# src/test/vmem_multiple_pools/Makefile -- build vmem_multiple_pools unit test
+#
+TARGET = vmem_multiple_pools
+OBJS = vmem_multiple_pools.o
+
+include ../Makefile.inc
+STATIC_DEBUG_LIBS = ../unittest/libut.a ../../debug/libvmem.a -luuid -pthread
+STATIC_NONDEBUG_LIBS = ../unittest/libut.a ../../nondebug/libvmem.a -luuid -pthread
+
+LIBS += -lvmem
+
+vmem_multiple_pools.o: vmem_multiple_pools.c
diff --git a/src/test/vmem_multiple_pools/TEST0 b/src/test/vmem_multiple_pools/TEST0
new file mode 100755
index 0000000000000000000000000000000000000000..177ed85fc311e96ead9f921e8e55a67db2528e01
--- /dev/null
+++ b/src/test/vmem_multiple_pools/TEST0
@@ -0,0 +1,52 @@
+#!/bin/bash -e
+#
+# Copyright (c) 2014, Intel Corporation
+#
+# Redistribution and use in source and binary forms, with or without
+# modification, are permitted provided that the following conditions
+# are met:
+#
+#     * Redistributions of source code must retain the above copyright
+#       notice, this list of conditions and the following disclaimer.
+#
+#     * Redistributions in binary form must reproduce the above copyright
+#       notice, this list of conditions and the following disclaimer in
+#       the documentation and/or other materials provided with the
+#       distribution.
+#
+#     * Neither the name of Intel Corporation nor the names of its
+#       contributors may be used to endorse or promote products derived
+#       from this software without specific prior written permission.
+#
+# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+#
+
+#
+# src/test/vmem_multiple_pools/TEST0 -- unit test for vmem_multiple_pools
+#
+export UNITTEST_NAME=vmem_multiple_pools/TEST0
+export UNITTEST_NUM=0
+
+# standard unit test setup
+. ../unittest/unittest.sh
+
+require_fs_type local
+require_build_type debug nondebug
+
+setup
+
+expect_normal_exit ./vmem_multiple_pools$EXESUFFIX $DIR
+
+check
+
+pass
diff --git a/src/test/vmem_multiple_pools/err0.log.match b/src/test/vmem_multiple_pools/err0.log.match
new file mode 100644
index 0000000000000000000000000000000000000000..e69de29bb2d1d6434b8b29ae775ad8c2e48c5391
diff --git a/src/test/vmem_multiple_pools/out0.log.match b/src/test/vmem_multiple_pools/out0.log.match
new file mode 100644
index 0000000000000000000000000000000000000000..b3fc582abb309c1671d1325cc2887bb9c9bd6f48
--- /dev/null
+++ b/src/test/vmem_multiple_pools/out0.log.match
@@ -0,0 +1,3 @@
+vmem_multiple_pools/TEST0: START: vmem_multiple_pools
+ ./vmem_multiple_pools$(*)
+vmem_multiple_pools/TEST0: Done
diff --git a/src/test/vmem_multiple_pools/vmem_multiple_pools.c b/src/test/vmem_multiple_pools/vmem_multiple_pools.c
new file mode 100644
index 0000000000000000000000000000000000000000..1432bceab6427fd8bed5ac3f52e7ed9d78f0a123
--- /dev/null
+++ b/src/test/vmem_multiple_pools/vmem_multiple_pools.c
@@ -0,0 +1,100 @@
+/*
+ * Copyright (c) 2014, Intel Corporation
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ *     * Redistributions of source code must retain the above copyright
+ *       notice, this list of conditions and the following disclaimer.
+ *
+ *     * Redistributions in binary form must reproduce the above copyright
+ *       notice, this list of conditions and the following disclaimer in
+ *       the documentation and/or other materials provided with the
+ *       distribution.
+ *
+ *     * Neither the name of Intel Corporation nor the names of its
+ *       contributors may be used to endorse or promote products derived
+ *       from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+/*
+ * vmem_multiple_pools.c -- unit test for vmem_multiple_pools
+ *
+ * usage: vmem_multiple_pools directory
+ */
+
+#include "unittest.h"
+
+#define	TEST_POOLS_MAX (9)
+#define	TEST_REPEAT_CREATE_POOLS (30)
+
+static char mem_pools[TEST_POOLS_MAX/2][VMEM_MIN_POOL];
+
+VMEM *pools[TEST_POOLS_MAX];
+
+int
+main(int argc, char *argv[])
+{
+	START(argc, argv, "vmem_multiple_pools");
+
+	if (argc < 2 || argc > 3)
+		FATAL("usage: %s directory", argv[0]);
+
+	const char *dir = argv[1];
+
+	/* create and destroy pools multiple times */
+	size_t repeat;
+	size_t pool_id;
+	for (repeat = 0; repeat < TEST_REPEAT_CREATE_POOLS; ++repeat) {
+		for (pool_id = 0; pool_id < TEST_POOLS_MAX; ++pool_id) {
+
+			/* delete old pool with this same id if exist */
+			if (pools[pool_id] != NULL) {
+				vmem_pool_delete(pools[pool_id]);
+				pools[pool_id] = NULL;
+			}
+
+			if (pool_id % 2 == 0) {
+				/* for even pool_id, create in region */
+				pools[pool_id] = vmem_pool_create_in_region(
+					mem_pools[pool_id % 2], VMEM_MIN_POOL);
+				if (pools[pool_id] == NULL)
+					FATAL("!vmem_pool_create_in_region");
+			} else {
+				/* for odd pool_id, create in file */
+				pools[pool_id] = vmem_pool_create(dir,
+					VMEM_MIN_POOL);
+				if (pools[pool_id] == NULL)
+					FATAL("!vmem_pool_create");
+			}
+
+			void *test = vmem_malloc(pools[pool_id],
+				sizeof (void *));
+
+			ASSERTne(test, NULL);
+			vmem_free(pools[pool_id], test);
+		}
+	}
+
+	for (pool_id = 0; pool_id < TEST_POOLS_MAX; ++pool_id) {
+		if (pools[pool_id] != NULL) {
+			vmem_pool_delete(pools[pool_id]);
+			pools[pool_id] = NULL;
+		}
+	}
+
+	DONE(NULL);
+}
diff --git a/src/test/vmem_out_of_memory/.gitignore b/src/test/vmem_out_of_memory/.gitignore
new file mode 100644
index 0000000000000000000000000000000000000000..56b02bb3d55a6d390a1e708fcd13a12cbfb295bf
--- /dev/null
+++ b/src/test/vmem_out_of_memory/.gitignore
@@ -0,0 +1 @@
+vmem_out_of_memory
diff --git a/src/test/vmem_out_of_memory/Makefile b/src/test/vmem_out_of_memory/Makefile
new file mode 100644
index 0000000000000000000000000000000000000000..cd08c646a830572aaf1e50754c1fdf40082113dd
--- /dev/null
+++ b/src/test/vmem_out_of_memory/Makefile
@@ -0,0 +1,45 @@
+#
+# Copyright (c) 2014, Intel Corporation
+#
+# Redistribution and use in source and binary forms, with or without
+# modification, are permitted provided that the following conditions
+# are met:
+#
+#     * Redistributions of source code must retain the above copyright
+#       notice, this list of conditions and the following disclaimer.
+#
+#     * Redistributions in binary form must reproduce the above copyright
+#       notice, this list of conditions and the following disclaimer in
+#       the documentation and/or other materials provided with the
+#       distribution.
+#
+#     * Neither the name of Intel Corporation nor the names of its
+#       contributors may be used to endorse or promote products derived
+#       from this software without specific prior written permission.
+#
+# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+#
+
+#
+# src/test/vmem_out_of_memory/Makefile -- build vmem_out_of_memory unit test
+#
+TARGET = vmem_out_of_memory
+OBJS = vmem_out_of_memory.o
+
+include ../Makefile.inc
+STATIC_DEBUG_LIBS = ../unittest/libut.a ../../debug/libvmem.a -luuid -pthread
+STATIC_NONDEBUG_LIBS = ../unittest/libut.a ../../nondebug/libvmem.a -luuid -pthread
+
+LIBS += -lvmem
+
+vmem_out_of_memory.o: vmem_out_of_memory.c
diff --git a/src/test/vmem_out_of_memory/TEST0 b/src/test/vmem_out_of_memory/TEST0
new file mode 100755
index 0000000000000000000000000000000000000000..bfe454a7c0866f1618c5d37331948fba6a09f683
--- /dev/null
+++ b/src/test/vmem_out_of_memory/TEST0
@@ -0,0 +1,55 @@
+#!/bin/bash -e
+#
+# Copyright (c) 2014, Intel Corporation
+#
+# Redistribution and use in source and binary forms, with or without
+# modification, are permitted provided that the following conditions
+# are met:
+#
+#     * Redistributions of source code must retain the above copyright
+#       notice, this list of conditions and the following disclaimer.
+#
+#     * Redistributions in binary form must reproduce the above copyright
+#       notice, this list of conditions and the following disclaimer in
+#       the documentation and/or other materials provided with the
+#       distribution.
+#
+#     * Neither the name of Intel Corporation nor the names of its
+#       contributors may be used to endorse or promote products derived
+#       from this software without specific prior written permission.
+#
+# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+#
+
+#
+# src/test/vmem_out_of_memory/TEST0 -- unit test for vmem_out_of_memory
+#
+export UNITTEST_NAME=vmem_out_of_memory/TEST0
+export UNITTEST_NUM=0
+
+# standard unit test setup
+. ../unittest/unittest.sh
+
+require_fs_type local
+require_build_type debug nondebug
+
+setup
+
+#limit output for file vmem*.log to reduce time of test execution
+export VMEM_LOG_LEVEL=2
+
+expect_normal_exit ./vmem_out_of_memory$EXESUFFIX
+
+check
+
+pass
diff --git a/src/test/vmem_out_of_memory/TEST1 b/src/test/vmem_out_of_memory/TEST1
new file mode 100755
index 0000000000000000000000000000000000000000..3d46693e45dcf9718a1ec2bd6e1b9664c4edd24e
--- /dev/null
+++ b/src/test/vmem_out_of_memory/TEST1
@@ -0,0 +1,55 @@
+#!/bin/bash -e
+#
+# Copyright (c) 2014, Intel Corporation
+#
+# Redistribution and use in source and binary forms, with or without
+# modification, are permitted provided that the following conditions
+# are met:
+#
+#     * Redistributions of source code must retain the above copyright
+#       notice, this list of conditions and the following disclaimer.
+#
+#     * Redistributions in binary form must reproduce the above copyright
+#       notice, this list of conditions and the following disclaimer in
+#       the documentation and/or other materials provided with the
+#       distribution.
+#
+#     * Neither the name of Intel Corporation nor the names of its
+#       contributors may be used to endorse or promote products derived
+#       from this software without specific prior written permission.
+#
+# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+#
+
+#
+# src/test/vmem_out_of_memory/TEST1 -- unit test for vmem_out_of_memory
+#
+export UNITTEST_NAME=vmem_out_of_memory/TEST1
+export UNITTEST_NUM=1
+
+# standard unit test setup
+. ../unittest/unittest.sh
+
+require_fs_type pmem
+require_build_type debug nondebug
+
+setup
+
+#limit output for file vmem*.log to reduce time of test execution
+export VMEM_LOG_LEVEL=2
+
+expect_normal_exit ./vmem_out_of_memory$EXESUFFIX $DIR
+
+check
+
+pass
diff --git a/src/test/vmem_out_of_memory/err0.log.match b/src/test/vmem_out_of_memory/err0.log.match
new file mode 100644
index 0000000000000000000000000000000000000000..e69de29bb2d1d6434b8b29ae775ad8c2e48c5391
diff --git a/src/test/vmem_out_of_memory/err1.log.match b/src/test/vmem_out_of_memory/err1.log.match
new file mode 100644
index 0000000000000000000000000000000000000000..e69de29bb2d1d6434b8b29ae775ad8c2e48c5391
diff --git a/src/test/vmem_out_of_memory/out0.log.match b/src/test/vmem_out_of_memory/out0.log.match
new file mode 100644
index 0000000000000000000000000000000000000000..233b29cc92ee2bfca9523e40fb301138ad7bb913
--- /dev/null
+++ b/src/test/vmem_out_of_memory/out0.log.match
@@ -0,0 +1,3 @@
+vmem_out_of_memory/TEST0: START: vmem_out_of_memory
+ ./vmem_out_of_memory$(*)
+vmem_out_of_memory/TEST0: Done
diff --git a/src/test/vmem_out_of_memory/out1.log.match b/src/test/vmem_out_of_memory/out1.log.match
new file mode 100644
index 0000000000000000000000000000000000000000..b6ba4431f7b5eb6c45cfcd17be3c8241880289e5
--- /dev/null
+++ b/src/test/vmem_out_of_memory/out1.log.match
@@ -0,0 +1,3 @@
+vmem_out_of_memory/TEST1: START: vmem_out_of_memory
+ ./vmem_out_of_memory$(*)
+vmem_out_of_memory/TEST1: Done
diff --git a/src/test/vmem_out_of_memory/vmem_out_of_memory.c b/src/test/vmem_out_of_memory/vmem_out_of_memory.c
new file mode 100644
index 0000000000000000000000000000000000000000..ce98abd2cf5dafe609ebf2ebda08152c2a8948dc
--- /dev/null
+++ b/src/test/vmem_out_of_memory/vmem_out_of_memory.c
@@ -0,0 +1,96 @@
+/*
+ * Copyright (c) 2014, Intel Corporation
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ *     * Redistributions of source code must retain the above copyright
+ *       notice, this list of conditions and the following disclaimer.
+ *
+ *     * Redistributions in binary form must reproduce the above copyright
+ *       notice, this list of conditions and the following disclaimer in
+ *       the documentation and/or other materials provided with the
+ *       distribution.
+ *
+ *     * Neither the name of Intel Corporation nor the names of its
+ *       contributors may be used to endorse or promote products derived
+ *       from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+/*
+ * vmem_out_of_memory -- unit test for vmem_out_of_memory
+ *
+ * usage: vmem_out_of_memory [directory]
+ */
+
+#include "unittest.h"
+
+static char mem_pool[VMEM_MIN_POOL];
+
+int
+main(int argc, char *argv[])
+{
+	char *dir = NULL;
+	VMEM *vmp;
+	START(argc, argv, "vmem_out_of_memory");
+
+	if (argc == 2) {
+		dir = argv[1];
+	} else if (argc > 2) {
+		FATAL("usage: %s [directory]", argv[0]);
+	}
+
+	if (dir == NULL) {
+		vmp = vmem_pool_create_in_region(mem_pool, VMEM_MIN_POOL);
+		if (vmp == NULL)
+			FATAL("!vmem_pool_create_in_region");
+	} else {
+		vmp = vmem_pool_create(dir, VMEM_MIN_POOL);
+		if (vmp == NULL)
+			FATAL("!vmem_pool_create");
+	}
+
+	/* allocate all memory */
+	void *prev = NULL;
+	for (;;) {
+		void **next = vmem_malloc(vmp, sizeof (void *));
+		if (next == NULL) {
+			/* out of memory */
+			break;
+		}
+
+		/* check that pointer came from mem_pool */
+		if (dir == NULL) {
+			ASSERTrange(next, mem_pool, VMEM_MIN_POOL);
+		}
+
+		*next = prev;
+		prev = next;
+	}
+
+	ASSERTne(prev, NULL);
+
+	/* free all allocations */
+	while (prev != NULL) {
+		void **act = prev;
+		prev = *act;
+		vmem_free(vmp, act);
+	}
+
+	vmem_pool_delete(vmp);
+
+	DONE(NULL);
+}
diff --git a/src/test/vmem_pool_create/.gitignore b/src/test/vmem_pool_create/.gitignore
new file mode 100644
index 0000000000000000000000000000000000000000..431dc90aadfd173660199a5e786a240bd74405b3
--- /dev/null
+++ b/src/test/vmem_pool_create/.gitignore
@@ -0,0 +1 @@
+vmem_pool_create
diff --git a/src/test/vmem_pool_create/Makefile b/src/test/vmem_pool_create/Makefile
new file mode 100644
index 0000000000000000000000000000000000000000..fcdc92ff3a4db151e5fa629f7c8408bb6551a923
--- /dev/null
+++ b/src/test/vmem_pool_create/Makefile
@@ -0,0 +1,45 @@
+#
+# Copyright (c) 2014, Intel Corporation
+#
+# Redistribution and use in source and binary forms, with or without
+# modification, are permitted provided that the following conditions
+# are met:
+#
+#     * Redistributions of source code must retain the above copyright
+#       notice, this list of conditions and the following disclaimer.
+#
+#     * Redistributions in binary form must reproduce the above copyright
+#       notice, this list of conditions and the following disclaimer in
+#       the documentation and/or other materials provided with the
+#       distribution.
+#
+#     * Neither the name of Intel Corporation nor the names of its
+#       contributors may be used to endorse or promote products derived
+#       from this software without specific prior written permission.
+#
+# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+#
+
+#
+# src/test/vmem_pool_create/Makefile -- build vmem_pool_create unit test
+#
+TARGET = vmem_pool_create
+OBJS = vmem_pool_create.o
+
+include ../Makefile.inc
+STATIC_DEBUG_LIBS = ../unittest/libut.a ../../debug/libvmem.a -luuid -pthread
+STATIC_NONDEBUG_LIBS = ../unittest/libut.a ../../nondebug/libvmem.a -luuid -pthread
+
+LIBS += -lvmem
+
+vmem_pool_create.o: vmem_pool_create.c
diff --git a/src/test/vmem_pool_create/TEST0 b/src/test/vmem_pool_create/TEST0
new file mode 100755
index 0000000000000000000000000000000000000000..37695ff538b55a543cf96d8e6af59017b2fc4972
--- /dev/null
+++ b/src/test/vmem_pool_create/TEST0
@@ -0,0 +1,51 @@
+#!/bin/bash -e
+#
+# Copyright (c) 2014, Intel Corporation
+#
+# Redistribution and use in source and binary forms, with or without
+# modification, are permitted provided that the following conditions
+# are met:
+#
+#     * Redistributions of source code must retain the above copyright
+#       notice, this list of conditions and the following disclaimer.
+#
+#     * Redistributions in binary form must reproduce the above copyright
+#       notice, this list of conditions and the following disclaimer in
+#       the documentation and/or other materials provided with the
+#       distribution.
+#
+#     * Neither the name of Intel Corporation nor the names of its
+#       contributors may be used to endorse or promote products derived
+#       from this software without specific prior written permission.
+#
+# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+#
+
+#
+# src/test/vmem_pool_create/TEST0 -- unit test for vmem_pool_create
+#
+export UNITTEST_NAME=vmem_pool_create/TEST0
+export UNITTEST_NUM=0
+
+# standard unit test setup
+. ../unittest/unittest.sh
+
+require_fs_type local
+
+setup
+
+expect_normal_exit ./vmem_pool_create$EXESUFFIX $DIR
+
+check
+
+pass
diff --git a/src/test/vmem_pool_create/err0.log.match b/src/test/vmem_pool_create/err0.log.match
new file mode 100644
index 0000000000000000000000000000000000000000..e69de29bb2d1d6434b8b29ae775ad8c2e48c5391
diff --git a/src/test/vmem_pool_create/out0.log.match b/src/test/vmem_pool_create/out0.log.match
new file mode 100644
index 0000000000000000000000000000000000000000..70f089e0db8532f925a348c50bc2e409c97f19b3
--- /dev/null
+++ b/src/test/vmem_pool_create/out0.log.match
@@ -0,0 +1,4 @@
+vmem_pool_create/TEST0: START: vmem_pool_create
+ ./vmem_pool_create$(*)
+signal: Segmentation fault
+vmem_pool_create/TEST0: Done
diff --git a/src/test/vmem_pool_create/vmem_pool_create.c b/src/test/vmem_pool_create/vmem_pool_create.c
new file mode 100644
index 0000000000000000000000000000000000000000..5b1b47471bc96ddc1c12004ff6695a6ca55f1395
--- /dev/null
+++ b/src/test/vmem_pool_create/vmem_pool_create.c
@@ -0,0 +1,81 @@
+/*
+ * Copyright (c) 2014, Intel Corporation
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ *     * Redistributions of source code must retain the above copyright
+ *       notice, this list of conditions and the following disclaimer.
+ *
+ *     * Redistributions in binary form must reproduce the above copyright
+ *       notice, this list of conditions and the following disclaimer in
+ *       the documentation and/or other materials provided with the
+ *       distribution.
+ *
+ *     * Neither the name of Intel Corporation nor the names of its
+ *       contributors may be used to endorse or promote products derived
+ *       from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+/*
+ * vmem_pool_create.c -- unit test for vmem_pool_create
+ *
+ * usage: vmem_pool_create directory
+ */
+
+#include "unittest.h"
+
+VMEM *Vmp;
+
+/*
+ * signal_handler -- called on SIGSEGV
+ */
+void
+signal_handler(int sig)
+{
+	OUT("signal: %s", strsignal(sig));
+
+	vmem_pool_delete(Vmp);
+
+	DONE(NULL);
+}
+
+int
+main(int argc, char *argv[])
+{
+	START(argc, argv, "vmem_pool_create");
+
+	if (argc < 2 || argc > 3)
+		FATAL("usage: %s directory", argv[0]);
+
+	Vmp = vmem_pool_create(argv[1], VMEM_MIN_POOL);
+
+	if (Vmp == NULL)
+		OUT("!vmem_pool_create");
+	else {
+		struct sigvec v = { 0 };
+
+		v.sv_handler = signal_handler;
+		if (sigvec(SIGSEGV, &v, NULL) < 0)
+			FATAL("!sigvec");
+
+		/* try to deref the opaque handle */
+		char x = *(char *)Vmp;
+		OUT("x = %c", x);
+	}
+
+	FATAL("no signal received");
+}
diff --git a/src/test/vmem_pool_create_error/.gitignore b/src/test/vmem_pool_create_error/.gitignore
new file mode 100644
index 0000000000000000000000000000000000000000..16c79c8dd56cb86a7a2fb159ec27c9c210f33c91
--- /dev/null
+++ b/src/test/vmem_pool_create_error/.gitignore
@@ -0,0 +1 @@
+vmem_pool_create_error
diff --git a/src/test/vmem_pool_create_error/Makefile b/src/test/vmem_pool_create_error/Makefile
new file mode 100644
index 0000000000000000000000000000000000000000..78f96e11d4521600bd3288e888ed3af6e6a227f4
--- /dev/null
+++ b/src/test/vmem_pool_create_error/Makefile
@@ -0,0 +1,45 @@
+#
+# Copyright (c) 2014, Intel Corporation
+#
+# Redistribution and use in source and binary forms, with or without
+# modification, are permitted provided that the following conditions
+# are met:
+#
+#     * Redistributions of source code must retain the above copyright
+#       notice, this list of conditions and the following disclaimer.
+#
+#     * Redistributions in binary form must reproduce the above copyright
+#       notice, this list of conditions and the following disclaimer in
+#       the documentation and/or other materials provided with the
+#       distribution.
+#
+#     * Neither the name of Intel Corporation nor the names of its
+#       contributors may be used to endorse or promote products derived
+#       from this software without specific prior written permission.
+#
+# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+#
+
+#
+# src/test/vmem_pool_create_error/Makefile -- build vmem_pool_create_error unit test
+#
+TARGET = vmem_pool_create_error
+OBJS = vmem_pool_create_error.o
+
+include ../Makefile.inc
+STATIC_DEBUG_LIBS = ../unittest/libut.a ../../debug/libvmem.a -luuid -pthread
+STATIC_NONDEBUG_LIBS = ../unittest/libut.a ../../nondebug/libvmem.a -luuid -pthread
+
+LIBS += -lvmem
+
+vmem_pool_create_error.o: vmem_pool_create_error.c
diff --git a/src/test/vmem_pool_create_error/TEST0 b/src/test/vmem_pool_create_error/TEST0
new file mode 100755
index 0000000000000000000000000000000000000000..1f4797eacee71eab7e3fa1b9199ec2a682597a0f
--- /dev/null
+++ b/src/test/vmem_pool_create_error/TEST0
@@ -0,0 +1,52 @@
+#!/bin/bash -e
+#
+# Copyright (c) 2014, Intel Corporation
+#
+# Redistribution and use in source and binary forms, with or without
+# modification, are permitted provided that the following conditions
+# are met:
+#
+#     * Redistributions of source code must retain the above copyright
+#       notice, this list of conditions and the following disclaimer.
+#
+#     * Redistributions in binary form must reproduce the above copyright
+#       notice, this list of conditions and the following disclaimer in
+#       the documentation and/or other materials provided with the
+#       distribution.
+#
+#     * Neither the name of Intel Corporation nor the names of its
+#       contributors may be used to endorse or promote products derived
+#       from this software without specific prior written permission.
+#
+# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+#
+
+#
+# src/test/vmem_pool_create_error/TEST0 -- unit test for vmem_pool_create_error
+#
+export UNITTEST_NAME=vmem_pool_create_error/TEST0
+export UNITTEST_NUM=0
+
+# standard unit test setup
+. ../unittest/unittest.sh
+
+require_fs_type local
+require_build_type debug nondebug
+
+setup
+
+expect_normal_exit ./vmem_pool_create_error$EXESUFFIX
+
+check
+
+pass
diff --git a/src/test/vmem_pool_create_error/err0.log.match b/src/test/vmem_pool_create_error/err0.log.match
new file mode 100644
index 0000000000000000000000000000000000000000..e69de29bb2d1d6434b8b29ae775ad8c2e48c5391
diff --git a/src/test/vmem_pool_create_error/out0.log.match b/src/test/vmem_pool_create_error/out0.log.match
new file mode 100644
index 0000000000000000000000000000000000000000..1760759a7b379dccd0a31d29ead9b9b84f5e1904
--- /dev/null
+++ b/src/test/vmem_pool_create_error/out0.log.match
@@ -0,0 +1,3 @@
+vmem_pool_create_error/TEST0: START: vmem_pool_create_error
+ ./vmem_pool_create_error$(*)
+vmem_pool_create_error/TEST0: Done
diff --git a/src/test/vmem_pool_create_error/vmem_pool_create_error.c b/src/test/vmem_pool_create_error/vmem_pool_create_error.c
new file mode 100644
index 0000000000000000000000000000000000000000..f470bd5e336d5733a78ac813198d515cbfc6781f
--- /dev/null
+++ b/src/test/vmem_pool_create_error/vmem_pool_create_error.c
@@ -0,0 +1,69 @@
+/*
+ * Copyright (c) 2014, Intel Corporation
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ *     * Redistributions of source code must retain the above copyright
+ *       notice, this list of conditions and the following disclaimer.
+ *
+ *     * Redistributions in binary form must reproduce the above copyright
+ *       notice, this list of conditions and the following disclaimer in
+ *       the documentation and/or other materials provided with the
+ *       distribution.
+ *
+ *     * Neither the name of Intel Corporation nor the names of its
+ *       contributors may be used to endorse or promote products derived
+ *       from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+/*
+ * vmem_pool_create_error.c -- unit test for vmem_pool_create_error
+ *
+ * usage: vmem_pool_create_error
+ */
+
+#include "unittest.h"
+
+static char mem_pool[VMEM_MIN_POOL];
+
+int
+main(int argc, char *argv[])
+{
+	VMEM *vmp;
+
+	START(argc, argv, "vmem_pool_create_error");
+
+	if (argc > 1)
+		FATAL("usage: %s", argv[0]);
+
+	errno = 0;
+	vmp = vmem_pool_create_in_region(mem_pool, 0);
+	ASSERTeq(vmp, NULL);
+	ASSERTeq(errno, EINVAL);
+
+	errno = 0;
+	vmp = vmem_pool_create("./", 0);
+	ASSERTeq(vmp, NULL);
+	ASSERTeq(errno, EINVAL);
+
+	errno = 0;
+	vmp = vmem_pool_create("invalid dir !@#$%^&*()=", VMEM_MIN_POOL);
+	ASSERTeq(vmp, NULL);
+	ASSERTne(errno, 0);
+
+	DONE(NULL);
+}
diff --git a/src/test/vmem_pool_create_in_region/.gitignore b/src/test/vmem_pool_create_in_region/.gitignore
new file mode 100644
index 0000000000000000000000000000000000000000..6e0c9297bdcd166c8ee9e0b01cab8934ca446d6b
--- /dev/null
+++ b/src/test/vmem_pool_create_in_region/.gitignore
@@ -0,0 +1 @@
+vmem_pool_create_in_region
diff --git a/src/test/vmem_pool_create_in_region/Makefile b/src/test/vmem_pool_create_in_region/Makefile
new file mode 100644
index 0000000000000000000000000000000000000000..4aa37fcd528c8f59ffbce7657f52581f55c6e395
--- /dev/null
+++ b/src/test/vmem_pool_create_in_region/Makefile
@@ -0,0 +1,45 @@
+#
+# Copyright (c) 2014, Intel Corporation
+#
+# Redistribution and use in source and binary forms, with or without
+# modification, are permitted provided that the following conditions
+# are met:
+#
+#     * Redistributions of source code must retain the above copyright
+#       notice, this list of conditions and the following disclaimer.
+#
+#     * Redistributions in binary form must reproduce the above copyright
+#       notice, this list of conditions and the following disclaimer in
+#       the documentation and/or other materials provided with the
+#       distribution.
+#
+#     * Neither the name of Intel Corporation nor the names of its
+#       contributors may be used to endorse or promote products derived
+#       from this software without specific prior written permission.
+#
+# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+#
+
+#
+# src/test/vmem_pool_create_in_region/Makefile -- build vmem_pool_create_in_region unit test
+#
+TARGET = vmem_pool_create_in_region
+OBJS = vmem_pool_create_in_region.o
+
+include ../Makefile.inc
+STATIC_DEBUG_LIBS = ../unittest/libut.a ../../debug/libvmem.a -luuid -pthread
+STATIC_NONDEBUG_LIBS = ../unittest/libut.a ../../nondebug/libvmem.a -luuid -pthread
+
+LIBS += -lvmem
+
+vmem_pool_create_in_region.o: vmem_pool_create_in_region.c
diff --git a/src/test/vmem_pool_create_in_region/TEST0 b/src/test/vmem_pool_create_in_region/TEST0
new file mode 100755
index 0000000000000000000000000000000000000000..f3267ab701ccb06ae85ba6d5aa8de9c7fc71c1da
--- /dev/null
+++ b/src/test/vmem_pool_create_in_region/TEST0
@@ -0,0 +1,51 @@
+#!/bin/bash -e
+#
+# Copyright (c) 2014, Intel Corporation
+#
+# Redistribution and use in source and binary forms, with or without
+# modification, are permitted provided that the following conditions
+# are met:
+#
+#     * Redistributions of source code must retain the above copyright
+#       notice, this list of conditions and the following disclaimer.
+#
+#     * Redistributions in binary form must reproduce the above copyright
+#       notice, this list of conditions and the following disclaimer in
+#       the documentation and/or other materials provided with the
+#       distribution.
+#
+#     * Neither the name of Intel Corporation nor the names of its
+#       contributors may be used to endorse or promote products derived
+#       from this software without specific prior written permission.
+#
+# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+#
+
+#
+# src/test/vmem_pool_create_in_region/TEST0 -- unit test for vmem_pool_create_in_region
+#
+export UNITTEST_NAME=vmem_pool_create_in_region/TEST0
+export UNITTEST_NUM=0
+
+# standard unit test setup
+. ../unittest/unittest.sh
+
+require_fs_type local
+
+setup
+
+expect_normal_exit ./vmem_pool_create_in_region$EXESUFFIX
+
+check
+
+pass
diff --git a/src/test/vmem_pool_create_in_region/err0.log.match b/src/test/vmem_pool_create_in_region/err0.log.match
new file mode 100644
index 0000000000000000000000000000000000000000..e69de29bb2d1d6434b8b29ae775ad8c2e48c5391
diff --git a/src/test/vmem_pool_create_in_region/out0.log.match b/src/test/vmem_pool_create_in_region/out0.log.match
new file mode 100644
index 0000000000000000000000000000000000000000..90811d75763352cbc79906152c2eeb41891525ab
--- /dev/null
+++ b/src/test/vmem_pool_create_in_region/out0.log.match
@@ -0,0 +1,3 @@
+vmem_pool_create_in_region/TEST0: START: vmem_pool_create_in_region
+ ./vmem_pool_create_in_region$(*)
+vmem_pool_create_in_region/TEST0: Done
diff --git a/src/test/vmem_pool_create_in_region/vmem_pool_create_in_region.c b/src/test/vmem_pool_create_in_region/vmem_pool_create_in_region.c
new file mode 100644
index 0000000000000000000000000000000000000000..31f4a892bc7f15f60944e7369a07526214698d8e
--- /dev/null
+++ b/src/test/vmem_pool_create_in_region/vmem_pool_create_in_region.c
@@ -0,0 +1,78 @@
+/*
+ * Copyright (c) 2014, Intel Corporation
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ *     * Redistributions of source code must retain the above copyright
+ *       notice, this list of conditions and the following disclaimer.
+ *
+ *     * Redistributions in binary form must reproduce the above copyright
+ *       notice, this list of conditions and the following disclaimer in
+ *       the documentation and/or other materials provided with the
+ *       distribution.
+ *
+ *     * Neither the name of Intel Corporation nor the names of its
+ *       contributors may be used to endorse or promote products derived
+ *       from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+/*
+ * vmem_pool_create_in_region.c -- unit test for vmem_pool_create_in_region
+ *
+ * usage: vmem_pool_create_in_region
+ */
+
+#include "unittest.h"
+
+#define	TEST_ALLOCATIONS (300)
+
+static char mem_pool[VMEM_MIN_POOL];
+static void *allocs[TEST_ALLOCATIONS];
+
+int
+main(int argc, char *argv[])
+{
+	VMEM *vmp;
+	size_t i;
+
+	START(argc, argv, "vmem_pool_create_in_region");
+
+	if (argc > 1)
+		FATAL("usage: %s", argv[0]);
+
+	vmp = vmem_pool_create_in_region(mem_pool, VMEM_MIN_POOL);
+
+	if (vmp == NULL)
+		FATAL("!vmem_pool_create_in_region");
+
+	for (i = 0; i < TEST_ALLOCATIONS; ++i) {
+		allocs[i] = vmem_malloc(vmp, sizeof (int));
+
+		ASSERTne(allocs[i], NULL);
+
+		/* check that pointer came from mem_pool */
+		ASSERTrange(allocs[i], mem_pool, VMEM_MIN_POOL);
+	}
+
+	for (i = 0; i < TEST_ALLOCATIONS; ++i) {
+		vmem_free(vmp, allocs[i]);
+	}
+
+	vmem_pool_delete(vmp);
+
+	DONE(NULL);
+}
diff --git a/src/test/vmem_realloc/.gitignore b/src/test/vmem_realloc/.gitignore
new file mode 100644
index 0000000000000000000000000000000000000000..74acfc67fc40a78ad170f08e28154afaafa8690c
--- /dev/null
+++ b/src/test/vmem_realloc/.gitignore
@@ -0,0 +1 @@
+vmem_realloc
diff --git a/src/test/vmem_realloc/Makefile b/src/test/vmem_realloc/Makefile
new file mode 100644
index 0000000000000000000000000000000000000000..eeb7022ffe975cd0993d98671f05ee31f295a0f2
--- /dev/null
+++ b/src/test/vmem_realloc/Makefile
@@ -0,0 +1,45 @@
+#
+# Copyright (c) 2014, Intel Corporation
+#
+# Redistribution and use in source and binary forms, with or without
+# modification, are permitted provided that the following conditions
+# are met:
+#
+#     * Redistributions of source code must retain the above copyright
+#       notice, this list of conditions and the following disclaimer.
+#
+#     * Redistributions in binary form must reproduce the above copyright
+#       notice, this list of conditions and the following disclaimer in
+#       the documentation and/or other materials provided with the
+#       distribution.
+#
+#     * Neither the name of Intel Corporation nor the names of its
+#       contributors may be used to endorse or promote products derived
+#       from this software without specific prior written permission.
+#
+# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+#
+
+#
+# src/test/vmem_realloc/Makefile -- build vmem_realloc unit test
+#
+TARGET = vmem_realloc
+OBJS = vmem_realloc.o
+
+include ../Makefile.inc
+STATIC_DEBUG_LIBS = ../unittest/libut.a ../../debug/libvmem.a -luuid -pthread
+STATIC_NONDEBUG_LIBS = ../unittest/libut.a ../../nondebug/libvmem.a -luuid -pthread
+
+LIBS += -lvmem
+
+vmem_realloc.o: vmem_realloc.c
diff --git a/src/test/vmem_realloc/TEST0 b/src/test/vmem_realloc/TEST0
new file mode 100755
index 0000000000000000000000000000000000000000..a3c21f67728c6c520edbed65daa16b2fc6e29a28
--- /dev/null
+++ b/src/test/vmem_realloc/TEST0
@@ -0,0 +1,51 @@
+#!/bin/bash -e
+#
+# Copyright (c) 2014, Intel Corporation
+#
+# Redistribution and use in source and binary forms, with or without
+# modification, are permitted provided that the following conditions
+# are met:
+#
+#     * Redistributions of source code must retain the above copyright
+#       notice, this list of conditions and the following disclaimer.
+#
+#     * Redistributions in binary form must reproduce the above copyright
+#       notice, this list of conditions and the following disclaimer in
+#       the documentation and/or other materials provided with the
+#       distribution.
+#
+#     * Neither the name of Intel Corporation nor the names of its
+#       contributors may be used to endorse or promote products derived
+#       from this software without specific prior written permission.
+#
+# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+#
+
+#
+# src/test/vmem_realloc/TEST0 -- unit test for vmem_realloc
+#
+export UNITTEST_NAME=vmem_realloc/TEST0
+export UNITTEST_NUM=0
+
+# standard unit test setup
+. ../unittest/unittest.sh
+
+require_fs_type local
+
+setup
+
+expect_normal_exit ./vmem_realloc$EXESUFFIX
+
+check
+
+pass
diff --git a/src/test/vmem_realloc/TEST1 b/src/test/vmem_realloc/TEST1
new file mode 100755
index 0000000000000000000000000000000000000000..7f1a6871da35a3ef08ec00f66666f93d181da26e
--- /dev/null
+++ b/src/test/vmem_realloc/TEST1
@@ -0,0 +1,51 @@
+#!/bin/bash -e
+#
+# Copyright (c) 2014, Intel Corporation
+#
+# Redistribution and use in source and binary forms, with or without
+# modification, are permitted provided that the following conditions
+# are met:
+#
+#     * Redistributions of source code must retain the above copyright
+#       notice, this list of conditions and the following disclaimer.
+#
+#     * Redistributions in binary form must reproduce the above copyright
+#       notice, this list of conditions and the following disclaimer in
+#       the documentation and/or other materials provided with the
+#       distribution.
+#
+#     * Neither the name of Intel Corporation nor the names of its
+#       contributors may be used to endorse or promote products derived
+#       from this software without specific prior written permission.
+#
+# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+#
+
+#
+# src/test/vmem_realloc/TEST1 -- unit test for vmem_realloc
+#
+export UNITTEST_NAME=vmem_realloc/TEST1
+export UNITTEST_NUM=1
+
+# standard unit test setup
+. ../unittest/unittest.sh
+
+require_fs_type pmem
+
+setup
+
+expect_normal_exit ./vmem_realloc$EXESUFFIX $DIR
+
+check
+
+pass
diff --git a/src/test/vmem_realloc/err0.log.match b/src/test/vmem_realloc/err0.log.match
new file mode 100644
index 0000000000000000000000000000000000000000..e69de29bb2d1d6434b8b29ae775ad8c2e48c5391
diff --git a/src/test/vmem_realloc/err1.log.match b/src/test/vmem_realloc/err1.log.match
new file mode 100644
index 0000000000000000000000000000000000000000..e69de29bb2d1d6434b8b29ae775ad8c2e48c5391
diff --git a/src/test/vmem_realloc/out0.log.match b/src/test/vmem_realloc/out0.log.match
new file mode 100644
index 0000000000000000000000000000000000000000..848c103835cd5cda7843694c63cf5b67e3788b39
--- /dev/null
+++ b/src/test/vmem_realloc/out0.log.match
@@ -0,0 +1,3 @@
+vmem_realloc/TEST0: START: vmem_realloc
+ ./vmem_realloc$(*)
+vmem_realloc/TEST0: Done
diff --git a/src/test/vmem_realloc/out1.log.match b/src/test/vmem_realloc/out1.log.match
new file mode 100644
index 0000000000000000000000000000000000000000..3e6cef7563a1fe6ee3305af13156eac8bbaedc4b
--- /dev/null
+++ b/src/test/vmem_realloc/out1.log.match
@@ -0,0 +1,3 @@
+vmem_realloc/TEST1: START: vmem_realloc
+ ./vmem_realloc$(*)
+vmem_realloc/TEST1: Done
diff --git a/src/test/vmem_realloc/vmem_realloc.c b/src/test/vmem_realloc/vmem_realloc.c
new file mode 100644
index 0000000000000000000000000000000000000000..c733e02c27e888f849ee17dc340966eb18ee49d1
--- /dev/null
+++ b/src/test/vmem_realloc/vmem_realloc.c
@@ -0,0 +1,95 @@
+/*
+ * Copyright (c) 2014, Intel Corporation
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ *     * Redistributions of source code must retain the above copyright
+ *       notice, this list of conditions and the following disclaimer.
+ *
+ *     * Redistributions in binary form must reproduce the above copyright
+ *       notice, this list of conditions and the following disclaimer in
+ *       the documentation and/or other materials provided with the
+ *       distribution.
+ *
+ *     * Neither the name of Intel Corporation nor the names of its
+ *       contributors may be used to endorse or promote products derived
+ *       from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+/*
+ * vmem_realloc -- unit test for vmem_realloc
+ *
+ * usage: vmem_realloc [directory]
+ */
+
+#include "unittest.h"
+
+static char mem_pool[VMEM_MIN_POOL];
+
+int
+main(int argc, char *argv[])
+{
+	const int test_value = 123456;
+	char *dir = NULL;
+	VMEM *vmp;
+
+	START(argc, argv, "vmem_realloc");
+
+	if (argc == 2) {
+		dir = argv[1];
+	} else if (argc > 2) {
+		FATAL("usage: %s [directory]", argv[0]);
+	}
+
+	if (dir == NULL) {
+		vmp = vmem_pool_create_in_region(mem_pool, VMEM_MIN_POOL);
+		if (vmp == NULL)
+			FATAL("!vmem_pool_create_in_region");
+	} else {
+		vmp = vmem_pool_create(dir, VMEM_MIN_POOL);
+		if (vmp == NULL)
+			FATAL("!vmem_pool_create");
+	}
+
+	int *test = vmem_realloc(vmp, NULL, sizeof (int));
+	ASSERTne(test, NULL);
+
+	test[0] = test_value;
+	ASSERTeq(test[0], test_value);
+
+	/* check that pointer came from mem_pool */
+	if (dir == NULL) {
+		ASSERTrange(test, mem_pool, VMEM_MIN_POOL);
+	}
+
+	test = vmem_realloc(vmp, test, sizeof (int) * 10);
+	ASSERTne(test, NULL);
+	ASSERTeq(test[0], test_value);
+	test[1] = test_value;
+	test[9] = test_value;
+
+	/* check that pointer came from mem_pool */
+	if (dir == NULL) {
+		ASSERTrange(test, mem_pool, VMEM_MIN_POOL);
+	}
+
+	vmem_free(vmp, test);
+
+	vmem_pool_delete(vmp);
+
+	DONE(NULL);
+}
diff --git a/src/test/vmem_stats/.gitignore b/src/test/vmem_stats/.gitignore
new file mode 100644
index 0000000000000000000000000000000000000000..423df3395e2152247f95d238c161a1b1fa4de488
--- /dev/null
+++ b/src/test/vmem_stats/.gitignore
@@ -0,0 +1 @@
+vmem_stats
diff --git a/src/test/vmem_stats/Makefile b/src/test/vmem_stats/Makefile
new file mode 100644
index 0000000000000000000000000000000000000000..e25b71d458f0ced72b98fcc5764de4d61897dc2d
--- /dev/null
+++ b/src/test/vmem_stats/Makefile
@@ -0,0 +1,45 @@
+#
+# Copyright (c) 2014, Intel Corporation
+#
+# Redistribution and use in source and binary forms, with or without
+# modification, are permitted provided that the following conditions
+# are met:
+#
+#     * Redistributions of source code must retain the above copyright
+#       notice, this list of conditions and the following disclaimer.
+#
+#     * Redistributions in binary form must reproduce the above copyright
+#       notice, this list of conditions and the following disclaimer in
+#       the documentation and/or other materials provided with the
+#       distribution.
+#
+#     * Neither the name of Intel Corporation nor the names of its
+#       contributors may be used to endorse or promote products derived
+#       from this software without specific prior written permission.
+#
+# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+#
+
+#
+# src/test/vmem_stats/Makefile -- build vmem_stats unit test
+#
+TARGET = vmem_stats
+OBJS = vmem_stats.o
+
+include ../Makefile.inc
+STATIC_DEBUG_LIBS = ../unittest/libut.a ../../debug/libvmem.a -luuid -pthread
+STATIC_NONDEBUG_LIBS = ../unittest/libut.a ../../nondebug/libvmem.a -luuid -pthread
+
+LIBS += -lvmem
+
+vmem_stats.o: vmem_stats.c
diff --git a/src/test/vmem_stats/TEST0 b/src/test/vmem_stats/TEST0
new file mode 100755
index 0000000000000000000000000000000000000000..6817dba47afe1f6f1d82c1970c1cff7237ef6ff6
--- /dev/null
+++ b/src/test/vmem_stats/TEST0
@@ -0,0 +1,52 @@
+#!/bin/bash -e
+#
+# Copyright (c) 2014, Intel Corporation
+#
+# Redistribution and use in source and binary forms, with or without
+# modification, are permitted provided that the following conditions
+# are met:
+#
+#     * Redistributions of source code must retain the above copyright
+#       notice, this list of conditions and the following disclaimer.
+#
+#     * Redistributions in binary form must reproduce the above copyright
+#       notice, this list of conditions and the following disclaimer in
+#       the documentation and/or other materials provided with the
+#       distribution.
+#
+#     * Neither the name of Intel Corporation nor the names of its
+#       contributors may be used to endorse or promote products derived
+#       from this software without specific prior written permission.
+#
+# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+#
+
+#
+# src/test/vmem_stats/TEST0 -- unit test for vmem_stats
+#
+export UNITTEST_NAME=vmem_stats/TEST0
+export UNITTEST_NUM=0
+
+# standard unit test setup
+. ../unittest/unittest.sh
+
+require_fs_type local
+require_build_type debug
+
+setup
+
+expect_normal_exit ./vmem_stats$EXESUFFIX
+
+check
+
+pass
diff --git a/src/test/vmem_stats/TEST1 b/src/test/vmem_stats/TEST1
new file mode 100755
index 0000000000000000000000000000000000000000..353462ee911357330b5904e3305cd24124983a13
--- /dev/null
+++ b/src/test/vmem_stats/TEST1
@@ -0,0 +1,52 @@
+#!/bin/bash -e
+#
+# Copyright (c) 2014, Intel Corporation
+#
+# Redistribution and use in source and binary forms, with or without
+# modification, are permitted provided that the following conditions
+# are met:
+#
+#     * Redistributions of source code must retain the above copyright
+#       notice, this list of conditions and the following disclaimer.
+#
+#     * Redistributions in binary form must reproduce the above copyright
+#       notice, this list of conditions and the following disclaimer in
+#       the documentation and/or other materials provided with the
+#       distribution.
+#
+#     * Neither the name of Intel Corporation nor the names of its
+#       contributors may be used to endorse or promote products derived
+#       from this software without specific prior written permission.
+#
+# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+#
+
+#
+# src/test/vmem_stats/TEST1 -- unit test for vmem_stats
+#
+export UNITTEST_NAME=vmem_stats/TEST1
+export UNITTEST_NUM=1
+
+# standard unit test setup
+. ../unittest/unittest.sh
+
+require_fs_type local
+require_build_type debug
+
+setup
+
+expect_normal_exit ./vmem_stats$EXESUFFIX g
+
+check
+
+pass
diff --git a/src/test/vmem_stats/TEST2 b/src/test/vmem_stats/TEST2
new file mode 100755
index 0000000000000000000000000000000000000000..e8baf5da0a2862426194bf641bb0c10e655af4d7
--- /dev/null
+++ b/src/test/vmem_stats/TEST2
@@ -0,0 +1,52 @@
+#!/bin/bash -e
+#
+# Copyright (c) 2014, Intel Corporation
+#
+# Redistribution and use in source and binary forms, with or without
+# modification, are permitted provided that the following conditions
+# are met:
+#
+#     * Redistributions of source code must retain the above copyright
+#       notice, this list of conditions and the following disclaimer.
+#
+#     * Redistributions in binary form must reproduce the above copyright
+#       notice, this list of conditions and the following disclaimer in
+#       the documentation and/or other materials provided with the
+#       distribution.
+#
+#     * Neither the name of Intel Corporation nor the names of its
+#       contributors may be used to endorse or promote products derived
+#       from this software without specific prior written permission.
+#
+# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+#
+
+#
+# src/test/vmem_stats/TEST2 -- unit test for vmem_stats
+#
+export UNITTEST_NAME=vmem_stats/TEST2
+export UNITTEST_NUM=2
+
+# standard unit test setup
+. ../unittest/unittest.sh
+
+require_fs_type local
+require_build_type debug
+
+setup
+
+expect_normal_exit ./vmem_stats$EXESUFFIX gbl
+
+check
+
+pass
diff --git a/src/test/vmem_stats/TEST3 b/src/test/vmem_stats/TEST3
new file mode 100755
index 0000000000000000000000000000000000000000..b1e5fc57ecfe1f8f3ec01e6902bf669327af2733
--- /dev/null
+++ b/src/test/vmem_stats/TEST3
@@ -0,0 +1,52 @@
+#!/bin/bash -e
+#
+# Copyright (c) 2014, Intel Corporation
+#
+# Redistribution and use in source and binary forms, with or without
+# modification, are permitted provided that the following conditions
+# are met:
+#
+#     * Redistributions of source code must retain the above copyright
+#       notice, this list of conditions and the following disclaimer.
+#
+#     * Redistributions in binary form must reproduce the above copyright
+#       notice, this list of conditions and the following disclaimer in
+#       the documentation and/or other materials provided with the
+#       distribution.
+#
+#     * Neither the name of Intel Corporation nor the names of its
+#       contributors may be used to endorse or promote products derived
+#       from this software without specific prior written permission.
+#
+# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+#
+
+#
+# src/test/vmem_stats/TEST3 -- unit test for vmem_stats
+#
+export UNITTEST_NAME=vmem_stats/TEST3
+export UNITTEST_NUM=3
+
+# standard unit test setup
+. ../unittest/unittest.sh
+
+require_fs_type local
+require_build_type debug
+
+setup
+
+expect_normal_exit ./vmem_stats$EXESUFFIX gbla
+
+check
+
+pass
diff --git a/src/test/vmem_stats/TEST4 b/src/test/vmem_stats/TEST4
new file mode 100755
index 0000000000000000000000000000000000000000..12caedf65a5ab9c8ad0e342f2614ad4a7572a740
--- /dev/null
+++ b/src/test/vmem_stats/TEST4
@@ -0,0 +1,52 @@
+#!/bin/bash -e
+#
+# Copyright (c) 2014, Intel Corporation
+#
+# Redistribution and use in source and binary forms, with or without
+# modification, are permitted provided that the following conditions
+# are met:
+#
+#     * Redistributions of source code must retain the above copyright
+#       notice, this list of conditions and the following disclaimer.
+#
+#     * Redistributions in binary form must reproduce the above copyright
+#       notice, this list of conditions and the following disclaimer in
+#       the documentation and/or other materials provided with the
+#       distribution.
+#
+#     * Neither the name of Intel Corporation nor the names of its
+#       contributors may be used to endorse or promote products derived
+#       from this software without specific prior written permission.
+#
+# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+#
+
+#
+# src/test/vmem_stats/TEST4 -- unit test for vmem_stats
+#
+export UNITTEST_NAME=vmem_stats/TEST4
+export UNITTEST_NUM=4
+
+# standard unit test setup
+. ../unittest/unittest.sh
+
+require_fs_type local
+require_build_type debug
+
+setup
+
+expect_normal_exit ./vmem_stats$EXESUFFIX gblma
+
+check
+
+pass
diff --git a/src/test/vmem_stats/vmem0.log.match b/src/test/vmem_stats/vmem0.log.match
new file mode 100644
index 0000000000000000000000000000000000000000..f51c5462724202fb5b92a95925b92ed3379659d2
--- /dev/null
+++ b/src/test/vmem_stats/vmem0.log.match
@@ -0,0 +1,61 @@
+<libvmem>: $(*)
+<libvmem>: $(*)
+<libvmem>: $(*)
+<libvmem>: $(*)
+<libvmem>: $(*)
+<libvmem>: $(*)
+<libvmem>: $(*)
+<libvmem>: $(*)
+<libvmem>: $(*)
+<libvmem>: $(*)
+<libvmem>: $(*)
+___ Begin jemalloc statistics ___
+Version:$(*)
+Assertions enabled
+Run-time option settings:
+  opt.abort: $(*)
+  opt.lg_chunk: $(*)
+  opt.dss: $(*)
+  opt.narenas: $(*)
+  opt.lg_dirty_mult: $(*)
+  opt.stats_print: $(*)
+  opt.junk: $(*)
+  opt.quarantine: $(*)
+  opt.redzone: $(*)
+  opt.zero: $(*)
+  opt.tcache: $(*)
+  opt.lg_tcache_max: $(*)
+CPUs: $(*)
+Arenas: $(*)
+Pointer size: $(*)
+Quantum size: $(*)
+Page size: $(*)
+Min active:dirty page ratio per arena: $(*)
+Chunk size: $(*)
+Allocated: $(*), active: $(*), mapped: $(*)
+Current active ceiling: $(*)
+chunks: nchunks   highchunks    curchunks
+              $(*)            $(*)            $(*)
+
+arenas[0]:
+assigned threads: $(*)
+dss allocation precedence: secondary
+dirty pages: $(*):$(*) active:dirty, $(*) sweeps, $(*) madvises, $(*) purged
+            allocated      nmalloc      ndalloc    nrequests
+small:          $(*)           $(*)            $(*)            $(*)
+large:          $(*)            $(*)            $(*)            $(*)
+huge:               $(*)            $(*)            $(*)            $(*)
+total:          $(*)           $(*)            $(*)            $(*)
+active:         $(*)
+mapped:       $(*)
+bins:     bin  size regs pgs    allocated      nmalloc      ndalloc    nrequests       nfills     nflushes      newruns       reruns      curruns
+[0..$(*)]
+           $(*)   $(*)   $(*)   $(*)        $(*)           $(*)            $(*)            $(*)            $(*)            $(*)            $(*)            $(*)            $(*)
+[$(*)..$(*)]
+large:   size pages      nmalloc      ndalloc    nrequests      curruns
+[$(*)]
+        $(*)     $(*)            $(*)            $(*)            $(*)            $(*)
+[$(*)]
+--- End jemalloc statistics ---
+<libvmem>: $(*)
+<libvmem>: $(*)
diff --git a/src/test/vmem_stats/vmem1.log.match b/src/test/vmem_stats/vmem1.log.match
new file mode 100644
index 0000000000000000000000000000000000000000..66ace582fa80549aefe173bf1b62fdffba7a413e
--- /dev/null
+++ b/src/test/vmem_stats/vmem1.log.match
@@ -0,0 +1,39 @@
+<libvmem>: $(*)
+<libvmem>: $(*)
+<libvmem>: $(*)
+<libvmem>: $(*)
+<libvmem>: $(*)
+<libvmem>: $(*)
+<libvmem>: $(*)
+<libvmem>: $(*)
+<libvmem>: $(*)
+<libvmem>: $(*)
+<libvmem>: $(*)
+___ Begin jemalloc statistics ___
+Allocated: $(*), active: $(*), mapped: $(*)
+Current active ceiling: $(*)
+chunks: nchunks   highchunks    curchunks
+              $(*)            $(*)            $(*)
+
+arenas[0]:
+assigned threads: $(*)
+dss allocation precedence: secondary
+dirty pages: $(*):$(*) active:dirty, $(*) sweeps, $(*) madvises, $(*) purged
+            allocated      nmalloc      ndalloc    nrequests
+small:          $(*)           $(*)            $(*)            $(*)
+large:          $(*)            $(*)            $(*)            $(*)
+huge:               $(*)            $(*)            $(*)            $(*)
+total:          $(*)           $(*)            $(*)            $(*)
+active:         $(*)
+mapped:       $(*)
+bins:     bin  size regs pgs    allocated      nmalloc      ndalloc    nrequests       nfills     nflushes      newruns       reruns      curruns
+[0..$(*)]
+           $(*)   $(*)   $(*)   $(*)        $(*)           $(*)            $(*)            $(*)            $(*)            $(*)            $(*)            $(*)            $(*)
+[$(*)..$(*)]
+large:   size pages      nmalloc      ndalloc    nrequests      curruns
+[$(*)]
+        $(*)     $(*)            $(*)            $(*)            $(*)            $(*)
+[$(*)]
+--- End jemalloc statistics ---
+<libvmem>: $(*)
+<libvmem>: $(*)
diff --git a/src/test/vmem_stats/vmem2.log.match b/src/test/vmem_stats/vmem2.log.match
new file mode 100644
index 0000000000000000000000000000000000000000..f8566e93d2799f06627d219d6b4af37069beba88
--- /dev/null
+++ b/src/test/vmem_stats/vmem2.log.match
@@ -0,0 +1,31 @@
+<libvmem>: $(*)
+<libvmem>: $(*)
+<libvmem>: $(*)
+<libvmem>: $(*)
+<libvmem>: $(*)
+<libvmem>: $(*)
+<libvmem>: $(*)
+<libvmem>: $(*)
+<libvmem>: $(*)
+<libvmem>: $(*)
+<libvmem>: $(*)
+___ Begin jemalloc statistics ___
+Allocated: $(*), active: $(*), mapped: $(*)
+Current active ceiling: $(*)
+chunks: nchunks   highchunks    curchunks
+              $(*)            $(*)            $(*)
+
+arenas[0]:
+assigned threads: $(*)
+dss allocation precedence: secondary
+dirty pages: $(*):$(*) active:dirty, $(*) sweeps, $(*) madvises, $(*) purged
+            allocated      nmalloc      ndalloc    nrequests
+small:          $(*)           $(*)            $(*)            $(*)
+large:          $(*)            $(*)            $(*)            $(*)
+huge:               $(*)            $(*)            $(*)            $(*)
+total:          $(*)           $(*)            $(*)            $(*)
+active:         $(*)
+mapped:       $(*)
+--- End jemalloc statistics ---
+<libvmem>: $(*)
+<libvmem>: $(*)
diff --git a/src/test/vmem_stats/vmem3.log.match b/src/test/vmem_stats/vmem3.log.match
new file mode 100644
index 0000000000000000000000000000000000000000..6a78ff98450056323e84bf8499db116ba6a21ddc
--- /dev/null
+++ b/src/test/vmem_stats/vmem3.log.match
@@ -0,0 +1,31 @@
+<libvmem>: $(*)
+<libvmem>: $(*)
+<libvmem>: $(*)
+<libvmem>: $(*)
+<libvmem>: $(*)
+<libvmem>: $(*)
+<libvmem>: $(*)
+<libvmem>: $(*)
+<libvmem>: $(*)
+<libvmem>: $(*)
+<libvmem>: $(*)
+___ Begin jemalloc statistics ___
+Allocated: $(*), active: $(*), mapped: $(*)
+Current active ceiling: $(*)
+chunks: nchunks   highchunks    curchunks
+              $(*)            $(*)            $(*)
+
+Merged arenas stats:
+assigned threads: $(*)
+dss allocation precedence: $(*)
+dirty pages: $(*):$(*) active:dirty, $(*) sweeps, $(*) madvises, $(*) purged
+            allocated      nmalloc      ndalloc    nrequests
+small:          $(*)           $(*)            $(*)            $(*)
+large:          $(*)            $(*)            $(*)            $(*)
+huge:               $(*)            $(*)            $(*)            $(*)
+total:          $(*)           $(*)            $(*)            $(*)
+active:         $(*)
+mapped:       $(*)
+--- End jemalloc statistics ---
+<libvmem>: $(*)
+<libvmem>: $(*)
diff --git a/src/test/vmem_stats/vmem4.log.match b/src/test/vmem_stats/vmem4.log.match
new file mode 100644
index 0000000000000000000000000000000000000000..46fdb1ec2f81b0e21df756cc92772f6724d989b1
--- /dev/null
+++ b/src/test/vmem_stats/vmem4.log.match
@@ -0,0 +1,19 @@
+<libvmem>: $(*)
+<libvmem>: $(*)
+<libvmem>: $(*)
+<libvmem>: $(*)
+<libvmem>: $(*)
+<libvmem>: $(*)
+<libvmem>: $(*)
+<libvmem>: $(*)
+<libvmem>: $(*)
+<libvmem>: $(*)
+<libvmem>: $(*)
+___ Begin jemalloc statistics ___
+Allocated: $(*), active: $(*), mapped: $(*)
+Current active ceiling: $(*)
+chunks: nchunks   highchunks    curchunks
+              $(*)            $(*)            $(*)
+--- End jemalloc statistics ---
+<libvmem>: $(*)
+<libvmem>: $(*)
diff --git a/src/test/vmem_stats/vmem_stats.c b/src/test/vmem_stats/vmem_stats.c
new file mode 100644
index 0000000000000000000000000000000000000000..68b85c8f2a8aeca9e4697612cab1345ac363ac72
--- /dev/null
+++ b/src/test/vmem_stats/vmem_stats.c
@@ -0,0 +1,77 @@
+/*
+ * Copyright (c) 2014, Intel Corporation
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ *     * Redistributions of source code must retain the above copyright
+ *       notice, this list of conditions and the following disclaimer.
+ *
+ *     * Redistributions in binary form must reproduce the above copyright
+ *       notice, this list of conditions and the following disclaimer in
+ *       the documentation and/or other materials provided with the
+ *       distribution.
+ *
+ *     * Neither the name of Intel Corporation nor the names of its
+ *       contributors may be used to endorse or promote products derived
+ *       from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+/*
+ * vmem_stats.c -- unit test for vmem_stats
+ *
+ * usage: vmem_stats [opts]
+ */
+
+#include "unittest.h"
+
+static char mem_pool[VMEM_MIN_POOL];
+#define TEST_VALUE 1234
+
+int
+main(int argc, char *argv[])
+{
+	char *opts = "";
+	VMEM *vmp;
+
+	START(argc, argv, "vmem_stats");
+
+	if (argc == 2) {
+		opts = argv[1];
+	} else if (argc > 2) {
+		FATAL("usage: %s [opts]", argv[0]);
+	}
+
+	vmp = vmem_pool_create_in_region(mem_pool, VMEM_MIN_POOL);
+	if (vmp == NULL)
+		FATAL("!vmem_pool_create_in_region");
+
+	int *test = vmem_malloc(vmp, sizeof (int)*100);
+	ASSERTne(test, NULL);
+
+	*test = TEST_VALUE;
+	ASSERTeq(*test, TEST_VALUE);
+
+	ASSERTrange(test, mem_pool, VMEM_MIN_POOL);
+
+	vmem_pool_stats_print(vmp, opts);
+
+	vmem_free(vmp, test);
+
+	vmem_pool_delete(vmp);
+
+	DONE(NULL);
+}
diff --git a/src/test/vmem_strdup/.gitignore b/src/test/vmem_strdup/.gitignore
new file mode 100644
index 0000000000000000000000000000000000000000..bb836d6020bf585f73c018abbb9abe4439e1ffb5
--- /dev/null
+++ b/src/test/vmem_strdup/.gitignore
@@ -0,0 +1 @@
+vmem_strdup
diff --git a/src/test/vmem_strdup/Makefile b/src/test/vmem_strdup/Makefile
new file mode 100644
index 0000000000000000000000000000000000000000..c1fc674daed0ce7aa1450f4ac65ad8fc56b479a0
--- /dev/null
+++ b/src/test/vmem_strdup/Makefile
@@ -0,0 +1,45 @@
+#
+# Copyright (c) 2014, Intel Corporation
+#
+# Redistribution and use in source and binary forms, with or without
+# modification, are permitted provided that the following conditions
+# are met:
+#
+#     * Redistributions of source code must retain the above copyright
+#       notice, this list of conditions and the following disclaimer.
+#
+#     * Redistributions in binary form must reproduce the above copyright
+#       notice, this list of conditions and the following disclaimer in
+#       the documentation and/or other materials provided with the
+#       distribution.
+#
+#     * Neither the name of Intel Corporation nor the names of its
+#       contributors may be used to endorse or promote products derived
+#       from this software without specific prior written permission.
+#
+# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+#
+
+#
+# src/test/vmem_strdup/Makefile -- build vmem_strdup unit test
+#
+TARGET = vmem_strdup
+OBJS =vmem_strdup.o
+
+include ../Makefile.inc
+STATIC_DEBUG_LIBS = ../unittest/libut.a ../../debug/libvmem.a -luuid -pthread
+STATIC_NONDEBUG_LIBS = ../unittest/libut.a ../../nondebug/libvmem.a -luuid -pthread
+
+LIBS += -lvmem
+
+vmem_strdup.o: vmem_strdup.c
diff --git a/src/test/vmem_strdup/TEST0 b/src/test/vmem_strdup/TEST0
new file mode 100755
index 0000000000000000000000000000000000000000..27d32313e684284e746e90013474c92bf93f032a
--- /dev/null
+++ b/src/test/vmem_strdup/TEST0
@@ -0,0 +1,51 @@
+#!/bin/bash -e
+#
+# Copyright (c) 2014, Intel Corporation
+#
+# Redistribution and use in source and binary forms, with or without
+# modification, are permitted provided that the following conditions
+# are met:
+#
+#     * Redistributions of source code must retain the above copyright
+#       notice, this list of conditions and the following disclaimer.
+#
+#     * Redistributions in binary form must reproduce the above copyright
+#       notice, this list of conditions and the following disclaimer in
+#       the documentation and/or other materials provided with the
+#       distribution.
+#
+#     * Neither the name of Intel Corporation nor the names of its
+#       contributors may be used to endorse or promote products derived
+#       from this software without specific prior written permission.
+#
+# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+#
+
+#
+# src/test/vmem_strdup/TEST0 -- unit test for vmem_strdup
+#
+export UNITTEST_NAME=vmem_strdup/TEST0
+export UNITTEST_NUM=0
+
+# standard unit test setup
+. ../unittest/unittest.sh
+
+require_fs_type local
+
+setup
+
+expect_normal_exit ./vmem_strdup$EXESUFFIX
+
+check
+
+pass
diff --git a/src/test/vmem_strdup/TEST1 b/src/test/vmem_strdup/TEST1
new file mode 100755
index 0000000000000000000000000000000000000000..e569b85540fc2d6f9a80502a8a93ec7be4203793
--- /dev/null
+++ b/src/test/vmem_strdup/TEST1
@@ -0,0 +1,51 @@
+#!/bin/bash -e
+#
+# Copyright (c) 2014, Intel Corporation
+#
+# Redistribution and use in source and binary forms, with or without
+# modification, are permitted provided that the following conditions
+# are met:
+#
+#     * Redistributions of source code must retain the above copyright
+#       notice, this list of conditions and the following disclaimer.
+#
+#     * Redistributions in binary form must reproduce the above copyright
+#       notice, this list of conditions and the following disclaimer in
+#       the documentation and/or other materials provided with the
+#       distribution.
+#
+#     * Neither the name of Intel Corporation nor the names of its
+#       contributors may be used to endorse or promote products derived
+#       from this software without specific prior written permission.
+#
+# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+#
+
+#
+# src/test/vmem_strdup/TEST1 -- unit test for vmem_strdup
+#
+export UNITTEST_NAME=vmem_strdup/TEST1
+export UNITTEST_NUM=1
+
+# standard unit test setup
+. ../unittest/unittest.sh
+
+require_fs_type pmem
+
+setup
+
+expect_normal_exit ./vmem_strdup$EXESUFFIX $DIR
+
+check
+
+pass
diff --git a/src/test/vmem_strdup/err0.log.match b/src/test/vmem_strdup/err0.log.match
new file mode 100644
index 0000000000000000000000000000000000000000..e69de29bb2d1d6434b8b29ae775ad8c2e48c5391
diff --git a/src/test/vmem_strdup/err1.log.match b/src/test/vmem_strdup/err1.log.match
new file mode 100644
index 0000000000000000000000000000000000000000..e69de29bb2d1d6434b8b29ae775ad8c2e48c5391
diff --git a/src/test/vmem_strdup/out0.log.match b/src/test/vmem_strdup/out0.log.match
new file mode 100644
index 0000000000000000000000000000000000000000..36520dd812e14e0c8a60847bd85cf85395e4cb2c
--- /dev/null
+++ b/src/test/vmem_strdup/out0.log.match
@@ -0,0 +1,3 @@
+vmem_strdup/TEST0: START: vmem_strdup
+ ./vmem_strdup$(*)
+vmem_strdup/TEST0: Done
diff --git a/src/test/vmem_strdup/out1.log.match b/src/test/vmem_strdup/out1.log.match
new file mode 100644
index 0000000000000000000000000000000000000000..5cbcb0ad6bc538a2b4517ee2e2955b9bbc0c60aa
--- /dev/null
+++ b/src/test/vmem_strdup/out1.log.match
@@ -0,0 +1,3 @@
+vmem_strdup/TEST1: START: vmem_strdup
+ ./vmem_strdup$(*)
+vmem_strdup/TEST1: Done
diff --git a/src/test/vmem_strdup/vmem_strdup.c b/src/test/vmem_strdup/vmem_strdup.c
new file mode 100644
index 0000000000000000000000000000000000000000..8eb0bcadd237917904405d832b30cf5da5d0fb95
--- /dev/null
+++ b/src/test/vmem_strdup/vmem_strdup.c
@@ -0,0 +1,93 @@
+/*
+ * Copyright (c) 2014, Intel Corporation
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ *     * Redistributions of source code must retain the above copyright
+ *       notice, this list of conditions and the following disclaimer.
+ *
+ *     * Redistributions in binary form must reproduce the above copyright
+ *       notice, this list of conditions and the following disclaimer in
+ *       the documentation and/or other materials provided with the
+ *       distribution.
+ *
+ *     * Neither the name of Intel Corporation nor the names of its
+ *       contributors may be used to endorse or promote products derived
+ *       from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+/*
+ * vmem_strdup.c -- unit test for vmem_strdup
+ *
+ * usage: vmem_strdup [directory]
+ */
+
+#include "unittest.h"
+
+static char mem_pool[VMEM_MIN_POOL];
+
+int
+main(int argc, char *argv[])
+{
+	const char *text = "Some test text";
+	const char *text_empty = "";
+	char *dir = NULL;
+	VMEM *vmp;
+
+	START(argc, argv, "vmem_strdup");
+
+	if (argc == 2) {
+		dir = argv[1];
+	} else if (argc > 2) {
+		FATAL("usage: %s [directory]", argv[0]);
+	}
+
+	if (dir == NULL) {
+		vmp = vmem_pool_create_in_region(mem_pool, VMEM_MIN_POOL);
+		if (vmp == NULL)
+			FATAL("!vmem_pool_create_in_region");
+	} else {
+		vmp = vmem_pool_create(dir, VMEM_MIN_POOL);
+		if (vmp == NULL)
+			FATAL("!vmem_pool_create");
+	}
+
+	char *str1 = vmem_strdup(vmp, text);
+	ASSERTne(str1, NULL);
+	ASSERTeq(strcmp(text, str1), 0);
+
+	/* check that pointer came from mem_pool */
+	if (dir == NULL) {
+		ASSERTrange(str1, mem_pool, VMEM_MIN_POOL);
+	}
+
+	char *str2 = vmem_strdup(vmp, text_empty);
+	ASSERTne(str2, NULL);
+	ASSERTeq(strcmp(text_empty, str2), 0);
+
+	/* check that pointer came from mem_pool */
+	if (dir == NULL) {
+		ASSERTrange(str2, mem_pool, VMEM_MIN_POOL);
+	}
+
+	vmem_free(vmp, str1);
+	vmem_free(vmp, str2);
+
+	vmem_pool_delete(vmp);
+
+	DONE(NULL);
+}
diff --git a/src/test/vmem_valgrind/.gitignore b/src/test/vmem_valgrind/.gitignore
new file mode 100644
index 0000000000000000000000000000000000000000..c4740f5b7c85cf7f95c8d68db804e201e9906f25
--- /dev/null
+++ b/src/test/vmem_valgrind/.gitignore
@@ -0,0 +1 @@
+vmem_valgrind
diff --git a/src/test/vmem_valgrind/Makefile b/src/test/vmem_valgrind/Makefile
new file mode 100644
index 0000000000000000000000000000000000000000..9d76faf181e7f4bf7f9155c53a31ba7d6ade7035
--- /dev/null
+++ b/src/test/vmem_valgrind/Makefile
@@ -0,0 +1,46 @@
+#
+# Copyright (c) 2014, Intel Corporation
+#
+# Redistribution and use in source and binary forms, with or without
+# modification, are permitted provided that the following conditions
+# are met:
+#
+#     * Redistributions of source code must retain the above copyright
+#       notice, this list of conditions and the following disclaimer.
+#
+#     * Redistributions in binary form must reproduce the above copyright
+#       notice, this list of conditions and the following disclaimer in
+#       the documentation and/or other materials provided with the
+#       distribution.
+#
+#     * Neither the name of Intel Corporation nor the names of its
+#       contributors may be used to endorse or promote products derived
+#       from this software without specific prior written permission.
+#
+# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+#
+
+#
+# src/test/vmem_valgrind/Makefile -- build vmem_valgrind unit test
+#
+TARGET = vmem_valgrind
+OBJS =vmem_valgrind.o
+
+include ../Makefile.inc
+STATIC_DEBUG_LIBS = ../unittest/libut.a ../../debug/libvmem.a -luuid -pthread
+STATIC_NONDEBUG_LIBS = ../unittest/libut.a ../../nondebug/libvmem.a -luuid -pthread
+
+LIBS += -lvmem
+
+vmem_valgrind.o: vmem_valgrind.c
+
diff --git a/src/test/vmem_valgrind/TEST0 b/src/test/vmem_valgrind/TEST0
new file mode 100755
index 0000000000000000000000000000000000000000..c9cb64bd6414731f97a5a0c8ec757ec31ac59693
--- /dev/null
+++ b/src/test/vmem_valgrind/TEST0
@@ -0,0 +1,59 @@
+#!/bin/bash -e
+#
+# Copyright (c) 2014, Intel Corporation
+#
+# Redistribution and use in source and binary forms, with or without
+# modification, are permitted provided that the following conditions
+# are met:
+#
+#     * Redistributions of source code must retain the above copyright
+#       notice, this list of conditions and the following disclaimer.
+#
+#     * Redistributions in binary form must reproduce the above copyright
+#       notice, this list of conditions and the following disclaimer in
+#       the documentation and/or other materials provided with the
+#       distribution.
+#
+#     * Neither the name of Intel Corporation nor the names of its
+#       contributors may be used to endorse or promote products derived
+#       from this software without specific prior written permission.
+#
+# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+#
+
+#
+# src/test/vmem_valgrind/TEST0 -- unit test for vmem_valgrind
+#
+export UNITTEST_NAME=vmem_valgrind/TEST0
+export UNITTEST_NUM=0
+
+# standard unit test setup
+. ../unittest/unittest.sh
+
+. ./valgrind_check.sh
+
+require_fs_type local pmem
+require_build_type debug nondebug
+require_valgrind_dev
+
+setup
+
+export VMEM_LOG_LEVEL=0
+unset VMEM_LOG_FILE
+[ "$FS" == "pmem" ] && DIR_WORK=$DIR
+
+expect_normal_exit valgrind --leak-check=full --show-reachable=yes --log-file=valgrind$UNITTEST_NUM.log ./vmem_valgrind$EXESUFFIX 0 $DIR_WORK
+
+check
+
+pass
diff --git a/src/test/vmem_valgrind/TEST1 b/src/test/vmem_valgrind/TEST1
new file mode 100755
index 0000000000000000000000000000000000000000..b376a9537a05ef31c20056c55e2a76b88c07282e
--- /dev/null
+++ b/src/test/vmem_valgrind/TEST1
@@ -0,0 +1,59 @@
+#!/bin/bash -e
+#
+# Copyright (c) 2014, Intel Corporation
+#
+# Redistribution and use in source and binary forms, with or without
+# modification, are permitted provided that the following conditions
+# are met:
+#
+#     * Redistributions of source code must retain the above copyright
+#       notice, this list of conditions and the following disclaimer.
+#
+#     * Redistributions in binary form must reproduce the above copyright
+#       notice, this list of conditions and the following disclaimer in
+#       the documentation and/or other materials provided with the
+#       distribution.
+#
+#     * Neither the name of Intel Corporation nor the names of its
+#       contributors may be used to endorse or promote products derived
+#       from this software without specific prior written permission.
+#
+# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+#
+
+#
+# src/test/vmem_valgrind/TEST1 -- unit test for vmem_valgrind
+#
+export UNITTEST_NAME=vmem_valgrind/TEST1
+export UNITTEST_NUM=1
+
+# standard unit test setup
+. ../unittest/unittest.sh
+
+. ./valgrind_check.sh
+
+require_fs_type local pmem
+require_build_type debug nondebug
+require_valgrind_dev
+
+setup
+
+export VMEM_LOG_LEVEL=0
+unset VMEM_LOG_FILE
+[ "$FS" == "pmem" ] && DIR_WORK=$DIR
+
+expect_normal_exit valgrind --leak-check=full --show-reachable=yes --log-file=valgrind$UNITTEST_NUM.log ./vmem_valgrind$EXESUFFIX 1 $DIR_WORK
+
+check
+
+pass
diff --git a/src/test/vmem_valgrind/TEST2 b/src/test/vmem_valgrind/TEST2
new file mode 100755
index 0000000000000000000000000000000000000000..cc09a0cd8745092166cc3b158c63d73d76aec8e8
--- /dev/null
+++ b/src/test/vmem_valgrind/TEST2
@@ -0,0 +1,59 @@
+#!/bin/bash -e
+#
+# Copyright (c) 2014, Intel Corporation
+#
+# Redistribution and use in source and binary forms, with or without
+# modification, are permitted provided that the following conditions
+# are met:
+#
+#     * Redistributions of source code must retain the above copyright
+#       notice, this list of conditions and the following disclaimer.
+#
+#     * Redistributions in binary form must reproduce the above copyright
+#       notice, this list of conditions and the following disclaimer in
+#       the documentation and/or other materials provided with the
+#       distribution.
+#
+#     * Neither the name of Intel Corporation nor the names of its
+#       contributors may be used to endorse or promote products derived
+#       from this software without specific prior written permission.
+#
+# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+#
+
+#
+# src/test/vmem_valgrind/TEST2 -- unit test for vmem_valgrind
+#
+export UNITTEST_NAME=vmem_valgrind/TEST2
+export UNITTEST_NUM=2
+
+# standard unit test setup
+. ../unittest/unittest.sh
+
+. ./valgrind_check.sh
+
+require_fs_type local pmem
+require_build_type debug nondebug
+require_valgrind_dev
+
+setup
+
+export VMEM_LOG_LEVEL=0
+unset VMEM_LOG_FILE
+[ "$FS" == "pmem" ] && DIR_WORK=$DIR
+
+expect_normal_exit valgrind --leak-check=full --show-reachable=yes --log-file=valgrind$UNITTEST_NUM.log ./vmem_valgrind$EXESUFFIX 2 $DIR_WORK
+
+check
+
+pass
diff --git a/src/test/vmem_valgrind/TEST3 b/src/test/vmem_valgrind/TEST3
new file mode 100755
index 0000000000000000000000000000000000000000..160e7852f284f7d5bc92cbc6a600dc87a3c60e62
--- /dev/null
+++ b/src/test/vmem_valgrind/TEST3
@@ -0,0 +1,59 @@
+#!/bin/bash -e
+#
+# Copyright (c) 2014, Intel Corporation
+#
+# Redistribution and use in source and binary forms, with or without
+# modification, are permitted provided that the following conditions
+# are met:
+#
+#     * Redistributions of source code must retain the above copyright
+#       notice, this list of conditions and the following disclaimer.
+#
+#     * Redistributions in binary form must reproduce the above copyright
+#       notice, this list of conditions and the following disclaimer in
+#       the documentation and/or other materials provided with the
+#       distribution.
+#
+#     * Neither the name of Intel Corporation nor the names of its
+#       contributors may be used to endorse or promote products derived
+#       from this software without specific prior written permission.
+#
+# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+#
+
+#
+# src/test/vmem_valgrind/TEST3 -- unit test for vmem_valgrind
+#
+export UNITTEST_NAME=vmem_valgrind/TEST3
+export UNITTEST_NUM=3
+
+# standard unit test setup
+. ../unittest/unittest.sh
+
+. ./valgrind_check.sh
+
+require_fs_type local pmem
+require_build_type debug nondebug
+require_valgrind_dev
+
+setup
+
+export VMEM_LOG_LEVEL=0
+unset VMEM_LOG_FILE
+[ "$FS" == "pmem" ] && DIR_WORK=$DIR
+
+expect_normal_exit valgrind --leak-check=full --show-reachable=yes --log-file=valgrind$UNITTEST_NUM.log ./vmem_valgrind$EXESUFFIX 3
+
+check
+
+pass
diff --git a/src/test/vmem_valgrind/TEST5 b/src/test/vmem_valgrind/TEST5
new file mode 100755
index 0000000000000000000000000000000000000000..285b0a506861eceef1a88e241a9dd34ccc478334
--- /dev/null
+++ b/src/test/vmem_valgrind/TEST5
@@ -0,0 +1,59 @@
+#!/bin/bash -e
+#
+# Copyright (c) 2014, Intel Corporation
+#
+# Redistribution and use in source and binary forms, with or without
+# modification, are permitted provided that the following conditions
+# are met:
+#
+#     * Redistributions of source code must retain the above copyright
+#       notice, this list of conditions and the following disclaimer.
+#
+#     * Redistributions in binary form must reproduce the above copyright
+#       notice, this list of conditions and the following disclaimer in
+#       the documentation and/or other materials provided with the
+#       distribution.
+#
+#     * Neither the name of Intel Corporation nor the names of its
+#       contributors may be used to endorse or promote products derived
+#       from this software without specific prior written permission.
+#
+# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+#
+
+#
+# src/test/vmem_valgrind/TEST5 -- unit test for vmem_valgrind
+#
+export UNITTEST_NAME=vmem_valgrind/TEST5
+export UNITTEST_NUM=5
+
+# standard unit test setup
+. ../unittest/unittest.sh
+
+. ./valgrind_check.sh
+
+require_fs_type local pmem
+require_build_type debug nondebug
+require_valgrind_dev
+
+setup
+
+export VMEM_LOG_LEVEL=0
+unset VMEM_LOG_FILE
+[ "$FS" == "pmem" ] && DIR_WORK=$DIR
+
+expect_normal_exit valgrind --leak-check=full --show-reachable=yes --log-file=valgrind$UNITTEST_NUM.log ./vmem_valgrind$EXESUFFIX 5
+
+check
+
+pass
diff --git a/src/test/vmem_valgrind/valgrind0.log.match b/src/test/vmem_valgrind/valgrind0.log.match
new file mode 100644
index 0000000000000000000000000000000000000000..ed8ee1bf99f88f2d64da8ce203fb7b7841bcd016
--- /dev/null
+++ b/src/test/vmem_valgrind/valgrind0.log.match
@@ -0,0 +1,15 @@
+==$(N)== Memcheck, a memory error detector
+==$(N)== Copyright $(*)
+==$(N)== Using $(*)
+==$(N)== Command:$(*)
+$(OPT)==$(N)== Parent PID: $(N)
+==$(N)== 
+==$(N)== 
+==$(N)== HEAP SUMMARY:
+==$(N)==     in use at exit: 0 bytes in 0 blocks
+==$(N)==   total heap usage: $(N) allocs, $(N) frees, $(*) bytes allocated
+==$(N)== 
+==$(N)== All heap blocks were freed -- no leaks are possible
+==$(N)== 
+==$(N)== For counts of detected and suppressed errors, rerun with: -v
+==$(N)== ERROR SUMMARY: 0 errors from 0 contexts (suppressed: $(N) from $(N))
diff --git a/src/test/vmem_valgrind/valgrind1.log.match b/src/test/vmem_valgrind/valgrind1.log.match
new file mode 100644
index 0000000000000000000000000000000000000000..ed8ee1bf99f88f2d64da8ce203fb7b7841bcd016
--- /dev/null
+++ b/src/test/vmem_valgrind/valgrind1.log.match
@@ -0,0 +1,15 @@
+==$(N)== Memcheck, a memory error detector
+==$(N)== Copyright $(*)
+==$(N)== Using $(*)
+==$(N)== Command:$(*)
+$(OPT)==$(N)== Parent PID: $(N)
+==$(N)== 
+==$(N)== 
+==$(N)== HEAP SUMMARY:
+==$(N)==     in use at exit: 0 bytes in 0 blocks
+==$(N)==   total heap usage: $(N) allocs, $(N) frees, $(*) bytes allocated
+==$(N)== 
+==$(N)== All heap blocks were freed -- no leaks are possible
+==$(N)== 
+==$(N)== For counts of detected and suppressed errors, rerun with: -v
+==$(N)== ERROR SUMMARY: 0 errors from 0 contexts (suppressed: $(N) from $(N))
diff --git a/src/test/vmem_valgrind/valgrind2.log.match b/src/test/vmem_valgrind/valgrind2.log.match
new file mode 100644
index 0000000000000000000000000000000000000000..a7da59c21e2efeb7dfa8e8da437890c49c2d9a00
--- /dev/null
+++ b/src/test/vmem_valgrind/valgrind2.log.match
@@ -0,0 +1,25 @@
+==$(N)== Memcheck, a memory error detector
+==$(N)== Copyright $(*)
+==$(N)== Using $(*)
+==$(N)== Command:$(*)
+==$(N)== Parent PID: $(N)
+==$(N)== 
+==$(N)== 
+==$(N)== HEAP SUMMARY:
+==$(N)==     in use at exit: $(N) bytes in 1 blocks
+==$(N)==   total heap usage: $(N) allocs, $(N) frees, $(*) bytes allocated
+==$(N)== 
+==$(N)== $(N) bytes in 1 blocks are definitely lost in loss record 1 of 1
+==$(N)==    at 0x$(X): je_vmem_pool_malloc (jemalloc.c:$(N))
+$(OPT)==$(N)==    by 0x$(X): vmem_malloc (vmem.c:$(N))
+==$(N)==    by 0x$(X): main (vmem_valgrind.c:$(N))
+==$(N)== 
+==$(N)== LEAK SUMMARY:
+==$(N)==    definitely lost: 8 bytes in 1 blocks
+==$(N)==    indirectly lost: 0 bytes in 0 blocks
+==$(N)==      possibly lost: 0 bytes in 0 blocks
+==$(N)==    still reachable: 0 bytes in 0 blocks
+==$(N)==         suppressed: 0 bytes in 0 blocks
+==$(N)== 
+==$(N)== For counts of detected and suppressed errors, rerun with: -v
+==$(N)== ERROR SUMMARY: 1 errors from 1 contexts (suppressed: $(N) from $(N))
diff --git a/src/test/vmem_valgrind/valgrind3.log.match b/src/test/vmem_valgrind/valgrind3.log.match
new file mode 100644
index 0000000000000000000000000000000000000000..6935a309093834fab80820e02cbbfc470eb589f2
--- /dev/null
+++ b/src/test/vmem_valgrind/valgrind3.log.match
@@ -0,0 +1,25 @@
+==$(N)== Memcheck, a memory error detector
+==$(N)== Copyright $(*)
+==$(N)== Using $(*)
+==$(N)== Command:$(*)
+==$(N)== Parent PID: $(N)
+==$(N)== 
+$(OPT)==$(N)== 
+==$(N)== HEAP SUMMARY:
+==$(N)==     in use at exit: $(N) bytes in 1 blocks
+==$(N)==   total heap usage: $(N) allocs, $(N) frees, $(*) bytes allocated
+==$(N)== 
+==$(N)== $(N) bytes in 1 blocks are definitely lost in loss record 1 of 1
+==$(N)==    at 0x$(X): je_vmem_pool_malloc (jemalloc.c:$(N))
+$(OPT)==$(N)==    by 0x$(X): vmem_malloc (vmem.c:$(N))
+==$(N)==    by 0x$(X): main (vmem_valgrind.c:$(N))
+==$(N)== 
+==$(N)== LEAK SUMMARY:
+==$(N)==    definitely lost: 8 bytes in 1 blocks
+==$(N)==    indirectly lost: 0 bytes in 0 blocks
+==$(N)==      possibly lost: 0 bytes in 0 blocks
+==$(N)==    still reachable: 0 bytes in 0 blocks
+==$(N)==         suppressed: 0 bytes in 0 blocks
+==$(N)== 
+==$(N)== For counts of detected and suppressed errors, rerun with: -v
+==$(N)== ERROR SUMMARY: 1 errors from 1 contexts (suppressed: $(N) from $(N))
diff --git a/src/test/vmem_valgrind/valgrind4.log.match b/src/test/vmem_valgrind/valgrind4.log.match
new file mode 100644
index 0000000000000000000000000000000000000000..c75c203c8c2157eb49cd23fc99ebbc7105406c45
--- /dev/null
+++ b/src/test/vmem_valgrind/valgrind4.log.match
@@ -0,0 +1,22 @@
+==$(N)== Memcheck, a memory error detector
+==$(N)== Copyright $(*)
+==$(N)== Using $(*)
+==$(N)== Command:$(*)
+==$(N)== Parent PID: $(N)
+==$(N)== 
+==$(N)== Invalid write of size 4
+==$(N)==    at 0x$(X): main (vmem_valgrind.c:$(N))
+==$(N)==  Address 0x$(X) is 0 bytes after a block of size $(N) alloc'd
+==$(N)==    at 0x$(X): je_vmem_pool_malloc (jemalloc.c:$(N))
+$(OPT)==$(N)==    by 0x$(X): vmem_malloc (vmem.c:$(N))
+==$(N)==    by 0x$(X): main (vmem_valgrind.c:$(N))
+==$(N)== 
+==$(N)== 
+==$(N)== HEAP SUMMARY:
+==$(N)==     in use at exit: 0 bytes in 0 blocks
+==$(N)==   total heap usage: $(N) allocs, $(N) frees, $(*) bytes allocated
+==$(N)== 
+==$(N)== All heap blocks were freed -- no leaks are possible
+==$(N)== 
+==$(N)== For counts of detected and suppressed errors, rerun with: -v
+==$(N)== ERROR SUMMARY: 1 errors from 1 contexts (suppressed: $(N) from $(N))
diff --git a/src/test/vmem_valgrind/valgrind5.log.match b/src/test/vmem_valgrind/valgrind5.log.match
new file mode 100644
index 0000000000000000000000000000000000000000..ed8ee1bf99f88f2d64da8ce203fb7b7841bcd016
--- /dev/null
+++ b/src/test/vmem_valgrind/valgrind5.log.match
@@ -0,0 +1,15 @@
+==$(N)== Memcheck, a memory error detector
+==$(N)== Copyright $(*)
+==$(N)== Using $(*)
+==$(N)== Command:$(*)
+$(OPT)==$(N)== Parent PID: $(N)
+==$(N)== 
+==$(N)== 
+==$(N)== HEAP SUMMARY:
+==$(N)==     in use at exit: 0 bytes in 0 blocks
+==$(N)==   total heap usage: $(N) allocs, $(N) frees, $(*) bytes allocated
+==$(N)== 
+==$(N)== All heap blocks were freed -- no leaks are possible
+==$(N)== 
+==$(N)== For counts of detected and suppressed errors, rerun with: -v
+==$(N)== ERROR SUMMARY: 0 errors from 0 contexts (suppressed: $(N) from $(N))
diff --git a/src/test/vmem_valgrind/valgrind_check.c b/src/test/vmem_valgrind/valgrind_check.c
new file mode 100644
index 0000000000000000000000000000000000000000..73dadf218ed848eaa2f1b47a7e3f879ba121f7d3
--- /dev/null
+++ b/src/test/vmem_valgrind/valgrind_check.c
@@ -0,0 +1,51 @@
+/*
+ * Copyright (c) 2014, Intel Corporation
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ *     * Redistributions of source code must retain the above copyright
+ *       notice, this list of conditions and the following disclaimer.
+ *
+ *     * Redistributions in binary form must reproduce the above copyright
+ *       notice, this list of conditions and the following disclaimer in
+ *       the documentation and/or other materials provided with the
+ *       distribution.
+ *
+ *     * Neither the name of Intel Corporation nor the names of its
+ *       contributors may be used to endorse or promote products derived
+ *       from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+/*
+ * valgrind_check.c -- compile this to check that we have the correct version
+ * of Valgrind headers
+ */
+
+#include <valgrind/valgrind.h>
+#include <valgrind/memcheck.h>
+
+/* check valgrind version required by jemalloc */
+#if !defined(VALGRIND_RESIZEINPLACE_BLOCK)
+#error "Incompatible Valgrind version"
+#endif
+
+int
+main()
+{
+	;
+	return 0;
+}
diff --git a/src/test/vmem_valgrind/valgrind_check.sh b/src/test/vmem_valgrind/valgrind_check.sh
new file mode 100755
index 0000000000000000000000000000000000000000..717b22ea6a62979aaf9a531b7adef1287875816e
--- /dev/null
+++ b/src/test/vmem_valgrind/valgrind_check.sh
@@ -0,0 +1,41 @@
+#
+# Copyright (c) 2014, Intel Corporation
+#
+# Redistribution and use in source and binary forms, with or without
+# modification, are permitted provided that the following conditions
+# are met:
+#
+#     * Redistributions of source code must retain the above copyright
+#       notice, this list of conditions and the following disclaimer.
+#
+#     * Redistributions in binary form must reproduce the above copyright
+#       notice, this list of conditions and the following disclaimer in
+#       the documentation and/or other materials provided with the
+#       distribution.
+#
+#     * Neither the name of Intel Corporation nor the names of its
+#       contributors may be used to endorse or promote products derived
+#       from this software without specific prior written permission.
+#
+# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+#
+
+#
+# require_valgrind_dev -- continue script execution only if correct version
+#	of valgrind-devel package is installed
+#
+function require_valgrind_dev() {
+	gcc valgrind_check.c -o /dev/null 1>/dev/null 2>/dev/null && return
+	echo "$UNITTEST_NAME: SKIP valgrind-devel package required"
+	exit 0
+}
diff --git a/src/test/vmem_valgrind/vmem_valgrind.c b/src/test/vmem_valgrind/vmem_valgrind.c
new file mode 100644
index 0000000000000000000000000000000000000000..350ff1580f5b49bc3082ea48bb35640d15683c88
--- /dev/null
+++ b/src/test/vmem_valgrind/vmem_valgrind.c
@@ -0,0 +1,218 @@
+/*
+ * Copyright (c) 2014, Intel Corporation
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ *     * Redistributions of source code must retain the above copyright
+ *       notice, this list of conditions and the following disclaimer.
+ *
+ *     * Redistributions in binary form must reproduce the above copyright
+ *       notice, this list of conditions and the following disclaimer in
+ *       the documentation and/or other materials provided with the
+ *       distribution.
+ *
+ *     * Neither the name of Intel Corporation nor the names of its
+ *       contributors may be used to endorse or promote products derived
+ *       from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+/*
+ * vmem_valgrind.c -- unit test for vmem_valgrind
+ *
+ * usage: vmem_valgrind <test-number> [directory]
+ *
+ * test-number can be a number from 0 to 9
+ */
+
+#include "unittest.h"
+
+static char mem_pool[VMEM_MIN_POOL];
+
+static int custom_allocs;
+static int custom_alloc_calls;
+
+/*
+ * malloc_custom -- custom malloc function
+ *
+ * This function updates statistics about custom alloc functions,
+ * and returns allocated memory.
+ */
+void *
+malloc_custom(size_t size)
+{
+	++custom_alloc_calls;
+	++custom_allocs;
+	return malloc(size);
+}
+
+/*
+ * free_custom -- custom free function
+ *
+ * This function updates statistics about custom alloc functions,
+ * and frees allocated memory.
+ */
+void
+free_custom(void *ptr)
+{
+	++custom_alloc_calls;
+	--custom_allocs;
+	free(ptr);
+}
+
+/*
+ * realloc_custom -- custom realloc function
+ *
+ * This function updates statistics about custom alloc functions,
+ * and returns reallocated memory.
+ */
+void *
+realloc_custom(void *ptr, size_t size)
+{
+	++custom_alloc_calls;
+	return realloc(ptr, size);
+}
+
+/*
+ * strdup_custom -- custom strdup function
+ *
+ * This function updates statistics about custom alloc functions,
+ * and returns allocated memory with a duplicated string.
+ */
+char *
+strdup_custom(const char *s)
+{
+	++custom_alloc_calls;
+	++custom_allocs;
+	return strdup(s);
+}
+
+int
+main(int argc, char *argv[])
+{
+	char *dir = NULL;
+	VMEM *vmp;
+	int *ptr;
+	int test_case = -1;
+	int expect_custom_alloc = 0;
+
+	START(argc, argv, "vmem_valgrind");
+
+	if (argc >= 2 && argc <= 3) {
+		test_case = atoi(argv[1]);
+		if (test_case > 9)
+			test_case = -1;
+
+		if (argc > 2)
+			dir = argv[2];
+	}
+
+	if (test_case < 0)
+		FATAL("usage: %s <test-number from 0 to 9> [directory]",
+			argv[0]);
+
+	if (test_case < 5) {
+		OUT("use default allocator");
+		expect_custom_alloc = 0;
+	} else {
+		OUT("use custom alloc functions");
+		test_case -= 5;
+		expect_custom_alloc = 1;
+		vmem_set_funcs(malloc_custom, free_custom,
+			realloc_custom, strdup_custom, NULL);
+	}
+
+	if (dir == NULL) {
+		vmp = vmem_pool_create_in_region(mem_pool, VMEM_MIN_POOL);
+		if (vmp == NULL)
+			FATAL("!vmem_pool_create_in_region");
+	} else {
+		vmp = vmem_pool_create(dir, VMEM_MIN_POOL);
+		if (vmp == NULL)
+			FATAL("!vmem_pool_create");
+	}
+
+	switch (test_case) {
+		case 0: {
+			OUT("remove all allocations and delete pool");
+			ptr = vmem_malloc(vmp, sizeof (int));
+			if (ptr == NULL)
+				FATAL("!vmem_malloc");
+
+			vmem_free(vmp, ptr);
+			vmem_pool_delete(vmp);
+			break;
+		}
+		case 1: {
+			OUT("only remove allocations");
+			ptr = vmem_malloc(vmp, sizeof (int));
+			if (ptr == NULL)
+				FATAL("!vmem_malloc");
+
+			vmem_free(vmp, ptr);
+			break;
+		}
+		case 2: {
+			OUT("only delete pool");
+			ptr = vmem_malloc(vmp, sizeof (int));
+			if (ptr == NULL)
+				FATAL("!vmem_malloc");
+
+			vmem_pool_delete(vmp);
+
+			/* prevent reporting leaked memory as still reachable */
+			ptr = NULL;
+			break;
+		}
+		case 3: {
+			OUT("memory leaks");
+			ptr = vmem_malloc(vmp, sizeof (int));
+			if (ptr == NULL)
+				FATAL("!vmem_malloc");
+
+			/* prevent reporting leaked memory as still reachable */
+			ptr = NULL;
+			break;
+		}
+		case 4: {
+			OUT("heap block overrun");
+			ptr = vmem_malloc(vmp, 12 * sizeof (int));
+			if (ptr == NULL)
+				FATAL("!vmem_malloc");
+
+			/* heap block overrun */
+			ptr[12] = 7;
+
+			vmem_free(vmp, ptr);
+			vmem_pool_delete(vmp);
+			break;
+		}
+		default: {
+			FATAL("!unknown test-number");
+		}
+	}
+
+	/* check memory leak in custom allocator */
+	ASSERTeq(custom_allocs, 0);
+
+	if (expect_custom_alloc == 0) {
+		ASSERTeq(custom_alloc_calls, 0);
+	} else {
+		ASSERTne(custom_alloc_calls, 0);
+	}
+
+	DONE(NULL);
+}
diff --git a/src/trn.c b/src/trn.c
new file mode 100644
index 0000000000000000000000000000000000000000..33b1fd62ae4e13a5699008f3e7fc7286eeb9169b
--- /dev/null
+++ b/src/trn.c
@@ -0,0 +1,205 @@
+/*
+ * Copyright (c) 2014, Intel Corporation
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ *     * Redistributions of source code must retain the above copyright
+ *       notice, this list of conditions and the following disclaimer.
+ *
+ *     * Redistributions in binary form must reproduce the above copyright
+ *       notice, this list of conditions and the following disclaimer in
+ *       the documentation and/or other materials provided with the
+ *       distribution.
+ *
+ *     * Neither the name of Intel Corporation nor the names of its
+ *       contributors may be used to endorse or promote products derived
+ *       from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY LOG OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+/*
+ * trn.c -- transactional memory pool entry points for libpmem
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <signal.h>
+#include <fcntl.h>
+#include <unistd.h>
+#include <errno.h>
+#include <stdint.h>
+#include <time.h>
+#include <uuid/uuid.h>
+#include <endian.h>
+#include <libpmem.h>
+#include "pmem.h"
+#include "util.h"
+#include "out.h"
+#include "trn.h"
+
+/*
+ * trn_init -- load-time initialization for trn
+ *
+ * Called automatically by the run-time loader.
+ */
+__attribute__((constructor))
+static void
+trn_init(void)
+{
+	out_init(LOG_PREFIX, LOG_LEVEL_VAR, LOG_FILE_VAR);
+	LOG(3, NULL);
+	util_init();
+}
+
+/*
+ * pmemtrn_map -- map a transactional memory pool
+ */
+PMEMtrn *
+pmemtrn_map(int fd)
+{
+	LOG(3, "fd %d", fd);
+
+	struct stat stbuf;
+
+	if (fstat(fd, &stbuf) < 0) {
+		LOG(1, "!fstat");
+		return NULL;
+	}
+
+	if (stbuf.st_size < PMEMTRN_MIN_POOL) {
+		LOG(1, "size %zu smaller than %zu",
+				stbuf.st_size, PMEMTRN_MIN_POOL);
+		errno = EINVAL;
+		return NULL;
+	}
+
+	void *addr;
+	if ((addr = util_map(fd, stbuf.st_size, 0)) == NULL)
+		return NULL;	/* util_map() set errno, called LOG */
+
+	/* check if the mapped region is located in persistent memory */
+	int is_pmem = pmem_is_pmem(addr, stbuf.st_size);
+
+	/* opaque info lives at the beginning of mapped memory pool */
+	struct pmemtrn *ptp = addr;
+
+	struct pool_hdr hdr;
+	memcpy(&hdr, &ptp->hdr, sizeof (hdr));
+
+	if (util_convert_hdr(&hdr)) {
+		/*
+		 * valid header found
+		 */
+		if (strncmp(hdr.signature, TRN_HDR_SIG, POOL_HDR_SIG_LEN)) {
+			LOG(1, "wrong pool type: \"%s\"", hdr.signature);
+
+			errno = EINVAL;
+			goto err;
+		}
+
+		if (hdr.major != TRN_FORMAT_MAJOR) {
+			LOG(1, "trn pool version %d (library expects %d)",
+				hdr.major, TRN_FORMAT_MAJOR);
+
+			errno = EINVAL;
+			goto err;
+		}
+
+		int retval = util_feature_check(&hdr, TRN_FORMAT_INCOMPAT,
+							TRN_FORMAT_RO_COMPAT,
+							TRN_FORMAT_COMPAT);
+		if (retval < 0)
+		    goto err;
+		else if (retval == 0) {
+			/* XXX switch to read-only mode */
+		}
+	} else {
+		/*
+		 * no valid header was found
+		 */
+		LOG(3, "creating new trn memory pool");
+
+		struct pool_hdr *hdrp = &ptp->hdr;
+
+		memset(hdrp, '\0', sizeof (*hdrp));
+		strncpy(hdrp->signature, TRN_HDR_SIG, POOL_HDR_SIG_LEN);
+		hdrp->major = htole32(TRN_FORMAT_MAJOR);
+		hdrp->compat_features = htole32(TRN_FORMAT_COMPAT);
+		hdrp->incompat_features = htole32(TRN_FORMAT_INCOMPAT);
+		hdrp->ro_compat_features = htole32(TRN_FORMAT_RO_COMPAT);
+		uuid_generate(hdrp->uuid);
+		hdrp->crtime = htole64((uint64_t)time(NULL));
+		util_checksum(hdrp, sizeof (*hdrp), &hdrp->checksum, 1);
+		hdrp->checksum = htole64(hdrp->checksum);
+
+		/* store pool's header */
+		libpmem_persist(is_pmem, hdrp, sizeof (*hdrp));
+
+		/* XXX create rest of required metadata */
+	}
+
+	/* use some of the memory pool area for run-time info */
+	ptp->addr = addr;
+	ptp->size = stbuf.st_size;
+
+	/*
+	 * If possible, turn off all permissions on the pool header page.
+	 *
+	 * The prototype PMFS doesn't allow this when large pages are in
+	 * use not it is not considered an error if this fails.
+	 */
+	util_range_none(addr, sizeof (struct pool_hdr));
+
+	/* the rest should be kept read-only for debug version */
+	RANGE_RO(addr + sizeof (struct pool_hdr),
+			stbuf.st_size - sizeof (struct pool_hdr));
+
+	LOG(3, "ptp %p", ptp);
+	return ptp;
+
+err:
+	LOG(4, "error clean up");
+	int oerrno = errno;
+	util_unmap(addr, stbuf.st_size);
+	errno = oerrno;
+	return NULL;
+}
+
+/*
+ * pmemtrn_unmap -- unmap a transactional memory pool
+ */
+void
+pmemtrn_unmap(PMEMtrn *ptp)
+{
+	LOG(3, "ptp %p", ptp);
+
+	util_unmap(ptp->addr, ptp->size);
+}
+
+/*
+ * pmemtrn_check -- transactional memory pool consistency check
+ */
+int
+pmemtrn_check(const char *path)
+{
+	LOG(3, "path \"%s\"", path);
+
+	/* XXX stub */
+	return 0;
+}
diff --git a/src/trn.h b/src/trn.h
new file mode 100644
index 0000000000000000000000000000000000000000..902a4f161ca5d07aded0bb9edb9ff23dafad9fc2
--- /dev/null
+++ b/src/trn.h
@@ -0,0 +1,52 @@
+/*
+ * Copyright (c) 2014, Intel Corporation
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ *     * Redistributions of source code must retain the above copyright
+ *       notice, this list of conditions and the following disclaimer.
+ *
+ *     * Redistributions in binary form must reproduce the above copyright
+ *       notice, this list of conditions and the following disclaimer in
+ *       the documentation and/or other materials provided with the
+ *       distribution.
+ *
+ *     * Neither the name of Intel Corporation nor the names of its
+ *       contributors may be used to endorse or promote products derived
+ *       from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+/*
+ * trn.h -- internal definitions for libpmem trn module
+ */
+
+/* attributes of the trn memory pool format for the pool header */
+#define	TRN_HDR_SIG "PMEMTRN"	/* must be 8 bytes including '\0' */
+#define	TRN_FORMAT_MAJOR 1
+#define	TRN_FORMAT_COMPAT 0x0000
+#define	TRN_FORMAT_INCOMPAT 0x0000
+#define	TRN_FORMAT_RO_COMPAT 0x0000
+
+struct pmemtrn {
+	struct pool_hdr hdr;	/* memory pool header */
+
+	/* root info for on-media format... */
+
+	/* some run-time state, allocated out of memory pool... */
+	void *addr;		/* mapped region */
+	size_t size;		/* size of mapped region */
+};
diff --git a/src/util.c b/src/util.c
new file mode 100644
index 0000000000000000000000000000000000000000..9de00784031da4859481f0e5acda20bacaf1b37a
--- /dev/null
+++ b/src/util.c
@@ -0,0 +1,340 @@
+/*
+ * Copyright (c) 2014, Intel Corporation
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ *     * Redistributions of source code must retain the above copyright
+ *       notice, this list of conditions and the following disclaimer.
+ *
+ *     * Redistributions in binary form must reproduce the above copyright
+ *       notice, this list of conditions and the following disclaimer in
+ *       the documentation and/or other materials provided with the
+ *       distribution.
+ *
+ *     * Neither the name of Intel Corporation nor the names of its
+ *       contributors may be used to endorse or promote products derived
+ *       from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+/*
+ * util.c -- general utilities used in the library
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <sys/types.h>
+#include <sys/mman.h>
+#include <unistd.h>
+#include <stdint.h>
+#include <endian.h>
+#include <errno.h>
+#include "util.h"
+#include "out.h"
+
+/* library-wide page size */
+unsigned long Pagesize;
+
+/*
+ * our versions of malloc & friends start off pointing to the libc versions
+ */
+Malloc_func Malloc = malloc;
+Free_func Free = free;
+Realloc_func Realloc = realloc;
+Strdup_func Strdup = strdup;
+
+/*
+ * util_init -- initialize the utils
+ *
+ * This is called from the library initialization code.
+ */
+void
+util_init(void)
+{
+	LOG(3, NULL);
+	if (Pagesize == 0)
+		Pagesize = (unsigned long) sysconf(_SC_PAGESIZE);
+}
+
+/*
+ * util_set_alloc_funcs -- allow one to override malloc, etc.
+ */
+void
+util_set_alloc_funcs(void *(*malloc_func)(size_t size),
+		void (*free_func)(void *ptr),
+		void *(*realloc_func)(void *ptr, size_t size),
+		char *(*strdup_func)(const char *s))
+{
+	LOG(3, "malloc %p free %p realloc %p strdup %p",
+			malloc_func, free_func, realloc_func, strdup_func);
+
+	Malloc = (malloc_func == NULL) ? malloc : malloc_func;
+	Free = (free_func == NULL) ? free : free_func;
+	Realloc = (realloc_func == NULL) ? realloc : realloc_func;
+	Strdup = (strdup_func == NULL) ? strdup : strdup_func;
+}
+
+/*
+ * util_map -- memory map a file
+ *
+ * This is just a convenience function that calls mmap() with the
+ * appropriate arguments and includes our trace points.
+ *
+ * If cow is set, the file is mapped copy-on-write.
+ */
+void *
+util_map(int fd, size_t len, int cow)
+{
+	void *base;
+
+	LOG(3, "fd %d len %zu cow %d", fd, len, cow);
+
+	if ((base = mmap(NULL, len, PROT_READ|PROT_WRITE,
+			(cow) ? MAP_PRIVATE|MAP_NORESERVE : MAP_SHARED,
+					fd, 0)) == MAP_FAILED) {
+		LOG(1, "!mmap %zu bytes", len);
+		return NULL;
+	}
+
+	LOG(3, "mapped at %p", base);
+
+	return base;
+}
+
+/*
+ * util_unmap -- unmap a file
+ *
+ * This is just a convenience function that calls munmap() with the
+ * appropriate arguments and includes our trace points.
+ */
+int
+util_unmap(void *addr, size_t len)
+{
+	LOG(3, "addr %p len %zu", addr, len);
+
+	int retval = munmap(addr, len);
+
+	if (retval < 0)
+		LOG(1, "!munmap");
+
+	return retval;
+}
+
+/*
+ * util_checksum -- compute Fletcher64 checksum
+ *
+ * csump points to where the checksum lives, so that location
+ * is treated as zeros while calculating the checksum.  If
+ * insert is true, the calculated checksum is inserted into
+ * the range at *csump.  Otherwise the calculated checksum is
+ * checked against *csump and the result returned (true means
+ * the range checksummed correctly).
+ */
+int
+util_checksum(void *addr, size_t len, uint64_t *csump, int insert)
+{
+	uint32_t *p32 = addr;
+	uint32_t *p32end = addr + len;
+	uint32_t lo32 = 0;
+	uint32_t hi32 = 0;
+	uint64_t csum;
+
+	while (p32 < p32end)
+		if (p32 == (uint32_t *)csump) {
+			/* lo32 += 0; treat first 32-bits as zero */
+			p32++;
+			hi32 += lo32;
+			/* lo32 += 0; treat second 32-bits as zero */
+			p32++;
+			hi32 += lo32;
+		} else {
+			lo32 += *p32++;
+			hi32 += lo32;
+		}
+
+	csum = (uint64_t)hi32 << 32 | lo32;
+
+	if (insert) {
+		*csump = csum;
+		return 1;
+	}
+
+	return *csump == csum;
+}
+
+/*
+ * util_convert_hdr -- convert header to host byte order & validate
+ *
+ * Returns true if header is valid, and all the integer fields are
+ * converted to host byte order.  If the header is not valid, this
+ * routine returns false and the header passed in is left in an
+ * unknown state.
+ */
+int
+util_convert_hdr(struct pool_hdr *hdrp)
+{
+	LOG(3, "hdrp %p", hdrp);
+
+	/* to be valid, a header must have a major version of at least 1 */
+	if ((hdrp->major = le32toh(hdrp->major)) == 0) {
+		LOG(3, "invalid major version (0)");
+		return 0;
+	}
+	hdrp->compat_features = le32toh(hdrp->compat_features);
+	hdrp->incompat_features = le32toh(hdrp->incompat_features);
+	hdrp->ro_compat_features = le32toh(hdrp->ro_compat_features);
+	hdrp->crtime = le64toh(hdrp->crtime);
+	hdrp->checksum = le64toh(hdrp->checksum);
+
+	/* and to be valid, the fields must checksum correctly */
+	if (!util_checksum(hdrp, sizeof (*hdrp), &hdrp->checksum, 0)) {
+		LOG(3, "invalid checksum");
+		return 0;
+	}
+
+	LOG(3, "valid header, signature \"%s\"", hdrp->signature);
+	return 1;
+}
+
+/*
+ * util_range_ro -- set a memory range read-only
+ */
+int
+util_range_ro(void *addr, size_t len)
+{
+	LOG(3, "addr %p len %zu", addr, len);
+
+	uintptr_t uptr;
+	int retval;
+
+	/*
+	 * mprotect requires addr to be a multiple of pagesize, so
+	 * adjust addr and len to represent the full 4k chunks
+	 * covering the given range.
+	 */
+
+	/* increase len by the amount we gain when we round addr down */
+	len += (uintptr_t)addr & (Pagesize - 1);
+
+	/* round addr down to page boundary */
+	uptr = (uintptr_t)addr & ~(Pagesize - 1);
+
+	if ((retval = mprotect((void *)uptr, len, PROT_READ)) < 0)
+		LOG(1, "!mprotect: PROT_READ");
+
+	return retval;
+}
+
+/*
+ * util_range_rw -- set a memory range read-write
+ */
+int
+util_range_rw(void *addr, size_t len)
+{
+	LOG(3, "addr %p len %zu", addr, len);
+
+	uintptr_t uptr;
+	int retval;
+
+	/*
+	 * mprotect requires addr to be a multiple of pagesize, so
+	 * adjust addr and len to represent the full 4k chunks
+	 * covering the given range.
+	 */
+
+	/* increase len by the amount we gain when we round addr down */
+	len += (uintptr_t)addr & (Pagesize - 1);
+
+	/* round addr down to page boundary */
+	uptr = (uintptr_t)addr & ~(Pagesize - 1);
+
+	if ((retval = mprotect((void *)uptr, len, PROT_READ|PROT_WRITE)) < 0)
+		LOG(1, "!mprotect: PROT_READ|PROT_WRITE");
+
+	return retval;
+}
+
+/*
+ * util_range_none -- set a memory range for no access allowed
+ */
+int
+util_range_none(void *addr, size_t len)
+{
+	LOG(3, "addr %p len %zu", addr, len);
+
+	uintptr_t uptr;
+	int retval;
+
+	/*
+	 * mprotect requires addr to be a multiple of pagesize, so
+	 * adjust addr and len to represent the full 4k chunks
+	 * covering the given range.
+	 */
+
+	/* increase len by the amount we gain when we round addr down */
+	len += (uintptr_t)addr & (Pagesize - 1);
+
+	/* round addr down to page boundary */
+	uptr = (uintptr_t)addr & ~(Pagesize - 1);
+
+	if ((retval = mprotect((void *)uptr, len, PROT_NONE)) < 0)
+		LOG(1, "!mprotect: PROT_NONE");
+
+	return retval;
+}
+
+/*
+ * util_feature_check -- check features masks
+ */
+int
+util_feature_check(struct pool_hdr *hdrp, uint32_t incompat,
+			uint32_t ro_compat, uint32_t compat)
+{
+	LOG(3, "hdrp %p incompat %#x ro_compat %#x compat %#x",
+			hdrp, incompat, ro_compat, compat);
+
+#define	GET_NOT_MASKED_BITS(x, mask) ((x) & ~(mask))
+
+	uint32_t ubits;	/* unsupported bits */
+
+	/* check incompatible ("must support") features */
+	ubits = GET_NOT_MASKED_BITS(hdrp->incompat_features, incompat);
+	if (ubits) {
+		LOG(1, "unsafe to continue due to unknown incompat "\
+							"features: %#x", ubits);
+		errno = EINVAL;
+		return -1;
+	}
+
+	/* check RO-compatible features (force RO if unsupported) */
+	ubits = GET_NOT_MASKED_BITS(hdrp->ro_compat_features, ro_compat);
+	if (ubits) {
+		LOG(1, "switching to read-only mode due to unknown ro_compat "\
+							"features: %#x", ubits);
+		return 0;
+	}
+
+	/* check compatible ("may") features */
+	ubits = GET_NOT_MASKED_BITS(hdrp->compat_features, compat);
+	if (ubits) {
+		LOG(3, "ignoring unknown compat features: %#x", ubits);
+	}
+
+#undef	GET_NOT_MASKED_BITS
+
+	return 1;
+}
diff --git a/src/util.h b/src/util.h
new file mode 100644
index 0000000000000000000000000000000000000000..fc72835ce54bf22cda8cd618dfd84bc4f913e32f
--- /dev/null
+++ b/src/util.h
@@ -0,0 +1,104 @@
+/*
+ * Copyright (c) 2014, Intel Corporation
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ *     * Redistributions of source code must retain the above copyright
+ *       notice, this list of conditions and the following disclaimer.
+ *
+ *     * Redistributions in binary form must reproduce the above copyright
+ *       notice, this list of conditions and the following disclaimer in
+ *       the documentation and/or other materials provided with the
+ *       distribution.
+ *
+ *     * Neither the name of Intel Corporation nor the names of its
+ *       contributors may be used to endorse or promote products derived
+ *       from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+/*
+ * util.h -- internal definitions for util module
+ */
+
+/*
+ * overridable names for malloc & friends used by this library
+ */
+typedef void *(*Malloc_func)(size_t size);
+typedef void (*Free_func)(void *ptr);
+typedef void *(*Realloc_func)(void *ptr, size_t size);
+typedef char *(*Strdup_func)(const char *s);
+
+Malloc_func Malloc;
+Free_func Free;
+Realloc_func Realloc;
+Strdup_func Strdup;
+
+void util_set_alloc_funcs(
+		void *(*malloc_func)(size_t size),
+		void (*free_func)(void *ptr),
+		void *(*realloc_func)(void *ptr, size_t size),
+		char *(*strdup_func)(const char *s));
+void *util_map(int fd, size_t len, int cow);
+int util_unmap(void *addr, size_t len);
+
+/*
+ * header used at the beginning of all types of memory pools
+ *
+ * for pools build on persistent memory, the integer types
+ * below are stored in little-endian byte order.
+ */
+#define	POOL_HDR_SIG_LEN 8
+#define	POOL_HDR_UUID_LEN 16
+struct pool_hdr {
+	char signature[POOL_HDR_SIG_LEN];
+	uint32_t major;			/* format major version number */
+	uint32_t compat_features;	/* mask: compatible "may" features */
+	uint32_t incompat_features;	/* mask: "must support" features */
+	uint32_t ro_compat_features;	/* mask: force RO if unsupported */
+	unsigned char uuid[POOL_HDR_UUID_LEN];
+	uint64_t crtime;		/* when created (seconds since epoch) */
+	unsigned char unused[4040];	/* must be zero */
+	uint64_t checksum;		/* checksum of above fields */
+};
+
+int util_checksum(void *addr, size_t len, uint64_t *csump, int insert);
+int util_convert_hdr(struct pool_hdr *hdrp);
+
+/*
+ * macros for micromanaging range protections for the debug version
+ */
+#ifdef	DEBUG
+
+#define	RANGE_RO(addr, len) ASSERT(util_range_ro(addr, len) >= 0)
+#define	RANGE_RW(addr, len) ASSERT(util_range_rw(addr, len) >= 0)
+
+#else
+
+/* nondebug version */
+#define	RANGE_RO(addr, len)
+#define	RANGE_RW(addr, len)
+
+#endif	/* DEBUG */
+
+void util_init(void);
+
+int util_range_ro(void *addr, size_t len);
+int util_range_rw(void *addr, size_t len);
+int util_range_none(void *addr, size_t len);
+
+int util_feature_check(struct pool_hdr *hdrp, uint32_t incompat,
+				uint32_t ro_compat, uint32_t compat);
diff --git a/src/vmem.c b/src/vmem.c
new file mode 100644
index 0000000000000000000000000000000000000000..bcc10efaaa9f56677f549fa5126cae2c250a0931
--- /dev/null
+++ b/src/vmem.c
@@ -0,0 +1,377 @@
+/*
+ * Copyright (c) 2014, Intel Corporation
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ *     * Redistributions of source code must retain the above copyright
+ *       notice, this list of conditions and the following disclaimer.
+ *
+ *     * Redistributions in binary form must reproduce the above copyright
+ *       notice, this list of conditions and the following disclaimer in
+ *       the documentation and/or other materials provided with the
+ *       distribution.
+ *
+ *     * Neither the name of Intel Corporation nor the names of its
+ *       contributors may be used to endorse or promote products derived
+ *       from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY LOG OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+/*
+ * vmem.c -- memory pool & allocation entry points for libvmem
+ */
+#include <stdbool.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <sys/types.h>
+#include <sys/param.h>
+#include <signal.h>
+#include <fcntl.h>
+#include <unistd.h>
+#include <errno.h>
+#include <stdint.h>
+#include <libvmem.h>
+#include "jemalloc.h"
+#include "util.h"
+#include "out.h"
+#include "vmem.h"
+
+/*
+ * private to this file...
+ */
+static unsigned Header_size;
+static void *vmem_tmpfile(const char *dir, size_t size);
+
+/*
+ * print_jemalloc_messages -- custom print function, for jemalloc
+ *
+ * Prints traces from jemalloc. All traces from jemalloc
+ * are considered as error messages.
+ */
+static void
+print_jemalloc_messages(void* ignore, const char *s)
+{
+	LOG_NONL(1, "%s", s);
+}
+
+/*
+ * print_jemalloc_stats -- print function, for jemalloc statistics
+ *
+ * Prints statistics from jemalloc. All statistics are printed with level 0.
+ */
+static void
+print_jemalloc_stats(void* ignore, const char *s)
+{
+	LOG_NONL(0, "%s", s);
+}
+
+/*
+ * vmem_init -- load-time initialization for vmem
+ *
+ * Called automatically by the run-time loader.
+ */
+__attribute__((constructor))
+static void
+vmem_init(void)
+{
+	out_init(LOG_PREFIX, LOG_LEVEL_VAR, LOG_FILE_VAR);
+	LOG(3, NULL);
+	util_init();
+	Header_size = roundup(sizeof (VMEM), Pagesize);
+
+	/* Set up jemalloc to forward messages to a custom print function */
+	je_vmem_malloc_message = print_jemalloc_messages;
+}
+
+/*
+ * vmem_pool_create -- create a memory pool in a temp file
+ */
+VMEM *
+vmem_pool_create(const char *dir, size_t size)
+{
+	LOG(3, "dir \"%s\" size %zu", dir, size);
+
+	if (size < VMEM_MIN_POOL) {
+		LOG(1, "size %zu smaller than %zu", size, VMEM_MIN_POOL);
+		errno = EINVAL;
+		return NULL;
+	}
+
+	/* silently enforce multiple of page size */
+	size = roundup(size, Pagesize);
+
+	void *addr;
+	if ((addr = vmem_tmpfile(dir, size)) == NULL)
+		return NULL;
+
+	/* store opaque info at beginning of mapped area */
+	struct vmem *vmp = addr;
+	memset(&vmp->hdr, '\0', sizeof (vmp->hdr));
+	strncpy(vmp->hdr.signature, VMEM_HDR_SIG, POOL_HDR_SIG_LEN);
+	vmp->addr = addr;
+	vmp->size = size;
+	vmp->caller_mapped = 0;
+
+	/* Prepare pool for jemalloc */
+	if (je_vmem_pool_create((void *)((uintptr_t)addr + Header_size),
+			size - Header_size, 1) == NULL) {
+		LOG(1, "return NULL");
+		util_unmap(vmp->addr, vmp->size);
+		return NULL;
+	}
+
+	/*
+	 * If possible, turn off all permissions on the pool header page.
+	 *
+	 * The prototype PMFS doesn't allow this when large pages are in
+	 * use not it is not considered an error if this fails.
+	 */
+	util_range_none(addr, sizeof (struct pool_hdr));
+
+	LOG(3, "vmp %p", vmp);
+	return vmp;
+}
+
+/*
+ * vmem_pool_create_in_region -- create a memory pool in a given range
+ */
+VMEM *
+vmem_pool_create_in_region(void *addr, size_t size)
+{
+	LOG(3, "addr %p size %zu", addr, size);
+
+	if (size < VMEM_MIN_POOL) {
+		LOG(1, "size %zu smaller than %zu", size, VMEM_MIN_POOL);
+		errno = EINVAL;
+		return NULL;
+	}
+
+	/* store opaque info at beginning of mapped area */
+	struct vmem *vmp = addr;
+	memset(&vmp->hdr, '\0', sizeof (vmp->hdr));
+	strncpy(vmp->hdr.signature, VMEM_HDR_SIG, POOL_HDR_SIG_LEN);
+	vmp->addr = addr;
+	vmp->size = size;
+	vmp->caller_mapped = 1;
+
+	/* Prepare pool for jemalloc */
+	if (je_vmem_pool_create((void *)((uintptr_t)addr + Header_size),
+				size - Header_size, 0) == NULL) {
+		LOG(1, "return NULL");
+		return NULL;
+	}
+
+#ifdef	notdef
+	/*
+	 * XXX not ready to call aligned util_range_none() yet,
+	 * addr should be aligned to do that.
+	 *
+	 * If possible, turn off all permissions on the pool header page.
+	 *
+	 * The prototype PMFS doesn't allow this when large pages are in
+	 * use not it is not considered an error if this fails.
+	 */
+	util_range_none(addr, sizeof (struct pool_hdr));
+#endif	/* notdef */
+
+	LOG(3, "vmp %p", vmp);
+	return vmp;
+}
+
+/*
+ * vmem_pool_delete -- delete a memory pool
+ */
+void
+vmem_pool_delete(VMEM *vmp)
+{
+	LOG(3, "vmp %p", vmp);
+
+	je_vmem_pool_delete((pool_t *)((uintptr_t)vmp + Header_size));
+
+	if (vmp->caller_mapped == 0)
+		util_unmap(vmp->addr, vmp->size);
+}
+
+/*
+ * vmem_pool_check -- memory pool consistency check
+ */
+int
+vmem_pool_check(VMEM *vmp)
+{
+	LOG(3, "vmp %p", vmp);
+
+	if (strncmp(vmp->hdr.signature, VMEM_HDR_SIG, POOL_HDR_SIG_LEN) != 0) {
+		return 0;
+	}
+
+	/* XXX stub */
+	return 1;
+}
+
+/*
+ * vmem_pool_freespace -- return current freespace in memory pool
+ */
+size_t
+vmem_pool_freespace(VMEM *vmp)
+{
+	LOG(3, "vmp %p", vmp);
+
+	/* XXX stub */
+	return vmp->size;
+}
+
+/*
+ * vmem_pool_stats_print -- spew memory allocator stats for a pool
+ */
+void
+vmem_pool_stats_print(VMEM *vmp, const char *opts)
+{
+	LOG(3, "vmp %p opts \"%s\"", vmp, opts);
+
+	je_vmem_pool_malloc_stats_print(
+			(pool_t *)((uintptr_t)vmp + Header_size),
+			print_jemalloc_stats, NULL, opts);
+}
+
+/*
+ * vmem_malloc -- allocate memory
+ */
+void *
+vmem_malloc(VMEM *vmp, size_t size)
+{
+	LOG(3, "vmp %p size %zu", vmp, size);
+
+	return je_vmem_pool_malloc(
+			(pool_t *)((uintptr_t)vmp + Header_size), size);
+}
+
+/*
+ * vmem_free -- free memory
+ */
+void
+vmem_free(VMEM *vmp, void *ptr)
+{
+	LOG(3, "vmp %p ptr %p", vmp, ptr);
+
+	ASSERT(ptr != NULL);
+	je_vmem_pool_free((pool_t *)((uintptr_t)vmp + Header_size), ptr);
+}
+
+/*
+ * vmem_calloc -- allocate zeroed memory
+ */
+void *
+vmem_calloc(VMEM *vmp, size_t nmemb, size_t size)
+{
+	LOG(3, "vmp %p nmemb %zu size %zu", vmp, nmemb, size);
+
+	return je_vmem_pool_calloc((pool_t *)((uintptr_t)vmp + Header_size),
+			nmemb, size);
+}
+
+/*
+ * vmem_realloc -- resize a memory allocation
+ */
+void *
+vmem_realloc(VMEM *vmp, void *ptr, size_t size)
+{
+	LOG(3, "vmp %p ptr %p size %zu", vmp, ptr, size);
+
+	return je_vmem_pool_ralloc((pool_t *)((uintptr_t)vmp + Header_size),
+			ptr, size);
+}
+
+/*
+ * vmem_aligned_alloc -- allocate aligned memory
+ */
+void *
+vmem_aligned_alloc(VMEM *vmp, size_t alignment, size_t size)
+{
+	LOG(3, "vmp %p alignment %zu size %zu", vmp, alignment, size);
+
+	return je_vmem_pool_aligned_alloc(
+			(pool_t *)((uintptr_t)vmp + Header_size),
+			alignment, size);
+}
+
+/*
+ * vmem_strdup -- allocate memory for copy of string
+ */
+char *
+vmem_strdup(VMEM *vmp, const char *s)
+{
+	LOG(3, "vmp %p s %p", vmp, s);
+
+	size_t size = strlen(s) + 1;
+	void *retaddr = je_vmem_pool_malloc(
+			(pool_t *)((uintptr_t)vmp + Header_size), size);
+	if (retaddr == NULL)
+		return NULL;
+
+	return (char *)memcpy(retaddr, s, size);
+}
+
+/*
+ * vmem_tmpfile -- reserve space in an unlinked file and memory-map it
+ *
+ * size must be multiple of page size.
+ */
+static void *
+vmem_tmpfile(const char *dir, size_t size)
+{
+	static char template[] = "/vmem.XXXXXX";
+
+	char fullname[strlen(dir) + sizeof (template)];
+	(void) strcpy(fullname, dir);
+	(void) strcat(fullname, template);
+
+	sigset_t set, oldset;
+	sigfillset(&set);
+	(void) sigprocmask(SIG_BLOCK, &set, &oldset);
+
+	int fd;
+	if ((fd = mkstemp(fullname)) < 0) {
+		LOG(1, "!mkstemp");
+		goto err;
+	}
+
+	(void) unlink(fullname);
+	(void) sigprocmask(SIG_SETMASK, &oldset, NULL);
+
+	LOG(3, "unlinked file is \"%s\"", fullname);
+
+	if ((errno = posix_fallocate(fd, 0, size)) != 0) {
+		LOG(1, "!posix_fallocate");
+		goto err;
+	}
+
+	void *base;
+	if ((base = util_map(fd, size, 0)) == NULL)
+		goto err;
+
+	(void) close(fd);
+	return base;
+
+err:
+	LOG(1, "return NULL");
+	int oerrno = errno;
+	(void) sigprocmask(SIG_SETMASK, &oldset, NULL);
+	if (fd != -1)
+		(void) close(fd);
+	errno = oerrno;
+	return NULL;
+}
diff --git a/src/vmem.h b/src/vmem.h
new file mode 100644
index 0000000000000000000000000000000000000000..d9fca88dc9f8d000e2cbcc017206a0defdc14c3e
--- /dev/null
+++ b/src/vmem.h
@@ -0,0 +1,56 @@
+/*
+ * Copyright (c) 2014, Intel Corporation
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ *     * Redistributions of source code must retain the above copyright
+ *       notice, this list of conditions and the following disclaimer.
+ *
+ *     * Redistributions in binary form must reproduce the above copyright
+ *       notice, this list of conditions and the following disclaimer in
+ *       the documentation and/or other materials provided with the
+ *       distribution.
+ *
+ *     * Neither the name of Intel Corporation nor the names of its
+ *       contributors may be used to endorse or promote products derived
+ *       from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+/*
+ * vmem.h -- internal definitions for libvmem
+ */
+
+#define	LOG_PREFIX "libvmem"
+#define	LOG_LEVEL_VAR "VMEM_LOG_LEVEL"
+#define	LOG_FILE_VAR "VMEM_LOG_FILE"
+
+/* attributes of the vmem memory pool format for the pool header */
+#define	VMEM_HDR_SIG "VMEM   "	/* must be 8 bytes including '\0' */
+#define	VMEM_FORMAT_MAJOR 1
+#define	VMEM_FORMAT_COMPAT 0x0000
+#define	VMEM_FORMAT_INCOMPAT 0x0000
+#define	VMEM_FORMAT_RO_COMPAT 0x0000
+
+extern unsigned long Pagesize;
+
+struct vmem {
+	struct pool_hdr hdr;	/* memory pool header */
+
+	void *addr;	/* mapped region */
+	size_t size;	/* size of mapped region */
+	int caller_mapped;
+};
diff --git a/utils/README b/utils/README
new file mode 100644
index 0000000000000000000000000000000000000000..5c977d11f6e098b91be299c32e863133d3e09d84
--- /dev/null
+++ b/utils/README
@@ -0,0 +1,5 @@
+Linux NVM Library
+
+This is utils/README.
+
+The scripts found here are used during library development.
diff --git a/utils/cstyle b/utils/cstyle
new file mode 100755
index 0000000000000000000000000000000000000000..d524ddfa458b66e71c5d92e763b754389df774b1
--- /dev/null
+++ b/utils/cstyle
@@ -0,0 +1,951 @@
+#!/usr/bin/perl -w
+#
+# CDDL HEADER START
+#
+# The contents of this file are subject to the terms of the
+# Common Development and Distribution License (the "License").
+# You may not use this file except in compliance with the License.
+#
+# You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+# or http://www.opensolaris.org/os/licensing.
+# See the License for the specific language governing permissions
+# and limitations under the License.
+#
+# When distributing Covered Code, include this CDDL HEADER in each
+# file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+# If applicable, add the following below this CDDL HEADER, with the
+# fields enclosed by brackets "[]" replaced with your own identifying
+# information: Portions Copyright [yyyy] [name of copyright owner]
+#
+# CDDL HEADER END
+#
+#
+# Copyright 2008 Sun Microsystems, Inc.  All rights reserved.
+# Use is subject to license terms.
+#
+# @(#)cstyle 1.58 98/09/09 (from shannon)
+#ident	"%Z%%M%	%I%	%E% SMI"
+#
+# cstyle - check for some common stylistic errors.
+#
+#	cstyle is a sort of "lint" for C coding style.
+#	It attempts to check for the style used in the
+#	kernel, sometimes known as "Bill Joy Normal Form".
+#
+#	There's a lot this can't check for, like proper indentation
+#	of code blocks.  There's also a lot more this could check for.
+#
+#	A note to the non perl literate:
+#
+#		perl regular expressions are pretty much like egrep
+#		regular expressions, with the following special symbols
+#
+#		\s	any space character
+#		\S	any non-space character
+#		\w	any "word" character [a-zA-Z0-9_]
+#		\W	any non-word character
+#		\d	a digit [0-9]
+#		\D	a non-digit
+#		\b	word boundary (between \w and \W)
+#		\B	non-word boundary
+#
+
+require 5.0;
+use IO::File;
+use Getopt::Std;
+use strict;
+
+my $usage =
+"usage: cstyle [-chpvCP] [-o constructs] file ...
+	-c	check continuation indentation inside functions
+	-h	perform heuristic checks that are sometimes wrong
+	-p	perform some of the more picky checks
+	-v	verbose
+	-C	don't check anything in header block comments
+	-P	check for use of non-POSIX types
+	-o constructs
+		allow a comma-seperated list of optional constructs:
+		    doxygen	allow doxygen-style block comments (/** /*!)
+		    splint	allow splint-style lint comments (/*@ ... @*/)
+";
+
+my %opts;
+
+if (!getopts("cho:pvCP", \%opts)) {
+	print $usage;
+	exit 2;
+}
+
+my $check_continuation = $opts{'c'};
+my $heuristic = $opts{'h'};
+my $picky = $opts{'p'};
+my $verbose = $opts{'v'};
+my $ignore_hdr_comment = $opts{'C'};
+my $check_posix_types = $opts{'P'};
+
+my $doxygen_comments = 0;
+my $splint_comments = 0;
+
+if (defined($opts{'o'})) {
+	for my $x (split /,/, $opts{'o'}) {
+		if ($x eq "doxygen") {
+			$doxygen_comments = 1;
+		} elsif ($x eq "splint") {
+			$splint_comments = 1;
+		} else {
+			print "cstyle: unrecognized construct \"$x\"\n";
+			print $usage;
+			exit 2;
+		}
+	}
+}
+
+my ($filename, $line, $prev);		# shared globals
+
+my $fmt;
+my $hdr_comment_start;
+
+if ($verbose) {
+	$fmt = "%s: %d: %s\n%s\n";
+} else {
+	$fmt = "%s: %d: %s\n";
+}
+
+if ($doxygen_comments) {
+	# doxygen comments look like "/*!" or "/**"; allow them.
+	$hdr_comment_start = qr/^\s*\/\*[\!\*]?$/;
+} else {
+	$hdr_comment_start = qr/^\s*\/\*$/;
+}
+
+# Note, following must be in single quotes so that \s and \w work right.
+my $typename = '(int|char|short|long|unsigned|float|double' .
+    '|\w+_t|struct\s+\w+|union\s+\w+|FILE)';
+
+# mapping of old types to POSIX compatible types
+my %old2posix = (
+	'unchar' => 'uchar_t',
+	'ushort' => 'ushort_t',
+	'uint' => 'uint_t',
+	'ulong' => 'ulong_t',
+	'u_int' => 'uint_t',
+	'u_short' => 'ushort_t',
+	'u_long' => 'ulong_t',
+	'u_char' => 'uchar_t',
+	'quad' => 'quad_t'
+);
+
+my $lint_re = qr/\/\*(?:
+	ARGSUSED[0-9]*|NOTREACHED|LINTLIBRARY|VARARGS[0-9]*|
+	CONSTCOND|CONSTANTCOND|CONSTANTCONDITION|EMPTY|
+	FALLTHRU|FALLTHROUGH|LINTED.*?|PRINTFLIKE[0-9]*|
+	PROTOLIB[0-9]*|SCANFLIKE[0-9]*|CSTYLED.*?
+    )\*\//x;
+
+my $splint_re = qr/\/\*@.*?@\*\//x;
+
+my $warlock_re = qr/\/\*\s*(?:
+	VARIABLES\ PROTECTED\ BY|
+	MEMBERS\ PROTECTED\ BY|
+	ALL\ MEMBERS\ PROTECTED\ BY|
+	READ-ONLY\ VARIABLES:|
+	READ-ONLY\ MEMBERS:|
+	VARIABLES\ READABLE\ WITHOUT\ LOCK:|
+	MEMBERS\ READABLE\ WITHOUT\ LOCK:|
+	LOCKS\ COVERED\ BY|
+	LOCK\ UNNEEDED\ BECAUSE|
+	LOCK\ NEEDED:|
+	LOCK\ HELD\ ON\ ENTRY:|
+	READ\ LOCK\ HELD\ ON\ ENTRY:|
+	WRITE\ LOCK\ HELD\ ON\ ENTRY:|
+	LOCK\ ACQUIRED\ AS\ SIDE\ EFFECT:|
+	READ\ LOCK\ ACQUIRED\ AS\ SIDE\ EFFECT:|
+	WRITE\ LOCK\ ACQUIRED\ AS\ SIDE\ EFFECT:|
+	LOCK\ RELEASED\ AS\ SIDE\ EFFECT:|
+	LOCK\ UPGRADED\ AS\ SIDE\ EFFECT:|
+	LOCK\ DOWNGRADED\ AS\ SIDE\ EFFECT:|
+	FUNCTIONS\ CALLED\ THROUGH\ POINTER|
+	FUNCTIONS\ CALLED\ THROUGH\ MEMBER|
+	LOCK\ ORDER:
+    )/x;
+
+my $err_stat = 0;		# exit status
+
+if ($#ARGV >= 0) {
+	foreach my $arg (@ARGV) {
+		my $fh = new IO::File $arg, "r";
+		if (!defined($fh)) {
+			printf "%s: can not open\n", $arg;
+		} else {
+			&cstyle($arg, $fh);
+			close $fh;
+		}
+	}
+} else {
+	&cstyle("<stdin>", *STDIN);
+}
+exit $err_stat;
+
+my $no_errs = 0;		# set for CSTYLED-protected lines
+
+sub err($) {
+	my ($error) = @_;
+	unless ($no_errs) {
+		printf $fmt, $filename, $., $error, $line;
+		$err_stat = 1;
+	}
+}
+
+sub err_prefix($$) {
+	my ($prevline, $error) = @_;
+	my $out = $prevline."\n".$line;
+	unless ($no_errs) {
+		printf $fmt, $filename, $., $error, $out;
+		$err_stat = 1;
+	}
+}
+
+sub err_prev($) {
+	my ($error) = @_;
+	unless ($no_errs) {
+		printf $fmt, $filename, $. - 1, $error, $prev;
+		$err_stat = 1;
+	}
+}
+
+sub cstyle($$) {
+
+my ($fn, $filehandle) = @_;
+$filename = $fn;			# share it globally
+
+my $in_cpp = 0;
+my $next_in_cpp = 0;
+
+my $in_comment = 0;
+my $in_header_comment = 0;
+my $comment_done = 0;
+my $in_warlock_comment = 0;
+my $in_function = 0;
+my $in_function_header = 0;
+my $in_declaration = 0;
+my $note_level = 0;
+my $nextok = 0;
+my $nocheck = 0;
+
+my $in_string = 0;
+
+my ($okmsg, $comment_prefix);
+
+$line = '';
+$prev = '';
+reset_indent();
+
+line: while (<$filehandle>) {
+	s/\r?\n$//;	# strip return and newline
+
+	# save the original line, then remove all text from within
+	# double or single quotes, we do not want to check such text.
+
+	$line = $_;
+
+	#
+	# C allows strings to be continued with a backslash at the end of
+	# the line.  We translate that into a quoted string on the previous
+	# line followed by an initial quote on the next line.
+	#
+	# (we assume that no-one will use backslash-continuation with character
+	# constants)
+	#
+	$_ = '"' . $_		if ($in_string && !$nocheck && !$in_comment);
+
+	#
+	# normal strings and characters
+	#
+	s/'([^\\']|\\[^xX0]|\\0[0-9]*|\\[xX][0-9a-fA-F]*)'/''/g;
+	s/"([^\\"]|\\.)*"/\"\"/g;
+
+	#
+	# detect string continuation
+	#
+	if ($nocheck || $in_comment) {
+		$in_string = 0;
+	} else {
+		#
+		# Now that all full strings are replaced with "", we check
+		# for unfinished strings continuing onto the next line.
+		#
+		$in_string =
+		    (s/([^"](?:"")*)"([^\\"]|\\.)*\\$/$1""/ ||
+		    s/^("")*"([^\\"]|\\.)*\\$/""/);
+	}
+
+	#
+	# figure out if we are in a cpp directive
+	#
+	$in_cpp = $next_in_cpp || /^\s*#/;	# continued or started
+	$next_in_cpp = $in_cpp && /\\$/;	# only if continued
+
+	# strip off trailing backslashes, which appear in long macros
+	s/\s*\\$//;
+
+	# an /* END CSTYLED */ comment ends a no-check block.
+	if ($nocheck) {
+		if (/\/\* *END *CSTYLED *\*\//) {
+			$nocheck = 0;
+		} else {
+			reset_indent();
+			next line;
+		}
+	}
+
+	# a /*CSTYLED*/ comment indicates that the next line is ok.
+	if ($nextok) {
+		if ($okmsg) {
+			err($okmsg);
+		}
+		$nextok = 0;
+		$okmsg = 0;
+		if (/\/\* *CSTYLED.*\*\//) {
+			/^.*\/\* *CSTYLED *(.*) *\*\/.*$/;
+			$okmsg = $1;
+			$nextok = 1;
+		}
+		$no_errs = 1;
+	} elsif ($no_errs) {
+		$no_errs = 0;
+	}
+
+	# check length of line.
+	# first, a quick check to see if there is any chance of being too long.
+	if (($line =~ tr/\t/\t/) * 7 + length($line) > 80) {
+		# yes, there is a chance.
+		# replace tabs with spaces and check again.
+		my $eline = $line;
+		1 while $eline =~
+		    s/\t+/' ' x (length($&) * 8 - length($`) % 8)/e;
+		if (length($eline) > 80) {
+			err("line > 80 characters");
+		}
+	}
+
+	# ignore NOTE(...) annotations (assumes NOTE is on lines by itself).
+	if ($note_level || /\b_?NOTE\s*\(/) { # if in NOTE or this is NOTE
+		s/[^()]//g;			  # eliminate all non-parens
+		$note_level += s/\(//g - length;  # update paren nest level
+		next;
+	}
+
+	# a /* BEGIN CSTYLED */ comment starts a no-check block.
+	if (/\/\* *BEGIN *CSTYLED *\*\//) {
+		$nocheck = 1;
+	}
+
+	# a /*CSTYLED*/ comment indicates that the next line is ok.
+	if (/\/\* *CSTYLED.*\*\//) {
+		/^.*\/\* *CSTYLED *(.*) *\*\/.*$/;
+		$okmsg = $1;
+		$nextok = 1;
+	}
+	if (/\/\/ *CSTYLED/) {
+		/^.*\/\/ *CSTYLED *(.*)$/;
+		$okmsg = $1;
+		$nextok = 1;
+	}
+
+	# universal checks; apply to everything
+	if (/\t +\t/) {
+		err("spaces between tabs");
+	}
+	if (/ \t+ /) {
+		err("tabs between spaces");
+	}
+	if (/\s$/) {
+		err("space or tab at end of line");
+	}
+	if (/[^ \t(]\/\*/ && !/\w\(\/\*.*\*\/\);/) {
+		err("comment preceded by non-blank");
+	}
+
+	# is this the beginning or ending of a function?
+	# (not if "struct foo\n{\n")
+	if (/^{$/ && $prev =~ /\)\s*(const\s*)?(\/\*.*\*\/\s*)?\\?$/) {
+		$in_function = 1;
+		$in_declaration = 1;
+		$in_function_header = 0;
+		$prev = $line;
+		next line;
+	}
+	if (/^}\s*(\/\*.*\*\/\s*)*$/) {
+		if ($prev =~ /^\s*return\s*;/) {
+			err_prev("unneeded return at end of function");
+		}
+		$in_function = 0;
+		reset_indent();		# we don't check between functions
+		$prev = $line;
+		next line;
+	}
+	if (/^\w*\($/) {
+		$in_function_header = 1;
+	}
+
+	if ($in_warlock_comment && /\*\//) {
+		$in_warlock_comment = 0;
+		$prev = $line;
+		next line;
+	}
+
+	# a blank line terminates the declarations within a function.
+	# XXX - but still a problem in sub-blocks.
+	if ($in_declaration && /^$/) {
+		$in_declaration = 0;
+	}
+
+	if ($comment_done) {
+		$in_comment = 0;
+		$in_header_comment = 0;
+		$comment_done = 0;
+	}
+	# does this looks like the start of a block comment?
+	if (/$hdr_comment_start/) {
+		if (!/^\t*\/\*/) {
+			err("block comment not indented by tabs");
+		}
+		$in_comment = 1;
+		/^(\s*)\//;
+		$comment_prefix = $1;
+		if ($comment_prefix eq "") {
+			$in_header_comment = 1;
+		}
+		$prev = $line;
+		next line;
+	}
+	# are we still in the block comment?
+	if ($in_comment) {
+		if (/^$comment_prefix \*\/$/) {
+			$comment_done = 1;
+		} elsif (/\*\//) {
+			$comment_done = 1;
+			err("improper block comment close")
+			    unless ($ignore_hdr_comment && $in_header_comment);
+		} elsif (!/^$comment_prefix \*[ \t]/ &&
+		    !/^$comment_prefix \*$/) {
+			err("improper block comment")
+			    unless ($ignore_hdr_comment && $in_header_comment);
+		}
+	}
+
+	if ($in_header_comment && $ignore_hdr_comment) {
+		$prev = $line;
+		next line;
+	}
+
+	# check for errors that might occur in comments and in code.
+
+	# allow spaces to be used to draw pictures in header comments.
+	if (/[^ ]     / && !/".*     .*"/ && !$in_header_comment) {
+		err("spaces instead of tabs");
+	}
+	if (/^ / && !/^ \*[ \t\/]/ && !/^ \*$/ &&
+	    (!/^    \w/ || $in_function != 0)) {
+		err("indent by spaces instead of tabs");
+	}
+	if (/^\t+ [^ \t\*]/ || /^\t+  \S/ || /^\t+   \S/) {
+		err("continuation line not indented by 4 spaces");
+	}
+	if (/$warlock_re/ && !/\*\//) {
+		$in_warlock_comment = 1;
+		$prev = $line;
+		next line;
+	}
+	if (/^\s*\/\*./ && !/^\s*\/\*.*\*\// && !/$hdr_comment_start/) {
+		err("improper first line of block comment");
+	}
+
+	if ($in_comment) {	# still in comment, don't do further checks
+		$prev = $line;
+		next line;
+	}
+
+	if ((/[^(]\/\*\S/ || /^\/\*\S/) &&
+	    !(/$lint_re/ || ($splint_comments && /$splint_re/))) {
+		err("missing blank after open comment");
+	}
+	if (/\S\*\/[^)]|\S\*\/$/ &&
+	    !(/$lint_re/ || ($splint_comments && /$splint_re/))) {
+		err("missing blank before close comment");
+	}
+	if (/\/\/\S/) {		# C++ comments
+		err("missing blank after start comment");
+	}
+	# check for unterminated single line comments, but allow them when
+	# they are used to comment out the argument list of a function
+	# declaration.
+	if (/\S.*\/\*/ && !/\S.*\/\*.*\*\// && !/\(\/\*/) {
+		err("unterminated single line comment");
+	}
+
+	if (/^(#else|#endif|#include)(.*)$/) {
+		$prev = $line;
+		if ($picky) {
+			my $directive = $1;
+			my $clause = $2;
+			# Enforce ANSI rules for #else and #endif: no noncomment
+			# identifiers are allowed after #endif or #else.  Allow
+			# C++ comments since they seem to be a fact of life.
+			if ((($1 eq "#endif") || ($1 eq "#else")) &&
+			    ($clause ne "") &&
+			    (!($clause =~ /^\s+\/\*.*\*\/$/)) &&
+			    (!($clause =~ /^\s+\/\/.*$/))) {
+				err("non-comment text following " .
+				    "$directive (or malformed $directive " .
+				    "directive)");
+			}
+		}
+		next line;
+	}
+
+	#
+	# delete any comments and check everything else.  Note that
+	# ".*?" is a non-greedy match, so that we don't get confused by
+	# multiple comments on the same line.
+	#
+	s/\/\*.*?\*\///g;
+	s/\/\/.*$//;		# C++ comments
+
+	# delete any trailing whitespace; we have already checked for that.
+	s/\s*$//;
+
+	# following checks do not apply to text in comments.
+
+	if (/[^<>\s][!<>=]=/ || /[^<>][!<>=]=[^\s,]/ ||
+	    (/[^->]>[^,=>\s]/ && !/[^->]>$/) ||
+	    (/[^<]<[^,=<\s]/ && !/[^<]<$/) ||
+	    /[^<\s]<[^<]/ || /[^->\s]>[^>]/) {
+		err("missing space around relational operator");
+	}
+	if (/\S>>=/ || /\S<<=/ || />>=\S/ || /<<=\S/ || /\S[-+*\/&|^%]=/ ||
+	    (/[^-+*\/&|^%!<>=\s]=[^=]/ && !/[^-+*\/&|^%!<>=\s]=$/) ||
+	    (/[^!<>=]=[^=\s]/ && !/[^!<>=]=$/)) {
+		# XXX - should only check this for C++ code
+		# XXX - there are probably other forms that should be allowed
+		if (!/\soperator=/) {
+			err("missing space around assignment operator");
+		}
+	}
+	if (/[,;]\S/ && !/\bfor \(;;\)/) {
+		err("comma or semicolon followed by non-blank");
+	}
+	# allow "for" statements to have empty "while" clauses
+	if (/\s[,;]/ && !/^[\t]+;$/ && !/^\s*for \([^;]*; ;[^;]*\)/) {
+		err("comma or semicolon preceded by blank");
+	}
+	if (/^\s*(&&|\|\|)/) {
+		err("improper boolean continuation");
+	}
+	if (/\S   *(&&|\|\|)/ || /(&&|\|\|)   *\S/) {
+		err("more than one space around boolean operator");
+	}
+	if (/\b(for|if|while|switch|sizeof|return|case)\(/) {
+		err("missing space between keyword and paren");
+	}
+	if (/(\b(for|if|while|switch|return)\b.*){2,}/ && !/^#define/) {
+		# multiple "case" and "sizeof" allowed
+		err("more than one keyword on line");
+	}
+	if (/\b(for|if|while|switch|sizeof|return|case)\s\s+\(/ &&
+	    !/^#if\s+\(/) {
+		err("extra space between keyword and paren");
+	}
+	# try to detect "func (x)" but not "if (x)" or
+	# "#define foo (x)" or "int (*func)();"
+	if (/\w\s\(/) {
+		my $s = $_;
+		# strip off all keywords on the line
+		s/\b(for|if|while|switch|return|case|sizeof)\s\(/XXX(/g;
+		s/#elif\s\(/XXX(/g;
+		s/^#define\s+\w+\s+\(/XXX(/;
+		# do not match things like "void (*f)();"
+		# or "typedef void (func_t)();"
+		s/\w\s\(+\*/XXX(*/g;
+		s/\b($typename|void)\s+\(+/XXX(/og;
+		if (/\w\s\(/) {
+			err("extra space between function name and left paren");
+		}
+		$_ = $s;
+	}
+	# try to detect "int foo(x)", but not "extern int foo(x);"
+	# XXX - this still trips over too many legitimate things,
+	# like "int foo(x,\n\ty);"
+#		if (/^(\w+(\s|\*)+)+\w+\(/ && !/\)[;,](\s|)*$/ &&
+#		    !/^(extern|static)\b/) {
+#			err("return type of function not on separate line");
+#		}
+	# this is a close approximation
+	if (/^(\w+(\s|\*)+)+\w+\(.*\)(\s|)*$/ &&
+	    !/^(extern|static)\b/) {
+		err("return type of function not on separate line");
+	}
+	if (/^#define /) {
+		err("#define followed by space instead of tab");
+	}
+	# AON C-style doesn't require this.
+	#if (/^\s*return\W[^;]*;/ && !/^\s*return\s*\(.*\);/) {
+	#	err("unparenthesized return expression");
+	#}
+	if (/\bsizeof\b/ && !/\bsizeof\s*\(.*\)/) {
+		err("unparenthesized sizeof expression");
+	}
+	if (/\(\s/) {
+		err("whitespace after left paren");
+	}
+	# allow "for" statements to have empty "continue" clauses
+	if (/\s\)/ && !/^\s*for \([^;]*;[^;]*; \)/) {
+		err("whitespace before right paren");
+	}
+	if (/^\s*\(void\)[^ ]/) {
+		err("missing space after (void) cast");
+	}
+	if (/\S{/ && !/{{/) {
+		err("missing space before left brace");
+	}
+	if ($in_function && /^\s+{/ &&
+	    ($prev =~ /\)\s*$/ || $prev =~ /\bstruct\s+\w+$/)) {
+		err("left brace starting a line");
+	}
+	if (/}(else|while)/) {
+		err("missing space after right brace");
+	}
+	if (/}\s\s+(else|while)/) {
+		err("extra space after right brace");
+	}
+	if (/\b_VOID\b|\bVOID\b|\bSTATIC\b/) {
+		err("obsolete use of VOID or STATIC");
+	}
+	if (/\b$typename\*/o) {
+		err("missing space between type name and *");
+	}
+	if (/^\s+#/) {
+		err("preprocessor statement not in column 1");
+	}
+	if (/^#\s/) {
+		err("blank after preprocessor #");
+	}
+	if (/!\s*(strcmp|strncmp|bcmp)\s*\(/) {
+		err("don't use boolean ! with comparison functions");
+	}
+
+	#
+	# We completely ignore, for purposes of indentation:
+	#  * lines outside of functions
+	#  * preprocessor lines
+	#
+	if ($check_continuation && $in_function && !$in_cpp) {
+		process_indent($_);
+	}
+	if ($picky) {
+		# try to detect spaces after casts, but allow (e.g.)
+		# "sizeof (int) + 1", "void (*funcptr)(int) = foo;", and
+		# "int foo(int) __NORETURN;"
+		if ((/^\($typename( \*+)?\)\s/o ||
+		    /\W\($typename( \*+)?\)\s/o) &&
+		    !/sizeof\s*\($typename( \*)?\)\s/o &&
+		    !/\($typename( \*+)?\)\s+=[^=]/o) {
+			err("space after cast");
+		}
+		if (/\b$typename\s*\*\s/o &&
+		    !/\b$typename\s*\*\s+const\b/o) {
+			err("unary * followed by space");
+		}
+	}
+	if ($check_posix_types) {
+		# try to detect old non-POSIX types.
+		# POSIX requires all non-standard typedefs to end in _t,
+		# but historically these have been used.
+		if (/\b(unchar|ushort|uint|ulong|u_int|u_short|u_long|u_char|quad)\b/) {
+			err("non-POSIX typedef $1 used: use $old2posix{$1} instead");
+		}
+	}
+	if ($heuristic) {
+		# cannot check this everywhere due to "struct {\n...\n} foo;"
+		if ($in_function && !$in_declaration &&
+		    /}./ && !/}\s+=/ && !/{.*}[;,]$/ && !/}(\s|)*$/ &&
+		    !/} (else|while)/ && !/}}/) {
+			err("possible bad text following right brace");
+		}
+		# cannot check this because sub-blocks in
+		# the middle of code are ok
+		if ($in_function && /^\s+{/) {
+			err("possible left brace starting a line");
+		}
+	}
+	if (/^\s*else\W/) {
+		if ($prev =~ /^\s*}$/) {
+			err_prefix($prev,
+			    "else and right brace should be on same line");
+		}
+	}
+	$prev = $line;
+}
+
+if ($prev eq "") {
+	err("last line in file is blank");
+}
+
+}
+
+#
+# Continuation-line checking
+#
+# The rest of this file contains the code for the continuation checking
+# engine.  It's a pretty simple state machine which tracks the expression
+# depth (unmatched '('s and '['s).
+#
+# Keep in mind that the argument to process_indent() has already been heavily
+# processed; all comments have been replaced by control-A, and the contents of
+# strings and character constants have been elided.
+#
+
+my $cont_in;		# currently inside of a continuation
+my $cont_off;		# skipping an initializer or definition
+my $cont_noerr;		# suppress cascading errors
+my $cont_start;		# the line being continued
+my $cont_base;		# the base indentation
+my $cont_first;		# this is the first line of a statement
+my $cont_multiseg;	# this continuation has multiple segments
+
+my $cont_special;	# this is a C statement (if, for, etc.)
+my $cont_macro;		# this is a macro
+my $cont_case;		# this is a multi-line case
+
+my @cont_paren;		# the stack of unmatched ( and [s we've seen
+
+sub
+reset_indent()
+{
+	$cont_in = 0;
+	$cont_off = 0;
+}
+
+sub
+delabel($)
+{
+	#
+	# replace labels with tabs.  Note that there may be multiple
+	# labels on a line.
+	#
+	local $_ = $_[0];
+
+	while (/^(\t*)( *(?:(?:\w+\s*)|(?:case\b[^:]*)): *)(.*)$/) {
+		my ($pre_tabs, $label, $rest) = ($1, $2, $3);
+		$_ = $pre_tabs;
+		while ($label =~ s/^([^\t]*)(\t+)//) {
+			$_ .= "\t" x (length($2) + length($1) / 8);
+		}
+		$_ .= ("\t" x (length($label) / 8)).$rest;
+	}
+
+	return ($_);
+}
+
+sub
+process_indent($)
+{
+	require strict;
+	local $_ = $_[0];			# preserve the global $_
+
+	s///g;	# No comments
+	s/\s+$//;	# Strip trailing whitespace
+
+	return			if (/^$/);	# skip empty lines
+
+	# regexps used below; keywords taking (), macros, and continued cases
+	my $special = '(?:(?:\}\s*)?else\s+)?(?:if|for|while|switch)\b';
+	my $macro = '[A-Z_][A-Z_0-9]*\(';
+	my $case = 'case\b[^:]*$';
+
+	# skip over enumerations, array definitions, initializers, etc.
+	if ($cont_off <= 0 && !/^\s*$special/ &&
+	    (/(?:(?:\b(?:enum|struct|union)\s*[^\{]*)|(?:\s+=\s*)){/ ||
+	    (/^\s*{/ && $prev =~ /=\s*(?:\/\*.*\*\/\s*)*$/))) {
+		$cont_in = 0;
+		$cont_off = tr/{/{/ - tr/}/}/;
+		return;
+	}
+	if ($cont_off) {
+		$cont_off += tr/{/{/ - tr/}/}/;
+		return;
+	}
+
+	if (!$cont_in) {
+		$cont_start = $line;
+
+		if (/^\t* /) {
+			err("non-continuation indented 4 spaces");
+			$cont_noerr = 1;		# stop reporting
+		}
+		$_ = delabel($_);	# replace labels with tabs
+
+		# check if the statement is complete
+		return		if (/^\s*\}?$/);
+		return		if (/^\s*\}?\s*else\s*\{?$/);
+		return		if (/^\s*do\s*\{?$/);
+		return		if (/{$/);
+		return		if (/}[,;]?$/);
+
+		# Allow macros on their own lines
+		return		if (/^\s*[A-Z_][A-Z_0-9]*$/);
+
+		# cases we don't deal with, generally non-kosher
+		if (/{/) {
+			err("stuff after {");
+			return;
+		}
+
+		# Get the base line, and set up the state machine
+		/^(\t*)/;
+		$cont_base = $1;
+		$cont_in = 1;
+		@cont_paren = ();
+		$cont_first = 1;
+		$cont_multiseg = 0;
+
+		# certain things need special processing
+		$cont_special = /^\s*$special/? 1 : 0;
+		$cont_macro = /^\s*$macro/? 1 : 0;
+		$cont_case = /^\s*$case/? 1 : 0;
+	} else {
+		$cont_first = 0;
+
+		# Strings may be pulled back to an earlier (half-)tabstop
+		unless ($cont_noerr || /^$cont_base    / ||
+		    (/^\t*(?:    )?(?:gettext\()?\"/ && !/^$cont_base\t/)) {
+			err_prefix($cont_start,
+			    "continuation should be indented 4 spaces");
+		}
+	}
+
+	my $rest = $_;			# keeps the remainder of the line
+
+	#
+	# The split matches 0 characters, so that each 'special' character
+	# is processed separately.  Parens and brackets are pushed and
+	# popped off the @cont_paren stack.  For normal processing, we wait
+	# until a ; or { terminates the statement.  "special" processing
+	# (if/for/while/switch) is allowed to stop when the stack empties,
+	# as is macro processing.  Case statements are terminated with a :
+	# and an empty paren stack.
+	#
+	foreach $_ (split /[^\(\)\[\]\{\}\;\:]*/) {
+		next		if (length($_) == 0);
+
+		# rest contains the remainder of the line
+		my $rxp = "[^\Q$_\E]*\Q$_\E";
+		$rest =~ s/^$rxp//;
+
+		if (/\(/ || /\[/) {
+			push @cont_paren, $_;
+		} elsif (/\)/ || /\]/) {
+			my $cur = $_;
+			tr/\)\]/\(\[/;
+
+			my $old = (pop @cont_paren);
+			if (!defined($old)) {
+				err("unexpected '$cur'");
+				$cont_in = 0;
+				last;
+			} elsif ($old ne $_) {
+				err("'$cur' mismatched with '$old'");
+				$cont_in = 0;
+				last;
+			}
+
+			#
+			# If the stack is now empty, do special processing
+			# for if/for/while/switch and macro statements.
+			#
+			next		if (@cont_paren != 0);
+			if ($cont_special) {
+				if ($rest =~ /^\s*{?$/) {
+					$cont_in = 0;
+					last;
+				}
+				if ($rest =~ /^\s*;$/) {
+					err("empty if/for/while body ".
+					    "not on its own line");
+					$cont_in = 0;
+					last;
+				}
+				if (!$cont_first && $cont_multiseg == 1) {
+					err_prefix($cont_start,
+					    "multiple statements continued ".
+					    "over multiple lines");
+					$cont_multiseg = 2;
+				} elsif ($cont_multiseg == 0) {
+					$cont_multiseg = 1;
+				}
+				# We've finished this section, start
+				# processing the next.
+				goto section_ended;
+			}
+			if ($cont_macro) {
+				if ($rest =~ /^$/) {
+					$cont_in = 0;
+					last;
+				}
+			}
+		} elsif (/\;/) {
+			if ($cont_case) {
+				err("unexpected ;");
+			} elsif (!$cont_special) {
+				err("unexpected ;")	if (@cont_paren != 0);
+				if (!$cont_first && $cont_multiseg == 1) {
+					err_prefix($cont_start,
+					    "multiple statements continued ".
+					    "over multiple lines");
+					$cont_multiseg = 2;
+				} elsif ($cont_multiseg == 0) {
+					$cont_multiseg = 1;
+				}
+				if ($rest =~ /^$/) {
+					$cont_in = 0;
+					last;
+				}
+				if ($rest =~ /^\s*special/) {
+					err("if/for/while/switch not started ".
+					    "on its own line");
+				}
+				goto section_ended;
+			}
+		} elsif (/\{/) {
+			err("{ while in parens/brackets") if (@cont_paren != 0);
+			err("stuff after {")		if ($rest =~ /[^\s}]/);
+			$cont_in = 0;
+			last;
+		} elsif (/\}/) {
+			err("} while in parens/brackets") if (@cont_paren != 0);
+			if (!$cont_special && $rest !~ /^\s*(while|else)\b/) {
+				if ($rest =~ /^$/) {
+					err("unexpected }");
+				} else {
+					err("stuff after }");
+				}
+				$cont_in = 0;
+				last;
+			}
+		} elsif (/\:/ && $cont_case && @cont_paren == 0) {
+			err("stuff after multi-line case") if ($rest !~ /$^/);
+			$cont_in = 0;
+			last;
+		}
+		next;
+section_ended:
+		# End of a statement or if/while/for loop.  Reset
+		# cont_special and cont_macro based on the rest of the
+		# line.
+		$cont_special = ($rest =~ /^\s*$special/)? 1 : 0;
+		$cont_macro = ($rest =~ /^\s*$macro/)? 1 : 0;
+		$cont_case = 0;
+		next;
+	}
+	$cont_noerr = 0			if (!$cont_in);
+}