master - libdm: add dm_bit_get_last()/dm_bit_get_prev()
by Bryn Reeves
Gitweb: http://git.fedorahosted.org/git/?p=lvm2.git;a=commitdiff;h=5d1d65e735b6dc...
Commit: 5d1d65e735b6dcc5f02d0e536e3b63617f40ce83
Parent: 107bc13db3b0117e32bacede53fbd382feaf4a17
Author: Bryn M. Reeves <bmr(a)redhat.com>
AuthorDate: Sun Dec 11 12:44:45 2016 +0000
Committer: Bryn M. Reeves <bmr(a)redhat.com>
CommitterDate: Tue Dec 13 21:01:58 2016 +0000
libdm: add dm_bit_get_last()/dm_bit_get_prev()
It is sometimes convenient to iterate over the set bits in a dm
bitset in reverse order (from the highest set bit toward zero), or
to quickly find the last set bit.
Add dm_bit_get_last() and dm_bit_get_prev(), mirroring the existing
dm_bit_get_first() and dm_bit_get_next().
dm_bit_get_prev() uses __builtin_clz when available to efficiently
test the bitset in reverse.
---
libdm/.exported_symbols.DM_1_02_138 | 2 +
libdm/datastruct/bitset.c | 36 +++++++++++++++++++++++++++++++++++
libdm/libdevmapper.h | 2 +
3 files changed, 40 insertions(+), 0 deletions(-)
diff --git a/libdm/.exported_symbols.DM_1_02_138 b/libdm/.exported_symbols.DM_1_02_138
new file mode 100644
index 0000000..63fc2b8
--- /dev/null
+++ b/libdm/.exported_symbols.DM_1_02_138
@@ -0,0 +1,2 @@
+dm_bit_get_last
+dm_bit_get_prev
diff --git a/libdm/datastruct/bitset.c b/libdm/datastruct/bitset.c
index 3fd6a9c..90efec6 100644
--- a/libdm/datastruct/bitset.c
+++ b/libdm/datastruct/bitset.c
@@ -76,6 +76,13 @@ static int _test_word(uint32_t test, int bit)
return (tb ? ffs(tb) + bit - 1 : -1);
}
+static int _test_word_rev(uint32_t test, int bit)
+{
+ uint32_t tb = test << (DM_BITS_PER_INT - 1 - bit);
+
+ return (tb ? bit - clz(tb) : -1);
+}
+
int dm_bit_get_next(dm_bitset_t bs, int last_bit)
{
int bit, word;
@@ -101,11 +108,40 @@ int dm_bit_get_next(dm_bitset_t bs, int last_bit)
return -1;
}
+int dm_bit_get_prev(dm_bitset_t bs, int last_bit)
+{
+ int bit, word;
+ uint32_t test;
+
+ last_bit--; /* otherwise we'll return the same bit again */
+
+ /*
+ * bs[0] holds number of bits
+ */
+ while (last_bit >= 0) {
+ word = last_bit >> INT_SHIFT;
+ test = bs[word + 1];
+ bit = last_bit & (DM_BITS_PER_INT - 1);
+
+ if ((bit = _test_word_rev(test, bit)) >= 0)
+ return (word * DM_BITS_PER_INT) + bit;
+
+ last_bit = (last_bit & ~(DM_BITS_PER_INT - 1)) - 1;
+ }
+
+ return -1;
+}
+
int dm_bit_get_first(dm_bitset_t bs)
{
return dm_bit_get_next(bs, -1);
}
+int dm_bit_get_last(dm_bitset_t bs)
+{
+ return dm_bit_get_prev(bs, bs[0] + 1);
+}
+
/*
* Based on the Linux kernel __bitmap_parselist from lib/bitmap.c
*/
diff --git a/libdm/libdevmapper.h b/libdm/libdevmapper.h
index ab69a56..44aa55c 100644
--- a/libdm/libdevmapper.h
+++ b/libdm/libdevmapper.h
@@ -2069,6 +2069,8 @@ void dm_bit_and(dm_bitset_t out, dm_bitset_t in1, dm_bitset_t in2);
void dm_bit_union(dm_bitset_t out, dm_bitset_t in1, dm_bitset_t in2);
int dm_bit_get_first(dm_bitset_t bs);
int dm_bit_get_next(dm_bitset_t bs, int last_bit);
+int dm_bit_get_last(dm_bitset_t bs);
+int dm_bit_get_prev(dm_bitset_t bs, int last_bit);
#define DM_BITS_PER_INT (sizeof(int) * CHAR_BIT)
6 years, 5 months
master - util: add clz() and use __builtin_clz() if available
by Bryn Reeves
Gitweb: http://git.fedorahosted.org/git/?p=lvm2.git;a=commitdiff;h=107bc13db3b011...
Commit: 107bc13db3b0117e32bacede53fbd382feaf4a17
Parent: 83a9cd5258fbd1acf293734cb4c3aba0f9ffcc9b
Author: Bryn M. Reeves <bmr(a)redhat.com>
AuthorDate: Mon Dec 12 12:03:50 2016 +0000
Committer: Bryn M. Reeves <bmr(a)redhat.com>
CommitterDate: Tue Dec 13 20:41:29 2016 +0000
util: add clz() and use __builtin_clz() if available
Add a macro for the clz (count leading zeros) operation.
Use the GCC __builtin_clz() for clz() if it is available and fall
back to a shift based implementation on systems that do not set
HAVE___BUILTIN_CLZ.
---
lib/misc/util.h | 41 +++++++++++++++++++++++++++++++++++++++++
1 files changed, 41 insertions(+), 0 deletions(-)
diff --git a/lib/misc/util.h b/lib/misc/util.h
index 730b903..9231ea9 100644
--- a/lib/misc/util.h
+++ b/lib/misc/util.h
@@ -35,6 +35,47 @@
#define uninitialized_var(x) x = x
#endif
+/*
+ * GCC 3.4 adds a __builtin_clz, which uses the count leading zeros (clz)
+ * instruction on arches that have one. Provide a fallback using shifts
+ * and comparisons for older compilers.
+ */
+#ifdef HAVE___BUILTIN_CLZ
+#define clz(x) __builtin_clz((x))
+#else /* ifdef HAVE___BUILTIN_CLZ */
+unsigned _dm_clz(unsigned x)
+{
+ int n;
+
+ if ((int)x <= 0) return (~x >> 26) & 32;
+
+ n = 1;
+
+ if ((x >> 16) == 0) {
+ n = n + 16;
+ x = x << 16;
+ }
+
+ if ((x >> 24) == 0) {
+ n = n + 8;
+ x = x << 8;
+ }
+
+ if ((x >> 28) == 0) {
+ n = n + 4;
+ x = x << 4;
+ }
+
+ if ((x >> 30) == 0) {
+ n = n + 2;
+ x = x << 2;
+ }
+ n = n - (x >> 31);
+ return n;
+}
+#define clz(x) _dm_clz((x))
+#endif /* ifdef HAVE___BUILTIN_CLZ */
+
#define KERNEL_VERSION(major, minor, release) (((major) << 16) + ((minor) << 8) + (release))
/* Define some portable printing types */
6 years, 5 months
master - configure: check for __builtin_clz()
by Bryn Reeves
Gitweb: http://git.fedorahosted.org/git/?p=lvm2.git;a=commitdiff;h=83a9cd5258fbd1...
Commit: 83a9cd5258fbd1acf293734cb4c3aba0f9ffcc9b
Parent: 930b0b4c9e4ca466d955f8729644ef26a939937c
Author: Bryn M. Reeves <bmr(a)redhat.com>
AuthorDate: Mon Dec 12 12:03:16 2016 +0000
Committer: Bryn M. Reeves <bmr(a)redhat.com>
CommitterDate: Tue Dec 13 20:38:40 2016 +0000
configure: check for __builtin_clz()
---
aclocal.m4 | 171 ++++++++++++++++++++++++++++++++++++++++++++++++
configure | 44 ++++++++++++
configure.in | 1 +
include/configure.h.in | 3 +
4 files changed, 219 insertions(+), 0 deletions(-)
diff --git a/aclocal.m4 b/aclocal.m4
index 35107ac..1f02c2b 100644
--- a/aclocal.m4
+++ b/aclocal.m4
@@ -536,4 +536,175 @@ AC_DEFUN([AM_RUN_LOG],
echo "$as_me:$LINENO: \$? = $ac_status" >&AS_MESSAGE_LOG_FD
(exit $ac_status); }])
+# ===========================================================================
+# http://www.gnu.org/software/autoconf-archive/ax_gcc_builtin.html
+# ===========================================================================
+#
+# SYNOPSIS
+#
+# AX_GCC_BUILTIN(BUILTIN)
+#
+# DESCRIPTION
+#
+# This macro checks if the compiler supports one of GCC's built-in
+# functions; many other compilers also provide those same built-ins.
+#
+# The BUILTIN parameter is the name of the built-in function.
+#
+# If BUILTIN is supported define HAVE_<BUILTIN>. Keep in mind that since
+# builtins usually start with two underscores they will be copied over
+# into the HAVE_<BUILTIN> definition (e.g. HAVE___BUILTIN_EXPECT for
+# __builtin_expect()).
+#
+# The macro caches its result in the ax_cv_have_<BUILTIN> variable (e.g.
+# ax_cv_have___builtin_expect).
+#
+# The macro currently supports the following built-in functions:
+#
+# __builtin_assume_aligned
+# __builtin_bswap16
+# __builtin_bswap32
+# __builtin_bswap64
+# __builtin_choose_expr
+# __builtin___clear_cache
+# __builtin_clrsb
+# __builtin_clrsbl
+# __builtin_clrsbll
+# __builtin_clz
+# __builtin_clzl
+# __builtin_clzll
+# __builtin_complex
+# __builtin_constant_p
+# __builtin_ctz
+# __builtin_ctzl
+# __builtin_ctzll
+# __builtin_expect
+# __builtin_ffs
+# __builtin_ffsl
+# __builtin_ffsll
+# __builtin_fpclassify
+# __builtin_huge_val
+# __builtin_huge_valf
+# __builtin_huge_vall
+# __builtin_inf
+# __builtin_infd128
+# __builtin_infd32
+# __builtin_infd64
+# __builtin_inff
+# __builtin_infl
+# __builtin_isinf_sign
+# __builtin_nan
+# __builtin_nand128
+# __builtin_nand32
+# __builtin_nand64
+# __builtin_nanf
+# __builtin_nanl
+# __builtin_nans
+# __builtin_nansf
+# __builtin_nansl
+# __builtin_object_size
+# __builtin_parity
+# __builtin_parityl
+# __builtin_parityll
+# __builtin_popcount
+# __builtin_popcountl
+# __builtin_popcountll
+# __builtin_powi
+# __builtin_powif
+# __builtin_powil
+# __builtin_prefetch
+# __builtin_trap
+# __builtin_types_compatible_p
+# __builtin_unreachable
+#
+# Unsuppored built-ins will be tested with an empty parameter set and the
+# result of the check might be wrong or meaningless so use with care.
+#
+# LICENSE
+#
+# Copyright (c) 2013 Gabriele Svelto <gabriele.svelto(a)gmail.com>
+#
+# Copying and distribution of this file, with or without modification, are
+# permitted in any medium without royalty provided the copyright notice
+# and this notice are preserved. This file is offered as-is, without any
+# warranty.
+
+#serial 3
+
+AC_DEFUN([AX_GCC_BUILTIN], [
+ AS_VAR_PUSHDEF([ac_var], [ax_cv_have_$1])
+
+ AC_CACHE_CHECK([for $1], [ac_var], [
+ AC_LINK_IFELSE([AC_LANG_PROGRAM([], [
+ m4_case([$1],
+ [__builtin_assume_aligned], [$1("", 0)],
+ [__builtin_bswap16], [$1(0)],
+ [__builtin_bswap32], [$1(0)],
+ [__builtin_bswap64], [$1(0)],
+ [__builtin_choose_expr], [$1(0, 0, 0)],
+ [__builtin___clear_cache], [$1("", "")],
+ [__builtin_clrsb], [$1(0)],
+ [__builtin_clrsbl], [$1(0)],
+ [__builtin_clrsbll], [$1(0)],
+ [__builtin_clz], [$1(0)],
+ [__builtin_clzl], [$1(0)],
+ [__builtin_clzll], [$1(0)],
+ [__builtin_complex], [$1(0.0, 0.0)],
+ [__builtin_constant_p], [$1(0)],
+ [__builtin_ctz], [$1(0)],
+ [__builtin_ctzl], [$1(0)],
+ [__builtin_ctzll], [$1(0)],
+ [__builtin_expect], [$1(0, 0)],
+ [__builtin_ffs], [$1(0)],
+ [__builtin_ffsl], [$1(0)],
+ [__builtin_ffsll], [$1(0)],
+ [__builtin_fpclassify], [$1(0, 1, 2, 3, 4, 0.0)],
+ [__builtin_huge_val], [$1()],
+ [__builtin_huge_valf], [$1()],
+ [__builtin_huge_vall], [$1()],
+ [__builtin_inf], [$1()],
+ [__builtin_infd128], [$1()],
+ [__builtin_infd32], [$1()],
+ [__builtin_infd64], [$1()],
+ [__builtin_inff], [$1()],
+ [__builtin_infl], [$1()],
+ [__builtin_isinf_sign], [$1(0.0)],
+ [__builtin_nan], [$1("")],
+ [__builtin_nand128], [$1("")],
+ [__builtin_nand32], [$1("")],
+ [__builtin_nand64], [$1("")],
+ [__builtin_nanf], [$1("")],
+ [__builtin_nanl], [$1("")],
+ [__builtin_nans], [$1("")],
+ [__builtin_nansf], [$1("")],
+ [__builtin_nansl], [$1("")],
+ [__builtin_object_size], [$1("", 0)],
+ [__builtin_parity], [$1(0)],
+ [__builtin_parityl], [$1(0)],
+ [__builtin_parityll], [$1(0)],
+ [__builtin_popcount], [$1(0)],
+ [__builtin_popcountl], [$1(0)],
+ [__builtin_popcountll], [$1(0)],
+ [__builtin_powi], [$1(0, 0)],
+ [__builtin_powif], [$1(0, 0)],
+ [__builtin_powil], [$1(0, 0)],
+ [__builtin_prefetch], [$1("")],
+ [__builtin_trap], [$1()],
+ [__builtin_types_compatible_p], [$1(int, int)],
+ [__builtin_unreachable], [$1()],
+ [m4_warn([syntax], [Unsupported built-in $1, the test may fail])
+ $1()]
+ )
+ ])],
+ [AS_VAR_SET([ac_var], [yes])],
+ [AS_VAR_SET([ac_var], [no])])
+ ])
+
+ AS_IF([test yes = AS_VAR_GET([ac_var])],
+ [AC_DEFINE_UNQUOTED(AS_TR_CPP(HAVE_$1), 1,
+ [Define to 1 if the system has the `$1' built-in function])], [])
+
+ AS_VAR_POPDEF([ac_var])
+])
+
m4_include([acinclude.m4])
diff --git a/configure b/configure
index c82a19b..1cb4b54 100755
--- a/configure
+++ b/configure
@@ -6321,6 +6321,50 @@ _ACEOF
esac
+
+
+ { $as_echo "$as_me:${as_lineno-$LINENO}: checking for __builtin_clz" >&5
+$as_echo_n "checking for __builtin_clz... " >&6; }
+if ${ax_cv_have___builtin_clz+:} false; then :
+ $as_echo_n "(cached) " >&6
+else
+
+ cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h. */
+
+int
+main ()
+{
+
+ __builtin_clz(0)
+
+ ;
+ return 0;
+}
+_ACEOF
+if ac_fn_c_try_link "$LINENO"; then :
+ ax_cv_have___builtin_clz=yes
+else
+ ax_cv_have___builtin_clz=no
+fi
+rm -f core conftest.err conftest.$ac_objext \
+ conftest$ac_exeext conftest.$ac_ext
+
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ax_cv_have___builtin_clz" >&5
+$as_echo "$ax_cv_have___builtin_clz" >&6; }
+
+ if test yes = $ax_cv_have___builtin_clz; then :
+
+cat >>confdefs.h <<_ACEOF
+#define HAVE___BUILTIN_CLZ 1
+_ACEOF
+
+fi
+
+
+
+
################################################################################
for ac_func in ftruncate gethostname getpagesize gettimeofday localtime_r \
memchr memset mkdir mkfifo munmap nl_langinfo realpath rmdir setenv \
diff --git a/configure.in b/configure.in
index cc77aab..8ec65c8 100644
--- a/configure.in
+++ b/configure.in
@@ -134,6 +134,7 @@ AC_TYPE_UINT8_T
AC_TYPE_UINT16_T
AC_TYPE_UINT32_T
AC_TYPE_UINT64_T
+AX_GCC_BUILTIN([__builtin_clz])
################################################################################
dnl -- Check for functions
diff --git a/include/configure.h.in b/include/configure.h.in
index 3c43bd5..cf8dc94 100644
--- a/include/configure.h.in
+++ b/include/configure.h.in
@@ -341,6 +341,9 @@
/* Define to 1 if the system has the type `ptrdiff_t'. */
#undef HAVE_PTRDIFF_T
+/* Define to 1 if the compiler has the `__builtin_clz` builtin. */
+#undef HAVE___BUILTIN_CLZ
+
/* Define to 1 if you have the <readline/history.h> header file. */
#undef HAVE_READLINE_HISTORY_H
6 years, 5 months
master - libdm: fix start of file detection in _stats_map_extents()
by Bryn Reeves
Gitweb: http://git.fedorahosted.org/git/?p=lvm2.git;a=commitdiff;h=930b0b4c9e4ca4...
Commit: 930b0b4c9e4ca466d955f8729644ef26a939937c
Parent: eb6557221715b30a374be46e4a52f79cd7bbed44
Author: Bryn M. Reeves <bmr(a)redhat.com>
AuthorDate: Tue Dec 13 18:14:13 2016 +0000
Committer: Bryn M. Reeves <bmr(a)redhat.com>
CommitterDate: Tue Dec 13 20:25:47 2016 +0000
libdm: fix start of file detection in _stats_map_extents()
---
libdm/libdm-stats.c | 2 +-
1 files changed, 1 insertions(+), 1 deletions(-)
diff --git a/libdm/libdm-stats.c b/libdm/libdm-stats.c
index d9f0427..471bd7b 100644
--- a/libdm/libdm-stats.c
+++ b/libdm/libdm-stats.c
@@ -4287,7 +4287,7 @@ static uint64_t _stats_map_extents(struct dm_pool *mem,
* If the file only has a single extent, no boundary is ever
* detected to trigger addition of the first extent.
*/
- if (fm_ext[i].fe_logical == 0)
+ if (fm_ext[i - 1].fe_logical == 0)
_stats_add_extent(mem, fm_pending, nr_extents);
fiemap->fm_start = (fm_ext[i - 1].fe_logical +
6 years, 5 months
master - libdm: break up _stats_get_extents_for_file()
by Bryn Reeves
Gitweb: http://git.fedorahosted.org/git/?p=lvm2.git;a=commitdiff;h=eb6557221715b3...
Commit: eb6557221715b30a374be46e4a52f79cd7bbed44
Parent: ea9af3e290879403d99dd602153ff9d0ad0de8de
Author: Bryn M. Reeves <bmr(a)redhat.com>
AuthorDate: Tue Dec 13 12:03:00 2016 +0000
Committer: Bryn M. Reeves <bmr(a)redhat.com>
CommitterDate: Tue Dec 13 20:25:45 2016 +0000
libdm: break up _stats_get_extents_for_file()
Split out the loop that iterates over each batch of FIEMAP
extent data from the function that sets up and calls the ioctl
to reduce nesting and simplify local variable use:
_stats_get_extents_for_file()
-> _stats_map_extents()
The _stats_map_extents() function is responsible for detecting
eof and extent boundaries and adding whole, allocated extents
to the file extent table for region creation.
---
libdm/libdm-stats.c | 145 +++++++++++++++++++++++++++++++--------------------
1 files changed, 88 insertions(+), 57 deletions(-)
diff --git a/libdm/libdm-stats.c b/libdm/libdm-stats.c
index 2d2a032..d9f0427 100644
--- a/libdm/libdm-stats.c
+++ b/libdm/libdm-stats.c
@@ -4226,6 +4226,82 @@ static int _stats_add_extent(struct dm_pool *mem, struct fiemap_extent *fm_ext,
((ext).fe_physical != (exp))
/*
+ * Copy fields from fiemap_extent 'from' to the fiemap_extent
+ * pointed to by 'to'.
+ */
+#define ext_copy(to, from) \
+do { \
+ *(to) = *(from); \
+} while (0)
+
+static uint64_t _stats_map_extents(struct dm_pool *mem,
+ struct fiemap *fiemap,
+ struct fiemap_extent *fm_ext,
+ struct fiemap_extent *fm_last,
+ struct fiemap_extent *fm_pending,
+ uint64_t next_extent,
+ int *eof)
+{
+ uint64_t expected = 0, nr_extents = next_extent;
+ unsigned int i;
+
+ /*
+ * Loop over the returned extents adding the fm_pending extent
+ * to the table of extents each time a discontinuity (or eof)
+ * is detected.
+ *
+ * We use a pointer to fm_pending in the caller since it is
+ * possible that logical extents comprising a single physical
+ * extent are returned by successive FIEMAP calls.
+ */
+ for (i = 0; i < fiemap->fm_mapped_extents; i++) {
+ expected = fm_last->fe_physical + fm_last->fe_length;
+
+ if (fm_ext[i].fe_flags & FIEMAP_EXTENT_LAST)
+ *eof = 1;
+
+ /* cannot map extents that are not yet allocated. */
+ if (fm_ext[i].fe_flags
+ & (FIEMAP_EXTENT_UNKNOWN | FIEMAP_EXTENT_DELALLOC))
+ continue;
+
+ if (ext_boundary(fm_ext[i], expected)) {
+ if (!_stats_add_extent(mem, fm_pending, nr_extents))
+ goto_bad;
+ nr_extents++;
+ /* Begin a new pending extent. */
+ ext_copy(fm_pending, fm_ext + i);
+ } else {
+ expected = 0;
+ /* Begin a new pending extent for extent 0. */
+ if (fm_ext[i].fe_logical == 0)
+ ext_copy(fm_pending, fm_ext + i);
+ else
+ /* accumulate this logical extent's length */
+ fm_pending->fe_length += fm_ext[i].fe_length;
+ }
+ *fm_last = fm_ext[i];
+ }
+
+ /*
+ * If the file only has a single extent, no boundary is ever
+ * detected to trigger addition of the first extent.
+ */
+ if (fm_ext[i].fe_logical == 0)
+ _stats_add_extent(mem, fm_pending, nr_extents);
+
+ fiemap->fm_start = (fm_ext[i - 1].fe_logical +
+ fm_ext[i - 1].fe_length);
+
+ /* return the number of extents found in this call. */
+ return nr_extents - next_extent;
+bad:
+ /* signal mapping error to caller */
+ *eof = -1;
+ return 0;
+}
+
+/*
* Read the extents of an open file descriptor into a table of struct _extent.
*
* Based on e2fsprogs/misc/filefrag.c::filefrag_fiemap().
@@ -4236,16 +4312,12 @@ static int _stats_add_extent(struct dm_pool *mem, struct fiemap_extent *fm_ext,
static struct _extent *_stats_get_extents_for_file(struct dm_pool *mem, int fd,
uint64_t *count)
{
- uint64_t *buf;
+ struct fiemap_extent fm_last = {0}, fm_pending = {0}, *fm_ext = NULL;
struct fiemap *fiemap = NULL;
- struct fiemap_extent *fm_ext = NULL;
- struct fiemap_extent fm_last = {0}, fm_pending = {0};
+ int eof = 0, nr_extents = 0;
struct _extent *extents;
- unsigned long long expected = 0;
unsigned long flags = 0;
- unsigned int i, num = 0;
- int tot_extents = 0, n = 0;
- int last = 0;
+ uint64_t *buf;
int rc;
buf = dm_zalloc(STATS_FIE_BUF_LEN);
@@ -4284,67 +4356,26 @@ static struct _extent *_stats_get_extents_for_file(struct dm_pool *mem, int fd,
goto bad;
}
- /* If 0 extents are returned, then more ioctls are not needed */
+ /* If 0 extents are returned, more ioctls are not needed */
if (fiemap->fm_mapped_extents == 0)
break;
- for (i = 0; i < fiemap->fm_mapped_extents; i++) {
- expected = fm_last.fe_physical + fm_last.fe_length;
+ nr_extents += _stats_map_extents(mem, fiemap, fm_ext, &fm_last,
+ &fm_pending, nr_extents, &eof);
- if (fm_ext[i].fe_flags & FIEMAP_EXTENT_LAST)
- last = 1;
-
- /* cannot map extents that are not yet allocated. */
- if (fm_ext[i].fe_flags
- & (FIEMAP_EXTENT_UNKNOWN | FIEMAP_EXTENT_DELALLOC))
- continue;
-
- if (ext_boundary(fm_ext[i], expected)) {
- tot_extents++;
- if (!_stats_add_extent(mem, &fm_pending,
- fm_pending.fe_flags))
- goto_bad;
- /* Begin a new pending extent. */
- fm_pending.fe_flags = tot_extents - 1;
- fm_pending.fe_physical = fm_ext[i].fe_physical;
- fm_pending.fe_logical = fm_ext[i].fe_logical;
- fm_pending.fe_length = fm_ext[i].fe_length;
- } else {
- expected = 0;
- if (!tot_extents)
- tot_extents = 1;
- /* Begin a new pending extent for extent 0. */
- if (fm_ext[i].fe_logical == 0) {
- fm_pending.fe_flags = tot_extents - 1;
- fm_pending.fe_physical = fm_ext[i].fe_physical;
- fm_pending.fe_logical = fm_ext[i].fe_logical;
- fm_pending.fe_length = fm_ext[i].fe_length;
- } else
- fm_pending.fe_length += fm_ext[i].fe_length;
- }
- num += tot_extents;
- fm_last = fm_ext[i];
- n++;
- }
-
- /*
- * If the file only has a single extent, no boundary is ever
- * detected to trigger addition of the first extent.
- */
- if (fm_ext[i].fe_logical == 0)
- _stats_add_extent(mem, &fm_pending, fm_pending.fe_flags);
+ /* check for extent mapping error */
+ if (eof < 0)
+ goto bad;
- fiemap->fm_start = (fm_ext[i - 1].fe_logical +
- fm_ext[i - 1].fe_length);
- } while (last == 0);
+ } while (eof == 0);
- if (!tot_extents) {
+ if (!nr_extents) {
log_error("Cannot map file: no allocated extents.");
goto bad;
}
/* return total number of extents */
- *count = tot_extents;
+ *count = nr_extents;
extents = dm_pool_end_object(mem);
/* free FIEMAP buffer. */
6 years, 5 months
master - libdm: fix dm_stats_foreach_group() macro
by Bryn Reeves
Gitweb: http://git.fedorahosted.org/git/?p=lvm2.git;a=commitdiff;h=ea9af3e2908794...
Commit: ea9af3e290879403d99dd602153ff9d0ad0de8de
Parent: 8e339728283d3b83222a25c7bf12b79a944c6ef5
Author: Bryn M. Reeves <bmr(a)redhat.com>
AuthorDate: Tue Dec 13 15:32:34 2016 +0000
Committer: Bryn M. Reeves <bmr(a)redhat.com>
CommitterDate: Tue Dec 13 20:01:00 2016 +0000
libdm: fix dm_stats_foreach_group() macro
---
libdm/libdevmapper.h | 6 +++---
1 files changed, 3 insertions(+), 3 deletions(-)
diff --git a/libdm/libdevmapper.h b/libdm/libdevmapper.h
index fe2e410..ab69a56 100644
--- a/libdm/libdevmapper.h
+++ b/libdm/libdevmapper.h
@@ -1138,9 +1138,9 @@ for (dm_stats_walk_init((dms), DM_STATS_WALK_AREA), \
*/
#define dm_stats_foreach_group(dms) \
for (dm_stats_walk_init((dms), DM_STATS_WALK_GROUP), \
- dm_stats_group_walk_start(dms); \
- !dm_stats_group_walk_end(dms); \
- dm_stats_group_walk_next(dms))
+ dm_stats_walk_start(dms); \
+ !dm_stats_walk_end(dms); \
+ dm_stats_walk_next(dms))
/*
* Start a walk iterating over the regions contained in dm_stats handle
6 years, 5 months
master - libdm: check for non-existent region_id values in groups
by Bryn Reeves
Gitweb: http://git.fedorahosted.org/git/?p=lvm2.git;a=commitdiff;h=8e339728283d3b...
Commit: 8e339728283d3b83222a25c7bf12b79a944c6ef5
Parent: 99b6d82e2dac7ef097fa940c64456620930d7758
Author: Bryn M. Reeves <bmr(a)redhat.com>
AuthorDate: Tue Dec 13 14:31:39 2016 +0000
Committer: Bryn M. Reeves <bmr(a)redhat.com>
CommitterDate: Tue Dec 13 15:37:48 2016 +0000
libdm: check for non-existent region_id values in groups
Check that all region_id values specified in a group bitmap are
actually present: although this should not normally happen when
using the dmstats tool, it is possible as a result of manual
changes (or bugs) for a group descriptor to contain one or more
group_id values that do not exist.
Check for this situation when reading group descriptors, warn
the user the user, and clear these bits in the bitmap when
formatting it for output.
---
libdm/libdm-stats.c | 27 +++++++++++++++++++++------
1 files changed, 21 insertions(+), 6 deletions(-)
diff --git a/libdm/libdm-stats.c b/libdm/libdm-stats.c
index 5833ac6..2d2a032 100644
--- a/libdm/libdm-stats.c
+++ b/libdm/libdm-stats.c
@@ -645,6 +645,23 @@ static void _stats_update_groups(struct dm_stats *dms)
}
}
+static void _check_group_regions_present(struct dm_stats *dms,
+ struct dm_stats_group *group)
+{
+ dm_bitset_t regions = group->regions;
+ int64_t i, group_id;
+
+ group_id = i = dm_bit_get_first(regions);
+
+ for (; i > 0; dm_bit_get_next(regions, i))
+ if (!_stats_region_present(&dms->regions[i])) {
+ log_warn("Group descriptor " FMTi64 " contains "
+ "non-existent region_id " FMTi64 ".",
+ group_id, i);
+ dm_bit_clear(regions, i);
+ }
+}
+
/*
* Parse a DMS_GROUP group descriptor embedded in a region's aux_data.
*
@@ -1030,6 +1047,9 @@ static int _stats_parse_list(struct dm_stats *dms, const char *resp)
dms->regions = dm_pool_end_object(mem);
dms->groups = dm_pool_end_object(group_mem);
+ dm_stats_foreach_group(dms)
+ _check_group_regions_present(dms, &dms->groups[dms->cur_group]);
+
_stats_update_groups(dms);
if (fclose(list_rows))
@@ -1742,17 +1762,12 @@ bad:
static size_t _stats_group_tag_len(const struct dm_stats *dms,
dm_bitset_t regions)
{
- int i, j, next, nr_regions = 0;
+ int64_t i, j, next, nr_regions = 0;
size_t buflen = 0, id_len = 0;
/* check region ids and find last set bit */
i = dm_bit_get_first(regions);
for (; i >= 0; i = dm_bit_get_next(regions, i)) {
- if (!dm_stats_region_present(dms, i)) {
- log_error("Region identifier %d not found", i);
- return 0;
- }
-
/* length of region_id or range start in characters */
id_len = (i) ? 1 + (size_t) log10(i) : 1;
buflen += id_len;
6 years, 5 months
master - libdm: fix segfault with invalid group descriptor
by Bryn Reeves
Gitweb: http://git.fedorahosted.org/git/?p=lvm2.git;a=commitdiff;h=99b6d82e2dac7e...
Commit: 99b6d82e2dac7ef097fa940c64456620930d7758
Parent: 138e4336fd8422623df7daa362b98a4899f5fbec
Author: Bryn M. Reeves <bmr(a)redhat.com>
AuthorDate: Tue Dec 13 13:56:10 2016 +0000
Committer: Bryn M. Reeves <bmr(a)redhat.com>
CommitterDate: Tue Dec 13 14:37:41 2016 +0000
libdm: fix segfault with invalid group descriptor
If a region has a a DMS_GROUP tag in aux_data where the first
region_id in the bitmap is not the same as the containing region,
dmstats will segfault:
# '2' is never a valid group bitset list for region_id == 0
# dmsetup message vg_hex/root 0 "@stats_set_aux 0 DMS_GROUP=img:2#"
# dmsetup message vg_hex/root 0 "@stats_list"
0: 45383680+16384 16384 dmstats DMS_GROUP=img:2#
1: 46071808+32768 32768 dmstats -
2: 47382528+16384 16384 dmstats -
# dmstats list
Segmentation fault (core dumped)
The crash will occur in some arbitrary dm_stats_get_* property
method - this happens while processing the 1st region_id in the
bitset, because the region is marked as grouped, but there is
no group bitmap present at dms->groups[2]->regions.
Fix this by detecting a mismatch between the expected region_id
and dm_bit_get_first() for the parsed bitset during
_parse_aux_data_group().
---
libdm/libdm-stats.c | 8 +++++++-
1 files changed, 7 insertions(+), 1 deletions(-)
diff --git a/libdm/libdm-stats.c b/libdm/libdm-stats.c
index 8c0428e..5833ac6 100644
--- a/libdm/libdm-stats.c
+++ b/libdm/libdm-stats.c
@@ -708,8 +708,14 @@ static int _parse_aux_data_group(struct dm_stats *dms,
}
group->group_id = dm_bit_get_first(regions);
- group->regions = regions;
+ if (group->group_id != region->region_id) {
+ log_error("Found invalid group descriptor in region " FMTu64
+ " aux_data.", region->region_id);
+ group->group_id = DM_STATS_GROUP_NOT_PRESENT;
+ goto bad;
+ }
+ group->regions = regions;
group->alias = NULL;
if (strlen(alias)) {
group->alias = dm_strdup(alias);
6 years, 5 months
master - libdm: fix region overlap tests
by Bryn Reeves
Gitweb: http://git.fedorahosted.org/git/?p=lvm2.git;a=commitdiff;h=138e4336fd8422...
Commit: 138e4336fd8422623df7daa362b98a4899f5fbec
Parent: 93f420caf4e58f468919f40a9f3f9c20157affd0
Author: Bryn M. Reeves <bmr(a)redhat.com>
AuthorDate: Mon Dec 12 22:49:31 2016 +0000
Committer: Bryn M. Reeves <bmr(a)redhat.com>
CommitterDate: Tue Dec 13 09:09:29 2016 +0000
libdm: fix region overlap tests
---
libdm/libdm-stats.c | 8 +++++++-
1 files changed, 7 insertions(+), 1 deletions(-)
diff --git a/libdm/libdm-stats.c b/libdm/libdm-stats.c
index 56a38f2..8c0428e 100644
--- a/libdm/libdm-stats.c
+++ b/libdm/libdm-stats.c
@@ -3880,6 +3880,12 @@ static int _stats_group_check_overlap(const struct dm_stats *dms,
i++;
}
+ /* A single region cannot overlap itself. */
+ if (i == 1) {
+ dm_pool_free(dms->mem, map);
+ return 1;
+ }
+
/* sort by extent.start */
qsort(map, count, sizeof(*map), _extent_start_compare);
@@ -3915,7 +3921,7 @@ merge:
goto merge;
dm_pool_free(dms->mem, map);
- return overlap;
+ return (overlap == 0);
}
static void _stats_copy_histogram_bounds(struct dm_histogram *to,
6 years, 5 months
master - libdm: fix _stats_get_extents_for_file()
by Bryn Reeves
Gitweb: http://git.fedorahosted.org/git/?p=lvm2.git;a=commitdiff;h=93f420caf4e58f...
Commit: 93f420caf4e58f468919f40a9f3f9c20157affd0
Parent: 87117c2b2546231c789f92c75590f053a8fb987c
Author: Bryn M. Reeves <bmr(a)redhat.com>
AuthorDate: Mon Dec 12 20:40:27 2016 +0000
Committer: Bryn M. Reeves <bmr(a)redhat.com>
CommitterDate: Tue Dec 13 09:09:25 2016 +0000
libdm: fix _stats_get_extents_for_file()
Handle files that contain multiple logical extents in a single
physical extent properly:
- In FIEMAP terms a logical extent is a contiguous range of
sectors in the file's address space.
- One or more physically adjacent logical extents comprise a
physical extent: these are the disk areas that will be mapped
to regions.
- An extent boundary occurs when the start sector of extent
n+1 is not equal to (n.start + n.length).
This requires that we accumulate the length values of extents
returned by FIEMAP until a discontinuity is found (since each
struct fiemap_extent returned by FIEMAP only represents a single
logical extent, which may be contiguous with other logical
extents on-disk).
This avoids creating large numbers of regions for physically
adjacent (logical) extents and fixes the earlier behaviour which
would only map the first logical extent of the physical extent,
leaving gaps in the region table for these files.
---
WHATS_NEW_DM | 3 +-
libdm/libdm-stats.c | 56 +++++++++++++++++++++++++++++++++-----------------
2 files changed, 39 insertions(+), 20 deletions(-)
diff --git a/WHATS_NEW_DM b/WHATS_NEW_DM
index f402113..ab32bdb 100644
--- a/WHATS_NEW_DM
+++ b/WHATS_NEW_DM
@@ -1,8 +1,9 @@
Version 1.02.138 -
=====================================
+ Fix file mapping for extents with physically adjacent extents.
Validation vsnprintf result in runtime translate of dm_log (1.02.136).
Separate filemap extent allocation from region table.
- Fix segmentation fault when filemap region creation fails
+ Fix segmentation fault when filemap region creation fails.
Fix performance of region cleanup for failed filemap creation.
Fix very slow region deletion with many regions.
diff --git a/libdm/libdm-stats.c b/libdm/libdm-stats.c
index 850aa49..56a38f2 100644
--- a/libdm/libdm-stats.c
+++ b/libdm/libdm-stats.c
@@ -4194,10 +4194,9 @@ static int _stats_add_extent(struct dm_pool *mem, struct fiemap_extent *fm_ext,
}
/* test for the boundary of an extent */
-#define ext_boundary(ext, exp, exp_dense) \
-(((ext).fe_logical != 0) && \
-((ext).fe_physical != (exp)) && \
-((ext).fe_physical != (exp_dense)))
+#define ext_boundary(ext, exp) \
+((ext).fe_logical != 0) && \
+((ext).fe_physical != (exp))
/*
* Read the extents of an open file descriptor into a table of struct _extent.
@@ -4213,10 +4212,9 @@ static struct _extent *_stats_get_extents_for_file(struct dm_pool *mem, int fd,
uint64_t *buf;
struct fiemap *fiemap = NULL;
struct fiemap_extent *fm_ext = NULL;
- struct fiemap_extent fm_last = {0};
+ struct fiemap_extent fm_last = {0}, fm_pending = {0};
struct _extent *extents;
unsigned long long expected = 0;
- unsigned long long expected_dense = 0;
unsigned long flags = 0;
unsigned int i, num = 0;
int tot_extents = 0, n = 0;
@@ -4264,31 +4262,51 @@ static struct _extent *_stats_get_extents_for_file(struct dm_pool *mem, int fd,
break;
for (i = 0; i < fiemap->fm_mapped_extents; i++) {
- expected_dense = fm_last.fe_physical +
- fm_last.fe_length;
- expected = fm_last.fe_physical +
- fm_ext[i].fe_logical - fm_last.fe_logical;
- if (ext_boundary(fm_ext[i], expected, expected_dense)) {
+ expected = fm_last.fe_physical + fm_last.fe_length;
+
+ if (fm_ext[i].fe_flags & FIEMAP_EXTENT_LAST)
+ last = 1;
+
+ /* cannot map extents that are not yet allocated. */
+ if (fm_ext[i].fe_flags
+ & (FIEMAP_EXTENT_UNKNOWN | FIEMAP_EXTENT_DELALLOC))
+ continue;
+
+ if (ext_boundary(fm_ext[i], expected)) {
tot_extents++;
- if (!_stats_add_extent(mem, fm_ext + i,
- tot_extents - 1))
+ if (!_stats_add_extent(mem, &fm_pending,
+ fm_pending.fe_flags))
goto_bad;
+ /* Begin a new pending extent. */
+ fm_pending.fe_flags = tot_extents - 1;
+ fm_pending.fe_physical = fm_ext[i].fe_physical;
+ fm_pending.fe_logical = fm_ext[i].fe_logical;
+ fm_pending.fe_length = fm_ext[i].fe_length;
} else {
expected = 0;
if (!tot_extents)
tot_extents = 1;
- if (fm_ext[i].fe_logical == 0)
- if (!_stats_add_extent(mem, fm_ext + i,
- tot_extents - 1))
- goto_bad;
+ /* Begin a new pending extent for extent 0. */
+ if (fm_ext[i].fe_logical == 0) {
+ fm_pending.fe_flags = tot_extents - 1;
+ fm_pending.fe_physical = fm_ext[i].fe_physical;
+ fm_pending.fe_logical = fm_ext[i].fe_logical;
+ fm_pending.fe_length = fm_ext[i].fe_length;
+ } else
+ fm_pending.fe_length += fm_ext[i].fe_length;
}
num += tot_extents;
- if (fm_ext[i].fe_flags & FIEMAP_EXTENT_LAST)
- last = 1;
fm_last = fm_ext[i];
n++;
}
+ /*
+ * If the file only has a single extent, no boundary is ever
+ * detected to trigger addition of the first extent.
+ */
+ if (fm_ext[i].fe_logical == 0)
+ _stats_add_extent(mem, &fm_pending, fm_pending.fe_flags);
+
fiemap->fm_start = (fm_ext[i - 1].fe_logical +
fm_ext[i - 1].fe_length);
} while (last == 0);
6 years, 5 months