Add a drive_insert HMP command that reconnects a host block device file
to an existing guest device whose backing store was previously removed
with drive_del.
After drive_del, the BlockBackend remains attached to the guest device
but has no BlockDriverState (shown as "[not inserted]" in info block).
drive_insert opens the specified file, finds the device's BlockBackend
by iterating all backends and matching the attached device ID, then
calls blk_insert_bs() to reconnect the backing store.
This complements drive_del for non-removable devices (such as NVMe
namespaces) where blockdev-change-medium cannot be used. Combined with
PCIe AER Surprise Down error injection to trigger a controller reset,
this enables complete NVMe disk hot-swap simulation where the guest
sees the same device names throughout.
Example usage:
drive_del drv0 # remove backing store
drive_insert ns0 disk.qcow2 # reconnect backing
pcie_aer_inject_error rp0 SDN # trigger controller reset
Signed-off-by: Matthieu Receveur <matthieu@min.io>
---
block/monitor/block-hmp-cmds.c | 59 ++++++++++++++++++++++++++++++++++
hmp-commands.hx | 18 +++++++++++
include/block/block-hmp-cmds.h | 1 +
3 files changed, 78 insertions(+)
diff --git a/block/monitor/block-hmp-cmds.c b/block/monitor/block-hmp-cmds.c
index 1fd28d59eb..77e9662ead 100644
--- a/block/monitor/block-hmp-cmds.c
+++ b/block/monitor/block-hmp-cmds.c
@@ -38,7 +38,9 @@
#include "qemu/osdep.h"
#include "hw/core/boards.h"
#include "system/block-backend.h"
+#include "system/block-backend-global-state.h"
#include "system/blockdev.h"
+#include "block/block-global-state.h"
#include "qapi/qapi-commands-block.h"
#include "qapi/qapi-commands-block-export.h"
#include "qobject/qdict.h"
@@ -195,6 +197,63 @@ unlock:
hmp_handle_error(mon, err);
}
+void hmp_drive_insert(Monitor *mon, const QDict *qdict)
+{
+ const char *id = qdict_get_str(qdict, "id");
+ const char *filename = qdict_get_str(qdict, "filename");
+ BlockBackend *blk = NULL;
+ BlockBackend *iter;
+ BlockDriverState *bs;
+ Error *err = NULL;
+
+ GLOBAL_STATE_CODE();
+
+ /*
+ * After drive_del, the BlockBackend is removed from the monitor name
+ * registry but still attached to the device. Find it by iterating all
+ * BlockBackends and matching by the device ID shown in "info block".
+ */
+ for (iter = blk_all_next(NULL); iter; iter = blk_all_next(iter)) {
+ DeviceState *dev = blk_get_attached_dev(iter);
+ if (dev && dev->id && strcmp(dev->id, id) == 0) {
+ blk = iter;
+ break;
+ }
+ }
+
+ if (!blk) {
+ /* Fallback: try by block backend name */
+ blk = blk_by_name(id);
+ }
+
+ if (!blk) {
+ error_setg(&err, "Device '%s' not found", id);
+ goto out;
+ }
+
+ if (blk_bs(blk)) {
+ error_setg(&err, "Device '%s' already has a medium inserted", id);
+ goto out;
+ }
+
+ bs = bdrv_open(filename, NULL, NULL, BDRV_O_RDWR, &err);
+ if (!bs) {
+ goto out;
+ }
+
+ if (blk_insert_bs(blk, bs, &err) < 0) {
+ bdrv_unref(bs);
+ goto out;
+ }
+
+ bdrv_unref(bs);
+ monitor_printf(mon, "OK\n");
+ return;
+
+out:
+ hmp_handle_error(mon, err);
+}
+
void hmp_commit(Monitor *mon, const QDict *qdict)
{
const char *device = qdict_get_str(qdict, "device");
diff --git a/hmp-commands.hx b/hmp-commands.hx
index 5cc4788f12..79af8e8988 100644
--- a/hmp-commands.hx
+++ b/hmp-commands.hx
@@ -207,6 +207,24 @@ SRST
actions (drive options rerror, werror).
ERST
+ {
+ .name = "drive_insert",
+ .args_type = "id:B,filename:F",
+ .params = "device filename",
+ .help = "insert a host block device into an empty drive",
+ .cmd = hmp_drive_insert,
+ },
+
+SRST
+``drive_insert`` *device* *filename*
+ Insert a host block device file into a drive that has been emptied by
+ ``drive_del``. This reconnects the backing store without removing the
+ guest device, enabling transparent disk hot-swap for non-removable devices
+ such as NVMe namespaces. Combined with PCIe AER Surprise Down error
+ injection (``pcie_aer_inject_error`` *device* ``SDN``), this enables
+ complete NVMe disk hot-swap simulation.
+ERST
+
{
.name = "change",
.args_type = "device:B,force:-f,target:F,arg:s?,read-only-mode:s?",
diff --git a/include/block/block-hmp-cmds.h b/include/block/block-hmp-cmds.h
index 71113cd7ef..73c9607402 100644
--- a/include/block/block-hmp-cmds.h
+++ b/include/block/block-hmp-cmds.h
@@ -21,6 +21,7 @@ void hmp_drive_add(Monitor *mon, const QDict *qdict);
void hmp_commit(Monitor *mon, const QDict *qdict);
void hmp_drive_del(Monitor *mon, const QDict *qdict);
+void hmp_drive_insert(Monitor *mon, const QDict *qdict);
void hmp_drive_mirror(Monitor *mon, const QDict *qdict);
void hmp_drive_backup(Monitor *mon, const QDict *qdict);
--
2.50.1 (Apple Git-155)