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