From ef81f30940e7a905b6e38262c20997fc8dc36ca4 Mon Sep 17 00:00:00 2001 From: Daniel Wagner Date: Wed, 11 Mar 2026 11:34:34 +0100 Subject: [PATCH 1/5] tree: handle error when trying to get transport handle nvme_ns_get_transport_handle is creating a handle on demand, which can fail. Thus we need to propagate this error case and not blindly access the handle later and cause a NULL pointer access. Signed-off-by: Daniel Wagner --- libnvme/src/nvme/private.h | 6 ++- libnvme/src/nvme/tree.c | 89 ++++++++++++++++++++++++++++++-------- libnvme/test/test.c | 6 ++- libnvme/test/zns.c | 7 ++- 4 files changed, 85 insertions(+), 23 deletions(-) diff --git a/libnvme/src/nvme/private.h b/libnvme/src/nvme/private.h index b1fff5b92d..7f82769b3f 100644 --- a/libnvme/src/nvme/private.h +++ b/libnvme/src/nvme/private.h @@ -739,6 +739,7 @@ static inline __u16 nvmf_exat_size(size_t val_len) /** * nvme_ns_get_transport_handle() - Get associated transport handle * @n: Namespace instance + * @hdl: Transport handle * * libnvme will open() the file (if not already opened) and keep * an internal copy of the link handle. Following calls to @@ -747,9 +748,10 @@ static inline __u16 nvmf_exat_size(size_t val_len) * remain cached until the ns object is deleted or * nvme_ns_release_transport_handle() is called. * - * Return: Link handle with @n or NULL + * Return: On success 0, else error code. */ -struct nvme_transport_handle *nvme_ns_get_transport_handle(nvme_ns_t n); +int nvme_ns_get_transport_handle(nvme_ns_t n, + struct nvme_transport_handle **hdl); /** * nvme_ns_release_transport_handle() - Free transport handle from ns object diff --git a/libnvme/src/nvme/tree.c b/libnvme/src/nvme/tree.c index ea9fb3a230..0adaa9f144 100644 --- a/libnvme/src/nvme/tree.c +++ b/libnvme/src/nvme/tree.c @@ -2299,19 +2299,24 @@ static int nvme_bytes_to_lba(nvme_ns_t n, off_t offset, size_t count, return 0; } -struct nvme_transport_handle *nvme_ns_get_transport_handle(nvme_ns_t n) +int nvme_ns_get_transport_handle(nvme_ns_t n, + struct nvme_transport_handle **hdl) { - if (!n->hdl) { - int err; + int err; - err = nvme_open(n->ctx, n->name, &n->hdl); - if (err) - nvme_msg(n->ctx, LOG_ERR, - "Failed to open ns %s, error %d\n", - n->name, err); + if (n->hdl) + goto valid; + + err = nvme_open(n->ctx, n->name, &n->hdl); + if (err) { + nvme_msg(n->ctx, LOG_ERR, "Failed to open ns %s, error %d\n", + n->name, err); + return err; } - return n->hdl; +valid: + *hdl = n->hdl; + return 0; } void nvme_ns_release_transport_handle(nvme_ns_t n) @@ -2415,8 +2420,13 @@ void nvme_ns_get_uuid(nvme_ns_t n, unsigned char out[NVME_UUID_LEN]) int nvme_ns_identify(nvme_ns_t n, struct nvme_id_ns *ns) { - struct nvme_transport_handle *hdl = nvme_ns_get_transport_handle(n); + struct nvme_transport_handle *hdl; struct nvme_passthru_cmd cmd; + int err; + + err = nvme_ns_get_transport_handle(n, &hdl); + if (err) + return err; nvme_init_identify_ns(&cmd, nvme_ns_get_nsid(n), ns); return nvme_submit_admin_passthru(hdl, &cmd); @@ -2424,8 +2434,13 @@ int nvme_ns_identify(nvme_ns_t n, struct nvme_id_ns *ns) int nvme_ns_identify_descs(nvme_ns_t n, struct nvme_ns_id_desc *descs) { - struct nvme_transport_handle *hdl = nvme_ns_get_transport_handle(n); + struct nvme_transport_handle *hdl; struct nvme_passthru_cmd cmd; + int err; + + err = nvme_ns_get_transport_handle(n, &hdl); + if (err) + return err; nvme_init_identify_ns_descs_list(&cmd, nvme_ns_get_nsid(n), descs); return nvme_submit_admin_passthru(hdl, &cmd); @@ -2433,10 +2448,15 @@ int nvme_ns_identify_descs(nvme_ns_t n, struct nvme_ns_id_desc *descs) int nvme_ns_verify(nvme_ns_t n, off_t offset, size_t count) { - struct nvme_transport_handle *hdl = nvme_ns_get_transport_handle(n); + struct nvme_transport_handle *hdl; struct nvme_passthru_cmd cmd; __u64 slba; __u16 nlb; + int err; + + err = nvme_ns_get_transport_handle(n, &hdl); + if (err) + return err; if (nvme_bytes_to_lba(n, offset, count, &slba, &nlb)) return -1; @@ -2449,10 +2469,15 @@ int nvme_ns_verify(nvme_ns_t n, off_t offset, size_t count) int nvme_ns_write_uncorrectable(nvme_ns_t n, off_t offset, size_t count) { - struct nvme_transport_handle *hdl = nvme_ns_get_transport_handle(n); + struct nvme_transport_handle *hdl; struct nvme_passthru_cmd cmd; __u64 slba; __u16 nlb; + int err; + + err = nvme_ns_get_transport_handle(n, &hdl); + if (err) + return err; if (nvme_bytes_to_lba(n, offset, count, &slba, &nlb)) return -1; @@ -2465,10 +2490,15 @@ int nvme_ns_write_uncorrectable(nvme_ns_t n, off_t offset, size_t count) int nvme_ns_write_zeros(nvme_ns_t n, off_t offset, size_t count) { - struct nvme_transport_handle *hdl = nvme_ns_get_transport_handle(n); + struct nvme_transport_handle *hdl; struct nvme_passthru_cmd cmd; __u64 slba; __u16 nlb; + int err; + + err = nvme_ns_get_transport_handle(n, &hdl); + if (err) + return err; if (nvme_bytes_to_lba(n, offset, count, &slba, &nlb)) return -1; @@ -2480,10 +2510,15 @@ int nvme_ns_write_zeros(nvme_ns_t n, off_t offset, size_t count) int nvme_ns_write(nvme_ns_t n, void *buf, off_t offset, size_t count) { - struct nvme_transport_handle *hdl = nvme_ns_get_transport_handle(n); + struct nvme_transport_handle *hdl; struct nvme_passthru_cmd cmd; __u64 slba; __u16 nlb; + int err; + + err = nvme_ns_get_transport_handle(n, &hdl); + if (err) + return err; if (nvme_bytes_to_lba(n, offset, count, &slba, &nlb)) return -1; @@ -2496,10 +2531,15 @@ int nvme_ns_write(nvme_ns_t n, void *buf, off_t offset, size_t count) int nvme_ns_read(nvme_ns_t n, void *buf, off_t offset, size_t count) { - struct nvme_transport_handle *hdl = nvme_ns_get_transport_handle(n); + struct nvme_transport_handle *hdl; struct nvme_passthru_cmd cmd; __u64 slba; __u16 nlb; + int err; + + err = nvme_ns_get_transport_handle(n, &hdl); + if (err) + return err; if (nvme_bytes_to_lba(n, offset, count, &slba, &nlb)) return -1; @@ -2512,10 +2552,15 @@ int nvme_ns_read(nvme_ns_t n, void *buf, off_t offset, size_t count) int nvme_ns_compare(nvme_ns_t n, void *buf, off_t offset, size_t count) { - struct nvme_transport_handle *hdl = nvme_ns_get_transport_handle(n); + struct nvme_transport_handle *hdl; struct nvme_passthru_cmd cmd; __u64 slba; __u16 nlb; + int err; + + err = nvme_ns_get_transport_handle(n, &hdl); + if (err) + return err; if (nvme_bytes_to_lba(n, offset, count, &slba, &nlb)) return -1; @@ -2528,8 +2573,14 @@ int nvme_ns_compare(nvme_ns_t n, void *buf, off_t offset, size_t count) int nvme_ns_flush(nvme_ns_t n) { - return nvme_flush(nvme_ns_get_transport_handle(n), - nvme_ns_get_nsid(n)); + struct nvme_transport_handle *hdl; + int err; + + err = nvme_ns_get_transport_handle(n, &hdl); + if (err) + return err; + + return nvme_flush(hdl, nvme_ns_get_nsid(n)); } static int nvme_strtou64(const char *str, void *res) diff --git a/libnvme/test/test.c b/libnvme/test/test.c index 8b7d54b7cb..31e5a4b39b 100644 --- a/libnvme/test/test.c +++ b/libnvme/test/test.c @@ -324,13 +324,17 @@ static int test_ctrl(nvme_ctrl_t c) static int test_namespace(nvme_ns_t n) { int ret, nsid = nvme_ns_get_nsid(n); - struct nvme_transport_handle *hdl = nvme_ns_get_transport_handle(n); + struct nvme_transport_handle *hdl; struct nvme_passthru_cmd cmd; struct nvme_id_ns ns = { 0 }, allocated = { 0 }; struct nvme_ns_id_desc *descs; __u64 result = 0; __u8 flbas; + ret = nvme_ns_get_transport_handle(n, &hdl); + if (ret) + return ret; + ret = nvme_ns_identify(n, &ns); if (ret) return ret; diff --git a/libnvme/test/zns.c b/libnvme/test/zns.c index b41ab4c9e7..6c4a4c1dfc 100644 --- a/libnvme/test/zns.c +++ b/libnvme/test/zns.c @@ -24,11 +24,16 @@ static void show_zns_properties(nvme_ns_t n) { - struct nvme_transport_handle *hdl = nvme_ns_get_transport_handle(n); + struct nvme_transport_handle *hdl; struct nvme_passthru_cmd cmd; struct nvme_zns_id_ns zns_ns; struct nvme_zns_id_ctrl zns_ctrl; struct nvme_zone_report *zr; + int err; + + err = nvme_ns_get_transport_handle(n, &hdl); + if (err) + return; zr = calloc(1, 0x1000); if (!zr) From f34bfade0102f8f8e28dc8193d5e162f553b5eb3 Mon Sep 17 00:00:00 2001 From: Daniel Wagner Date: Wed, 11 Mar 2026 11:37:10 +0100 Subject: [PATCH 2/5] tree: propagate error code for nvme_scan_ctrl The scanning can fail due to missing permissions etc. Thus propagate this error code instead creating invalid objects. Signed-off-by: Daniel Wagner --- libnvme/src/nvme/tree.c | 32 ++++++++++++++++++++++++-------- 1 file changed, 24 insertions(+), 8 deletions(-) diff --git a/libnvme/src/nvme/tree.c b/libnvme/src/nvme/tree.c index 0adaa9f144..75eeb05d60 100644 --- a/libnvme/src/nvme/tree.c +++ b/libnvme/src/nvme/tree.c @@ -1843,7 +1843,7 @@ nvme_ctrl_t nvme_lookup_ctrl(nvme_subsystem_t s, const char *transport, static int nvme_ctrl_scan_paths(struct nvme_global_ctx *ctx, struct nvme_ctrl *c) { _cleanup_dirents_ struct dirents paths = {}; - int i; + int err, i; if (ctx->create_only) { nvme_msg(ctx, LOG_DEBUG, @@ -1854,8 +1854,11 @@ static int nvme_ctrl_scan_paths(struct nvme_global_ctx *ctx, struct nvme_ctrl *c if (paths.num < 0) return paths.num; - for (i = 0; i < paths.num; i++) - nvme_ctrl_scan_path(ctx, c, paths.ents[i]->d_name); + for (i = 0; i < paths.num; i++) { + err = nvme_ctrl_scan_path(ctx, c, paths.ents[i]->d_name); + if (err) + return err; + } return 0; } @@ -1863,7 +1866,7 @@ static int nvme_ctrl_scan_paths(struct nvme_global_ctx *ctx, struct nvme_ctrl *c static int nvme_ctrl_scan_namespaces(struct nvme_global_ctx *ctx, struct nvme_ctrl *c) { _cleanup_dirents_ struct dirents namespaces = {}; - int i; + int err, i; if (ctx->create_only) { nvme_msg(ctx, LOG_DEBUG, "skipping namespace scan for ctrl %s\n", @@ -1871,8 +1874,12 @@ static int nvme_ctrl_scan_namespaces(struct nvme_global_ctx *ctx, struct nvme_ct return 0; } namespaces.num = nvme_scan_ctrl_namespaces(c, &namespaces.ents); - for (i = 0; i < namespaces.num; i++) - nvme_ctrl_scan_namespace(ctx, c, namespaces.ents[i]->d_name); + for (i = 0; i < namespaces.num; i++) { + err = nvme_ctrl_scan_namespace(ctx, c, + namespaces.ents[i]->d_name); + if (err) + return err; + } return 0; } @@ -2267,8 +2274,17 @@ int nvme_scan_ctrl(struct nvme_global_ctx *ctx, const char *name, if (ret) return ret; - nvme_ctrl_scan_paths(ctx, c); - nvme_ctrl_scan_namespaces(ctx, c); + ret = nvme_ctrl_scan_paths(ctx, c); + if (ret) { + nvme_free_ctrl(c); + return ret; + } + + ret = nvme_ctrl_scan_namespaces(ctx, c); + if (ret) { + nvme_free_ctrl(c); + return ret; + } *cp = c; return 0; From 837ef96c2a442985ebc8f3519acb6c380246d1b2 Mon Sep 17 00:00:00 2001 From: Daniel Wagner Date: Wed, 11 Mar 2026 11:47:40 +0100 Subject: [PATCH 3/5] test: ignore ENOENT and EACCES from nvme_scan_topology Replace nvme_scan with nvme_scan_topology and ignore any ENOENT and EACCES. Either the nvme module is not loaded/present or the current user might now have permissions to access the device. Signed-off-by: Daniel Wagner --- libnvme/test/cpp.cc | 15 ++++++++++++--- 1 file changed, 12 insertions(+), 3 deletions(-) diff --git a/libnvme/test/cpp.cc b/libnvme/test/cpp.cc index 48ac9cec54..2df093a6b5 100644 --- a/libnvme/test/cpp.cc +++ b/libnvme/test/cpp.cc @@ -18,9 +18,16 @@ int main() nvme_ctrl_t c; nvme_path_t p; nvme_ns_t n; + int err; - if (nvme_scan(NULL, &ctx)) - return -1; + ctx = nvme_create_global_ctx(stdout, DEFAULT_LOGLEVEL); + if (!ctx) + return 1; + + err = nvme_scan_topology(ctx, NULL, NULL); + if (err && !(err == -ENOENT || err == -EACCES)) + goto out; + err = 0; nvme_for_each_host(ctx, h) { nvme_for_each_subsystem(h, s) { @@ -60,7 +67,9 @@ int main() } } std::cout << "\n"; + +out: nvme_free_global_ctx(ctx); - return 0; + return err != 0 ? 1 : 0; } From 442f1d6dc462e4e1129b64451da6181e2d2779c9 Mon Sep 17 00:00:00 2001 From: Daniel Wagner Date: Wed, 11 Mar 2026 12:16:38 +0100 Subject: [PATCH 4/5] tree: remove nvme_scan The problem with this function is that it does several things at once which prevents fine grained error handling. And almost every user of this function was not interested in reading a config file. Thus open code this and handle the ENOENT and EACCES case. For the Python binding we just ignore any nvme_scan_topology and nvme_read_config error because this happens inside the global context constructor Signed-off-by: Daniel Wagner --- libnvme/examples/discover-loop.c | 20 +++++++++++++------- libnvme/examples/display-columnar.c | 12 ++++++++++-- libnvme/examples/display-tree.c | 12 ++++++++++-- libnvme/examples/telemetry-listen.c | 8 +++++++- libnvme/libnvme/nvme.i | 8 +++++++- libnvme/src/libnvme.ld | 1 - libnvme/src/nvme/tree.c | 26 -------------------------- libnvme/src/nvme/tree.h | 9 --------- libnvme/test/cpp.cc | 11 ++++++----- libnvme/test/sysfs/tree-dump.c | 4 +++- libnvme/test/test.c | 16 ++++++++++------ libnvme/test/zns.c | 14 ++++++++++++-- 12 files changed, 78 insertions(+), 63 deletions(-) diff --git a/libnvme/examples/discover-loop.c b/libnvme/examples/discover-loop.c index 367507d9d2..f4d7d80b57 100644 --- a/libnvme/examples/discover-loop.c +++ b/libnvme/examples/discover-loop.c @@ -50,7 +50,7 @@ static void print_discover_log(struct nvmf_discovery_log *log) int main() { - struct nvmf_discovery_log *log = NULL; + struct nvmf_discovery_log *log; struct nvme_global_ctx *ctx; nvme_host_t h; nvme_ctrl_t c; @@ -59,24 +59,30 @@ int main() nvmf_default_config(&cfg); - ret = nvme_scan(NULL, &ctx); - if (ret) - return ret; + ctx = nvme_create_global_ctx(stdout, DEFAULT_LOGLEVEL); + if (!ctx) + return 1; + + ret = nvme_scan_topology(ctx, NULL, NULL); + if (ret) { + nvme_free_global_ctx(ctx); + return 1; + } ret = nvme_host_get(ctx, NULL, NULL, &h); if (ret) { fprintf(stderr, "Failed to allocated memory\n"); - return ret; + return 1; } ret = nvme_create_ctrl(ctx, NVME_DISC_SUBSYS_NAME, "loop", NULL, NULL, NULL, NULL, &c); if (ret) { fprintf(stderr, "Failed to allocate memory\n"); - return ENOMEM; + return 1; } ret = nvmf_add_ctrl(h, c, &cfg); if (ret) { fprintf(stderr, "no controller found\n"); - return ret; + return 1; } ret = nvmf_get_discovery_log(c, &log, 4); diff --git a/libnvme/examples/display-columnar.c b/libnvme/examples/display-columnar.c index 777f8a94a8..a08a2acbef 100644 --- a/libnvme/examples/display-columnar.c +++ b/libnvme/examples/display-columnar.c @@ -23,9 +23,17 @@ int main() nvme_ctrl_t c; nvme_path_t p; nvme_ns_t n; + int err; - if (nvme_scan(NULL, &ctx)) - return -1; + ctx = nvme_create_global_ctx(stdout, DEFAULT_LOGLEVEL); + if (!ctx) + return 1; + + err = nvme_scan_topology(ctx, NULL, NULL); + if (err) { + nvme_free_global_ctx(ctx); + return 1; + } printf("%-16s %-96s %-.16s\n", "Subsystem", "Subsystem-NQN", "Controllers"); printf("%-.16s %-.96s %-.16s\n", dash, dash, dash); diff --git a/libnvme/examples/display-tree.c b/libnvme/examples/display-tree.c index b3e980ceaa..8de77978da 100644 --- a/libnvme/examples/display-tree.c +++ b/libnvme/examples/display-tree.c @@ -22,9 +22,17 @@ int main() nvme_ctrl_t c, _c; nvme_path_t p, _p; nvme_ns_t n, _n; + int err; - if (nvme_scan(NULL, &ctx)) - return -1; + ctx = nvme_create_global_ctx(stdout, DEFAULT_LOGLEVEL); + if (!ctx) + return 1; + + err = nvme_scan_topology(ctx, NULL, NULL); + if (err) { + nvme_free_global_ctx(ctx); + return 1; + } printf(".\n"); nvme_for_each_host(ctx, h) { diff --git a/libnvme/examples/telemetry-listen.c b/libnvme/examples/telemetry-listen.c index 9db65e3299..2029da5848 100644 --- a/libnvme/examples/telemetry-listen.c +++ b/libnvme/examples/telemetry-listen.c @@ -135,8 +135,14 @@ int main() nvme_ctrl_t c; nvme_host_t h; - if (nvme_scan(NULL, &ctx)) + ctx = nvme_create_global_ctx(stdout, DEFAULT_LOGLEVEL); + if (!ctx) + return 1; + + if (nvme_scan_topology(ctx, NULL, NULL)) { + nvme_free_global_ctx(ctx); return EXIT_FAILURE; + } nvme_for_each_host(ctx, h) nvme_for_each_subsystem(h, s) diff --git a/libnvme/libnvme/nvme.i b/libnvme/libnvme/nvme.i index 6981742d8b..c606532b33 100644 --- a/libnvme/libnvme/nvme.i +++ b/libnvme/libnvme/nvme.i @@ -487,8 +487,14 @@ struct nvme_ns { %extend nvme_global_ctx { nvme_global_ctx(const char *config_file = NULL) { struct nvme_global_ctx *ctx; - if (nvme_scan(config_file, &ctx)) + + ctx = nvme_create_global_ctx(stdout, DEFAULT_LOGLEVEL); + if (!ctx) return NULL; + + nvme_scan_topology(ctx, NULL, NULL); + nvme_read_config(ctx, config_file); + return ctx; } ~nvme_global_ctx() { diff --git a/libnvme/src/libnvme.ld b/libnvme/src/libnvme.ld index a2ad5e478e..4072407de9 100644 --- a/libnvme/src/libnvme.ld +++ b/libnvme/src/libnvme.ld @@ -208,7 +208,6 @@ LIBNVME_2_0 { nvme_release_fds; nvme_rescan_ctrl; nvme_revoke_tls_key; - nvme_scan; nvme_scan_ctrl; nvme_scan_ctrl_namespace_paths; nvme_scan_ctrl_namespaces; diff --git a/libnvme/src/nvme/tree.c b/libnvme/src/nvme/tree.c index 75eeb05d60..dcc540fb89 100644 --- a/libnvme/src/nvme/tree.c +++ b/libnvme/src/nvme/tree.c @@ -345,32 +345,6 @@ int nvme_read_config(struct nvme_global_ctx *ctx, const char *config_file) return err; } -int nvme_scan(const char *config_file, struct nvme_global_ctx **ctxp) -{ - struct nvme_global_ctx *ctx = - nvme_create_global_ctx(NULL, DEFAULT_LOGLEVEL); - int ret; - - if (!ctx) - return -ENOMEM; - - ret = nvme_scan_topology(ctx, NULL, NULL); - if (ret && ret != -ENOENT) - goto err; - if (config_file) { - ret = nvme_read_config(ctx, config_file); - if (ret) - goto err; - } - - *ctxp = ctx; - return 0; - -err: - nvme_free_global_ctx(ctx); - return ret; -} - int nvme_dump_config(struct nvme_global_ctx *ctx, int fd) { return json_update_config(ctx, fd); diff --git a/libnvme/src/nvme/tree.h b/libnvme/src/nvme/tree.h index 91060943ce..dfc6f386ba 100644 --- a/libnvme/src/nvme/tree.h +++ b/libnvme/src/nvme/tree.h @@ -1339,15 +1339,6 @@ void nvme_host_release_fds(struct nvme_host *h); */ void nvme_free_host(nvme_host_t h); -/** - * nvme_scan() - Scan NVMe topology - * @config_file: Configuration file - * @ctx: &nvme_global_ctx object to return - * - * Return: 0 on success or negative error code otherwise - */ -int nvme_scan(const char *config_file, struct nvme_global_ctx **ctx); - /** * nvme_read_config() - Read NVMe JSON configuration file * @ctx: &struct nvme_global_ctx object diff --git a/libnvme/test/cpp.cc b/libnvme/test/cpp.cc index 2df093a6b5..309359cee1 100644 --- a/libnvme/test/cpp.cc +++ b/libnvme/test/cpp.cc @@ -25,9 +25,11 @@ int main() return 1; err = nvme_scan_topology(ctx, NULL, NULL); - if (err && !(err == -ENOENT || err == -EACCES)) - goto out; - err = 0; + if (err && !(err == -ENOENT || err == -EACCES)) { + fprintf(stderr, "nvme_scan_topology failed %d\n", err); + nvme_free_global_ctx(ctx); + return 1; + } nvme_for_each_host(ctx, h) { nvme_for_each_subsystem(h, s) { @@ -68,8 +70,7 @@ int main() } std::cout << "\n"; -out: nvme_free_global_ctx(ctx); - return err != 0 ? 1 : 0; + return 0; } diff --git a/libnvme/test/sysfs/tree-dump.c b/libnvme/test/sysfs/tree-dump.c index 1cd6d3a99a..a6c9831323 100644 --- a/libnvme/test/sysfs/tree-dump.c +++ b/libnvme/test/sysfs/tree-dump.c @@ -22,8 +22,10 @@ static bool tree_dump(void) return false; err = nvme_scan_topology(ctx, NULL, NULL); - if (err && err != ENOENT) + if (err && !(err == ENOENT || err == EACCES)) { + fprintf(stderr, "nvme_scan_topology failed %d\n", err); goto out; + } if (nvme_dump_tree(ctx)) goto out; diff --git a/libnvme/test/test.c b/libnvme/test/test.c index 31e5a4b39b..96d9272035 100644 --- a/libnvme/test/test.c +++ b/libnvme/test/test.c @@ -387,14 +387,22 @@ int main(int argc, char **argv) nvme_ctrl_t c; nvme_path_t p; nvme_ns_t n; + int err; const char *ctrl = "nvme4"; const char *nqn_match = "testnqn"; printf("Test filter for common loop back target\n"); - ctx = nvme_create_global_ctx(NULL, DEFAULT_LOGLEVEL); + ctx = nvme_create_global_ctx(stdout, DEFAULT_LOGLEVEL); if (!ctx) return 1; - nvme_scan_topology(ctx, nvme_match_subsysnqn_filter, (void *)nqn_match); + + err = nvme_scan_topology(ctx, nvme_match_subsysnqn_filter, + (void *)nqn_match); + if (err && !(err == ENOENT || err == EACCES)) { + nvme_free_global_ctx(ctx); + return 1; + } + nvme_for_each_host(ctx, h) { nvme_for_each_subsystem(h, s) { printf("%s - NQN=%s\n", nvme_subsystem_get_name(s), @@ -421,10 +429,6 @@ int main(int argc, char **argv) nvme_free_ctrl(c); } printf("\n"); - nvme_free_global_ctx(ctx); - - if (nvme_scan(NULL, &ctx)) - return -1; printf("Test walking the topology\n"); nvme_for_each_host(ctx, h) { diff --git a/libnvme/test/zns.c b/libnvme/test/zns.c index 6c4a4c1dfc..82d81a5e7f 100644 --- a/libnvme/test/zns.c +++ b/libnvme/test/zns.c @@ -80,9 +80,17 @@ int main() nvme_host_t h; nvme_ctrl_t c; nvme_ns_t n; + int err; + + ctx = nvme_create_global_ctx(stdout, DEFAULT_LOGLEVEL); + if (!ctx) + return 1; - if (nvme_scan(NULL, &ctx)) - return -1; + err = nvme_scan_topology(ctx, NULL, NULL); + if (err && !(err == -ENOENT || err == -EACCES)) { + nvme_free_global_ctx(ctx); + return 1; + } nvme_for_each_host(ctx, h) { nvme_for_each_subsystem(h, s) { @@ -98,5 +106,7 @@ int main() } } } + nvme_free_global_ctx(ctx); + return 0; } From 6dbd532e53a3446621b5b1bb3d3846180775879e Mon Sep 17 00:00:00 2001 From: Daniel Wagner Date: Wed, 11 Mar 2026 15:49:11 +0100 Subject: [PATCH 5/5] filters: return error code The scan helpers should also return the error code instead the generic -1. Fixes: f4c6eee2939d ("rrc: return error codes directly") Signed-off-by: Daniel Wagner --- libnvme/src/nvme/filters.c | 46 +++++++++++++++++++++++++++++++++----- libnvme/src/nvme/filters.h | 12 +++++----- 2 files changed, 46 insertions(+), 12 deletions(-) diff --git a/libnvme/src/nvme/filters.c b/libnvme/src/nvme/filters.c index 3aa351bcbd..e2f50e3137 100644 --- a/libnvme/src/nvme/filters.c +++ b/libnvme/src/nvme/filters.c @@ -78,37 +78,71 @@ int nvme_subsys_filter(const struct dirent *d) int nvme_scan_subsystems(struct dirent ***subsys) { const char *dir = nvme_subsys_sysfs_dir(); + int ret; - return scandir(dir, subsys, nvme_subsys_filter, alphasort); + ret = scandir(dir, subsys, nvme_subsys_filter, alphasort); + if (ret < 0) + return -errno; + + return ret; } int nvme_scan_subsystem_namespaces(nvme_subsystem_t s, struct dirent ***ns) { - return scandir(nvme_subsystem_get_sysfs_dir(s), ns, + int ret; + + ret = scandir(nvme_subsystem_get_sysfs_dir(s), ns, nvme_namespace_filter, alphasort); + if (ret < 0) + return -errno; + + return ret; } int nvme_scan_ctrls(struct dirent ***ctrls) { const char *dir = nvme_ctrl_sysfs_dir(); + int ret; - return scandir(dir, ctrls, nvme_ctrls_filter, alphasort); + ret = scandir(dir, ctrls, nvme_ctrls_filter, alphasort); + if (ret < 0) + return -errno; + + return ret; } int nvme_scan_ctrl_namespace_paths(nvme_ctrl_t c, struct dirent ***paths) { - return scandir(nvme_ctrl_get_sysfs_dir(c), paths, + int ret; + + ret = scandir(nvme_ctrl_get_sysfs_dir(c), paths, nvme_paths_filter, alphasort); + if (ret < 0) + return -errno; + + return ret; } int nvme_scan_ctrl_namespaces(nvme_ctrl_t c, struct dirent ***ns) { - return scandir(nvme_ctrl_get_sysfs_dir(c), ns, + int ret; + + ret = scandir(nvme_ctrl_get_sysfs_dir(c), ns, nvme_namespace_filter, alphasort); + if (ret < 0) + return -errno; + + return ret; } int nvme_scan_ns_head_paths(nvme_ns_head_t head, struct dirent ***paths) { - return scandir(nvme_ns_head_get_sysfs_dir(head), paths, + int ret; + + ret = scandir(nvme_ns_head_get_sysfs_dir(head), paths, nvme_paths_filter, alphasort); + if (ret < 0) + return -errno; + + return ret; } diff --git a/libnvme/src/nvme/filters.h b/libnvme/src/nvme/filters.h index 9e9dbb9598..44f26ab2b3 100644 --- a/libnvme/src/nvme/filters.h +++ b/libnvme/src/nvme/filters.h @@ -55,7 +55,7 @@ int nvme_subsys_filter(const struct dirent *d); * nvme_scan_subsystems() - Scan for subsystems * @subsys: Pointer to array of dirents * - * Return: number of entries in @subsys + * Return: number of entries in @subsys or a negative error code */ int nvme_scan_subsystems(struct dirent ***subsys); @@ -64,7 +64,7 @@ int nvme_scan_subsystems(struct dirent ***subsys); * @s: Subsystem to scan * @ns: Pointer to array of dirents * - * Return: number of entries in @ns + * Return: number of entries in @ns or a negative error code */ int nvme_scan_subsystem_namespaces(nvme_subsystem_t s, struct dirent ***ns); @@ -72,7 +72,7 @@ int nvme_scan_subsystem_namespaces(nvme_subsystem_t s, struct dirent ***ns); * nvme_scan_ctrls() - Scan for controllers * @ctrls: Pointer to array of dirents * - * Return: number of entries in @ctrls + * Return: number of entries in @ctrls or a negative error code */ int nvme_scan_ctrls(struct dirent ***ctrls); @@ -81,7 +81,7 @@ int nvme_scan_ctrls(struct dirent ***ctrls); * @c: Controller to scan * @paths: Pointer to array of dirents * - * Return: number of entries in @paths + * Return: number of entries in @paths or a negative error code */ int nvme_scan_ctrl_namespace_paths(nvme_ctrl_t c, struct dirent ***paths); @@ -90,7 +90,7 @@ int nvme_scan_ctrl_namespace_paths(nvme_ctrl_t c, struct dirent ***paths); * @c: Controller to scan * @ns: Pointer to array of dirents * - * Return: number of entries in @ns + * Return: number of entries in @ns or a negative error code */ int nvme_scan_ctrl_namespaces(nvme_ctrl_t c, struct dirent ***ns); @@ -99,7 +99,7 @@ int nvme_scan_ctrl_namespaces(nvme_ctrl_t c, struct dirent ***ns); * @head: Namespace head node to scan * @paths : Pointer to array of dirents * - * Return: number of entries in @ents + * Return: number of entries in @ents or a negative error code */ int nvme_scan_ns_head_paths(nvme_ns_head_t head, struct dirent ***paths);