From: Alexander Mikhalitsyn <alexander@mihalicyn.com>
To: qemu-devel@nongnu.org
Cc: "Stéphane Graber" <stgraber@stgraber.org>,
"Alexander Mikhalitsyn" <alexander@mihalicyn.com>,
"Keith Busch" <kbusch@kernel.org>,
"Klaus Jensen" <its@irrelevant.dk>,
qemu-block@nongnu.org, "Jesper Devantier" <foss@defmacro.it>,
"Alexander Mikhalitsyn" <aleksandr.mikhalitsyn@futurfusion.io>
Subject: [PATCH v3 2/2] hw/nvme: support online resize
Date: Mon, 3 Aug 2026 10:30:46 +0200 [thread overview]
Message-ID: <20260803083046.110121-3-alexander@mihalicyn.com> (raw)
In-Reply-To: <20260803083046.110121-1-alexander@mihalicyn.com>
From: Alexander Mikhalitsyn <aleksandr.mikhalitsyn@futurfusion.io>
Implement (BlockDevOps *)->resize_cb() for NVMe namespace to enable
online resize support.
We must handle cases when multiple namespaces are attached to
a single controller, or namespace is shared across a few
different controllers by iterating over controllers attached to
a NvmeSubsystem and properly notify every controller about a size change.
Signed-off-by: Alexander Mikhalitsyn <aleksandr.mikhalitsyn@futurfusion.io>
---
v3:
- rebased
v2:
- check-patch fixes
---
hw/nvme/ctrl.c | 9 +++++++
hw/nvme/ns.c | 68 +++++++++++++++++++++++++++++++++++++++++++++++++-
hw/nvme/nvme.h | 2 ++
3 files changed, 78 insertions(+), 1 deletion(-)
diff --git a/hw/nvme/ctrl.c b/hw/nvme/ctrl.c
index 710c3e0d77d..d60b3e105a1 100644
--- a/hw/nvme/ctrl.c
+++ b/hw/nvme/ctrl.c
@@ -7009,6 +7009,15 @@ static uint16_t nvme_ns_attachment(NvmeCtrl *n, NvmeRequest *req)
return NVME_SUCCESS;
}
+void nvme_ctrl_notify_ns_resize(NvmeCtrl *ctrl, NvmeNamespace *ns)
+{
+ if (!test_and_set_bit(ns->params.nsid, ctrl->changed_nsids)) {
+ nvme_enqueue_event(ctrl, NVME_AER_TYPE_NOTICE,
+ NVME_AER_INFO_NOTICE_NS_ATTR_CHANGED,
+ NVME_LOG_CHANGED_NSLIST);
+ }
+}
+
typedef struct NvmeFormatAIOCB {
BlockAIOCB common;
BlockAIOCB *aiocb;
diff --git a/hw/nvme/ns.c b/hw/nvme/ns.c
index 7f0f9ac7662..e2954fd91b3 100644
--- a/hw/nvme/ns.c
+++ b/hw/nvme/ns.c
@@ -163,6 +163,70 @@ lbaf_found:
return 0;
}
+static void nvme_ns_resize_cb(void *opaque)
+{
+ NvmeNamespace *ns = opaque;
+ int64_t size;
+ int cntlid, notified_ctrls;
+
+ size = blk_getlength(ns->blkconf.blk);
+ if (size < 0) {
+ error_report("can't get size of block device %s: %s",
+ blk_name(ns->blkconf.blk), strerror(-size));
+ return;
+ }
+
+ ns->size = size;
+ nvme_ns_init_format(ns);
+
+ if (!ns->attached) {
+ return;
+ }
+
+ /*
+ * Okay, the namespace is attached so we need to notify all controllers
+ * about size change.
+ *
+ * Let's just take ns->subsys, iterate over all controllers and find
+ * to which of them our namespace is attached.
+ */
+
+ assert(ns->subsys);
+ assert(ns->subsys->ctrls);
+
+ notified_ctrls = 0;
+ for (cntlid = 0; cntlid < ARRAY_SIZE(ns->subsys->ctrls); cntlid++) {
+ NvmeCtrl *ctrl;
+
+ /* notified everyone? */
+ if (notified_ctrls == ns->attached) {
+ break;
+ }
+
+ ctrl = nvme_subsys_ctrl(ns->subsys, cntlid);
+ if (!ctrl) {
+ continue;
+ }
+
+ for (uint32_t nsid = 1; nsid <= NVME_MAX_NAMESPACES; nsid++) {
+ NvmeNamespace *ns_iter = ctrl->namespaces[nsid];
+
+ if (!ns_iter || ns_iter != ns) {
+ continue;
+ }
+
+ nvme_ctrl_notify_ns_resize(ctrl, ns);
+
+ notified_ctrls++;
+ break;
+ }
+ }
+}
+
+static const BlockDevOps nvme_ns_block_ops = {
+ .resize_cb = nvme_ns_resize_cb,
+};
+
static int nvme_ns_init_blk(NvmeNamespace *ns, Error **errp)
{
bool read_only;
@@ -172,10 +236,12 @@ static int nvme_ns_init_blk(NvmeNamespace *ns, Error **errp)
}
read_only = !blk_supports_write_perm(ns->blkconf.blk);
- if (!blkconf_apply_backend_options(&ns->blkconf, read_only, false, errp)) {
+ if (!blkconf_apply_backend_options(&ns->blkconf, read_only, true, errp)) {
return -1;
}
+ blk_set_dev_ops(ns->blkconf.blk, &nvme_ns_block_ops, ns);
+
if (ns->blkconf.discard_granularity == -1) {
ns->blkconf.discard_granularity =
MAX(ns->blkconf.logical_block_size, MIN_DISCARD_GRANULARITY);
diff --git a/hw/nvme/nvme.h b/hw/nvme/nvme.h
index 43e3c916f73..a4b2c01a2cc 100644
--- a/hw/nvme/nvme.h
+++ b/hw/nvme/nvme.h
@@ -764,6 +764,8 @@ void nvme_atomic_configure_max_write_size(bool dn, uint16_t awun,
void nvme_ns_atomic_configure_boundary(bool dn, uint16_t nabsn,
uint16_t nabspf, NvmeAtomic *atomic);
+void nvme_ctrl_notify_ns_resize(NvmeCtrl *ctrl, NvmeNamespace *ns);
+
extern const VMStateDescription nvme_vmstate_atomic;
extern const VMStateDescription nvme_vmstate_ns;
--
2.47.3
next prev parent reply other threads:[~2026-08-03 8:31 UTC|newest]
Thread overview: 7+ messages / expand[flat|nested] mbox.gz Atom feed top
2026-08-03 8:30 [PATCH v3 0/2] hw/nvme: support online resize Alexander Mikhalitsyn
2026-08-03 8:30 ` [PATCH v3 1/2] hw/nvme: initialize ns->subsys for n->namespace Alexander Mikhalitsyn
2026-08-03 8:30 ` Alexander Mikhalitsyn [this message]
2026-08-03 13:42 ` [PATCH v3 0/2] hw/nvme: support online resize Klaus Jensen
2026-08-31 7:04 ` Alexander Mikhalitsyn
2026-09-07 7:39 ` Klaus Jensen
2026-09-07 8:24 ` Alexander Mikhalitsyn
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=20260803083046.110121-3-alexander@mihalicyn.com \
--to=alexander@mihalicyn.com \
--cc=aleksandr.mikhalitsyn@futurfusion.io \
--cc=foss@defmacro.it \
--cc=its@irrelevant.dk \
--cc=kbusch@kernel.org \
--cc=qemu-block@nongnu.org \
--cc=qemu-devel@nongnu.org \
--cc=stgraber@stgraber.org \
/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 an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.