qemu-devel
[Top][All Lists]
Advanced

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

[Qemu-devel] [PATCH v2 3/3] block: Fix snapshot=on for protocol parsed f


From: Kevin Wolf
Subject: [Qemu-devel] [PATCH v2 3/3] block: Fix snapshot=on for protocol parsed from filename
Date: Fri, 4 Apr 2014 16:56:00 +0200

Since commit 9fd3171a, BDRV_O_SNAPSHOT uses an option QDict to specify
the originally requested image as the backing file of the newly created
temporary snapshot. This means that the filename is stored in
"file.filename", which is an option that is not parsed for protocol
names. Therefore things like -drive file=nbd:localhost:10809 were
broken because it looked for a local file with the literal name
'nbd:localhost:10809'.

This patch changes the way BDRV_O_SNAPSHOT works once again. We now open
the originally requested image as normal, and then do a similar
operation as for live snapshots to put the temporary snapshot on top.
This way, both driver specific options and parsed filenames work.

As a nice side effect, this results in code movement to factor
bdrv_append_temp_snapshot() out. This is a good preparation for moving
its call to drive_init() and friends eventually.

Signed-off-by: Kevin Wolf <address@hidden>
---
v2:
- open the backing file for the temporary snapshot read-only from the
  beginning so that you can get an r/w block device from a read-only
  file using snapshot=on. Gets rid of the bdrv_reopen() whose return
  value was ignored in v1, too.

 block.c                    | 148 ++++++++++++++++++++++++---------------------
 include/block/block.h      |   1 +
 tests/qemu-iotests/051     |   8 +++
 tests/qemu-iotests/051.out |  28 +++++++++
 4 files changed, 115 insertions(+), 70 deletions(-)

diff --git a/block.c b/block.c
index df2b8d1..d89c344 100644
--- a/block.c
+++ b/block.c
@@ -767,6 +767,11 @@ static int bdrv_open_flags(BlockDriverState *bs, int flags)
 {
     int open_flags = flags | BDRV_O_CACHE_WB;
 
+    /* The backing file of a temporary snapshot is read-only */
+    if (flags & BDRV_O_SNAPSHOT) {
+        open_flags &= ~BDRV_O_RDWR;
+    }
+
     /*
      * Clear flags that are internal to the block layer before opening the
      * image.
@@ -1162,6 +1167,68 @@ done:
     return ret;
 }
 
+void bdrv_append_temp_snapshot(BlockDriverState *bs, Error **errp)
+{
+    /* TODO: extra byte is a hack to ensure MAX_PATH space on Windows. */
+    char tmp_filename[PATH_MAX + 1];
+
+    int64_t total_size;
+    BlockDriver *bdrv_qcow2;
+    QEMUOptionParameter *create_options;
+    QDict *snapshot_options;
+    BlockDriverState *bs_snapshot;
+    Error *local_err;
+    int ret;
+
+    /* if snapshot, we create a temporary backing file and open it
+       instead of opening 'filename' directly */
+
+    /* Get the required size from the image */
+    total_size = bdrv_getlength(bs) & BDRV_SECTOR_MASK;
+
+    /* Create the temporary image */
+    ret = get_tmp_filename(tmp_filename, sizeof(tmp_filename));
+    if (ret < 0) {
+        error_setg_errno(errp, -ret, "Could not get temporary filename");
+        return;
+    }
+
+    bdrv_qcow2 = bdrv_find_format("qcow2");
+    create_options = parse_option_parameters("", bdrv_qcow2->create_options,
+                                             NULL);
+
+    set_option_parameter_int(create_options, BLOCK_OPT_SIZE, total_size);
+
+    ret = bdrv_create(bdrv_qcow2, tmp_filename, create_options, &local_err);
+    free_option_parameters(create_options);
+    if (ret < 0) {
+        error_setg_errno(errp, -ret, "Could not create temporary overlay "
+                         "'%s': %s", tmp_filename,
+                         error_get_pretty(local_err));
+        error_free(local_err);
+        return;
+    }
+
+    /* Prepare a new options QDict for the temporary file */
+    snapshot_options = qdict_new();
+    qdict_put(snapshot_options, "file.driver",
+              qstring_from_str("file"));
+    qdict_put(snapshot_options, "file.filename",
+              qstring_from_str(tmp_filename));
+
+    bs_snapshot = bdrv_new("");
+    bs_snapshot->is_temporary = 1;
+
+    ret = bdrv_open(&bs_snapshot, NULL, NULL, snapshot_options,
+                    bs->open_flags & ~BDRV_O_SNAPSHOT, bdrv_qcow2, &local_err);
+    if (ret < 0) {
+        error_propagate(errp, local_err);
+        return;
+    }
+
+    bdrv_append(bs_snapshot, bs);
+}
+
 /*
  * Opens a disk image (raw, qcow2, vmdk, ...)
  *
@@ -1182,8 +1249,6 @@ int bdrv_open(BlockDriverState **pbs, const char 
*filename,
               BlockDriver *drv, Error **errp)
 {
     int ret;
-    /* TODO: extra byte is a hack to ensure MAX_PATH space on Windows. */
-    char tmp_filename[PATH_MAX + 1];
     BlockDriverState *file = NULL, *bs;
     const char *drvname;
     Error *local_err = NULL;
