nbdkit/0004-checkwrite-Display-differences-if-D-checkwrite.showd.patch
Richard W.M. Jones ea09ddbfb4 Rebase to nbdkit 1.46.1
Backport nbdkit_debug_hexdiff from nbdkit 1.47.
  resolves: RHEL-111242
Synchronize spec file with Fedora.
vddk: Don't use FNM_PATHNAME when matching export parameter
  resolves: RHEL-122755
2026-01-04 09:27:36 +00:00

255 lines
8.2 KiB
Diff

From 99153ed5592c9a08c5d5c393a625c54a5a0ea0c0 Mon Sep 17 00:00:00 2001
From: "Richard W.M. Jones" <rjones@redhat.com>
Date: Tue, 30 Dec 2025 17:09:07 +0000
Subject: [PATCH] checkwrite: Display differences if -D checkwrite.showdiffs=1
is used
Add a debug flag which shows the differences between what was written
and what we expected.
(cherry picked from commit 6a1c92f6a30941f8a891e704eeb95296e6d5669a)
---
filters/checkwrite/checkwrite.c | 27 +++++--
.../checkwrite/nbdkit-checkwrite-filter.pod | 14 +++-
tests/Makefile.am | 2 +
tests/test-checkwrite-evil.sh | 80 +++++++++++++++++++
tests/test-checkwrite-fail.sh | 1 +
tests/test-checkwrite.sh | 3 +-
6 files changed, 120 insertions(+), 7 deletions(-)
create mode 100755 tests/test-checkwrite-evil.sh
diff --git a/filters/checkwrite/checkwrite.c b/filters/checkwrite/checkwrite.c
index d5f20e54..44fb22aa 100644
--- a/filters/checkwrite/checkwrite.c
+++ b/filters/checkwrite/checkwrite.c
@@ -108,9 +108,26 @@ checkwrite_can_multi_conn (nbdkit_next *next,
return 1;
}
+NBDKIT_DLL_PUBLIC int checkwrite_debug_showdiffs = 0;
+
static inline int
-data_does_not_match (int *err)
+data_does_not_match (int *err,
+ const void *expected, const void *actual, size_t count,
+ uint64_t offset)
{
+ if (checkwrite_debug_showdiffs) {
+ /* Caller passes expected == NULL to mean we expected zeroes.
+ * However hexdiff requires an actual buffer, so ...
+ */
+ CLEANUP_FREE char *zerobuf = NULL;
+
+ if (expected == NULL)
+ zerobuf = calloc (count, 1);
+
+ if (expected || zerobuf)
+ nbdkit_debug_hexdiff (expected ? : zerobuf, actual, count, NULL, offset);
+ }
+
*err = EIO;
nbdkit_error ("data written does not match expected");
return -1;
@@ -137,8 +154,8 @@ checkwrite_pwrite (nbdkit_next *next,
return -1;
/* If data written doesn't match data expected, inject EIO. */
- if (memcmp (buf, expected, count) != 0)
- return data_does_not_match (err);
+ if (memcmp (expected, buf, count) != 0)
+ return data_does_not_match (err, expected, buf, count, offset);
return 0;
}
@@ -207,7 +224,7 @@ checkwrite_trim_zero (nbdkit_next *next,
if (next->pread (next, buf, buflen, offset, 0, err) == -1)
return -1;
if (! is_zero (buf, buflen))
- return data_does_not_match (err);
+ return data_does_not_match (err, NULL, buf, buflen, offset);
count -= buflen;
offset += buflen;
@@ -243,7 +260,7 @@ checkwrite_trim_zero (nbdkit_next *next,
if (next->pread (next, buf, n, offset, 0, err) == -1)
return -1;
if (! is_zero (buf, n))
- return data_does_not_match (err);
+ return data_does_not_match (err, NULL, buf, n, offset);
count -= n;
offset += n;
}
diff --git a/filters/checkwrite/nbdkit-checkwrite-filter.pod b/filters/checkwrite/nbdkit-checkwrite-filter.pod
index 6855d798..0689fb26 100644
--- a/filters/checkwrite/nbdkit-checkwrite-filter.pod
+++ b/filters/checkwrite/nbdkit-checkwrite-filter.pod
@@ -4,7 +4,7 @@ nbdkit-checkwrite-filter - check writes match contents of plugin
=head1 SYNOPSIS
- nbdkit --filter=checkwrite PLUGIN
+ nbdkit --filter=checkwrite PLUGIN [-D checkwrite.showdiffs=1]
=head1 DESCRIPTION
@@ -59,6 +59,17 @@ with arbitrary plugins.
There are no parameters specific to this filter. Parameters are
passed through to the underlying plugin.
+=head1 DEBUG FLAG
+
+When both foreground mode and debugging are enabled (I<-fv>) you can
+get checkwrite to show the differences between what was written and
+what should have been written by adding:
+
+ nbdkit -fv --filter=checkwrite -D checkwrite.showdiffs=1 [...]
+
+For further information on the format used see
+L<nbdkit_debug_hexdiff(3)>.
+
=head1 FILES
=over 4
@@ -82,6 +93,7 @@ L<nbdkit-random-plugin(1)>,
L<nbdkit-sparse-random-plugin(1)>,
L<nbdkit-filter(3)>,
L<nbdkit-plugin(3)>,
+L<nbdkit_debug_hexdiff(3)>,
L<nbdcopy(1)>,
L<qemu-img(1)>.
diff --git a/tests/Makefile.am b/tests/Makefile.am
index a887ac75..beeb0fc3 100644
--- a/tests/Makefile.am
+++ b/tests/Makefile.am
@@ -1806,12 +1806,14 @@ EXTRA_DIST += \
TESTS += \
test-checkwrite.sh \
test-checkwrite-bounds.sh \
+ test-checkwrite-evil.sh \
test-checkwrite-fail.sh \
test-checkwrite-fastzero.sh \
$(NULL)
EXTRA_DIST += \
test-checkwrite.sh \
test-checkwrite-bounds.sh \
+ test-checkwrite-evil.sh \
test-checkwrite-fail.sh \
test-checkwrite-fastzero.sh \
$(NULL)
diff --git a/tests/test-checkwrite-evil.sh b/tests/test-checkwrite-evil.sh
new file mode 100755
index 00000000..2d9e25b4
--- /dev/null
+++ b/tests/test-checkwrite-evil.sh
@@ -0,0 +1,80 @@
+#!/usr/bin/env bash
+# nbdkit
+# Copyright Red Hat
+#
+# Redistribution and use in source and binary forms, with or without
+# modification, are permitted provided that the following conditions are
+# met:
+#
+# * Redistributions of source code must retain the above copyright
+# notice, this list of conditions and the following disclaimer.
+#
+# * Redistributions in binary form must reproduce the above copyright
+# notice, this list of conditions and the following disclaimer in the
+# documentation and/or other materials provided with the distribution.
+#
+# * Neither the name of Red Hat nor the names of its contributors may be
+# used to endorse or promote products derived from this software without
+# specific prior written permission.
+#
+# THIS SOFTWARE IS PROVIDED BY RED HAT AND CONTRIBUTORS ''AS IS'' AND
+# ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
+# THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
+# PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL RED HAT OR
+# CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
+# USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+# ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
+# OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
+# OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+# SUCH DAMAGE.
+
+# Test checkwrite + evil filters together.
+
+source ./functions.sh
+set -e
+set -x
+set -u
+
+# Across a 1G disk, with the default failure probability of the evil
+# filter, we expect about 43 stuck high bits. The test actually fails
+# at the first stuck high bit so we don't end up grinding across the
+# whole virtual size.
+size=1G
+
+requires_plugin null
+requires_filter checkwrite
+requires_filter evil
+requires_filter noextents
+
+# nbdcopy >= 1.5.9 required for this test.
+requires_nbdcopy
+requires_libnbd_version 1.5.9
+
+sock1=$(mktemp -u /tmp/nbdkit-test-sock.XXXXXX)
+sock2=$(mktemp -u /tmp/nbdkit-test-sock.XXXXXX)
+pid1=checkwrite-evil.pid1
+pid2=checkwrite-evil.pid2
+files="$sock1 $sock2 $pid1 $pid2"
+rm -f $files
+cleanup_fn rm -f $files
+
+# Source nbdkit.
+start_nbdkit -P $pid1 -U $sock1 \
+ null $size \
+ --filter=evil \
+ --filter=noextents
+
+# Target nbdkit.
+start_nbdkit -P $pid2 -U $sock2 \
+ -v -D checkwrite.showdiffs=1 \
+ null $size \
+ --filter=checkwrite
+
+fail=
+nbdcopy "nbd+unix:///?socket=$sock1" "nbd+unix:///?socket=$sock2" || fail=1
+if ! test "$fail"; then
+ echo "$0: expected nbdcopy to fail but it did not"
+ exit 1
+fi
diff --git a/tests/test-checkwrite-fail.sh b/tests/test-checkwrite-fail.sh
index d46c2865..c577b12d 100755
--- a/tests/test-checkwrite-fail.sh
+++ b/tests/test-checkwrite-fail.sh
@@ -49,6 +49,7 @@ import sys
h.connect_command(["nbdkit", "-s", "-v",
"--filter=checkwrite",
+ "-D", "checkwrite.showdiffs=1",
"memory", "1M"])
try:
h.pwrite(b"1", 0)
diff --git a/tests/test-checkwrite.sh b/tests/test-checkwrite.sh
index aecb729c..490ab45b 100755
--- a/tests/test-checkwrite.sh
+++ b/tests/test-checkwrite.sh
@@ -46,7 +46,8 @@ requires_libnbd_version 1.5.9
do_test ()
{
- nbdkit -v --filter=checkwrite "$@" --run 'nbdcopy "$uri" "$uri"'
+ nbdkit -v --filter=checkwrite -D checkwrite.showdiffs=1 "$@" \
+ --run 'nbdcopy "$uri" "$uri"'
}
# Tests zero-sized disk.
--
2.47.3