qemu-devel.nongnu.org archive mirror
 help / color / mirror / Atom feed
* [PATCH 0/3] qcow2: Fix alloc_cluster_abort() for pre-existing clusters
@ 2020-02-25 14:31 Max Reitz
  2020-02-25 14:31 ` [PATCH 1/3] " Max Reitz
                   ` (3 more replies)
  0 siblings, 4 replies; 5+ messages in thread
From: Max Reitz @ 2020-02-25 14:31 UTC (permalink / raw)
  To: qemu-block; +Cc: Kevin Wolf, qemu-stable, qemu-devel, Max Reitz

Hi,

With c3b6658c1a5a3fb2, Kevin has fixed a case in alloc_cluster_abort()
where we used to free a cluster that wasn’t even allocated by
handle_alloc(), thus leading to an error and/or corruption.  Besides
external data files, there is another case where alloc_cluster_abort()
must not free the “new” cluster: Namely when the cluster isn’t new
because we’re reusing an existing pre-allocated zero cluster.

I think Berto’s subcluster series fixes this, too, but it’s still an
RFC, so I suppose we have to fix the bug independently of it.

Patch 2 adds a regression test; patch 3 adds a regression test for
Kevin’s patch c3b6658c1a5a3fb2 (which didn’t come with one).


Max Reitz (3):
  qcow2: Fix alloc_cluster_abort() for pre-existing clusters
  iotests/026: Test EIO on preallocated zero cluster
  iotests/026: Test EIO on allocation in a data-file

 block/qcow2-cluster.c              |  2 +-
 tests/qemu-iotests/026             | 53 ++++++++++++++++++++++++++++++
 tests/qemu-iotests/026.out         | 16 +++++++++
 tests/qemu-iotests/026.out.nocache | 16 +++++++++
 4 files changed, 86 insertions(+), 1 deletion(-)

-- 
2.24.1



^ permalink raw reply	[flat|nested] 5+ messages in thread

* [PATCH 1/3] qcow2: Fix alloc_cluster_abort() for pre-existing clusters
  2020-02-25 14:31 [PATCH 0/3] qcow2: Fix alloc_cluster_abort() for pre-existing clusters Max Reitz
@ 2020-02-25 14:31 ` Max Reitz
  2020-02-25 14:31 ` [PATCH 2/3] iotests/026: Test EIO on preallocated zero cluster Max Reitz
                   ` (2 subsequent siblings)
  3 siblings, 0 replies; 5+ messages in thread
From: Max Reitz @ 2020-02-25 14:31 UTC (permalink / raw)
  To: qemu-block; +Cc: Kevin Wolf, qemu-stable, qemu-devel, Max Reitz

handle_alloc() reuses preallocated zero clusters.  If anything goes
wrong during the data write, we do not change their L2 entry, so we
must not let qcow2_alloc_cluster_abort() free them.

Fixes: 8b24cd141549b5b264baeddd4e72902cfb5de23b
Cc: qemu-stable@nongnu.org
Signed-off-by: Max Reitz <mreitz@redhat.com>
---
 block/qcow2-cluster.c | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/block/qcow2-cluster.c b/block/qcow2-cluster.c
index 78c95dfa16..17f1363279 100644
--- a/block/qcow2-cluster.c
+++ b/block/qcow2-cluster.c
@@ -1026,7 +1026,7 @@ err:
 void qcow2_alloc_cluster_abort(BlockDriverState *bs, QCowL2Meta *m)
 {
     BDRVQcow2State *s = bs->opaque;
-    if (!has_data_file(bs)) {
+    if (!has_data_file(bs) && !m->keep_old_clusters) {
         qcow2_free_clusters(bs, m->alloc_offset,
                             m->nb_clusters << s->cluster_bits,
                             QCOW2_DISCARD_NEVER);
-- 
2.24.1



^ permalink raw reply related	[flat|nested] 5+ messages in thread

* [PATCH 2/3] iotests/026: Test EIO on preallocated zero cluster
  2020-02-25 14:31 [PATCH 0/3] qcow2: Fix alloc_cluster_abort() for pre-existing clusters Max Reitz
  2020-02-25 14:31 ` [PATCH 1/3] " Max Reitz