@@ -1243,74 +1308,6 @@ int bdrv_open(BlockDriverState **pbs, const char 
*filename,
         }
     }
 
-    /* For snapshot=on, create a temporary qcow2 overlay */
-    if (flags & BDRV_O_SNAPSHOT) {
-        BlockDriverState *bs1;
-        int64_t total_size;
-        BlockDriver *bdrv_qcow2;
-        QEMUOptionParameter *create_options;
-        QDict *snapshot_options;
-
-        /* if snapshot, we create a temporary backing file and open it
-           instead of opening 'filename' directly */
-
-        /* Get the required size from the image */
-        QINCREF(options);
-        bs1 = NULL;
-        ret = bdrv_open(&bs1, filename, NULL, options, BDRV_O_NO_BACKING,
-                        drv, &local_err);
-        if (ret < 0) {
-            goto fail;
-        }
-        total_size = bdrv_getlength(bs1) & BDRV_SECTOR_MASK;
-
-        bdrv_unref(bs1);
-
-        /* Create the temporary image */
-        ret = get_tmp_filename(tmp_filename, sizeof(tmp_filename));
-        if (ret < 0) {
-            error_setg_errno(errp, -ret, "Could not get temporary filename");
-            goto fail;
-        }
-
-        bdrv_qcow2 = bdrv_find_format("qcow2");
-        create_options = parse_option_parameters("", 
bdrv_qcow2->create_options,
-                                                 NULL);
-
-        set_option_parameter_int(create_options, BLOCK_OPT_SIZE, total_size);
-
-        ret = bdrv_create(bdrv_qcow2, tmp_filename, create_options, 
&local_err);
-        free_option_parameters(create_options);
-        if (ret < 0) {
-            error_setg_errno(errp, -ret, "Could not create temporary overlay "
-                             "'%s': %s", tmp_filename,
-                             error_get_pretty(local_err));
-            error_free(local_err);
-            local_err = NULL;
-            goto fail;
-        }
-
-        /* Prepare a new options QDict for the temporary file, where user
-         * options refer to the backing file */
-        if (filename) {
-            qdict_put(options, "file.filename", qstring_from_str(filename));
-        }
-        if (drv) {
-            qdict_put(options, "driver", qstring_from_str(drv->format_name));
-        }
-
-        snapshot_options = qdict_new();
-        qdict_put(snapshot_options, "backing", options);
-        qdict_flatten(snapshot_options);
-
-        bs->options = snapshot_options;
-        options = qdict_clone_shallow(bs->options);
-
-        filename = tmp_filename;
-        drv = bdrv_qcow2;
-        bs->is_temporary = 1;
-    }
-
     /* Open image file without format layer */
     if (flags & BDRV_O_RDWR) {
         flags |= BDRV_O_ALLOW_RDWR;
@@ -1372,6 +1369,17 @@ int bdrv_open(BlockDriverState **pbs, const char 
*filename,
         }
     }
 
