Either if we are querying an extent larger than ~ 4G, or more simply
if the server returns adjacent extents of the same type, nbdinfo --map
will now coalesce them which makes the output more readable.
This also adjust an existing test and adds new tests.
I didn't feel there was any need to add a "no-coalesce" option
(although one certainly could be added) for a couple of reasons:
(1) nbdinfo is splitting some large requests itself.
(2) If you really want this information you can use the libnbd API.
---
info/Makefile.am | 2 +
info/info-map-base-allocation-large.sh | 7 ++-
info/info-map-base-allocation-weird.sh | 49 +++++++++++++++
info/info-map-base-allocation-zero.sh | 37 +++++++++++
info/nbdinfo.c | 85 ++++++++++++++++++--------
5 files changed, 150 insertions(+), 30 deletions(-)
diff --git a/info/Makefile.am b/info/Makefile.am
index 8303658..c3ab780 100644
--- a/info/Makefile.am
+++ b/info/Makefile.am
@@ -32,6 +32,8 @@ info_sh_files = \
info-map-base-allocation.sh \
info-map-base-allocation-json.sh \
info-map-base-allocation-large.sh \
+ info-map-base-allocation-weird.sh \
+ info-map-base-allocation-zero.sh \
info-map-qemu-dirty-bitmap.sh \
info-atomic-output.sh \
$(NULL)
diff --git a/info/info-map-base-allocation-large.sh
b/info/info-map-base-allocation-large.sh
index 373a974..7d87368 100755
--- a/info/info-map-base-allocation-large.sh
+++ b/info/info-map-base-allocation-large.sh
@@ -30,7 +30,7 @@ rm -f $out
# The sparse allocator used by nbdkit-data-plugin uses a 32K page
# size, and extents are always aligned with this.
-nbdkit -U - data data='1 @131072 2' size=6G \
+nbdkit -U - data data='1 @131072 2 @6442450944 3' size=8G \
--run '$VG nbdinfo --map "$uri"' > $out
cat $out
@@ -38,8 +38,9 @@ cat $out
if [ "$(tr -s ' ' < $out)" != " 0 32768 0 allocated
32768 98304 3 hole,zero
131072 32768 0 allocated
- 163840 4294803456 3 hole,zero
-4294967296 2147483648 3 hole,zero" ]; then
+ 163840 6442287104 3 hole,zero
+6442450944 32768 0 allocated
+6442483712 2147450880 3 hole,zero" ]; then
echo "$0: unexpected output from nbdinfo --map"
exit 1
fi
diff --git a/info/info-map-base-allocation-weird.sh
b/info/info-map-base-allocation-weird.sh
new file mode 100755
index 0000000..c766ebf
--- /dev/null
+++ b/info/info-map-base-allocation-weird.sh
@@ -0,0 +1,49 @@
+#!/usr/bin/env bash
+# nbd client library in userspace
+# Copyright (C) 2020 Red Hat Inc.
+#
+# This library is free software; you can redistribute it and/or
+# modify it under the terms of the GNU Lesser General Public
+# License as published by the Free Software Foundation; either
+# version 2 of the License, or (at your option) any later version.
+#
+# This library is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+# Lesser General Public License for more details.
+#
+# You should have received a copy of the GNU Lesser General Public
+# License along with this library; if not, write to the Free Software
+# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+
+. ../tests/functions.sh
+
+set -e
+set -x
+
+requires nbdkit --version
+requires nbdkit sh --version
+requires tr --version
+
+out=info-base-allocation-weird.out
+cleanup_fn rm -f $out
+rm -f $out
+
+# This is a "weird" server that returns extents that are all 1 byte.
+nbdkit -U - sh - \
+ --run '$VG nbdinfo --map "$uri"' > $out
<<'EOF'
+case "$1" in
+ get_size) echo 32 ;;
+ pread) dd if=/dev/zero count=$3 iflag=count_bytes ;;
+ can_extents) exit 0 ;;
+ extents) echo $4 1 ;;
+ *) exit 2 ;;
+esac
+EOF
+
+cat $out
+
+if [ "$(tr -s ' ' < $out)" != " 0 32 0 allocated" ]; then
+ echo "$0: unexpected output from nbdinfo --map"
+ exit 1
+fi
diff --git a/info/info-map-base-allocation-zero.sh
b/info/info-map-base-allocation-zero.sh
new file mode 100755
index 0000000..3d3d44e
--- /dev/null
+++ b/info/info-map-base-allocation-zero.sh
@@ -0,0 +1,37 @@
+#!/usr/bin/env bash
+# nbd client library in userspace
+# Copyright (C) 2020 Red Hat Inc.
+#
+# This library is free software; you can redistribute it and/or
+# modify it under the terms of the GNU Lesser General Public
+# License as published by the Free Software Foundation; either
+# version 2 of the License, or (at your option) any later version.
+#
+# This library is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+# Lesser General Public License for more details.
+#
+# You should have received a copy of the GNU Lesser General Public
+# License along with this library; if not, write to the Free Software
+# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+
+. ../tests/functions.sh
+
+set -e
+set -x
+
+requires nbdkit --version
+
+out=info-base-allocation-zero.out
+cleanup_fn rm -f $out
+rm -f $out
+
+nbdkit -U - null --run '$VG nbdinfo --map "$uri"' > $out
+
+cat $out
+
+if [ "$(cat $out)" != "" ]; then
+ echo "$0: unexpected output from nbdinfo --map"
+ exit 1
+fi
diff --git a/info/nbdinfo.c b/info/nbdinfo.c
index 088d673..2a08a13 100644
--- a/info/nbdinfo.c
+++ b/info/nbdinfo.c
@@ -801,45 +801,76 @@ extent_description (const char *metacontext, uint32_t type)
return NULL; /* Don't know - description field will be omitted. */
}
+static void print_one_extent (uint64_t offset, uint64_t len, uint32_t type);
+
static void
print_extents (uint32_vector *entries)
{
- uint64_t offset = 0;
- size_t i;
- bool comma = false;
+ size_t i, j;
+ uint64_t offset = 0; /* end of last extent printed + 1 */
+ size_t last = 0; /* last entry printed + 2 */
if (json_output) fprintf (fp, "[\n");
for (i = 0; i < entries->size; i += 2) {
- const char *descr = extent_description (map, entries->ptr[i+1]);
+ uint32_t type = entries->ptr[last+1];
- if (!json_output) {
- fprintf (fp, "%10" PRIu64 " "
- "%10" PRIu32 " "
- "%3" PRIu32,
- offset, entries->ptr[i], entries->ptr[i+1]);
- if (descr)
- fprintf (fp, " %s", descr);
- fprintf (fp, "\n");
- }
- else {
- if (comma)
- fprintf (fp, ",\n");
+ /* If we're coalescing and the current type is different from the
+ * previous one then we should print everything up to this entry.
+ */
+ if (last != i && entries->ptr[i+1] != type) {
+ uint64_t len;
- fprintf (fp, "{ \"offset\": %" PRIu64 ", "
- "\"length\": %" PRIu32 ", "
- "\"type\": %" PRIu32,
- offset, entries->ptr[i], entries->ptr[i+1]);
- if (descr) {
- fprintf (fp, ", \"description\": ");
- print_json_string (descr);
- }
- fprintf (fp, "}");
- comma = true;
+ /* Calculate the length of the coalesced extent. */
+ for (j = last, len = 0; j < i; j += 2)
+ len += entries->ptr[j];
+ print_one_extent (offset, len, type);
+ offset += len;
+ last = i;
}
+ }
+
+ /* Print the last extent if there is one. */
+ if (last != i) {
+ uint32_t type = entries->ptr[last+1];
+ uint64_t len;
- offset += entries->ptr[i];
+ for (j = last, len = 0; j < i; j += 2)
+ len += entries->ptr[j];
+ print_one_extent (offset, len, type);
}
if (json_output) fprintf (fp, "\n]\n");
}
+
+static void
+print_one_extent (uint64_t offset, uint64_t len, uint32_t type)
+{
+ static bool comma = false;
+ const char *descr = extent_description (map, type);
+
+ if (!json_output) {
+ fprintf (fp, "%10" PRIu64 " "
+ "%10" PRIu64 " "
+ "%3" PRIu32,
+ offset, len, type);
+ if (descr)
+ fprintf (fp, " %s", descr);
+ fprintf (fp, "\n");
+ }
+ else {
+ if (comma)
+ fprintf (fp, ",\n");
+
+ fprintf (fp, "{ \"offset\": %" PRIu64 ", "
+ "\"length\": %" PRIu64 ", "
+ "\"type\": %" PRIu32,
+ offset, len, type);
+ if (descr) {
+ fprintf (fp, ", \"description\": ");
+ print_json_string (descr);
+ }
+ fprintf (fp, "}");
+ comma = true;
+ }
+}
--
2.29.0.rc2