@ 2020-02-25 14:31 ` Max Reitz
  2020-02-25 14:31 ` [PATCH 3/3] iotests/026: Test EIO on allocation in a data-file Max Reitz
  2020-02-26 13:53 ` [PATCH 0/3] qcow2: Fix alloc_cluster_abort() for pre-existing clusters Kevin Wolf
  3 siblings, 0 replies; 5+ messages in thread
From: Max Reitz @ 2020-02-25 14:31 UTC (permalink / raw)
  To: qemu-block; +Cc: Kevin Wolf, qemu-stable, qemu-devel, Max Reitz

Test what happens when writing data to a preallocated zero cluster, but
the data write fails.

Signed-off-by: Max Reitz <mreitz@redhat.com>
---
 tests/qemu-iotests/026             | 21 +++++++++++++++++++++
 tests/qemu-iotests/026.out         | 10 ++++++++++
 tests/qemu-iotests/026.out.nocache | 10 ++++++++++
 3 files changed, 41 insertions(+)

diff --git a/tests/qemu-iotests/026 b/tests/qemu-iotests/026
index a4aa74764f..0c1273c339 100755
--- a/tests/qemu-iotests/026
+++ b/tests/qemu-iotests/026
@@ -218,6 +218,27 @@ _make_test_img 64M
 $QEMU_IO -c "write 0 1M" -c "write 0 1M" "$BLKDBG_TEST_IMG" | _filter_qemu_io
 _check_test_img
 
+echo
+echo === Avoid freeing preallocated zero clusters on failure ===
+echo
+
+cat > "$TEST_DIR/blkdebug.conf" <<EOF
+[inject-error]
+event = "write_aio"
+errno = "5"
+once = "on"
+EOF
+
+_make_test_img $CLUSTER_SIZE
+# Create a preallocated zero cluster
+$QEMU_IO -c "write 0 $CLUSTER_SIZE" -c "write -z 0 $CLUSTER_SIZE" "$TEST_IMG" \
+    | _filter_qemu_io
+# Try to overwrite it (prompting an I/O error from blkdebug), thus
+# triggering the alloc abort code
+$QEMU_IO -c "write 0 $CLUSTER_SIZE" "$BLKDBG_TEST_IMG" | _filter_qemu_io
+
+_check_test_img
+
 # success, all done
 echo "*** done"
 rm -f $seq.full
diff --git a/tests/qemu-iotests/026.out b/tests/qemu-iotests/026.out
index ff0817b6f2..83989996ff 100644
--- a/tests/qemu-iotests/026.out
+++ b/tests/qemu-iotests/026.out
@@ -643,4 +643,14 @@ write failed: Input/output error
 wrote 1048576/1048576 bytes at offset 0
 1 MiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
 No errors were found on the image.
+
+=== Avoid freeing preallocated zero clusters on failure ===
+
+Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=1024
+wrote 1024/1024 bytes at offset 0
+1 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
+wrote 1024/1024 bytes at offset 0
+1 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
+write failed: Input/output error
+No errors were found on the image.
 *** done
diff --git a/tests/qemu-iotests/026.out.nocache b/tests/qemu-iotests/026.out.nocache
index 495d013007..9359d26d7e 100644
--- a/tests/qemu-iotests/026.out.nocache
+++ b/tests/qemu-iotests/026.out.nocache
@@ -651,4 +651,14 @@ write failed: Input/output error
 wrote 1048576/1048576 bytes at offset 0
 1 MiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
 No errors were found on the image.
+
+=== Avoid freeing preallocated zero clusters on failure ===
+
+Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=1024
+wrote 1024/1024 bytes at offset 0
+1 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
+wrote 1024/1024 bytes at offset 0
+1 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
+write failed: Input/output error
+No errors were found on the image.
 *** done
-- 
2.24.1



^ permalink raw reply related	[flat|nested] 5+ messages in thread

* [PATCH 3/3] iotests/026: Test EIO on allocation in a data-file
  2020-02-25 14:31 [PATCH 0/3] qcow2: Fix alloc_cluster_abort() for pre-existing clusters Max Reitz
  2020-02-25 14:31 ` [PATCH 1/3] " Max Reitz
  2020-02-25 14:31 ` [PATCH 2/3] iotests/026: Test EIO on preallocated zero cluster Max Reitz
@ 2020-02-25 14:31 ` Max Reitz
  2020-02-26 13:53 ` [PATCH 0/3] qcow2: Fix alloc_cluster_abort() for pre-existing clusters Kevin Wolf
  3 siblings, 0 replies; 5+ messages in thread
From: Max Reitz @ 2020-02-25 14:31 UTC (permalink / raw)
  To: qemu-block; +Cc: Kevin Wolf, qemu-stable, qemu-devel, Max Reitz

Test what happens when writing data to an external data file, where the
write requires an L2 entry to be allocated, but the data write fails.

Signed-off-by: Max Reitz <mreitz@redhat.com>
---
 tests/qemu-iotests/026             | 32 ++++++++++++++++++++++++++++++
 tests/qemu-iotests/026.out         |  6 ++++++
 tests/qemu-iotests/026.out.nocache |  6 ++++++
 3 files changed, 44 insertions(+)

diff --git a/tests/qemu-iotests/026 b/tests/qemu-iotests/026
index 0c1273c339..b05a4692cf 100755
--- a/tests/qemu-iotests/026
+++ b/tests/qemu-iotests/026
@@ -30,6 +30,7 @@ _cleanup()
 {
 	_cleanup_test_img
     rm "$TEST_DIR/blkdebug.conf"
+    rm -f "$TEST_IMG.data_file"
 }
 trap "_cleanup; exit \$status" 0 1 2 3 15
 
@@ -239,6 +240,37 @@ $QEMU_IO -c "write 0 $CLUSTER_SIZE" "$BLKDBG_TEST_IMG" | _filter_qemu_io
 
 _check_test_img
 
+echo
+echo === Avoid freeing external data clusters on failure ===
+echo
+
+# Similar test as the last one, except we test what happens when there
+# is an error when writing to an external data file instead of when
+# writing to a preallocated zero cluster
+_make_test_img -o "data_file=$TEST_IMG.data_file" $CLUSTER_SIZE
+
+# Put blkdebug above the data-file, and a raw node on top of that so
+# that blkdebug will see a write_aio event and emit an error
+$QEMU_IO -c "write 0 $CLUSTER_SIZE" \
+    "json:{
+         'driver': 'qcow2',
+         'file': { 'driver': 'file', 'filename': '$TEST_IMG' },
+         'data-file': {
+             'driver': 'raw',
+             'file': {
+                 'driver': 'blkdebug',
+                 'config': '$TEST_DIR/blkdebug.conf',
+                 'image': {
+                     'driver': 'file',
+                     'filename': '$TEST_IMG.data_file'
+                 }
+             }
+         }
+     }" \
+    | _filter_qemu_io
+
+_check_test_img
+
 # success, all done
 echo "*** done"
 rm -f $seq.full
diff --git a/tests/qemu-iotests/026.out b/tests/qemu-iotests/026.out
index 83989996ff..c1b3b58482 100644
--- a/tests/qemu-iotests/026.out
+++ b/tests/qemu-iotests/026.out
@@ -653,4 +653,10 @@ wrote 1024/1024 bytes at offset 0
 1 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
 write failed: Input/output error
 No errors were found on the image.
+
+=== Avoid freeing external data clusters on failure ===
+
+Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=1024 data_file=TEST_DIR/t.IMGFMT.data_file
+write failed: Input/output error
+No errors were found on the image.
 *** done
diff --git a/tests/qemu-iotests/026.out.nocache b/tests/qemu-iotests/026.out.nocache
index 9359d26d7e..8d5001648a 100644
--- a/tests/qemu-iotests/026.out.nocache
+++ b/tests/qemu-iotests/026.out.nocache
@@ -661,4 +661,10 @@ wrote 1024/1024 bytes at offset 0
 1 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
 write failed: Input/output error
 No errors were found on the image.
+
+=== Avoid freeing external data clusters on failure ===
+
+Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=1024 data_file=TEST_DIR/t.IMGFMT.data_file
+write failed: Input/output error
+No errors were found on the image.
 *** done
-- 
2.24.1



^ permalink raw reply related	[flat|nested] 5+ messages in thread

* Re: [PATCH 0/3] qcow2: Fix alloc_cluster_abort() for pre-existing clusters
  2020-02-25 14:31 [PATCH 0/3] qcow2: Fix alloc_cluster_abort() for pre-existing clusters Max Reitz
                   ` (2 preceding siblings ...)
  2020-02-25 14:31 ` [PATCH 3/3] iotests/026: Test EIO on allocation in a data-file Max Reitz
@ 2020-02-26 13:53 ` Kevin Wolf
  3 siblings, 0 replies; 5+ messages in thread
