From b8598520a54e22a4fc024880db2194e5ba7bbfe0 Mon Sep 17 00:00:00 2001 From: Daniel Wagner Date: Wed, 15 Feb 2023 12:35:10 +0100 Subject: [PATCH] nvme: Use chunked read in get_log() Large transfer might not work because we exhaust resource limits, so chunk the read into 4k (default). Signed-off-by: Daniel Wagner --- Documentation/nvme-get-log.txt | 6 ++++++ nvme-wrap.c | 6 ++++++ nvme-wrap.h | 3 +++ nvme.c | 12 +++++++++++- 4 files changed, 26 insertions(+), 1 deletion(-) diff --git a/Documentation/nvme-get-log.txt b/Documentation/nvme-get-log.txt index a92ab6a3..a51c435d 100644 --- a/Documentation/nvme-get-log.txt +++ b/Documentation/nvme-get-log.txt @@ -19,6 +19,7 @@ SYNOPSIS [--rae | -r] [--csi= | -y ] [--ot= | -O ] + [--xfer-len= | -x ] DESCRIPTION ----------- @@ -95,6 +96,11 @@ OPTIONS The default is byte offset. If the option is specified the index mode is used. +-x :: +--xfer-len : + Specify the read chunk size. The length argument is expected to be + a multiple of 4096. The default size is 4096. + EXAMPLES -------- * Get 512 bytes from log page 2 diff --git a/nvme-wrap.c b/nvme-wrap.c index ae7cd925..cee9b235 100644 --- a/nvme-wrap.c +++ b/nvme-wrap.c @@ -158,6 +158,12 @@ int nvme_cli_get_log(struct nvme_dev *dev, struct nvme_get_log_args *args) return do_admin_args_op(get_log, dev, args); } +int nvme_cli_get_log_page(struct nvme_dev *dev, __u32 xfer_len, + struct nvme_get_log_args *args) +{ + return do_admin_op(get_log_page, dev, xfer_len, args); +} + int nvme_cli_get_nsid_log(struct nvme_dev *dev, bool rae, enum nvme_cmd_get_log_lid lid, __u32 nsid, __u32 len, void *log) diff --git a/nvme-wrap.h b/nvme-wrap.h index 4dcc6651..e44a4f28 100644 --- a/nvme-wrap.h +++ b/nvme-wrap.h @@ -51,6 +51,9 @@ int nvme_cli_get_features(struct nvme_dev *dev, int nvme_cli_get_log(struct nvme_dev *dev, struct nvme_get_log_args *args); +int nvme_cli_get_log_page(struct nvme_dev *dev, + __u32 xfer_len, + struct nvme_get_log_args *args); int nvme_cli_get_nsid_log(struct nvme_dev *dev, bool rae, enum nvme_cmd_get_log_lid lid, diff --git a/nvme.c b/nvme.c index b76df852..2ab59236 100644 --- a/nvme.c +++ b/nvme.c @@ -2119,6 +2119,7 @@ static int get_log(int argc, char **argv, struct command *cmd, struct plugin *pl const char *raw = "output in raw format"; const char *csi = "command set identifier"; const char *offset_type = "offset type"; + const char *xfer_len = "read chunk size (default 4k)"; struct nvme_dev *dev; unsigned char *log; int err; @@ -2136,6 +2137,7 @@ static int get_log(int argc, char **argv, struct command *cmd, struct plugin *pl bool raw_binary; __u8 csi; bool ot; + __u32 xfer_len; }; struct config cfg = { @@ -2151,6 +2153,7 @@ static int get_log(int argc, char **argv, struct command *cmd, struct plugin *pl .raw_binary = false, .csi = NVME_CSI_NVM, .ot = false, + .xfer_len = 4096, }; OPT_ARGS(opts) = { @@ -2166,6 +2169,7 @@ static int get_log(int argc, char **argv, struct command *cmd, struct plugin *pl OPT_FLAG("raw-binary", 'b', &cfg.raw_binary, raw), OPT_BYTE("csi", 'y', &cfg.csi, csi), OPT_FLAG("ot", 'O', &cfg.ot, offset_type), + OPT_UINT("xfer-len", 'x', &cfg.xfer_len, xfer_len), OPT_END() }; @@ -2196,6 +2200,12 @@ static int get_log(int argc, char **argv, struct command *cmd, struct plugin *pl goto close_dev; } + if (cfg.xfer_len == 0 || cfg.xfer_len % 4096) { + fprintf(stderr, "xfer-len argument invalid. It needs to be mulitple of 4k"); + err = -EINVAL; + goto close_dev; + } + log = malloc(cfg.log_len); if (!log) { perror("could not alloc buffer for log\n"); @@ -2218,7 +2228,7 @@ static int get_log(int argc, char **argv, struct command *cmd, struct plugin *pl .log = log, .result = NULL, }; - err = nvme_cli_get_log(dev, &args); + err = nvme_cli_get_log_page(dev, cfg.xfer_len, &args); if (!err) { if (!cfg.raw_binary) { printf("Device:%s log-id:%d namespace-id:%#x\n", -- 2.50.1