+    /* For snapshot=on, create a temporary qcow2 overlay. bs points to the
+     * temporary snapshot afterwards. */
+    if (flags & BDRV_O_SNAPSHOT) {
+        bdrv_append_temp_snapshot(bs, &local_err);
+        if (local_err) {
+            error_propagate(errp, local_err);
+            goto close_and_fail;
+        }
+    }
+
+
 done:
     /* Check if any unknown options were used */
     if (options && (qdict_size(options) != 0)) {
diff --git a/include/block/block.h b/include/block/block.h
index 1ed55d8..b3230a2 100644
--- a/include/block/block.h
+++ b/include/block/block.h
@@ -190,6 +190,7 @@ int bdrv_open_image(BlockDriverState **pbs, const char 
*filename,
                     QDict *options, const char *bdref_key, int flags,
                     bool allow_none, Error **errp);
 int bdrv_open_backing_file(BlockDriverState *bs, QDict *options, Error **errp);
+void bdrv_append_temp_snapshot(BlockDriverState *bs, Error **errp);
 int bdrv_open(BlockDriverState **pbs, const char *filename,
               const char *reference, QDict *options, int flags,
               BlockDriver *drv, Error **errp);
diff --git a/tests/qemu-iotests/051 b/tests/qemu-iotests/051
index 2f79b26..073dc7a 100755
--- a/tests/qemu-iotests/051
+++ b/tests/qemu-iotests/051
@@ -218,6 +218,14 @@ echo 'qemu-io ide0-hd0 "write -P 0x22 0 4k"' | run_qemu 
-drive file="$TEST_IMG"
 echo 'qemu-io ide0-hd0 "write -P 0x22 0 4k"' | run_qemu -drive 
file="$TEST_IMG",snapshot=on | _filter_qemu_io
 echo 'qemu-io ide0-hd0 "write -P 0x22 0 4k"' | run_qemu -drive 
file.filename="$TEST_IMG",driver=qcow2,snapshot=on | _filter_qemu_io
 echo 'qemu-io ide0-hd0 "write -P 0x22 0 4k"' | run_qemu -drive 
file.filename="$TEST_IMG",driver=qcow2 -snapshot | _filter_qemu_io
+echo 'qemu-io ide0-hd0 "write -P 0x22 0 4k"' | run_qemu -drive 
file="file:$TEST_IMG" -snapshot | _filter_qemu_io
+echo 'qemu-io ide0-hd0 "write -P 0x22 0 4k"' | run_qemu -drive 
file="file:$TEST_IMG",snapshot=on | _filter_qemu_io
+
+# Opening a read-only file r/w with snapshot=on
+chmod u-w "$TEST_IMG"
+echo 'qemu-io ide0-hd0 "write -P 0x22 0 4k"' | run_qemu -drive 
file="$TEST_IMG" -snapshot | _filter_qemu_io
+echo 'qemu-io ide0-hd0 "write -P 0x22 0 4k"' | run_qemu -drive 
file="$TEST_IMG",snapshot=on | _filter_qemu_io
+chmod u+w "$TEST_IMG"
 
 $QEMU_IO -c "read -P 0x11 0 4k" "$TEST_IMG" | _filter_qemu_io
 
diff --git a/tests/qemu-iotests/051.out b/tests/qemu-iotests/051.out
index a631b0b..01b0384 100644
--- a/tests/qemu-iotests/051.out
+++ b/tests/qemu-iotests/051.out
@@ -319,6 +319,34 @@ wrote 4096/4096 bytes at offset 0
 4 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
 (qemu) qququiquit
 
+Testing: -drive file=file:TEST_DIR/t.qcow2 -snapshot
+QEMU X.Y.Z monitor - type 'help' for more information
+(qemu) 
qqeqemqemuqemu-qemu-iqemu-ioqemu-io
 qemu-io iqemu-io 
idqemu-io 
ideqemu-io 
ide0qemu-io 
ide0-qemu-io 
ide0-hqemu-io 
ide0-hdqemu-io 
ide0-hd0qemu-io ide0-hd0 
qemu-io ide0-hd0 
"qemu-io ide0-hd0 
"wqemu-io ide0-hd0 
"wrqemu-io 
ide0-hd0 "wri!
 qemu-io ide0-hd0 
"writqemu-io
 ide0-hd0 
"writeqemu-io
 ide0-hd0 "write 
qemu-io
 ide0-hd0 "write 
-qemu-io
 ide0-hd0 "write 
-Pqemu-io
 ide0-hd0 "write -P 
qemu-io
 ide0-hd0 "write -P 
0qemu-io
 ide0-hd0 "write -P 
0xqemu-io
 ide0-hd0 "write -P 
0x2qemu-io
 ide0-hd0 "w!
 rite -P 
0x22qemu-io
 ide0-hd0 "write -P 0x22 
qemu-io
 ide0-hd0 "write -P 0x22 
0qemu-io
 ide0-hd0 "write -P 0x22 0 
qemu-io
 ide0-hd0 "write -P 0x22 0 
4qemu-io
 ide0-hd0 "write -P 0x22 0 
4kqemu-io
 ide0-hd0 "write -P 0x22 0 4k"
+wrote 4096/4096 bytes at offset 0
+4 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
+(qemu) qququiquit
+
+Testing: -drive file=file:TEST_DIR/t.qcow2,snapshot=on
+QEMU X.Y.Z monitor - type 'help' for more information
+(qemu) 
qqeqemqemuqemu-qemu-iqemu-ioqemu-io
 qemu-io iqemu-io 
idqemu-io 
ideqemu-io 
ide0qemu-io 
ide0-qemu-io 
ide0-hqemu-io 
ide0-hdqemu-io 
ide0-hd0qemu-io ide0-hd0 
qemu-io ide0-hd0 
"qemu-io ide0-hd0 
"wqemu-io ide0-hd0 
"wrqemu-io 
ide0-hd0 "wri!
 qemu-io ide0-hd0 
"writqemu-io
 ide0-hd0 
"writeqemu-io
 ide0-hd0 "write 
qemu-io
 ide0-hd0 "write 
-qemu-io
 ide0-hd0 "write 
-Pqemu-io
 ide0-hd0 "write -P 
qemu-io
 ide0-hd0 "write -P 
0qemu-io
 ide0-hd0 "write -P 
0xqemu-io
 ide0-hd0 "write -P 
0x2qemu-io
 ide0-hd0 "w!
 rite -P 
0x22qemu-io
 ide0-hd0 "write -P 0x22 
qemu-io
 ide0-hd0 "write -P 0x22 
0qemu-io
 ide0-hd0 "write -P 0x22 0 
qemu-io
 ide0-hd0 "write -P 0x22 0 
4qemu-io
 ide0-hd0 "write -P 0x22 0 
4kqemu-io
 ide0-hd0 "write -P 0x22 0 4k"
+wrote 4096/4096 bytes at offset 0
+4 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
+(qemu) qququiquit
+
+Testing: -drive file=TEST_DIR/t.qcow2 -snapshot
+QEMU X.Y.Z monitor - type 'help' for more information
+(qemu) 
qqeqemqemuqemu-qemu-iqemu-ioqemu-io
 qemu-io iqemu-io 
idqemu-io 
ideqemu-io 
ide0qemu-io 
ide0-qemu-io 
ide0-hqemu-io 
ide0-hdqemu-io 
ide0-hd0qemu-io ide0-hd0 
qemu-io ide0-hd0 
"qemu-io ide0-hd0 
"wqemu-io ide0-hd0 
"wrqemu-io 
ide0-hd0 "wri!
 qemu-io ide0-hd0 
"writqemu-io
 ide0-hd0 
"writeqemu-io
 ide0-hd0 "write 
qemu-io
 ide0-hd0 "write 
-qemu-io
 ide0-hd0 "write 
-Pqemu-io
 ide0-hd0 "write -P 
qemu-io
 ide0-hd0 "write -P 
0qemu-io
 ide0-hd0 "write -P 
0xqemu-io
 ide0-hd0 "write -P 
0x2qemu-io
 ide0-hd0 "w!
 rite -P 
0x22qemu-io
 ide0-hd0 "write -P 0x22 
qemu-io
 ide0-hd0 "write -P 0x22 
0qemu-io
 ide0-hd0 "write -P 0x22 0 
qemu-io
 ide0-hd0 "write -P 0x22 0 
4qemu-io
 ide0-hd0 "write -P 0x22 0 
4kqemu-io
 ide0-hd0 "write -P 0x22 0 4k"
+wrote 4096/4096 bytes at offset 0
+4 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
+(qemu) qququiquit
+
+Testing: -drive file=TEST_DIR/t.qcow2,snapshot=on
+QEMU X.Y.Z monitor - type 'help' for more information
+(qemu) 
qqeqemqemuqemu-qemu-iqemu-ioqemu-io
 qemu-io iqemu-io 
idqemu-io 
ideqemu-io 
ide0qemu-io 
ide0-qemu-io 
ide0-hqemu-io 
ide0-hdqemu-io 
ide0-hd0qemu-io ide0-hd0 
qemu-io ide0-hd0 
"qemu-io ide0-hd0 
"wqemu-io ide0-hd0 
"wrqemu-io 
ide0-hd0 "wri!
 qemu-io ide0-hd0 
"writqemu-io
 ide0-hd0 
"writeqemu-io
 ide0-hd0 "write 
qemu-io
 ide0-hd0 "write 
-qemu-io
 ide0-hd0 "write 
-Pqemu-io
 ide0-hd0 "write -P 
qemu-io
 ide0-hd0 "write -P 
0qemu-io
 ide0-hd0 "write -P 
0xqemu-io
 ide0-hd0 "write -P 
0x2qemu-io
 ide0-hd0 "w!
 rite -P 
0x22qemu-io
 ide0-hd0 "write -P 0x22 
qemu-io
 ide0-hd0 "write -P 0x22 
0qemu-io
 ide0-hd0 "write -P 0x22 0 
qemu-io
 ide0-hd0 "write -P 0x22 0 
4qemu-io
 ide0-hd0 "write -P 0x22 0 
4kqemu-io
 ide0-hd0 "write -P 0x22 0 4k"
+wrote 4096/4096 bytes at offset 0
+4 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
+(qemu) qququiquit
+
 read 4096/4096 bytes at offset 0
 4 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
 Testing: -drive file=TEST_DIR/t.qcow2,snapshot=off
-- 
1.8.3.1




reply via email to

[Prev in Thread] Current Thread [Next in Thread]