Patch Detail
get:
Show a patch.
patch:
Update a patch.
put:
Update a patch.
GET /api/1.1/patches/2223605/?format=api
{ "id": 2223605, "url": "http://patchwork.ozlabs.org/api/1.1/patches/2223605/?format=api", "web_url": "http://patchwork.ozlabs.org/project/qemu-devel/patch/20260415173905.71224-1-matthieu@min.io/", "project": { "id": 14, "url": "http://patchwork.ozlabs.org/api/1.1/projects/14/?format=api", "name": "QEMU Development", "link_name": "qemu-devel", "list_id": "qemu-devel.nongnu.org", "list_email": "qemu-devel@nongnu.org", "web_url": "", "scm_url": "", "webscm_url": "" }, "msgid": "<20260415173905.71224-1-matthieu@min.io>", "date": "2026-04-15T17:39:05", "name": "block: add blockdev-attach QMP command", "commit_ref": null, "pull_url": null, "state": "new", "archived": false, "hash": "68f4b2c0a2facabe5d1a193aa31da3843f8f45d8", "submitter": { "id": 93098, "url": "http://patchwork.ozlabs.org/api/1.1/people/93098/?format=api", "name": "Matthieu Rolla", "email": "matthieu@minio.io" }, "delegate": null, "mbox": "http://patchwork.ozlabs.org/project/qemu-devel/patch/20260415173905.71224-1-matthieu@min.io/mbox/", "series": [ { "id": 500023, "url": "http://patchwork.ozlabs.org/api/1.1/series/500023/?format=api", "web_url": "http://patchwork.ozlabs.org/project/qemu-devel/list/?series=500023", "date": "2026-04-15T17:39:05", "name": "block: add blockdev-attach QMP command", "version": 1, "mbox": "http://patchwork.ozlabs.org/series/500023/mbox/" } ], "comments": "http://patchwork.ozlabs.org/api/patches/2223605/comments/", "check": "pending", "checks": "http://patchwork.ozlabs.org/api/patches/2223605/checks/", "tags": {}, "headers": { "Return-Path": "<qemu-devel-bounces+incoming=patchwork.ozlabs.org@nongnu.org>", "X-Original-To": "incoming@patchwork.ozlabs.org", "Delivered-To": "patchwork-incoming@legolas.ozlabs.org", "Authentication-Results": [ "legolas.ozlabs.org;\n\tdkim=pass (2048-bit key;\n secure) header.d=minio.io header.i=@minio.io header.a=rsa-sha256\n header.s=minio header.b=SmyD8BSQ;\n\tdkim-atps=neutral", "legolas.ozlabs.org;\n spf=pass (sender SPF authorized) smtp.mailfrom=nongnu.org\n (client-ip=209.51.188.17; helo=lists1p.gnu.org;\n envelope-from=qemu-devel-bounces+incoming=patchwork.ozlabs.org@nongnu.org;\n receiver=patchwork.ozlabs.org)" ], "Received": [ "from lists1p.gnu.org (lists1p.gnu.org [209.51.188.17])\n\t(using TLSv1.2 with cipher ECDHE-ECDSA-AES256-GCM-SHA384 (256/256 bits))\n\t(No client certificate requested)\n\tby legolas.ozlabs.org (Postfix) with ESMTPS id 4fwpLQ18Vtz1yHc\n\tfor <incoming@patchwork.ozlabs.org>; Thu, 16 Apr 2026 03:39:40 +1000 (AEST)", "from localhost ([::1] helo=lists1p.gnu.org)\n\tby lists1p.gnu.org with esmtp (Exim 4.90_1)\n\t(envelope-from <qemu-devel-bounces@nongnu.org>)\n\tid 1wD4Cb-0000Bn-RE; Wed, 15 Apr 2026 13:39:01 -0400", "from eggs.gnu.org ([2001:470:142:3::10])\n by lists1p.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256)\n (Exim 4.90_1) (envelope-from <matthieu@minio.io>) id 1wD4CZ-0000AQ-7c\n for qemu-devel@nongnu.org; Wed, 15 Apr 2026 13:38:59 -0400", "from mail-wm1-x32c.google.com ([2a00:1450:4864:20::32c])\n by eggs.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_128_GCM_SHA256:128)\n (Exim 4.90_1) (envelope-from <matthieu@minio.io>) id 1wD4CX-0002kn-FC\n for qemu-devel@nongnu.org; Wed, 15 Apr 2026 13:38:58 -0400", "by mail-wm1-x32c.google.com with SMTP id\n 5b1f17b1804b1-488a29e6110so75767855e9.3\n for <qemu-devel@nongnu.org>; Wed, 15 Apr 2026 10:38:57 -0700 (PDT)", "from localhost\n (2a01cb001411480010f92e9cd3b40a22.ipv6.abo.wanadoo.fr.\n [2a01:cb00:1411:4800:10f9:2e9c:d3b4:a22])\n by smtp.gmail.com with UTF8SMTPSA id\n 5b1f17b1804b1-488f0edaf47sm24184345e9.35.2026.04.15.10.38.54\n (version=TLS1_3 cipher=TLS_AES_128_GCM_SHA256 bits=128/128);\n Wed, 15 Apr 2026 10:38:55 -0700 (PDT)" ], "DKIM-Signature": "v=1; a=rsa-sha256; c=relaxed/relaxed;\n d=minio.io; s=minio; t=1776274736; x=1776879536; darn=nongnu.org;\n h=content-transfer-encoding:mime-version:message-id:date:subject:cc\n :to:from:from:to:cc:subject:date:message-id:reply-to;\n bh=czMoe/c8/XX5KWWs2YbJoq4mu8G0tJQUrKnaro6zT2M=;\n b=SmyD8BSQ590BU28c9vs6K5UFLRcP9DSeHT1gG6z8Wsp7CYTBaOiOWucmfl3jsRnczd\n u+OtausaHc9ksIcSXN8Z7EBaNNISZGvMvlz8DgFgyht/wXXfjXtfV77R0XrL9Ne+QyBZ\n ZP4JB2iiwF6YdTrSxJdgXDG80zGgOYrKoG6rS9ZNH62jykzcMVfh15Dgu7j5CJWA41/r\n pRDQBisQAo5UX4jrxHLvvpt/HAfu122AANdtBEWHYdjFUp2Q5+EaDeR5NLSFjow8pEnS\n Wy9FH0GiIfGG/3wCYRmApcRUmt69aA2+y6g0McVb+RSUJhaW8eslQaKpp13sn1wqP4g5\n 1+pg==", "X-Google-DKIM-Signature": "v=1; a=rsa-sha256; c=relaxed/relaxed;\n d=1e100.net; s=20251104; t=1776274736; x=1776879536;\n h=content-transfer-encoding:mime-version:message-id:date:subject:cc\n :to:from:x-gm-gg:x-gm-message-state:from:to:cc:subject:date\n :message-id:reply-to;\n bh=czMoe/c8/XX5KWWs2YbJoq4mu8G0tJQUrKnaro6zT2M=;\n b=FeqXwlWyr/Zn5/wh5vJYYd/NhPjnkxmJcOzAHoKiMns30Ey54IVvxoELFUYXBfEHja\n IoXSb9IsEVpOSn7zEMH07lCvFSj+KWLzxbsk5eD2/EU9ltuK7lA/K3yeTFo2DarX8gKb\n gNyqYjldSLdC8jdMZBmUdWaw6kR8AAmF7QZj94ix9Ke+TQAUqj9Sq7uGEXxxr+CcMoP7\n fqXYLqfxL31UASUzi2PULY2NsjhMDTKM4lhUZllxn33f+CrHHaRcP5WGwf3s7Awp+Vri\n /mNC4VsBWGJq8PTnzVKKrHvO2c7VamzHyOdsx+9CbzHJmkFsGbmeiAjpeyYOkVDjVwx3\n EeXw==", "X-Gm-Message-State": "AOJu0YxQzR1yRjqBSCUTozJLjSvyMLDkoXqhxIxMmz31T6eaKmAwjzQY\n wE1uJcbqQ9d7mGH0L7z9/eKiM034zY03ScT91D34loXdavihnTTPANteE/GEMtnEeGdQFASMyow\n zVjAPPCPgtfkHfCZW+MvmCU0SNmFF6L7+ptfW09ebsSFS+ewtLJ91VctG1cY6AnWk16hRnRz3qk\n 6CpeVACRTslq/4eilhl8skx1Z6rvq+CWLJNlN9WxQ=", "X-Gm-Gg": "AeBDievMbdFozrg1fBfXXwJFiXpu/FY1APfEvz3/y9rNrJQ+LLXxI1Vx1TELuWX8UCD\n KOJvZ+dOytOFIRDCHZPeLN/YSp13R2KrQpvGHSkv8VS3nX+GMXHb+3++fXbc4onSWJQLo2I2EdG\n FbqDyuPXlZGb00TQH9ImE9F9xu2SfTJJ1Ih1ZzIXcEEjsHvGGpyOxgYiaJwLXylyEC0Kx51kYhs\n MLA8hTJuVg2DZDeuBoccaP89IHV1EGWcNZ+Wrtw291au+mhlK9yG0q8NDvECuiCSXsJhdLaMgP6\n lx47J07HnMQfiF2DwbDt+N0KagbBeL4bTJiG/oxRATwEB1DBTaaXfK/I41peCRJaV6PUkV/aDKl\n z4LlVdQmzjzn9HM8tFCSc75/zbt+XEsL7fgyr2jGLocA8sOPGEcZ8wPzgW2aOVmOzKcUafvjKSM\n TbN80ecC+cWZCyBtPtqvOKnW/TcwQucUegEWGD8j8xrZiBkflVwKSdA2KVffLGIbOlNoa0bruyh\n ChGN0I6tSTmdN9fOYrN43KXhlDK/M7xoGnfZP6Vx6/ebqJKJIaTY0skpPklqGLu7IoKfEhH6RGX\n ZkdZTQ==", "X-Received": "by 2002:a05:600c:a305:b0:488:ab37:b442 with SMTP id\n 5b1f17b1804b1-488d68c7f92mr216679995e9.28.1776274735540;\n Wed, 15 Apr 2026 10:38:55 -0700 (PDT)", "From": "mr-083 <matthieu@minio.io>", "X-Google-Original-From": "mr-083 <matthieu@min.io>", "To": "qemu-devel@nongnu.org,\n\tqemu-block@nongnu.org", "Cc": "its@irrelevant.dk, kbusch@kernel.org, stefanha@redhat.com,\n berrange@redhat.com, mr-083 <matthieu@min.io>", "Subject": "[PATCH] block: add blockdev-attach QMP command", "Date": "Wed, 15 Apr 2026 19:39:05 +0200", "Message-ID": "<20260415173905.71224-1-matthieu@min.io>", "X-Mailer": "git-send-email 2.53.0", "MIME-Version": "1.0", "Content-Transfer-Encoding": "8bit", "Received-SPF": "pass client-ip=2a00:1450:4864:20::32c;\n envelope-from=matthieu@minio.io; helo=mail-wm1-x32c.google.com", "X-Spam_score_int": "-10", "X-Spam_score": "-1.1", "X-Spam_bar": "-", "X-Spam_report": "(-1.1 / 5.0 requ) BAYES_00=-1.9, DKIM_SIGNED=0.1,\n DKIM_VALID=-0.1, DKIM_VALID_AU=-0.1, DKIM_VALID_EF=-0.1,\n HK_NAME_MR_MRS=0.998,\n RCVD_IN_DNSWL_NONE=-0.0001, SPF_HELO_NONE=0.001,\n SPF_PASS=-0.001 autolearn=no autolearn_force=no", "X-Spam_action": "no action", "X-BeenThere": "qemu-devel@nongnu.org", "X-Mailman-Version": "2.1.29", "Precedence": "list", "List-Id": "qemu development <qemu-devel.nongnu.org>", "List-Unsubscribe": "<https://lists.nongnu.org/mailman/options/qemu-devel>,\n <mailto:qemu-devel-request@nongnu.org?subject=unsubscribe>", "List-Archive": "<https://lists.nongnu.org/archive/html/qemu-devel>", "List-Post": "<mailto:qemu-devel@nongnu.org>", "List-Help": "<mailto:qemu-devel-request@nongnu.org?subject=help>", "List-Subscribe": "<https://lists.nongnu.org/mailman/listinfo/qemu-devel>,\n <mailto:qemu-devel-request@nongnu.org?subject=subscribe>", "Errors-To": "qemu-devel-bounces+incoming=patchwork.ozlabs.org@nongnu.org", "Sender": "qemu-devel-bounces+incoming=patchwork.ozlabs.org@nongnu.org" }, "content": "Add a blockdev-attach QMP command that attaches a block driver state\ntree to a device's block backend. Unlike blockdev-insert-medium, this\nworks for non-removable devices such as NVMe namespaces.\n\nAfter drive_del removes a device's backing store, the BlockBackend\nremains attached to the guest device but has no BlockDriverState.\nblockdev-attach reconnects a block node (previously created with\nblockdev-add) to the device's BlockBackend via blk_insert_bs().\n\nThis separates the two concerns as recommended: blockdev-add creates\nthe block node, blockdev-attach associates it with the device.\n\nExample usage with NVMe namespace hot-swap:\n drive_del drv0\n blockdev-add node-name=node0 driver=qcow2 file.driver=file \\\n file.filename=disk.qcow2\n blockdev-attach id=ns0 node-name=node0\n\nAn HMP wrapper is included for convenience.\n\nSigned-off-by: Matthieu <matthieu@min.io>\n---\n block/monitor/block-hmp-cmds.c | 10 ++++++++++\n block/qapi-system.c | 36 ++++++++++++++++++++++++++++++++++\n hmp-commands.hx | 16 +++++++++++++++\n include/block/block-hmp-cmds.h | 1 +\n qapi/block.json | 33 +++++++++++++++++++++++++++++++\n 5 files changed, 96 insertions(+)", "diff": "diff --git a/block/monitor/block-hmp-cmds.c b/block/monitor/block-hmp-cmds.c\nindex 1fd28d59eb..8a3d821e01 100644\n--- a/block/monitor/block-hmp-cmds.c\n+++ b/block/monitor/block-hmp-cmds.c\n@@ -195,6 +195,16 @@ unlock:\n hmp_handle_error(mon, err);\n }\n \n+void hmp_blockdev_attach(Monitor *mon, const QDict *qdict)\n+{\n+ const char *id = qdict_get_str(qdict, \"id\");\n+ const char *node_name = qdict_get_str(qdict, \"node-name\");\n+ Error *err = NULL;\n+\n+ qmp_blockdev_attach(id, node_name, &err);\n+ hmp_handle_error(mon, err);\n+}\n+\n void hmp_commit(Monitor *mon, const QDict *qdict)\n {\n const char *device = qdict_get_str(qdict, \"device\");\ndiff --git a/block/qapi-system.c b/block/qapi-system.c\nindex 54b7409b2b..ec89645bc1 100644\n--- a/block/qapi-system.c\n+++ b/block/qapi-system.c\n@@ -304,6 +304,42 @@ void qmp_blockdev_insert_medium(const char *id, const char *node_name,\n blockdev_insert_medium(NULL, id, node_name, errp);\n }\n \n+void qmp_blockdev_attach(const char *id, const char *node_name,\n+ Error **errp)\n+{\n+ BlockBackend *blk;\n+ BlockDriverState *bs;\n+ int ret;\n+\n+ GRAPH_RDLOCK_GUARD_MAINLOOP();\n+\n+ blk = qmp_get_blk(NULL, id, errp);\n+ if (!blk) {\n+ return;\n+ }\n+\n+ if (blk_bs(blk)) {\n+ error_setg(errp, \"Device already has a medium inserted\");\n+ return;\n+ }\n+\n+ bs = bdrv_find_node(node_name);\n+ if (!bs) {\n+ error_setg(errp, \"Node '%s' not found\", node_name);\n+ return;\n+ }\n+\n+ if (bdrv_has_blk(bs)) {\n+ error_setg(errp, \"Node '%s' is already in use\", node_name);\n+ return;\n+ }\n+\n+ ret = blk_insert_bs(blk, bs, errp);\n+ if (ret < 0) {\n+ return;\n+ }\n+}\n+\n void qmp_blockdev_change_medium(const char *device,\n const char *id,\n const char *filename,\ndiff --git a/hmp-commands.hx b/hmp-commands.hx\nindex 5cc4788f12..ce32ed33ab 100644\n--- a/hmp-commands.hx\n+++ b/hmp-commands.hx\n@@ -207,6 +207,22 @@ SRST\n actions (drive options rerror, werror).\n ERST\n \n+ {\n+ .name = \"blockdev-attach\",\n+ .args_type = \"id:s,node-name:s\",\n+ .params = \"id node-name\",\n+ .help = \"attach a block node to a device (non-removable)\",\n+ .cmd = hmp_blockdev_attach,\n+ },\n+\n+SRST\n+``blockdev-attach`` *id* *node-name*\n+ Attach a block driver state tree (created with ``blockdev-add``) to a\n+ device's block backend. Unlike ``blockdev-insert-medium``, this works\n+ for non-removable devices such as NVMe namespaces. The device must\n+ have no medium inserted (e.g. after ``drive_del``).\n+ERST\n+\n {\n .name = \"change\",\n .args_type = \"device:B,force:-f,target:F,arg:s?,read-only-mode:s?\",\ndiff --git a/include/block/block-hmp-cmds.h b/include/block/block-hmp-cmds.h\nindex 71113cd7ef..34d30915fc 100644\n--- a/include/block/block-hmp-cmds.h\n+++ b/include/block/block-hmp-cmds.h\n@@ -21,6 +21,7 @@ void hmp_drive_add(Monitor *mon, const QDict *qdict);\n \n void hmp_commit(Monitor *mon, const QDict *qdict);\n void hmp_drive_del(Monitor *mon, const QDict *qdict);\n+void hmp_blockdev_attach(Monitor *mon, const QDict *qdict);\n \n void hmp_drive_mirror(Monitor *mon, const QDict *qdict);\n void hmp_drive_backup(Monitor *mon, const QDict *qdict);\ndiff --git a/qapi/block.json b/qapi/block.json\nindex 46955bbb3e..c05d3b5ac1 100644\n--- a/qapi/block.json\n+++ b/qapi/block.json\n@@ -295,6 +295,39 @@\n 'data': { 'id': 'str',\n 'node-name': 'str'} }\n \n+##\n+# @blockdev-attach:\n+#\n+# Attach a block driver state tree to a device's block backend.\n+# Unlike blockdev-insert-medium, this works for non-removable\n+# devices such as NVMe namespaces. The device must currently have\n+# no medium inserted (e.g. after drive_del removed the backing).\n+#\n+# @id: The name or QOM path of the guest device\n+#\n+# @node-name: name of a node in the block driver state graph\n+#\n+# Since: 11.1\n+#\n+# .. qmp-example::\n+#\n+# -> { \"execute\": \"blockdev-add\",\n+# \"arguments\": {\n+# \"node-name\": \"node0\",\n+# \"driver\": \"qcow2\",\n+# \"file\": { \"driver\": \"file\",\n+# \"filename\": \"disk.qcow2\" } } }\n+# <- { \"return\": {} }\n+#\n+# -> { \"execute\": \"blockdev-attach\",\n+# \"arguments\": { \"id\": \"ns0\",\n+# \"node-name\": \"node0\" } }\n+# <- { \"return\": {} }\n+##\n+{ 'command': 'blockdev-attach',\n+ 'data': { 'id': 'str',\n+ 'node-name': 'str'} }\n+\n ##\n # @BlockdevChangeReadOnlyMode:\n #\n", "prefixes": [] }