aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorWanpeng Qian <wanpengqian@gmail.com>2025-11-18 08:24:23 -0700
committerColin Percival <cperciva@FreeBSD.org>2025-11-19 13:37:09 -0800
commit2c5edd4860b2a1912f987557dfa09bae3c322d36 (patch)
tree28c1f280cb700db5089f913b33a9cf3efd3bef50
parent7b31e6a121c788829d5546f6474a250770c1609e (diff)
nvme: Notify namespace changes better
When we get a namespace notification, we have to reconstrut the namespace to get the new identification data from the namespace. For each namespace in the AEN, we will reconstrict it before we call the notification. We also flag it as changed for the duration of the change callback (prior versions of the patch needed to keep track, but we no longer do, so this bit may be removed). Note when we've seen the namespace so we can notify when it goes away. Approved by: re (cperciva) Co-authored-by: imp Differential Revision: https://reviews.freebsd.org/D33032 (cherry picked from commit 20e94950c54e398049396647da36b9e2c3b639c1) (cherry picked from commit fe6ee00d174e0d7f4c7a38db9af7b94c56579054)
-rw-r--r--sys/dev/nvme/nvme.h7
-rw-r--r--sys/dev/nvme/nvme_ctrlr.c12
-rw-r--r--sys/dev/nvme/nvme_ns.c9
3 files changed, 22 insertions, 6 deletions
diff --git a/sys/dev/nvme/nvme.h b/sys/dev/nvme/nvme.h
index 17c5cdb4db87..8e69c0ffe339 100644
--- a/sys/dev/nvme/nvme.h
+++ b/sys/dev/nvme/nvme.h
@@ -1930,8 +1930,11 @@ typedef void (*nvme_cons_async_fn_t)(void *, const struct nvme_completion *,
typedef void (*nvme_cons_fail_fn_t)(void *);
enum nvme_namespace_flags {
- NVME_NS_DEALLOCATE_SUPPORTED = 0x1,
- NVME_NS_FLUSH_SUPPORTED = 0x2,
+ NVME_NS_DEALLOCATE_SUPPORTED = 0x01,
+ NVME_NS_FLUSH_SUPPORTED = 0x02,
+ NVME_NS_ADDED = 0x04,
+ NVME_NS_CHANGED = 0x08,
+ NVME_NS_GONE = 0x10,
};
int nvme_ctrlr_passthrough_cmd(struct nvme_controller *ctrlr,
diff --git a/sys/dev/nvme/nvme_ctrlr.c b/sys/dev/nvme/nvme_ctrlr.c
index 07c1bcdfbf08..63b8643d97d7 100644
--- a/sys/dev/nvme/nvme_ctrlr.c
+++ b/sys/dev/nvme/nvme_ctrlr.c
@@ -1216,10 +1216,20 @@ nvme_ctrlr_aer_task(void *arg, int pending)
} else if (aer->log_page_id == NVME_LOG_CHANGED_NAMESPACE) {
struct nvme_ns_list *nsl =
(struct nvme_ns_list *)aer->log_page_buffer;
+ struct nvme_controller *ctrlr = aer->ctrlr;
+
for (int i = 0; i < nitems(nsl->ns) && nsl->ns[i] != 0; i++) {
+ struct nvme_namespace *ns;
+ uint32_t id = nsl->ns[i];
+
if (nsl->ns[i] > NVME_MAX_NAMESPACES)
break;
- nvme_notify_ns(aer->ctrlr, nsl->ns[i]);
+
+ ns = &ctrlr->ns[id - 1];
+ ns->flags |= NVME_NS_CHANGED;
+ nvme_ns_construct(ns, id, ctrlr);
+ nvme_notify_ns(ctrlr, id);
+ ns->flags &= ~NVME_NS_CHANGED;
}
}
diff --git a/sys/dev/nvme/nvme_ns.c b/sys/dev/nvme/nvme_ns.c
index e84d2066930e..21d7965bf7a6 100644
--- a/sys/dev/nvme/nvme_ns.c
+++ b/sys/dev/nvme/nvme_ns.c
@@ -78,7 +78,7 @@ nvme_ns_ioctl(struct cdev *cdev, u_long cmd, caddr_t arg, int flag,
break;
case NVME_PASSTHROUGH_CMD:
pt = (struct nvme_pt_command *)arg;
- return (nvme_ctrlr_passthrough_cmd(ctrlr, pt, ns->id,
+ return (nvme_ctrlr_passthrough_cmd(ctrlr, pt, ns->id,
1 /* is_user_buffer */, 0 /* is_admin_cmd */));
case NVME_GET_NSID:
{
@@ -557,8 +557,10 @@ nvme_ns_construct(struct nvme_namespace *ns, uint32_t id,
* standard says the entire id will be zeros, so this is a
* cheap way to test for that.
*/
- if (ns->data.nsze == 0)
- return (ENXIO);
+ if (ns->data.nsze == 0) {
+ ns->flags |= NVME_NS_GONE;
+ return ((ns->flags & NVME_NS_ADDED) ? 0 : ENXIO);
+ }
flbas_fmt = NVMEV(NVME_NS_DATA_FLBAS_FORMAT, ns->data.flbas);
@@ -622,6 +624,7 @@ nvme_ns_construct(struct nvme_namespace *ns, uint32_t id,
ns->cdev->si_drv2 = make_dev_alias(ns->cdev, "%sns%d",
device_get_nameunit(ctrlr->dev), ns->id);
ns->cdev->si_flags |= SI_UNMAPPED;
+ ns->flags |= NVME_NS_ADDED;
return (0);
}