From: Kevin Wolf @ 2020-02-26 13:53 UTC (permalink / raw)
  To: Max Reitz; +Cc: qemu-devel, qemu-block, qemu-stable

Am 25.02.2020 um 15:31 hat Max Reitz geschrieben:
> With c3b6658c1a5a3fb2, Kevin has fixed a case in alloc_cluster_abort()
> where we used to free a cluster that wasn’t even allocated by
> handle_alloc(), thus leading to an error and/or corruption.  Besides
> external data files, there is another case where alloc_cluster_abort()
> must not free the “new” cluster: Namely when the cluster isn’t new
> because we’re reusing an existing pre-allocated zero cluster.
> 
> I think Berto’s subcluster series fixes this, too, but it’s still an
> RFC, so I suppose we have to fix the bug independently of it.
> 
> Patch 2 adds a regression test; patch 3 adds a regression test for
> Kevin’s patch c3b6658c1a5a3fb2 (which didn’t come with one).

Thanks, applied to the block branch.

Kevin



^ permalink raw reply	[flat|nested] 5+ messages in thread

end of thread, other threads:[~2020-02-26 13:54 UTC | newest]

Thread overview: 5+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2020-02-25 14:31 [PATCH 0/3] qcow2: Fix alloc_cluster_abort() for pre-existing clusters Max Reitz
2020-02-25 14:31 ` [PATCH 1/3] " Max Reitz
2020-02-25 14:31 ` [PATCH 2/3] iotests/026: Test EIO on preallocated zero cluster Max Reitz
2020-02-25 14:31 ` [PATCH 3/3] iotests/026: Test EIO on allocation in a data-file Max Reitz
2020-02-26 13:53 ` [PATCH 0/3] qcow2: Fix alloc_cluster_abort() for pre-existing clusters Kevin Wolf

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).