Blame SOURCES/kvm-qcow2-Fix-header-update-with-overridden-backing-file.patch

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