9ae3a8
From 820c45fa40b9763a207e9eeb1268f87c2ac06351 Mon Sep 17 00:00:00 2001
9ae3a8
From: Jeffrey Cody <jcody@redhat.com>
9ae3a8
Date: Fri, 19 Sep 2014 03:18:57 +0200
9ae3a8
Subject: [PATCH 18/20] block: extend block-commit to accept a string for the backing file
9ae3a8
9ae3a8
Message-id: <d49dacc368c02a3cd3d3d9b1d7ea0dc75cc7884a.1411096194.git.jcody@redhat.com>
9ae3a8
Patchwork-id: 61311
9ae3a8
O-Subject: [PATCH qemu-kvm-rhev RHEL7.0.z 2/4] block: extend block-commit to accept a string for the backing file
9ae3a8
Bugzilla: 1122925
9ae3a8
RH-Acked-by: Kevin Wolf <kwolf@redhat.com>
9ae3a8
RH-Acked-by: Eric Blake <eblake@redhat.com>
9ae3a8
RH-Acked-by: Stefan Hajnoczi <stefanha@redhat.com>
9ae3a8
9ae3a8
On some image chains, QEMU may not always be able to resolve the
9ae3a8
filenames properly, when updating the backing file of an image
9ae3a8
after a block commit.
9ae3a8
9ae3a8
For instance, certain relative pathnames may fail, or drives may
9ae3a8
have been specified originally by file descriptor (e.g. /dev/fd/???),
9ae3a8
or a relative protocol pathname may have been used.
9ae3a8
9ae3a8
In these instances, QEMU may lack the information to be able to make
9ae3a8
the correct choice, but the user or management layer most likely does
9ae3a8
have that knowledge.
9ae3a8
9ae3a8
With this extension to the block-commit api, the user is able to change
9ae3a8
the backing file of the overlay image as part of the block-commit
9ae3a8
operation.
9ae3a8
9ae3a8
This allows the change to be 'safe', in the sense that if the attempt
9ae3a8
to write the overlay image metadata fails, then the block-commit
9ae3a8
operation returns failure, without disrupting the guest.
9ae3a8
9ae3a8
If the commit top is the active layer, then specifying the backing
9ae3a8
file string will be treated as an error (there is no overlay image
9ae3a8
to modify in that case).
9ae3a8
9ae3a8
If a backing file string is not specified in the command, the backing
9ae3a8
file string to use is determined in the same manner as it was
9ae3a8
previously.
9ae3a8
9ae3a8
Reviewed-by: Eric Blake <eblake@redhat.com>
9ae3a8
Signed-off-by: Jeff Cody <jcody@redhat.com>
9ae3a8
Reviewed-by: Kevin Wolf <kwolf@redhat.com>
9ae3a8
Signed-off-by: Stefan Hajnoczi <stefanha@redhat.com>
9ae3a8
(cherry picked from commit 54e269009099cdc9483be115f1e12d56ad459c5e)
9ae3a8
9ae3a8
Conflicts:
9ae3a8
	qapi/block-core.json
9ae3a8
9ae3a8
RHEL7 Notes: Conflict is due to qapi json being divided into separate
9ae3a8
             files upstream; downstream in RHEL7 it is still in a single
9ae3a8
             json file.
9ae3a8
9ae3a8
Signed-off-by: Jeff Cody <jcody@redhat.com>
9ae3a8
Signed-off-by: Miroslav Rezanina <mrezanin@redhat.com>
9ae3a8
---
9ae3a8
 block.c                   |    8 ++++++--
9ae3a8
 block/commit.c            |    9 ++++++---
9ae3a8
 blockdev.c                |    8 +++++++-
9ae3a8
 include/block/block.h     |    3 ++-
9ae3a8
 include/block/block_int.h |    3 ++-
9ae3a8
 qapi-schema.json          |   20 ++++++++++++++++++--
9ae3a8
 qmp-commands.hx           |   19 ++++++++++++++++++-
9ae3a8
 7 files changed, 59 insertions(+), 11 deletions(-)
