From 3120b49d3a20a4e98355572a362fc83f157b7a46 Mon Sep 17 00:00:00 2001 From: Caleb Sander Mateos Date: Mon, 24 Jun 2024 14:44:54 -0600 Subject: [PATCH] linux: add nvme_get_ana_log_len_from_id_ctrl() The existing function nvme_get_ana_log_len() returns the maximum length of the ANA log page but has a few restrictions: - It doesn't work with NVMe-MI controllers, only file descriptors - It combines calculating the ANA log length from Identify Controller with issuing the Identify Controller command - It always returns a maximum length for the ANA log page with NSIDs. If the ANA log page is going to be fetched with the RGO bit set, the max length may be much lower, so a smaller buffer could be used. nvme_get_ana_log_len_from_id_ctrl() is more flexible: it uses an existing Identify Controller response and accepts a rgo parameter. This allows it to work with Identify Controller reponses from MI devices or to reuse existing Identify Controller results. And it can return a tighter length bound when the RGO bit will be set. This makes it suitable for use in nvme-cli. Signed-off-by: Caleb Sander Mateos --- src/libnvme.map | 1 + src/nvme/linux.c | 14 +++++++++++--- src/nvme/linux.h | 10 ++++++++++ 3 files changed, 22 insertions(+), 3 deletions(-) diff --git a/src/libnvme.map b/src/libnvme.map index 6bee73a2..e642bb63 100644 --- a/src/libnvme.map +++ b/src/libnvme.map @@ -3,6 +3,7 @@ LIBNVME_1.10 { global: nvme_free_uri; nvme_get_ana_log_atomic; + nvme_get_ana_log_len_from_id_ctrl; nvme_init_default_logging; nvme_parse_uri; nvme_root_skip_namespaces; diff --git a/src/nvme/linux.c b/src/nvme/linux.c index 095c0655..82bcfa11 100644 --- a/src/nvme/linux.c +++ b/src/nvme/linux.c @@ -386,6 +386,16 @@ int nvme_namespace_detach_ctrls(int fd, __u32 nsid, __u16 num_ctrls, NVME_DEFAULT_IOCTL_TIMEOUT); } +size_t nvme_get_ana_log_len_from_id_ctrl(const struct nvme_id_ctrl *id_ctrl, + bool rgo) +{ + __u32 nanagrpid = le32_to_cpu(id_ctrl->nanagrpid); + size_t size = sizeof(struct nvme_ana_log) + + nanagrpid * sizeof(struct nvme_ana_group_desc); + + return rgo ? size : size + le32_to_cpu(id_ctrl->mnan) * sizeof(__le32); +} + int nvme_get_ana_log_len(int fd, size_t *analen) { _cleanup_free_ struct nvme_id_ctrl *ctrl = NULL; @@ -400,9 +410,7 @@ int nvme_get_ana_log_len(int fd, size_t *analen) if (ret) return ret; - *analen = sizeof(struct nvme_ana_log) + - le32_to_cpu(ctrl->nanagrpid) * sizeof(struct nvme_ana_group_desc) + - le32_to_cpu(ctrl->mnan) * sizeof(__le32); + *analen = nvme_get_ana_log_len_from_id_ctrl(ctrl, false); return 0; } diff --git a/src/nvme/linux.h b/src/nvme/linux.h index bd742620..6ef7ec82 100644 --- a/src/nvme/linux.h +++ b/src/nvme/linux.h @@ -128,6 +128,16 @@ int nvme_get_host_telemetry(int fd, struct nvme_telemetry_log **log, int nvme_get_new_host_telemetry(int fd, struct nvme_telemetry_log **log, enum nvme_telemetry_da da, size_t *size); +/** + * nvme_get_ana_log_len_from_id_ctrl() - Retrieve maximum possible ANA log size + * @id_ctrl: Controller identify data + * @rgo: If true, return maximum log page size without NSIDs + * + * Return: A byte limit on the size of the controller's ANA log page + */ +size_t nvme_get_ana_log_len_from_id_ctrl(const struct nvme_id_ctrl *id_ctrl, + bool rgo); + /** * nvme_get_ana_log_len() - Retrieve size of the current ANA log * @fd: File descriptor of nvme device