From 66c1f7046964c4c9b96f1535fa7f0aa6fa391605 Mon Sep 17 00:00:00 2001 From: Caleb Sander Mateos Date: Tue, 30 Apr 2024 16:35:01 -0600 Subject: [PATCH] nvme: use libnvme's atomic ANA log page fetch nvme ana-log currently uses libnvme's nvme{,_mi_admin}_get_log_ana() function to fetch the ANA log page. As described in the commit adding nvme_get_ana_log_atomic() to libnvme, this has the potential to overread the ANA log page and may result in a torn result if the log page changes concurrently. Use nvme{,_mi_admin}_get_ana_log_atomic() to only fetch up to the end of the ANA log page and protect against concurrent log page changes. Signed-off-by: Caleb Sander Mateos --- nvme-wrap.c | 8 ++++---- nvme-wrap.h | 6 +++--- nvme.c | 20 ++++++++++++-------- 3 files changed, 19 insertions(+), 15 deletions(-) diff --git a/nvme-wrap.c b/nvme-wrap.c index 1327c86d..9013ddc5 100644 --- a/nvme-wrap.c +++ b/nvme-wrap.c @@ -256,11 +256,11 @@ int nvme_cli_get_log_predictable_lat_event(struct nvme_dev *dev, bool rae, len, log); } -int nvme_cli_get_log_ana(struct nvme_dev *dev, - enum nvme_log_ana_lsp lsp, bool rae, - __u64 offset, __u32 len, void *log) +int nvme_cli_get_ana_log_atomic(struct nvme_dev *dev, bool rgo, bool rae, + unsigned int retries, + struct nvme_ana_log *log, __u32 *len) { - return do_admin_op(get_log_ana, dev, lsp, rae, offset, len, log); + return do_admin_op(get_ana_log_atomic, dev, rgo, rae, retries, log, len); } int nvme_cli_get_log_lba_status(struct nvme_dev *dev, bool rae, diff --git a/nvme-wrap.h b/nvme-wrap.h index c3bb09a6..5005af62 100644 --- a/nvme-wrap.h +++ b/nvme-wrap.h @@ -88,9 +88,9 @@ int nvme_cli_get_log_predictable_lat_nvmset(struct nvme_dev *dev, struct nvme_nvmset_predictable_lat_log *log); int nvme_cli_get_log_predictable_lat_event(struct nvme_dev *dev, bool rae, __u32 offset, __u32 len, void *log); -int nvme_cli_get_log_ana(struct nvme_dev *dev, - enum nvme_log_ana_lsp lsp, bool rae, - __u64 offset, __u32 len, void *log); +int nvme_cli_get_ana_log_atomic(struct nvme_dev *dev, bool rgo, bool rae, + unsigned int retries, + struct nvme_ana_log *log, __u32 *len); int nvme_cli_get_log_lba_status(struct nvme_dev *dev, bool rae, __u64 offset, __u32 len, void *log); int nvme_cli_get_log_endurance_grp_evt(struct nvme_dev *dev, bool rae, diff --git a/nvme.c b/nvme.c index 1da98657..bde49258 100644 --- a/nvme.c +++ b/nvme.c @@ -592,10 +592,10 @@ static int get_ana_log(int argc, char **argv, struct command *cmd, _cleanup_nvme_dev_ struct nvme_dev *dev = NULL; _cleanup_free_ struct nvme_id_ctrl *ctrl = NULL; - _cleanup_free_ void *ana_log = NULL; - size_t ana_log_len; + _cleanup_free_ struct nvme_ana_log *ana_log = NULL; + size_t max_ana_log_len; + __u32 ana_log_len; enum nvme_print_flags flags; - enum nvme_log_ana_lsp lsp; int err = -1; struct config { @@ -630,15 +630,19 @@ static int get_ana_log(int argc, char **argv, struct command *cmd, return err; } - ana_log_len = nvme_get_ana_log_len_from_id_ctrl(ctrl, cfg.groups); + max_ana_log_len = nvme_get_ana_log_len_from_id_ctrl(ctrl, cfg.groups); + ana_log_len = max_ana_log_len; + if (ana_log_len < max_ana_log_len) { + nvme_show_error("ANA log length %zu too large", max_ana_log_len); + return -ENOMEM; + } + ana_log = nvme_alloc(ana_log_len); if (!ana_log) return -ENOMEM; - lsp = cfg.groups ? NVME_LOG_ANA_LSP_RGO_GROUPS_ONLY : - NVME_LOG_ANA_LSP_RGO_NAMESPACES; - - err = nvme_cli_get_log_ana(dev, lsp, true, 0, ana_log_len, ana_log); + err = nvme_cli_get_ana_log_atomic(dev, cfg.groups, true, 10, + ana_log, &ana_log_len); if (!err) nvme_show_ana_log(ana_log, dev->name, ana_log_len, flags); else if (err > 0) -- 2.50.1