master - [bcache] Add some unit tests for invalidate block.
by Joe Thornber
Gitweb: https://sourceware.org/git/?p=lvm2.git;a=commitdiff;h=8a14b8a733b95ccb92f...
Commit: 8a14b8a733b95ccb92fc8b907dc330bac474b712
Parent: 5b6e62dc1f3b27089179308fa2f7d004850d5a2c
Author: Joe Thornber <ejt(a)redhat.com>
AuthorDate: Fri Apr 27 09:12:57 2018 +0100
Committer: Joe Thornber <ejt(a)redhat.com>
CommitterDate: Fri Apr 27 09:12:57 2018 +0100
[bcache] Add some unit tests for invalidate block.
Trying to identify dct's lockup.
---
unit-test/bcache_t.c | 43 +++++++++++++++++++++++++++++++++++++++++++
1 files changed, 43 insertions(+), 0 deletions(-)
diff --git a/unit-test/bcache_t.c b/unit-test/bcache_t.c
index 4fe913b..23498a8 100644
--- a/unit-test/bcache_t.c
+++ b/unit-test/bcache_t.c
@@ -723,6 +723,46 @@ static void test_write_bad_io_stops_flush(void *context)
T_ASSERT(bcache_flush(cache));
}
+static void test_invalidate_not_present(void *context)
+{
+ struct fixture *f = context;
+ struct bcache *cache = f->cache;
+ int fd = 17;
+
+ bcache_invalidate(cache, fd, 0);
+}
+
+static void test_invalidate_present(void *context)
+{
+ struct fixture *f = context;
+ struct mock_engine *me = f->me;
+ struct bcache *cache = f->cache;
+ struct block *b;
+ int fd = 17;
+ int err;
+
+ _expect_read(me, fd, 0);
+ _expect(me, E_WAIT);
+ T_ASSERT(bcache_get(cache, fd, 0, 0, &b, &err));
+ bcache_put(b);
+
+ bcache_invalidate(cache, fd, 0);
+}
+
+static void test_invalidate_after_error(void *context)
+{
+ struct fixture *f = context;
+ struct mock_engine *me = f->me;
+ struct bcache *cache = f->cache;
+ struct block *b;
+ int fd = 17;
+ int err;
+
+ _expect_read_bad_issue(me, fd, 0);
+ T_ASSERT(!bcache_get(cache, fd, 0, 0, &b, &err));
+ bcache_invalidate(cache, fd, 0);
+}
+
// Tests to be written
// show invalidate works
// show invalidate_fd works
@@ -759,6 +799,9 @@ static struct test_suite *_small_tests(void)
T("read-bad-io-intermittent", "failed io, followed by success", test_read_bad_wait_intermittent);
T("write-bad-issue-stops-flush", "flush fails temporarily if any block fails to write", test_write_bad_issue_stops_flush);
T("write-bad-io-stops-flush", "flush fails temporarily if any block fails to write", test_write_bad_io_stops_flush);
+ T("invalidate-not-present", "invalidate a block that isn't in the cache", test_invalidate_not_present);
+ T("invalidate-present", "invalidate a block that is in the cache", test_invalidate_present);
+ T("invalidate-error", "invalidate a block that errored", test_invalidate_after_error);
return ts;
}
5 years, 11 months
master - clvmd: drop old saved_vg when returning new saved_vg
by David Teigland
Gitweb: https://sourceware.org/git/?p=lvm2.git;a=commitdiff;h=5b6e62dc1f3b2708917...
Commit: 5b6e62dc1f3b27089179308fa2f7d004850d5a2c
Parent: cdb8400de2d89e2e5901524acdd2178118d740b7
Author: David Teigland <teigland(a)redhat.com>
AuthorDate: Thu Apr 26 14:41:57 2018 -0500
Committer: David Teigland <teigland(a)redhat.com>
CommitterDate: Thu Apr 26 14:57:45 2018 -0500
clvmd: drop old saved_vg when returning new saved_vg
In some pvmove tests, clvmd uses the new (precommitted)
saved_vg, but then requests the old saved_vg, and
expects that the new saved_vg be returned instead of
the old. So, when returning the new saved_vg, forget
the old one so we don't return it again.
---
lib/activate/activate.c | 12 +++++-
lib/cache/lvmcache.c | 89 +++++++++++++++++++++++++++++++++++++++++++++--
lib/metadata/metadata.c | 2 +-
3 files changed, 97 insertions(+), 6 deletions(-)
diff --git a/lib/activate/activate.c b/lib/activate/activate.c
index 8e79cf5..7a2a945 100644
--- a/lib/activate/activate.c
+++ b/lib/activate/activate.c
@@ -2164,6 +2164,8 @@ static int _lv_suspend(struct cmd_context *cmd, const char *lvid_s,
vg_pre = lvmcache_get_saved_vg(vgid, 1);
if (!vg || !vg_pre) {
+ log_debug("lv_suspend dropping both saved vgs and rereading");
+
lvmcache_drop_saved_vgid(vgid);
vg = vg_read_by_vgid(cmd, vgid, 0);
@@ -2175,8 +2177,14 @@ static int _lv_suspend(struct cmd_context *cmd, const char *lvid_s,
goto out;
}
- log_debug("lv_suspend found vg %s vg %p vg_pre %p",
- vg->name, vg, vg_pre);
+ /*
+ * Note that vg and vg_pre returned by vg_read_by_vgid will
+ * not be the same as saved_vg_old/saved_vg_new that would
+ * be returned by lvmcache_get_saved_vg() because the saved_vg's
+ * are copies of the vg struct that is created by _vg_read.
+ * (Should we grab and use the saved_vg to use here instead of
+ * the vg returned by vg_read_by_vgid?)
+ */
if ((vg->status & EXPORTED_VG) || (vg_pre->status & EXPORTED_VG)) {
log_error("Volume group \"%s\" is exported", vg->name);
diff --git a/lib/cache/lvmcache.c b/lib/cache/lvmcache.c
index e88d350..bd92055 100644
--- a/lib/cache/lvmcache.c
+++ b/lib/cache/lvmcache.c
@@ -300,7 +300,7 @@ void lvmcache_save_vg(struct volume_group *vg, int precommitted)
vginfo->saved_vg_old_buf = susp_buf;
vginfo->saved_vg_old_cft = susp_cft;
vginfo->saved_vg_old = save_vg;
- log_debug_cache("lvmcache saved vg %s seqno %d %p",
+ log_debug_cache("lvmcache saved old vg %s seqno %d %p",
save_vg->name, save_vg->seqno, save_vg);
} else {
vginfo->saved_vg_new_buf = susp_buf;
@@ -326,10 +326,57 @@ struct volume_group *lvmcache_get_saved_vg(const char *vgid, int precommitted)
if (!(vginfo = lvmcache_vginfo_from_vgid(vgid)))
goto out;
+ /*
+ * Once new is returned, then also return new if old is requested,
+ * i.e. new becomes both old and new once it's used.
+ */
+
if (new)
vg = vginfo->saved_vg_new;
else if (old)
vg = vginfo->saved_vg_old;
+
+ if (vg && old) {
+ if (!vginfo->saved_vg_new)
+ log_debug_cache("lvmcache: get old saved_vg %d %s %p",
+ vg->seqno, vg->name, vg);
+ else
+ log_debug_cache("lvmcache: get old saved_vg %d %s %p new is %d %p",
+ vg->seqno, vg->name, vg,
+ vginfo->saved_vg_new->seqno,
+ vginfo->saved_vg_new);
+ }
+
+ if (vg && new) {
+ if (!vginfo->saved_vg_old)
+ log_debug_cache("lvmcache: get new (pre) saved_vg %d %s %p",
+ vg->seqno, vg->name, vg);
+ else
+ log_debug_cache("lvmcache: get new (pre) saved_vg %d %s %p old is %d %p",
+ vg->seqno, vg->name, vg,
+ vginfo->saved_vg_old->seqno,
+ vginfo->saved_vg_old);
+
+ /* Do we need to actually set saved_vg_old to match saved_vg_new?
+ * By just dropping old, we force a subsequent request for old to
+ * reread it rather than just using new. */
+ if (vginfo->saved_vg_old) {
+ log_debug_cache("lvmcache: drop saved_vg_old because new invalidates");
+ _saved_vg_free(vginfo, 1, 0);
+ }
+ }
+
+ if (!vg && new && vginfo->saved_vg_old)
+ log_warn("lvmcache_get_saved_vg pre %d wanted new but only have old %d %s",
+ precommitted,
+ vginfo->saved_vg_old->seqno,
+ vginfo->saved_vg_old->name);
+
+ if (!vg && old && vginfo->saved_vg_new)
+ log_warn("lvmcache_get_saved_vg pre %d wanted old but only have new %d %s",
+ precommitted,
+ vginfo->saved_vg_new->seqno,
+ vginfo->saved_vg_new->name);
out:
if (!vg)
log_debug_cache("lvmcache no saved vg %s pre %d", vgid, precommitted);
@@ -340,14 +387,49 @@ struct volume_group *lvmcache_get_saved_vg_latest(const char *vgid)
{
struct lvmcache_vginfo *vginfo;
struct volume_group *vg = NULL;
+ int old = 0;
+ int new = 0;
if (!(vginfo = lvmcache_vginfo_from_vgid(vgid)))
goto out;
- if (vginfo->saved_vg_committed)
+ if (vginfo->saved_vg_committed) {
vg = vginfo->saved_vg_new;
- else
+ new = 1;
+ } else {
vg = vginfo->saved_vg_old;
+ old = 1;
+ }
+
+ if (vg && old) {
+ if (!vginfo->saved_vg_new)
+ log_debug_cache("lvmcache: get_latest old saved_vg %d %s %p",
+ vg->seqno, vg->name, vg);
+ else
+ log_debug_cache("lvmcache: get_latest old saved_vg %d %s %p new is %d %p",
+ vg->seqno, vg->name, vg,
+ vginfo->saved_vg_new->seqno,
+ vginfo->saved_vg_new);
+ }
+
+ if (vg && new) {
+ if (!vginfo->saved_vg_old)
+ log_debug_cache("lvmcache: get_latest new (pre) saved_vg %d %s %p",
+ vg->seqno, vg->name, vg);
+ else
+ log_debug_cache("lvmcache: get_latest new (pre) saved_vg %d %s %p old is %d %p",
+ vg->seqno, vg->name, vg,
+ vginfo->saved_vg_old->seqno,
+ vginfo->saved_vg_old);
+
+ /* Do we need to actually set saved_vg_old to match saved_vg_new?
+ * By just dropping old, we force a subsequent request for old to
+ * reread it rather than just using new. */
+ if (vginfo->saved_vg_old) {
+ log_debug_cache("lvmcache: drop saved_vg_old because new invalidates");
+ _saved_vg_free(vginfo, 1, 0);
+ }
+ }
out:
if (!vg)
log_debug_cache("lvmcache no saved vg %s", vgid);
@@ -1246,6 +1328,7 @@ int lvmcache_label_scan(struct cmd_context *cmd)
goto out;
}
+ /* FIXME: can this happen? */
if (!cmd->full_filter) {
log_error("label scan is missing full filter");
goto out;
diff --git a/lib/metadata/metadata.c b/lib/metadata/metadata.c
index 3c1d8a4..97225df 100644
--- a/lib/metadata/metadata.c
+++ b/lib/metadata/metadata.c
@@ -3869,7 +3869,7 @@ static struct volume_group *_vg_read(struct cmd_context *cmd,
if (warn_flags & SKIP_RESCAN)
goto find_vg;
skipped_rescan = 0;
- log_debug_metadata("Rescanning devices for for %s", vgname);
+ log_debug_metadata("Rescanning devices for %s", vgname);
lvmcache_label_rescan_vg(cmd, vgname, vgid);
} else {
log_debug_metadata("Skipped rescanning devices for %s", vgname);
5 years, 11 months
master - scan: refresh filters before scan
by David Teigland
Gitweb: https://sourceware.org/git/?p=lvm2.git;a=commitdiff;h=cdb8400de2d89e2e590...
Commit: cdb8400de2d89e2e5901524acdd2178118d740b7
Parent: 1c97fda42576367e263f8c928c060271787ad1c1
Author: David Teigland <teigland(a)redhat.com>
AuthorDate: Thu Apr 26 14:48:13 2018 -0500
Committer: David Teigland <teigland(a)redhat.com>
CommitterDate: Thu Apr 26 14:48:13 2018 -0500
scan: refresh filters before scan
The filters save information about devices that should
be ignored, so if we need to repeat a scan (unusual,
but happens in clvmd), we need to update the filters.
---
lib/cache/lvmcache.c | 3 +++
1 files changed, 3 insertions(+), 0 deletions(-)
diff --git a/lib/cache/lvmcache.c b/lib/cache/lvmcache.c
index 7534567..e88d350 100644
--- a/lib/cache/lvmcache.c
+++ b/lib/cache/lvmcache.c
@@ -1251,6 +1251,9 @@ int lvmcache_label_scan(struct cmd_context *cmd)
goto out;
}
+ if (!refresh_filters(cmd))
+ log_error("Scan failed to refresh device filter.");
+
/*
* Duplicates found during this label scan are added to _found_duplicate_devs().
*/
5 years, 11 months
master - [bcache] get all unit tests passing again
by Joe Thornber
Gitweb: https://sourceware.org/git/?p=lvm2.git;a=commitdiff;h=1c97fda42576367e263...
Commit: 1c97fda42576367e263f8c928c060271787ad1c1
Parent: ea34dad66fe4a46a2f7ec51c4358144f6cb3ed67
Author: Joe Thornber <ejt(a)redhat.com>
AuthorDate: Thu Apr 26 13:13:27 2018 +0100
Committer: Joe Thornber <ejt(a)redhat.com>
CommitterDate: Thu Apr 26 13:13:27 2018 +0100
[bcache] get all unit tests passing again
---
lib/device/bcache.c | 33 +++++++++++++--------------------
1 files changed, 13 insertions(+), 20 deletions(-)
diff --git a/lib/device/bcache.c b/lib/device/bcache.c
index ea8f702..641838f 100644
--- a/lib/device/bcache.c
+++ b/lib/device/bcache.c
@@ -537,29 +537,16 @@ static void _complete_io(void *context, int err)
*/
dm_list_del(&b->list);
- if (b->error)
- memset(b->data, 0, cache->block_sectors << SECTOR_SHIFT);
-
/* Things don't work with this block of code, but work without it. */
-#if 0
if (b->error) {
log_warn("bcache io error %d fd %d", b->error, b->fd);
- if (b->io_dir == DIR_READ) {
- // We can just forget about this block, since there's
- // no dirty data to be written back.
- _hash_remove(b);
- dm_list_add(&cache->free, &b->list);
- } else
- dm_list_add(&cache->errored, &b->list);
+ dm_list_add(&cache->errored, &b->list);
} else {
_clear_flags(b, BF_DIRTY);
_link_block(b);
}
-#endif
- _clear_flags(b, BF_DIRTY);
- _link_block(b);
}
/*
@@ -908,17 +895,23 @@ bool bcache_get(struct bcache *cache, int fd, block_address index,
b = _lookup_or_read_block(cache, fd, index, flags);
if (b) {
+ if (b->error) {
+ if (b->io_dir == DIR_READ) {
+ // Now we know the read failed we can just forget
+ // about this block, since there's no dirty data to
+ // be written back.
+ _hash_remove(b);
+ dm_list_add(&cache->free, &b->list);
+ }
+ *error = b->error;
+ return false;
+ }
+
if (!b->ref_count)
cache->nr_locked++;
b->ref_count++;
*result = b;
-
- if (error)
- *error = b->error;
-
- if (b->error)
- return false;
return true;
}
5 years, 11 months
master - [unit-test] Push the new unit test framwork.
by Joe Thornber
Gitweb: https://sourceware.org/git/?p=lvm2.git;a=commitdiff;h=ea34dad66fe4a46a2f7...
Commit: ea34dad66fe4a46a2f7ec51c4358144f6cb3ed67
Parent: c7fdacbc5001f3bdfaa441fedb7da120af5d8af9
Author: Joe Thornber <ejt(a)redhat.com>
AuthorDate: Thu Apr 26 11:59:39 2018 +0100
Committer: Joe Thornber <ejt(a)redhat.com>
CommitterDate: Thu Apr 26 11:59:39 2018 +0100
[unit-test] Push the new unit test framwork.
See doc/unit-test.txt for details.
Some bcache tests failing. Probably due to dct changing semantics, will
fix in follow up patch.
---
.gitignore | 2 +
Makefile.in | 7 +-
configure | 175 +----
configure.in | 7 +-
doc/unit-tests.txt | 257 +++++
report-generators/lib/log.rb | 40 -
report-generators/lib/report_templates.rb | 38 -
report-generators/lib/reports.rb | 58 --
report-generators/lib/schedule_file.rb | 56 --
report-generators/lib/string-store.rb | 42 -
report-generators/memcheck.rb | 86 --
report-generators/templates/boiler_plate.rhtml | 25 -
report-generators/templates/index.rhtml | 17 -
report-generators/templates/memcheck.rhtml | 30 -
report-generators/templates/unit_detail.rhtml | 37 -
report-generators/templates/unit_test.rhtml | 23 -
report-generators/test/example.schedule | 4 -
.../test/strings/more_strings/test3.txt | 1 -
report-generators/test/strings/test1.txt | 1 -
report-generators/test/strings/test2 | 3 -
report-generators/test/tc_log.rb | 36 -
report-generators/test/tc_schedule_file.rb | 38 -
report-generators/test/tc_string_store.rb | 29 -
report-generators/test/ts.rb | 13 -
report-generators/title_page.rb | 42 -
report-generators/unit_test.rb | 56 --
reports/stylesheet.css | 77 --
test/unit/Makefile.in | 39 -
test/unit/bcache_t.c | 636 ------------
test/unit/bitset_t.c | 129 ---
test/unit/config_t.c | 152 ---
test/unit/dmlist_t.c | 49 -
test/unit/dmstatus_t.c | 72 --
test/unit/matcher_data.h | 1013 --------------------
test/unit/matcher_t.c | 70 --
test/unit/percent_t.c | 101 --
test/unit/run.c | 39 -
test/unit/string_t.c | 78 --
test/unit/units.h | 35 -
unit-test/Makefile.in | 40 +
unit-test/bcache_t.c | 783 +++++++++++++++
unit-test/bitset_t.c | 148 +++
unit-test/config_t.c | 167 ++++
unit-test/dmlist_t.c | 49 +
unit-test/dmstatus_t.c | 84 ++
unit-test/framework.c | 66 ++
unit-test/framework.h | 49 +
unit-test/matcher_data.h | 1013 ++++++++++++++++++++
unit-test/matcher_t.c | 89 ++
unit-test/percent_t.c | 102 ++
unit-test/run.c | 309 ++++++
unit-test/string_t.c | 91 ++
unit-test/units.h | 46 +
53 files changed, 3301 insertions(+), 3348 deletions(-)
diff --git a/.gitignore b/.gitignore
index 7e031bf..201cbe5 100644
--- a/.gitignore
+++ b/.gitignore
@@ -79,3 +79,5 @@ test/lib/vgrename
test/lib/vgs
test/lib/vgscan
test/lib/vgsplit
+
+unit-test/unit-test
diff --git a/Makefile.in b/Makefile.in
index 146ed55..2420267 100644
--- a/Makefile.in
+++ b/Makefile.in
@@ -43,8 +43,7 @@ endif
ifeq ($(MAKECMDGOALS),distclean)
SUBDIRS = conf include man test scripts \
libdaemon lib tools daemons libdm \
- udev po liblvm python \
- unit-tests/datastruct unit-tests/mm unit-tests/regex
+ udev po liblvm python
tools.distclean: test.distclean
endif
DISTCLEAN_DIRS += lcov_reports*
@@ -97,7 +96,7 @@ endif
DISTCLEAN_TARGETS += cscope.out
CLEAN_DIRS += autom4te.cache
-check check_system check_cluster check_local check_lvmetad check_lvmpolld check_lvmlockd_test check_lvmlockd_dlm check_lvmlockd_sanlock unit: all
+check check_system check_cluster check_local check_lvmetad check_lvmpolld check_lvmlockd_test check_lvmlockd_dlm check_lvmlockd_sanlock unit-test: all
$(MAKE) -C test $(@)
conf.generate man.generate: tools
@@ -212,7 +211,7 @@ endif
endif
ifeq ("$(TESTING)", "yes")
-include test/unit/Makefile
+include unit-test/Makefile
endif
ifneq ($(shell which ctags),)
diff --git a/configure b/configure
index 5011089..63ca480 100755
--- a/configure
+++ b/configure
@@ -707,9 +707,7 @@ FSADM
ELDFLAGS
DM_LIB_PATCHLEVEL
DMEVENTD_PATH
-AIO_LIBS
DL_LIBS
-AIO
DEVMAPPER
DEFAULT_USE_LVMLOCKD
DEFAULT_USE_LVMPOLLD
@@ -783,8 +781,6 @@ LOCKD_SANLOCK_LIBS
LOCKD_SANLOCK_CFLAGS
VALGRIND_LIBS
VALGRIND_CFLAGS
-CUNIT_LIBS
-CUNIT_CFLAGS
GENPNG
GENHTML
LCOV
@@ -957,7 +953,6 @@ enable_profiling
enable_testing
enable_valgrind_pool
enable_devmapper
-enable_aio
enable_lvmetad
enable_lvmpolld
enable_lvmlockd_sanlock
@@ -1047,8 +1042,6 @@ DLM_CFLAGS
DLM_LIBS
SACKPT_CFLAGS
SACKPT_LIBS
-CUNIT_CFLAGS
-CUNIT_LIBS
VALGRIND_CFLAGS
VALGRIND_LIBS
LOCKD_SANLOCK_CFLAGS
@@ -1707,7 +1700,6 @@ Optional Features:
--enable-testing enable testing targets in the makefile
--enable-valgrind-pool enable valgrind awareness of pools
--disable-devmapper disable LVM2 device-mapper interaction
- --disable-aio disable asynchronous I/O
--enable-lvmetad enable the LVM Metadata Daemon
--enable-lvmpolld enable the LVM Polling Daemon
--enable-lvmlockd-sanlock
@@ -1894,9 +1886,6 @@ Some influential environment variables:
SACKPT_CFLAGS
C compiler flags for SACKPT, overriding pkg-config
SACKPT_LIBS linker flags for SACKPT, overriding pkg-config
- CUNIT_CFLAGS
- C compiler flags for CUNIT, overriding pkg-config
- CUNIT_LIBS linker flags for CUNIT, overriding pkg-config
VALGRIND_CFLAGS
C compiler flags for VALGRIND, overriding pkg-config
VALGRIND_LIBS
@@ -3195,7 +3184,6 @@ case "$host_os" in
LDDEPS="$LDDEPS .export.sym"
LIB_SUFFIX=so
DEVMAPPER=yes
- AIO=yes
BUILD_LVMETAD=no
BUILD_LVMPOLLD=no
LOCKDSANLOCK=no
@@ -3215,7 +3203,6 @@ case "$host_os" in
CLDNOWHOLEARCHIVE=
LIB_SUFFIX=dylib
DEVMAPPER=yes
- AIO=no
ODIRECT=no
DM_IOCTLS=no
SELINUX=no
@@ -11623,101 +11610,6 @@ fi
{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $TESTING" >&5
$as_echo "$TESTING" >&6; }
-if test "$TESTING" = yes; then
- pkg_config_init
-
-pkg_failed=no
-{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for CUNIT" >&5
-$as_echo_n "checking for CUNIT... " >&6; }
-
-if test -n "$CUNIT_CFLAGS"; then
- pkg_cv_CUNIT_CFLAGS="$CUNIT_CFLAGS"
- elif test -n "$PKG_CONFIG"; then
- if test -n "$PKG_CONFIG" && \
- { { $as_echo "$as_me:${as_lineno-$LINENO}: \$PKG_CONFIG --exists --print-errors \"cunit >= 2.0\""; } >&5
- ($PKG_CONFIG --exists --print-errors "cunit >= 2.0") 2>&5
- ac_status=$?
- $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
- test $ac_status = 0; }; then
- pkg_cv_CUNIT_CFLAGS=`$PKG_CONFIG --cflags "cunit >= 2.0" 2>/dev/null`
- test "x$?" != "x0" && pkg_failed=yes
-else
- pkg_failed=yes
-fi
- else
- pkg_failed=untried
-fi
-if test -n "$CUNIT_LIBS"; then
- pkg_cv_CUNIT_LIBS="$CUNIT_LIBS"
- elif test -n "$PKG_CONFIG"; then
- if test -n "$PKG_CONFIG" && \
- { { $as_echo "$as_me:${as_lineno-$LINENO}: \$PKG_CONFIG --exists --print-errors \"cunit >= 2.0\""; } >&5
- ($PKG_CONFIG --exists --print-errors "cunit >= 2.0") 2>&5
- ac_status=$?
- $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
- test $ac_status = 0; }; then
- pkg_cv_CUNIT_LIBS=`$PKG_CONFIG --libs "cunit >= 2.0" 2>/dev/null`
- test "x$?" != "x0" && pkg_failed=yes
-else
- pkg_failed=yes
-fi
- else
- pkg_failed=untried
-fi
-
-
-
-if test $pkg_failed = yes; then
- { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
-$as_echo "no" >&6; }
-
-if $PKG_CONFIG --atleast-pkgconfig-version 0.20; then
- _pkg_short_errors_supported=yes
-else
- _pkg_short_errors_supported=no
-fi
- if test $_pkg_short_errors_supported = yes; then
- CUNIT_PKG_ERRORS=`$PKG_CONFIG --short-errors --print-errors --cflags --libs "cunit >= 2.0" 2>&1`
- else
- CUNIT_PKG_ERRORS=`$PKG_CONFIG --print-errors --cflags --libs "cunit >= 2.0" 2>&1`
- fi
- # Put the nasty error message in config.log where it belongs
- echo "$CUNIT_PKG_ERRORS" >&5
-
- as_fn_error $? "Package requirements (cunit >= 2.0) were not met:
-
-$CUNIT_PKG_ERRORS
-
-Consider adjusting the PKG_CONFIG_PATH environment variable if you
-installed software in a non-standard prefix.
-
-Alternatively, you may set the environment variables CUNIT_CFLAGS
-and CUNIT_LIBS to avoid the need to call pkg-config.
-See the pkg-config man page for more details." "$LINENO" 5
-elif test $pkg_failed = untried; then
- { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
-$as_echo "no" >&6; }
- { { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5
-$as_echo "$as_me: error: in \`$ac_pwd':" >&2;}
-as_fn_error $? "The pkg-config script could not be found or is too old. Make sure it
-is in your PATH or set the PKG_CONFIG environment variable to the full
-path to pkg-config.
-
-Alternatively, you may set the environment variables CUNIT_CFLAGS
-and CUNIT_LIBS to avoid the need to call pkg-config.
-See the pkg-config man page for more details.
-
-To get pkg-config, see <http://pkg-config.freedesktop.org/>.
-See \`config.log' for more details" "$LINENO" 5; }
-else
- CUNIT_CFLAGS=$pkg_cv_CUNIT_CFLAGS
- CUNIT_LIBS=$pkg_cv_CUNIT_LIBS
- { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5
-$as_echo "yes" >&6; }
-
-fi
-fi
-
################################################################################
TESTSUITE_DATA='${datarootdir}/lvm2-testsuite'
# double eval needed ${datarootdir} -> ${prefix}/share -> real path
@@ -11845,67 +11737,6 @@ $as_echo "#define DEVMAPPER_SUPPORT 1" >>confdefs.h
fi
################################################################################
-{ $as_echo "$as_me:${as_lineno-$LINENO}: checking whether to use asynchronous I/O" >&5
-$as_echo_n "checking whether to asynchronous I/O... " >&6; }
-# Check whether --enable-aio was given.
-if test "${enable_aio+set}" = set; then :
- enableval=$enable_aio; AIO=$enableval
-fi
-
-{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $AIO" >&5
-$as_echo "$AIO" >&6; }
-
-if test "$AIO" = yes; then
- { $as_echo "$as_me:${as_lineno-$LINENO}: checking for io_setup in -laio" >&5
-$as_echo_n "checking for io_setup in -laio... " >&6; }
-if ${ac_cv_lib_aio_io_setup+:} false; then :
- $as_echo_n "(cached) " >&6
-else
- ac_check_lib_save_LIBS=$LIBS
-LIBS="-laio $LIBS"
-cat confdefs.h - <<_ACEOF >conftest.$ac_ext
-/* end confdefs.h. */
-
-/* Override any GCC internal prototype to avoid an error.
- Use char because int might match the return type of a GCC
- builtin and then its argument prototype would still apply. */
-#ifdef __cplusplus
-extern "C"
-#endif
-char io_setup ();
-int
-main ()
-{
-return io_setup ();
- ;
- return 0;
-}
-_ACEOF
-if ac_fn_c_try_link "$LINENO"; then :
- ac_cv_lib_aio_io_setup=yes
-else
- ac_cv_lib_aio_io_setup=no
-fi
-rm -f core conftest.err conftest.$ac_objext \
- conftest$ac_exeext conftest.$ac_ext
-LIBS=$ac_check_lib_save_LIBS
-fi
-{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_aio_io_setup" >&5
-$as_echo "$ac_cv_lib_aio_io_setup" >&6; }
-if test "x$ac_cv_lib_aio_io_setup" = xyes; then :
-
-$as_echo "#define AIO_SUPPORT 1" >>confdefs.h
-
- AIO_LIBS="-laio"
- AIO_SUPPORT=yes
-else
- AIO_LIBS=
- AIO_SUPPORT=no
-fi
-
-fi
-
-################################################################################
{ $as_echo "$as_me:${as_lineno-$LINENO}: checking whether to build LVMetaD" >&5
$as_echo_n "checking whether to build LVMetaD... " >&6; }
# Check whether --enable-lvmetad was given.
@@ -15857,10 +15688,8 @@ _ACEOF
-
-
################################################################################
-ac_config_files="$ac_config_files Makefile make.tmpl daemons/Makefile daemons/clvmd/Makefile daemons/cmirrord/Makefile daemons/dmeventd/Makefile daemons/dmeventd/libdevmapper-event.pc daemons/dmeventd/plugins/Makefile daemons/dmeventd/plugins/lvm2/Makefile daemons/dmeventd/plugins/raid/Makefile daemons/dmeventd/plugins/mirror/Makefile daemons/dmeventd/plugins/snapshot/Makefile daemons/dmeventd/plugins/thin/Makefile daemons/dmfilemapd/Makefile daemons/lvmdbusd/Makefile daemons/lvmdbusd/lvmdbusd daemons/lvmdbusd/lvmdb.py daemons/lvmdbusd/lvm_shell_proxy.py daemons/lvmdbusd/path.py daemons/lvmetad/Makefile daemons/lvmpolld/Makefile daemons/lvmlockd/Makefile conf/Makefile conf/example.conf conf/lvmlocal.conf conf/command_profile_template.profile conf/metadata_profile_template.profile include/.symlinks include/Makefile lib/Makefile lib/format1/Makefile lib/format_pool/Makefile lib/locking/Makefile lib/mirror/Makefile include/lvm-version.h lib/raid/Makefile lib/snapshot/Makefile lib/thin/
Makefile lib/cache_segtype/Makefile libdaemon/Makefile libdaemon/client/Makefile libdaemon/server/Makefile libdm/Makefile libdm/libdevmapper.pc liblvm/Makefile liblvm/liblvm2app.pc man/Makefile po/Makefile python/Makefile python/setup.py scripts/blkdeactivate.sh scripts/blk_availability_init_red_hat scripts/blk_availability_systemd_red_hat.service scripts/clvmd_init_red_hat scripts/cmirrord_init_red_hat scripts/com.redhat.lvmdbus1.service scripts/dm_event_systemd_red_hat.service scripts/dm_event_systemd_red_hat.socket scripts/lvm2_cluster_activation_red_hat.sh scripts/lvm2_cluster_activation_systemd_red_hat.service scripts/lvm2_clvmd_systemd_red_hat.service scripts/lvm2_cmirrord_systemd_red_hat.service scripts/lvm2_lvmdbusd_systemd_red_hat.service scripts/lvm2_lvmetad_init_red_hat scripts/lvm2_lvmetad_systemd_red_hat.service scripts/lvm2_lvmetad_systemd_red_hat.socket scripts/lvm2_lvmpolld_init_red_hat scripts/lvm2_lvmpolld_systemd_red_hat.service scripts/lvm2_lvmpolld_systemd_red_h
at.socket scripts/lvm2_lvmlockd_systemd_red_hat.service scripts/lvm2_lvmlocking_systemd_red_hat.service scripts/lvm2_monitoring_init_red_hat scripts/lvm2_monitoring_systemd_red_hat.service scripts/lvm2_pvscan_systemd_red_hat@.service scripts/lvm2_tmpfiles_red_hat.conf scripts/lvmdump.sh scripts/Makefile test/Makefile test/api/Makefile test/unit/Makefile tools/Makefile udev/Makefile"
+ac_config_files="$ac_config_files Makefile make.tmpl daemons/Makefile daemons/clvmd/Makefile daemons/cmirrord/Makefile daemons/dmeventd/Makefile daemons/dmeventd/libdevmapper-event.pc daemons/dmeventd/plugins/Makefile daemons/dmeventd/plugins/lvm2/Makefile daemons/dmeventd/plugins/raid/Makefile daemons/dmeventd/plugins/mirror/Makefile daemons/dmeventd/plugins/snapshot/Makefile daemons/dmeventd/plugins/thin/Makefile daemons/dmfilemapd/Makefile daemons/lvmdbusd/Makefile daemons/lvmdbusd/lvmdbusd daemons/lvmdbusd/lvmdb.py daemons/lvmdbusd/lvm_shell_proxy.py daemons/lvmdbusd/path.py daemons/lvmetad/Makefile daemons/lvmpolld/Makefile daemons/lvmlockd/Makefile conf/Makefile conf/example.conf conf/lvmlocal.conf conf/command_profile_template.profile conf/metadata_profile_template.profile include/.symlinks include/Makefile lib/Makefile lib/format1/Makefile lib/format_pool/Makefile lib/locking/Makefile lib/mirror/Makefile include/lvm-version.h lib/raid/Makefile lib/snapshot/Makefile lib/thin/
Makefile lib/cache_segtype/Makefile libdaemon/Makefile libdaemon/client/Makefile libdaemon/server/Makefile libdm/Makefile libdm/libdevmapper.pc liblvm/Makefile liblvm/liblvm2app.pc man/Makefile po/Makefile python/Makefile python/setup.py scripts/blkdeactivate.sh scripts/blk_availability_init_red_hat scripts/blk_availability_systemd_red_hat.service scripts/clvmd_init_red_hat scripts/cmirrord_init_red_hat scripts/com.redhat.lvmdbus1.service scripts/dm_event_systemd_red_hat.service scripts/dm_event_systemd_red_hat.socket scripts/lvm2_cluster_activation_red_hat.sh scripts/lvm2_cluster_activation_systemd_red_hat.service scripts/lvm2_clvmd_systemd_red_hat.service scripts/lvm2_cmirrord_systemd_red_hat.service scripts/lvm2_lvmdbusd_systemd_red_hat.service scripts/lvm2_lvmetad_init_red_hat scripts/lvm2_lvmetad_systemd_red_hat.service scripts/lvm2_lvmetad_systemd_red_hat.socket scripts/lvm2_lvmpolld_init_red_hat scripts/lvm2_lvmpolld_systemd_red_hat.service scripts/lvm2_lvmpolld_systemd_red_h
at.socket scripts/lvm2_lvmlockd_systemd_red_hat.service scripts/lvm2_lvmlocking_systemd_red_hat.service scripts/lvm2_monitoring_init_red_hat scripts/lvm2_monitoring_systemd_red_hat.service scripts/lvm2_pvscan_systemd_red_hat@.service scripts/lvm2_tmpfiles_red_hat.conf scripts/lvmdump.sh scripts/Makefile test/Makefile test/api/Makefile unit-test/Makefile tools/Makefile udev/Makefile"
cat >confcache <<\_ACEOF
# This file is a shell script that caches the results of configure
@@ -16634,7 +16463,7 @@ do
"scripts/Makefile") CONFIG_FILES="$CONFIG_FILES scripts/Makefile" ;;
"test/Makefile") CONFIG_FILES="$CONFIG_FILES test/Makefile" ;;
"test/api/Makefile") CONFIG_FILES="$CONFIG_FILES test/api/Makefile" ;;
- "test/unit/Makefile") CONFIG_FILES="$CONFIG_FILES test/unit/Makefile" ;;
+ "unit-test/Makefile") CONFIG_FILES="$CONFIG_FILES unit-test/Makefile" ;;
"tools/Makefile") CONFIG_FILES="$CONFIG_FILES tools/Makefile" ;;
"udev/Makefile") CONFIG_FILES="$CONFIG_FILES udev/Makefile" ;;
diff --git a/configure.in b/configure.in
index 0d268e8..461c21b 100644
--- a/configure.in
+++ b/configure.in
@@ -1076,11 +1076,6 @@ AC_ARG_ENABLE(testing,
TESTING=$enableval, TESTING=no)
AC_MSG_RESULT($TESTING)
-if test "$TESTING" = yes; then
- pkg_config_init
- PKG_CHECK_MODULES(CUNIT, cunit >= 2.0)
-fi
-
################################################################################
dnl -- Set LVM2 testsuite data
TESTSUITE_DATA='${datarootdir}/lvm2-testsuite'
@@ -2251,7 +2246,7 @@ scripts/lvmdump.sh
scripts/Makefile
test/Makefile
test/api/Makefile
-test/unit/Makefile
+unit-test/Makefile
tools/Makefile
udev/Makefile
])
diff --git a/doc/unit-tests.txt b/doc/unit-tests.txt
new file mode 100644
index 0000000..55bbceb
--- /dev/null
+++ b/doc/unit-tests.txt
@@ -0,0 +1,257 @@
+Building unit tests
+===================
+
+ make unit-unit/unit-test
+
+
+Running unit tests
+==================
+
+The tests leave no artifacts at the moment, so you can just run
+unit-test/unit-test from wherever you want.
+
+ ./unit-test <list|run> [pattern]
+
+Listing tests
+-------------
+
+Every test has a symbolic path associated with it. Just like file paths they
+are split into components separated by '/'s. The 'list' command will show you
+a tree of these tests, along with some description text.
+
+
+ejt@devel-vm1:~/lvm2/unit-test/$ ./unit-test list
+base
+ data-struct
+ bitset
+ and ................................................. and all bits
+ equal ............................................... equality
+ get_next ............................................ get next set bit
+ list
+ splice .............................................. joining lists together
+ string
+ asprint ............................................. tests asprint
+ strncpy ............................................. tests string copying
+ device
+ bcache
+ block-size-multiple-page ............................ block size must be a multiple of page size
+ block-size-positive ................................. block size must be positive
+ blocks-get-evicted .................................. block get evicted with many reads
+ cache-blocks-positive ............................... nr cache blocks must be positive
+ create-destroy ...................................... simple create/destroy
+ flush-waits ......................................... flush waits for all dirty
+ get-reads ........................................... bcache_get() triggers read
+ prefetch-never-waits ................................ too many prefetches does not trigger a wait
+ prefetch-reads ...................................... prefetch issues a read
+ read-multiple-files ................................. read from multiple files
+ reads-cached ........................................ repeated reads are cached
+ writeback-occurs .................................... dirty data gets written back
+ zero-flag-dirties ................................... zeroed data counts as dirty
+ formatting
+ percent
+ 0 ................................................... Pretty printing of percentages near 0%
+ 100 ................................................. Pretty printing of percentages near 100%
+ regex
+ fingerprints .......................................... not sure
+ matching .............................................. test the matcher with a variety of regexes
+dm
+ target
+ mirror
+ status .............................................. parsing mirror status
+metadata
+ config
+ cascade ............................................... cascade
+ clone ................................................. duplicating a config tree
+ parse ................................................. parsing various
+
+
+An optional 'pattern' argument may be specified to select subsets of tests.
+This pattern is a posix regex and does a substring match, so you will need to
+use anchors if you particularly want the match at the beginning or end of the
+string.
+
+ejt@devel-vm1:~/lvm2/unit-test/$ ./unit-test list data-struct
+base
+ data-struct
+ bitset
+ and ................................................. and all bits
+ equal ............................................... equality
+ get_next ............................................ get next set bit
+ list
+ splice .............................................. joining lists together
+ string
+ asprint ............................................. tests asprint
+ strncpy ............................................. tests string copying
+
+ejt@devel-vm1:~/lvm2/unit-test/$ ./unit-test list s$
+base
+ device
+ bcache
+ flush-waits ......................................... flush waits for all dirty
+ get-reads ........................................... bcache_get() triggers read
+ prefetch-never-waits ................................ too many prefetches does not trigger a wait
+ prefetch-reads ...................................... prefetch issues a read
+ read-multiple-files ................................. read from multiple files
+ writeback-occurs .................................... dirty data gets written back
+ zero-flag-dirties ................................... zeroed data counts as dirty
+ regex
+ fingerprints .......................................... not sure
+dm
+ target
+ mirror
+ status .............................................. parsing mirror status
+
+
+Running tests
+=============
+
+'make run-unit-test' from the top level will run all unit tests. But I tend to
+run it by hand to I can select just the tests I'm working on.
+
+Use the 'run' command to run the tests. Currently all logging goes to stderr,
+so the test runner prints a line at the start of the test and a line
+indicating success or failure at the end.
+
+ejt@devel-vm1:~/lvm2/unit-test/$ ./unit-test run bcache/block-size
+[RUN ] /base/device/bcache/block-size-multiple-page
+bcache block size must be a multiple of page size
+bcache block size must be a multiple of page size
+bcache block size must be a multiple of page size
+bcache block size must be a multiple of page size
+[ OK] /base/device/bcache/block-size-multiple-page
+
+[RUN ] /base/device/bcache/block-size-positive
+bcache must have a non zero block size
+[ OK] /base/device/bcache/block-size-positive
+
+
+2/2 tests passed
+
+
+ejt@devel-vm1:~/lvm2/unit-test/$ ./unit-test run data-struct
+[RUN ] /base/data-struct/bitset/and
+[ OK] /base/data-struct/bitset/and
+
+[RUN ] /base/data-struct/bitset/equal
+[ OK] /base/data-struct/bitset/equal
+
+[RUN ] /base/data-struct/bitset/get_next
+[ OK] /base/data-struct/bitset/get_next
+
+[RUN ] /base/data-struct/list/splice
+[ OK] /base/data-struct/list/splice
+
+[RUN ] /base/data-struct/string/asprint
+[ OK] /base/data-struct/string/asprint
+
+[RUN ] /base/data-struct/string/strncpy
+[ OK] /base/data-struct/string/strncpy
+
+
+6/6 tests passed
+
+
+Writing tests
+=============
+
+[See unit-test/framework.h and unit-test/units.h for the details]
+
+Tests are grouped together into 'suites', all tests in a suite share a
+'fixture'. A fixture is a void * to any object you want; use it to set up any
+common environment that you need for the tests to run (eg, creating a dm_pool).
+
+Test suites have nothing to do with the test paths, you can have tests from
+different suites with similar paths, the runner sorts things for you.
+
+Put your tests in a file in unit-test/, with '_t' at the end of the name
+(convention only, nothing relies on this).
+
+#include "units.h"
+
+Then write any fixtures you need:
+
+eg,
+static void *_mem_init(void) {
+ struct dm_pool *mem = dm_pool_create("bitset test", 1024);
+ if (!mem) {
+ fprintf(stderr, "out of memory\n");
+ exit(1);
+ }
+
+ return mem;
+}
+
+static void _mem_exit(void *mem)
+{
+ dm_pool_destroy(mem);
+}
+
+Then write your tests, which should take the void * that was returned by your
+fixture. Use the T_ASSERT* macros to indicate failure.
+
+eg,
+static void test_equal(void *fixture)
+{
+ struct dm_pool *mem = fixture;
+ dm_bitset_t bs1 = dm_bitset_create(mem, NR_BITS);
+ dm_bitset_t bs2 = dm_bitset_create(mem, NR_BITS);
+
+ int i, j;
+ for (i = 0, j = 1; i < NR_BITS; i += j, j++) {
+ dm_bit_set(bs1, i);
+ dm_bit_set(bs2, i);
+ }
+
+ T_ASSERT(dm_bitset_equal(bs1, bs2));
+ T_ASSERT(dm_bitset_equal(bs2, bs1));
+
+ for (i = 0; i < NR_BITS; i++) {
+ bit_flip(bs1, i);
+ T_ASSERT(!dm_bitset_equal(bs1, bs2));
+ T_ASSERT(!dm_bitset_equal(bs2, bs1));
+
+ T_ASSERT(dm_bitset_equal(bs1, bs1)); /* comparing with self */
+ bit_flip(bs1, i);
+ }
+}
+
+At the end of your test file you should write a function that builds one or
+more test suites and adds them to the list of all suites that is passed in. I
+tend to write a little macro (T) to save typing the same test path repeatedly.
+
+eg,
+#define T(path, desc, fn) register_test(ts, "/base/data-struct/bitset/" path, desc, fn)
+
+void bitset_tests(struct dm_list *all_tests)
+{
+ struct test_suite *ts = test_suite_create(_mem_init, _mem_exit);
+ if (!ts) {
+ fprintf(stderr, "out of memory\n");
+ exit(1);
+ }
+
+ T("get_next", "get next set bit", test_get_next);
+ T("equal", "equality", test_equal);
+ T("and", "and all bits", test_and);
+
+ dm_list_add(all_tests, &ts->list);
+}
+
+Then you need to declare your registration function and call it in units.h.
+
+
+// Declare the function that adds tests suites here ...
+ ...
+void bitset_tests(struct dm_list *suites);
+ ...
+
+// ... and call it in here.
+static inline void register_all_tests(struct dm_list *suites)
+{
+ ...
+ bitset_tests(suites);
+ ...
+}
+
+Finally add your test file to the Makefile.in and rerun configure.
+
diff --git a/report-generators/lib/log.rb b/report-generators/lib/log.rb
deleted file mode 100644
index cf74fc4..0000000
--- a/report-generators/lib/log.rb
+++ /dev/null
@@ -1,40 +0,0 @@
-# Copyright (C) 2010 Red Hat, Inc. All rights reserved.
-#
-# This copyrighted material is made available to anyone wishing to use,
-# modify, copy, or redistribute it subject to the terms and conditions
-# of the GNU General Public License v.2.
-#
-# You should have received a copy of the GNU General Public License
-# along with this program; if not, write to the Free Software Foundation,
-# Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
-
-# Merely wraps the logger library with a bit of standard policy.
-require 'logger'
-
-module Log
- $log = Logger.new(STDERR)
-
- def init(io_)
- $log = Logger.new(io_)
- end
-end
-
-def fatal(*args)
- $log.fatal(*args)
-end
-
-def error(*args)
- $log.error(*args)
-end
-
-def info(*args)
- $log.info(*args)
-end
-
-def warning(*args)
- $log.warn(*args)
-end
-
-def debug(*args)
- $log.debug(*args)
-end
diff --git a/report-generators/lib/report_templates.rb b/report-generators/lib/report_templates.rb
deleted file mode 100644
index 3da29ab..0000000
--- a/report-generators/lib/report_templates.rb
+++ /dev/null
@@ -1,38 +0,0 @@
-# Copyright (C) 2010 Red Hat, Inc. All rights reserved.
-#
-# This copyrighted material is made available to anyone wishing to use,
-# modify, copy, or redistribute it subject to the terms and conditions
-# of the GNU General Public License v.2.
-#
-# You should have received a copy of the GNU General Public License
-# along with this program; if not, write to the Free Software Foundation,
-# Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
-
-# Policy for the location of report templates
-require 'string-store'
-
-class TemplateStringStore < StringStore
- def initialize()
- super(['report-generators/templates'])
- end
-end
-
-module ReportTemplates
- def generate_report(report, bs, dest_path = nil)
- include Reports
- reports = ReportRegister.new
- template_store = TemplateStringStore.new
- report = reports.get_report(report)
- erb = ERB.new(template_store.lookup(report.template))
- body = erb.result(bs)
- title = report.short_desc
-
- erb = ERB.new(template_store.lookup("boiler_plate.rhtml"))
- txt = erb.result(binding)
-
- dest_path = dest_path.nil? ? report.path : dest_path
- dest_path.open("w") do |out|
- out.puts txt
- end
- end
-end
diff --git a/report-generators/lib/reports.rb b/report-generators/lib/reports.rb
deleted file mode 100644
index 2930f83..0000000
--- a/report-generators/lib/reports.rb
+++ /dev/null
@@ -1,58 +0,0 @@
-# Copyright (C) 2010 Red Hat, Inc. All rights reserved.
-#
-# This copyrighted material is made available to anyone wishing to use,
-# modify, copy, or redistribute it subject to the terms and conditions
-# of the GNU General Public License v.2.
-#
-# You should have received a copy of the GNU General Public License
-# along with this program; if not, write to the Free Software Foundation,
-# Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
-
-# Data about the various reports we support
-require 'log'
-require 'pathname'
-
-module Reports
- Report = Struct.new(:short_desc, :desc, :path, :template)
-
- class ReportRegister
- attr_reader :reports
-
- private
- def add_report(sym, *args)
- @reports[sym] = Report.new(*args)
- end
-
- public
- def initialize()
- @reports = Hash.new
-
- add_report(:unit_test,
- "Unit Tests",
- "unit tests",
- Pathname.new("reports/unit.html"),
- Pathname.new("unit_test.rhtml"))
-
- add_report(:memcheck,
- "Memory Tests",
- "unit tests with valgrind memory checking",
- Pathname.new("reports/memcheck.html"),
- Pathname.new("memcheck.rhtml"))
-
- add_report(:unit_detail,
- "Unit Test Detail",
- "unit test detail",
- Pathname.new("reports/unit_detail.html"), # FIXME replace this with a lambda
- Pathname.new("unit_detail.rhtml"))
- end
-
- def get_report(sym)
- raise RuntimeError, "unknown report '#{sym}'" unless @reports.member?(sym)
- @reports[sym]
- end
-
- def each(&block)
- @reports.each(&block)
- end
- end
-end
diff --git a/report-generators/lib/schedule_file.rb b/report-generators/lib/schedule_file.rb
deleted file mode 100644
index d695f57..0000000
--- a/report-generators/lib/schedule_file.rb
+++ /dev/null
@@ -1,56 +0,0 @@
-# Copyright (C) 2010 Red Hat, Inc. All rights reserved.
-#
-# This copyrighted material is made available to anyone wishing to use,
-# modify, copy, or redistribute it subject to the terms and conditions
-# of the GNU General Public License v.2.
-#
-# You should have received a copy of the GNU General Public License
-# along with this program; if not, write to the Free Software Foundation,
-# Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
-
-# Parses the simple colon delimited test schedule files.
-
-ScheduledTest = Struct.new(:desc, :command_line, :status, :output)
-
-class Schedule
- attr_reader :dir, :schedules
-
- def initialize(dir, ss)
- @dir = dir
- @schedules = ss
- end
-
- def run
- Dir::chdir(@dir.to_s) do
- @schedules.each do |s|
- reader, writer = IO.pipe
- print "#{s.desc} ... "
- pid = spawn(s.command_line, [ STDERR, STDOUT ] => writer)
- writer.close
- _, s.status = Process::waitpid2(pid)
- puts (s.status.success? ? "pass" : "fail")
- s.output = reader.read
- end
- end
- end
-
- def self.read(dir, io)
- ss = Array.new
-
- io.readlines.each do |line|
- case line.strip
- when /^\#.*/
- next
-
- when /([^:]+):(.*)/
- ss << ScheduledTest.new($1.strip, $2.strip)
-
- else
- raise RuntimeError, "badly formatted schedule line"
- end
- end
-
- Schedule.new(dir, ss)
- end
-end
-
diff --git a/report-generators/lib/string-store.rb b/report-generators/lib/string-store.rb
deleted file mode 100644
index 66d2231..0000000
--- a/report-generators/lib/string-store.rb
+++ /dev/null
@@ -1,42 +0,0 @@
-# Copyright (C) 2010 Red Hat, Inc. All rights reserved.
-#
-# This copyrighted material is made available to anyone wishing to use,
-# modify, copy, or redistribute it subject to the terms and conditions
-# of the GNU General Public License v.2.
-#
-# You should have received a copy of the GNU General Public License
-# along with this program; if not, write to the Free Software Foundation,
-# Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
-
-# Provides a simple way of accessing the contents of files by a symbol
-# name. Useful for erb templates.
-
-require 'pathname'
-
-class StringStore
- attr_accessor :path
-
- def initialize(p)
- @paths = p.nil? ? Array.new : p # FIXME: do we need to copy p ?
- end
-
- def lookup(sym)
- files = expansions(sym)
-
- @paths.each do |p|
- files.each do |f|
- pn = Pathname.new("#{p}/#{f}")
- if pn.file?
- return pn.read
- end
- end
- end
-
- raise RuntimeError, "unknown string entry: #{sym}"
- end
-
- private
- def expansions(sym)
- ["#{sym}", "#{sym}.txt"]
- end
-end
diff --git a/report-generators/memcheck.rb b/report-generators/memcheck.rb
deleted file mode 100644
index 1dccd21..0000000
--- a/report-generators/memcheck.rb
+++ /dev/null
@@ -1,86 +0,0 @@
-# Copyright (C) 2010 Red Hat, Inc. All rights reserved.
-#
-# This copyrighted material is made available to anyone wishing to use,
-# modify, copy, or redistribute it subject to the terms and conditions
-# of the GNU General Public License v.2.
-#
-# You should have received a copy of the GNU General Public License
-# along with this program; if not, write to the Free Software Foundation,
-# Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
-
-# Reads the schedule files given on the command line. Runs them and
-# generates the reports.
-
-# FIXME: a lot of duplication with unit_test.rb
-
-require 'schedule_file'
-require 'pathname'
-require 'reports'
-require 'erb'
-require 'report_templates'
-
-include ReportTemplates
-
-schedules = ARGV.map do |f|
- p = Pathname.new(f)
- Schedule.read(p.dirname, p)
-end
-
-total_passed = 0
-total_failed = 0
-
-# We need to make sure the lvm shared libs are in the LD_LIBRARY_PATH
-ENV['LD_LIBRARY_PATH'] = `pwd`.strip + "/libdm:" + (ENV['LD_LIBRARY_PATH'] || '')
-
-ENV['TEST_TOOL'] = "valgrind --leak-check=full --show-reachable=yes"
-
-schedules.each do |s|
- s.run
-
- s.schedules.each do |t|
- if t.status.success?
- total_passed += 1
- else
- total_failed += 1
- end
- end
-end
-
-def mangle(txt)
- txt.gsub(/\s+/, '_')
-end
-
-MemcheckStats = Struct.new(:definitely_lost, :indirectly_lost, :possibly_lost, :reachable)
-
-def format(bytes, blocks)
- "#{bytes} bytes, #{blocks} blocks"
-end
-
-# Examines the output for details of leaks
-def extract_stats(t)
- d = i = p = r = '-'
-
- t.output.split("\n").each do |l|
- case l
- when /==\d+== definitely lost: ([0-9,]+) bytes in ([0-9,]+) blocks/
- d = format($1, $2)
- when /==\d+== indirectly lost: ([0-9,]+) bytes in ([0-9,]+) blocks/
- i = format($1, $2)
- when /==\d+== possibly lost: ([0-9,]+) bytes in ([0-9,]+) blocks/
- p = format($1, $2)
- when /==\d+== still reachable: ([0-9,]+) bytes in ([0-9,]+) blocks/
- r = format($1, $2)
- end
- end
-
- MemcheckStats.new(d, i, p, r)
-end
-
-generate_report(:memcheck, binding)
-
-# now we generate a detail report for each schedule
-schedules.each do |s|
- s.schedules.each do |t|
- generate_report(:unit_detail, binding, Pathname.new("reports/memcheck_#{mangle(t.desc)}.html"))
- end
-end
diff --git a/report-generators/templates/boiler_plate.rhtml b/report-generators/templates/boiler_plate.rhtml
deleted file mode 100644
index 23f01cb..0000000
--- a/report-generators/templates/boiler_plate.rhtml
+++ /dev/null
@@ -1,25 +0,0 @@
-<html>
-<head>
-<META http-equiv="Content-Type" content="text/html; charset=US-ASCII">
-<title><%= title %></title>
-<link title="Style" type="text/css" rel="stylesheet" href="stylesheet.css">
-</head>
-
-<body>
-<div id="banner">
-<h2><%= title %></h2>
-</div>
-<div id="main">
- <div id="controls">
- <table>
- <tr><td><a href="index.html">Generation times</a></td></tr>
- <tr><td><a href="unit.html">Unit tests</a></td></tr>
- <tr><td><a href="memcheck.html">Memory tests</a></td></tr>
- </table>
- </div>
-
- <div id="body">
- <%= body %>
- </div>
-</div>
-</body>
diff --git a/report-generators/templates/index.rhtml b/report-generators/templates/index.rhtml
deleted file mode 100644
index 6d72081..0000000
--- a/report-generators/templates/index.rhtml
+++ /dev/null
@@ -1,17 +0,0 @@
-<table width="95%" cellspacing="2" cellpadding="5" border="0" class="stripes">
-<tr><th>Report</th><th>Generation time</th></tr>
-<% [:unit_test, :memcheck].each do |sym| %>
-<% r = reports.get_report(sym) %>
-<tr>
- <td>
- <% if r.path.file? %>
- <a href="<%= r.path.to_s.gsub(/^reports\//, '') %>"><%= r.short_desc %></a>
- <% else %>
- <%= r.short_desc %>
- <% end %>
- </td>
- <td><%= safe_mtime(r) %></td>
-</tr>
-<% end %>
-</table>
-
diff --git a/report-generators/templates/memcheck.rhtml b/report-generators/templates/memcheck.rhtml
deleted file mode 100644
index 75872ed..0000000
--- a/report-generators/templates/memcheck.rhtml
+++ /dev/null
@@ -1,30 +0,0 @@
-<table width="95%" cellspacing="2" cellpadding="5" border="0" class="stripes">
- <tr><th>Tests passed</th><th>Tests failed</th></tr>
- <tr><td class="pass"><%= total_passed %></td><td <%= total_failed == 0 ? "" : "class=\"fail\""%>><%= total_failed %></td></tr>
-</table>
-
-<% schedules.each do |s| %>
-<h3><%= s.dir.sub('./unit-tests/', '') %></h3>
-<table width="95%" cellspacing="2" cellpadding="5" border="0" class="stripes">
-<tr><th>Test</th><th>Result</th><th>Definitely lost</th><th>indirectly lost</th><th>possibly lost</th><th>still reachable</th><tr>
-
-<% s.schedules.each do |t| %>
-<tr>
- <td>
- <a href="memcheck_<%= mangle(t.desc) %>.html"><%= t.desc %></a>
- </td>
- <% if t.status.success? %>
- <td class="pass">pass</td>
- <% else %>
- <td class="fail">fail</td>
- <% end %>
-
- <% stats = extract_stats(t) %>
- <td><%= stats.definitely_lost %></td>
- <td><%= stats.indirectly_lost %></td>
- <td><%= stats.possibly_lost %></td>
- <td><%= stats.reachable %></td>
-</tr>
-<% end %>
-</table>
-<% end %>
diff --git a/report-generators/templates/unit_detail.rhtml b/report-generators/templates/unit_detail.rhtml
deleted file mode 100644
index 5324f07..0000000
--- a/report-generators/templates/unit_detail.rhtml
+++ /dev/null
@@ -1,37 +0,0 @@
-<table width="95%" cellspacing="2" cellpadding="5" border="0" class="stripes">
-<tr><th>Test</th><th>Result</th></tr>
-<tr>
- <td>
- <%= t.desc %>
- </td>
- <% if t.status.success? %>
- <td class="pass">pass</td>
- <% else %>
- <td class="fail">fail</td>
- <% end %>
-</tr>
-</table>
-
-<table width="95%" cellspacing="2" cellpadding="5" border="0" class="stripes">
-<tr><th>Command line</th></tr>
-<tr>
- <td>
- <pre>
-<%= t.command_line %>
- </pre>
- </td>
-</tr>
-</table>
-
-
-<table width="95%" cellspacing="2" cellpadding="5" border="0" class="stripes">
-<tr><th>Output</th></tr>
-<tr>
- <td>
- <pre>
-<%= t.output %>
- </pre>
- </td>
-</tr>
-</table>
-
diff --git a/report-generators/templates/unit_test.rhtml b/report-generators/templates/unit_test.rhtml
deleted file mode 100644
index 3137abd..0000000
--- a/report-generators/templates/unit_test.rhtml
+++ /dev/null
@@ -1,23 +0,0 @@
-<table width="95%" cellspacing="2" cellpadding="5" border="0" class="stripes">
- <tr><th>Tests passed</th><th>Tests failed</th></tr>
- <tr><td class="pass"><%= total_passed %></td><td <%= total_failed == 0 ? "" : "class=\"fail\""%>><%= total_failed %></td></tr>
-</table>
-
-<% schedules.each do |s| %>
-<h3><%= s.dir.sub('./unit-tests/', '') %></h3>
-<table width="95%" cellspacing="2" cellpadding="5" border="0" class="stripes">
-<tr><th>Test</th><th>Result</th></tr>
-<% s.schedules.each do |t| %>
-<tr>
- <td>
- <a href="detail_<%= mangle(t.desc) %>.html"><%= t.desc %></a>
- </td>
- <% if t.status.success? %>
- <td class="pass">pass</td>
- <% else %>
- <td class="fail">fail</td>
- <% end %>
-</tr>
-<% end %>
-</table>
-<% end %>
diff --git a/report-generators/test/example.schedule b/report-generators/test/example.schedule
deleted file mode 100644
index f617187..0000000
--- a/report-generators/test/example.schedule
+++ /dev/null
@@ -1,4 +0,0 @@
-# This is a comment
-description number 1:$TEST_TOOL ls
-foo bar: $TEST_TOOL du -hs .
- this comment is prefixed with whitespace: $TEST_TOOL date
\ No newline at end of file
diff --git a/report-generators/test/strings/more_strings/test3.txt b/report-generators/test/strings/more_strings/test3.txt
deleted file mode 100644
index 3e9ffe0..0000000
--- a/report-generators/test/strings/more_strings/test3.txt
+++ /dev/null
@@ -1 +0,0 @@
-lorem
diff --git a/report-generators/test/strings/test1.txt b/report-generators/test/strings/test1.txt
deleted file mode 100644
index af5626b..0000000
--- a/report-generators/test/strings/test1.txt
+++ /dev/null
@@ -1 +0,0 @@
-Hello, world!
diff --git a/report-generators/test/strings/test2 b/report-generators/test/strings/test2
deleted file mode 100644
index 54d55bf..0000000
--- a/report-generators/test/strings/test2
+++ /dev/null
@@ -1,3 +0,0 @@
-one
-two
-three
\ No newline at end of file
diff --git a/report-generators/test/tc_log.rb b/report-generators/test/tc_log.rb
deleted file mode 100644
index 8ed3396..0000000
--- a/report-generators/test/tc_log.rb
+++ /dev/null
@@ -1,36 +0,0 @@
-# Copyright (C) 2010 Red Hat, Inc. All rights reserved.
-#
-# This copyrighted material is made available to anyone wishing to use,
-# modify, copy, or redistribute it subject to the terms and conditions
-# of the GNU General Public License v.2.
-#
-# You should have received a copy of the GNU General Public License
-# along with this program; if not, write to the Free Software Foundation,
-# Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
-
-require 'test/unit'
-require 'stringio'
-require 'log'
-
-class TestLog < Test::Unit::TestCase
- include Log
-
- private
- def remove_timestamps(l)
- l.gsub(/\[[^\]]*\]/, '')
- end
-
- public
- def test_log
- StringIO.open do |out|
- init(out)
-
- info("msg1")
- warning("msg2")
- debug("msg3")
-
- assert_equal("I, INFO -- : msg1\nW, WARN -- : msg2\nD, DEBUG -- : msg3\n",
- remove_timestamps(out.string))
- end
- end
-end
diff --git a/report-generators/test/tc_schedule_file.rb b/report-generators/test/tc_schedule_file.rb
deleted file mode 100644
index 00f9ec3..0000000
--- a/report-generators/test/tc_schedule_file.rb
+++ /dev/null
@@ -1,38 +0,0 @@
-# Copyright (C) 2010 Red Hat, Inc. All rights reserved.
-#
-# This copyrighted material is made available to anyone wishing to use,
-# modify, copy, or redistribute it subject to the terms and conditions
-# of the GNU General Public License v.2.
-#
-# You should have received a copy of the GNU General Public License
-# along with this program; if not, write to the Free Software Foundation,
-# Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
-
-require 'test/unit'
-require 'pathname'
-require 'schedule_file'
-
-class TestScheduleFile < Test::Unit::TestCase
- def test_reading
- p = Pathname.new("report-generators/test/example.schedule")
- p.open do |f|
- s = Schedule.read(p.dirname, f)
-
- assert_equal(3, s.schedules.size)
- assert_equal(s.schedules[2].desc, "this comment is prefixed with whitespace")
- assert_equal(s.schedules[0].command_line, "$TEST_TOOL ls")
- end
- end
-
- def test_running
- p = Pathname.new("report-generators/test/example.schedule")
- p.open do |f|
- s = Schedule.read(p.dirname, f)
- s.run
-
- s.schedules.each do |t|
- assert(t.status.success?)
- end
- end
- end
-end
diff --git a/report-generators/test/tc_string_store.rb b/report-generators/test/tc_string_store.rb
deleted file mode 100644
index 127e0a8..0000000
--- a/report-generators/test/tc_string_store.rb
+++ /dev/null
@@ -1,29 +0,0 @@
-# Copyright (C) 2010 Red Hat, Inc. All rights reserved.
-#
-# This copyrighted material is made available to anyone wishing to use,
-# modify, copy, or redistribute it subject to the terms and conditions
-# of the GNU General Public License v.2.
-#
-# You should have received a copy of the GNU General Public License
-# along with this program; if not, write to the Free Software Foundation,
-# Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
-
-require 'string-store'
-require 'test/unit'
-
-class TestStringStore < Test::Unit::TestCase
- def setup
- @ss = StringStore.new(['report-generators/test/strings',
- 'report-generators/test/strings/more_strings'])
- end
-
- def test_lookup
- assert_equal("Hello, world!\n", @ss.lookup(:test1))
- assert_equal("one\ntwo\nthree", @ss.lookup(:test2))
- assert_equal("lorem\n", @ss.lookup(:test3))
-
- assert_raises(RuntimeError) do
- @ss.lookup(:unlikely_name)
- end
- end
-end
diff --git a/report-generators/test/ts.rb b/report-generators/test/ts.rb
deleted file mode 100644
index 0501780..0000000
--- a/report-generators/test/ts.rb
+++ /dev/null
@@ -1,13 +0,0 @@
-# Copyright (C) 2010 Red Hat, Inc. All rights reserved.
-#
-# This copyrighted material is made available to anyone wishing to use,
-# modify, copy, or redistribute it subject to the terms and conditions
-# of the GNU General Public License v.2.
-#
-# You should have received a copy of the GNU General Public License
-# along with this program; if not, write to the Free Software Foundation,
-# Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
-
-require 'tc_log'
-require 'tc_string_store'
-require 'tc_schedule_file'
diff --git a/report-generators/title_page.rb b/report-generators/title_page.rb
deleted file mode 100644
index 66e5b03..0000000
--- a/report-generators/title_page.rb
+++ /dev/null
@@ -1,42 +0,0 @@
-# Copyright (C) 2010 Red Hat, Inc. All rights reserved.
-#
-# This copyrighted material is made available to anyone wishing to use,
-# modify, copy, or redistribute it subject to the terms and conditions
-# of the GNU General Public License v.2.
-#
-# You should have received a copy of the GNU General Public License
-# along with this program; if not, write to the Free Software Foundation,
-# Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
-
-# This generates the index for the reports, including generation
-# times.
-
-require 'log'
-require 'string-store'
-require 'reports'
-require 'erb'
-require 'report_templates'
-
-include Reports
-
-reports = ReportRegister.new
-
-def safe_mtime(r)
- r.path.file? ? r.path.mtime.to_s : "not generated"
-end
-
-template_store = TemplateStringStore.new
-
-# FIXME: use generate_report() method
-erb = ERB.new(template_store.lookup("index.rhtml"))
-body = erb.result(binding)
-title = "Generation times"
-
-erb = ERB.new(template_store.lookup("boiler_plate.rhtml"))
-txt = erb.result(binding)
-
-Pathname.new("reports/index.html").open("w") do |f|
- f.puts txt
-end
-
-
diff --git a/report-generators/unit_test.rb b/report-generators/unit_test.rb
deleted file mode 100644
index 1e5c895..0000000
--- a/report-generators/unit_test.rb
+++ /dev/null
@@ -1,56 +0,0 @@
-# Copyright (C) 2010 Red Hat, Inc. All rights reserved.
-#
-# This copyrighted material is made available to anyone wishing to use,
-# modify, copy, or redistribute it subject to the terms and conditions
-# of the GNU General Public License v.2.
-#
-# You should have received a copy of the GNU General Public License
-# along with this program; if not, write to the Free Software Foundation,
-# Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
-
-# Reads the schedule files given on the command line. Runs them and
-# generates the reports.
-
-require 'schedule_file'
-require 'pathname'
-require 'reports'
-require 'erb'
-require 'report_templates'
-
-include ReportTemplates
-
-schedules = ARGV.map do |f|
- p = Pathname.new(f)
- Schedule.read(p.dirname, p)
-end
-
-total_passed = 0
-total_failed = 0
-
-# We need to make sure the lvm shared libs are in the LD_LIBRARY_PATH
-ENV['LD_LIBRARY_PATH'] = `pwd`.strip + "/libdm:" + (ENV['LD_LIBRARY_PATH'] || '')
-
-schedules.each do |s|
- s.run
-
- s.schedules.each do |t|
- if t.status.success?
- total_passed += 1
- else
- total_failed += 1
- end
- end
-end
-
-def mangle(txt)
- txt.gsub(/\s+/, '_')
-end
-
-generate_report(:unit_test, binding)
-
-# now we generate a detail report for each schedule
-schedules.each do |s|
- s.schedules.each do |t|
- generate_report(:unit_detail, binding, Pathname.new("reports/detail_#{mangle(t.desc)}.html"))
- end
-end
diff --git a/reports/stylesheet.css b/reports/stylesheet.css
deleted file mode 100644
index 3d41926..0000000
--- a/reports/stylesheet.css
+++ /dev/null
@@ -1,77 +0,0 @@
-/* Styles for main page */
-#banner {
- background: #9c9;
- padding-top: 5px;
- padding-bottom: 5px;
- border-bottom: 2px solid;
- font: small-caps 20px/20px "Times New Roman", serif;
- color: #282;
- text-align: center;
-}
-
-#banner img {
- float: left;
-}
-
-#main {
- margin-left: 0em;
- padding-top: 4ex;
- padding-left: 2em;
- background: white;
-}
-
-h1 {
- font: 150% sans-serif;
- color: #226;
- border-bottom: 3px dotted #77d;
-}
-
-body {
- font: normal 75% verdana,arial,helvetica;
- color:#000000;
-}
-
-table tr td, table tr th {
- font-size: 75%;
-}
-
-table.stripes tr th {
- font-weight: bold;
- text-align: left;
- background: #a0a0a0;
-}
-
-table.stripes tr td {
- background: #ccccc0;
-}
-
-td.pass {
- color: green;
-}
-
-td.fail {
- color: red;
- font-weight: bold;
-}
-
-#main {
- padding-left: 0em;
-}
-
-#controls {
- float: left;
- padding-top: 1em;
- padding-left: 1em;
- padding-right: 1em;
- padding-bottom: 1em;
- width: 14em;
- border-right: 2px solid;
-}
-
-#body {
- margin-left: 16em;
- padding-top: 4ex;
- padding-left: 2em;
- background: white;
- border-left: 2px solid;
-}
diff --git a/test/unit/Makefile.in b/test/unit/Makefile.in
deleted file mode 100644
index a070329..0000000
--- a/test/unit/Makefile.in
+++ /dev/null
@@ -1,39 +0,0 @@
-# Copyright (C) 2011-2018 Red Hat, Inc. All rights reserved.
-#
-# This file is part of LVM2.
-#
-# This copyrighted material is made available to anyone wishing to use,
-# modify, copy, or redistribute it subject to the terms and conditions
-# of the GNU General Public License v.2.
-#
-# You should have received a copy of the GNU General Public License
-# along with this program; if not, write to the Free Software Foundation,
-# Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
-
-UNIT_SOURCE=\
- test/unit/bcache_t.c \
-
-
-# test/unit/run.c
-
-# test/unit/bitset_t.c\
-# test/unit/config_t.c\
-# test/unit/dmlist_t.c\
-# test/unit/dmstatus_t.c\
-# test/unit/matcher_t.c\
-# test/unit/percent_t.c\
-# test/unit/string_t.c\
-
-UNIT_OBJECTS=$(UNIT_SOURCE:%.c=%.o)
-
-UNIT_LDLIBS += $(LVMINTERNAL_LIBS) -ldevmapper -laio
-
-test/unit/run: $(UNIT_OBJECTS) libdm/libdevmapper.$(LIB_SUFFIX) lib/liblvm-internal.a
- @echo " [LD] $@"
- $(Q) $(CC) $(CFLAGS) $(LDFLAGS) $(EXTRA_EXEC_LDFLAGS) -L$(top_builddir)/libdm \
- -o $@ $(UNIT_OBJECTS) $(UNIT_LDLIBS)
-
-.PHONEY: unit-test
-unit-test: test/unit/run
- @echo Running unit tests
- LD_LIBRARY_PATH=libdm test/unit/run
diff --git a/test/unit/bcache_t.c b/test/unit/bcache_t.c
deleted file mode 100644
index 07a45fe..0000000
--- a/test/unit/bcache_t.c
+++ /dev/null
@@ -1,636 +0,0 @@
-/*
- * Copyright (C) 2018 Red Hat, Inc. All rights reserved.
- *
- * This file is part of LVM2.
- *
- * This copyrighted material is made available to anyone wishing to use,
- * modify, copy, or redistribute it subject to the terms and conditions
- * of the GNU General Public License v.2.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
- */
-
-#include <stdio.h>
-#include <stdlib.h>
-#include <unistd.h>
-#include <setjmp.h>
-
-#include "bcache.h"
-
-#define SHOW_MOCK_CALLS 0
-
-/*----------------------------------------------------------------
- * Assertions
- *--------------------------------------------------------------*/
-
-static jmp_buf _test_k;
-#define TEST_FAILED 1
-
-static void _fail(const char *fmt, ...)
- __attribute__((format (printf, 1, 2)));
-
-
-static void _fail(const char *fmt, ...)
-{
- va_list ap;
-
- va_start(ap, fmt);
- vfprintf(stderr, fmt, ap);
- va_end(ap);
- fprintf(stderr, "\n");
-
- longjmp(_test_k, TEST_FAILED);
-}
-
-#define T_ASSERT(e) if (!(e)) {_fail("assertion failed: '%s'", # e);}
-
-/*----------------------------------------------------------------
- * Mock engine
- *--------------------------------------------------------------*/
-struct mock_engine {
- struct io_engine e;
- struct dm_list expected_calls;
- struct dm_list issued_io;
- unsigned max_io;
- sector_t block_size;
-};
-
-enum method {
- E_DESTROY,
- E_ISSUE,
- E_WAIT,
- E_MAX_IO
-};
-
-struct mock_call {
- struct dm_list list;
- enum method m;
-
- bool match_args;
- enum dir d;
- int fd;
- block_address b;
-};
-
-struct mock_io {
- struct dm_list list;
- int fd;
- sector_t sb;
- sector_t se;
- void *data;
- void *context;
-};
-
-static const char *_show_method(enum method m)
-{
- switch (m) {
- case E_DESTROY:
- return "destroy()";
- case E_ISSUE:
- return "issue()";
- case E_WAIT:
- return "wait()";
- case E_MAX_IO:
- return "max_io()";
- }
-
- return "<unknown>";
-}
-
-static void _expect(struct mock_engine *e, enum method m)
-{
- struct mock_call *mc = malloc(sizeof(*mc));
- mc->m = m;
- mc->match_args = false;
- dm_list_add(&e->expected_calls, &mc->list);
-}
-
-static void _expect_read(struct mock_engine *e, int fd, block_address b)
-{
- struct mock_call *mc = malloc(sizeof(*mc));
- mc->m = E_ISSUE;
- mc->match_args = true;
- mc->d = DIR_READ;
- mc->fd = fd;
- mc->b = b;
- dm_list_add(&e->expected_calls, &mc->list);
-}
-
-static void _expect_write(struct mock_engine *e, int fd, block_address b)
-{
- struct mock_call *mc = malloc(sizeof(*mc));
- mc->m = E_ISSUE;
- mc->match_args = true;
- mc->d = DIR_WRITE;
- mc->fd = fd;
- mc->b = b;
- dm_list_add(&e->expected_calls, &mc->list);
-}
-
-static struct mock_call *_match_pop(struct mock_engine *e, enum method m)
-{
-
- struct mock_call *mc;
-
- if (dm_list_empty(&e->expected_calls))
- _fail("unexpected call to method %s\n", _show_method(m));
-
- mc = dm_list_item(e->expected_calls.n, struct mock_call);
- dm_list_del(&mc->list);
-
- if (mc->m != m)
- _fail("expected %s, but got %s\n", _show_method(mc->m), _show_method(m));
-#if SHOW_MOCK_CALLS
- else
- fprintf(stderr, "%s called (expected)\n", _show_method(m));
-#endif
-
- return mc;
-}
-
-static void _match(struct mock_engine *e, enum method m)
-{
- free(_match_pop(e, m));
-}
-
-static void _no_outstanding_expectations(struct mock_engine *e)
-{
- struct mock_call *mc;
-
- if (!dm_list_empty(&e->expected_calls)) {
- fprintf(stderr, "unsatisfied expectations:\n");
- dm_list_iterate_items (mc, &e->expected_calls)
- fprintf(stderr, " %s\n", _show_method(mc->m));
- }
- T_ASSERT(dm_list_empty(&e->expected_calls));
-}
-
-static struct mock_engine *_to_mock(struct io_engine *e)
-{
- return container_of(e, struct mock_engine, e);
-}
-
-static void _mock_destroy(struct io_engine *e)
-{
- struct mock_engine *me = _to_mock(e);
-
- _match(me, E_DESTROY);
- T_ASSERT(dm_list_empty(&me->issued_io));
- T_ASSERT(dm_list_empty(&me->expected_calls));
- free(_to_mock(e));
-}
-
-static bool _mock_issue(struct io_engine *e, enum dir d, int fd,
- sector_t sb, sector_t se, void *data, void *context)
-{
- struct mock_io *io;
- struct mock_call *mc;
- struct mock_engine *me = _to_mock(e);
-
- mc = _match_pop(me, E_ISSUE);
- if (mc->match_args) {
- T_ASSERT(d == mc->d);
- T_ASSERT(fd == mc->fd);
- T_ASSERT(sb == mc->b * me->block_size);
- T_ASSERT(se == (mc->b + 1) * me->block_size);
- }
- free(mc);
-
- io = malloc(sizeof(*io));
- if (!io)
- abort();
-
- io->fd = fd;
- io->sb = sb;
- io->se = se;
- io->data = data;
- io->context = context;
-
- dm_list_add(&me->issued_io, &io->list);
- return true;
-}
-
-static bool _mock_wait(struct io_engine *e, io_complete_fn fn)
-{
- struct mock_io *io;
- struct mock_engine *me = _to_mock(e);
- _match(me, E_WAIT);
-
- // FIXME: provide a way to control how many are completed and whether
- // they error.
- T_ASSERT(!dm_list_empty(&me->issued_io));
- io = dm_list_item(me->issued_io.n, struct mock_io);
- dm_list_del(&io->list);
- fn(io->context, 0);
- return true;
-}
-
-static unsigned _mock_max_io(struct io_engine *e)
-{
- struct mock_engine *me = _to_mock(e);
- _match(me, E_MAX_IO);
- return me->max_io;
-}
-
-static struct mock_engine *_mock_create(unsigned max_io, sector_t block_size)
-{
- struct mock_engine *m = malloc(sizeof(*m));
-
- m->e.destroy = _mock_destroy;
- m->e.issue = _mock_issue;
- m->e.wait = _mock_wait;
- m->e.max_io = _mock_max_io;
-
- m->max_io = max_io;
- m->block_size = block_size;
- dm_list_init(&m->expected_calls);
- dm_list_init(&m->issued_io);
-
- return m;
-}
-
-/*----------------------------------------------------------------
- * Fixtures
- *--------------------------------------------------------------*/
-struct fixture {
- struct mock_engine *me;
- struct bcache *cache;
-};
-
-static struct fixture *_fixture_init(sector_t block_size, unsigned nr_cache_blocks)
-{
- struct fixture *f = malloc(sizeof(*f));
-
- f->me = _mock_create(16, block_size);
- T_ASSERT(f->me);
-
- _expect(f->me, E_MAX_IO);
- f->cache = bcache_create(block_size, nr_cache_blocks, &f->me->e);
- T_ASSERT(f->cache);
-
- return f;
-}
-
-static void _fixture_exit(struct fixture *f)
-{
- _expect(f->me, E_DESTROY);
- bcache_destroy(f->cache);
-
- free(f);
-}
-
-static void *_small_fixture_init(void)
-{
- return _fixture_init(128, 16);
-}
-
-static void _small_fixture_exit(void *context)
-{
- _fixture_exit(context);
-}
-
-static void *_large_fixture_init(void)
-{
- return _fixture_init(128, 1024);
-}
-
-static void _large_fixture_exit(void *context)
-{
- _fixture_exit(context);
-}
-
-/*----------------------------------------------------------------
- * Tests
- *--------------------------------------------------------------*/
-#define MEG 2048
-#define SECTOR_SHIFT 9
-
-static void good_create(sector_t block_size, unsigned nr_cache_blocks)
-{
- struct bcache *cache;
- struct mock_engine *me = _mock_create(16, 128);
-
- _expect(me, E_MAX_IO);
- cache = bcache_create(block_size, nr_cache_blocks, &me->e);
- T_ASSERT(cache);
-
- _expect(me, E_DESTROY);
- bcache_destroy(cache);
-}
-
-static void bad_create(sector_t block_size, unsigned nr_cache_blocks)
-{
- struct bcache *cache;
- struct mock_engine *me = _mock_create(16, 128);
-
- _expect(me, E_MAX_IO);
- cache = bcache_create(block_size, nr_cache_blocks, &me->e);
- T_ASSERT(!cache);
-
- _expect(me, E_DESTROY);
- me->e.destroy(&me->e);
-}
-
-static void test_create(void *fixture)
-{
- good_create(8, 16);
-}
-
-static void test_nr_cache_blocks_must_be_positive(void *fixture)
-{
- bad_create(8, 0);
-}
-
-static void test_block_size_must_be_positive(void *fixture)
-{
- bad_create(0, 16);
-}
-
-static void test_block_size_must_be_multiple_of_page_size(void *fixture)
-{
- static unsigned _bad_examples[] = {3, 9, 13, 1025};
-
- unsigned i;
-
- for (i = 0; i < DM_ARRAY_SIZE(_bad_examples); i++)
- bad_create(_bad_examples[i], 16);
-
- for (i = 1; i < 1000; i++)
- good_create(i * 8, 16);
-}
-
-static void test_get_triggers_read(void *context)
-{
- struct fixture *f = context;
-
- int fd = 17; // arbitrary key
- struct block *b;
-
- _expect_read(f->me, fd, 0);
- _expect(f->me, E_WAIT);
- T_ASSERT(bcache_get(f->cache, fd, 0, 0, &b));
- bcache_put(b);
-}
-
-static void test_repeated_reads_are_cached(void *context)
-{
- struct fixture *f = context;
-
- int fd = 17; // arbitrary key
- unsigned i;
- struct block *b;
-
- _expect_read(f->me, fd, 0);
- _expect(f->me, E_WAIT);
- for (i = 0; i < 100; i++) {
- T_ASSERT(bcache_get(f->cache, fd, 0, 0, &b));
- bcache_put(b);
- }
-}
-
-static void test_block_gets_evicted_with_many_reads(void *context)
-{
- struct fixture *f = context;
-
- struct mock_engine *me = f->me;
- struct bcache *cache = f->cache;
- const unsigned nr_cache_blocks = 16;
-
- int fd = 17; // arbitrary key
- unsigned i;
- struct block *b;
-
- for (i = 0; i < nr_cache_blocks; i++) {
- _expect_read(me, fd, i);
- _expect(me, E_WAIT);
- T_ASSERT(bcache_get(cache, fd, i, 0, &b));
- bcache_put(b);
- }
-
- // Not enough cache blocks to hold this one
- _expect_read(me, fd, nr_cache_blocks);
- _expect(me, E_WAIT);
- T_ASSERT(bcache_get(cache, fd, nr_cache_blocks, 0, &b));
- bcache_put(b);
-
- // Now if we run through we should find one block has been
- // evicted. We go backwards because the oldest is normally
- // evicted first.
- _expect(me, E_ISSUE);
- _expect(me, E_WAIT);
- for (i = nr_cache_blocks; i; i--) {
- T_ASSERT(bcache_get(cache, fd, i - 1, 0, &b));
- bcache_put(b);
- }
-}
-
-static void test_prefetch_issues_a_read(void *context)
-{
- struct fixture *f = context;
- struct mock_engine *me = f->me;
- struct bcache *cache = f->cache;
- const unsigned nr_cache_blocks = 16;
-
- int fd = 17; // arbitrary key
- unsigned i;
- struct block *b;
-
- for (i = 0; i < nr_cache_blocks; i++) {
- // prefetch should not wait
- _expect_read(me, fd, i);
- bcache_prefetch(cache, fd, i);
- }
-
-
- for (i = 0; i < nr_cache_blocks; i++) {
- _expect(me, E_WAIT);
- T_ASSERT(bcache_get(cache, fd, i, 0, &b));
- bcache_put(b);
- }
-}
-
-static void test_too_many_prefetches_does_not_trigger_a_wait(void *context)
-{
- struct fixture *f = context;
- struct mock_engine *me = f->me;
- struct bcache *cache = f->cache;
-
- const unsigned nr_cache_blocks = 16;
- int fd = 17; // arbitrary key
- unsigned i;
-
- for (i = 0; i < 10 * nr_cache_blocks; i++) {
- // prefetch should not wait
- if (i < nr_cache_blocks)
- _expect_read(me, fd, i);
- bcache_prefetch(cache, fd, i);
- }
-
- // Destroy will wait for any in flight IO triggered by prefetches.
- for (i = 0; i < nr_cache_blocks; i++)
- _expect(me, E_WAIT);
-}
-
-static void test_dirty_data_gets_written_back(void *context)
-{
- struct fixture *f = context;
- struct mock_engine *me = f->me;
- struct bcache *cache = f->cache;
-
- int fd = 17; // arbitrary key
- struct block *b;
-
- // Expect the read
- _expect_read(me, fd, 0);
- _expect(me, E_WAIT);
- T_ASSERT(bcache_get(cache, fd, 0, GF_DIRTY, &b));
- bcache_put(b);
-
- // Expect the write
- _expect_write(me, fd, 0);
- _expect(me, E_WAIT);
-}
-
-static void test_zeroed_data_counts_as_dirty(void *context)
-{
- struct fixture *f = context;
- struct mock_engine *me = f->me;
- struct bcache *cache = f->cache;
-
- int fd = 17; // arbitrary key
- struct block *b;
-
- // No read
- T_ASSERT(bcache_get(cache, fd, 0, GF_ZERO, &b));
- bcache_put(b);
-
- // Expect the write
- _expect_write(me, fd, 0);
- _expect(me, E_WAIT);
-}
-
-static void test_flush_waits_for_all_dirty(void *context)
-{
- struct fixture *f = context;
- struct mock_engine *me = f->me;
- struct bcache *cache = f->cache;
-
- const unsigned count = 16;
- int fd = 17; // arbitrary key
- unsigned i;
- struct block *b;
-
- for (i = 0; i < count; i++) {
- if (i % 2) {
- T_ASSERT(bcache_get(cache, fd, i, GF_ZERO, &b));
- } else {
- _expect_read(me, fd, i);
- _expect(me, E_WAIT);
- T_ASSERT(bcache_get(cache, fd, i, 0, &b));
- }
- bcache_put(b);
- }
-
- for (i = 0; i < count; i++) {
- if (i % 2)
- _expect_write(me, fd, i);
- }
-
- for (i = 0; i < count; i++) {
- if (i % 2)
- _expect(me, E_WAIT);
- }
-
- bcache_flush(cache);
- _no_outstanding_expectations(me);
-}
-
-static void test_multiple_files(void * context)
-{
- static int _fds[] = {1, 128, 345, 678, 890};
-
- struct fixture *f = context;
- struct mock_engine *me = f->me;
- struct bcache *cache = f->cache;
- struct block *b;
- unsigned i;
-
- for (i = 0; i < DM_ARRAY_SIZE(_fds); i++) {
- _expect_read(me, _fds[i], 0);
- _expect(me, E_WAIT);
-
- T_ASSERT(bcache_get(cache, _fds[i], 0, 0, &b));
- bcache_put(b);
- }
-}
-
-// Tests to be written
-// Open multiple files and prove the blocks are coming from the correct file
-// show invalidate works
-// show invalidate_fd works
-// show writeback is working
-// check zeroing
-
-struct test_details {
- const char *path;
- const char *desc;
- void (*fn)(void *);
- void *(*fixture_init)(void);
- void (*fixture_exit)(void *);
-};
-
-#define PATH "device/bcache/"
-#define TEST(path, name, fn) {PATH path, name, fn, NULL, NULL}
-#define TEST_S(path, name, fn) {PATH path, name, fn, _small_fixture_init, _small_fixture_exit}
-#define TEST_L(path, name, fn) {PATH path, name, fn, _large_fixture_init, _large_fixture_exit}
-
-int main(int argc, char **argv)
-{
- static struct test_details _tests[] = {
- TEST("create-destroy", "simple create/destroy", test_create),
- TEST("cache-blocks-positive", "nr cache blocks must be positive", test_nr_cache_blocks_must_be_positive),
- TEST("block-size-positive", "block size must be positive", test_block_size_must_be_positive),
- TEST("block-size-multiple-page", "block size must be a multiple of page size", test_block_size_must_be_multiple_of_page_size),
- TEST_S("get-reads", "bcache_get() triggers read", test_get_triggers_read),
- TEST_S("reads-cached", "repeated reads are cached", test_repeated_reads_are_cached),
- TEST_S("blocks-get-evicted", "block get evicted with many reads", test_block_gets_evicted_with_many_reads),
- TEST_S("prefetch-reads", "prefetch issues a read", test_prefetch_issues_a_read),
- TEST_S("prefetch-never-waits", "too many prefetches does not trigger a wait", test_too_many_prefetches_does_not_trigger_a_wait),
- TEST_S("writeback-occurs", "dirty data gets written back", test_dirty_data_gets_written_back),
- TEST_S("zero-flag-dirties", "zeroed data counts as dirty", test_zeroed_data_counts_as_dirty),
- TEST_L("flush waits for all dirty", "flush waits for all dirty", test_flush_waits_for_all_dirty),
- TEST_S("read-multiple-files", "read from multiple files", test_multiple_files),
- };
-
- // We have to declare these as volatile because of the setjmp()
- volatile unsigned i = 0, passed = 0;
-
- for (i = 0; i < DM_ARRAY_SIZE(_tests); i++) {
- void *fixture;
- struct test_details *t = _tests + i;
- fprintf(stderr, "[RUN ] %s\n", t->path);
-
- if (setjmp(_test_k))
- fprintf(stderr, "[ FAIL] %s\n", t->path);
- else {
- if (t->fixture_init)
- fixture = t->fixture_init();
- else
- fixture = NULL;
-
- t->fn(fixture);
-
- if (t->fixture_exit)
- t->fixture_exit(fixture);
-
- passed++;
- fprintf(stderr, "[ OK] %s\n", t->path);
- }
- }
-
- fprintf(stderr, "\n%u/%lu tests passed\n", passed, DM_ARRAY_SIZE(_tests));
-
- return 0;
-}
diff --git a/test/unit/bitset_t.c b/test/unit/bitset_t.c
deleted file mode 100644
index dadb9ec..0000000
--- a/test/unit/bitset_t.c
+++ /dev/null
@@ -1,129 +0,0 @@
-/*
- * Copyright (C) 2010 Red Hat, Inc. All rights reserved.
- *
- * This file is part of LVM2.
- *
- * This copyrighted material is made available to anyone wishing to use,
- * modify, copy, or redistribute it subject to the terms and conditions
- * of the GNU General Public License v.2.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
- */
-
-#include "units.h"
-
-enum {
- NR_BITS = 137
-};
-
-static struct dm_pool *mem;
-
-int bitset_init(void) {
- mem = dm_pool_create("bitset test", 1024);
- return mem == NULL;
-}
-
-int bitset_fini(void) {
- dm_pool_destroy(mem);
- return 0;
-}
-
-static void test_get_next(void)
-{
- int i, j, last = 0, first;
- dm_bitset_t bs = dm_bitset_create(mem, NR_BITS);
-
- for (i = 0; i < NR_BITS; i++)
- CU_ASSERT(!dm_bit(bs, i));
-
- for (i = 0, j = 1; i < NR_BITS; i += j, j++)
- dm_bit_set(bs, i);
-
- first = 1;
- for (i = 0, j = 1; i < NR_BITS; i += j, j++) {
- if (first) {
- last = dm_bit_get_first(bs);
- first = 0;
- } else
- last = dm_bit_get_next(bs, last);
-
- CU_ASSERT(last == i);
- }
-
- CU_ASSERT(dm_bit_get_next(bs, last) == -1);
-}
-
-static void bit_flip(dm_bitset_t bs, int bit)
-{
- int old = dm_bit(bs, bit);
- if (old)
- dm_bit_clear(bs, bit);
- else
- dm_bit_set(bs, bit);
-}
-
-static void test_equal(void)
-{
- dm_bitset_t bs1 = dm_bitset_create(mem, NR_BITS);
- dm_bitset_t bs2 = dm_bitset_create(mem, NR_BITS);
-
- int i, j;
- for (i = 0, j = 1; i < NR_BITS; i += j, j++) {
- dm_bit_set(bs1, i);
- dm_bit_set(bs2, i);
- }
-
- CU_ASSERT(dm_bitset_equal(bs1, bs2));
- CU_ASSERT(dm_bitset_equal(bs2, bs1));
-
- for (i = 0; i < NR_BITS; i++) {
- bit_flip(bs1, i);
- CU_ASSERT(!dm_bitset_equal(bs1, bs2));
- CU_ASSERT(!dm_bitset_equal(bs2, bs1));
-
- CU_ASSERT(dm_bitset_equal(bs1, bs1)); /* comparing with self */
- bit_flip(bs1, i);
- }
-}
-
-static void test_and(void)
-{
- dm_bitset_t bs1 = dm_bitset_create(mem, NR_BITS);
- dm_bitset_t bs2 = dm_bitset_create(mem, NR_BITS);
- dm_bitset_t bs3 = dm_bitset_create(mem, NR_BITS);
-
- int i, j;
- for (i = 0, j = 1; i < NR_BITS; i += j, j++) {
- dm_bit_set(bs1, i);
- dm_bit_set(bs2, i);
- }
-
- dm_bit_and(bs3, bs1, bs2);
-
- CU_ASSERT(dm_bitset_equal(bs1, bs2));
- CU_ASSERT(dm_bitset_equal(bs1, bs3));
- CU_ASSERT(dm_bitset_equal(bs2, bs3));
-
- dm_bit_clear_all(bs1);
- dm_bit_clear_all(bs2);
-
- for (i = 0; i < NR_BITS; i++) {
- if (i % 2)
- dm_bit_set(bs1, i);
- else
- dm_bit_set(bs2, i);
- }
-
- dm_bit_and(bs3, bs1, bs2);
- for (i = 0; i < NR_BITS; i++)
- CU_ASSERT(!dm_bit(bs3, i));
-}
-
-CU_TestInfo bitset_list[] = {
- { (char*)"get_next", test_get_next },
- { (char*)"equal", test_equal },
- { (char*)"and", test_and },
- CU_TEST_INFO_NULL
-};
diff --git a/test/unit/config_t.c b/test/unit/config_t.c
deleted file mode 100644
index 342667e..0000000
--- a/test/unit/config_t.c
+++ /dev/null
@@ -1,152 +0,0 @@
-/*
- * Copyright (C) 2010 Red Hat, Inc. All rights reserved.
- *
- * This file is part of LVM2.
- *
- * This copyrighted material is made available to anyone wishing to use,
- * modify, copy, or redistribute it subject to the terms and conditions
- * of the GNU General Public License v.2.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
- */
-
-#include "units.h"
-
-static struct dm_pool *mem;
-
-int config_init(void) {
- mem = dm_pool_create("config test", 1024);
- return mem == NULL;
-}
-
-int config_fini(void) {
- dm_pool_destroy(mem);
- return 0;
-}
-
-static const char *conf =
- "id = \"yada-yada\"\n"
- "seqno = 15\n"
- "status = [\"READ\", \"WRITE\"]\n"
- "flags = []\n"
- "extent_size = 8192\n"
- "physical_volumes {\n"
- " pv0 {\n"
- " id = \"abcd-efgh\"\n"
- " }\n"
- " pv1 {\n"
- " id = \"bbcd-efgh\"\n"
- " }\n"
- " pv2 {\n"
- " id = \"cbcd-efgh\"\n"
- " }\n"
- "}\n";
-
-static const char *overlay =
- "id = \"yoda-soda\"\n"
- "flags = [\"FOO\"]\n"
- "physical_volumes {\n"
- " pv1 {\n"
- " id = \"hgfe-dcba\"\n"
- " }\n"
- " pv3 {\n"
- " id = \"dbcd-efgh\"\n"
- " }\n"
- "}\n";
-
-static void test_parse(void)
-{
- struct dm_config_tree *tree = dm_config_from_string(conf);
- const struct dm_config_value *value;
-
- CU_ASSERT((long) tree);
- CU_ASSERT(dm_config_has_node(tree->root, "id"));
- CU_ASSERT(dm_config_has_node(tree->root, "physical_volumes"));
- CU_ASSERT(dm_config_has_node(tree->root, "physical_volumes/pv0"));
- CU_ASSERT(dm_config_has_node(tree->root, "physical_volumes/pv0/id"));
-
- CU_ASSERT(!strcmp(dm_config_find_str(tree->root, "id", "foo"), "yada-yada"));
- CU_ASSERT(!strcmp(dm_config_find_str(tree->root, "idt", "foo"), "foo"));
-
- CU_ASSERT(!strcmp(dm_config_find_str(tree->root, "physical_volumes/pv0/bb", "foo"), "foo"));
- CU_ASSERT(!strcmp(dm_config_find_str(tree->root, "physical_volumes/pv0/id", "foo"), "abcd-efgh"));
-
- CU_ASSERT(!dm_config_get_uint32(tree->root, "id", NULL));
- CU_ASSERT(dm_config_get_uint32(tree->root, "extent_size", NULL));
-
- /* FIXME: Currently everything parses as a list, even if it's not */
- // CU_ASSERT(!dm_config_get_list(tree->root, "id", NULL));
- // CU_ASSERT(!dm_config_get_list(tree->root, "extent_size", NULL));
-
- CU_ASSERT(dm_config_get_list(tree->root, "flags", &value));
- CU_ASSERT(value->next == NULL); /* an empty list */
- CU_ASSERT(dm_config_get_list(tree->root, "status", &value));
- CU_ASSERT(value->next != NULL); /* a non-empty list */
-
- dm_config_destroy(tree);
-}
-
-static void test_clone(void)
-{
- struct dm_config_tree *tree = dm_config_from_string(conf);
- struct dm_config_node *n = dm_config_clone_node(tree, tree->root, 1);
- const struct dm_config_value *value;
-
- /* Check that the nodes are actually distinct. */
- CU_ASSERT(n != tree->root);
- CU_ASSERT(n->sib != tree->root->sib);
- CU_ASSERT(dm_config_find_node(n, "physical_volumes") != NULL);
- CU_ASSERT(dm_config_find_node(tree->root, "physical_volumes") != NULL);
- CU_ASSERT(dm_config_find_node(n, "physical_volumes") != dm_config_find_node(tree->root, "physical_volumes"));
-
- CU_ASSERT(dm_config_has_node(n, "id"));
- CU_ASSERT(dm_config_has_node(n, "physical_volumes"));
- CU_ASSERT(dm_config_has_node(n, "physical_volumes/pv0"));
- CU_ASSERT(dm_config_has_node(n, "physical_volumes/pv0/id"));
-
- CU_ASSERT(!strcmp(dm_config_find_str(n, "id", "foo"), "yada-yada"));
- CU_ASSERT(!strcmp(dm_config_find_str(n, "idt", "foo"), "foo"));
-
- CU_ASSERT(!strcmp(dm_config_find_str(n, "physical_volumes/pv0/bb", "foo"), "foo"));
- CU_ASSERT(!strcmp(dm_config_find_str(n, "physical_volumes/pv0/id", "foo"), "abcd-efgh"));
-
- CU_ASSERT(!dm_config_get_uint32(n, "id", NULL));
- CU_ASSERT(dm_config_get_uint32(n, "extent_size", NULL));
-
- /* FIXME: Currently everything parses as a list, even if it's not */
- // CU_ASSERT(!dm_config_get_list(tree->root, "id", NULL));
- // CU_ASSERT(!dm_config_get_list(tree->root, "extent_size", NULL));
-
- CU_ASSERT(dm_config_get_list(n, "flags", &value));
- CU_ASSERT(value->next == NULL); /* an empty list */
- CU_ASSERT(dm_config_get_list(n, "status", &value));
- CU_ASSERT(value->next != NULL); /* a non-empty list */
-
- dm_config_destroy(tree);
-}
-
-static void test_cascade(void)
-{
- struct dm_config_tree *t1 = dm_config_from_string(conf),
- *t2 = dm_config_from_string(overlay),
- *tree = dm_config_insert_cascaded_tree(t2, t1);
-
- CU_ASSERT(!strcmp(dm_config_tree_find_str(tree, "id", "foo"), "yoda-soda"));
- CU_ASSERT(!strcmp(dm_config_tree_find_str(tree, "idt", "foo"), "foo"));
-
- CU_ASSERT(!strcmp(dm_config_tree_find_str(tree, "physical_volumes/pv0/bb", "foo"), "foo"));
- CU_ASSERT(!strcmp(dm_config_tree_find_str(tree, "physical_volumes/pv1/id", "foo"), "hgfe-dcba"));
- CU_ASSERT(!strcmp(dm_config_tree_find_str(tree, "physical_volumes/pv3/id", "foo"), "dbcd-efgh"));
-
- dm_config_destroy(t1);
- dm_config_destroy(t2);
-}
-
-CU_TestInfo config_list[] = {
- { (char*)"parse", test_parse },
- { (char*)"clone", test_clone },
- { (char*)"cascade", test_cascade },
- CU_TEST_INFO_NULL
-};
diff --git a/test/unit/dmlist_t.c b/test/unit/dmlist_t.c
deleted file mode 100644
index f582e83..0000000
--- a/test/unit/dmlist_t.c
+++ /dev/null
@@ -1,49 +0,0 @@
-/*
- * Copyright (C) 2015 Red Hat, Inc. All rights reserved.
- *
- * This file is part of LVM2.
- *
- * This copyrighted material is made available to anyone wishing to use,
- * modify, copy, or redistribute it subject to the terms and conditions
- * of the GNU General Public License v.2.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
- */
-
-#include "units.h"
-
-int dmlist_init(void)
-{
- return 0;
-}
-
-int dmlist_fini(void)
-{
- return 0;
-}
-
-static void test_dmlist_splice(void)
-{
- struct dm_list a[10];
- struct dm_list list1;
- struct dm_list list2;
- unsigned i;
-
- dm_list_init(&list1);
- dm_list_init(&list2);
-
- for (i = 0; i < DM_ARRAY_SIZE(a); i++)
- dm_list_add(&list1, &a[i]);
-
- dm_list_splice(&list2, &list1);
- CU_ASSERT_EQUAL(dm_list_size(&list1), 0);
- CU_ASSERT_EQUAL(dm_list_size(&list2), 10);
-}
-
-CU_TestInfo dmlist_list[] = {
- { (char*)"dmlist_splice", test_dmlist_splice },
- //{ (char*)"dmlist", test_strncpy },
- CU_TEST_INFO_NULL
-};
diff --git a/test/unit/dmstatus_t.c b/test/unit/dmstatus_t.c
deleted file mode 100644
index 00af56d..0000000
--- a/test/unit/dmstatus_t.c
+++ /dev/null
@@ -1,72 +0,0 @@
-/*
- * Copyright (C) 2015 Red Hat, Inc. All rights reserved.
- *
- * This file is part of LVM2.
- *
- * This copyrighted material is made available to anyone wishing to use,
- * modify, copy, or redistribute it subject to the terms and conditions
- * of the GNU General Public License v.2.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
- */
-
-#include "units.h"
-
-static struct dm_pool *_mem;
-
-int dmstatus_init(void)
-{
- _mem = dm_pool_create("dmstatus test", 1024);
- return (_mem == NULL);
-}
-
-int dmstatus_fini(void)
-{
- dm_pool_destroy(_mem);
- return 0;
-}
-
-static void _test_mirror_status(void)
-{
- struct dm_status_mirror *s = NULL;
-
- CU_ASSERT(dm_get_status_mirror(_mem,
- "2 253:1 253:2 80/81 1 AD 3 disk 253:0 A",
- &s));
- if (s) {
- CU_ASSERT_EQUAL(s->total_regions, 81);
- CU_ASSERT_EQUAL(s->insync_regions, 80);
- CU_ASSERT_EQUAL(s->dev_count, 2);
- CU_ASSERT_EQUAL(s->devs[0].health, 'A');
- CU_ASSERT_EQUAL(s->devs[0].major, 253);
- CU_ASSERT_EQUAL(s->devs[0].minor, 1);
- CU_ASSERT_EQUAL(s->devs[1].health, 'D');
- CU_ASSERT_EQUAL(s->devs[1].major, 253);
- CU_ASSERT_EQUAL(s->devs[1].minor, 2);
- CU_ASSERT_EQUAL(s->log_count, 1);
- CU_ASSERT_EQUAL(s->logs[0].major, 253);
- CU_ASSERT_EQUAL(s->logs[0].minor, 0);
- CU_ASSERT_EQUAL(s->logs[0].health, 'A');
- CU_ASSERT(!strcmp(s->log_type, "disk"));
- }
-
- CU_ASSERT(dm_get_status_mirror(_mem,
- "4 253:1 253:2 253:3 253:4 10/10 1 ADFF 1 core",
- &s));
- if (s) {
- CU_ASSERT_EQUAL(s->total_regions, 10);
- CU_ASSERT_EQUAL(s->insync_regions, 10);
- CU_ASSERT_EQUAL(s->dev_count, 4);
- CU_ASSERT_EQUAL(s->devs[3].minor, 4);
- CU_ASSERT_EQUAL(s->devs[3].health, 'F');
- CU_ASSERT_EQUAL(s->log_count, 0);
- CU_ASSERT(!strcmp(s->log_type, "core"));
- }
-}
-
-CU_TestInfo dmstatus_list[] = {
- { (char*)"mirror_status", _test_mirror_status },
- CU_TEST_INFO_NULL
-};
diff --git a/test/unit/matcher_data.h b/test/unit/matcher_data.h
deleted file mode 100644
index 97dbbfe..0000000
--- a/test/unit/matcher_data.h
+++ /dev/null
@@ -1,1013 +0,0 @@
-struct check_item {
- const char *str;
- int expected;
-};
-
-static const char *dev_patterns[] = {
- "loop/[0-9]+",
- "hd[a-d][0-5]+",
- NULL
-};
-
-static const char *nonprint_patterns[] = {
- "foo\x80" "bar",
- "foo\xc2" "b",
- "\x80",
- NULL
-};
-
-static const struct check_item nonprint[] = {
- { "foo\x2e" "bar", 0 },
- { "foo\x80" "bar", 3 },
- { "foo\xc2" "b", 2 },
- { "\x80", 3 },
- { NULL, 0 }
-};
-
-static const char *random_patterns[] = {
- "(((a?)(([Ub]*)|z))((([qr]|X)+)([Qn]*)))+",
- "[HZejtuw]*",
- "((B|s)*)|(((([Fv]l)(N+))(([el]|C)(tJ)))?)",
- "((([Ma]?)|(t*))*)|((([cm]E)|(M?))|(([BE][EV])|([Qj][Mh])))",
- "(((([bw]*)|([IO]*))((zK)*))|(((pU)|(i|q))|((z?)|([HL]?))))*",
- "((([Pt]?)|[Tr])?)((Hq)*)",
- "[HOXcfgikosvwxz]",
- "[BCEFGHNPTUWfjlprsy]",
- "((((aD)*)|([Xo]+))+)(([HKn](([Eq]|[JQ])(I*)))*)",
- "([LNWYeghv]|e)*",
- "(((y(L*))*)|((([EP]+)(W+))*))*",
- "U*",
- "((((R+)(W|[Qr]))|([py]+))+)([LM]*)",
- "(([DOjx](D(b?)))|([Ke]*))*",
- "((([ls](c|[FT]))*)([JS]*))*",
- "((l?)|(([Gz]+)|(D*)))*",
- "[ABgjn]",
- "(((q|[dg])?)|([Uk]*))((([Fl]?)|([Ry]+))|(([IR]|c)|(T?)))",
- "((([an]|P)|[Jw])((a*)|(m*)))*",
- "((((R[ht])(h+))?)|(([pz](n?))+))+",
- "(((([Dc]b)([Sp][Ii]))|((k|F)*))|[Uiovz])*",
- "[Res]*",
- "[Zl]|a",
- "^[ANZdf]$",
- "[En]|(((Q+)(U+))([pt]*))",
- "[ADEIMQUWXZhklrsvz]",
- "(((S(y*))*)|(j*))*",
- "n*",
- "[NUau]*",
- "((((Z*)(D|[Nd]))|(([np]|B)+))|(([Xy][Fi])*))+",
- "((([EZ]?)|(d[HR]))*)((([Hg]|q)(P+))*)",
- "q",
- "((m*)|(p|B))|((((x?)|(t+))(([Sb][PX])(O|[HM])))+)",
- "((((A*)(z[RS]))*)|(((z+)(Q*))+))*",
- "(((M*)([Uu]*))+)|[Uk]",
- "[imv]",
- "[GLSchtw](([Yw]((F[Dd])|([Tw]+)))?)",
- "([MOZj]*)(S|[Wknr])",
- "((G|q)*)[BHKN]",
- "((((NW)|([Ao]?))|((l|[UV])+))+)|((i|(z*))*)",
- "((((Z+)|([IR]?))|(L*))|([JKQ]+))+",
- "([Bdin](S*))+",
- "[HLNSTp]*",
- "(((J*)([Bq]|[Yu]))*)|([Kv]*)",
- "(((([BJ]|[Zy])(wI))*)(y*))+",
- "(((hF)+)|(H*))*",
- "((([QU][Pj])([GQ]?))+)|[PWo]",
- "(((([cq][BX])?)|((f[DI])*))*)(([GM]*)[SVYr])",
- "(([Zt]*)|((qx)|(([BV]+)(f?))))*",
- "[ILWYhsx]*",
- "(([Uy]*)|[sv])|([NSc]*)",
- "((c*)|([JUfhy]?))+",
- "(((q*)([So]*))(((g[jq])(j?))+))*",
- "((b+)|(((T+)([fw]T))?))*",
- "((([DS]?)|([Th]|u))(Q*))*",
- "[FKLX]|((([fw](L?))(([gq]*)|(O?)))?)",
- "((([HZ]+)u)*)|[APWijn]",
- "(e*)|(((v?)|((J+)(Hb)))?)",
- "(e|((w+)f))*",
- "[BEHKPQVdelnqy]",
- "((((B|N)(s*))|[Rr])(((g?)|([rv]+))+))+",
- "(((s*)|(K*))([AP]G))*",
- "[CELTp]",
- "(([Fq]?)|([Al]+))*",
- "((((r?)|(y[jx]))|([mp]*))+)|((B(S*))*)",
- "((([Eq]+)|(Y[ds]))|(x|(i|[Ku])))[IJNrvy]",
- "((([NO]*)[Ix])+)([Jenq]+)",
- "(((([HP]*)(j|y))*)[Ylqvy])*",
- "[PTv]+",
- "[AINSZhpx]|([EOYZ]*)",
- "([ABCFQv]*)((([Zx]|h)+)|([ej]*))",
- "((([pr]*)|(([Dq]|p)|(H?)))?)([NRUXmoq]*)",
- "(([er]*)|([mx]*))(((nV)([am]?))+)",
- "[BHPRlpu]",
- "(((([Ah]|[tx])|(e|[uy]))?)((([fl]+)([Vz]|v))*))*",
- "[AGdm]",
- "(((K*)^(O*)$)|(B?))*",
- "((([Ks]|[Ka])*)|([FSTab]?))?",
- "(([kw]+)[ei])(([Hy]*)(([Mc]*)|(G|f)))",
- "((((e*)|(Zf))|(R|[nq]))((([Jz]v)([Rj]+))+))*",
- "(((a?)|(e?))(([Uc]*)(S+)))*",
- "((((E+)([MZ]?))+)|(((s|[Az])|z)*))?",
- "((((i[MO])*)|((LH)*))|(((BA)|([AI]+))|[Ug]))*",
- "[EGHILcho]*",
- "(((Z[vw])?)((z|g)+))(((H|U)([iv]Q))|([qw]?))",
- "(([ehmr]|((L[Uw])*))+)((a+)I)",
- "[EKNSWYagj](((v|[TX])|([Uk]+))*)",
- "(((R[Mo])|(O*))|([Fm]|([qw]*)))((m*)|((S|[Ki])?))",
- "((((kP)|c)?)((([do]+)|([Gi]?))*))*",
- "((^(B|W)$|([Ww]+))([no]*))|((([iv]?)|(M*))|((x|L)?))",
- "[AEGPRSbcfhsy]",
- "[Wbcf]|((([MO]?)|([NT]|m))(([Oo]?)([Wg]*)))",
- "(((YZ)*)[PQVei])*",
- "[GJKYt][AEGWdegmnt]",
- "^[CDEGJKNUVYZagkv]$",
- "([DPWbx]*)|(((q|B)|(P|u))((M[Bq])*))",
- "[FHIJRTVYZdiorsuvz]*",
- "([MWoqvz]*)|^(l*)",
- "(((I|[Rx])*)((X[Mf])([Xa]L)))([Ha]|([HY]*))",
- "(((l|[Sd])*)((([Ix]+)|([XY]?))(Z*)))+",
- NULL
-};
-
-struct check_item devices[] = {
- { "/dev", 0 },
- { "/dev/.devfsd", 0 },
- { "/dev/cpu", 0 },
- { "/dev/cpu/mtrr", 0 },
- { "/dev/netlink", 0 },
- { "/dev/netlink/route", 0 },
- { "/dev/netlink/skip", 0 },
- { "/dev/netlink/USERSOCK", 0 },
- { "/dev/netlink/fwmonitor", 0 },
- { "/dev/netlink/ARPD", 0 },
- { "/dev/netlink/ROUTE6", 0 },
- { "/dev/netlink/IP6_FW", 0 },
- { "/dev/netlink/tap0", 0 },
- { "/dev/netlink/tap1", 0 },
- { "/dev/netlink/tap2", 0 },
- { "/dev/netlink/tap3", 0 },
- { "/dev/netlink/tap4", 0 },
- { "/dev/netlink/tap5", 0 },
- { "/dev/netlink/tap6", 0 },
- { "/dev/netlink/tap7", 0 },
- { "/dev/netlink/tap8", 0 },
- { "/dev/netlink/tap9", 0 },
- { "/dev/netlink/tap10", 0 },
- { "/dev/netlink/tap11", 0 },
- { "/dev/netlink/tap12", 0 },
- { "/dev/netlink/tap13", 0 },
- { "/dev/netlink/tap14", 0 },
- { "/dev/netlink/tap15", 0 },
- { "/dev/shm", 0 },
- { "/dev/mem", 0 },
- { "/dev/kmem", 0 },
- { "/dev/null", 0 },
- { "/dev/port", 0 },
- { "/dev/zero", 0 },
- { "/dev/full", 0 },
- { "/dev/random", 0 },
- { "/dev/urandom", 0 },
- { "/dev/tty", 0 },
- { "/dev/console", 0 },
- { "/dev/vc", 0 },
- { "/dev/vc/1", 0 },
- { "/dev/vc/2", 0 },
- { "/dev/vc/3", 0 },
- { "/dev/vc/4", 0 },
- { "/dev/vc/5", 0 },
- { "/dev/vc/6", 0 },
- { "/dev/vc/7", 0 },
- { "/dev/vc/8", 0 },
- { "/dev/vc/9", 0 },
- { "/dev/vc/10", 0 },
- { "/dev/vc/11", 0 },
- { "/dev/vc/12", 0 },
- { "/dev/vc/13", 0 },
- { "/dev/vc/14", 0 },
- { "/dev/vc/15", 0 },
- { "/dev/vc/16", 0 },
- { "/dev/vc/17", 0 },
- { "/dev/vc/18", 0 },
- { "/dev/vc/19", 0 },
- { "/dev/vc/20", 0 },
- { "/dev/vc/21", 0 },
- { "/dev/vc/22", 0 },
- { "/dev/vc/23", 0 },
- { "/dev/vc/24", 0 },
- { "/dev/vc/25", 0 },
- { "/dev/vc/26", 0 },
- { "/dev/vc/27", 0 },
- { "/dev/vc/28", 0 },
- { "/dev/vc/29", 0 },
- { "/dev/vc/30", 0 },
- { "/dev/vc/31", 0 },
- { "/dev/vc/32", 0 },
- { "/dev/vc/33", 0 },
- { "/dev/vc/34", 0 },
- { "/dev/vc/35", 0 },
- { "/dev/vc/36", 0 },
- { "/dev/vc/37", 0 },
- { "/dev/vc/38", 0 },
- { "/dev/vc/39", 0 },
- { "/dev/vc/40", 0 },
- { "/dev/vc/41", 0 },
- { "/dev/vc/42", 0 },
- { "/dev/vc/43", 0 },
- { "/dev/vc/44", 0 },
- { "/dev/vc/45", 0 },
- { "/dev/vc/46", 0 },
- { "/dev/vc/47", 0 },
- { "/dev/vc/48", 0 },
- { "/dev/vc/49", 0 },
- { "/dev/vc/50", 0 },
- { "/dev/vc/51", 0 },
- { "/dev/vc/52", 0 },
- { "/dev/vc/53", 0 },
- { "/dev/vc/54", 0 },
- { "/dev/vc/55", 0 },
- { "/dev/vc/56", 0 },
- { "/dev/vc/57", 0 },
- { "/dev/vc/58", 0 },
- { "/dev/vc/59", 0 },
- { "/dev/vc/60", 0 },
- { "/dev/vc/61", 0 },
- { "/dev/vc/62", 0 },
- { "/dev/vc/63", 0 },
- { "/dev/vc/0", 0 },
- { "/dev/ptmx", 0 },
- { "/dev/misc", 0 },
- { "/dev/misc/psaux", 0 },
- { "/dev/pty", 0 },
- { "/dev/pty/m0", 0 },
- { "/dev/pty/m1", 0 },
- { "/dev/pty/m2", 0 },
- { "/dev/pty/m3", 0 },
- { "/dev/pty/m4", 0 },
- { "/dev/pty/m5", 0 },
- { "/dev/pty/m6", 0 },
- { "/dev/pty/m7", 0 },
- { "/dev/pty/m8", 0 },
- { "/dev/pty/m9", 0 },
- { "/dev/pty/m10", 0 },
- { "/dev/pty/m11", 0 },
- { "/dev/pty/m12", 0 },
- { "/dev/pty/m13", 0 },
- { "/dev/pty/m14", 0 },
- { "/dev/pty/m15", 0 },
- { "/dev/pty/m16", 0 },
- { "/dev/pty/m17", 0 },
- { "/dev/pty/m18", 0 },
- { "/dev/pty/m19", 0 },
- { "/dev/pty/m20", 0 },
- { "/dev/pty/m21", 0 },
- { "/dev/pty/m22", 0 },
- { "/dev/pty/m23", 0 },
- { "/dev/pty/m24", 0 },
- { "/dev/pty/m25", 0 },
- { "/dev/pty/m26", 0 },
- { "/dev/pty/m27", 0 },
- { "/dev/pty/m28", 0 },
- { "/dev/pty/m29", 0 },
- { "/dev/pty/m30", 0 },
- { "/dev/pty/m31", 0 },
- { "/dev/pty/m32", 0 },
- { "/dev/pty/m33", 0 },
- { "/dev/pty/m34", 0 },
- { "/dev/pty/m35", 0 },
- { "/dev/pty/m36", 0 },
- { "/dev/pty/m37", 0 },
- { "/dev/pty/m38", 0 },
- { "/dev/pty/m39", 0 },
- { "/dev/pty/m40", 0 },
- { "/dev/pty/m41", 0 },
- { "/dev/pty/m42", 0 },
- { "/dev/pty/m43", 0 },
- { "/dev/pty/m44", 0 },
- { "/dev/pty/m45", 0 },
- { "/dev/pty/m46", 0 },
- { "/dev/pty/m47", 0 },
- { "/dev/pty/m48", 0 },
- { "/dev/pty/m49", 0 },
- { "/dev/pty/m50", 0 },
- { "/dev/pty/m51", 0 },
- { "/dev/pty/m52", 0 },
- { "/dev/pty/m53", 0 },
- { "/dev/pty/m54", 0 },
- { "/dev/pty/m55", 0 },
- { "/dev/pty/m56", 0 },
- { "/dev/pty/m57", 0 },
- { "/dev/pty/m58", 0 },
- { "/dev/pty/m59", 0 },
- { "/dev/pty/m60", 0 },
- { "/dev/pty/m61", 0 },
- { "/dev/pty/m62", 0 },
- { "/dev/pty/m63", 0 },
- { "/dev/pty/m64", 0 },
- { "/dev/pty/m65", 0 },
- { "/dev/pty/m66", 0 },
- { "/dev/pty/m67", 0 },
- { "/dev/pty/m68", 0 },
- { "/dev/pty/m69", 0 },
- { "/dev/pty/m70", 0 },
- { "/dev/pty/m71", 0 },
- { "/dev/pty/m72", 0 },
- { "/dev/pty/m73", 0 },
- { "/dev/pty/m74", 0 },
- { "/dev/pty/m75", 0 },
- { "/dev/pty/m76", 0 },
- { "/dev/pty/m77", 0 },
- { "/dev/pty/m78", 0 },
- { "/dev/pty/m79", 0 },
- { "/dev/pty/m80", 0 },
- { "/dev/pty/m81", 0 },
- { "/dev/pty/m82", 0 },
- { "/dev/pty/m83", 0 },
- { "/dev/pty/m84", 0 },
- { "/dev/pty/m85", 0 },
- { "/dev/pty/m86", 0 },
- { "/dev/pty/m87", 0 },
- { "/dev/pty/m88", 0 },
- { "/dev/pty/m89", 0 },
- { "/dev/pty/m90", 0 },
- { "/dev/pty/m91", 0 },
- { "/dev/pty/m92", 0 },
- { "/dev/pty/m93", 0 },
- { "/dev/pty/m94", 0 },
- { "/dev/pty/m95", 0 },
- { "/dev/pty/m96", 0 },
- { "/dev/pty/m97", 0 },
- { "/dev/pty/m98", 0 },
- { "/dev/pty/m99", 0 },
- { "/dev/pty/m100", 0 },
- { "/dev/pty/m101", 0 },
- { "/dev/pty/m102", 0 },
- { "/dev/pty/m103", 0 },
- { "/dev/pty/m104", 0 },
- { "/dev/pty/m105", 0 },
- { "/dev/pty/m106", 0 },
- { "/dev/pty/m107", 0 },
- { "/dev/pty/m108", 0 },
- { "/dev/pty/m109", 0 },
- { "/dev/pty/m110", 0 },
- { "/dev/pty/m111", 0 },
- { "/dev/pty/m112", 0 },
- { "/dev/pty/m113", 0 },
- { "/dev/pty/m114", 0 },
- { "/dev/pty/m115", 0 },
- { "/dev/pty/m116", 0 },
- { "/dev/pty/m117", 0 },
- { "/dev/pty/m118", 0 },
- { "/dev/pty/m119", 0 },
- { "/dev/pty/m120", 0 },
- { "/dev/pty/m121", 0 },
- { "/dev/pty/m122", 0 },
- { "/dev/pty/m123", 0 },
- { "/dev/pty/m124", 0 },
- { "/dev/pty/m125", 0 },
- { "/dev/pty/m126", 0 },
- { "/dev/pty/m127", 0 },
- { "/dev/pty/m128", 0 },
- { "/dev/pty/m129", 0 },
- { "/dev/pty/m130", 0 },
- { "/dev/pty/m131", 0 },
- { "/dev/pty/m132", 0 },
- { "/dev/pty/m133", 0 },
- { "/dev/pty/m134", 0 },
- { "/dev/pty/m135", 0 },
- { "/dev/pty/m136", 0 },
- { "/dev/pty/m137", 0 },
- { "/dev/pty/m138", 0 },
- { "/dev/pty/m139", 0 },
- { "/dev/pty/m140", 0 },
- { "/dev/pty/m141", 0 },
- { "/dev/pty/m142", 0 },
- { "/dev/pty/m143", 0 },
- { "/dev/pty/m144", 0 },
- { "/dev/pty/m145", 0 },
- { "/dev/pty/m146", 0 },
- { "/dev/pty/m147", 0 },
- { "/dev/pty/m148", 0 },
- { "/dev/pty/m149", 0 },
- { "/dev/pty/m150", 0 },
- { "/dev/pty/m151", 0 },
- { "/dev/pty/m152", 0 },
- { "/dev/pty/m153", 0 },
- { "/dev/pty/m154", 0 },
- { "/dev/pty/m155", 0 },
- { "/dev/pty/m156", 0 },
- { "/dev/pty/m157", 0 },
- { "/dev/pty/m158", 0 },
- { "/dev/pty/m159", 0 },
- { "/dev/pty/m160", 0 },
- { "/dev/pty/m161", 0 },
- { "/dev/pty/m162", 0 },
- { "/dev/pty/m163", 0 },
- { "/dev/pty/m164", 0 },
- { "/dev/pty/m165", 0 },
- { "/dev/pty/m166", 0 },
- { "/dev/pty/m167", 0 },
- { "/dev/pty/m168", 0 },
- { "/dev/pty/m169", 0 },
- { "/dev/pty/m170", 0 },
- { "/dev/pty/m171", 0 },
- { "/dev/pty/m172", 0 },
- { "/dev/pty/m173", 0 },
- { "/dev/pty/m174", 0 },
- { "/dev/pty/m175", 0 },
- { "/dev/pty/m176", 0 },
- { "/dev/pty/m177", 0 },
- { "/dev/pty/m178", 0 },
- { "/dev/pty/m179", 0 },
- { "/dev/pty/m180", 0 },
- { "/dev/pty/m181", 0 },
- { "/dev/pty/m182", 0 },
- { "/dev/pty/m183", 0 },
- { "/dev/pty/m184", 0 },
- { "/dev/pty/m185", 0 },
- { "/dev/pty/m186", 0 },
- { "/dev/pty/m187", 0 },
- { "/dev/pty/m188", 0 },
- { "/dev/pty/m189", 0 },
- { "/dev/pty/m190", 0 },
- { "/dev/pty/m191", 0 },
- { "/dev/pty/m192", 0 },
- { "/dev/pty/m193", 0 },
- { "/dev/pty/m194", 0 },
- { "/dev/pty/m195", 0 },
- { "/dev/pty/m196", 0 },
- { "/dev/pty/m197", 0 },
- { "/dev/pty/m198", 0 },
- { "/dev/pty/m199", 0 },
- { "/dev/pty/m200", 0 },
- { "/dev/pty/m201", 0 },
- { "/dev/pty/m202", 0 },
- { "/dev/pty/m203", 0 },
- { "/dev/pty/m204", 0 },
- { "/dev/pty/m205", 0 },
- { "/dev/pty/m206", 0 },
- { "/dev/pty/m207", 0 },
- { "/dev/pty/m208", 0 },
- { "/dev/pty/m209", 0 },
- { "/dev/pty/m210", 0 },
- { "/dev/pty/m211", 0 },
- { "/dev/pty/m212", 0 },
- { "/dev/pty/m213", 0 },
- { "/dev/pty/m214", 0 },
- { "/dev/pty/m215", 0 },
- { "/dev/pty/m216", 0 },
- { "/dev/pty/m217", 0 },
- { "/dev/pty/m218", 0 },
- { "/dev/pty/m219", 0 },
- { "/dev/pty/m220", 0 },
- { "/dev/pty/m221", 0 },
- { "/dev/pty/m222", 0 },
- { "/dev/pty/m223", 0 },
- { "/dev/pty/m224", 0 },
- { "/dev/pty/m225", 0 },
- { "/dev/pty/m226", 0 },
- { "/dev/pty/m227", 0 },
- { "/dev/pty/m228", 0 },
- { "/dev/pty/m229", 0 },
- { "/dev/pty/m230", 0 },
- { "/dev/pty/m231", 0 },
- { "/dev/pty/m232", 0 },
- { "/dev/pty/m233", 0 },
- { "/dev/pty/m234", 0 },
- { "/dev/pty/m235", 0 },
- { "/dev/pty/m236", 0 },
- { "/dev/pty/m237", 0 },
- { "/dev/pty/m238", 0 },
- { "/dev/pty/m239", 0 },
- { "/dev/pty/m240", 0 },
- { "/dev/pty/m241", 0 },
- { "/dev/pty/m242", 0 },
- { "/dev/pty/m243", 0 },
- { "/dev/pty/m244", 0 },
- { "/dev/pty/m245", 0 },
- { "/dev/pty/m246", 0 },
- { "/dev/pty/m247", 0 },
- { "/dev/pty/m248", 0 },
- { "/dev/pty/m249", 0 },
- { "/dev/pty/m250", 0 },
- { "/dev/pty/m251", 0 },
- { "/dev/pty/m252", 0 },
- { "/dev/pty/m253", 0 },
- { "/dev/pty/m254", 0 },
- { "/dev/pty/m255", 0 },
- { "/dev/pts", 0 },
- { "/dev/pts/0", 0 },
- { "/dev/pts/1", 0 },
- { "/dev/pts/2", 0 },
- { "/dev/pts/3", 0 },
- { "/dev/pts/4", 0 },
- { "/dev/pts/5", 0 },
- { "/dev/pts/6", 0 },
- { "/dev/pts/7", 0 },
- { "/dev/vcc", 0 },
- { "/dev/vcc/0", 0 },
- { "/dev/vcc/a", 0 },
- { "/dev/vcc/1", 0 },
- { "/dev/vcc/a1", 0 },
- { "/dev/vcc/2", 0 },
- { "/dev/vcc/a2", 0 },
- { "/dev/vcc/3", 0 },
- { "/dev/vcc/a3", 0 },
- { "/dev/vcc/5", 0 },
- { "/dev/vcc/a5", 0 },
- { "/dev/vcc/4", 0 },
- { "/dev/vcc/a4", 0 },
- { "/dev/vcc/6", 0 },
- { "/dev/vcc/a6", 0 },
- { "/dev/vcc/7", 0 },
- { "/dev/vcc/a7", 0 },
- { "/dev/tts", 0 },
- { "/dev/tts/0", 0 },
- { "/dev/cua", 0 },
- { "/dev/cua/0", 0 },
- { "/dev/ide", 0 },
- { "/dev/ide/host0", 0 },
- { "/dev/ide/host0/bus0", 0 },
- { "/dev/ide/host0/bus0/target0", 0 },
- { "/dev/ide/host0/bus0/target0/lun0", 0 },
- { "/dev/ide/host0/bus0/target0/lun0/disc", 0 },
- { "/dev/ide/host0/bus0/target0/lun0/part1", 0 },
- { "/dev/ide/host0/bus0/target0/lun0/part2", 0 },
- { "/dev/ide/host0/bus0/target0/lun0/part3", 0 },
- { "/dev/ide/host0/bus0/target0/lun0/part4", 0 },
- { "/dev/ide/host0/bus0/target0/lun0/part5", 0 },
- { "/dev/ide/host0/bus0/target0/lun0/part6", 0 },
- { "/dev/ide/host0/bus0/target0/lun0/part7", 0 },
- { "/dev/ide/host0/bus0/target0/lun0/part8", 0 },
- { "/dev/ide/host0/bus0/target1", 0 },
- { "/dev/ide/host0/bus0/target1/lun0", 0 },
- { "/dev/ide/host0/bus0/target1/lun0/disc", 0 },
- { "/dev/ide/host0/bus0/target1/lun0/part1", 0 },
- { "/dev/ide/host0/bus1", 0 },
- { "/dev/ide/host0/bus1/target0", 0 },
- { "/dev/ide/host0/bus1/target0/lun0", 0 },
- { "/dev/ide/host0/bus1/target0/lun0/disc", 0 },
- { "/dev/ide/host0/bus1/target0/lun0/part1", 0 },
- { "/dev/ide/host0/bus1/target1", 0 },
- { "/dev/ide/host0/bus1/target1/lun0", 0 },
- { "/dev/discs", 0 },
- { "/dev/discs/disc0", 0 },
- { "/dev/discs/disc1", 0 },
- { "/dev/discs/disc2", 0 },
- { "/dev/floppy", 0 },
- { "/dev/floppy/0u1440", 0 },
- { "/dev/floppy/0u1680", 0 },
- { "/dev/floppy/0u1722", 0 },
- { "/dev/floppy/0u1743", 0 },
- { "/dev/floppy/0u1760", 0 },
- { "/dev/floppy/0u1920", 0 },
- { "/dev/floppy/0u1840", 0 },
- { "/dev/floppy/0u1600", 0 },
- { "/dev/floppy/0u360", 0 },
- { "/dev/floppy/0u720", 0 },
- { "/dev/floppy/0u820", 0 },
- { "/dev/floppy/0u830", 0 },
- { "/dev/floppy/0u1040", 0 },
- { "/dev/floppy/0u1120", 0 },
- { "/dev/floppy/0u800", 0 },
- { "/dev/floppy/0", 0 },
- { "/dev/loop", 0 },
- { "/dev/loop/0", 1 },
- { "/dev/loop/1", 1 },
- { "/dev/loop/2", 1 },
- { "/dev/loop/3", 1 },
- { "/dev/loop/4", 1 },
- { "/dev/loop/5", 1 },
- { "/dev/loop/6", 1 },
- { "/dev/loop/7", 1 },
- { "/dev/cdroms", 0 },
- { "/dev/sound", 0 },
- { "/dev/sound/dsp", 0 },
- { "/dev/sound/dsp1", 0 },
- { "/dev/sound/mixer", 0 },
- { "/dev/sound/midi", 0 },
- { "/dev/usb", 0 },
- { "/dev/root", 0 },
- { "/dev/initctl", 0 },
- { "/dev/xconsole", 0 },
- { "/dev/fd", 0 },
- { "/dev/stdin", 0 },
- { "/dev/stdout", 0 },
- { "/dev/stderr", 0 },
- { "/dev/route", 0 },
- { "/dev/skip", 0 },
- { "/dev/USERSOCK", 0 },
- { "/dev/fwmonitor", 0 },
- { "/dev/ARPD", 0 },
- { "/dev/ROUTE6", 0 },
- { "/dev/IP6_FW", 0 },
- { "/dev/tap0", 0 },
- { "/dev/tap1", 0 },
- { "/dev/tap2", 0 },
- { "/dev/tap3", 0 },
- { "/dev/tap4", 0 },
- { "/dev/tap5", 0 },
- { "/dev/tap6", 0 },
- { "/dev/tap7", 0 },
- { "/dev/tap8", 0 },
- { "/dev/tap9", 0 },
- { "/dev/tap10", 0 },
- { "/dev/tap11", 0 },
- { "/dev/tap12", 0 },
- { "/dev/tap13", 0 },
- { "/dev/tap14", 0 },
- { "/dev/tap15", 0 },
- { "/dev/tty1", 0 },
- { "/dev/tty2", 0 },
- { "/dev/tty3", 0 },
- { "/dev/tty4", 0 },
- { "/dev/tty5", 0 },
- { "/dev/tty6", 0 },
- { "/dev/tty7", 0 },
- { "/dev/tty8", 0 },
- { "/dev/tty9", 0 },
- { "/dev/tty10", 0 },
- { "/dev/tty11", 0 },
- { "/dev/tty12", 0 },
- { "/dev/tty13", 0 },
- { "/dev/tty14", 0 },
- { "/dev/tty15", 0 },
- { "/dev/tty16", 0 },
- { "/dev/tty17", 0 },
- { "/dev/tty18", 0 },
- { "/dev/tty19", 0 },
- { "/dev/tty20", 0 },
- { "/dev/tty21", 0 },
- { "/dev/tty22", 0 },
- { "/dev/tty23", 0 },
- { "/dev/tty24", 0 },
- { "/dev/tty25", 0 },
- { "/dev/tty26", 0 },
- { "/dev/tty27", 0 },
- { "/dev/tty28", 0 },
- { "/dev/tty29", 0 },
- { "/dev/tty30", 0 },
- { "/dev/tty31", 0 },
- { "/dev/tty32", 0 },
- { "/dev/tty33", 0 },
- { "/dev/tty34", 0 },
- { "/dev/tty35", 0 },
- { "/dev/tty36", 0 },
- { "/dev/tty37", 0 },
- { "/dev/tty38", 0 },
- { "/dev/tty39", 0 },
- { "/dev/tty40", 0 },
- { "/dev/tty41", 0 },
- { "/dev/tty42", 0 },
- { "/dev/tty43", 0 },
- { "/dev/tty44", 0 },
- { "/dev/tty45", 0 },
- { "/dev/tty46", 0 },
- { "/dev/tty47", 0 },
- { "/dev/tty48", 0 },
- { "/dev/tty49", 0 },
- { "/dev/tty50", 0 },
- { "/dev/tty51", 0 },
- { "/dev/tty52", 0 },
- { "/dev/tty53", 0 },
- { "/dev/tty54", 0 },
- { "/dev/tty55", 0 },
- { "/dev/tty56", 0 },
- { "/dev/tty57", 0 },
- { "/dev/tty58", 0 },
- { "/dev/tty59", 0 },
- { "/dev/tty60", 0 },
- { "/dev/tty61", 0 },
- { "/dev/tty62", 0 },
- { "/dev/tty63", 0 },
- { "/dev/tty0", 0 },
- { "/dev/psaux", 0 },
- { "/dev/ptyp0", 0 },
- { "/dev/ptyp1", 0 },
- { "/dev/ptyp2", 0 },
- { "/dev/ptyp3", 0 },
- { "/dev/ptyp4", 0 },
- { "/dev/ptyp5", 0 },
- { "/dev/ptyp6", 0 },
- { "/dev/ptyp7", 0 },
- { "/dev/ptyp8", 0 },
- { "/dev/ptyp9", 0 },
- { "/dev/ptypa", 0 },
- { "/dev/ptypb", 0 },
- { "/dev/ptypc", 0 },
- { "/dev/ptypd", 0 },
- { "/dev/ptype", 0 },
- { "/dev/ptypf", 0 },
- { "/dev/ptyq0", 0 },
- { "/dev/ptyq1", 0 },
- { "/dev/ptyq2", 0 },
- { "/dev/ptyq3", 0 },
- { "/dev/ptyq4", 0 },
- { "/dev/ptyq5", 0 },
- { "/dev/ptyq6", 0 },
- { "/dev/ptyq7", 0 },
- { "/dev/ptyq8", 0 },
- { "/dev/ptyq9", 0 },
- { "/dev/ptyqa", 0 },
- { "/dev/ptyqb", 0 },
- { "/dev/ptyqc", 0 },
- { "/dev/ptyqd", 0 },
- { "/dev/ptyqe", 0 },
- { "/dev/ptyqf", 0 },
- { "/dev/ptyr0", 0 },
- { "/dev/ptyr1", 0 },
- { "/dev/ptyr2", 0 },
- { "/dev/ptyr3", 0 },
- { "/dev/ptyr4", 0 },
- { "/dev/ptyr5", 0 },
- { "/dev/ptyr6", 0 },
- { "/dev/ptyr7", 0 },
- { "/dev/ptyr8", 0 },
- { "/dev/ptyr9", 0 },
- { "/dev/ptyra", 0 },
- { "/dev/ptyrb", 0 },
- { "/dev/ptyrc", 0 },
- { "/dev/ptyrd", 0 },
- { "/dev/ptyre", 0 },
- { "/dev/ptyrf", 0 },
- { "/dev/ptys0", 0 },
- { "/dev/ptys1", 0 },
- { "/dev/ptys2", 0 },
- { "/dev/ptys3", 0 },
- { "/dev/ptys4", 0 },
- { "/dev/ptys5", 0 },
- { "/dev/ptys6", 0 },
- { "/dev/ptys7", 0 },
- { "/dev/ptys8", 0 },
- { "/dev/ptys9", 0 },
- { "/dev/ptysa", 0 },
- { "/dev/ptysb", 0 },
- { "/dev/ptysc", 0 },
- { "/dev/ptysd", 0 },
- { "/dev/ptyse", 0 },
- { "/dev/ptysf", 0 },
- { "/dev/ptyt0", 0 },
- { "/dev/ptyt1", 0 },
- { "/dev/ptyt2", 0 },
- { "/dev/ptyt3", 0 },
- { "/dev/ptyt4", 0 },
- { "/dev/ptyt5", 0 },
- { "/dev/ptyt6", 0 },
- { "/dev/ptyt7", 0 },
- { "/dev/ptyt8", 0 },
- { "/dev/ptyt9", 0 },
- { "/dev/ptyta", 0 },
- { "/dev/ptytb", 0 },
- { "/dev/ptytc", 0 },
- { "/dev/ptytd", 0 },
- { "/dev/ptyte", 0 },
- { "/dev/ptytf", 0 },
- { "/dev/ptyu0", 0 },
- { "/dev/ptyu1", 0 },
- { "/dev/ptyu2", 0 },
- { "/dev/ptyu3", 0 },
- { "/dev/ptyu4", 0 },
- { "/dev/ptyu5", 0 },
- { "/dev/ptyu6", 0 },
- { "/dev/ptyu7", 0 },
- { "/dev/ptyu8", 0 },
- { "/dev/ptyu9", 0 },
- { "/dev/ptyua", 0 },
- { "/dev/ptyub", 0 },
- { "/dev/ptyuc", 0 },
- { "/dev/ptyud", 0 },
- { "/dev/ptyue", 0 },
- { "/dev/ptyuf", 0 },
- { "/dev/ptyv0", 0 },
- { "/dev/ptyv1", 0 },
- { "/dev/ptyv2", 0 },
- { "/dev/ptyv3", 0 },
- { "/dev/ptyv4", 0 },
- { "/dev/ptyv5", 0 },
- { "/dev/ptyv6", 0 },
- { "/dev/ptyv7", 0 },
- { "/dev/ptyv8", 0 },
- { "/dev/ptyv9", 0 },
- { "/dev/ptyva", 0 },
- { "/dev/ptyvb", 0 },
- { "/dev/ptyvc", 0 },
- { "/dev/ptyvd", 0 },
- { "/dev/ptyve", 0 },
- { "/dev/ptyvf", 0 },
- { "/dev/ptyw0", 0 },
- { "/dev/ptyw1", 0 },
- { "/dev/ptyw2", 0 },
- { "/dev/ptyw3", 0 },
- { "/dev/ptyw4", 0 },
- { "/dev/ptyw5", 0 },
- { "/dev/ptyw6", 0 },
- { "/dev/ptyw7", 0 },
- { "/dev/ptyw8", 0 },
- { "/dev/ptyw9", 0 },
- { "/dev/ptywa", 0 },
- { "/dev/ptywb", 0 },
- { "/dev/ptywc", 0 },
- { "/dev/ptywd", 0 },
- { "/dev/ptywe", 0 },
- { "/dev/ptywf", 0 },
- { "/dev/ptyx0", 0 },
- { "/dev/ptyx1", 0 },
- { "/dev/ptyx2", 0 },
- { "/dev/ptyx3", 0 },
- { "/dev/ptyx4", 0 },
- { "/dev/ptyx5", 0 },
- { "/dev/ptyx6", 0 },
- { "/dev/ptyx7", 0 },
- { "/dev/ptyx8", 0 },
- { "/dev/ptyx9", 0 },
- { "/dev/ptyxa", 0 },
- { "/dev/ptyxb", 0 },
- { "/dev/ptyxc", 0 },
- { "/dev/ptyxd", 0 },
- { "/dev/ptyxe", 0 },
- { "/dev/ptyxf", 0 },
- { "/dev/ptyy0", 0 },
- { "/dev/ptyy1", 0 },
- { "/dev/ptyy2", 0 },
- { "/dev/ptyy3", 0 },
- { "/dev/ptyy4", 0 },
- { "/dev/ptyy5", 0 },
- { "/dev/ptyy6", 0 },
- { "/dev/ptyy7", 0 },
- { "/dev/ptyy8", 0 },
- { "/dev/ptyy9", 0 },
- { "/dev/ptyya", 0 },
- { "/dev/ptyyb", 0 },
- { "/dev/ptyyc", 0 },
- { "/dev/ptyyd", 0 },
- { "/dev/ptyye", 0 },
- { "/dev/ptyyf", 0 },
- { "/dev/ptyz0", 0 },
- { "/dev/ptyz1", 0 },
- { "/dev/ptyz2", 0 },
- { "/dev/ptyz3", 0 },
- { "/dev/ptyz4", 0 },
- { "/dev/ptyz5", 0 },
- { "/dev/ptyz6", 0 },
- { "/dev/ptyz7", 0 },
- { "/dev/ptyz8", 0 },
- { "/dev/ptyz9", 0 },
- { "/dev/ptyza", 0 },
- { "/dev/ptyzb", 0 },
- { "/dev/ptyzc", 0 },
- { "/dev/ptyzd", 0 },
- { "/dev/ptyze", 0 },
- { "/dev/ptyzf", 0 },
- { "/dev/ptya0", 0 },
- { "/dev/ptya1", 0 },
- { "/dev/ptya2", 0 },
- { "/dev/ptya3", 0 },
- { "/dev/ptya4", 0 },
- { "/dev/ptya5", 0 },
- { "/dev/ptya6", 0 },
- { "/dev/ptya7", 0 },
- { "/dev/ptya8", 0 },
- { "/dev/ptya9", 0 },
- { "/dev/ptyaa", 0 },
- { "/dev/ptyab", 0 },
- { "/dev/ptyac", 0 },
- { "/dev/ptyad", 0 },
- { "/dev/ptyae", 0 },
- { "/dev/ptyaf", 0 },
- { "/dev/ptyb0", 0 },
- { "/dev/ptyb1", 0 },
- { "/dev/ptyb2", 0 },
- { "/dev/ptyb3", 0 },
- { "/dev/ptyb4", 0 },
- { "/dev/ptyb5", 0 },
- { "/dev/ptyb6", 0 },
- { "/dev/ptyb7", 0 },
- { "/dev/ptyb8", 0 },
- { "/dev/ptyb9", 0 },
- { "/dev/ptyba", 0 },
- { "/dev/ptybb", 0 },
- { "/dev/ptybc", 0 },
- { "/dev/ptybd", 0 },
- { "/dev/ptybe", 0 },
- { "/dev/ptybf", 0 },
- { "/dev/ptyc0", 0 },
- { "/dev/ptyc1", 0 },
- { "/dev/ptyc2", 0 },
- { "/dev/ptyc3", 0 },
- { "/dev/ptyc4", 0 },
- { "/dev/ptyc5", 0 },
- { "/dev/ptyc6", 0 },
- { "/dev/ptyc7", 0 },
- { "/dev/ptyc8", 0 },
- { "/dev/ptyc9", 0 },
- { "/dev/ptyca", 0 },
- { "/dev/ptycb", 0 },
- { "/dev/ptycc", 0 },
- { "/dev/ptycd", 0 },
- { "/dev/ptyce", 0 },
- { "/dev/ptycf", 0 },
- { "/dev/ptyd0", 0 },
- { "/dev/ptyd1", 0 },
- { "/dev/ptyd2", 0 },
- { "/dev/ptyd3", 0 },
- { "/dev/ptyd4", 0 },
- { "/dev/ptyd5", 0 },
- { "/dev/ptyd6", 0 },
- { "/dev/ptyd7", 0 },
- { "/dev/ptyd8", 0 },
- { "/dev/ptyd9", 0 },
- { "/dev/ptyda", 0 },
- { "/dev/ptydb", 0 },
- { "/dev/ptydc", 0 },
- { "/dev/ptydd", 0 },
- { "/dev/ptyde", 0 },
- { "/dev/ptydf", 0 },
- { "/dev/ptye0", 0 },
- { "/dev/ptye1", 0 },
- { "/dev/ptye2", 0 },
- { "/dev/ptye3", 0 },
- { "/dev/ptye4", 0 },
- { "/dev/ptye5", 0 },
- { "/dev/ptye6", 0 },
- { "/dev/ptye7", 0 },
- { "/dev/ptye8", 0 },
- { "/dev/ptye9", 0 },
- { "/dev/ptyea", 0 },
- { "/dev/ptyeb", 0 },
- { "/dev/ptyec", 0 },
- { "/dev/ptyed", 0 },
- { "/dev/ptyee", 0 },
- { "/dev/ptyef", 0 },
- { "/dev/vcs", 0 },
- { "/dev/vcsa", 0 },
- { "/dev/vcs1", 0 },
- { "/dev/vcsa1", 0 },
- { "/dev/ttyS0", 0 },
- { "/dev/cua0", 0 },
- { "/dev/hda", 0 },
- { "/dev/hda1", 2 },
- { "/dev/hda2", 2 },
- { "/dev/hda3", 2 },
- { "/dev/hda4", 2 },
- { "/dev/hda5", 2 },
- { "/dev/hda6", 0 },
- { "/dev/hda7", 0 },
- { "/dev/hda8", 0 },
- { "/dev/hdb", 0 },
- { "/dev/hdb1", 2 },
- { "/dev/hdc", 0 },
- { "/dev/hdc1", 2 },
- { "/dev/fd0u1440", 0 },
- { "/dev/fd0u1680", 0 },
- { "/dev/fd0u1722", 0 },
- { "/dev/fd0u1743", 0 },
- { "/dev/fd0u1760", 0 },
- { "/dev/fd0u1920", 0 },
- { "/dev/fd0u1840", 0 },
- { "/dev/fd0u1600", 0 },
- { "/dev/fd0u360", 0 },
- { "/dev/fd0u720", 0 },
- { "/dev/fd0u820", 0 },
- { "/dev/fd0u830", 0 },
- { "/dev/fd0u1040", 0 },
- { "/dev/fd0u1120", 0 },
- { "/dev/fd0u800", 0 },
- { "/dev/fd0", 0 },
- { "/dev/loop0", 0 },
- { "/dev/loop1", 0 },
- { "/dev/loop2", 0 },
- { "/dev/loop3", 0 },
- { "/dev/loop4", 0 },
- { "/dev/loop5", 0 },
- { "/dev/loop6", 0 },
- { "/dev/loop7", 0 },
- { "/dev/dsp", 0 },
- { "/dev/dsp1", 0 },
- { "/dev/mixer", 0 },
- { "/dev/midi", 0 },
- { "/dev/lvm", 0 },
- { "/dev/vg0", 0 },
- { "/dev/vg0/group", 0 },
- { "/dev/vg0/packages", 0 },
- { "/dev/vg0/photos", 0 },
- { "/dev/vg0/music", 0 },
- { "/dev/log", 0 },
- { "/dev/MAKEDEV", 0 },
- { "/dev/printer", 0 },
- { "/dev/vcs2", 0 },
- { "/dev/vcsa2", 0 },
- { "/dev/vcs3", 0 },
- { "/dev/vcsa3", 0 },
- { "/dev/vcs5", 0 },
- { "/dev/vcsa5", 0 },
- { "/dev/vcs4", 0 },
- { "/dev/vcsa4", 0 },
- { "/dev/vcs6", 0 },
- { "/dev/vcsa6", 0 },
- { "/dev/nvidia0", 0 },
- { "/dev/nvidia1", 0 },
- { "/dev/nvidia2", 0 },
- { "/dev/nvidia3", 0 },
- { "/dev/nvidiactl", 0 },
- { "/dev/vcs7", 0 },
- { "/dev/vcsa7", 0 },
- { NULL, 0 }
-};
diff --git a/test/unit/matcher_t.c b/test/unit/matcher_t.c
deleted file mode 100644
index f7fac97..0000000
--- a/test/unit/matcher_t.c
+++ /dev/null
@@ -1,70 +0,0 @@
-/*
- * Copyright (C) 2001-2004 Sistina Software, Inc. All rights reserved.
- * Copyright (C) 2004-2010 Red Hat, Inc. All rights reserved.
- *
- * This file is part of LVM2.
- *
- * This copyrighted material is made available to anyone wishing to use,
- * modify, copy, or redistribute it subject to the terms and conditions
- * of the GNU General Public License v.2.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
- */
-
-#include "units.h"
-
-#include "matcher_data.h"
-
-static struct dm_pool *mem = NULL;
-
-int regex_init(void) {
- mem = dm_pool_create("bitset test", 1024);
- return mem == NULL;
-}
-
-int regex_fini(void) {
- dm_pool_destroy(mem);
- return 0;
-}
-
-static struct dm_regex *make_scanner(const char **rx)
-{
- struct dm_regex *scanner;
- int nrx = 0;
- for (; rx[nrx]; ++nrx);
-
- scanner = dm_regex_create(mem, rx, nrx);
- CU_ASSERT_FATAL(scanner != NULL);
- return scanner;
-}
-
-static void test_fingerprints(void) {
- struct dm_regex *scanner;
-
- scanner = make_scanner(dev_patterns);
- CU_ASSERT_EQUAL(dm_regex_fingerprint(scanner), 0x7f556c09);
-
- scanner = make_scanner(random_patterns);
- CU_ASSERT_EQUAL(dm_regex_fingerprint(scanner), 0x9f11076c);
-}
-
-static void test_matching(void) {
- struct dm_regex *scanner;
- int i;
-
- scanner = make_scanner(dev_patterns);
- for (i = 0; devices[i].str; ++i)
- CU_ASSERT_EQUAL(dm_regex_match(scanner, devices[i].str), devices[i].expected - 1);
-
- scanner = make_scanner(nonprint_patterns);
- for (i = 0; nonprint[i].str; ++i)
- CU_ASSERT_EQUAL(dm_regex_match(scanner, nonprint[i].str), nonprint[i].expected - 1);
-}
-
-CU_TestInfo regex_list[] = {
- { (char*)"fingerprints", test_fingerprints },
- { (char*)"matching", test_matching },
- CU_TEST_INFO_NULL
-};
diff --git a/test/unit/percent_t.c b/test/unit/percent_t.c
deleted file mode 100644
index 650f381..0000000
--- a/test/unit/percent_t.c
+++ /dev/null
@@ -1,101 +0,0 @@
-/*
- * Copyright (C) 2017 Red Hat, Inc. All rights reserved.
- *
- * This file is part of LVM2.
- *
- * This copyrighted material is made available to anyone wishing to use,
- * modify, copy, or redistribute it subject to the terms and conditions
- * of the GNU General Public License v.2.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
- */
-
-#include "units.h"
-
-#include <stdio.h>
-#include <string.h>
-
-int percent_init(void)
-{
- return 0;
-}
-
-int percent_fini(void)
-{
- return 0;
-}
-
-static void test_percent_100(void)
-{
- char buf[32];
-
- /* Check 100% is shown only for DM_PERCENT_100*/
- dm_percent_t p_100 = dm_make_percent(100, 100);
- dm_percent_t p1_100 = dm_make_percent(100000, 100000);
- dm_percent_t n_100 = dm_make_percent(999999, 1000000);
-
- CU_ASSERT_EQUAL(p_100, DM_PERCENT_100);
- CU_ASSERT_EQUAL(p1_100, DM_PERCENT_100);
- CU_ASSERT_NOT_EQUAL(n_100, DM_PERCENT_100);
-
- dm_snprintf(buf, sizeof(buf), "%.2f", dm_percent_to_float(p_100));
- CU_ASSERT_EQUAL(strcmp(buf, "100.00"), 0);
-
- dm_snprintf(buf, sizeof(buf), "%.2f", dm_percent_to_float(p1_100));
- CU_ASSERT_EQUAL(strcmp(buf, "100.00"), 0);
-
- dm_snprintf(buf, sizeof(buf), "%.2f", dm_percent_to_float(n_100));
- CU_ASSERT_NOT_EQUAL(strcmp(buf, "99.99"), 0); /* Would like to gett */
-
- dm_snprintf(buf, sizeof(buf), "%.2f", dm_percent_to_round_float(n_100, 2));
- CU_ASSERT_EQUAL(strcmp(buf, "99.99"), 0);
-
- dm_snprintf(buf, sizeof(buf), "%.3f", dm_percent_to_round_float(n_100, 3));
- CU_ASSERT_EQUAL(strcmp(buf, "99.999"), 0);
-
- dm_snprintf(buf, sizeof(buf), "%.4f", dm_percent_to_round_float(n_100, 4));
- CU_ASSERT_EQUAL(strcmp(buf, "99.9999"), 0);
-
- dm_snprintf(buf, sizeof(buf), "%d", (int)dm_percent_to_round_float(n_100, 0));
- CU_ASSERT_EQUAL(strcmp(buf, "99"), 0);
-}
-
-static void test_percent_0(void)
-{
- char buf[32];
-
- /* Check 0% is shown only for DM_PERCENT_0 */
- dm_percent_t p_0 = dm_make_percent(0, 100);
- dm_percent_t p1_0 = dm_make_percent(0, 100000);
- dm_percent_t n_0 = dm_make_percent(1, 1000000);
-
- CU_ASSERT_EQUAL(p_0, DM_PERCENT_0);
- CU_ASSERT_EQUAL(p1_0, DM_PERCENT_0);
- CU_ASSERT_NOT_EQUAL(n_0, DM_PERCENT_0);
-
- dm_snprintf(buf, sizeof(buf), "%.2f", dm_percent_to_float(p_0));
- CU_ASSERT_EQUAL(strcmp(buf, "0.00"), 0);
-
- dm_snprintf(buf, sizeof(buf), "%.2f", dm_percent_to_float(p1_0));
- CU_ASSERT_EQUAL(strcmp(buf, "0.00"), 0);
-
- dm_snprintf(buf, sizeof(buf), "%.2f", dm_percent_to_float(n_0));
- CU_ASSERT_NOT_EQUAL(strcmp(buf, "0.01"), 0);
-
- dm_snprintf(buf, sizeof(buf), "%.2f", dm_percent_to_round_float(n_0, 2));
- CU_ASSERT_EQUAL(strcmp(buf, "0.01"), 0);
-
- dm_snprintf(buf, sizeof(buf), "%.3f", dm_percent_to_round_float(n_0, 3));
- CU_ASSERT_EQUAL(strcmp(buf, "0.001"), 0);
-
- dm_snprintf(buf, sizeof(buf), "%d", (int)dm_percent_to_round_float(n_0, 0));
- CU_ASSERT_EQUAL(strcmp(buf, "1"), 0);
-}
-
-CU_TestInfo percent_list[] = {
- { (char*)"percent_100", test_percent_100 },
- { (char*)"percent_0", test_percent_0 },
- CU_TEST_INFO_NULL
-};
diff --git a/test/unit/run.c b/test/unit/run.c
deleted file mode 100644
index 82090ba..0000000
--- a/test/unit/run.c
+++ /dev/null
@@ -1,39 +0,0 @@
-#include "units.h"
-#include <CUnit/Basic.h>
-
-#include <stdio.h>
-#include <stdlib.h>
-
-/* Setup SuiteInfo struct in a compatible way across different CUnit versions */
-/* old version of CUnit has used char* for .pName, so using cast here */
-#define USE(n) { \
- .pName = (char*) #n, \
- .pInitFunc = n##_init, \
- .pCleanupFunc = n##_fini, \
- .pTests = n##_list }
-
-CU_SuiteInfo suites[] = {
- USE(bcache),
- USE(bitset),
- USE(config),
- USE(dmlist),
- USE(dmstatus),
- USE(regex),
- USE(percent),
- USE(string),
- CU_SUITE_INFO_NULL
-};
-
-int main(int argc, char **argv) {
- if (CU_initialize_registry() != CUE_SUCCESS) {
- printf("Initialization of Test Registry failed.\n");
- return CU_get_error();
- }
-
- CU_register_suites(suites);
- CU_basic_set_mode(CU_BRM_VERBOSE);
- CU_basic_run_tests();
- CU_cleanup_registry();
-
- return (CU_get_number_of_failures() != 0);
-}
diff --git a/test/unit/string_t.c b/test/unit/string_t.c
deleted file mode 100644
index 68e39c6..0000000
--- a/test/unit/string_t.c
+++ /dev/null
@@ -1,78 +0,0 @@
-/*
- * Copyright (C) 2012 Red Hat, Inc. All rights reserved.
- *
- * This file is part of LVM2.
- *
- * This copyrighted material is made available to anyone wishing to use,
- * modify, copy, or redistribute it subject to the terms and conditions
- * of the GNU General Public License v.2.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
- */
-
-#include "units.h"
-
-#include <stdio.h>
-#include <string.h>
-
-static struct dm_pool *mem = NULL;
-
-int string_init(void)
-{
- mem = dm_pool_create("string test", 1024);
-
- return (mem == NULL);
-}
-
-int string_fini(void)
-{
- dm_pool_destroy(mem);
-
- return 0;
-}
-
-/* TODO: Add more string unit tests here */
-
-static void test_strncpy(void)
-{
- const char st[] = "1234567890";
- char buf[sizeof(st)];
-
- CU_ASSERT_EQUAL(dm_strncpy(buf, st, sizeof(buf)), 1);
- CU_ASSERT_EQUAL(strcmp(buf, st), 0);
-
- CU_ASSERT_EQUAL(dm_strncpy(buf, st, sizeof(buf) - 1), 0);
- CU_ASSERT_EQUAL(strlen(buf) + 1, sizeof(buf) - 1);
-}
-
-static void test_asprint(void)
-{
- const char st0[] = "";
- const char st1[] = "12345678901";
- const char st2[] = "1234567890123456789012345678901234567890123456789012345678901234567";
- char *buf;
- int a;
-
- a = dm_asprintf(&buf, "%s", st0);
- CU_ASSERT_EQUAL(strcmp(buf, st0), 0);
- CU_ASSERT_EQUAL(a, sizeof(st0));
- free(buf);
-
- a = dm_asprintf(&buf, "%s", st1);
- CU_ASSERT_EQUAL(strcmp(buf, st1), 0);
- CU_ASSERT_EQUAL(a, sizeof(st1));
- free(buf);
-
- a = dm_asprintf(&buf, "%s", st2);
- CU_ASSERT_EQUAL(a, sizeof(st2));
- CU_ASSERT_EQUAL(strcmp(buf, st2), 0);
- free(buf);
-}
-
-CU_TestInfo string_list[] = {
- { (char*)"asprint", test_asprint },
- { (char*)"strncpy", test_strncpy },
- CU_TEST_INFO_NULL
-};
diff --git a/test/unit/units.h b/test/unit/units.h
deleted file mode 100644
index 319e7ce..0000000
--- a/test/unit/units.h
+++ /dev/null
@@ -1,35 +0,0 @@
-/*
- * Copyright (C) 2015-2017 Red Hat, Inc. All rights reserved.
- *
- * This file is part of LVM2.
- *
- * This copyrighted material is made available to anyone wishing to use,
- * modify, copy, or redistribute it subject to the terms and conditions
- * of the GNU General Public License v.2.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
- */
-
-#ifndef _UNITS_H
-#define _UNITS_H
-
-#include "libdevmapper.h"
-#include <CUnit/CUnit.h>
-
-#define DECL(n) \
- extern CU_TestInfo n ## _list[];\
- int n ## _init(void); \
- int n ## _fini(void);
-
-DECL(bcache);
-DECL(bitset);
-DECL(config);
-DECL(dmlist);
-DECL(dmstatus);
-DECL(regex);
-DECL(percent);
-DECL(string);
-
-#endif
diff --git a/unit-test/Makefile.in b/unit-test/Makefile.in
new file mode 100644
index 0000000..5577706
--- /dev/null
+++ b/unit-test/Makefile.in
@@ -0,0 +1,40 @@
+# Copyright (C) 2011-2018 Red Hat, Inc. All rights reserved.
+#
+# This file is part of LVM2.
+#
+# This copyrighted material is made available to anyone wishing to use,
+# modify, copy, or redistribute it subject to the terms and conditions
+# of the GNU General Public License v.2.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software Foundation,
+# Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+
+UNIT_SOURCE=\
+ unit-test/bcache_t.c \
+ unit-test/bitset_t.c \
+ unit-test/config_t.c \
+ unit-test/dmlist_t.c \
+ unit-test/dmstatus_t.c \
+ unit-test/matcher_t.c \
+ unit-test/framework.c \
+ unit-test/percent_t.c \
+ unit-test/run.c \
+ unit-test/string_t.c
+
+UNIT_DEPENDS=$(subst .c,.d,$(UNIT_SOURCE))
+UNIT_OBJECTS=$(UNIT_SOURCE:%.c=%.o)
+CLEAN_TARGETS+=$(UNIT_DEPENDS) $(UNIT_OBJECTS)
+UNIT_LDLIBS += $(LVMINTERNAL_LIBS) -ldevmapper -laio
+
+unit-test/unit-test: $(UNIT_OBJECTS) libdm/libdevmapper.$(LIB_SUFFIX) lib/liblvm-internal.a
+ @echo " [LD] $@"
+ $(Q) $(CC) $(CFLAGS) $(LDFLAGS) $(EXTRA_EXEC_LDFLAGS) -L$(top_builddir)/libdm \
+ -o $@ $(UNIT_OBJECTS) $(UNIT_LDLIBS)
+
+.PHONEY: run-unit-test
+run-unit-test: unit-test/unit-test
+ @echo Running unit tests
+ LD_LIBRARY_PATH=libdm unit-test/unit-test run
+
+-include $(UNIT_DEPENDS)
diff --git a/unit-test/bcache_t.c b/unit-test/bcache_t.c
new file mode 100644
index 0000000..4fe913b
--- /dev/null
+++ b/unit-test/bcache_t.c
@@ -0,0 +1,783 @@
+/*
+ * Copyright (C) 2018 Red Hat, Inc. All rights reserved.
+ *
+ * This file is part of LVM2.
+ *
+ * This copyrighted material is made available to anyone wishing to use,
+ * modify, copy, or redistribute it subject to the terms and conditions
+ * of the GNU General Public License v.2.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+#include <errno.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+
+#include "bcache.h"
+#include "framework.h"
+#include "units.h"
+
+#define SHOW_MOCK_CALLS 0
+
+/*----------------------------------------------------------------
+ * Mock engine
+ *--------------------------------------------------------------*/
+struct mock_engine {
+ struct io_engine e;
+ struct dm_list expected_calls;
+ struct dm_list issued_io;
+ unsigned max_io;
+ sector_t block_size;
+};
+
+enum method {
+ E_DESTROY,
+ E_ISSUE,
+ E_WAIT,
+ E_MAX_IO
+};
+
+struct mock_call {
+ struct dm_list list;
+ enum method m;
+
+ bool match_args;
+ enum dir d;
+ int fd;
+ block_address b;
+ bool issue_r;
+ bool wait_r;
+};
+
+struct mock_io {
+ struct dm_list list;
+ int fd;
+ sector_t sb;
+ sector_t se;
+ void *data;
+ void *context;
+ bool r;
+};
+
+static const char *_show_method(enum method m)
+{
+ switch (m) {
+ case E_DESTROY:
+ return "destroy()";
+ case E_ISSUE:
+ return "issue()";
+ case E_WAIT:
+ return "wait()";
+ case E_MAX_IO:
+ return "max_io()";
+ }
+
+ return "<unknown>";
+}
+
+static void _expect(struct mock_engine *e, enum method m)
+{
+ struct mock_call *mc = malloc(sizeof(*mc));
+ mc->m = m;
+ mc->match_args = false;
+ dm_list_add(&e->expected_calls, &mc->list);
+}
+
+static void _expect_read(struct mock_engine *e, int fd, block_address b)
+{
+ struct mock_call *mc = malloc(sizeof(*mc));
+ mc->m = E_ISSUE;
+ mc->match_args = true;
+ mc->d = DIR_READ;
+ mc->fd = fd;
+ mc->b = b;
+ mc->issue_r = true;
+ mc->wait_r = true;
+ dm_list_add(&e->expected_calls, &mc->list);
+}
+
+static void _expect_write(struct mock_engine *e, int fd, block_address b)
+{
+ struct mock_call *mc = malloc(sizeof(*mc));
+ mc->m = E_ISSUE;
+ mc->match_args = true;
+ mc->d = DIR_WRITE;
+ mc->fd = fd;
+ mc->b = b;
+ mc->issue_r = true;
+ mc->wait_r = true;
+ dm_list_add(&e->expected_calls, &mc->list);
+}
+
+static void _expect_read_bad_issue(struct mock_engine *e, int fd, block_address b)
+{
+ struct mock_call *mc = malloc(sizeof(*mc));
+ mc->m = E_ISSUE;
+ mc->match_args = true;
+ mc->d = DIR_READ;
+ mc->fd = fd;
+ mc->b = b;
+ mc->issue_r = false;
+ mc->wait_r = true;
+ dm_list_add(&e->expected_calls, &mc->list);
+}
+
+static void _expect_write_bad_issue(struct mock_engine *e, int fd, block_address b)
+{
+ struct mock_call *mc = malloc(sizeof(*mc));
+ mc->m = E_ISSUE;
+ mc->match_args = true;
+ mc->d = DIR_WRITE;
+ mc->fd = fd;
+ mc->b = b;
+ mc->issue_r = false;
+ mc->wait_r = true;
+ dm_list_add(&e->expected_calls, &mc->list);
+}
+
+static void _expect_read_bad_wait(struct mock_engine *e, int fd, block_address b)
+{
+ struct mock_call *mc = malloc(sizeof(*mc));
+ mc->m = E_ISSUE;
+ mc->match_args = true;
+ mc->d = DIR_READ;
+ mc->fd = fd;
+ mc->b = b;
+ mc->issue_r = true;
+ mc->wait_r = false;
+ dm_list_add(&e->expected_calls, &mc->list);
+}
+
+static void _expect_write_bad_wait(struct mock_engine *e, int fd, block_address b)
+{
+ struct mock_call *mc = malloc(sizeof(*mc));
+ mc->m = E_ISSUE;
+ mc->match_args = true;
+ mc->d = DIR_WRITE;
+ mc->fd = fd;
+ mc->b = b;
+ mc->issue_r = true;
+ mc->wait_r = false;
+ dm_list_add(&e->expected_calls, &mc->list);
+}
+
+static struct mock_call *_match_pop(struct mock_engine *e, enum method m)
+{
+
+ struct mock_call *mc;
+
+ if (dm_list_empty(&e->expected_calls))
+ test_fail("unexpected call to method %s\n", _show_method(m));
+
+ mc = dm_list_item(e->expected_calls.n, struct mock_call);
+ dm_list_del(&mc->list);
+
+ if (mc->m != m)
+ test_fail("expected %s, but got %s\n", _show_method(mc->m), _show_method(m));
+#if SHOW_MOCK_CALLS
+ else
+ fprintf(stderr, "%s called (expected)\n", _show_method(m));
+#endif
+
+ return mc;
+}
+
+static void _match(struct mock_engine *e, enum method m)
+{
+ free(_match_pop(e, m));
+}
+
+static void _no_outstanding_expectations(struct mock_engine *e)
+{
+ struct mock_call *mc;
+
+ if (!dm_list_empty(&e->expected_calls)) {
+ fprintf(stderr, "unsatisfied expectations:\n");
+ dm_list_iterate_items (mc, &e->expected_calls)
+ fprintf(stderr, " %s\n", _show_method(mc->m));
+ }
+ T_ASSERT(dm_list_empty(&e->expected_calls));
+}
+
+static struct mock_engine *_to_mock(struct io_engine *e)
+{
+ return container_of(e, struct mock_engine, e);
+}
+
+static void _mock_destroy(struct io_engine *e)
+{
+ struct mock_engine *me = _to_mock(e);
+
+ _match(me, E_DESTROY);
+ T_ASSERT(dm_list_empty(&me->issued_io));
+ T_ASSERT(dm_list_empty(&me->expected_calls));
+ free(_to_mock(e));
+}
+
+static bool _mock_issue(struct io_engine *e, enum dir d, int fd,
+ sector_t sb, sector_t se, void *data, void *context)
+{
+ bool r, wait_r;
+ struct mock_io *io;
+ struct mock_call *mc;
+ struct mock_engine *me = _to_mock(e);
+
+ mc = _match_pop(me, E_ISSUE);
+ if (mc->match_args) {
+ T_ASSERT(d == mc->d);
+ T_ASSERT(fd == mc->fd);
+ T_ASSERT(sb == mc->b * me->block_size);
+ T_ASSERT(se == (mc->b + 1) * me->block_size);
+ }
+ r = mc->issue_r;
+ wait_r = mc->wait_r;
+ free(mc);
+
+ if (r) {
+ io = malloc(sizeof(*io));
+ if (!io)
+ abort();
+
+ io->fd = fd;
+ io->sb = sb;
+ io->se = se;
+ io->data = data;
+ io->context = context;
+ io->r = wait_r;
+
+ dm_list_add(&me->issued_io, &io->list);
+ }
+
+ return r;
+}
+
+static bool _mock_wait(struct io_engine *e, io_complete_fn fn)
+{
+ struct mock_io *io;
+ struct mock_engine *me = _to_mock(e);
+ _match(me, E_WAIT);
+
+ // FIXME: provide a way to control how many are completed and whether
+ // they error.
+ T_ASSERT(!dm_list_empty(&me->issued_io));
+ io = dm_list_item(me->issued_io.n, struct mock_io);
+ dm_list_del(&io->list);
+ fn(io->context, io->r ? 0 : -EIO);
+ free(io);
+
+ return true;
+}
+
+static unsigned _mock_max_io(struct io_engine *e)
+{
+ struct mock_engine *me = _to_mock(e);
+ _match(me, E_MAX_IO);
+ return me->max_io;
+}
+
+static struct mock_engine *_mock_create(unsigned max_io, sector_t block_size)
+{
+ struct mock_engine *m = malloc(sizeof(*m));
+
+ m->e.destroy = _mock_destroy;
+ m->e.issue = _mock_issue;
+ m->e.wait = _mock_wait;
+ m->e.max_io = _mock_max_io;
+
+ m->max_io = max_io;
+ m->block_size = block_size;
+ dm_list_init(&m->expected_calls);
+ dm_list_init(&m->issued_io);
+
+ return m;
+}
+
+/*----------------------------------------------------------------
+ * Fixtures
+ *--------------------------------------------------------------*/
+struct fixture {
+ struct mock_engine *me;
+ struct bcache *cache;
+};
+
+static struct fixture *_fixture_init(sector_t block_size, unsigned nr_cache_blocks)
+{
+ struct fixture *f = malloc(sizeof(*f));
+
+ f->me = _mock_create(16, block_size);
+ T_ASSERT(f->me);
+
+ _expect(f->me, E_MAX_IO);
+ f->cache = bcache_create(block_size, nr_cache_blocks, &f->me->e);
+ T_ASSERT(f->cache);
+
+ return f;
+}
+
+static void _fixture_exit(struct fixture *f)
+{
+ _expect(f->me, E_DESTROY);
+ bcache_destroy(f->cache);
+
+ free(f);
+}
+
+static void *_small_fixture_init(void)
+{
+ return _fixture_init(128, 16);
+}
+
+static void _small_fixture_exit(void *context)
+{
+ _fixture_exit(context);
+}
+
+static void *_large_fixture_init(void)
+{
+ return _fixture_init(128, 1024);
+}
+
+static void _large_fixture_exit(void *context)
+{
+ _fixture_exit(context);
+}
+
+/*----------------------------------------------------------------
+ * Tests
+ *--------------------------------------------------------------*/
+#define MEG 2048
+#define SECTOR_SHIFT 9
+
+static void good_create(sector_t block_size, unsigned nr_cache_blocks)
+{
+ struct bcache *cache;
+ struct mock_engine *me = _mock_create(16, 128);
+
+ _expect(me, E_MAX_IO);
+ cache = bcache_create(block_size, nr_cache_blocks, &me->e);
+ T_ASSERT(cache);
+
+ _expect(me, E_DESTROY);
+ bcache_destroy(cache);
+}
+
+static void bad_create(sector_t block_size, unsigned nr_cache_blocks)
+{
+ struct bcache *cache;
+ struct mock_engine *me = _mock_create(16, 128);
+
+ _expect(me, E_MAX_IO);
+ cache = bcache_create(block_size, nr_cache_blocks, &me->e);
+ T_ASSERT(!cache);
+
+ _expect(me, E_DESTROY);
+ me->e.destroy(&me->e);
+}
+
+static void test_create(void *fixture)
+{
+ good_create(8, 16);
+}
+
+static void test_nr_cache_blocks_must_be_positive(void *fixture)
+{
+ bad_create(8, 0);
+}
+
+static void test_block_size_must_be_positive(void *fixture)
+{
+ bad_create(0, 16);
+}
+
+static void test_block_size_must_be_multiple_of_page_size(void *fixture)
+{
+ static unsigned _bad_examples[] = {3, 9, 13, 1025};
+
+ unsigned i;
+
+ for (i = 0; i < DM_ARRAY_SIZE(_bad_examples); i++)
+ bad_create(_bad_examples[i], 16);
+
+ for (i = 1; i < 1000; i++)
+ good_create(i * 8, 16);
+}
+
+static void test_get_triggers_read(void *context)
+{
+ int err;
+ struct fixture *f = context;
+
+ int fd = 17; // arbitrary key
+ struct block *b;
+
+ _expect_read(f->me, fd, 0);
+ _expect(f->me, E_WAIT);
+ T_ASSERT(bcache_get(f->cache, fd, 0, 0, &b, &err));
+ bcache_put(b);
+}
+
+static void test_repeated_reads_are_cached(void *context)
+{
+ int err;
+ struct fixture *f = context;
+
+ int fd = 17; // arbitrary key
+ unsigned i;
+ struct block *b;
+
+ _expect_read(f->me, fd, 0);
+ _expect(f->me, E_WAIT);
+ for (i = 0; i < 100; i++) {
+ T_ASSERT(bcache_get(f->cache, fd, 0, 0, &b, &err));
+ bcache_put(b);
+ }
+}
+
+static void test_block_gets_evicted_with_many_reads(void *context)
+{
+ struct fixture *f = context;
+
+ int err;
+ struct mock_engine *me = f->me;
+ struct bcache *cache = f->cache;
+ const unsigned nr_cache_blocks = 16;
+
+ int fd = 17; // arbitrary key
+ unsigned i;
+ struct block *b;
+
+ for (i = 0; i < nr_cache_blocks; i++) {
+ _expect_read(me, fd, i);
+ _expect(me, E_WAIT);
+ T_ASSERT(bcache_get(cache, fd, i, 0, &b, &err));
+ bcache_put(b);
+ }
+
+ // Not enough cache blocks to hold this one
+ _expect_read(me, fd, nr_cache_blocks);
+ _expect(me, E_WAIT);
+ T_ASSERT(bcache_get(cache, fd, nr_cache_blocks, 0, &b, &err));
+ bcache_put(b);
+
+ // Now if we run through we should find one block has been
+ // evicted. We go backwards because the oldest is normally
+ // evicted first.
+ _expect(me, E_ISSUE);
+ _expect(me, E_WAIT);
+ for (i = nr_cache_blocks; i; i--) {
+ T_ASSERT(bcache_get(cache, fd, i - 1, 0, &b, &err));
+ bcache_put(b);
+ }
+}
+
+static void test_prefetch_issues_a_read(void *context)
+{
+ struct fixture *f = context;
+ struct mock_engine *me = f->me;
+ struct bcache *cache = f->cache;
+ const unsigned nr_cache_blocks = 16;
+
+ int err;
+ int fd = 17; // arbitrary key
+ unsigned i;
+ struct block *b;
+
+ for (i = 0; i < nr_cache_blocks; i++) {
+ // prefetch should not wait
+ _expect_read(me, fd, i);
+ bcache_prefetch(cache, fd, i);
+ }
+
+
+ for (i = 0; i < nr_cache_blocks; i++) {
+ _expect(me, E_WAIT);
+ T_ASSERT(bcache_get(cache, fd, i, 0, &b, &err));
+ bcache_put(b);
+ }
+}
+
+static void test_too_many_prefetches_does_not_trigger_a_wait(void *context)
+{
+ struct fixture *f = context;
+ struct mock_engine *me = f->me;
+ struct bcache *cache = f->cache;
+
+ const unsigned nr_cache_blocks = 16;
+ int fd = 17; // arbitrary key
+ unsigned i;
+
+ for (i = 0; i < 10 * nr_cache_blocks; i++) {
+ // prefetch should not wait
+ if (i < nr_cache_blocks)
+ _expect_read(me, fd, i);
+ bcache_prefetch(cache, fd, i);
+ }
+
+ // Destroy will wait for any in flight IO triggered by prefetches.
+ for (i = 0; i < nr_cache_blocks; i++)
+ _expect(me, E_WAIT);
+}
+
+static void test_dirty_data_gets_written_back(void *context)
+{
+ struct fixture *f = context;
+ struct mock_engine *me = f->me;
+ struct bcache *cache = f->cache;
+
+ int err;
+ int fd = 17; // arbitrary key
+ struct block *b;
+
+ // Expect the read
+ _expect_read(me, fd, 0);
+ _expect(me, E_WAIT);
+ T_ASSERT(bcache_get(cache, fd, 0, GF_DIRTY, &b, &err));
+ bcache_put(b);
+
+ // Expect the write
+ _expect_write(me, fd, 0);
+ _expect(me, E_WAIT);
+}
+
+static void test_zeroed_data_counts_as_dirty(void *context)
+{
+ struct fixture *f = context;
+ struct mock_engine *me = f->me;
+ struct bcache *cache = f->cache;
+
+ int err;
+ int fd = 17; // arbitrary key
+ struct block *b;
+
+ // No read
+ T_ASSERT(bcache_get(cache, fd, 0, GF_ZERO, &b, &err));
+ bcache_put(b);
+
+ // Expect the write
+ _expect_write(me, fd, 0);
+ _expect(me, E_WAIT);
+}
+
+static void test_flush_waits_for_all_dirty(void *context)
+{
+ struct fixture *f = context;
+ struct mock_engine *me = f->me;
+ struct bcache *cache = f->cache;
+
+ const unsigned count = 16;
+ int err;
+ int fd = 17; // arbitrary key
+ unsigned i;
+ struct block *b;
+
+ for (i = 0; i < count; i++) {
+ if (i % 2) {
+ T_ASSERT(bcache_get(cache, fd, i, GF_ZERO, &b, &err));
+ } else {
+ _expect_read(me, fd, i);
+ _expect(me, E_WAIT);
+ T_ASSERT(bcache_get(cache, fd, i, 0, &b, &err));
+ }
+ bcache_put(b);
+ }
+
+ for (i = 0; i < count; i++) {
+ if (i % 2)
+ _expect_write(me, fd, i);
+ }
+
+ for (i = 0; i < count; i++) {
+ if (i % 2)
+ _expect(me, E_WAIT);
+ }
+
+ bcache_flush(cache);
+ _no_outstanding_expectations(me);
+}
+
+static void test_multiple_files(void *context)
+{
+ static int _fds[] = {1, 128, 345, 678, 890};
+
+ int err;
+ struct fixture *f = context;
+ struct mock_engine *me = f->me;
+ struct bcache *cache = f->cache;
+ struct block *b;
+ unsigned i;
+
+ for (i = 0; i < DM_ARRAY_SIZE(_fds); i++) {
+ _expect_read(me, _fds[i], 0);
+ _expect(me, E_WAIT);
+
+ T_ASSERT(bcache_get(cache, _fds[i], 0, 0, &b, &err));
+ bcache_put(b);
+ }
+}
+
+static void test_read_bad_issue(void *context)
+{
+ struct fixture *f = context;
+ struct mock_engine *me = f->me;
+ struct bcache *cache = f->cache;
+ struct block *b;
+ int err;
+
+ _expect_read_bad_issue(me, 17, 0);
+ T_ASSERT(!bcache_get(cache, 17, 0, 0, &b, &err));
+}
+
+static void test_read_bad_issue_intermittent(void *context)
+{
+ struct fixture *f = context;
+ struct mock_engine *me = f->me;
+ struct bcache *cache = f->cache;
+ struct block *b;
+ int fd = 17;
+ int err;
+
+ _expect_read_bad_issue(me, fd, 0);
+ T_ASSERT(!bcache_get(cache, fd, 0, 0, &b, &err));
+
+ _expect_read(me, fd, 0);
+ _expect(me, E_WAIT);
+ T_ASSERT(bcache_get(cache, fd, 0, 0, &b, &err));
+ bcache_put(b);
+}
+
+static void test_read_bad_wait(void *context)
+{
+ struct fixture *f = context;
+ struct mock_engine *me = f->me;
+ struct bcache *cache = f->cache;
+ struct block *b;
+ int fd = 17;
+ int err;
+
+ _expect_read_bad_wait(me, fd, 0);
+ _expect(me, E_WAIT);
+ T_ASSERT(!bcache_get(cache, fd, 0, 0, &b, &err));
+}
+
+static void test_read_bad_wait_intermittent(void *context)
+{
+ struct fixture *f = context;
+ struct mock_engine *me = f->me;
+ struct bcache *cache = f->cache;
+ struct block *b;
+ int fd = 17;
+ int err;
+
+ _expect_read_bad_wait(me, fd, 0);
+ _expect(me, E_WAIT);
+ T_ASSERT(!bcache_get(cache, fd, 0, 0, &b, &err));
+
+ _expect_read(me, fd, 0);
+ _expect(me, E_WAIT);
+ T_ASSERT(bcache_get(cache, fd, 0, 0, &b, &err));
+ bcache_put(b);
+}
+
+static void test_write_bad_issue_stops_flush(void *context)
+{
+ struct fixture *f = context;
+ struct mock_engine *me = f->me;
+ struct bcache *cache = f->cache;
+ struct block *b;
+ int fd = 17;
+ int err;
+
+ T_ASSERT(bcache_get(cache, fd, 0, GF_ZERO, &b, &err));
+ _expect_write_bad_issue(me, fd, 0);
+ bcache_put(b);
+ T_ASSERT(!bcache_flush(cache));
+
+ // we'll let it succeed the second time
+ _expect_write(me, fd, 0);
+ _expect(me, E_WAIT);
+ T_ASSERT(bcache_flush(cache));
+}
+
+static void test_write_bad_io_stops_flush(void *context)
+{
+ struct fixture *f = context;
+ struct mock_engine *me = f->me;
+ struct bcache *cache = f->cache;
+ struct block *b;
+ int fd = 17;
+ int err;
+
+ T_ASSERT(bcache_get(cache, fd, 0, GF_ZERO, &b, &err));
+ _expect_write_bad_wait(me, fd, 0);
+ _expect(me, E_WAIT);
+ bcache_put(b);
+ T_ASSERT(!bcache_flush(cache));
+
+ // we'll let it succeed the second time
+ _expect_write(me, fd, 0);
+ _expect(me, E_WAIT);
+ T_ASSERT(bcache_flush(cache));
+}
+
+// Tests to be written
+// show invalidate works
+// show invalidate_fd works
+// show writeback is working
+
+/*----------------------------------------------------------------
+ * Top level
+ *--------------------------------------------------------------*/
+#define T(path, desc, fn) register_test(ts, "/base/device/bcache/" path, desc, fn)
+
+static struct test_suite *_small_tests(void)
+{
+ struct test_suite *ts = test_suite_create(_small_fixture_init, _small_fixture_exit);
+ if (!ts) {
+ fprintf(stderr, "out of memory\n");
+ exit(1);
+ }
+
+ T("create-destroy", "simple create/destroy", test_create);
+ T("cache-blocks-positive", "nr cache blocks must be positive", test_nr_cache_blocks_must_be_positive);
+ T("block-size-positive", "block size must be positive", test_block_size_must_be_positive);
+ T("block-size-multiple-page", "block size must be a multiple of page size", test_block_size_must_be_multiple_of_page_size);
+ T("get-reads", "bcache_get() triggers read", test_get_triggers_read);
+ T("reads-cached", "repeated reads are cached", test_repeated_reads_are_cached);
+ T("blocks-get-evicted", "block get evicted with many reads", test_block_gets_evicted_with_many_reads);
+ T("prefetch-reads", "prefetch issues a read", test_prefetch_issues_a_read);
+ T("prefetch-never-waits", "too many prefetches does not trigger a wait", test_too_many_prefetches_does_not_trigger_a_wait);
+ T("writeback-occurs", "dirty data gets written back", test_dirty_data_gets_written_back);
+ T("zero-flag-dirties", "zeroed data counts as dirty", test_zeroed_data_counts_as_dirty);
+ T("read-multiple-files", "read from multiple files", test_multiple_files);
+ T("read-bad-issue", "read fails if io engine unable to issue", test_read_bad_issue);
+ T("read-bad-issue-intermittent", "failed issue, followed by succes", test_read_bad_issue_intermittent);
+ T("read-bad-io", "read issued ok, but io fails", test_read_bad_wait);
+ T("read-bad-io-intermittent", "failed io, followed by success", test_read_bad_wait_intermittent);
+ T("write-bad-issue-stops-flush", "flush fails temporarily if any block fails to write", test_write_bad_issue_stops_flush);
+ T("write-bad-io-stops-flush", "flush fails temporarily if any block fails to write", test_write_bad_io_stops_flush);
+
+ return ts;
+}
+
+static struct test_suite *_large_tests(void)
+{
+ struct test_suite *ts = test_suite_create(_large_fixture_init, _large_fixture_exit);
+ if (!ts) {
+ fprintf(stderr, "out of memory\n");
+ exit(1);
+ }
+
+ T("flush-waits", "flush waits for all dirty", test_flush_waits_for_all_dirty);
+
+ return ts;
+}
+
+void bcache_tests(struct dm_list *all_tests)
+{
+ dm_list_add(all_tests, &_small_tests()->list);
+ dm_list_add(all_tests, &_large_tests()->list);
+}
diff --git a/unit-test/bitset_t.c b/unit-test/bitset_t.c
new file mode 100644
index 0000000..106f60f
--- /dev/null
+++ b/unit-test/bitset_t.c
@@ -0,0 +1,148 @@
+/*
+ * Copyright (C) 2010 Red Hat, Inc. All rights reserved.
+ *
+ * This file is part of LVM2.
+ *
+ * This copyrighted material is made available to anyone wishing to use,
+ * modify, copy, or redistribute it subject to the terms and conditions
+ * of the GNU General Public License v.2.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+#include "units.h"
+#include "libdevmapper.h"
+
+enum {
+ NR_BITS = 137
+};
+
+static void *_mem_init(void) {
+ struct dm_pool *mem = dm_pool_create("bitset test", 1024);
+ if (!mem) {
+ fprintf(stderr, "out of memory\n");
+ exit(1);
+ }
+
+ return mem;
+}
+
+static void _mem_exit(void *mem)
+{
+ dm_pool_destroy(mem);
+}
+
+static void test_get_next(void *fixture)
+{
+ struct dm_pool *mem = fixture;
+
+ int i, j, last = 0, first;
+ dm_bitset_t bs = dm_bitset_create(mem, NR_BITS);
+
+ for (i = 0; i < NR_BITS; i++)
+ T_ASSERT(!dm_bit(bs, i));
+
+ for (i = 0, j = 1; i < NR_BITS; i += j, j++)
+ dm_bit_set(bs, i);
+
+ first = 1;
+ for (i = 0, j = 1; i < NR_BITS; i += j, j++) {
+ if (first) {
+ last = dm_bit_get_first(bs);
+ first = 0;
+ } else
+ last = dm_bit_get_next(bs, last);
+
+ T_ASSERT(last == i);
+ }
+
+ T_ASSERT(dm_bit_get_next(bs, last) == -1);
+}
+
+static void bit_flip(dm_bitset_t bs, int bit)
+{
+ int old = dm_bit(bs, bit);
+ if (old)
+ dm_bit_clear(bs, bit);
+ else
+ dm_bit_set(bs, bit);
+}
+
+static void test_equal(void *fixture)
+{
+ struct dm_pool *mem = fixture;
+ dm_bitset_t bs1 = dm_bitset_create(mem, NR_BITS);
+ dm_bitset_t bs2 = dm_bitset_create(mem, NR_BITS);
+
+ int i, j;
+ for (i = 0, j = 1; i < NR_BITS; i += j, j++) {
+ dm_bit_set(bs1, i);
+ dm_bit_set(bs2, i);
+ }
+
+ T_ASSERT(dm_bitset_equal(bs1, bs2));
+ T_ASSERT(dm_bitset_equal(bs2, bs1));
+
+ for (i = 0; i < NR_BITS; i++) {
+ bit_flip(bs1, i);
+ T_ASSERT(!dm_bitset_equal(bs1, bs2));
+ T_ASSERT(!dm_bitset_equal(bs2, bs1));
+
+ T_ASSERT(dm_bitset_equal(bs1, bs1)); /* comparing with self */
+ bit_flip(bs1, i);
+ }
+}
+
+static void test_and(void *fixture)
+{
+ struct dm_pool *mem = fixture;
+ dm_bitset_t bs1 = dm_bitset_create(mem, NR_BITS);
+ dm_bitset_t bs2 = dm_bitset_create(mem, NR_BITS);
+ dm_bitset_t bs3 = dm_bitset_create(mem, NR_BITS);
+
+ int i, j;
+ for (i = 0, j = 1; i < NR_BITS; i += j, j++) {
+ dm_bit_set(bs1, i);
+ dm_bit_set(bs2, i);
+ }
+
+ dm_bit_and(bs3, bs1, bs2);
+
+ T_ASSERT(dm_bitset_equal(bs1, bs2));
+ T_ASSERT(dm_bitset_equal(bs1, bs3));
+ T_ASSERT(dm_bitset_equal(bs2, bs3));
+
+ dm_bit_clear_all(bs1);
+ dm_bit_clear_all(bs2);
+
+ for (i = 0; i < NR_BITS; i++) {
+ if (i % 2)
+ dm_bit_set(bs1, i);
+ else
+ dm_bit_set(bs2, i);
+ }
+
+ dm_bit_and(bs3, bs1, bs2);
+ for (i = 0; i < NR_BITS; i++)
+ T_ASSERT(!dm_bit(bs3, i));
+}
+
+#define T(path, desc, fn) register_test(ts, "/base/data-struct/bitset/" path, desc, fn)
+
+void bitset_tests(struct dm_list *all_tests)
+{
+ struct test_suite *ts = test_suite_create(_mem_init, _mem_exit);
+ if (!ts) {
+ fprintf(stderr, "out of memory\n");
+ exit(1);
+ }
+
+ T("get_next", "get next set bit", test_get_next);
+ T("equal", "equality", test_equal);
+ T("and", "and all bits", test_and);
+
+ dm_list_add(all_tests, &ts->list);
+}
+
diff --git a/unit-test/config_t.c b/unit-test/config_t.c
new file mode 100644
index 0000000..5331f79
--- /dev/null
+++ b/unit-test/config_t.c
@@ -0,0 +1,167 @@
+/*
+ * Copyright (C) 2010 Red Hat, Inc. All rights reserved.
+ *
+ * This file is part of LVM2.
+ *
+ * This copyrighted material is made available to anyone wishing to use,
+ * modify, copy, or redistribute it subject to the terms and conditions
+ * of the GNU General Public License v.2.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+#include "units.h"
+#include "libdevmapper.h"
+
+static void *_mem_init(void)
+{
+ struct dm_pool *mem = dm_pool_create("config test", 1024);
+ if (!mem) {
+ fprintf(stderr, "out of memory\n");
+ exit(1);
+ }
+
+ return mem;
+}
+
+static void _mem_exit(void *mem)
+{
+ dm_pool_destroy(mem);
+}
+
+static const char *conf =
+ "id = \"yada-yada\"\n"
+ "seqno = 15\n"
+ "status = [\"READ\", \"WRITE\"]\n"
+ "flags = []\n"
+ "extent_size = 8192\n"
+ "physical_volumes {\n"
+ " pv0 {\n"
+ " id = \"abcd-efgh\"\n"
+ " }\n"
+ " pv1 {\n"
+ " id = \"bbcd-efgh\"\n"
+ " }\n"
+ " pv2 {\n"
+ " id = \"cbcd-efgh\"\n"
+ " }\n"
+ "}\n";
+
+static const char *overlay =
+ "id = \"yoda-soda\"\n"
+ "flags = [\"FOO\"]\n"
+ "physical_volumes {\n"
+ " pv1 {\n"
+ " id = \"hgfe-dcba\"\n"
+ " }\n"
+ " pv3 {\n"
+ " id = \"dbcd-efgh\"\n"
+ " }\n"
+ "}\n";
+
+static void test_parse(void *fixture)
+{
+ struct dm_config_tree *tree = dm_config_from_string(conf);
+ const struct dm_config_value *value;
+
+ T_ASSERT((long) tree);
+ T_ASSERT(dm_config_has_node(tree->root, "id"));
+ T_ASSERT(dm_config_has_node(tree->root, "physical_volumes"));
+ T_ASSERT(dm_config_has_node(tree->root, "physical_volumes/pv0"));
+ T_ASSERT(dm_config_has_node(tree->root, "physical_volumes/pv0/id"));
+
+ T_ASSERT(!strcmp(dm_config_find_str(tree->root, "id", "foo"), "yada-yada"));
+ T_ASSERT(!strcmp(dm_config_find_str(tree->root, "idt", "foo"), "foo"));
+
+ T_ASSERT(!strcmp(dm_config_find_str(tree->root, "physical_volumes/pv0/bb", "foo"), "foo"));
+ T_ASSERT(!strcmp(dm_config_find_str(tree->root, "physical_volumes/pv0/id", "foo"), "abcd-efgh"));
+
+ T_ASSERT(!dm_config_get_uint32(tree->root, "id", NULL));
+ T_ASSERT(dm_config_get_uint32(tree->root, "extent_size", NULL));
+
+ /* FIXME: Currently everything parses as a list, even if it's not */
+ // T_ASSERT(!dm_config_get_list(tree->root, "id", NULL));
+ // T_ASSERT(!dm_config_get_list(tree->root, "extent_size", NULL));
+
+ T_ASSERT(dm_config_get_list(tree->root, "flags", &value));
+ T_ASSERT(value->next == NULL); /* an empty list */
+ T_ASSERT(dm_config_get_list(tree->root, "status", &value));
+ T_ASSERT(value->next != NULL); /* a non-empty list */
+
+ dm_config_destroy(tree);
+}
+
+static void test_clone(void *fixture)
+{
+ struct dm_config_tree *tree = dm_config_from_string(conf);
+ struct dm_config_node *n = dm_config_clone_node(tree, tree->root, 1);
+ const struct dm_config_value *value;
+
+ /* Check that the nodes are actually distinct. */
+ T_ASSERT(n != tree->root);
+ T_ASSERT(n->sib != tree->root->sib);
+ T_ASSERT(dm_config_find_node(n, "physical_volumes") != NULL);
+ T_ASSERT(dm_config_find_node(tree->root, "physical_volumes") != NULL);
+ T_ASSERT(dm_config_find_node(n, "physical_volumes") != dm_config_find_node(tree->root, "physical_volumes"));
+
+ T_ASSERT(dm_config_has_node(n, "id"));
+ T_ASSERT(dm_config_has_node(n, "physical_volumes"));
+ T_ASSERT(dm_config_has_node(n, "physical_volumes/pv0"));
+ T_ASSERT(dm_config_has_node(n, "physical_volumes/pv0/id"));
+
+ T_ASSERT(!strcmp(dm_config_find_str(n, "id", "foo"), "yada-yada"));
+ T_ASSERT(!strcmp(dm_config_find_str(n, "idt", "foo"), "foo"));
+
+ T_ASSERT(!strcmp(dm_config_find_str(n, "physical_volumes/pv0/bb", "foo"), "foo"));
+ T_ASSERT(!strcmp(dm_config_find_str(n, "physical_volumes/pv0/id", "foo"), "abcd-efgh"));
+
+ T_ASSERT(!dm_config_get_uint32(n, "id", NULL));
+ T_ASSERT(dm_config_get_uint32(n, "extent_size", NULL));
+
+ /* FIXME: Currently everything parses as a list, even if it's not */
+ // T_ASSERT(!dm_config_get_list(tree->root, "id", NULL));
+ // T_ASSERT(!dm_config_get_list(tree->root, "extent_size", NULL));
+
+ T_ASSERT(dm_config_get_list(n, "flags", &value));
+ T_ASSERT(value->next == NULL); /* an empty list */
+ T_ASSERT(dm_config_get_list(n, "status", &value));
+ T_ASSERT(value->next != NULL); /* a non-empty list */
+
+ dm_config_destroy(tree);
+}
+
+static void test_cascade(void *fixture)
+{
+ struct dm_config_tree *t1 = dm_config_from_string(conf),
+ *t2 = dm_config_from_string(overlay),
+ *tree = dm_config_insert_cascaded_tree(t2, t1);
+
+ T_ASSERT(!strcmp(dm_config_tree_find_str(tree, "id", "foo"), "yoda-soda"));
+ T_ASSERT(!strcmp(dm_config_tree_find_str(tree, "idt", "foo"), "foo"));
+
+ T_ASSERT(!strcmp(dm_config_tree_find_str(tree, "physical_volumes/pv0/bb", "foo"), "foo"));
+ T_ASSERT(!strcmp(dm_config_tree_find_str(tree, "physical_volumes/pv1/id", "foo"), "hgfe-dcba"));
+ T_ASSERT(!strcmp(dm_config_tree_find_str(tree, "physical_volumes/pv3/id", "foo"), "dbcd-efgh"));
+
+ dm_config_destroy(t1);
+ dm_config_destroy(t2);
+}
+
+#define T(path, desc, fn) register_test(ts, "/metadata/config/" path, desc, fn)
+
+void config_tests(struct dm_list *all_tests)
+{
+ struct test_suite *ts = test_suite_create(_mem_init, _mem_exit);
+ if (!ts) {
+ fprintf(stderr, "out of memory\n");
+ exit(1);
+ }
+
+ T("parse", "parsing various", test_parse);
+ T("clone", "duplicating a config tree", test_clone);
+ T("cascade", "cascade", test_cascade);
+
+ dm_list_add(all_tests, &ts->list);
+};
diff --git a/unit-test/dmlist_t.c b/unit-test/dmlist_t.c
new file mode 100644
index 0000000..82789ba
--- /dev/null
+++ b/unit-test/dmlist_t.c
@@ -0,0 +1,49 @@
+/*
+ * Copyright (C) 2015 Red Hat, Inc. All rights reserved.
+ *
+ * This file is part of LVM2.
+ *
+ * This copyrighted material is made available to anyone wishing to use,
+ * modify, copy, or redistribute it subject to the terms and conditions
+ * of the GNU General Public License v.2.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+#include "units.h"
+#include "libdevmapper.h"
+
+static void test_dmlist_splice(void *fixture)
+{
+ unsigned i;
+ struct dm_list a[10];
+ struct dm_list list1;
+ struct dm_list list2;
+
+ dm_list_init(&list1);
+ dm_list_init(&list2);
+
+ for (i = 0; i < DM_ARRAY_SIZE(a); i++)
+ dm_list_add(&list1, &a[i]);
+
+ dm_list_splice(&list2, &list1);
+ T_ASSERT(dm_list_size(&list1) == 0);
+ T_ASSERT(dm_list_size(&list2) == 10);
+}
+
+#define T(path, desc, fn) register_test(ts, "/base/data-struct/list/" path, desc, fn)
+
+void dm_list_tests(struct dm_list *all_tests)
+{
+ struct test_suite *ts = test_suite_create(NULL, NULL);
+ if (!ts) {
+ fprintf(stderr, "out of memory\n");
+ exit(1);
+ }
+
+ T("splice", "joining lists together", test_dmlist_splice);
+
+ dm_list_add(all_tests, &ts->list);
+}
diff --git a/unit-test/dmstatus_t.c b/unit-test/dmstatus_t.c
new file mode 100644
index 0000000..4b57f29
--- /dev/null
+++ b/unit-test/dmstatus_t.c
@@ -0,0 +1,84 @@
+/*
+ * Copyright (C) 2015 Red Hat, Inc. All rights reserved.
+ *
+ * This file is part of LVM2.
+ *
+ * This copyrighted material is made available to anyone wishing to use,
+ * modify, copy, or redistribute it subject to the terms and conditions
+ * of the GNU General Public License v.2.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+#include "units.h"
+#include "libdevmapper.h"
+
+static void *_mem_init(void)
+{
+ struct dm_pool *mem = dm_pool_create("dmstatus test", 1024);
+ if (!mem) {
+ fprintf(stderr, "out of memory\n");
+ exit(1);
+ }
+
+ return mem;
+}
+
+static void _mem_exit(void *mem)
+{
+ dm_pool_destroy(mem);
+}
+
+static void _test_mirror_status(void *fixture)
+{
+ struct dm_pool *mem = fixture;
+ struct dm_status_mirror *s = NULL;
+
+ T_ASSERT(dm_get_status_mirror(mem,
+ "2 253:1 253:2 80/81 1 AD 3 disk 253:0 A",
+ &s));
+ if (s) {
+ T_ASSERT_EQUAL(s->total_regions, 81);
+ T_ASSERT_EQUAL(s->insync_regions, 80);
+ T_ASSERT_EQUAL(s->dev_count, 2);
+ T_ASSERT_EQUAL(s->devs[0].health, 'A');
+ T_ASSERT_EQUAL(s->devs[0].major, 253);
+ T_ASSERT_EQUAL(s->devs[0].minor, 1);
+ T_ASSERT_EQUAL(s->devs[1].health, 'D');
+ T_ASSERT_EQUAL(s->devs[1].major, 253);
+ T_ASSERT_EQUAL(s->devs[1].minor, 2);
+ T_ASSERT_EQUAL(s->log_count, 1);
+ T_ASSERT_EQUAL(s->logs[0].major, 253);
+ T_ASSERT_EQUAL(s->logs[0].minor, 0);
+ T_ASSERT_EQUAL(s->logs[0].health, 'A');
+ T_ASSERT(!strcmp(s->log_type, "disk"));
+ }
+
+ T_ASSERT(dm_get_status_mirror(mem,
+ "4 253:1 253:2 253:3 253:4 10/10 1 ADFF 1 core",
+ &s));
+ if (s) {
+ T_ASSERT_EQUAL(s->total_regions, 10);
+ T_ASSERT_EQUAL(s->insync_regions, 10);
+ T_ASSERT_EQUAL(s->dev_count, 4);
+ T_ASSERT_EQUAL(s->devs[3].minor, 4);
+ T_ASSERT_EQUAL(s->devs[3].health, 'F');
+ T_ASSERT_EQUAL(s->log_count, 0);
+ T_ASSERT(!strcmp(s->log_type, "core"));
+ }
+}
+
+void dm_status_tests(struct dm_list *all_tests)
+{
+ struct test_suite *ts = test_suite_create(_mem_init, _mem_exit);
+ if (!ts) {
+ fprintf(stderr, "out of memory\n");
+ exit(1);
+ }
+
+ register_test(ts, "/dm/target/mirror/status", "parsing mirror status", _test_mirror_status);
+ dm_list_add(all_tests, &ts->list);
+}
+
diff --git a/unit-test/framework.c b/unit-test/framework.c
new file mode 100644
index 0000000..de9a8b1
--- /dev/null
+++ b/unit-test/framework.c
@@ -0,0 +1,66 @@
+#include "framework.h"
+
+/*----------------------------------------------------------------
+ * Assertions
+ *--------------------------------------------------------------*/
+
+jmp_buf test_k;
+#define TEST_FAILED 1
+
+void test_fail(const char *fmt, ...)
+{
+ va_list ap;
+
+ va_start(ap, fmt);
+ vfprintf(stderr, fmt, ap);
+ va_end(ap);
+ fprintf(stderr, "\n");
+
+ longjmp(test_k, TEST_FAILED);
+}
+
+struct test_suite *test_suite_create(void *(*fixture_init)(void),
+ void (*fixture_exit)(void *))
+{
+ struct test_suite *ts = malloc(sizeof(*ts));
+ if (ts) {
+ ts->fixture_init = fixture_init;
+ ts->fixture_exit = fixture_exit;
+ dm_list_init(&ts->tests);
+ }
+
+ return ts;
+}
+
+void test_suite_destroy(struct test_suite *ts)
+{
+ struct test_details *td, *tmp;
+
+ dm_list_iterate_items_safe (td, tmp, &ts->tests) {
+ dm_list_del(&td->list);
+ free(td);
+ }
+
+ free(ts);
+}
+
+bool register_test(struct test_suite *ts,
+ const char *path, const char *desc,
+ void (*fn)(void *))
+{
+ struct test_details *t = malloc(sizeof(*t));
+ if (!t) {
+ fprintf(stderr, "out of memory\n");
+ return false;
+ }
+
+ t->parent = ts;
+ t->path = path;
+ t->desc = desc;
+ t->fn = fn;
+ dm_list_add(&ts->tests, &t->list);
+
+ return true;
+}
+
+//-----------------------------------------------------------------
diff --git a/unit-test/framework.h b/unit-test/framework.h
new file mode 100644
index 0000000..5a33ca6
--- /dev/null
+++ b/unit-test/framework.h
@@ -0,0 +1,49 @@
+#ifndef TEST_UNIT_FRAMEWORK_H
+#define TEST_UNIT_FRAMEWORK_H
+
+#include "libdevmapper.h"
+
+#include <stdbool.h>
+#include <stdint.h>
+#include <setjmp.h>
+
+//-----------------------------------------------------------------
+
+// A test suite gathers a set of tests with a common fixture together.
+struct test_suite {
+ struct dm_list list;
+
+ void *(*fixture_init)(void);
+ void (*fixture_exit)(void *);
+ struct dm_list tests;
+};
+
+struct test_details {
+ struct test_suite *parent;
+ struct dm_list list;
+
+ const char *path;
+ const char *desc;
+ void (*fn)(void *);
+};
+
+struct test_suite *test_suite_create(void *(*fixture_init)(void),
+ void (*fixture_exit)(void *));
+void test_suite_destroy(struct test_suite *ts);
+
+bool register_test(struct test_suite *ts,
+ const char *path, const char *desc, void (*fn)(void *));
+
+void test_fail(const char *fmt, ...)
+ __attribute__((noreturn, format (printf, 1, 2)));
+
+#define T_ASSERT(e) do {if (!(e)) {test_fail("assertion failed: '%s'", # e);} } while(0)
+#define T_ASSERT_EQUAL(x, y) T_ASSERT((x) == (y))
+#define T_ASSERT_NOT_EQUAL(x, y) T_ASSERT((x) != (y))
+
+extern jmp_buf test_k;
+#define TEST_FAILED 1
+
+//-----------------------------------------------------------------
+
+#endif
diff --git a/unit-test/matcher_data.h b/unit-test/matcher_data.h
new file mode 100644
index 0000000..97dbbfe
--- /dev/null
+++ b/unit-test/matcher_data.h
@@ -0,0 +1,1013 @@
+struct check_item {
+ const char *str;
+ int expected;
+};
+
+static const char *dev_patterns[] = {
+ "loop/[0-9]+",
+ "hd[a-d][0-5]+",
+ NULL
+};
+
+static const char *nonprint_patterns[] = {
+ "foo\x80" "bar",
+ "foo\xc2" "b",
+ "\x80",
+ NULL
+};
+
+static const struct check_item nonprint[] = {
+ { "foo\x2e" "bar", 0 },
+ { "foo\x80" "bar", 3 },
+ { "foo\xc2" "b", 2 },
+ { "\x80", 3 },
+ { NULL, 0 }
+};
+
+static const char *random_patterns[] = {
+ "(((a?)(([Ub]*)|z))((([qr]|X)+)([Qn]*)))+",
+ "[HZejtuw]*",
+ "((B|s)*)|(((([Fv]l)(N+))(([el]|C)(tJ)))?)",
+ "((([Ma]?)|(t*))*)|((([cm]E)|(M?))|(([BE][EV])|([Qj][Mh])))",
+ "(((([bw]*)|([IO]*))((zK)*))|(((pU)|(i|q))|((z?)|([HL]?))))*",
+ "((([Pt]?)|[Tr])?)((Hq)*)",
+ "[HOXcfgikosvwxz]",
+ "[BCEFGHNPTUWfjlprsy]",
+ "((((aD)*)|([Xo]+))+)(([HKn](([Eq]|[JQ])(I*)))*)",
+ "([LNWYeghv]|e)*",
+ "(((y(L*))*)|((([EP]+)(W+))*))*",
+ "U*",
+ "((((R+)(W|[Qr]))|([py]+))+)([LM]*)",
+ "(([DOjx](D(b?)))|([Ke]*))*",
+ "((([ls](c|[FT]))*)([JS]*))*",
+ "((l?)|(([Gz]+)|(D*)))*",
+ "[ABgjn]",
+ "(((q|[dg])?)|([Uk]*))((([Fl]?)|([Ry]+))|(([IR]|c)|(T?)))",
+ "((([an]|P)|[Jw])((a*)|(m*)))*",
+ "((((R[ht])(h+))?)|(([pz](n?))+))+",
+ "(((([Dc]b)([Sp][Ii]))|((k|F)*))|[Uiovz])*",
+ "[Res]*",
+ "[Zl]|a",
+ "^[ANZdf]$",
+ "[En]|(((Q+)(U+))([pt]*))",
+ "[ADEIMQUWXZhklrsvz]",
+ "(((S(y*))*)|(j*))*",
+ "n*",
+ "[NUau]*",
+ "((((Z*)(D|[Nd]))|(([np]|B)+))|(([Xy][Fi])*))+",
+ "((([EZ]?)|(d[HR]))*)((([Hg]|q)(P+))*)",
+ "q",
+ "((m*)|(p|B))|((((x?)|(t+))(([Sb][PX])(O|[HM])))+)",
+ "((((A*)(z[RS]))*)|(((z+)(Q*))+))*",
+ "(((M*)([Uu]*))+)|[Uk]",
+ "[imv]",
+ "[GLSchtw](([Yw]((F[Dd])|([Tw]+)))?)",
+ "([MOZj]*)(S|[Wknr])",
+ "((G|q)*)[BHKN]",
+ "((((NW)|([Ao]?))|((l|[UV])+))+)|((i|(z*))*)",
+ "((((Z+)|([IR]?))|(L*))|([JKQ]+))+",
+ "([Bdin](S*))+",
+ "[HLNSTp]*",
+ "(((J*)([Bq]|[Yu]))*)|([Kv]*)",
+ "(((([BJ]|[Zy])(wI))*)(y*))+",
+ "(((hF)+)|(H*))*",
+ "((([QU][Pj])([GQ]?))+)|[PWo]",
+ "(((([cq][BX])?)|((f[DI])*))*)(([GM]*)[SVYr])",
+ "(([Zt]*)|((qx)|(([BV]+)(f?))))*",
+ "[ILWYhsx]*",
+ "(([Uy]*)|[sv])|([NSc]*)",
+ "((c*)|([JUfhy]?))+",
+ "(((q*)([So]*))(((g[jq])(j?))+))*",
+ "((b+)|(((T+)([fw]T))?))*",
+ "((([DS]?)|([Th]|u))(Q*))*",
+ "[FKLX]|((([fw](L?))(([gq]*)|(O?)))?)",
+ "((([HZ]+)u)*)|[APWijn]",
+ "(e*)|(((v?)|((J+)(Hb)))?)",
+ "(e|((w+)f))*",
+ "[BEHKPQVdelnqy]",
+ "((((B|N)(s*))|[Rr])(((g?)|([rv]+))+))+",
+ "(((s*)|(K*))([AP]G))*",
+ "[CELTp]",
+ "(([Fq]?)|([Al]+))*",
+ "((((r?)|(y[jx]))|([mp]*))+)|((B(S*))*)",
+ "((([Eq]+)|(Y[ds]))|(x|(i|[Ku])))[IJNrvy]",
+ "((([NO]*)[Ix])+)([Jenq]+)",
+ "(((([HP]*)(j|y))*)[Ylqvy])*",
+ "[PTv]+",
+ "[AINSZhpx]|([EOYZ]*)",
+ "([ABCFQv]*)((([Zx]|h)+)|([ej]*))",
+ "((([pr]*)|(([Dq]|p)|(H?)))?)([NRUXmoq]*)",
+ "(([er]*)|([mx]*))(((nV)([am]?))+)",
+ "[BHPRlpu]",
+ "(((([Ah]|[tx])|(e|[uy]))?)((([fl]+)([Vz]|v))*))*",
+ "[AGdm]",
+ "(((K*)^(O*)$)|(B?))*",
+ "((([Ks]|[Ka])*)|([FSTab]?))?",
+ "(([kw]+)[ei])(([Hy]*)(([Mc]*)|(G|f)))",
+ "((((e*)|(Zf))|(R|[nq]))((([Jz]v)([Rj]+))+))*",
+ "(((a?)|(e?))(([Uc]*)(S+)))*",
+ "((((E+)([MZ]?))+)|(((s|[Az])|z)*))?",
+ "((((i[MO])*)|((LH)*))|(((BA)|([AI]+))|[Ug]))*",
+ "[EGHILcho]*",
+ "(((Z[vw])?)((z|g)+))(((H|U)([iv]Q))|([qw]?))",
+ "(([ehmr]|((L[Uw])*))+)((a+)I)",
+ "[EKNSWYagj](((v|[TX])|([Uk]+))*)",
+ "(((R[Mo])|(O*))|([Fm]|([qw]*)))((m*)|((S|[Ki])?))",
+ "((((kP)|c)?)((([do]+)|([Gi]?))*))*",
+ "((^(B|W)$|([Ww]+))([no]*))|((([iv]?)|(M*))|((x|L)?))",
+ "[AEGPRSbcfhsy]",
+ "[Wbcf]|((([MO]?)|([NT]|m))(([Oo]?)([Wg]*)))",
+ "(((YZ)*)[PQVei])*",
+ "[GJKYt][AEGWdegmnt]",
+ "^[CDEGJKNUVYZagkv]$",
+ "([DPWbx]*)|(((q|B)|(P|u))((M[Bq])*))",
+ "[FHIJRTVYZdiorsuvz]*",
+ "([MWoqvz]*)|^(l*)",
+ "(((I|[Rx])*)((X[Mf])([Xa]L)))([Ha]|([HY]*))",
+ "(((l|[Sd])*)((([Ix]+)|([XY]?))(Z*)))+",
+ NULL
+};
+
+struct check_item devices[] = {
+ { "/dev", 0 },
+ { "/dev/.devfsd", 0 },
+ { "/dev/cpu", 0 },
+ { "/dev/cpu/mtrr", 0 },
+ { "/dev/netlink", 0 },
+ { "/dev/netlink/route", 0 },
+ { "/dev/netlink/skip", 0 },
+ { "/dev/netlink/USERSOCK", 0 },
+ { "/dev/netlink/fwmonitor", 0 },
+ { "/dev/netlink/ARPD", 0 },
+ { "/dev/netlink/ROUTE6", 0 },
+ { "/dev/netlink/IP6_FW", 0 },
+ { "/dev/netlink/tap0", 0 },
+ { "/dev/netlink/tap1", 0 },
+ { "/dev/netlink/tap2", 0 },
+ { "/dev/netlink/tap3", 0 },
+ { "/dev/netlink/tap4", 0 },
+ { "/dev/netlink/tap5", 0 },
+ { "/dev/netlink/tap6", 0 },
+ { "/dev/netlink/tap7", 0 },
+ { "/dev/netlink/tap8", 0 },
+ { "/dev/netlink/tap9", 0 },
+ { "/dev/netlink/tap10", 0 },
+ { "/dev/netlink/tap11", 0 },
+ { "/dev/netlink/tap12", 0 },
+ { "/dev/netlink/tap13", 0 },
+ { "/dev/netlink/tap14", 0 },
+ { "/dev/netlink/tap15", 0 },
+ { "/dev/shm", 0 },
+ { "/dev/mem", 0 },
+ { "/dev/kmem", 0 },
+ { "/dev/null", 0 },
+ { "/dev/port", 0 },
+ { "/dev/zero", 0 },
+ { "/dev/full", 0 },
+ { "/dev/random", 0 },
+ { "/dev/urandom", 0 },
+ { "/dev/tty", 0 },
+ { "/dev/console", 0 },
+ { "/dev/vc", 0 },
+ { "/dev/vc/1", 0 },
+ { "/dev/vc/2", 0 },
+ { "/dev/vc/3", 0 },
+ { "/dev/vc/4", 0 },
+ { "/dev/vc/5", 0 },
+ { "/dev/vc/6", 0 },
+ { "/dev/vc/7", 0 },
+ { "/dev/vc/8", 0 },
+ { "/dev/vc/9", 0 },
+ { "/dev/vc/10", 0 },
+ { "/dev/vc/11", 0 },
+ { "/dev/vc/12", 0 },
+ { "/dev/vc/13", 0 },
+ { "/dev/vc/14", 0 },
+ { "/dev/vc/15", 0 },
+ { "/dev/vc/16", 0 },
+ { "/dev/vc/17", 0 },
+ { "/dev/vc/18", 0 },
+ { "/dev/vc/19", 0 },
+ { "/dev/vc/20", 0 },
+ { "/dev/vc/21", 0 },
+ { "/dev/vc/22", 0 },
+ { "/dev/vc/23", 0 },
+ { "/dev/vc/24", 0 },
+ { "/dev/vc/25", 0 },
+ { "/dev/vc/26", 0 },
+ { "/dev/vc/27", 0 },
+ { "/dev/vc/28", 0 },
+ { "/dev/vc/29", 0 },
+ { "/dev/vc/30", 0 },
+ { "/dev/vc/31", 0 },
+ { "/dev/vc/32", 0 },
+ { "/dev/vc/33", 0 },
+ { "/dev/vc/34", 0 },
+ { "/dev/vc/35", 0 },
+ { "/dev/vc/36", 0 },
+ { "/dev/vc/37", 0 },
+ { "/dev/vc/38", 0 },
+ { "/dev/vc/39", 0 },
+ { "/dev/vc/40", 0 },
+ { "/dev/vc/41", 0 },
+ { "/dev/vc/42", 0 },
+ { "/dev/vc/43", 0 },
+ { "/dev/vc/44", 0 },
+ { "/dev/vc/45", 0 },
+ { "/dev/vc/46", 0 },
+ { "/dev/vc/47", 0 },
+ { "/dev/vc/48", 0 },
+ { "/dev/vc/49", 0 },
+ { "/dev/vc/50", 0 },
+ { "/dev/vc/51", 0 },
+ { "/dev/vc/52", 0 },
+ { "/dev/vc/53", 0 },
+ { "/dev/vc/54", 0 },
+ { "/dev/vc/55", 0 },
+ { "/dev/vc/56", 0 },
+ { "/dev/vc/57", 0 },
+ { "/dev/vc/58", 0 },
+ { "/dev/vc/59", 0 },
+ { "/dev/vc/60", 0 },
+ { "/dev/vc/61", 0 },
+ { "/dev/vc/62", 0 },
+ { "/dev/vc/63", 0 },
+ { "/dev/vc/0", 0 },
+ { "/dev/ptmx", 0 },
+ { "/dev/misc", 0 },
+ { "/dev/misc/psaux", 0 },
+ { "/dev/pty", 0 },
+ { "/dev/pty/m0", 0 },
+ { "/dev/pty/m1", 0 },
+ { "/dev/pty/m2", 0 },
+ { "/dev/pty/m3", 0 },
+ { "/dev/pty/m4", 0 },
+ { "/dev/pty/m5", 0 },
+ { "/dev/pty/m6", 0 },
+ { "/dev/pty/m7", 0 },
+ { "/dev/pty/m8", 0 },
+ { "/dev/pty/m9", 0 },
+ { "/dev/pty/m10", 0 },
+ { "/dev/pty/m11", 0 },
+ { "/dev/pty/m12", 0 },
+ { "/dev/pty/m13", 0 },
+ { "/dev/pty/m14", 0 },
+ { "/dev/pty/m15", 0 },
+ { "/dev/pty/m16", 0 },
+ { "/dev/pty/m17", 0 },
+ { "/dev/pty/m18", 0 },
+ { "/dev/pty/m19", 0 },
+ { "/dev/pty/m20", 0 },
+ { "/dev/pty/m21", 0 },
+ { "/dev/pty/m22", 0 },
+ { "/dev/pty/m23", 0 },
+ { "/dev/pty/m24", 0 },
+ { "/dev/pty/m25", 0 },
+ { "/dev/pty/m26", 0 },
+ { "/dev/pty/m27", 0 },
+ { "/dev/pty/m28", 0 },
+ { "/dev/pty/m29", 0 },
+ { "/dev/pty/m30", 0 },
+ { "/dev/pty/m31", 0 },
+ { "/dev/pty/m32", 0 },
+ { "/dev/pty/m33", 0 },
+ { "/dev/pty/m34", 0 },
+ { "/dev/pty/m35", 0 },
+ { "/dev/pty/m36", 0 },
+ { "/dev/pty/m37", 0 },
+ { "/dev/pty/m38", 0 },
+ { "/dev/pty/m39", 0 },
+ { "/dev/pty/m40", 0 },
+ { "/dev/pty/m41", 0 },
+ { "/dev/pty/m42", 0 },
+ { "/dev/pty/m43", 0 },
+ { "/dev/pty/m44", 0 },
+ { "/dev/pty/m45", 0 },
+ { "/dev/pty/m46", 0 },
+ { "/dev/pty/m47", 0 },
+ { "/dev/pty/m48", 0 },
+ { "/dev/pty/m49", 0 },
+ { "/dev/pty/m50", 0 },
+ { "/dev/pty/m51", 0 },
+ { "/dev/pty/m52", 0 },
+ { "/dev/pty/m53", 0 },
+ { "/dev/pty/m54", 0 },
+ { "/dev/pty/m55", 0 },
+ { "/dev/pty/m56", 0 },
+ { "/dev/pty/m57", 0 },
+ { "/dev/pty/m58", 0 },
+ { "/dev/pty/m59", 0 },
+ { "/dev/pty/m60", 0 },
+ { "/dev/pty/m61", 0 },
+ { "/dev/pty/m62", 0 },
+ { "/dev/pty/m63", 0 },
+ { "/dev/pty/m64", 0 },
+ { "/dev/pty/m65", 0 },
+ { "/dev/pty/m66", 0 },
+ { "/dev/pty/m67", 0 },
+ { "/dev/pty/m68", 0 },
+ { "/dev/pty/m69", 0 },
+ { "/dev/pty/m70", 0 },
+ { "/dev/pty/m71", 0 },
+ { "/dev/pty/m72", 0 },
+ { "/dev/pty/m73", 0 },
+ { "/dev/pty/m74", 0 },
+ { "/dev/pty/m75", 0 },
+ { "/dev/pty/m76", 0 },
+ { "/dev/pty/m77", 0 },
+ { "/dev/pty/m78", 0 },
+ { "/dev/pty/m79", 0 },
+ { "/dev/pty/m80", 0 },
+ { "/dev/pty/m81", 0 },
+ { "/dev/pty/m82", 0 },
+ { "/dev/pty/m83", 0 },
+ { "/dev/pty/m84", 0 },
+ { "/dev/pty/m85", 0 },
+ { "/dev/pty/m86", 0 },
+ { "/dev/pty/m87", 0 },
+ { "/dev/pty/m88", 0 },
+ { "/dev/pty/m89", 0 },
+ { "/dev/pty/m90", 0 },
+ { "/dev/pty/m91", 0 },
+ { "/dev/pty/m92", 0 },
+ { "/dev/pty/m93", 0 },
+ { "/dev/pty/m94", 0 },
+ { "/dev/pty/m95", 0 },
+ { "/dev/pty/m96", 0 },
+ { "/dev/pty/m97", 0 },
+ { "/dev/pty/m98", 0 },
+ { "/dev/pty/m99", 0 },
+ { "/dev/pty/m100", 0 },
+ { "/dev/pty/m101", 0 },
+ { "/dev/pty/m102", 0 },
+ { "/dev/pty/m103", 0 },
+ { "/dev/pty/m104", 0 },
+ { "/dev/pty/m105", 0 },
+ { "/dev/pty/m106", 0 },
+ { "/dev/pty/m107", 0 },
+ { "/dev/pty/m108", 0 },
+ { "/dev/pty/m109", 0 },
+ { "/dev/pty/m110", 0 },
+ { "/dev/pty/m111", 0 },
+ { "/dev/pty/m112", 0 },
+ { "/dev/pty/m113", 0 },
+ { "/dev/pty/m114", 0 },
+ { "/dev/pty/m115", 0 },
+ { "/dev/pty/m116", 0 },
+ { "/dev/pty/m117", 0 },
+ { "/dev/pty/m118", 0 },
+ { "/dev/pty/m119", 0 },
+ { "/dev/pty/m120", 0 },
+ { "/dev/pty/m121", 0 },
+ { "/dev/pty/m122", 0 },
+ { "/dev/pty/m123", 0 },
+ { "/dev/pty/m124", 0 },
+ { "/dev/pty/m125", 0 },
+ { "/dev/pty/m126", 0 },
+ { "/dev/pty/m127", 0 },
+ { "/dev/pty/m128", 0 },
+ { "/dev/pty/m129", 0 },
+ { "/dev/pty/m130", 0 },
+ { "/dev/pty/m131", 0 },
+ { "/dev/pty/m132", 0 },
+ { "/dev/pty/m133", 0 },
+ { "/dev/pty/m134", 0 },
+ { "/dev/pty/m135", 0 },
+ { "/dev/pty/m136", 0 },
+ { "/dev/pty/m137", 0 },
+ { "/dev/pty/m138", 0 },
+ { "/dev/pty/m139", 0 },
+ { "/dev/pty/m140", 0 },
+ { "/dev/pty/m141", 0 },
+ { "/dev/pty/m142", 0 },
+ { "/dev/pty/m143", 0 },
+ { "/dev/pty/m144", 0 },
+ { "/dev/pty/m145", 0 },
+ { "/dev/pty/m146", 0 },
+ { "/dev/pty/m147", 0 },
+ { "/dev/pty/m148", 0 },
+ { "/dev/pty/m149", 0 },
+ { "/dev/pty/m150", 0 },
+ { "/dev/pty/m151", 0 },
+ { "/dev/pty/m152", 0 },
+ { "/dev/pty/m153", 0 },
+ { "/dev/pty/m154", 0 },
+ { "/dev/pty/m155", 0 },
+ { "/dev/pty/m156", 0 },
+ { "/dev/pty/m157", 0 },
+ { "/dev/pty/m158", 0 },
+ { "/dev/pty/m159", 0 },
+ { "/dev/pty/m160", 0 },
+ { "/dev/pty/m161", 0 },
+ { "/dev/pty/m162", 0 },
+ { "/dev/pty/m163", 0 },
+ { "/dev/pty/m164", 0 },
+ { "/dev/pty/m165", 0 },
+ { "/dev/pty/m166", 0 },
+ { "/dev/pty/m167", 0 },
+ { "/dev/pty/m168", 0 },
+ { "/dev/pty/m169", 0 },
+ { "/dev/pty/m170", 0 },
+ { "/dev/pty/m171", 0 },
+ { "/dev/pty/m172", 0 },
+ { "/dev/pty/m173", 0 },
+ { "/dev/pty/m174", 0 },
+ { "/dev/pty/m175", 0 },
+ { "/dev/pty/m176", 0 },
+ { "/dev/pty/m177", 0 },
+ { "/dev/pty/m178", 0 },
+ { "/dev/pty/m179", 0 },
+ { "/dev/pty/m180", 0 },
+ { "/dev/pty/m181", 0 },
+ { "/dev/pty/m182", 0 },
+ { "/dev/pty/m183", 0 },
+ { "/dev/pty/m184", 0 },
+ { "/dev/pty/m185", 0 },
+ { "/dev/pty/m186", 0 },
+ { "/dev/pty/m187", 0 },
+ { "/dev/pty/m188", 0 },
+ { "/dev/pty/m189", 0 },
+ { "/dev/pty/m190", 0 },
+ { "/dev/pty/m191", 0 },
+ { "/dev/pty/m192", 0 },
+ { "/dev/pty/m193", 0 },
+ { "/dev/pty/m194", 0 },
+ { "/dev/pty/m195", 0 },
+ { "/dev/pty/m196", 0 },
+ { "/dev/pty/m197", 0 },
+ { "/dev/pty/m198", 0 },
+ { "/dev/pty/m199", 0 },
+ { "/dev/pty/m200", 0 },
+ { "/dev/pty/m201", 0 },
+ { "/dev/pty/m202", 0 },
+ { "/dev/pty/m203", 0 },
+ { "/dev/pty/m204", 0 },
+ { "/dev/pty/m205", 0 },
+ { "/dev/pty/m206", 0 },
+ { "/dev/pty/m207", 0 },
+ { "/dev/pty/m208", 0 },
+ { "/dev/pty/m209", 0 },
+ { "/dev/pty/m210", 0 },
+ { "/dev/pty/m211", 0 },
+ { "/dev/pty/m212", 0 },
+ { "/dev/pty/m213", 0 },
+ { "/dev/pty/m214", 0 },
+ { "/dev/pty/m215", 0 },
+ { "/dev/pty/m216", 0 },
+ { "/dev/pty/m217", 0 },
+ { "/dev/pty/m218", 0 },
+ { "/dev/pty/m219", 0 },
+ { "/dev/pty/m220", 0 },
+ { "/dev/pty/m221", 0 },
+ { "/dev/pty/m222", 0 },
+ { "/dev/pty/m223", 0 },
+ { "/dev/pty/m224", 0 },
+ { "/dev/pty/m225", 0 },
+ { "/dev/pty/m226", 0 },
+ { "/dev/pty/m227", 0 },
+ { "/dev/pty/m228", 0 },
+ { "/dev/pty/m229", 0 },
+ { "/dev/pty/m230", 0 },
+ { "/dev/pty/m231", 0 },
+ { "/dev/pty/m232", 0 },
+ { "/dev/pty/m233", 0 },
+ { "/dev/pty/m234", 0 },
+ { "/dev/pty/m235", 0 },
+ { "/dev/pty/m236", 0 },
+ { "/dev/pty/m237", 0 },
+ { "/dev/pty/m238", 0 },
+ { "/dev/pty/m239", 0 },
+ { "/dev/pty/m240", 0 },
+ { "/dev/pty/m241", 0 },
+ { "/dev/pty/m242", 0 },
+ { "/dev/pty/m243", 0 },
+ { "/dev/pty/m244", 0 },
+ { "/dev/pty/m245", 0 },
+ { "/dev/pty/m246", 0 },
+ { "/dev/pty/m247", 0 },
+ { "/dev/pty/m248", 0 },
+ { "/dev/pty/m249", 0 },
+ { "/dev/pty/m250", 0 },
+ { "/dev/pty/m251", 0 },
+ { "/dev/pty/m252", 0 },
+ { "/dev/pty/m253", 0 },
+ { "/dev/pty/m254", 0 },
+ { "/dev/pty/m255", 0 },
+ { "/dev/pts", 0 },
+ { "/dev/pts/0", 0 },
+ { "/dev/pts/1", 0 },
+ { "/dev/pts/2", 0 },
+ { "/dev/pts/3", 0 },
+ { "/dev/pts/4", 0 },
+ { "/dev/pts/5", 0 },
+ { "/dev/pts/6", 0 },
+ { "/dev/pts/7", 0 },
+ { "/dev/vcc", 0 },
+ { "/dev/vcc/0", 0 },
+ { "/dev/vcc/a", 0 },
+ { "/dev/vcc/1", 0 },
+ { "/dev/vcc/a1", 0 },
+ { "/dev/vcc/2", 0 },
+ { "/dev/vcc/a2", 0 },
+ { "/dev/vcc/3", 0 },
+ { "/dev/vcc/a3", 0 },
+ { "/dev/vcc/5", 0 },
+ { "/dev/vcc/a5", 0 },
+ { "/dev/vcc/4", 0 },
+ { "/dev/vcc/a4", 0 },
+ { "/dev/vcc/6", 0 },
+ { "/dev/vcc/a6", 0 },
+ { "/dev/vcc/7", 0 },
+ { "/dev/vcc/a7", 0 },
+ { "/dev/tts", 0 },
+ { "/dev/tts/0", 0 },
+ { "/dev/cua", 0 },
+ { "/dev/cua/0", 0 },
+ { "/dev/ide", 0 },
+ { "/dev/ide/host0", 0 },
+ { "/dev/ide/host0/bus0", 0 },
+ { "/dev/ide/host0/bus0/target0", 0 },
+ { "/dev/ide/host0/bus0/target0/lun0", 0 },
+ { "/dev/ide/host0/bus0/target0/lun0/disc", 0 },
+ { "/dev/ide/host0/bus0/target0/lun0/part1", 0 },
+ { "/dev/ide/host0/bus0/target0/lun0/part2", 0 },
+ { "/dev/ide/host0/bus0/target0/lun0/part3", 0 },
+ { "/dev/ide/host0/bus0/target0/lun0/part4", 0 },
+ { "/dev/ide/host0/bus0/target0/lun0/part5", 0 },
+ { "/dev/ide/host0/bus0/target0/lun0/part6", 0 },
+ { "/dev/ide/host0/bus0/target0/lun0/part7", 0 },
+ { "/dev/ide/host0/bus0/target0/lun0/part8", 0 },
+ { "/dev/ide/host0/bus0/target1", 0 },
+ { "/dev/ide/host0/bus0/target1/lun0", 0 },
+ { "/dev/ide/host0/bus0/target1/lun0/disc", 0 },
+ { "/dev/ide/host0/bus0/target1/lun0/part1", 0 },
+ { "/dev/ide/host0/bus1", 0 },
+ { "/dev/ide/host0/bus1/target0", 0 },
+ { "/dev/ide/host0/bus1/target0/lun0", 0 },
+ { "/dev/ide/host0/bus1/target0/lun0/disc", 0 },
+ { "/dev/ide/host0/bus1/target0/lun0/part1", 0 },
+ { "/dev/ide/host0/bus1/target1", 0 },
+ { "/dev/ide/host0/bus1/target1/lun0", 0 },
+ { "/dev/discs", 0 },
+ { "/dev/discs/disc0", 0 },
+ { "/dev/discs/disc1", 0 },
+ { "/dev/discs/disc2", 0 },
+ { "/dev/floppy", 0 },
+ { "/dev/floppy/0u1440", 0 },
+ { "/dev/floppy/0u1680", 0 },
+ { "/dev/floppy/0u1722", 0 },
+ { "/dev/floppy/0u1743", 0 },
+ { "/dev/floppy/0u1760", 0 },
+ { "/dev/floppy/0u1920", 0 },
+ { "/dev/floppy/0u1840", 0 },
+ { "/dev/floppy/0u1600", 0 },
+ { "/dev/floppy/0u360", 0 },
+ { "/dev/floppy/0u720", 0 },
+ { "/dev/floppy/0u820", 0 },
+ { "/dev/floppy/0u830", 0 },
+ { "/dev/floppy/0u1040", 0 },
+ { "/dev/floppy/0u1120", 0 },
+ { "/dev/floppy/0u800", 0 },
+ { "/dev/floppy/0", 0 },
+ { "/dev/loop", 0 },
+ { "/dev/loop/0", 1 },
+ { "/dev/loop/1", 1 },
+ { "/dev/loop/2", 1 },
+ { "/dev/loop/3", 1 },
+ { "/dev/loop/4", 1 },
+ { "/dev/loop/5", 1 },
+ { "/dev/loop/6", 1 },
+ { "/dev/loop/7", 1 },
+ { "/dev/cdroms", 0 },
+ { "/dev/sound", 0 },
+ { "/dev/sound/dsp", 0 },
+ { "/dev/sound/dsp1", 0 },
+ { "/dev/sound/mixer", 0 },
+ { "/dev/sound/midi", 0 },
+ { "/dev/usb", 0 },
+ { "/dev/root", 0 },
+ { "/dev/initctl", 0 },
+ { "/dev/xconsole", 0 },
+ { "/dev/fd", 0 },
+ { "/dev/stdin", 0 },
+ { "/dev/stdout", 0 },
+ { "/dev/stderr", 0 },
+ { "/dev/route", 0 },
+ { "/dev/skip", 0 },
+ { "/dev/USERSOCK", 0 },
+ { "/dev/fwmonitor", 0 },
+ { "/dev/ARPD", 0 },
+ { "/dev/ROUTE6", 0 },
+ { "/dev/IP6_FW", 0 },
+ { "/dev/tap0", 0 },
+ { "/dev/tap1", 0 },
+ { "/dev/tap2", 0 },
+ { "/dev/tap3", 0 },
+ { "/dev/tap4", 0 },
+ { "/dev/tap5", 0 },
+ { "/dev/tap6", 0 },
+ { "/dev/tap7", 0 },
+ { "/dev/tap8", 0 },
+ { "/dev/tap9", 0 },
+ { "/dev/tap10", 0 },
+ { "/dev/tap11", 0 },
+ { "/dev/tap12", 0 },
+ { "/dev/tap13", 0 },
+ { "/dev/tap14", 0 },
+ { "/dev/tap15", 0 },
+ { "/dev/tty1", 0 },
+ { "/dev/tty2", 0 },
+ { "/dev/tty3", 0 },
+ { "/dev/tty4", 0 },
+ { "/dev/tty5", 0 },
+ { "/dev/tty6", 0 },
+ { "/dev/tty7", 0 },
+ { "/dev/tty8", 0 },
+ { "/dev/tty9", 0 },
+ { "/dev/tty10", 0 },
+ { "/dev/tty11", 0 },
+ { "/dev/tty12", 0 },
+ { "/dev/tty13", 0 },
+ { "/dev/tty14", 0 },
+ { "/dev/tty15", 0 },
+ { "/dev/tty16", 0 },
+ { "/dev/tty17", 0 },
+ { "/dev/tty18", 0 },
+ { "/dev/tty19", 0 },
+ { "/dev/tty20", 0 },
+ { "/dev/tty21", 0 },
+ { "/dev/tty22", 0 },
+ { "/dev/tty23", 0 },
+ { "/dev/tty24", 0 },
+ { "/dev/tty25", 0 },
+ { "/dev/tty26", 0 },
+ { "/dev/tty27", 0 },
+ { "/dev/tty28", 0 },
+ { "/dev/tty29", 0 },
+ { "/dev/tty30", 0 },
+ { "/dev/tty31", 0 },
+ { "/dev/tty32", 0 },
+ { "/dev/tty33", 0 },
+ { "/dev/tty34", 0 },
+ { "/dev/tty35", 0 },
+ { "/dev/tty36", 0 },
+ { "/dev/tty37", 0 },
+ { "/dev/tty38", 0 },
+ { "/dev/tty39", 0 },
+ { "/dev/tty40", 0 },
+ { "/dev/tty41", 0 },
+ { "/dev/tty42", 0 },
+ { "/dev/tty43", 0 },
+ { "/dev/tty44", 0 },
+ { "/dev/tty45", 0 },
+ { "/dev/tty46", 0 },
+ { "/dev/tty47", 0 },
+ { "/dev/tty48", 0 },
+ { "/dev/tty49", 0 },
+ { "/dev/tty50", 0 },
+ { "/dev/tty51", 0 },
+ { "/dev/tty52", 0 },
+ { "/dev/tty53", 0 },
+ { "/dev/tty54", 0 },
+ { "/dev/tty55", 0 },
+ { "/dev/tty56", 0 },
+ { "/dev/tty57", 0 },
+ { "/dev/tty58", 0 },
+ { "/dev/tty59", 0 },
+ { "/dev/tty60", 0 },
+ { "/dev/tty61", 0 },
+ { "/dev/tty62", 0 },
+ { "/dev/tty63", 0 },
+ { "/dev/tty0", 0 },
+ { "/dev/psaux", 0 },
+ { "/dev/ptyp0", 0 },
+ { "/dev/ptyp1", 0 },
+ { "/dev/ptyp2", 0 },
+ { "/dev/ptyp3", 0 },
+ { "/dev/ptyp4", 0 },
+ { "/dev/ptyp5", 0 },
+ { "/dev/ptyp6", 0 },
+ { "/dev/ptyp7", 0 },
+ { "/dev/ptyp8", 0 },
+ { "/dev/ptyp9", 0 },
+ { "/dev/ptypa", 0 },
+ { "/dev/ptypb", 0 },
+ { "/dev/ptypc", 0 },
+ { "/dev/ptypd", 0 },
+ { "/dev/ptype", 0 },
+ { "/dev/ptypf", 0 },
+ { "/dev/ptyq0", 0 },
+ { "/dev/ptyq1", 0 },
+ { "/dev/ptyq2", 0 },
+ { "/dev/ptyq3", 0 },
+ { "/dev/ptyq4", 0 },
+ { "/dev/ptyq5", 0 },
+ { "/dev/ptyq6", 0 },
+ { "/dev/ptyq7", 0 },
+ { "/dev/ptyq8", 0 },
+ { "/dev/ptyq9", 0 },
+ { "/dev/ptyqa", 0 },
+ { "/dev/ptyqb", 0 },
+ { "/dev/ptyqc", 0 },
+ { "/dev/ptyqd", 0 },
+ { "/dev/ptyqe", 0 },
+ { "/dev/ptyqf", 0 },
+ { "/dev/ptyr0", 0 },
+ { "/dev/ptyr1", 0 },
+ { "/dev/ptyr2", 0 },
+ { "/dev/ptyr3", 0 },
+ { "/dev/ptyr4", 0 },
+ { "/dev/ptyr5", 0 },
+ { "/dev/ptyr6", 0 },
+ { "/dev/ptyr7", 0 },
+ { "/dev/ptyr8", 0 },
+ { "/dev/ptyr9", 0 },
+ { "/dev/ptyra", 0 },
+ { "/dev/ptyrb", 0 },
+ { "/dev/ptyrc", 0 },
+ { "/dev/ptyrd", 0 },
+ { "/dev/ptyre", 0 },
+ { "/dev/ptyrf", 0 },
+ { "/dev/ptys0", 0 },
+ { "/dev/ptys1", 0 },
+ { "/dev/ptys2", 0 },
+ { "/dev/ptys3", 0 },
+ { "/dev/ptys4", 0 },
+ { "/dev/ptys5", 0 },
+ { "/dev/ptys6", 0 },
+ { "/dev/ptys7", 0 },
+ { "/dev/ptys8", 0 },
+ { "/dev/ptys9", 0 },
+ { "/dev/ptysa", 0 },
+ { "/dev/ptysb", 0 },
+ { "/dev/ptysc", 0 },
+ { "/dev/ptysd", 0 },
+ { "/dev/ptyse", 0 },
+ { "/dev/ptysf", 0 },
+ { "/dev/ptyt0", 0 },
+ { "/dev/ptyt1", 0 },
+ { "/dev/ptyt2", 0 },
+ { "/dev/ptyt3", 0 },
+ { "/dev/ptyt4", 0 },
+ { "/dev/ptyt5", 0 },
+ { "/dev/ptyt6", 0 },
+ { "/dev/ptyt7", 0 },
+ { "/dev/ptyt8", 0 },
+ { "/dev/ptyt9", 0 },
+ { "/dev/ptyta", 0 },
+ { "/dev/ptytb", 0 },
+ { "/dev/ptytc", 0 },
+ { "/dev/ptytd", 0 },
+ { "/dev/ptyte", 0 },
+ { "/dev/ptytf", 0 },
+ { "/dev/ptyu0", 0 },
+ { "/dev/ptyu1", 0 },
+ { "/dev/ptyu2", 0 },
+ { "/dev/ptyu3", 0 },
+ { "/dev/ptyu4", 0 },
+ { "/dev/ptyu5", 0 },
+ { "/dev/ptyu6", 0 },
+ { "/dev/ptyu7", 0 },
+ { "/dev/ptyu8", 0 },
+ { "/dev/ptyu9", 0 },
+ { "/dev/ptyua", 0 },
+ { "/dev/ptyub", 0 },
+ { "/dev/ptyuc", 0 },
+ { "/dev/ptyud", 0 },
+ { "/dev/ptyue", 0 },
+ { "/dev/ptyuf", 0 },
+ { "/dev/ptyv0", 0 },
+ { "/dev/ptyv1", 0 },
+ { "/dev/ptyv2", 0 },
+ { "/dev/ptyv3", 0 },
+ { "/dev/ptyv4", 0 },
+ { "/dev/ptyv5", 0 },
+ { "/dev/ptyv6", 0 },
+ { "/dev/ptyv7", 0 },
+ { "/dev/ptyv8", 0 },
+ { "/dev/ptyv9", 0 },
+ { "/dev/ptyva", 0 },
+ { "/dev/ptyvb", 0 },
+ { "/dev/ptyvc", 0 },
+ { "/dev/ptyvd", 0 },
+ { "/dev/ptyve", 0 },
+ { "/dev/ptyvf", 0 },
+ { "/dev/ptyw0", 0 },
+ { "/dev/ptyw1", 0 },
+ { "/dev/ptyw2", 0 },
+ { "/dev/ptyw3", 0 },
+ { "/dev/ptyw4", 0 },
+ { "/dev/ptyw5", 0 },
+ { "/dev/ptyw6", 0 },
+ { "/dev/ptyw7", 0 },
+ { "/dev/ptyw8", 0 },
+ { "/dev/ptyw9", 0 },
+ { "/dev/ptywa", 0 },
+ { "/dev/ptywb", 0 },
+ { "/dev/ptywc", 0 },
+ { "/dev/ptywd", 0 },
+ { "/dev/ptywe", 0 },
+ { "/dev/ptywf", 0 },
+ { "/dev/ptyx0", 0 },
+ { "/dev/ptyx1", 0 },
+ { "/dev/ptyx2", 0 },
+ { "/dev/ptyx3", 0 },
+ { "/dev/ptyx4", 0 },
+ { "/dev/ptyx5", 0 },
+ { "/dev/ptyx6", 0 },
+ { "/dev/ptyx7", 0 },
+ { "/dev/ptyx8", 0 },
+ { "/dev/ptyx9", 0 },
+ { "/dev/ptyxa", 0 },
+ { "/dev/ptyxb", 0 },
+ { "/dev/ptyxc", 0 },
+ { "/dev/ptyxd", 0 },
+ { "/dev/ptyxe", 0 },
+ { "/dev/ptyxf", 0 },
+ { "/dev/ptyy0", 0 },
+ { "/dev/ptyy1", 0 },
+ { "/dev/ptyy2", 0 },
+ { "/dev/ptyy3", 0 },
+ { "/dev/ptyy4", 0 },
+ { "/dev/ptyy5", 0 },
+ { "/dev/ptyy6", 0 },
+ { "/dev/ptyy7", 0 },
+ { "/dev/ptyy8", 0 },
+ { "/dev/ptyy9", 0 },
+ { "/dev/ptyya", 0 },
+ { "/dev/ptyyb", 0 },
+ { "/dev/ptyyc", 0 },
+ { "/dev/ptyyd", 0 },
+ { "/dev/ptyye", 0 },
+ { "/dev/ptyyf", 0 },
+ { "/dev/ptyz0", 0 },
+ { "/dev/ptyz1", 0 },
+ { "/dev/ptyz2", 0 },
+ { "/dev/ptyz3", 0 },
+ { "/dev/ptyz4", 0 },
+ { "/dev/ptyz5", 0 },
+ { "/dev/ptyz6", 0 },
+ { "/dev/ptyz7", 0 },
+ { "/dev/ptyz8", 0 },
+ { "/dev/ptyz9", 0 },
+ { "/dev/ptyza", 0 },
+ { "/dev/ptyzb", 0 },
+ { "/dev/ptyzc", 0 },
+ { "/dev/ptyzd", 0 },
+ { "/dev/ptyze", 0 },
+ { "/dev/ptyzf", 0 },
+ { "/dev/ptya0", 0 },
+ { "/dev/ptya1", 0 },
+ { "/dev/ptya2", 0 },
+ { "/dev/ptya3", 0 },
+ { "/dev/ptya4", 0 },
+ { "/dev/ptya5", 0 },
+ { "/dev/ptya6", 0 },
+ { "/dev/ptya7", 0 },
+ { "/dev/ptya8", 0 },
+ { "/dev/ptya9", 0 },
+ { "/dev/ptyaa", 0 },
+ { "/dev/ptyab", 0 },
+ { "/dev/ptyac", 0 },
+ { "/dev/ptyad", 0 },
+ { "/dev/ptyae", 0 },
+ { "/dev/ptyaf", 0 },
+ { "/dev/ptyb0", 0 },
+ { "/dev/ptyb1", 0 },
+ { "/dev/ptyb2", 0 },
+ { "/dev/ptyb3", 0 },
+ { "/dev/ptyb4", 0 },
+ { "/dev/ptyb5", 0 },
+ { "/dev/ptyb6", 0 },
+ { "/dev/ptyb7", 0 },
+ { "/dev/ptyb8", 0 },
+ { "/dev/ptyb9", 0 },
+ { "/dev/ptyba", 0 },
+ { "/dev/ptybb", 0 },
+ { "/dev/ptybc", 0 },
+ { "/dev/ptybd", 0 },
+ { "/dev/ptybe", 0 },
+ { "/dev/ptybf", 0 },
+ { "/dev/ptyc0", 0 },
+ { "/dev/ptyc1", 0 },
+ { "/dev/ptyc2", 0 },
+ { "/dev/ptyc3", 0 },
+ { "/dev/ptyc4", 0 },
+ { "/dev/ptyc5", 0 },
+ { "/dev/ptyc6", 0 },
+ { "/dev/ptyc7", 0 },
+ { "/dev/ptyc8", 0 },
+ { "/dev/ptyc9", 0 },
+ { "/dev/ptyca", 0 },
+ { "/dev/ptycb", 0 },
+ { "/dev/ptycc", 0 },
+ { "/dev/ptycd", 0 },
+ { "/dev/ptyce", 0 },
+ { "/dev/ptycf", 0 },
+ { "/dev/ptyd0", 0 },
+ { "/dev/ptyd1", 0 },
+ { "/dev/ptyd2", 0 },
+ { "/dev/ptyd3", 0 },
+ { "/dev/ptyd4", 0 },
+ { "/dev/ptyd5", 0 },
+ { "/dev/ptyd6", 0 },
+ { "/dev/ptyd7", 0 },
+ { "/dev/ptyd8", 0 },
+ { "/dev/ptyd9", 0 },
+ { "/dev/ptyda", 0 },
+ { "/dev/ptydb", 0 },
+ { "/dev/ptydc", 0 },
+ { "/dev/ptydd", 0 },
+ { "/dev/ptyde", 0 },
+ { "/dev/ptydf", 0 },
+ { "/dev/ptye0", 0 },
+ { "/dev/ptye1", 0 },
+ { "/dev/ptye2", 0 },
+ { "/dev/ptye3", 0 },
+ { "/dev/ptye4", 0 },
+ { "/dev/ptye5", 0 },
+ { "/dev/ptye6", 0 },
+ { "/dev/ptye7", 0 },
+ { "/dev/ptye8", 0 },
+ { "/dev/ptye9", 0 },
+ { "/dev/ptyea", 0 },
+ { "/dev/ptyeb", 0 },
+ { "/dev/ptyec", 0 },
+ { "/dev/ptyed", 0 },
+ { "/dev/ptyee", 0 },
+ { "/dev/ptyef", 0 },
+ { "/dev/vcs", 0 },
+ { "/dev/vcsa", 0 },
+ { "/dev/vcs1", 0 },
+ { "/dev/vcsa1", 0 },
+ { "/dev/ttyS0", 0 },
+ { "/dev/cua0", 0 },
+ { "/dev/hda", 0 },
+ { "/dev/hda1", 2 },
+ { "/dev/hda2", 2 },
+ { "/dev/hda3", 2 },
+ { "/dev/hda4", 2 },
+ { "/dev/hda5", 2 },
+ { "/dev/hda6", 0 },
+ { "/dev/hda7", 0 },
+ { "/dev/hda8", 0 },
+ { "/dev/hdb", 0 },
+ { "/dev/hdb1", 2 },
+ { "/dev/hdc", 0 },
+ { "/dev/hdc1", 2 },
+ { "/dev/fd0u1440", 0 },
+ { "/dev/fd0u1680", 0 },
+ { "/dev/fd0u1722", 0 },
+ { "/dev/fd0u1743", 0 },
+ { "/dev/fd0u1760", 0 },
+ { "/dev/fd0u1920", 0 },
+ { "/dev/fd0u1840", 0 },
+ { "/dev/fd0u1600", 0 },
+ { "/dev/fd0u360", 0 },
+ { "/dev/fd0u720", 0 },
+ { "/dev/fd0u820", 0 },
+ { "/dev/fd0u830", 0 },
+ { "/dev/fd0u1040", 0 },
+ { "/dev/fd0u1120", 0 },
+ { "/dev/fd0u800", 0 },
+ { "/dev/fd0", 0 },
+ { "/dev/loop0", 0 },
+ { "/dev/loop1", 0 },
+ { "/dev/loop2", 0 },
+ { "/dev/loop3", 0 },
+ { "/dev/loop4", 0 },
+ { "/dev/loop5", 0 },
+ { "/dev/loop6", 0 },
+ { "/dev/loop7", 0 },
+ { "/dev/dsp", 0 },
+ { "/dev/dsp1", 0 },
+ { "/dev/mixer", 0 },
+ { "/dev/midi", 0 },
+ { "/dev/lvm", 0 },
+ { "/dev/vg0", 0 },
+ { "/dev/vg0/group", 0 },
+ { "/dev/vg0/packages", 0 },
+ { "/dev/vg0/photos", 0 },
+ { "/dev/vg0/music", 0 },
+ { "/dev/log", 0 },
+ { "/dev/MAKEDEV", 0 },
+ { "/dev/printer", 0 },
+ { "/dev/vcs2", 0 },
+ { "/dev/vcsa2", 0 },
+ { "/dev/vcs3", 0 },
+ { "/dev/vcsa3", 0 },
+ { "/dev/vcs5", 0 },
+ { "/dev/vcsa5", 0 },
+ { "/dev/vcs4", 0 },
+ { "/dev/vcsa4", 0 },
+ { "/dev/vcs6", 0 },
+ { "/dev/vcsa6", 0 },
+ { "/dev/nvidia0", 0 },
+ { "/dev/nvidia1", 0 },
+ { "/dev/nvidia2", 0 },
+ { "/dev/nvidia3", 0 },
+ { "/dev/nvidiactl", 0 },
+ { "/dev/vcs7", 0 },
+ { "/dev/vcsa7", 0 },
+ { NULL, 0 }
+};
diff --git a/unit-test/matcher_t.c b/unit-test/matcher_t.c
new file mode 100644
index 0000000..a5eb5f9
--- /dev/null
+++ b/unit-test/matcher_t.c
@@ -0,0 +1,89 @@
+/*
+ * Copyright (C) 2001-2004 Sistina Software, Inc. All rights reserved.
+ * Copyright (C) 2004-2010 Red Hat, Inc. All rights reserved.
+ *
+ * This file is part of LVM2.
+ *
+ * This copyrighted material is made available to anyone wishing to use,
+ * modify, copy, or redistribute it subject to the terms and conditions
+ * of the GNU General Public License v.2.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+#include "units.h"
+#include "libdevmapper.h"
+
+#include "matcher_data.h"
+
+static void *_mem_init(void)
+{
+ struct dm_pool *mem = dm_pool_create("bitset test", 1024);
+ if (!mem) {
+ fprintf(stderr, "out of memory");
+ exit(1);
+ }
+
+ return mem;
+}
+
+static void _mem_exit(void *mem)
+{
+ dm_pool_destroy(mem);
+}
+
+static struct dm_regex *make_scanner(struct dm_pool *mem, const char **rx)
+{
+ struct dm_regex *scanner;
+ int nrx = 0;
+ for (; rx[nrx]; ++nrx);
+
+ scanner = dm_regex_create(mem, rx, nrx);
+ T_ASSERT(scanner != NULL);
+ return scanner;
+}
+
+static void test_fingerprints(void *fixture)
+{
+ struct dm_pool *mem = fixture;
+ struct dm_regex *scanner;
+
+ scanner = make_scanner(mem, dev_patterns);
+ T_ASSERT_EQUAL(dm_regex_fingerprint(scanner), 0x7f556c09);
+
+ scanner = make_scanner(mem, random_patterns);
+ T_ASSERT_EQUAL(dm_regex_fingerprint(scanner), 0x9f11076c);
+}
+
+static void test_matching(void *fixture)
+{
+ struct dm_pool *mem = fixture;
+ struct dm_regex *scanner;
+ int i;
+
+ scanner = make_scanner(mem, dev_patterns);
+ for (i = 0; devices[i].str; ++i)
+ T_ASSERT_EQUAL(dm_regex_match(scanner, devices[i].str), devices[i].expected - 1);
+
+ scanner = make_scanner(mem, nonprint_patterns);
+ for (i = 0; nonprint[i].str; ++i)
+ T_ASSERT_EQUAL(dm_regex_match(scanner, nonprint[i].str), nonprint[i].expected - 1);
+}
+
+#define T(path, desc, fn) register_test(ts, "/base/regex/" path, desc, fn)
+
+void regex_tests(struct dm_list *all_tests)
+{
+ struct test_suite *ts = test_suite_create(_mem_init, _mem_exit);
+ if (!ts) {
+ fprintf(stderr, "out of memory\n");
+ exit(1);
+ }
+
+ T("fingerprints", "not sure", test_fingerprints);
+ T("matching", "test the matcher with a variety of regexes", test_matching);
+
+ dm_list_add(all_tests, &ts->list);
+}
diff --git a/unit-test/percent_t.c b/unit-test/percent_t.c
new file mode 100644
index 0000000..84dd3bd
--- /dev/null
+++ b/unit-test/percent_t.c
@@ -0,0 +1,102 @@
+/*
+ * Copyright (C) 2017 Red Hat, Inc. All rights reserved.
+ *
+ * This file is part of LVM2.
+ *
+ * This copyrighted material is made available to anyone wishing to use,
+ * modify, copy, or redistribute it subject to the terms and conditions
+ * of the GNU General Public License v.2.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+#include "units.h"
+#include "libdevmapper.h"
+
+#include <stdio.h>
+#include <string.h>
+
+static void test_percent_100(void *fixture)
+{
+ char buf[32];
+
+ /* Check 100% is shown only for DM_PERCENT_100*/
+ dm_percent_t p_100 = dm_make_percent(100, 100);
+ dm_percent_t p1_100 = dm_make_percent(100000, 100000);
+ dm_percent_t n_100 = dm_make_percent(999999, 1000000);
+
+ T_ASSERT_EQUAL(p_100, DM_PERCENT_100);
+ T_ASSERT_EQUAL(p1_100, DM_PERCENT_100);
+ T_ASSERT_NOT_EQUAL(n_100, DM_PERCENT_100);
+
+ dm_snprintf(buf, sizeof(buf), "%.2f", dm_percent_to_float(p_100));
+ T_ASSERT_EQUAL(strcmp(buf, "100.00"), 0);
+
+ dm_snprintf(buf, sizeof(buf), "%.2f", dm_percent_to_float(p1_100));
+ T_ASSERT_EQUAL(strcmp(buf, "100.00"), 0);
+
+ dm_snprintf(buf, sizeof(buf), "%.2f", dm_percent_to_float(n_100));
+ T_ASSERT_NOT_EQUAL(strcmp(buf, "99.99"), 0); /* Would like to gett */
+
+ dm_snprintf(buf, sizeof(buf), "%.2f", dm_percent_to_round_float(n_100, 2));
+ T_ASSERT_EQUAL(strcmp(buf, "99.99"), 0);
+
+ dm_snprintf(buf, sizeof(buf), "%.3f", dm_percent_to_round_float(n_100, 3));
+ T_ASSERT_EQUAL(strcmp(buf, "99.999"), 0);
+
+ dm_snprintf(buf, sizeof(buf), "%.4f", dm_percent_to_round_float(n_100, 4));
+ T_ASSERT_EQUAL(strcmp(buf, "99.9999"), 0);
+
+ dm_snprintf(buf, sizeof(buf), "%d", (int)dm_percent_to_round_float(n_100, 0));
+ T_ASSERT_EQUAL(strcmp(buf, "99"), 0);
+}
+
+static void test_percent_0(void *fixture)
+{
+ char buf[32];
+
+ /* Check 0% is shown only for DM_PERCENT_0 */
+ dm_percent_t p_0 = dm_make_percent(0, 100);
+ dm_percent_t p1_0 = dm_make_percent(0, 100000);
+ dm_percent_t n_0 = dm_make_percent(1, 1000000);
+
+ T_ASSERT_EQUAL(p_0, DM_PERCENT_0);
+ T_ASSERT_EQUAL(p1_0, DM_PERCENT_0);
+ T_ASSERT_NOT_EQUAL(n_0, DM_PERCENT_0);
+
+ dm_snprintf(buf, sizeof(buf), "%.2f", dm_percent_to_float(p_0));
+ T_ASSERT_EQUAL(strcmp(buf, "0.00"), 0);
+
+ dm_snprintf(buf, sizeof(buf), "%.2f", dm_percent_to_float(p1_0));
+ T_ASSERT_EQUAL(strcmp(buf, "0.00"), 0);
+
+ dm_snprintf(buf, sizeof(buf), "%.2f", dm_percent_to_float(n_0));
+ T_ASSERT_NOT_EQUAL(strcmp(buf, "0.01"), 0);
+
+ dm_snprintf(buf, sizeof(buf), "%.2f", dm_percent_to_round_float(n_0, 2));
+ T_ASSERT_EQUAL(strcmp(buf, "0.01"), 0);
+
+ dm_snprintf(buf, sizeof(buf), "%.3f", dm_percent_to_round_float(n_0, 3));
+ T_ASSERT_EQUAL(strcmp(buf, "0.001"), 0);
+
+ dm_snprintf(buf, sizeof(buf), "%d", (int)dm_percent_to_round_float(n_0, 0));
+ T_ASSERT_EQUAL(strcmp(buf, "1"), 0);
+}
+
+#define T(path, desc, fn) register_test(ts, "/base/formatting/percent/" path, desc, fn)
+
+void percent_tests(struct dm_list *all_tests)
+{
+ struct test_suite *ts = test_suite_create(NULL, NULL);
+ if (!ts) {
+ fprintf(stderr, "out of memory\n");
+ exit(1);
+ }
+
+ T("100", "Pretty printing of percentages near 100%", test_percent_100);
+ T("0", "Pretty printing of percentages near 0%", test_percent_0);
+
+ dm_list_add(all_tests, &ts->list);
+}
diff --git a/unit-test/run.c b/unit-test/run.c
new file mode 100644
index 0000000..9cbb605
--- /dev/null
+++ b/unit-test/run.c
@@ -0,0 +1,309 @@
+#include "units.h"
+
+#include <getopt.h>
+#include <regex.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <setjmp.h>
+#include <unistd.h>
+
+//-----------------------------------------------------------------
+
+#define MAX_COMPONENTS 16
+
+struct token {
+ const char *b, *e;
+};
+
+static bool _pop_component(const char *path, struct token *result)
+{
+ const char *b, *e;
+
+ while (*path && *path == '/')
+ path++;
+
+ b = path;
+ while (*path && (*path != '/'))
+ path++;
+ e = path;
+
+ if (b == e)
+ return false;
+
+ result->b = b;
+ result->e = e;
+ return true;
+}
+
+static unsigned _split_components(const char *path, struct token *toks, unsigned len)
+{
+ unsigned count = 0;
+ struct token tok;
+ tok.e = path;
+
+ while (len && _pop_component(tok.e, &tok)) {
+ *toks = tok;
+ toks++;
+ count++;
+ len--;
+ }
+
+ return count;
+}
+
+static void _indent(FILE *stream, unsigned count)
+{
+ unsigned i;
+
+ for (i = 0; i < count; i++)
+ fprintf(stream, " ");
+}
+
+static void _print_token(FILE *stream, struct token *t)
+{
+ const char *ptr;
+
+ for (ptr = t->b; ptr != t->e; ptr++)
+ fprintf(stream, "%c", *ptr);
+}
+
+static int _char_cmp(char l, char r)
+{
+ if (l < r)
+ return -1;
+
+ else if (r < l)
+ return 1;
+
+ else
+ return 0;
+}
+
+static int _tok_cmp(struct token *lhs, struct token *rhs)
+{
+ const char *l = lhs->b, *le = lhs->e;
+ const char *r = rhs->b, *re = rhs->e;
+
+ while ((l != le) && (r != re) && (*l == *r)) {
+ l++;
+ r++;
+ }
+
+ if ((l != le) && (r != re))
+ return _char_cmp(*l, *r);
+
+ else if (r != re)
+ return -1;
+
+ else if (l != le)
+ return 1;
+
+ else
+ return 0;
+}
+
+static void _print_path_delta(FILE *stream,
+ struct token *old, unsigned old_len,
+ struct token *new, unsigned new_len,
+ const char *desc)
+{
+ unsigned i, common_prefix = 0, len, d;
+ unsigned max_prefix = old_len < new_len ? old_len : new_len;
+
+ for (i = 0; i < max_prefix; i++) {
+ if (_tok_cmp(old + i, new + i))
+ break;
+ else
+ common_prefix++;
+ }
+
+ for (; i < new_len; i++) {
+ _indent(stream, common_prefix);
+ _print_token(stream, new + i);
+ common_prefix++;
+ if (i < new_len - 1)
+ fprintf(stream, "\n");
+ }
+
+ len = common_prefix * 2 + (new[new_len - 1].e - new[new_len - 1].b);
+ fprintf(stream, " ");
+ for (d = len; d < 60; d++)
+ fprintf(stream, ".");
+ fprintf(stream, " ");
+ fprintf(stream, "%s", desc);
+ fprintf(stream, "\n");
+}
+
+typedef struct token comp_t[MAX_COMPONENTS];
+
+static void _list_tests(struct test_details **tests, unsigned nr)
+{
+ unsigned i, current = 0, current_len, last_len = 0;
+
+ comp_t components[2];
+
+ for (i = 0; i < nr; i++) {
+ struct test_details *t = tests[i];
+ current_len = _split_components(t->path, components[current], MAX_COMPONENTS);
+ _print_path_delta(stderr, components[!current], last_len,
+ components[current], current_len, t->desc);
+
+ last_len = current_len;
+ current = !current;
+ }
+}
+
+static void _destroy_tests(struct dm_list *suites)
+{
+ struct test_suite *ts, *tmp;
+
+ dm_list_iterate_items_safe (ts, tmp, suites)
+ test_suite_destroy(ts);
+}
+
+static const char *red(bool c)
+{
+ return c ? "\x1B[31m" : "";
+}
+
+static const char *green(bool c)
+{
+ return c ? "\x1B[32m" : "";
+}
+
+static const char *normal(bool c)
+{
+ return c ? "\x1B[0m" : "";
+}
+
+static void _run_test(struct test_details *t, bool use_colour, unsigned *passed, unsigned *total)
+{
+ void *fixture;
+ struct test_suite *ts = t->parent;
+ fprintf(stderr, "[RUN ] %s\n", t->path);
+
+ (*total)++;
+ if (setjmp(test_k))
+ fprintf(stderr, "%s[ FAIL]%s %s\n", red(use_colour), normal(use_colour), t->path);
+ else {
+ if (ts->fixture_init)
+ fixture = ts->fixture_init();
+ else
+ fixture = NULL;
+
+ t->fn(fixture);
+
+ if (ts->fixture_exit)
+ ts->fixture_exit(fixture);
+
+ (*passed)++;
+ fprintf(stderr, "%s[ OK]%s\n", green(use_colour), normal(use_colour));
+ }
+}
+
+static bool _run_tests(struct test_details **tests, unsigned nr)
+{
+ bool use_colour = isatty(fileno(stderr));
+ unsigned i, passed = 0, total = 0;
+
+ for (i = 0; i < nr; i++)
+ _run_test(tests[i], use_colour, &passed, &total);
+
+ fprintf(stderr, "\n%u/%u tests passed\n", passed, total);
+
+ return passed == total;
+}
+
+static void _usage(void)
+{
+ fprintf(stderr, "Usage: unit-test <list|run> [pattern]\n");
+}
+
+static int _cmp_paths(const void *lhs, const void *rhs)
+{
+ struct test_details *l = *((struct test_details **) lhs);
+ struct test_details *r = *((struct test_details **) rhs);
+
+ return strcmp(l->path, r->path);
+}
+
+static unsigned _filter(const char *pattern, struct test_details **tests, unsigned nr)
+{
+ unsigned i, found = 0;
+ regex_t rx;
+
+ if (regcomp(&rx, pattern, 0)) {
+ fprintf(stderr, "couldn't compile regex '%s'\n", pattern);
+ exit(1);
+ }
+
+ for (i = 0; i < nr; i++)
+ if (!regexec(&rx, tests[i]->path, 0, NULL, 0))
+ tests[found++] = tests[i];
+
+ regfree(&rx);
+
+ return found;
+}
+
+int main(int argc, char **argv)
+{
+ int r;
+ unsigned i, nr_tests;
+ struct test_suite *ts;
+ struct test_details *t, **t_array;
+ struct dm_list suites;
+
+ dm_list_init(&suites);
+ register_all_tests(&suites);
+
+ // count all tests
+ nr_tests = 0;
+ dm_list_iterate_items (ts, &suites)
+ dm_list_iterate_items (t, &ts->tests)
+ nr_tests++;
+
+ // stick them in an array
+ t_array = malloc(sizeof(*t_array) * nr_tests);
+ if (!t_array) {
+ fprintf(stderr, "out of memory\n");
+ exit(1);
+ }
+
+ i = 0;
+ dm_list_iterate_items (ts, &suites)
+ dm_list_iterate_items (t, &ts->tests)
+ t_array[i++] = t;
+
+ // filter
+ if (argc == 3)
+ nr_tests = _filter(argv[2], t_array, nr_tests);
+
+ // sort
+ qsort(t_array, nr_tests, sizeof(*t_array), _cmp_paths);
+
+ // run or list them
+ if (argc == 1)
+ r = !_run_tests(t_array, nr_tests);
+ else {
+ const char *cmd = argv[1];
+ if (!strcmp(cmd, "run"))
+ r = !_run_tests(t_array, nr_tests);
+
+ else if (!strcmp(cmd, "list")) {
+ _list_tests(t_array, nr_tests);
+ r = 0;
+
+ } else {
+ _usage();
+ r = 1;
+ }
+ }
+
+ free(t_array);
+ _destroy_tests(&suites);
+
+ return r;
+}
+
+//-----------------------------------------------------------------
diff --git a/unit-test/string_t.c b/unit-test/string_t.c
new file mode 100644
index 0000000..2af0f37
--- /dev/null
+++ b/unit-test/string_t.c
@@ -0,0 +1,91 @@
+/*
+ * Copyright (C) 2012 Red Hat, Inc. All rights reserved.
+ *
+ * This file is part of LVM2.
+ *
+ * This copyrighted material is made available to anyone wishing to use,
+ * modify, copy, or redistribute it subject to the terms and conditions
+ * of the GNU General Public License v.2.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+#include "units.h"
+#include "libdevmapper.h"
+
+#include <stdio.h>
+#include <string.h>
+
+#if 0
+static int _mem_init(void)
+{
+ struct dm_pool *mem = dm_pool_create("string test", 1024);
+ if (!mem) {
+ fprintf(stderr, "out of memory\n");
+ exit(1);
+ }
+
+ return mem;
+}
+
+static void _mem_exit(void *mem)
+{
+ dm_pool_destroy(mem);
+}
+
+/* TODO: Add more string unit tests here */
+#endif
+
+static void test_strncpy(void *fixture)
+{
+ const char st[] = "1234567890";
+ char buf[sizeof(st)];
+
+ T_ASSERT_EQUAL(dm_strncpy(buf, st, sizeof(buf)), 1);
+ T_ASSERT_EQUAL(strcmp(buf, st), 0);
+
+ T_ASSERT_EQUAL(dm_strncpy(buf, st, sizeof(buf) - 1), 0);
+ T_ASSERT_EQUAL(strlen(buf) + 1, sizeof(buf) - 1);
+}
+
+static void test_asprint(void *fixture)
+{
+ const char st0[] = "";
+ const char st1[] = "12345678901";
+ const char st2[] = "1234567890123456789012345678901234567890123456789012345678901234567";
+ char *buf;
+ int a;
+
+ a = dm_asprintf(&buf, "%s", st0);
+ T_ASSERT_EQUAL(strcmp(buf, st0), 0);
+ T_ASSERT_EQUAL(a, sizeof(st0));
+ free(buf);
+
+ a = dm_asprintf(&buf, "%s", st1);
+ T_ASSERT_EQUAL(strcmp(buf, st1), 0);
+ T_ASSERT_EQUAL(a, sizeof(st1));
+ free(buf);
+
+ a = dm_asprintf(&buf, "%s", st2);
+ T_ASSERT_EQUAL(a, sizeof(st2));
+ T_ASSERT_EQUAL(strcmp(buf, st2), 0);
+ free(buf);
+}
+
+#define T(path, desc, fn) register_test(ts, "/base/data-struct/string/" path, desc, fn)
+
+void string_tests(struct dm_list *all_tests)
+{
+ struct test_suite *ts = test_suite_create(NULL, NULL);
+ if (!ts) {
+ fprintf(stderr, "out of memory\n");
+ exit(1);
+ }
+
+ T("asprint", "tests asprint", test_asprint);
+ T("strncpy", "tests string copying", test_strncpy);
+
+ dm_list_add(all_tests, &ts->list);
+}
diff --git a/unit-test/units.h b/unit-test/units.h
new file mode 100644
index 0000000..47f04c2
--- /dev/null
+++ b/unit-test/units.h
@@ -0,0 +1,46 @@
+/*
+ * Copyright (C) 2018 Red Hat, Inc. All rights reserved.
+ *
+ * This file is part of LVM2.
+ *
+ * This copyrighted material is made available to anyone wishing to use,
+ * modify, copy, or redistribute it subject to the terms and conditions
+ * of the GNU General Public License v.2.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+#ifndef TEST_UNIT_UNITS_H
+#define TEST_UNIT_UNITS_H
+
+#include "framework.h"
+
+//-----------------------------------------------------------------
+
+// Declare the function that adds tests suites here ...
+void bcache_tests(struct dm_list *suites);
+void bitset_tests(struct dm_list *suites);
+void config_tests(struct dm_list *suites);
+void dm_list_tests(struct dm_list *suites);
+void dm_status_tests(struct dm_list *suites);
+void regex_tests(struct dm_list *suites);
+void percent_tests(struct dm_list *suites);
+void string_tests(struct dm_list *suites);
+
+// ... and call it in here.
+static inline void register_all_tests(struct dm_list *suites)
+{
+ bcache_tests(suites);
+ bitset_tests(suites);
+ config_tests(suites);
+ dm_list_tests(suites);
+ dm_status_tests(suites);
+ regex_tests(suites);
+ percent_tests(suites);
+ string_tests(suites);
+}
+
+//-----------------------------------------------------------------
+#endif
5 years, 11 months
master - pvmove: in fork mode destroy bcache in child
by David Teigland
Gitweb: https://sourceware.org/git/?p=lvm2.git;a=commitdiff;h=c7fdacbc5001f3bdfaa...
Commit: c7fdacbc5001f3bdfaa441fedb7da120af5d8af9
Parent: 0fe4f65f65faf9c61017bb14e281108b41165185
Author: David Teigland <teigland(a)redhat.com>
AuthorDate: Wed Apr 25 16:23:55 2018 -0500
Committer: David Teigland <teigland(a)redhat.com>
CommitterDate: Wed Apr 25 16:40:36 2018 -0500
pvmove: in fork mode destroy bcache in child
When pvmove was run in background mode and forks
instead of using lvmpolld, the child pvmove process
was not clearing the bcache from the parent, so all
the aio ops in the child were failing.
---
tools/polldaemon.c | 9 +++++++--
1 files changed, 7 insertions(+), 2 deletions(-)
diff --git a/tools/polldaemon.c b/tools/polldaemon.c
index 83f0424..5b5f57f 100644
--- a/tools/polldaemon.c
+++ b/tools/polldaemon.c
@@ -377,8 +377,6 @@ static void _poll_for_all_vgs(struct cmd_context *cmd,
process_each_vg(cmd, 0, NULL, NULL, NULL, READ_FOR_UPDATE, 0, handle, _poll_vg);
if (!parms->outstanding_count)
break;
- if (parms->interval)
- dev_close_all();
_nanosleep(parms->interval, 1);
}
}
@@ -618,6 +616,12 @@ static int _poll_daemon(struct cmd_context *cmd, struct poll_operation_id *id,
/*
* Process one specific task or all incomplete tasks?
*/
+
+ /* clear lvmcache/bcache/fds from the parent */
+ lvmcache_destroy(cmd, 1, 0);
+ label_scan_destroy(cmd);
+ dev_close_all();
+
if (id) {
if (!wait_for_single_lv(cmd, id, parms)) {
stack;
@@ -626,6 +630,7 @@ static int _poll_daemon(struct cmd_context *cmd, struct poll_operation_id *id,
} else {
if (!parms->interval)
parms->interval = find_config_tree_int(cmd, activation_polling_interval_CFG, NULL);
+
if (!(handle = init_processing_handle(cmd, NULL))) {
log_error("Failed to initialize processing handle.");
ret = ECMD_FAILED;
5 years, 11 months
master - scan: don't use cmd mem pool in scan
by David Teigland
Gitweb: https://sourceware.org/git/?p=lvm2.git;a=commitdiff;h=0fe4f65f65faf9c6101...
Commit: 0fe4f65f65faf9c61017bb14e281108b41165185
Parent: 4670e9f698099bf1b9612d16855f9207c0e0f467
Author: David Teigland <teigland(a)redhat.com>
AuthorDate: Wed Apr 25 15:48:19 2018 -0500
Committer: David Teigland <teigland(a)redhat.com>
CommitterDate: Wed Apr 25 16:40:08 2018 -0500
scan: don't use cmd mem pool in scan
Make it consistent with all the other allocations
in scanning.
---
lib/label/label.c | 2 +-
1 files changed, 1 insertions(+), 1 deletions(-)
diff --git a/lib/label/label.c b/lib/label/label.c
index 4b18f56..97e2a0b 100644
--- a/lib/label/label.c
+++ b/lib/label/label.c
@@ -639,7 +639,7 @@ int label_scan(struct cmd_context *cmd)
}
while ((dev = dev_iter_get(iter))) {
- if (!(devl = dm_pool_zalloc(cmd->mem, sizeof(*devl))))
+ if (!(devl = dm_zalloc(sizeof(*devl))))
return 0;
devl->dev = dev;
dm_list_add(&all_devs, &devl->list);
5 years, 11 months
master - skip some clvmd-specific code in common cases
by David Teigland
Gitweb: https://sourceware.org/git/?p=lvm2.git;a=commitdiff;h=4670e9f698099bf1b96...
Commit: 4670e9f698099bf1b9612d16855f9207c0e0f467
Parent: 47bfac21cab25b104170bf31e4fec84096bf90a5
Author: David Teigland <teigland(a)redhat.com>
AuthorDate: Wed Apr 25 15:08:54 2018 -0500
Committer: David Teigland <teigland(a)redhat.com>
CommitterDate: Wed Apr 25 16:40:08 2018 -0500
skip some clvmd-specific code in common cases
This, or something like it, can probably be done
in many other places.
---
daemons/clvmd/lvm-functions.c | 1 +
lib/activate/activate.c | 9 +++++++--
lib/cache/lvmcache.c | 2 --
lib/commands/toolcontext.h | 1 +
4 files changed, 9 insertions(+), 4 deletions(-)
diff --git a/daemons/clvmd/lvm-functions.c b/daemons/clvmd/lvm-functions.c
index 6254122..7e7b992 100644
--- a/daemons/clvmd/lvm-functions.c
+++ b/daemons/clvmd/lvm-functions.c
@@ -913,6 +913,7 @@ int init_clvm(struct dm_hash_table *excl_uuid)
return 0;
}
+ cmd->is_clvmd = 1;
cmd->cmd_line = "clvmd";
/* Check lvm.conf is setup for cluster-LVM */
diff --git a/lib/activate/activate.c b/lib/activate/activate.c
index eb04ef0..8e79cf5 100644
--- a/lib/activate/activate.c
+++ b/lib/activate/activate.c
@@ -2154,6 +2154,9 @@ static int _lv_suspend(struct cmd_context *cmd, const char *lvid_s,
if (!activation())
return 1;
+ if (!cmd->is_clvmd)
+ goto skip_read;
+
if (lv && lv_pre)
goto skip_read;
@@ -2223,8 +2226,10 @@ skip_read:
* did happen (or failed), and it will resume LVs using the
* new/precommitted metadata if the vg_commit succeeded.
*/
- lvmcache_save_vg(lv->vg, 0);
- lvmcache_save_vg(lv_pre->vg, 1);
+ if (cmd->is_clvmd) {
+ lvmcache_save_vg(lv->vg, 0);
+ lvmcache_save_vg(lv_pre->vg, 1);
+ }
if (!info.exists || info.suspended) {
if (!error_if_not_suspended) {
diff --git a/lib/cache/lvmcache.c b/lib/cache/lvmcache.c
index 4a7b6f9..7534567 100644
--- a/lib/cache/lvmcache.c
+++ b/lib/cache/lvmcache.c
@@ -246,8 +246,6 @@ static void _drop_metadata(const char *vgname, int drop_precommitted)
if (!(vginfo = lvmcache_vginfo_from_vgname(vgname, NULL)))
return;
- log_debug_cache("lvmcache: dropping saved_vg %s pre %d", vgname, drop_precommitted);
-
if (drop_precommitted)
_saved_vg_free(vginfo, 0, 1);
else
diff --git a/lib/commands/toolcontext.h b/lib/commands/toolcontext.h
index 2474264..1d9de0a 100644
--- a/lib/commands/toolcontext.h
+++ b/lib/commands/toolcontext.h
@@ -170,6 +170,7 @@ struct cmd_context {
unsigned mirror_warn_printed:1; /* command already printed warning about non-monitored mirrors */
unsigned pvscan_cache_single:1;
unsigned can_use_one_scan:1;
+ unsigned is_clvmd:1;
/*
* Filtering.
5 years, 11 months
master - clvmd: skip dev rescan after full scan
by David Teigland
Gitweb: https://sourceware.org/git/?p=lvm2.git;a=commitdiff;h=47bfac21cab25b10417...
Commit: 47bfac21cab25b104170bf31e4fec84096bf90a5
Parent: 1fec86571ff9133c0a24a794d1221a0fefde7670
Author: David Teigland <teigland(a)redhat.com>
AuthorDate: Tue Apr 24 14:48:30 2018 -0500
Committer: David Teigland <teigland(a)redhat.com>
CommitterDate: Wed Apr 25 16:39:43 2018 -0500
clvmd: skip dev rescan after full scan
When clvmd does a full label scan just prior to
calling _vg_read(), pass a new flag into _vg_read
to indicate that the normal rescan of VG devs is
not needed.
---
lib/metadata/metadata-exported.h | 1 +
lib/metadata/metadata.c | 8 ++++++++
2 files changed, 9 insertions(+), 0 deletions(-)
diff --git a/lib/metadata/metadata-exported.h b/lib/metadata/metadata-exported.h
index 73041cf..e8ecfd6 100644
--- a/lib/metadata/metadata-exported.h
+++ b/lib/metadata/metadata-exported.h
@@ -645,6 +645,7 @@ void pvcreate_params_set_defaults(struct pvcreate_params *pp);
*/
#define WARN_PV_READ 0x00000001
#define WARN_INCONSISTENT 0x00000002
+#define SKIP_RESCAN 0x00000004
/*
* Utility functions
diff --git a/lib/metadata/metadata.c b/lib/metadata/metadata.c
index a908658..3c1d8a4 100644
--- a/lib/metadata/metadata.c
+++ b/lib/metadata/metadata.c
@@ -3864,6 +3864,10 @@ static struct volume_group *_vg_read(struct cmd_context *cmd,
* we can also skip the rescan in that case.
*/
if (!cmd->can_use_one_scan || lvmcache_scan_mismatch(cmd, vgname, vgid)) {
+ /* the skip rescan special case is for clvmd vg_read_by_vgid */
+ /* FIXME: this is not a warn flag, pass this differently */
+ if (warn_flags & SKIP_RESCAN)
+ goto find_vg;
skipped_rescan = 0;
log_debug_metadata("Rescanning devices for for %s", vgname);
lvmcache_label_rescan_vg(cmd, vgname, vgid);
@@ -3872,6 +3876,8 @@ static struct volume_group *_vg_read(struct cmd_context *cmd,
skipped_rescan = 1;
}
+ find_vg:
+
if (!(fmt = lvmcache_fmt_from_vgname(cmd, vgname, vgid, 0))) {
log_debug_metadata("Cache did not find fmt for vgname %s", vgname);
return_NULL;
@@ -4593,6 +4599,7 @@ struct volume_group *vg_read_by_vgid(struct cmd_context *cmd,
lvmcache_destroy(cmd, 0, 0);
label_scan_destroy(cmd);
lvmcache_label_scan(cmd);
+ warn_flags |= SKIP_RESCAN;
}
if (!(vgname = lvmcache_vgname_from_vgid(cmd->mem, vgid))) {
@@ -4623,6 +4630,7 @@ struct volume_group *vg_read_by_vgid(struct cmd_context *cmd,
lvmcache_destroy(cmd, 0, 0);
label_scan_destroy(cmd);
lvmcache_label_scan(cmd);
+ warn_flags |= SKIP_RESCAN;
if (!(vg = _vg_read(cmd, vgname, vgid, warn_flags, &consistent, precommitted)))
goto fail;
5 years, 11 months
master - clvmd: reuse a vg struct for sequential LV operations
by David Teigland
Gitweb: https://sourceware.org/git/?p=lvm2.git;a=commitdiff;h=1fec86571ff9133c0a2...
Commit: 1fec86571ff9133c0a24a794d1221a0fefde7670
Parent: f8616ac2d87b247dd9ae041d59e6dbe43c88172c
Author: David Teigland <teigland(a)redhat.com>
AuthorDate: Tue Apr 24 13:19:48 2018 -0500
Committer: David Teigland <teigland(a)redhat.com>
CommitterDate: Wed Apr 25 16:39:43 2018 -0500
clvmd: reuse a vg struct for sequential LV operations
After reading a VG, stash it in lvmcache as "saved_vg".
Before reading the VG again, try to use the saved_vg.
The saved_vg is dropped on VG lock operations.
---
lib/activate/activate.c | 70 +++++++++++++++++++++++++++---------------
lib/cache/lvmcache.c | 78 ++++++++++++++++++++++++++++++++++++++++------
lib/cache/lvmcache.h | 4 ++-
lib/metadata/metadata.c | 19 ++++++++---
lib/metadata/metadata.h | 4 ++
lib/metadata/vg.c | 5 +++
lib/metadata/vg.h | 1 +
7 files changed, 139 insertions(+), 42 deletions(-)
diff --git a/lib/activate/activate.c b/lib/activate/activate.c
index 9211714..eb04ef0 100644
--- a/lib/activate/activate.c
+++ b/lib/activate/activate.c
@@ -29,6 +29,7 @@
#include "segtype.h"
#include "sharedlib.h"
#include "lvmcache.h"
+#include "metadata.h"
#include <limits.h>
#include <fcntl.h>
@@ -2144,11 +2145,52 @@ static int _lv_suspend(struct cmd_context *cmd, const char *lvid_s,
struct dm_pool *mem = NULL;
struct dm_list suspend_lvs;
struct lv_list *lvl;
+ const union lvid *lvid = (const union lvid *) lvid_s;
+ const char *vgid = (const char *)lvid->id[0].uuid;
+ struct volume_group *vg;
+ struct volume_group *vg_pre;
int found;
if (!activation())
return 1;
+ if (lv && lv_pre)
+ goto skip_read;
+
+ vg = lvmcache_get_saved_vg(vgid, 0);
+ vg_pre = lvmcache_get_saved_vg(vgid, 1);
+
+ if (!vg || !vg_pre) {
+ lvmcache_drop_saved_vgid(vgid);
+
+ vg = vg_read_by_vgid(cmd, vgid, 0);
+ vg_pre = vg_read_by_vgid(cmd, vgid, 1);
+
+ if (!vg || !vg_pre) {
+ log_error("lv_suspend could not find vgid %.8s vg %p vg_pre %p",
+ vgid, vg, vg_pre);
+ goto out;
+ }
+
+ log_debug("lv_suspend found vg %s vg %p vg_pre %p",
+ vg->name, vg, vg_pre);
+
+ if ((vg->status & EXPORTED_VG) || (vg_pre->status & EXPORTED_VG)) {
+ log_error("Volume group \"%s\" is exported", vg->name);
+ goto out;
+ }
+ }
+
+ lv = lv_to_free = find_lv_in_vg_by_lvid(vg, lvid);
+ lv_pre = lv_pre_to_free = find_lv_in_vg_by_lvid(vg_pre, lvid);
+
+ if (!lv || !lv_pre) {
+ log_error("lv_suspend could not find lv %p lv_pre %p vg %p vg_pre %p vgid %s",
+ lv, lv_pre, vg, vg_pre, vgid);
+ goto out;
+ }
+
+skip_read:
/* lv comes from committed metadata */
if (!lv && !(lv_to_free = lv = lv_from_lvid(cmd, lvid_s, 0)))
goto_out;
@@ -2405,16 +2447,16 @@ static int _lv_resume(struct cmd_context *cmd, const char *lvid_s,
* When called in clvmd, lvid_s is set and lv is not. We need to
* get the VG metadata without reading disks because devs are
* suspended. lv_suspend() saved old and new VG metadata for us
- * to use here. If vg_commit() happened, lvmcache_get_saved_vg
+ * to use here. If vg_commit() happened, lvmcache_get_saved_vg_latest
* will return the new metadata for us to use in resuming LVs.
- * If vg_commit() did not happen, lvmcache_get_saved_vg
+ * If vg_commit() did not happen, lvmcache_get_saved_vg_latest
* returns the old metadata which we use to resume LVs.
*/
if (!lv && lvid_s) {
lvid = (const union lvid *) lvid_s;
vgid = (const char *)lvid->id[0].uuid;
- if ((vg = lvmcache_get_saved_vg(vgid))) {
+ if ((vg = lvmcache_get_saved_vg_latest(vgid))) {
log_debug_activation("Resuming LVID %s found saved vg seqno %d %s", lvid_s, vg->seqno, vg->name);
if ((lv_found = find_lv_in_vg_by_lvid(vg, lvid))) {
log_debug_activation("Resuming LVID %s found saved LV %s", lvid_s, display_lvname(lv_found));
@@ -2635,10 +2677,6 @@ int lv_activation_filter(struct cmd_context *cmd, const char *lvid_s,
int *activate_lv, const struct logical_volume *lv)
{
const struct logical_volume *lv_to_free = NULL;
- struct volume_group *vg = NULL;
- struct logical_volume *lv_found = NULL;
- const union lvid *lvid;
- const char *vgid;
int r = 0;
if (!activation()) {
@@ -2646,24 +2684,6 @@ int lv_activation_filter(struct cmd_context *cmd, const char *lvid_s,
return 1;
}
- /*
- * This function is called while devices are suspended,
- * so try to use the copy of the vg that was saved in
- * lv_suspend.
- */
- if (!lv && lvid_s) {
- lvid = (const union lvid *) lvid_s;
- vgid = (const char *)lvid->id[0].uuid;
-
- if ((vg = lvmcache_get_saved_vg(vgid))) {
- log_debug_activation("activation_filter for %s found saved VG seqno %d %s", lvid_s, vg->seqno, vg->name);
- if ((lv_found = find_lv_in_vg_by_lvid(vg, lvid))) {
- log_debug_activation("activation_filter for %s found saved LV %s", lvid_s, display_lvname(lv_found));
- lv = lv_found;
- }
- }
- }
-
if (!lv && !(lv_to_free = lv = lv_from_lvid(cmd, lvid_s, 0)))
goto_out;
diff --git a/lib/cache/lvmcache.c b/lib/cache/lvmcache.c
index 7978b07..4a7b6f9 100644
--- a/lib/cache/lvmcache.c
+++ b/lib/cache/lvmcache.c
@@ -197,6 +197,14 @@ static void _update_cache_lock_state(const char *vgname, int locked)
static void _saved_vg_free(struct lvmcache_vginfo *vginfo, int free_old, int free_new)
{
if (free_old) {
+ if (vginfo->saved_vg_old) {
+ log_debug_cache("lvmcache: free saved_vg %s old %p",
+ vginfo->saved_vg_old->name,
+ vginfo->saved_vg_old);
+
+ vginfo->saved_vg_old->saved_in_clvmd = 0;
+ }
+
if (vginfo->saved_vg_old_buf)
dm_free(vginfo->saved_vg_old_buf);
if (vginfo->saved_vg_old_cft)
@@ -210,6 +218,14 @@ static void _saved_vg_free(struct lvmcache_vginfo *vginfo, int free_old, int fre
}
if (free_new) {
+ if (vginfo->saved_vg_new) {
+ log_debug_cache("lvmcache: free saved_vg %s new pre %p",
+ vginfo->saved_vg_new->name,
+ vginfo->saved_vg_new);
+
+ vginfo->saved_vg_new->saved_in_clvmd = 0;
+ }
+
if (vginfo->saved_vg_new_buf)
dm_free(vginfo->saved_vg_new_buf);
if (vginfo->saved_vg_new_cft)
@@ -230,6 +246,8 @@ static void _drop_metadata(const char *vgname, int drop_precommitted)
if (!(vginfo = lvmcache_vginfo_from_vgname(vgname, NULL)))
return;
+ log_debug_cache("lvmcache: dropping saved_vg %s pre %d", vgname, drop_precommitted);
+
if (drop_precommitted)
_saved_vg_free(vginfo, 0, 1);
else
@@ -241,7 +259,7 @@ void lvmcache_save_vg(struct volume_group *vg, int precommitted)
struct lvmcache_vginfo *vginfo;
struct format_instance *fid;
struct format_instance_ctx fic;
- struct volume_group *susp_vg = NULL;
+ struct volume_group *save_vg = NULL;
struct dm_config_tree *susp_cft = NULL;
char *susp_buf = NULL;
size_t size;
@@ -275,39 +293,67 @@ void lvmcache_save_vg(struct volume_group *vg, int precommitted)
if (!(susp_cft = config_tree_from_string_without_dup_node_check(susp_buf)))
goto_bad;
- if (!(susp_vg = import_vg_from_config_tree(susp_cft, fid)))
+ if (!(save_vg = import_vg_from_config_tree(susp_cft, fid)))
goto_bad;
+ save_vg->saved_in_clvmd = 1;
+
if (old) {
vginfo->saved_vg_old_buf = susp_buf;
vginfo->saved_vg_old_cft = susp_cft;
- vginfo->saved_vg_old = susp_vg;
- log_debug_cache("lvmcache saved suspended vg old seqno %d %s", vg->seqno, vg->name);
+ vginfo->saved_vg_old = save_vg;
+ log_debug_cache("lvmcache saved vg %s seqno %d %p",
+ save_vg->name, save_vg->seqno, save_vg);
} else {
vginfo->saved_vg_new_buf = susp_buf;
vginfo->saved_vg_new_cft = susp_cft;
- vginfo->saved_vg_new = susp_vg;
- log_debug_cache("lvmcache saved suspended vg new seqno %d %s", vg->seqno, vg->name);
+ vginfo->saved_vg_new = save_vg;
+ log_debug_cache("lvmcache saved pre vg %s seqno %d %p",
+ save_vg->name, save_vg->seqno, save_vg);
}
return;
bad:
_saved_vg_free(vginfo, old, new);
- log_debug_cache("lvmcache failed to save suspended pre %d vg %s", precommitted, vg->name);
+ log_debug_cache("lvmcache failed to save pre %d vg %s", precommitted, vg->name);
}
-struct volume_group *lvmcache_get_saved_vg(const char *vgid)
+struct volume_group *lvmcache_get_saved_vg(const char *vgid, int precommitted)
{
struct lvmcache_vginfo *vginfo;
+ struct volume_group *vg = NULL;
+ int new = precommitted;
+ int old = !precommitted;
if (!(vginfo = lvmcache_vginfo_from_vgid(vgid)))
- return_NULL;
+ goto out;
+
+ if (new)
+ vg = vginfo->saved_vg_new;
+ else if (old)
+ vg = vginfo->saved_vg_old;
+out:
+ if (!vg)
+ log_debug_cache("lvmcache no saved vg %s pre %d", vgid, precommitted);
+ return vg;
+}
+struct volume_group *lvmcache_get_saved_vg_latest(const char *vgid)
+{
+ struct lvmcache_vginfo *vginfo;
+ struct volume_group *vg = NULL;
+
+ if (!(vginfo = lvmcache_vginfo_from_vgid(vgid)))
+ goto out;
if (vginfo->saved_vg_committed)
- return vginfo->saved_vg_new;
+ vg = vginfo->saved_vg_new;
else
- return vginfo->saved_vg_old;
+ vg = vginfo->saved_vg_old;
+out:
+ if (!vg)
+ log_debug_cache("lvmcache no saved vg %s", vgid);
+ return vg;
}
void lvmcache_drop_saved_vg(struct volume_group *vg)
@@ -320,6 +366,16 @@ void lvmcache_drop_saved_vg(struct volume_group *vg)
_saved_vg_free(vginfo, 1, 1);
}
+void lvmcache_drop_saved_vgid(const char *vgid)
+{
+ struct lvmcache_vginfo *vginfo;
+
+ if (!(vginfo = lvmcache_vginfo_from_vgid(vgid)))
+ return;
+
+ _saved_vg_free(vginfo, 1, 1);
+}
+
/*
* Remote node uses this to upgrade precommitted metadata to commited state
* when receives vg_commit notification.
diff --git a/lib/cache/lvmcache.h b/lib/cache/lvmcache.h
index b62d589..7cdda43 100644
--- a/lib/cache/lvmcache.h
+++ b/lib/cache/lvmcache.h
@@ -214,8 +214,10 @@ int lvmcache_get_vg_devs(struct cmd_context *cmd,
void lvmcache_set_independent_location(const char *vgname);
void lvmcache_save_vg(struct volume_group *vg, int precommitted);
-struct volume_group *lvmcache_get_saved_vg(const char *vgid);
+struct volume_group *lvmcache_get_saved_vg(const char *vgid, int precommitted);
+struct volume_group *lvmcache_get_saved_vg_latest(const char *vgid);
void lvmcache_drop_saved_vg(struct volume_group *vg);
+void lvmcache_drop_saved_vgid(const char *vgid);
int lvmcache_scan_mismatch(struct cmd_context *cmd, const char *vgname, const char *vgid);
diff --git a/lib/metadata/metadata.c b/lib/metadata/metadata.c
index 2df9abe..a908658 100644
--- a/lib/metadata/metadata.c
+++ b/lib/metadata/metadata.c
@@ -4559,9 +4559,9 @@ void free_pv_fid(struct physical_volume *pv)
* activate.c so we know the appropriate VG lock is already held and
* the vg_read_internal is therefore safe.
*/
-static struct volume_group *_vg_read_by_vgid(struct cmd_context *cmd,
- const char *vgid,
- unsigned precommitted)
+struct volume_group *vg_read_by_vgid(struct cmd_context *cmd,
+ const char *vgid,
+ unsigned precommitted)
{
const char *vgname;
struct volume_group *vg;
@@ -4578,6 +4578,12 @@ static struct volume_group *_vg_read_by_vgid(struct cmd_context *cmd,
if (lvmlockd_use())
log_error(INTERNAL_ERROR "vg_read_by_vgid failed with lvmlockd");
+ if ((vg = lvmcache_get_saved_vg(vgid, precommitted))) {
+ log_debug_metadata("lvmcache: using saved_vg %s seqno %d pre %d %p",
+ vg->name, vg->seqno, precommitted, vg);
+ return vg;
+ }
+
/* Mustn't scan if memory locked: ensure cache gets pre-populated! */
if (critical_section())
log_debug_metadata("Reading VG by vgid in critical section pre %d vgid %.8s", precommitted, vgid);
@@ -4610,6 +4616,7 @@ static struct volume_group *_vg_read_by_vgid(struct cmd_context *cmd,
}
label_scan_destroy(cmd); /* drop bcache to close devs, keep lvmcache */
+ lvmcache_save_vg(vg, precommitted);
return vg;
scan:
@@ -4621,6 +4628,8 @@ static struct volume_group *_vg_read_by_vgid(struct cmd_context *cmd,
goto fail;
label_scan_destroy(cmd); /* drop bcache to close devs, keep lvmcache */
+
+ lvmcache_save_vg(vg, precommitted);
return vg;
fail:
@@ -4640,12 +4649,12 @@ struct logical_volume *lv_from_lvid(struct cmd_context *cmd, const char *lvid_s,
lvid = (const union lvid *) lvid_s;
log_very_verbose("Finding %svolume group for uuid %s", precommitted ? "precommitted " : "", lvid_s);
- if (!(vg = _vg_read_by_vgid(cmd, (const char *)lvid->id[0].uuid, precommitted))) {
+ if (!(vg = vg_read_by_vgid(cmd, (const char *)lvid->id[0].uuid, precommitted))) {
log_error("Reading VG not found for LVID %s", lvid_s);
return NULL;
}
- log_verbose("Found volume group \"%s\"", vg->name);
+ log_verbose("Found volume group \"%s\" %p", vg->name, vg);
if (vg->status & EXPORTED_VG) {
log_error("Volume group \"%s\" is exported", vg->name);
goto out;
diff --git a/lib/metadata/metadata.h b/lib/metadata/metadata.h
index 83983b4..1e3dd1b 100644
--- a/lib/metadata/metadata.h
+++ b/lib/metadata/metadata.h
@@ -374,6 +374,10 @@ int add_pv_to_vg(struct volume_group *vg, const char *pv_name,
struct logical_volume *find_lv_in_vg_by_lvid(struct volume_group *vg,
const union lvid *lvid);
+struct volume_group *vg_read_by_vgid(struct cmd_context *cmd,
+ const char *vgid,
+ unsigned precommitted);
+
struct lv_list *find_lv_in_lv_list(const struct dm_list *ll,
const struct logical_volume *lv);
diff --git a/lib/metadata/vg.c b/lib/metadata/vg.c
index 0b69e42..1020a67 100644
--- a/lib/metadata/vg.c
+++ b/lib/metadata/vg.c
@@ -97,6 +97,11 @@ void release_vg(struct volume_group *vg)
if (!vg || (vg->fid && vg == vg->fid->fmt->orphan_vg))
return;
+ if (vg->saved_in_clvmd) {
+ log_debug("release_vg skip saved %s %p", vg->name, vg);
+ return;
+ }
+
release_vg(vg->vg_committed);
release_vg(vg->vg_precommitted);
_free_vg(vg);
diff --git a/lib/metadata/vg.h b/lib/metadata/vg.h
index 086a42c..29d88f8 100644
--- a/lib/metadata/vg.h
+++ b/lib/metadata/vg.h
@@ -50,6 +50,7 @@ struct volume_group {
uint32_t seqno; /* Metadata sequence number */
unsigned skip_validate_lock_args : 1;
unsigned lvmetad_update_pending: 1;
+ unsigned saved_in_clvmd: 1;
/*
* The parsed committed (on-disk) copy of this VG; is NULL if this VG is committed
5 years, 11 months