|
|
05bba0 |
From 8538f7d5ace7b8ddb751d61a17c4a822b2333b39 Mon Sep 17 00:00:00 2001
|
|
|
05bba0 |
From: Max Reitz <mreitz@redhat.com>
|
|
|
05bba0 |
Date: Sat, 13 Jun 2015 16:22:35 +0200
|
|
|
05bba0 |
Subject: [PATCH 41/42] qcow2: Fix header update with overridden backing file
|
|
|
05bba0 |
|
|
|
05bba0 |
Message-id: <1434212556-3927-42-git-send-email-mreitz@redhat.com>
|
|
|
05bba0 |
Patchwork-id: 66060
|
|
|
05bba0 |
O-Subject: [RHEL-7.2 qemu-kvm PATCH 41/42] qcow2: Fix header update with overridden backing file
|
|
|
05bba0 |
Bugzilla: 1129893
|
|
|
05bba0 |
RH-Acked-by: Jeffrey Cody <jcody@redhat.com>
|
|
|
05bba0 |
RH-Acked-by: Fam Zheng <famz@redhat.com>
|
|
|
05bba0 |
RH-Acked-by: Stefan Hajnoczi <stefanha@redhat.com>
|
|
|
05bba0 |
|
|
|
05bba0 |
From: Kevin Wolf <kwolf@redhat.com>
|
|
|
05bba0 |
|
|
|
05bba0 |
BZ: 1129893
|
|
|
05bba0 |
|
|
|
05bba0 |
In recent qemu versions, it is possible to override the backing file
|
|
|
05bba0 |
name and format that is stored in the image file with values given at
|
|
|
05bba0 |
runtime. In such cases, the temporary override could end up in the
|
|
|
05bba0 |
image header if the qcow2 header was updated, while obviously correct
|
|
|
05bba0 |
behaviour would be to leave the on-disk backing file path/format
|
|
|
05bba0 |
unchanged.
|
|
|
05bba0 |
|
|
|
05bba0 |
Fix this and add a test case for it.
|
|
|
05bba0 |
|
|
|
05bba0 |
Reported-by: Michael Tokarev <mjt@tls.msk.ru>
|
|
|
05bba0 |
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
|
|
|
05bba0 |
Reviewed-by: Eric Blake <eblake@redhat.com>
|
|
|
05bba0 |
Message-id: 1428411796-2852-1-git-send-email-kwolf@redhat.com
|
|
|
05bba0 |
Signed-off-by: Stefan Hajnoczi <stefanha@redhat.com>
|
|
|
05bba0 |
(cherry picked from commit e4603fe139e2161464d7e75faa3a650e31f057fc)
|
|
|
05bba0 |
Signed-off-by: Miroslav Rezanina <mrezanin@redhat.com>
|
|
|
05bba0 |
|
|
|
05bba0 |
Conflicts:
|
|
|
05bba0 |
tests/qemu-iotests/group
|
|
|
05bba0 |
tests/qemu-iotests/130
|
|
|
05bba0 |
tests/qemu-iotests/130.out
|
|
|
05bba0 |
|
|
|
05bba0 |
common.qemu does not exist downstream, so the HMP commit case cannot be
|
|
|
05bba0 |
tested. _filter_img_info does not exist either, so just omit it and add
|
|
|
05bba0 |
the additional cluster_size line to the test output (this test is
|
|
|
05bba0 |
qcow2-specific anyway).
|
|
|
05bba0 |
|
|
|
05bba0 |
Signed-off-by: Max Reitz <mreitz@redhat.com>
|
|
|
05bba0 |
---
|
|
|
05bba0 |
block/qcow2.c | 29 ++++++++++++++-----
|
|
|
05bba0 |
block/qcow2.h | 6 ++++
|
|
|
05bba0 |
tests/qemu-iotests/130 | 71 ++++++++++++++++++++++++++++++++++++++++++++++
|
|
|
05bba0 |
tests/qemu-iotests/130.out | 28 ++++++++++++++++++
|
|
|
05bba0 |
tests/qemu-iotests/group | 1 +
|
|
|
05bba0 |
5 files changed, 128 insertions(+), 7 deletions(-)
|
|
|
05bba0 |
create mode 100755 tests/qemu-iotests/130
|
|
|
05bba0 |
create mode 100644 tests/qemu-iotests/130.out
|
|
|
05bba0 |
|
|
|
05bba0 |
diff --git a/block/qcow2.c b/block/qcow2.c
|
|
|
05bba0 |
index 991c41f..61f7e57 100644
|
|
|
05bba0 |
--- a/block/qcow2.c
|
|
|
05bba0 |
+++ b/block/qcow2.c
|
|
|
05bba0 |
@@ -139,6 +139,7 @@ static int qcow2_read_extensions(BlockDriverState *bs, uint64_t start_offset,
|
|
|
05bba0 |
return 3;
|
|
|
05bba0 |
}
|
|
|
05bba0 |
bs->backing_format[ext.len] = '\0';
|
|
|
05bba0 |
+ s->image_backing_format = g_strdup(bs->backing_format);
|
|
|
05bba0 |
#ifdef DEBUG_EXT
|
|
|
05bba0 |
printf("Qcow2: Got format extension %s\n", bs->backing_format);
|
|
|
05bba0 |
#endif
|
|
|
05bba0 |
@@ -734,6 +735,7 @@ static int qcow2_open(BlockDriverState *bs, QDict *options, int flags,
|
|
|
05bba0 |
goto fail;
|
|
|
05bba0 |
}
|
|
|
05bba0 |
bs->backing_file[len] = '\0';
|
|
|
05bba0 |
+ s->image_backing_file = g_strdup(bs->backing_file);
|
|
|
05bba0 |
}
|
|
|
05bba0 |
|
|
|
05bba0 |
/* Internal snapshots */
|
|
|
05bba0 |
@@ -1249,6 +1251,9 @@ static void qcow2_close(BlockDriverState *bs)
|
|
|
05bba0 |
g_free(s->unknown_header_fields);
|
|
|
05bba0 |
cleanup_unknown_header_ext(bs);
|
|
|
05bba0 |
|
|
|
05bba0 |
+ g_free(s->image_backing_file);
|
|
|
05bba0 |
+ g_free(s->image_backing_format);
|
|
|
05bba0 |
+
|
|
|
05bba0 |
g_free(s->cluster_cache);
|
|
|
05bba0 |
qemu_vfree(s->cluster_data);
|
|
|
05bba0 |
qcow2_refcount_close(bs);
|
|
|
05bba0 |
@@ -1399,9 +1404,10 @@ int qcow2_update_header(BlockDriverState *bs)
|
|
|
05bba0 |
}
|
|
|
05bba0 |
|
|
|
05bba0 |
/* Backing file format header extension */
|
|
|
05bba0 |
- if (*bs->backing_format) {
|
|
|
05bba0 |
+ if (s->image_backing_format) {
|
|
|
05bba0 |
ret = header_ext_add(buf, QCOW2_EXT_MAGIC_BACKING_FORMAT,
|
|
|
05bba0 |
- bs->backing_format, strlen(bs->backing_format),
|
|
|
05bba0 |
+ s->image_backing_format,
|
|
|
05bba0 |
+ strlen(s->image_backing_format),
|
|
|
05bba0 |
buflen);
|
|
|
05bba0 |
if (ret < 0) {
|
|
|
05bba0 |
goto fail;
|
|
|
05bba0 |
@@ -1459,8 +1465,8 @@ int qcow2_update_header(BlockDriverState *bs)
|
|
|
05bba0 |
buflen -= ret;
|
|
|
05bba0 |
|
|
|
05bba0 |
/* Backing file name */
|
|
|
05bba0 |
- if (*bs->backing_file) {
|
|
|
05bba0 |
- size_t backing_file_len = strlen(bs->backing_file);
|
|
|
05bba0 |
+ if (s->image_backing_file) {
|
|
|
05bba0 |
+ size_t backing_file_len = strlen(s->image_backing_file);
|
|
|
05bba0 |
|
|
|
05bba0 |
if (buflen < backing_file_len) {
|
|
|
05bba0 |
ret = -ENOSPC;
|
|
|
05bba0 |
@@ -1468,7 +1474,7 @@ int qcow2_update_header(BlockDriverState *bs)
|
|
|
05bba0 |
}
|
|
|
05bba0 |
|
|
|
05bba0 |
/* Using strncpy is ok here, since buf is not NUL-terminated. */
|
|
|
05bba0 |
- strncpy(buf, bs->backing_file, buflen);
|
|
|
05bba0 |
+ strncpy(buf, s->image_backing_file, buflen);
|
|
|
05bba0 |
|
|
|
05bba0 |
header->backing_file_offset = cpu_to_be64(buf - ((char*) header));
|
|
|
05bba0 |
header->backing_file_size = cpu_to_be32(backing_file_len);
|
|
|
05bba0 |
@@ -1489,9 +1495,17 @@ fail:
|
|
|
05bba0 |
static int qcow2_change_backing_file(BlockDriverState *bs,
|
|
|
05bba0 |
const char *backing_file, const char *backing_fmt)
|
|
|
05bba0 |
{
|
|
|
05bba0 |
+ BDRVQcowState *s = bs->opaque;
|
|
|
05bba0 |
+
|
|
|
05bba0 |
pstrcpy(bs->backing_file, sizeof(bs->backing_file), backing_file ?: "");
|
|
|
05bba0 |
pstrcpy(bs->backing_format, sizeof(bs->backing_format), backing_fmt ?: "");
|
|
|
05bba0 |
|
|
|
05bba0 |
+ g_free(s->image_backing_file);
|
|
|
05bba0 |
+ g_free(s->image_backing_format);
|
|
|
05bba0 |
+
|
|
|
05bba0 |
+ s->image_backing_file = backing_file ? g_strdup(bs->backing_file) : NULL;
|
|
|
05bba0 |
+ s->image_backing_format = backing_fmt ? g_strdup(bs->backing_format) : NULL;
|
|
|
05bba0 |
+
|
|
|
05bba0 |
return qcow2_update_header(bs);
|
|
|
05bba0 |
}
|
|
|
05bba0 |
|
|
|
05bba0 |
@@ -2286,8 +2300,9 @@ static int qcow2_amend_options(BlockDriverState *bs,
|
|
|
05bba0 |
}
|
|
|
05bba0 |
|
|
|
05bba0 |
if (backing_file || backing_format) {
|
|
|
05bba0 |
- ret = qcow2_change_backing_file(bs, backing_file ?: bs->backing_file,
|
|
|
05bba0 |
- backing_format ?: bs->backing_format);
|
|
|
05bba0 |
+ ret = qcow2_change_backing_file(bs,
|
|
|
05bba0 |
+ backing_file ?: s->image_backing_file,
|
|
|
05bba0 |
+ backing_format ?: s->image_backing_format);
|
|
|
05bba0 |
if (ret < 0) {
|
|
|
05bba0 |
return ret;
|
|
|
05bba0 |
}
|
|
|
05bba0 |
diff --git a/block/qcow2.h b/block/qcow2.h
|
|
|
05bba0 |
index b210a7f..dd3e768 100644
|
|
|
05bba0 |
--- a/block/qcow2.h
|
|
|
05bba0 |
+++ b/block/qcow2.h
|
|
|
05bba0 |
@@ -263,6 +263,12 @@ typedef struct BDRVQcowState {
|
|
|
05bba0 |
QLIST_HEAD(, Qcow2UnknownHeaderExtension) unknown_header_ext;
|
|
|
05bba0 |
QTAILQ_HEAD (, Qcow2DiscardRegion) discards;
|
|
|
05bba0 |
bool cache_discards;
|
|
|
05bba0 |
+
|
|
|
05bba0 |
+ /* Backing file path and format as stored in the image (this is not the
|
|
|
05bba0 |
+ * effective path/format, which may be the result of a runtime option
|
|
|
05bba0 |
+ * override) */
|
|
|
05bba0 |
+ char *image_backing_file;
|
|
|
05bba0 |
+ char *image_backing_format;
|
|
|
05bba0 |
} BDRVQcowState;
|
|
|
05bba0 |
|
|
|
05bba0 |
/* XXX: use std qcow open function ? */
|
|
|
05bba0 |
diff --git a/tests/qemu-iotests/130 b/tests/qemu-iotests/130
|
|
|
05bba0 |
new file mode 100755
|
|
|
05bba0 |
index 0000000..68dbb48
|
|
|
05bba0 |
--- /dev/null
|
|
|
05bba0 |
+++ b/tests/qemu-iotests/130
|
|
|
05bba0 |
@@ -0,0 +1,71 @@
|
|
|
05bba0 |
+#!/bin/bash
|
|
|
05bba0 |
+#
|
|
|
05bba0 |
+# Test that temporary backing file overrides (on the command line or in
|
|
|
05bba0 |
+# blockdev-add) don't replace the original path stored in the image during
|
|
|
05bba0 |
+# header updates.
|
|
|
05bba0 |
+#
|
|
|
05bba0 |
+# Copyright (C) 2015 Red Hat, Inc.
|
|
|
05bba0 |
+#
|
|
|
05bba0 |
+# This program is free software; you can redistribute it and/or modify
|
|
|
05bba0 |
+# it under the terms of the GNU General Public License as published by
|
|
|
05bba0 |
+# the Free Software Foundation; either version 2 of the License, or
|
|
|
05bba0 |
+# (at your option) any later version.
|
|
|
05bba0 |
+#
|
|
|
05bba0 |
+# This program is distributed in the hope that it will be useful,
|
|
|
05bba0 |
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
|
05bba0 |
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
|
05bba0 |
+# GNU General Public License for more details.
|
|
|
05bba0 |
+#
|
|
|
05bba0 |
+# You should have received a copy of the GNU General Public License
|
|
|
05bba0 |
+# along with this program. If not, see <http://www.gnu.org/licenses/>.
|
|
|
05bba0 |
+#
|
|
|
05bba0 |
+
|
|
|
05bba0 |
+# creator
|
|
|
05bba0 |
+owner=kwolf@redhat.com
|
|
|
05bba0 |
+
|
|
|
05bba0 |
+seq="$(basename $0)"
|
|
|
05bba0 |
+echo "QA output created by $seq"
|
|
|
05bba0 |
+
|
|
|
05bba0 |
+here="$PWD"
|
|
|
05bba0 |
+tmp=/tmp/$$
|
|
|
05bba0 |
+status=1 # failure is the default!
|
|
|
05bba0 |
+
|
|
|
05bba0 |
+_cleanup()
|
|
|
05bba0 |
+{
|
|
|
05bba0 |
+ _cleanup_test_img
|
|
|
05bba0 |
+}
|
|
|
05bba0 |
+trap "_cleanup; exit \$status" 0 1 2 3 15
|
|
|
05bba0 |
+
|
|
|
05bba0 |
+# get standard environment, filters and checks
|
|
|
05bba0 |
+. ./common.rc
|
|
|
05bba0 |
+. ./common.filter
|
|
|
05bba0 |
+
|
|
|
05bba0 |
+_supported_fmt qcow2
|
|
|
05bba0 |
+_supported_proto generic
|
|
|
05bba0 |
+_supported_os Linux
|
|
|
05bba0 |
+
|
|
|
05bba0 |
+
|
|
|
05bba0 |
+TEST_IMG="$TEST_IMG.orig" _make_test_img 64M
|
|
|
05bba0 |
+TEST_IMG="$TEST_IMG.base" _make_test_img 64M
|
|
|
05bba0 |
+_make_test_img 64M
|
|
|
05bba0 |
+_img_info
|
|
|
05bba0 |
+
|
|
|
05bba0 |
+echo
|
|
|
05bba0 |
+echo "=== Marking image dirty (lazy refcounts) ==="
|
|
|
05bba0 |
+echo
|
|
|
05bba0 |
+
|
|
|
05bba0 |
+# Test that a backing file isn't written
|
|
|
05bba0 |
+_make_test_img 64M
|
|
|
05bba0 |
+$QEMU_IO -c "open -o backing.file.filename=$TEST_IMG.base,lazy-refcounts=on $TEST_IMG" -c "write 0 4k" | _filter_qemu_io
|
|
|
05bba0 |
+_img_info
|
|
|
05bba0 |
+
|
|
|
05bba0 |
+# Make sure that if there was a backing file that was just overridden on the
|
|
|
05bba0 |
+# command line, that backing file is retained, with the right format
|
|
|
05bba0 |
+_make_test_img -F raw -b "$TEST_IMG.orig" 64M
|
|
|
05bba0 |
+$QEMU_IO -c "open -o backing.file.filename=$TEST_IMG.base,backing.driver=$IMGFMT,lazy-refcounts=on $TEST_IMG" -c "write 0 4k" | _filter_qemu_io
|
|
|
05bba0 |
+_img_info
|
|
|
05bba0 |
+
|
|
|
05bba0 |
+# success, all done
|
|
|
05bba0 |
+echo '*** done'
|
|
|
05bba0 |
+rm -f $seq.full
|
|
|
05bba0 |
+status=0
|
|
|
05bba0 |
diff --git a/tests/qemu-iotests/130.out b/tests/qemu-iotests/130.out
|
|
|
05bba0 |
new file mode 100644
|
|
|
05bba0 |
index 0000000..bd489dd
|
|
|
05bba0 |
--- /dev/null
|
|
|
05bba0 |
+++ b/tests/qemu-iotests/130.out
|
|
|
05bba0 |
@@ -0,0 +1,28 @@
|
|
|
05bba0 |
+QA output created by 130
|
|
|
05bba0 |
+Formatting 'TEST_DIR/t.IMGFMT.orig', fmt=IMGFMT size=67108864
|
|
|
05bba0 |
+Formatting 'TEST_DIR/t.IMGFMT.base', fmt=IMGFMT size=67108864
|
|
|
05bba0 |
+Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=67108864
|
|
|
05bba0 |
+image: TEST_DIR/t.IMGFMT
|
|
|
05bba0 |
+file format: IMGFMT
|
|
|
05bba0 |
+virtual size: 64M (67108864 bytes)
|
|
|
05bba0 |
+cluster_size: 65536
|
|
|
05bba0 |
+
|
|
|
05bba0 |
+=== Marking image dirty (lazy refcounts) ===
|
|
|
05bba0 |
+
|
|
|
05bba0 |
+Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=67108864
|
|
|
05bba0 |
+wrote 4096/4096 bytes at offset 0
|
|
|
05bba0 |
+4 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
|
|
|
05bba0 |
+image: TEST_DIR/t.IMGFMT
|
|
|
05bba0 |
+file format: IMGFMT
|
|
|
05bba0 |
+virtual size: 64M (67108864 bytes)
|
|
|
05bba0 |
+cluster_size: 65536
|
|
|
05bba0 |
+Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=67108864 backing_file='TEST_DIR/t.IMGFMT.orig' backing_fmt='raw'
|
|
|
05bba0 |
+wrote 4096/4096 bytes at offset 0
|
|
|
05bba0 |
+4 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
|
|
|
05bba0 |
+image: TEST_DIR/t.IMGFMT
|
|
|
05bba0 |
+file format: IMGFMT
|
|
|
05bba0 |
+virtual size: 64M (67108864 bytes)
|
|
|
05bba0 |
+cluster_size: 65536
|
|
|
05bba0 |
+backing file: TEST_DIR/t.IMGFMT.orig
|
|
|
05bba0 |
+backing file format: raw
|
|
|
05bba0 |
+*** done
|
|
|
05bba0 |
diff --git a/tests/qemu-iotests/group b/tests/qemu-iotests/group
|
|
|
05bba0 |
index dbb2a36..739c266 100644
|
|
|
05bba0 |
--- a/tests/qemu-iotests/group
|
|
|
05bba0 |
+++ b/tests/qemu-iotests/group
|
|
|
05bba0 |
@@ -90,3 +90,4 @@
|
|
|
05bba0 |
108 rw auto quick
|
|
|
05bba0 |
114 rw auto quick
|
|
|
05bba0 |
121 rw auto
|
|
|
05bba0 |
+130 rw auto quick
|
|
|
05bba0 |
--
|
|
|
05bba0 |
1.8.3.1
|
|
|
05bba0 |
|