9ae3a8
9ae3a8
diff --git a/block.c b/block.c
9ae3a8
index 7bdbbc6..496eb72 100644
9ae3a8
--- a/block.c
9ae3a8
+++ b/block.c
9ae3a8
@@ -2323,12 +2323,15 @@ typedef struct BlkIntermediateStates {
9ae3a8
  *
9ae3a8
  * base <- active
9ae3a8
  *
9ae3a8
+ * If backing_file_str is non-NULL, it will be used when modifying top's
9ae3a8
+ * overlay image metadata.
9ae3a8
+ *
9ae3a8
  * Error conditions:
9ae3a8
  *  if active == top, that is considered an error
9ae3a8
  *
9ae3a8
  */
9ae3a8
 int bdrv_drop_intermediate(BlockDriverState *active, BlockDriverState *top,
9ae3a8
-                           BlockDriverState *base)
9ae3a8
+                           BlockDriverState *base, const char *backing_file_str)
9ae3a8
 {
9ae3a8
     BlockDriverState *intermediate;
9ae3a8
     BlockDriverState *base_bs = NULL;
9ae3a8
@@ -2380,7 +2383,8 @@ int bdrv_drop_intermediate(BlockDriverState *active, BlockDriverState *top,
9ae3a8
     }
9ae3a8
 
9ae3a8
     /* success - we can delete the intermediate states, and link top->base */
9ae3a8
-    ret = bdrv_change_backing_file(new_top_bs, base_bs->filename,
9ae3a8
+    backing_file_str = backing_file_str ? backing_file_str : base_bs->filename;
9ae3a8
+    ret = bdrv_change_backing_file(new_top_bs, backing_file_str,
9ae3a8
                                    base_bs->drv ? base_bs->drv->format_name : "");
9ae3a8
     if (ret) {
9ae3a8
         goto exit;
9ae3a8
diff --git a/block/commit.c b/block/commit.c
9ae3a8
index e3e395d..b6e1770 100644
9ae3a8
--- a/block/commit.c
9ae3a8
+++ b/block/commit.c
9ae3a8
@@ -37,6 +37,7 @@ typedef struct CommitBlockJob {
9ae3a8
     BlockdevOnError on_error;
9ae3a8
     int base_flags;
9ae3a8
     int orig_overlay_flags;
9ae3a8
+    char *backing_file_str;
9ae3a8
 } CommitBlockJob;
9ae3a8
 
9ae3a8
 static int coroutine_fn commit_populate(BlockDriverState *bs,
9ae3a8
@@ -141,7 +142,7 @@ wait:
9ae3a8
 
9ae3a8
     if (!block_job_is_cancelled(&s->common) && sector_num == end) {
9ae3a8
         /* success */
9ae3a8
-        ret = bdrv_drop_intermediate(active, top, base);
9ae3a8
+        ret = bdrv_drop_intermediate(active, top, base, s->backing_file_str);
9ae3a8
     }
9ae3a8
 
9ae3a8
 exit_free_buf:
9ae3a8
@@ -158,7 +159,7 @@ exit_restore_reopen:
9ae3a8
     if (overlay_bs && s->orig_overlay_flags != bdrv_get_flags(overlay_bs)) {
9ae3a8
         bdrv_reopen(overlay_bs, s->orig_overlay_flags, NULL);
9ae3a8
     }
9ae3a8
-
9ae3a8
+    g_free(s->backing_file_str);
9ae3a8
     block_job_completed(&s->common, ret);
9ae3a8
 }
9ae3a8
 
9ae3a8
@@ -182,7 +183,7 @@ static const BlockJobDriver commit_job_driver = {
9ae3a8
 void commit_start(BlockDriverState *bs, BlockDriverState *base,
9ae3a8
                   BlockDriverState *top, int64_t speed,
9ae3a8
                   BlockdevOnError on_error, BlockDriverCompletionFunc *cb,
9ae3a8
-                  void *opaque, Error **errp)
9ae3a8
+                  void *opaque, const char *backing_file_str, Error **errp)
9ae3a8
 {
9ae3a8
     CommitBlockJob *s;
9ae3a8
     BlockReopenQueue *reopen_queue = NULL;
9ae3a8
@@ -244,6 +245,8 @@ void commit_start(BlockDriverState *bs, BlockDriverState *base,
9ae3a8
     s->base_flags          = orig_base_flags;
9ae3a8
     s->orig_overlay_flags  = orig_overlay_flags;
9ae3a8
 
9ae3a8
+    s->backing_file_str = g_strdup(backing_file_str);
9ae3a8
+
9ae3a8
     s->on_error = on_error;
9ae3a8
     s->common.co = qemu_coroutine_create(commit_run);
9ae3a8
 
9ae3a8
diff --git a/blockdev.c b/blockdev.c
9ae3a8
index 107e27e..96dc3df 100644
9ae3a8
--- a/blockdev.c
9ae3a8
+++ b/blockdev.c
9ae3a8
@@ -1465,6 +1465,7 @@ void qmp_block_stream(const char *device, bool has_base,
9ae3a8
 void qmp_block_commit(const char *device,
9ae3a8
                       bool has_base, const char *base,
9ae3a8
                       bool has_top, const char *top,
9ae3a8
+                      bool has_backing_file, const char *backing_file,
9ae3a8
                       bool has_speed, int64_t speed,
9ae3a8
                       Error **errp)
9ae3a8
 {
9ae3a8
@@ -1522,11 +1523,16 @@ void qmp_block_commit(const char *device,
9ae3a8
     }
9ae3a8
 
9ae3a8
     if (top_bs == bs) {
9ae3a8
+        if (has_backing_file) {
9ae3a8
+            error_setg(errp, "'backing-file' specified,"
9ae3a8
+                             " but 'top' is the active layer");
9ae3a8
+            return;
9ae3a8
+        }
9ae3a8
         commit_active_start(bs, base_bs, speed, on_error, block_job_cb,
9ae3a8
                             bs, &local_err);
9ae3a8
     } else {
9ae3a8
         commit_start(bs, base_bs, top_bs, speed, on_error, block_job_cb, bs,
9ae3a8
-                    &local_err);
9ae3a8
+                     has_backing_file ? backing_file : NULL, &local_err);
9ae3a8
     }
9ae3a8
     if (local_err != NULL) {
9ae3a8
         error_propagate(errp, local_err);
9ae3a8
diff --git a/include/block/block.h b/include/block/block.h
9ae3a8
index 972c0e7..03b7960 100644
9ae3a8
--- a/include/block/block.h
9ae3a8
+++ b/include/block/block.h
9ae3a8
@@ -256,7 +256,8 @@ int bdrv_change_backing_file(BlockDriverState *bs,
9ae3a8
     const char *backing_file, const char *backing_fmt);
9ae3a8
 void bdrv_register(BlockDriver *bdrv);
9ae3a8
 int bdrv_drop_intermediate(BlockDriverState *active, BlockDriverState *top,
9ae3a8
-                           BlockDriverState *base);
9ae3a8
+                           BlockDriverState *base,
9ae3a8
+                           const char *backing_file_str);
9ae3a8
 BlockDriverState *bdrv_find_overlay(BlockDriverState *active,
9ae3a8
                                     BlockDriverState *bs);
9ae3a8
 BlockDriverState *bdrv_find_base(BlockDriverState *bs);
9ae3a8
diff --git a/include/block/block_int.h b/include/block/block_int.h
9ae3a8
index 53fc98c..e6874b4 100644
9ae3a8
--- a/include/block/block_int.h
9ae3a8
+++ b/include/block/block_int.h
9ae3a8
@@ -389,13 +389,14 @@ void stream_start(BlockDriverState *bs, BlockDriverState *base,
9ae3a8
  * @on_error: The action to take upon error.
9ae3a8
  * @cb: Completion function for the job.
9ae3a8
  * @opaque: Opaque pointer value passed to @cb.
9ae3a8
+ * @backing_file_str: String to use as the backing file in @top's overlay
9ae3a8
  * @errp: Error object.
9ae3a8
  *
9ae3a8
  */
9ae3a8
 void commit_start(BlockDriverState *bs, BlockDriverState *base,
9ae3a8
                  BlockDriverState *top, int64_t speed,
9ae3a8
                  BlockdevOnError on_error, BlockDriverCompletionFunc *cb,
9ae3a8
-                 void *opaque, Error **errp);
9ae3a8
+                 void *opaque, const char *backing_file_str, Error **errp);
9ae3a8
 /**
9ae3a8
  * commit_active_start:
9ae3a8
  * @bs: Active block device to be committed.
9ae3a8
diff --git a/qapi-schema.json b/qapi-schema.json
9ae3a8
index 18ab949..ed79eb9 100644
9ae3a8
--- a/qapi-schema.json
9ae3a8
+++ b/qapi-schema.json
9ae3a8
@@ -1848,6 +1848,23 @@
9ae3a8
 #                    which contains the topmost data to be committed down. If
9ae3a8
 #                    not specified, this is the active layer.
9ae3a8
 #
9ae3a8
+# @backing-file:  #optional The backing file string to write into the overlay
9ae3a8
+#                           image of 'top'.  If 'top' is the active layer,
9ae3a8
+#                           specifying a backing file string is an error. This
9ae3a8
+#                           filename is not validated.
9ae3a8
+#
9ae3a8
+#                           If a pathname string is such that it cannot be
9ae3a8
+#                           resolved by QEMU, that means that subsequent QMP or
9ae3a8
+#                           HMP commands must use node-names for the image in
9ae3a8
+#                           question, as filename lookup methods will fail.
9ae3a8
+#
9ae3a8
+#                           If not specified, QEMU will automatically determine
9ae3a8
+#                           the backing file string to use, or error out if
9ae3a8
+#                           there is no obvious choice. Care should be taken
9ae3a8
+#                           when specifying the string, to specify a valid
9ae3a8
+#                           filename or protocol.
9ae3a8
+#                           (Since 2.1)
9ae3a8
+#
9ae3a8
 #                    If top == base, that is an error.
9ae3a8
 #                    If top == active, the job will not be completed by itself,
9ae3a8
 #                    user needs to complete the job with the block-job-complete
9ae3a8
@@ -1860,7 +1877,6 @@
9ae3a8
 #                    size of the smaller top, you can safely truncate it
9ae3a8
 #                    yourself once the commit operation successfully completes.
9ae3a8
 #
9ae3a8
-#
9ae3a8
 # @speed:  #optional the maximum speed, in bytes per second
9ae3a8
 #
9ae3a8
 # Returns: Nothing on success
9ae3a8
@@ -1875,7 +1891,7 @@
9ae3a8
 ##
9ae3a8
 { 'command': 'block-commit',
9ae3a8
   'data': { 'device': 'str', '*base': 'str', '*top': 'str',
9ae3a8
-            '*speed': 'int' } }
9ae3a8
+            '*backing-file': 'str', '*speed': 'int' } }
9ae3a8
 
9ae3a8
 ##
9ae3a8
 # @drive-mirror
9ae3a8
diff --git a/qmp-commands.hx b/qmp-commands.hx
9ae3a8
index f67121a..5ece4f9 100644
9ae3a8
--- a/qmp-commands.hx
9ae3a8
+++ b/qmp-commands.hx
9ae3a8
@@ -1005,7 +1005,7 @@ EQMP
9ae3a8
 
9ae3a8
     {
9ae3a8
         .name       = "block-commit",
9ae3a8
-        .args_type  = "device:B,base:s?,top:s?,speed:o?",
9ae3a8
+        .args_type  = "device:B,base:s?,top:s?,backing-file:s?,speed:o?",
9ae3a8
         .mhandler.cmd_new = qmp_marshal_input_block_commit,
9ae3a8
     },
9ae3a8
 
9ae3a8
@@ -1026,6 +1026,23 @@ Arguments:
9ae3a8
           which contains the topmost data to be committed down. If
9ae3a8
           not specified, this is the active layer. (json-string, optional)
9ae3a8
 
9ae3a8
+- backing-file:     The backing file string to write into the overlay
9ae3a8
+                    image of 'top'.  If 'top' is the active layer,
9ae3a8
+                    specifying a backing file string is an error. This
9ae3a8
+                    filename is not validated.
9ae3a8
+
9ae3a8
+                    If a pathname string is such that it cannot be
9ae3a8
+                    resolved by QEMU, that means that subsequent QMP or
9ae3a8
+                    HMP commands must use node-names for the image in
9ae3a8
+                    question, as filename lookup methods will fail.
9ae3a8
+
9ae3a8
+                    If not specified, QEMU will automatically determine
9ae3a8
+                    the backing file string to use, or error out if
9ae3a8
+                    there is no obvious choice. Care should be taken
9ae3a8
+                    when specifying the string, to specify a valid
9ae3a8
+                    filename or protocol.
9ae3a8
+                    (json-string, optional) (Since 2.1)
9ae3a8
+
9ae3a8
           If top == base, that is an error.
9ae3a8
           If top == active, the job will not be completed by itself,
9ae3a8
           user needs to complete the job with the block-job-complete
9ae3a8
-- 
9ae3a8
1.7.1
9ae3a8