qemu-devel.nongnu.org archive mirror
 help / color / mirror / Atom feed
From: Kevin Wolf <kwolf@redhat.com>
To: qemu-block@nongnu.org
Cc: kwolf@redhat.com, hreitz@redhat.com, stefanha@redhat.com,
	pkrempa@redhat.com, peterx@redhat.com, farosas@suse.de,
	qemu-devel@nongnu.org
Subject: [PATCH v3 08/16] block: Add blockdev-set-active QMP command
Date: Tue,  4 Feb 2025 22:13:59 +0100	[thread overview]
Message-ID: <20250204211407.381505-9-kwolf@redhat.com> (raw)
In-Reply-To: <20250204211407.381505-1-kwolf@redhat.com>

The system emulator tries to automatically activate and inactivate block
nodes at the right point during migration. However, there are still
cases where it's necessary that the user can do this manually.

Images are only activated on the destination VM of a migration when the
VM is actually resumed. If the VM was paused, this doesn't happen
automatically. The user may want to perform some operation on a block
device (e.g. taking a snapshot or starting a block job) without also
resuming the VM yet. This is an example where a manual command is
necessary.

Another example is VM migration when the image files are opened by an
external qemu-storage-daemon instance on each side. In this case, the
process that needs to hand over the images isn't even part of the
migration and can't know when the migration completes. Management tools
need a way to explicitly inactivate images on the source and activate
them on the destination.

This adds a new blockdev-set-active QMP command that lets the user
change the status of individual nodes (this is necessary in
qemu-storage-daemon because it could be serving multiple VMs and only
one of them migrates at a time). For convenience, operating on all
devices (like QEMU does automatically during migration) is offered as an
option, too, and can be used in the context of single VM.

Signed-off-by: Kevin Wolf <kwolf@redhat.com>
Acked-by: Fabiano Rosas <farosas@suse.de>
Reviewed-by: Eric Blake <eblake@redhat.com>
Reviewed-by: Stefan Hajnoczi <stefanha@redhat.com>
---
 qapi/block-core.json               | 32 ++++++++++++++++++++++++++++++
 include/block/block-global-state.h |  3 +++
 block.c                            | 21 ++++++++++++++++++++
 blockdev.c                         | 32 ++++++++++++++++++++++++++++++
 4 files changed, 88 insertions(+)

diff --git a/qapi/block-core.json b/qapi/block-core.json
index 6029e54889..ee6eccc68c 100644
--- a/qapi/block-core.json
+++ b/qapi/block-core.json
@@ -4945,6 +4945,38 @@
 { 'command': 'blockdev-del', 'data': { 'node-name': 'str' },
   'allow-preconfig': true }
 
+##
+# @blockdev-set-active:
+#
+# Activate or inactivate a block device. Use this to manage the handover of
+# block devices on migration with qemu-storage-daemon.
+#
+# Activating a node automatically activates all of its child nodes first.
+# Inactivating a node automatically inactivates any of its child nodes that are
+# not in use by a still active node.
+#
+# @node-name: Name of the graph node to activate or inactivate. By default, all
+#     nodes are affected by the operation.
+#
+# @active: true if the nodes should be active when the command returns success,
+#     false if they should be inactive.
+#
+# Since: 10.0
+#
+# .. qmp-example::
+#
+#     -> { "execute": "blockdev-set-active",
+#          "arguments": {
+#               "node-name": "node0",
+#               "active": false
+#          }
+#        }
+#     <- { "return": {} }
+##
+{ 'command': 'blockdev-set-active',
+  'data': { '*node-name': 'str', 'active': 'bool' },
+  'allow-preconfig': true }
+
 ##
 # @BlockdevCreateOptionsFile:
 #
diff --git a/include/block/block-global-state.h b/include/block/block-global-state.h
index a826bf5f78..9be34b3c99 100644
--- a/include/block/block-global-state.h
+++ b/include/block/block-global-state.h
@@ -184,6 +184,9 @@ bdrv_activate(BlockDriverState *bs, Error **errp);
 int coroutine_fn no_co_wrapper_bdrv_rdlock
 bdrv_co_activate(BlockDriverState *bs, Error **errp);
 
+int no_coroutine_fn
+bdrv_inactivate(BlockDriverState *bs, Error **errp);
+
 void bdrv_activate_all(Error **errp);
 int bdrv_inactivate_all(void);
 
diff --git a/block.c b/block.c
index 7f6eca392f..7eeb8d076e 100644
--- a/block.c
+++ b/block.c
@@ -7052,6 +7052,27 @@ bdrv_inactivate_recurse(BlockDriverState *bs, bool top_level)
     return 0;
 }
 
+int bdrv_inactivate(BlockDriverState *bs, Error **errp)
+{
+    int ret;
+
+    GLOBAL_STATE_CODE();
+    GRAPH_RDLOCK_GUARD_MAINLOOP();
+
+    if (bdrv_has_bds_parent(bs, true)) {
+        error_setg(errp, "Node has active parent node");
+        return -EPERM;
+    }
+
+    ret = bdrv_inactivate_recurse(bs, true);
+    if (ret < 0) {
+        error_setg_errno(errp, -ret, "Failed to inactivate node");
+        return ret;
+    }
+
+    return 0;
+}
+
 int bdrv_inactivate_all(void)
 {
     BlockDriverState *bs = NULL;
diff --git a/blockdev.c b/blockdev.c
index eb2517f1dd..7e0d433712 100644
--- a/blockdev.c
+++ b/blockdev.c
@@ -3471,6 +3471,38 @@ void qmp_blockdev_del(const char *node_name, Error **errp)
     bdrv_unref(bs);
 }
 
+void qmp_blockdev_set_active(const char *node_name, bool active, Error **errp)
+{
+    int ret;
+
+    GLOBAL_STATE_CODE();
+    GRAPH_RDLOCK_GUARD_MAINLOOP();
+
+    if (!node_name) {
+        if (active) {
+            bdrv_activate_all(errp);
+        } else {
+            ret = bdrv_inactivate_all();
+            if (ret < 0) {
+                error_setg_errno(errp, -ret, "Failed to inactivate all nodes");
+            }
+        }
+    } else {
+        BlockDriverState *bs = bdrv_find_node(node_name);
+        if (!bs) {
+            error_setg(errp, "Failed to find node with node-name='%s'",
+                       node_name);
+            return;
+        }
+
+        if (active) {
+            bdrv_activate(bs, errp);
+        } else {
+            bdrv_inactivate(bs, errp);
+        }
+    }
+}
+
 static BdrvChild * GRAPH_RDLOCK
 bdrv_find_child(BlockDriverState *parent_bs, const char *child_name)
 {
-- 
2.48.1



  parent reply	other threads:[~2025-02-04 21:17 UTC|newest]

Thread overview: 24+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2025-02-04 21:13 [PATCH v3 00/16] block: Managing inactive nodes (QSD migration) Kevin Wolf
2025-02-04 21:13 ` [PATCH v3 01/16] block: Add 'active' field to BlockDeviceInfo Kevin Wolf
2025-02-04 21:13 ` [PATCH v3 02/16] block: Allow inactivating already inactive nodes Kevin Wolf
2025-02-04 21:13 ` [PATCH v3 03/16] block: Inactivate external snapshot overlays when necessary Kevin Wolf
2025-02-04 21:13 ` [PATCH v3 04/16] migration/block-active: Remove global active flag Kevin Wolf
2025-02-04 21:13 ` [PATCH v3 05/16] block: Don't attach inactive child to active node Kevin Wolf
2025-02-04 21:13 ` [PATCH v3 06/16] block: Fix crash on block_resize on inactive node Kevin Wolf
2025-02-04 21:13 ` [PATCH v3 07/16] block: Add option to create inactive nodes Kevin Wolf
2025-02-04 21:13 ` Kevin Wolf [this message]
2025-02-04 21:14 ` [PATCH v3 09/16] block: Support inactive nodes in blk_insert_bs() Kevin Wolf
2025-02-04 21:14 ` [PATCH v3 10/16] block/export: Don't ignore image activation error in blk_exp_add() Kevin Wolf
2025-02-04 21:14 ` [PATCH v3 11/16] block: Drain nodes before inactivating them Kevin Wolf
2025-02-05 20:42   ` Eric Blake
2025-02-04 21:14 ` [PATCH v3 12/16] block/export: Add option to allow export of inactive nodes Kevin Wolf
2025-02-04 21:14 ` [PATCH v3 13/16] nbd/server: Support " Kevin Wolf
2025-02-05 20:43   ` Eric Blake
2025-02-04 21:14 ` [PATCH v3 14/16] iotests: Add filter_qtest() Kevin Wolf
2025-02-04 21:14 ` [PATCH v3 15/16] iotests: Add qsd-migrate case Kevin Wolf
2025-02-05 20:46   ` Eric Blake
2025-02-24 10:23   ` Thomas Huth
2025-02-24 13:13     ` Kevin Wolf
2025-02-04 21:14 ` [PATCH v3 16/16] iotests: Add (NBD-based) tests for inactive nodes Kevin Wolf
2025-02-05 20:49   ` Eric Blake
2025-02-05 15:35 ` [PATCH v3 00/16] block: Managing inactive nodes (QSD migration) Stefan Hajnoczi

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=20250204211407.381505-9-kwolf@redhat.com \
    --to=kwolf@redhat.com \
    --cc=farosas@suse.de \
    --cc=hreitz@redhat.com \
    --cc=peterx@redhat.com \
    --cc=pkrempa@redhat.com \
    --cc=qemu-block@nongnu.org \
    --cc=qemu-devel@nongnu.org \
    --cc=stefanha@redhat.com \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).