Bug Summary

File:.build-ci/../libnvme/src/nvme/tree.c
Warning:line 1488, column 6
Access to field 'create_only' results in a dereference of a null pointer (loaded from variable 'ctx')

Annotated Source Code

Press '?' to see keyboard shortcuts

clang -cc1 -cc1 -triple x86_64-pc-linux-gnu -analyze -disable-free -clear-ast-before-backend -disable-llvm-verifier -discard-value-names -main-file-name tree.c -analyzer-checker=core -analyzer-checker=apiModeling -analyzer-checker=unix -analyzer-checker=deadcode -analyzer-checker=security.insecureAPI.UncheckedReturn -analyzer-checker=security.insecureAPI.getpw -analyzer-checker=security.insecureAPI.gets -analyzer-checker=security.insecureAPI.mktemp -analyzer-checker=security.insecureAPI.mkstemp -analyzer-checker=security.insecureAPI.vfork -analyzer-checker=nullability.NullPassedToNonnull -analyzer-checker=nullability.NullReturnedFromNonnull -analyzer-output plist -w -setup-static-analyzer -mrelocation-model pic -pic-level 2 -fhalf-no-semantic-interposition -mframe-pointer=none -fmath-errno -ffp-contract=on -fno-rounding-math -mconstructor-aliases -funwind-tables=2 -target-cpu x86-64 -tune-cpu generic -debugger-tuning=gdb -fdebug-compilation-dir=/__w/nvme-cli/nvme-cli/.build-ci -fcoverage-compilation-dir=/__w/nvme-cli/nvme-cli/.build-ci -resource-dir /usr/lib/llvm-19/lib/clang/19 -include /__w/nvme-cli/nvme-cli/.build-ci/nvme-config.h -I libnvme/src/libnvme3.so.3.0.0.p -I libnvme/src -I ../libnvme/src -I ccan -I ../ccan -I . -I .. -I /usr/include/json-c -D _FILE_OFFSET_BITS=64 -D _GNU_SOURCE -U NDEBUG -internal-isystem /usr/lib/llvm-19/lib/clang/19/include -internal-isystem /usr/local/include -internal-isystem /usr/lib/gcc/x86_64-linux-gnu/14/../../../../x86_64-linux-gnu/include -internal-externc-isystem /usr/include/x86_64-linux-gnu -internal-externc-isystem /include -internal-externc-isystem /usr/include -O3 -std=gnu99 -ferror-limit 19 -fvisibility=hidden -fgnuc-version=4.2.1 -fskip-odr-check-in-gmf -fcolor-diagnostics -vectorize-loops -vectorize-slp -analyzer-opt-analyze-headers -analyzer-output=html -faddrsig -D__GCC_HAVE_DWARF2_CFI_ASM=1 -o /__w/nvme-cli/nvme-cli/.build-ci/scan-results/2026-06-24-175442-590-1 -x c ../libnvme/src/nvme/tree.c
1// SPDX-License-Identifier: LGPL-2.1-or-later
2/*
3 * This file is part of libnvme.
4 * Copyright (c) 2020 Western Digital Corporation or its affiliates.
5 *
6 * Authors: Keith Busch <keith.busch@wdc.com>
7 * Chaitanya Kulkarni <chaitanya.kulkarni@wdc.com>
8 */
9#include <errno(*__errno_location ()).h>
10#include <fcntl.h>
11#include <libgen.h>
12#include <stdint.h>
13#include <stdio.h>
14#include <stdlib.h>
15#include <string.h>
16#include <unistd.h>
17#include <time.h>
18
19#include <sys/stat.h>
20#include <sys/types.h>
21
22#include <ccan/endian/endian.h>
23#include <ccan/list/list.h>
24
25#include <libnvme.h>
26
27#include "cleanup.h"
28#include "cleanup-linux.h"
29#include "private.h"
30#include "private-tree.h"
31#include "util.h"
32#include "compiler-attributes.h"
33
34static void __libnvme_free_ctrl(libnvme_ctrl_t c);
35static int libnvme_subsystem_scan_namespace(struct libnvme_global_ctx *ctx,
36 struct libnvme_subsystem *s, char *name);
37static int libnvme_scan_subsystem(struct libnvme_global_ctx *ctx,
38 const char *name);
39static int libnvme_ctrl_scan_namespace(struct libnvme_global_ctx *ctx,
40 struct libnvme_ctrl *c, char *name);
41static int libnvme_ctrl_scan_path(struct libnvme_global_ctx *ctx,
42 struct libnvme_ctrl *c, char *name);
43
44char *libnvme_hostid_from_hostnqn(const char *hostnqn)
45{
46 const char *uuid;
47
48 uuid = strstr(hostnqn, "uuid:");
49 if (!uuid)
50 return NULL((void*)0);
51
52 return strdup(uuid + strlen("uuid:"));
53}
54
55static void libnvme_filter_subsystem(struct libnvme_global_ctx *ctx,
56 libnvme_subsystem_t s, libnvme_scan_filter_t f, void *f_args)
57{
58 if (f(s, NULL((void*)0), NULL((void*)0), f_args))
59 return;
60
61 libnvme_msg(ctx, LIBNVME_LOG_DEBUG, "filter out subsystem %s\n",__libnvme_msg(ctx, LIBNVME_LOG_DEBUG, ((void*)0), "filter out subsystem %s\n"
, libnvme_subsystem_get_name(s))
62 libnvme_subsystem_get_name(s))__libnvme_msg(ctx, LIBNVME_LOG_DEBUG, ((void*)0), "filter out subsystem %s\n"
, libnvme_subsystem_get_name(s))
;
63 libnvme_free_subsystem(s);
64}
65
66static void libnvme_filter_ns(struct libnvme_global_ctx *ctx, libnvme_ns_t n,
67 libnvme_scan_filter_t f, void *f_args)
68{
69 if (f(NULL((void*)0), NULL((void*)0), n, f_args))
70 return;
71
72 libnvme_msg(ctx, LIBNVME_LOG_DEBUG, "filter out namespace %s\n",__libnvme_msg(ctx, LIBNVME_LOG_DEBUG, ((void*)0), "filter out namespace %s\n"
, libnvme_ns_get_name(n))
73 libnvme_ns_get_name(n))__libnvme_msg(ctx, LIBNVME_LOG_DEBUG, ((void*)0), "filter out namespace %s\n"
, libnvme_ns_get_name(n))
;
74 libnvme_free_ns(n);
75}
76
77static void libnvme_filter_ctrl(struct libnvme_global_ctx *ctx,
78 libnvme_ctrl_t c, libnvme_scan_filter_t f, void *f_args)
79{
80 if (f(NULL((void*)0), c, NULL((void*)0), f_args))
81 return;
82
83 libnvme_msg(ctx, LIBNVME_LOG_DEBUG, "filter out controller %s\n",__libnvme_msg(ctx, LIBNVME_LOG_DEBUG, ((void*)0), "filter out controller %s\n"
, libnvme_ctrl_get_name(c))
84 libnvme_ctrl_get_name(c))__libnvme_msg(ctx, LIBNVME_LOG_DEBUG, ((void*)0), "filter out controller %s\n"
, libnvme_ctrl_get_name(c))
;
85 libnvme_free_ctrl(c);
86}
87
88static void libnvme_filter_tree(struct libnvme_global_ctx *ctx,
89 libnvme_scan_filter_t f, void *f_args)
90{
91 libnvme_host_t h, _h;
92 libnvme_subsystem_t s, _s;
93 libnvme_ns_t n, _n;
94 libnvme_path_t p, _p;
95 libnvme_ctrl_t c, _c;
96
97 if (!f)
98 return;
99
100 libnvme_for_each_host_safe(ctx, h, _h)for (h = libnvme_first_host(ctx), _h = libnvme_next_host(ctx,
h); h != ((void*)0); h = _h, _h = libnvme_next_host(ctx, h))
{
101 libnvme_for_each_subsystem_safe(h, s, _s)for (s = libnvme_first_subsystem(h), _s = libnvme_next_subsystem
(h, s); s != ((void*)0); s = _s, _s = libnvme_next_subsystem(
h, s))
{
102 libnvme_subsystem_for_each_ctrl_safe(s, c, _c)for (c = libnvme_subsystem_first_ctrl(s), _c = libnvme_subsystem_next_ctrl
(s, c); c != ((void*)0); c = _c, _c = libnvme_subsystem_next_ctrl
(s, c))
103 libnvme_filter_ctrl(ctx, c, f, f_args);
104
105 libnvme_subsystem_for_each_ns_safe(s, n, _n)for (n = libnvme_subsystem_first_ns(s), _n = libnvme_subsystem_next_ns
(s, n); n != ((void*)0); n = _n, _n = libnvme_subsystem_next_ns
(s, n))
{
106 libnvme_namespace_for_each_path_safe(n, p, _p)for (p = libnvme_namespace_first_path(n), _p = libnvme_namespace_next_path
(n, p); p != ((void*)0); p = _p, _p = libnvme_namespace_next_path
(n, p))
{
107 libnvme_filter_ctrl(ctx, libnvme_path_get_ctrl(p),
108 f, f_args);
109 }
110 libnvme_filter_ns(ctx, n, f, f_args);
111 }
112
113 libnvme_filter_subsystem(ctx, s, f, f_args);
114 }
115 }
116}
117
118__libnvme_public__attribute__((visibility("default"))) int libnvme_scan_topology(struct libnvme_global_ctx *ctx,
119 libnvme_scan_filter_t f, void *f_args)
120{
121 __cleanup_dirents__attribute__((cleanup(cleanup_dirents))) struct dirents subsys = {}, ctrls = {};
122 int i, ret;
123
124 if (!ctx)
125 return 0;
126
127 ctrls.num = libnvme_scan_ctrls(&ctrls.ents);
128 if (ctrls.num < 0) {
129 libnvme_msg(ctx, LIBNVME_LOG_DEBUG, "failed to scan ctrls: %s\n",__libnvme_msg(ctx, LIBNVME_LOG_DEBUG, ((void*)0), "failed to scan ctrls: %s\n"
, libnvme_strerror(-ctrls.num))
130 libnvme_strerror(-ctrls.num))__libnvme_msg(ctx, LIBNVME_LOG_DEBUG, ((void*)0), "failed to scan ctrls: %s\n"
, libnvme_strerror(-ctrls.num))
;
131 return ctrls.num;
132 }
133
134 for (i = 0; i < ctrls.num; i++) {
135 libnvme_ctrl_t c;
136
137 ret = libnvme_scan_ctrl(ctx, ctrls.ents[i]->d_name, &c);
138 if (ret < 0) {
139 libnvme_msg(ctx, LIBNVME_LOG_DEBUG,__libnvme_msg(ctx, LIBNVME_LOG_DEBUG, ((void*)0), "failed to scan ctrl %s: %s\n"
, ctrls.ents[i]->d_name, libnvme_strerror(-ret))
140 "failed to scan ctrl %s: %s\n",__libnvme_msg(ctx, LIBNVME_LOG_DEBUG, ((void*)0), "failed to scan ctrl %s: %s\n"
, ctrls.ents[i]->d_name, libnvme_strerror(-ret))
141 ctrls.ents[i]->d_name, libnvme_strerror(-ret))__libnvme_msg(ctx, LIBNVME_LOG_DEBUG, ((void*)0), "failed to scan ctrl %s: %s\n"
, ctrls.ents[i]->d_name, libnvme_strerror(-ret))
;
142 continue;
143 }
144 }
145
146 subsys.num = libnvme_scan_subsystems(&subsys.ents);
147 if (subsys.num < 0) {
148 libnvme_msg(ctx, LIBNVME_LOG_DEBUG, "failed to scan subsystems: %s\n",__libnvme_msg(ctx, LIBNVME_LOG_DEBUG, ((void*)0), "failed to scan subsystems: %s\n"
, libnvme_strerror(-subsys.num))
149 libnvme_strerror(-subsys.num))__libnvme_msg(ctx, LIBNVME_LOG_DEBUG, ((void*)0), "failed to scan subsystems: %s\n"
, libnvme_strerror(-subsys.num))
;
150 return subsys.num;
151 }
152
153 for (i = 0; i < subsys.num; i++) {
154 ret = libnvme_scan_subsystem(ctx, subsys.ents[i]->d_name);
155 if (ret < 0) {
156 libnvme_msg(ctx, LIBNVME_LOG_DEBUG,__libnvme_msg(ctx, LIBNVME_LOG_DEBUG, ((void*)0), "failed to scan subsystem %s: %s\n"
, subsys.ents[i]->d_name, libnvme_strerror(-ret))
157 "failed to scan subsystem %s: %s\n",__libnvme_msg(ctx, LIBNVME_LOG_DEBUG, ((void*)0), "failed to scan subsystem %s: %s\n"
, subsys.ents[i]->d_name, libnvme_strerror(-ret))
158 subsys.ents[i]->d_name,__libnvme_msg(ctx, LIBNVME_LOG_DEBUG, ((void*)0), "failed to scan subsystem %s: %s\n"
, subsys.ents[i]->d_name, libnvme_strerror(-ret))
159 libnvme_strerror(-ret))__libnvme_msg(ctx, LIBNVME_LOG_DEBUG, ((void*)0), "failed to scan subsystem %s: %s\n"
, subsys.ents[i]->d_name, libnvme_strerror(-ret))
;
160 }
161 }
162
163 /*
164 * Filter the tree after it has been fully populated and
165 * updated
166 */
167 libnvme_filter_tree(ctx, f, f_args);
168
169 return 0;
170}
171
172__libnvme_public__attribute__((visibility("default"))) int libnvme_read_config(struct libnvme_global_ctx *ctx,
173 const char *config_file)
174{
175 int err;
176
177 if (!ctx || !config_file)
178 return -ENODEV19;
179
180 ctx->config_file = strdup(config_file);
181 if (!ctx->config_file)
182 return -ENOMEM12;
183
184 err = json_read_config(ctx, config_file);
185 /*
186 * The json configuration file is optional,
187 * so ignore errors when opening the file.
188 */
189 if (err < 0 && err != -EPROTO71)
190 return 0;
191
192 return err;
193}
194
195__libnvme_public__attribute__((visibility("default"))) int libnvme_dump_config(struct libnvme_global_ctx *ctx, int fd)
196{
197 return json_update_config(ctx, fd);
198}
199
200__libnvme_public__attribute__((visibility("default"))) int libnvme_dump_tree(struct libnvme_global_ctx *ctx)
201{
202 return json_dump_tree(ctx);
203}
204
205__libnvme_public__attribute__((visibility("default"))) void libnvme_skip_namespaces(struct libnvme_global_ctx *ctx)
206{
207 ctx->create_only = true1;
208}
209
210__libnvme_public__attribute__((visibility("default"))) libnvme_host_t libnvme_first_host(
211 struct libnvme_global_ctx *ctx)
212{
213 return list_top(&ctx->hosts, struct libnvme_host, entry)((struct libnvme_host *)list_top_((&ctx->hosts), (__builtin_offsetof
(struct libnvme_host, entry) + ((typeof(((struct libnvme_host
*)0)->entry) *)0 != (struct list_node *)0))))
;
214}
215
216__libnvme_public__attribute__((visibility("default"))) libnvme_host_t libnvme_next_host(
217 struct libnvme_global_ctx *ctx, libnvme_host_t h)
218{
219 return h ? list_next(&ctx->hosts, h, entry)((typeof(h))list_entry_or_null(((void)"../libnvme/src/nvme/tree.c"
":" "219", &ctx->hosts), (h)->entry.next, (__builtin_offsetof
(typeof(*(h)), entry) + ((typeof((h)->entry) *)0 != (struct
list_node *)0))))
: NULL((void*)0);
220}
221
222__libnvme_public__attribute__((visibility("default"))) struct libnvme_global_ctx *libnvme_host_get_global_ctx(
223 libnvme_host_t h)
224{
225 return h->ctx;
226}
227
228__libnvme_public__attribute__((visibility("default"))) void libnvme_host_set_pdc_enabled(
229 libnvme_host_t h, bool_Bool enabled)
230{
231 h->pdc_enabled_valid = true1;
232 h->pdc_enabled = enabled;
233}
234
235__libnvme_public__attribute__((visibility("default"))) bool_Bool libnvme_host_is_pdc_enabled(
236 libnvme_host_t h, bool_Bool fallback)
237{
238 if (h->pdc_enabled_valid)
239 return h->pdc_enabled;
240 return fallback;
241}
242
243__libnvme_public__attribute__((visibility("default"))) libnvme_subsystem_t libnvme_first_subsystem(libnvme_host_t h)
244{
245 return list_top(&h->subsystems, struct libnvme_subsystem, entry)((struct libnvme_subsystem *)list_top_((&h->subsystems
), (__builtin_offsetof(struct libnvme_subsystem, entry) + ((typeof
(((struct libnvme_subsystem *)0)->entry) *)0 != (struct list_node
*)0))))
;
246}
247
248__libnvme_public__attribute__((visibility("default"))) libnvme_subsystem_t libnvme_next_subsystem(libnvme_host_t h,
249 libnvme_subsystem_t s)
250{
251 return s ? list_next(&h->subsystems, s, entry)((typeof(s))list_entry_or_null(((void)"../libnvme/src/nvme/tree.c"
":" "251", &h->subsystems), (s)->entry.next, (__builtin_offsetof
(typeof(*(s)), entry) + ((typeof((s)->entry) *)0 != (struct
list_node *)0))))
: NULL((void*)0);
252}
253
254__libnvme_public__attribute__((visibility("default"))) void libnvme_refresh_topology(struct libnvme_global_ctx *ctx)
255{
256 struct libnvme_host *h, *_h;
257
258 libnvme_for_each_host_safe(ctx, h, _h)for (h = libnvme_first_host(ctx), _h = libnvme_next_host(ctx,
h); h != ((void*)0); h = _h, _h = libnvme_next_host(ctx, h))
259 __libnvme_free_host(h);
260 libnvme_scan_topology(ctx, NULL((void*)0), NULL((void*)0));
261}
262
263void nvme_root_release_fds(struct libnvme_global_ctx *ctx)
264{
265 struct libnvme_host *h, *_h;
266
267 libnvme_for_each_host_safe(ctx, h, _h)for (h = libnvme_first_host(ctx), _h = libnvme_next_host(ctx,
h); h != ((void*)0); h = _h, _h = libnvme_next_host(ctx, h))
268 libnvme_host_release_fds(h);
269}
270
271__libnvme_public__attribute__((visibility("default"))) libnvme_ctrl_t libnvme_subsystem_first_ctrl(
272 libnvme_subsystem_t s)
273{
274 return list_top(&s->ctrls, struct libnvme_ctrl, entry)((struct libnvme_ctrl *)list_top_((&s->ctrls), (__builtin_offsetof
(struct libnvme_ctrl, entry) + ((typeof(((struct libnvme_ctrl
*)0)->entry) *)0 != (struct list_node *)0))))
;
275}
276
277__libnvme_public__attribute__((visibility("default"))) libnvme_ctrl_t libnvme_subsystem_next_ctrl(
278 libnvme_subsystem_t s, libnvme_ctrl_t c)
279{
280 return c ? list_next(&s->ctrls, c, entry)((typeof(c))list_entry_or_null(((void)"../libnvme/src/nvme/tree.c"
":" "280", &s->ctrls), (c)->entry.next, (__builtin_offsetof
(typeof(*(c)), entry) + ((typeof((c)->entry) *)0 != (struct
list_node *)0))))
: NULL((void*)0);
281}
282
283__libnvme_public__attribute__((visibility("default"))) libnvme_host_t libnvme_subsystem_get_host(
284 libnvme_subsystem_t s)
285{
286 return s->h;
287}
288
289__libnvme_public__attribute__((visibility("default"))) char *libnvme_subsystem_get_iopolicy(libnvme_subsystem_t s)
290{
291 __cleanup_free__attribute__((cleanup(freep))) char *iopolicy = NULL((void*)0);
292
293 iopolicy = libnvme_get_subsys_attr(s, "iopolicy");
294 if (iopolicy) {
295 if (!s->iopolicy || strcmp(iopolicy, s->iopolicy)) {
296 free(s->iopolicy);
297 s->iopolicy = strdup(iopolicy);
298 }
299 }
300
301 return s->iopolicy;
302}
303
304__libnvme_public__attribute__((visibility("default"))) libnvme_ns_t libnvme_subsystem_first_ns(libnvme_subsystem_t s)
305{
306 return list_top(&s->namespaces, struct libnvme_ns, entry)((struct libnvme_ns *)list_top_((&s->namespaces), (__builtin_offsetof
(struct libnvme_ns, entry) + ((typeof(((struct libnvme_ns *)0
)->entry) *)0 != (struct list_node *)0))))
;
307}
308
309__libnvme_public__attribute__((visibility("default"))) libnvme_ns_t libnvme_subsystem_next_ns(libnvme_subsystem_t s,
310 libnvme_ns_t n)
311{
312 return n ? list_next(&s->namespaces, n, entry)((typeof(n))list_entry_or_null(((void)"../libnvme/src/nvme/tree.c"
":" "312", &s->namespaces), (n)->entry.next, (__builtin_offsetof
(typeof(*(n)), entry) + ((typeof((n)->entry) *)0 != (struct
list_node *)0))))
: NULL((void*)0);
313}
314
315__libnvme_public__attribute__((visibility("default"))) libnvme_path_t libnvme_namespace_first_path(libnvme_ns_t ns)
316{
317 return list_top(&ns->head->paths, struct libnvme_path, nentry)((struct libnvme_path *)list_top_((&ns->head->paths
), (__builtin_offsetof(struct libnvme_path, nentry) + ((typeof
(((struct libnvme_path *)0)->nentry) *)0 != (struct list_node
*)0))))
;
318}
319
320__libnvme_public__attribute__((visibility("default"))) libnvme_path_t libnvme_namespace_next_path(libnvme_ns_t ns,
321 libnvme_path_t p)
322{
323 return p ? list_next(&ns->head->paths, p, nentry)((typeof(p))list_entry_or_null(((void)"../libnvme/src/nvme/tree.c"
":" "323", &ns->head->paths), (p)->nentry.next,
(__builtin_offsetof(typeof(*(p)), nentry) + ((typeof((p)->
nentry) *)0 != (struct list_node *)0))))
: NULL((void*)0);
324}
325
326static void __nvme_free_ns(struct libnvme_ns *n)
327{
328 struct libnvme_path *p, *_p;
329
330 list_del_init(&n->entry)list_del_init_(&n->entry, "../libnvme/src/nvme/tree.c"
":" "330")
;
331 libnvme_ns_release_transport_handle(n);
332 free(n->generic_name);
333 free(n->name);
334 free(n->sysfs_dir);
335 libnvme_namespace_for_each_path_safe(n, p, _p)for (p = libnvme_namespace_first_path(n), _p = libnvme_namespace_next_path
(n, p); p != ((void*)0); p = _p, _p = libnvme_namespace_next_path
(n, p))
{
336 list_del_init(&p->nentry)list_del_init_(&p->nentry, "../libnvme/src/nvme/tree.c"
":" "336")
;
337 p->n = NULL((void*)0);
338 }
339 list_head_init(&n->head->paths);
340 free(n->head->sysfs_dir);
341 free(n->head);
342 free(n);
343}
344
345/* Stub for SWIG */
346__libnvme_public__attribute__((visibility("default"))) void libnvme_free_ns(struct libnvme_ns *n)
347{
348 if (!n)
349 return;
350
351 __nvme_free_ns(n);
352}
353
354static void __nvme_free_subsystem(struct libnvme_subsystem *s)
355{
356 struct libnvme_ctrl *c, *_c;
357 struct libnvme_ns *n, *_n;
358
359 list_del_init(&s->entry)list_del_init_(&s->entry, "../libnvme/src/nvme/tree.c"
":" "359")
;
360 libnvme_subsystem_for_each_ctrl_safe(s, c, _c)for (c = libnvme_subsystem_first_ctrl(s), _c = libnvme_subsystem_next_ctrl
(s, c); c != ((void*)0); c = _c, _c = libnvme_subsystem_next_ctrl
(s, c))
361 __libnvme_free_ctrl(c);
362
363 libnvme_subsystem_for_each_ns_safe(s, n, _n)for (n = libnvme_subsystem_first_ns(s), _n = libnvme_subsystem_next_ns
(s, n); n != ((void*)0); n = _n, _n = libnvme_subsystem_next_ns
(s, n))
364 __nvme_free_ns(n);
365
366 free(s->name);
367 free(s->sysfs_dir);
368 free(s->subsysnqn);
369 free(s->model);
370 free(s->serial);
371 free(s->firmware);
372 free(s->subsystype);
373 free(s->iopolicy);
374 free(s);
375}
376
377__libnvme_public__attribute__((visibility("default"))) void libnvme_subsystem_release_fds(struct libnvme_subsystem *s)
378{
379 struct libnvme_ctrl *c, *_c;
380 struct libnvme_ns *n, *_n;
381
382 libnvme_subsystem_for_each_ctrl_safe(s, c, _c)for (c = libnvme_subsystem_first_ctrl(s), _c = libnvme_subsystem_next_ctrl
(s, c); c != ((void*)0); c = _c, _c = libnvme_subsystem_next_ctrl
(s, c))
383 libnvme_ctrl_release_transport_handle(c);
384
385 libnvme_subsystem_for_each_ns_safe(s, n, _n)for (n = libnvme_subsystem_first_ns(s), _n = libnvme_subsystem_next_ns
(s, n); n != ((void*)0); n = _n, _n = libnvme_subsystem_next_ns
(s, n))
386 libnvme_ns_release_transport_handle(n);
387}
388
389/*
390 * Stub for SWIG
391 */
392__libnvme_public__attribute__((visibility("default"))) void libnvme_free_subsystem(libnvme_subsystem_t s)
393{
394 if (!s)
395 return;
396
397 __nvme_free_subsystem(s);
398}
399
400struct libnvme_subsystem *nvme_alloc_subsystem(struct libnvme_host *h,
401 const char *name, const char *subsysnqn)
402{
403 struct libnvme_subsystem *s;
404
405 s = calloc(1, sizeof(*s));
406 if (!s)
407 return NULL((void*)0);
408
409 s->h = h;
410 s->subsysnqn = strdup(subsysnqn);
411 if (name)
412 libnvme_init_subsystem(s, name);
413 list_head_init(&s->ctrls);
414 list_head_init(&s->namespaces);
415 list_node_init(&s->entry);
416 list_add_tail(&h->subsystems, &s->entry)list_add_tail_(&h->subsystems, &s->entry, "../libnvme/src/nvme/tree.c"
":" "416")
;
417 return s;
418}
419
420struct libnvme_subsystem *libnvme_lookup_subsystem(struct libnvme_host *h,
421 const char *name, const char *subsysnqn)
422{
423 struct libnvme_subsystem *s;
424
425 libnvme_for_each_subsystem(h, s)for (s = libnvme_first_subsystem(h); s != ((void*)0); s = libnvme_next_subsystem
(h, s))
{
426 if (subsysnqn && s->subsysnqn &&
427 strcmp(s->subsysnqn, subsysnqn))
428 continue;
429 if (name && s->name &&
430 strcmp(s->name, name))
431 continue;
432 return s;
433 }
434 return nvme_alloc_subsystem(h, name, subsysnqn);
435}
436
437__libnvme_public__attribute__((visibility("default"))) int libnvme_get_subsystem(struct libnvme_global_ctx *ctx,
438 struct libnvme_host *h, const char *name,
439 const char *subsysnqn, struct libnvme_subsystem **subsys)
440{
441 struct libnvme_subsystem *s;
442
443 s = libnvme_lookup_subsystem(h, name, subsysnqn);
444 if (!s)
445 return -ENOMEM12;
446
447 *subsys = s;
448
449 return 0;
450}
451
452void __libnvme_free_host(struct libnvme_host *h)
453{
454 struct libnvme_subsystem *s, *_s;
455
456 list_del_init(&h->entry)list_del_init_(&h->entry, "../libnvme/src/nvme/tree.c"
":" "456")
;
457 libnvme_for_each_subsystem_safe(h, s, _s)for (s = libnvme_first_subsystem(h), _s = libnvme_next_subsystem
(h, s); s != ((void*)0); s = _s, _s = libnvme_next_subsystem(
h, s))
458 __nvme_free_subsystem(s);
459 free(h->hostnqn);
460 free(h->hostid);
461 free(h->dhchap_host_key);
462 libnvme_host_set_hostsymname(h, NULL((void*)0));
463 free(h);
464}
465
466__libnvme_public__attribute__((visibility("default"))) void libnvme_host_release_fds(struct libnvme_host *h)
467{
468 struct libnvme_subsystem *s, *_s;
469
470 libnvme_for_each_subsystem_safe(h, s, _s)for (s = libnvme_first_subsystem(h), _s = libnvme_next_subsystem
(h, s); s != ((void*)0); s = _s, _s = libnvme_next_subsystem(
h, s))
471 libnvme_subsystem_release_fds(s);
472}
473
474/* Stub for SWIG */
475__libnvme_public__attribute__((visibility("default"))) void libnvme_free_host(struct libnvme_host *h)
476{
477 if (!h)
478 return;
479
480 __libnvme_free_host(h);
481}
482
483static int libnvme_create_host(struct libnvme_global_ctx *ctx,
484 const char *hostnqn, const char *hostid,
485 struct libnvme_host **host)
486{
487 struct libnvme_host *h;
488
489 h = calloc(1, sizeof(*h));
490 if (!h)
491 return -ENOMEM12;
492
493 h->hostnqn = strdup(hostnqn);
494 if (hostid)
495 h->hostid = strdup(hostid);
496 else
497 h->hostid = libnvme_hostid_from_hostnqn(hostnqn);
498 list_head_init(&h->subsystems);
499 list_node_init(&h->entry);
500 h->ctx = ctx;
501
502 list_add_tail(&ctx->hosts, &h->entry)list_add_tail_(&ctx->hosts, &h->entry, "../libnvme/src/nvme/tree.c"
":" "502")
;
503
504 *host = h;
505
506 return 0;
507}
508
509struct libnvme_host *libnvme_lookup_host(struct libnvme_global_ctx *ctx,
510 const char *hostnqn, const char *hostid)
511{
512 struct libnvme_host *h;
513
514 if (!hostnqn)
515 return NULL((void*)0);
516
517 libnvme_for_each_host(ctx, h)for (h = libnvme_first_host(ctx); h != ((void*)0); h = libnvme_next_host
(ctx, h))
{
518 if (strcmp(h->hostnqn, hostnqn))
519 continue;
520 if (hostid && (!h->hostid ||
521 strcmp(h->hostid, hostid)))
522 continue;
523 return h;
524 }
525
526 if (libnvme_create_host(ctx, hostnqn, hostid, &h))
527 return NULL((void*)0);
528
529 return h;
530}
531
532static int nvme_subsystem_scan_namespaces(struct libnvme_global_ctx *ctx,
533 libnvme_subsystem_t s)
534{
535 __cleanup_dirents__attribute__((cleanup(cleanup_dirents))) struct dirents namespaces = {};
536 int i, ret;
537
538 if (ctx->create_only) {
539 libnvme_msg(ctx, LIBNVME_LOG_DEBUG,__libnvme_msg(ctx, LIBNVME_LOG_DEBUG, ((void*)0), "skipping namespace scan for subsys %s\n"
, s->subsysnqn)
540 "skipping namespace scan for subsys %s\n",__libnvme_msg(ctx, LIBNVME_LOG_DEBUG, ((void*)0), "skipping namespace scan for subsys %s\n"
, s->subsysnqn)
541 s->subsysnqn)__libnvme_msg(ctx, LIBNVME_LOG_DEBUG, ((void*)0), "skipping namespace scan for subsys %s\n"
, s->subsysnqn)
;
542 return 0;
543 }
544 namespaces.num = libnvme_scan_subsystem_namespaces(s, &namespaces.ents);
545 if (namespaces.num < 0) {
546 libnvme_msg(ctx, LIBNVME_LOG_DEBUG,__libnvme_msg(ctx, LIBNVME_LOG_DEBUG, ((void*)0), "failed to scan namespaces for subsys %s: %s\n"
, s->subsysnqn, libnvme_strerror(-namespaces.num))
547 "failed to scan namespaces for subsys %s: %s\n",__libnvme_msg(ctx, LIBNVME_LOG_DEBUG, ((void*)0), "failed to scan namespaces for subsys %s: %s\n"
, s->subsysnqn, libnvme_strerror(-namespaces.num))
548 s->subsysnqn, libnvme_strerror(-namespaces.num))__libnvme_msg(ctx, LIBNVME_LOG_DEBUG, ((void*)0), "failed to scan namespaces for subsys %s: %s\n"
, s->subsysnqn, libnvme_strerror(-namespaces.num))
;
549 return namespaces.num;
550 }
551
552 for (i = 0; i < namespaces.num; i++) {
553 ret = libnvme_subsystem_scan_namespace(ctx, s,
554 namespaces.ents[i]->d_name);
555 if (ret < 0)
556 libnvme_msg(ctx, LIBNVME_LOG_DEBUG,__libnvme_msg(ctx, LIBNVME_LOG_DEBUG, ((void*)0), "failed to scan namespace %s: %s\n"
, namespaces.ents[i]->d_name, libnvme_strerror(-ret))
557 "failed to scan namespace %s: %s\n",__libnvme_msg(ctx, LIBNVME_LOG_DEBUG, ((void*)0), "failed to scan namespace %s: %s\n"
, namespaces.ents[i]->d_name, libnvme_strerror(-ret))
558 namespaces.ents[i]->d_name,__libnvme_msg(ctx, LIBNVME_LOG_DEBUG, ((void*)0), "failed to scan namespace %s: %s\n"
, namespaces.ents[i]->d_name, libnvme_strerror(-ret))
559 libnvme_strerror(-ret))__libnvme_msg(ctx, LIBNVME_LOG_DEBUG, ((void*)0), "failed to scan namespace %s: %s\n"
, namespaces.ents[i]->d_name, libnvme_strerror(-ret))
;
560 }
561
562 return 0;
563}
564
565static int libnvme_scan_subsystem(struct libnvme_global_ctx *ctx,
566 const char *name)
567{
568 struct libnvme_subsystem *s = NULL((void*)0), *_s;
569 __cleanup_free__attribute__((cleanup(freep))) char *path = NULL((void*)0), *subsysnqn = NULL((void*)0);
570 libnvme_host_t h = NULL((void*)0);
571 int ret;
572
573 libnvme_msg(ctx, LIBNVME_LOG_DEBUG, "scan subsystem %s\n", name)__libnvme_msg(ctx, LIBNVME_LOG_DEBUG, ((void*)0), "scan subsystem %s\n"
, name)
;
574 ret = asprintf(&path, "%s/%s", libnvme_subsys_sysfs_dir(), name);
575 if (ret < 0)
576 return -ENOMEM12;
577
578 subsysnqn = libnvme_get_attr(path, "subsysnqn");
579 if (!subsysnqn)
580 return -ENODEV19;
581 libnvme_for_each_host(ctx, h)for (h = libnvme_first_host(ctx); h != ((void*)0); h = libnvme_next_host
(ctx, h))
{
582 libnvme_for_each_subsystem(h, _s)for (_s = libnvme_first_subsystem(h); _s != ((void*)0); _s = libnvme_next_subsystem
(h, _s))
{
583 /*
584 * We are always called after libnvme_scan_ctrl(),
585 * so any subsystem we're interested at _must_
586 * have a name.
587 */
588 if (!_s->name)
589 continue;
590 if (strcmp(_s->name, name))
591 continue;
592 if (nvme_subsystem_scan_namespaces(ctx, _s))
593 return -EINVAL22;
594 s = _s;
595 }
596 }
597 if (!s) {
598 /*
599 * Subsystem with non-matching controller. odd.
600 * Create a subsystem with the default host
601 * and hope for the best.
602 */
603 libnvme_msg(ctx, LIBNVME_LOG_DEBUG,__libnvme_msg(ctx, LIBNVME_LOG_DEBUG, ((void*)0), "creating detached subsystem '%s'\n"
, name)
604 "creating detached subsystem '%s'\n", name)__libnvme_msg(ctx, LIBNVME_LOG_DEBUG, ((void*)0), "creating detached subsystem '%s'\n"
, name)
;
605 ret = libnvme_get_host(ctx, NULL((void*)0), NULL((void*)0), &h);
606 if (ret)
607 return ret;
608 s = nvme_alloc_subsystem(h, name, subsysnqn);
609 if (!s)
610 return -ENOMEM12;
611 if (nvme_subsystem_scan_namespaces(ctx, s))
612 return -EINVAL22;
613 } else if (strcmp(s->subsysnqn, subsysnqn)) {
614 libnvme_msg(ctx, LIBNVME_LOG_DEBUG, "NQN mismatch for subsystem '%s'\n",__libnvme_msg(ctx, LIBNVME_LOG_DEBUG, ((void*)0), "NQN mismatch for subsystem '%s'\n"
, name)
615 name)__libnvme_msg(ctx, LIBNVME_LOG_DEBUG, ((void*)0), "NQN mismatch for subsystem '%s'\n"
, name)
;
616 return -EINVAL22;
617 }
618
619 return 0;
620}
621
622__libnvme_public__attribute__((visibility("default"))) libnvme_ctrl_t libnvme_path_get_ctrl(libnvme_path_t p)
623{
624 return p->c;
625}
626
627__libnvme_public__attribute__((visibility("default"))) libnvme_ns_t libnvme_path_get_ns(libnvme_path_t p)
628{
629 return p->n;
630}
631
632__libnvme_public__attribute__((visibility("default"))) int libnvme_path_get_queue_depth(libnvme_path_t p)
633{
634 __cleanup_free__attribute__((cleanup(freep))) char *queue_depth = NULL((void*)0);
635
636 queue_depth = libnvme_get_path_attr(p, "queue_depth");
637 if (queue_depth) {
638 sscanf(queue_depth, "%d", &p->queue_depth);
639 }
640
641 return p->queue_depth;
642}
643
644__libnvme_public__attribute__((visibility("default"))) char *libnvme_path_get_ana_state(libnvme_path_t p)
645{
646 __cleanup_free__attribute__((cleanup(freep))) char *ana_state = NULL((void*)0);
647
648 ana_state = libnvme_get_path_attr(p, "ana_state");
649 if (ana_state) {
650 if (!p->ana_state || strcmp(ana_state, p->ana_state)) {
651 free(p->ana_state);
652 p->ana_state = strdup(ana_state);
653 }
654 }
655
656 return p->ana_state;
657}
658
659__libnvme_public__attribute__((visibility("default"))) char *libnvme_path_get_numa_nodes(libnvme_path_t p)
660{
661 __cleanup_free__attribute__((cleanup(freep))) char *numa_nodes = NULL((void*)0);
662
663 numa_nodes = libnvme_get_path_attr(p, "numa_nodes");
664 if (numa_nodes) {
665 if (!p->numa_nodes || strcmp(numa_nodes, p->numa_nodes)) {
666 free(p->numa_nodes);
667 p->numa_nodes = strdup(numa_nodes);
668 }
669 }
670
671 return p->numa_nodes;
672}
673
674__libnvme_public__attribute__((visibility("default"))) long libnvme_path_get_multipath_failover_count(
675 libnvme_path_t p)
676{
677 __cleanup_free__attribute__((cleanup(freep))) char *failover_count = NULL((void*)0);
678
679 failover_count = libnvme_get_path_attr(p,
680 "diag/multipath_failover_count");
681 if (failover_count)
682 sscanf(failover_count, "%ld", &p->multipath_failover_count);
683
684 return p->multipath_failover_count;
685}
686
687__libnvme_public__attribute__((visibility("default"))) long libnvme_path_get_command_retry_count(libnvme_path_t p)
688{
689 __cleanup_free__attribute__((cleanup(freep))) char *retry_count = NULL((void*)0);
690
691 retry_count = libnvme_get_path_attr(p, "diag/command_retry_count");
692 if (retry_count)
693 sscanf(retry_count, "%ld", &p->command_retry_count);
694
695 return p->command_retry_count;
696}
697
698__libnvme_public__attribute__((visibility("default"))) long libnvme_path_get_command_error_count(libnvme_path_t p)
699{
700 __cleanup_free__attribute__((cleanup(freep))) char *error_count = NULL((void*)0);
701
702 error_count = libnvme_get_path_attr(p, "diag/command_error_count");
703 if (error_count)
704 sscanf(error_count, "%ld", &p->command_error_count);
705
706 return p->command_error_count;
707}
708
709static libnvme_stat_t libnvme_path_get_stat(libnvme_path_t p, unsigned int idx)
710{
711 if (idx > 1)
712 return NULL((void*)0);
713
714 return &p->stat[idx];
715}
716
717__libnvme_public__attribute__((visibility("default"))) void libnvme_path_reset_stat(libnvme_path_t p)
718{
719 libnvme_stat_t stat = &p->stat[0];
720
721 memset(stat, 0, 2 * sizeof(struct libnvme_stat));
722}
723
724static libnvme_stat_t libnvme_ns_get_stat(libnvme_ns_t n, unsigned int idx)
725{
726 if (idx > 1)
727 return NULL((void*)0);
728
729 return &n->stat[idx];
730}
731
732__libnvme_public__attribute__((visibility("default"))) void libnvme_ns_reset_stat(libnvme_ns_t n)
733{
734 libnvme_stat_t stat = &n->stat[0];
735
736 memset(stat, 0, 2 * sizeof(struct libnvme_stat));
737}
738
739static int libnvme_update_stat(const char *sysfs_stat_path, libnvme_stat_t stat)
740{
741 int n;
742 struct timespec ts;
743 unsigned long rd_ios, rd_merges, wr_ios, wr_merges;
744 unsigned long dc_ios, dc_merges, fl_ios;
745 unsigned long long rd_sectors, wr_sectors, dc_sectors;
746 unsigned int rd_ticks, wr_ticks, dc_ticks, fl_ticks;
747 unsigned int io_ticks, tot_ticks, inflights;
748
749 memset(stat, 0, sizeof(struct libnvme_stat));
750
751 n = sscanf(sysfs_stat_path,
752 "%lu %lu %llu %u %lu %lu %llu %u %u %u %u %lu %lu %llu %u %lu %u",
753 &rd_ios, &rd_merges, &rd_sectors, &rd_ticks,
754 &wr_ios, &wr_merges, &wr_sectors, &wr_ticks,
755 &inflights, &io_ticks, &tot_ticks,
756 &dc_ios, &dc_merges, &dc_sectors, &dc_ticks,
757 &fl_ios, &fl_ticks);
758
759 if (n < 17)
760 return -EINVAL22;
761
762 /* update read stat */
763 stat->group[READ].ios = rd_ios;
764 stat->group[READ].merges = rd_merges;
765 stat->group[READ].sectors = rd_sectors;
766 stat->group[READ].ticks = rd_ticks;
767
768 /* update write stat */
769 stat->group[WRITE].ios = wr_ios;
770 stat->group[WRITE].merges = wr_merges;
771 stat->group[WRITE].sectors = wr_sectors;
772 stat->group[WRITE].ticks = wr_ticks;
773
774 /* update inflight counters and ticks */
775 stat->inflights = inflights;
776 stat->io_ticks = io_ticks;
777 stat->tot_ticks = tot_ticks;
778
779 /* update discard stat */
780 stat->group[DISCARD].ios = dc_ios;
781 stat->group[DISCARD].merges = dc_merges;
782 stat->group[DISCARD].sectors = dc_sectors;
783 stat->group[DISCARD].ticks = dc_ticks;
784
785 /* update flush stat */
786 stat->group[FLUSH].ios = fl_ios;
787 stat->group[FLUSH].ticks = fl_ticks;
788
789 clock_gettime(CLOCK_MONOTONIC1, &ts);
790 stat->ts_ms = ts.tv_sec * 1000 + (double)ts.tv_nsec / 1e6;
791
792 return 0;
793}
794
795__libnvme_public__attribute__((visibility("default"))) int libnvme_path_update_stat(libnvme_path_t p, bool_Bool diffstat)
796{
797 __cleanup_free__attribute__((cleanup(freep))) char *sysfs_stat_path = NULL((void*)0);
798 libnvme_stat_t stat;
799
800 p->diffstat = diffstat;
801 p->curr_idx ^= 1;
802 stat = libnvme_path_get_stat(p, p->curr_idx);
803 if (!stat)
804 return -EINVAL22;
805
806 sysfs_stat_path = libnvme_get_path_attr(p, "stat");
807 if (!sysfs_stat_path)
808 return -EINVAL22;
809
810 return libnvme_update_stat(sysfs_stat_path, stat);
811}
812
813__libnvme_public__attribute__((visibility("default"))) int libnvme_ns_update_stat(libnvme_ns_t n, bool_Bool diffstat)
814{
815 __cleanup_free__attribute__((cleanup(freep))) char *sysfs_stat_path = NULL((void*)0);
816 libnvme_stat_t stat;
817
818 n->diffstat = diffstat;
819 n->curr_idx ^= 1;
820 stat = libnvme_ns_get_stat(n, n->curr_idx);
821 if (!stat)
822 return -EINVAL22;
823
824 sysfs_stat_path = libnvme_get_ns_attr(n, "stat");
825 if (!sysfs_stat_path)
826 return -EINVAL22;
827
828 return libnvme_update_stat(sysfs_stat_path, stat);
829}
830
831static int libnvme_stat_get_inflights(libnvme_stat_t stat)
832{
833 return stat->inflights;
834}
835
836__libnvme_public__attribute__((visibility("default"))) unsigned int libnvme_path_get_inflights(libnvme_path_t p)
837{
838 libnvme_stat_t curr;
839
840 curr = libnvme_path_get_stat(p, p->curr_idx);
841 if (!curr)
842 return 0;
843
844 return libnvme_stat_get_inflights(curr);
845}
846
847__libnvme_public__attribute__((visibility("default"))) unsigned int libnvme_ns_get_inflights(libnvme_ns_t n)
848{
849 libnvme_stat_t curr;
850
851 curr = libnvme_ns_get_stat(n, n->curr_idx);
852 if (!curr)
853 return 0;
854
855 return libnvme_stat_get_inflights(curr);
856}
857
858static int libnvme_stat_get_io_ticks(libnvme_stat_t curr, libnvme_stat_t prev,
859 bool_Bool diffstat)
860{
861 unsigned int delta = 0;
862
863 if (!diffstat)
864 return curr->io_ticks;
865
866 if (curr->io_ticks > prev->io_ticks)
867 delta = curr->io_ticks - prev->io_ticks;
868
869 return delta;
870}
871
872__libnvme_public__attribute__((visibility("default"))) unsigned int libnvme_path_get_io_ticks(libnvme_path_t p)
873{
874 libnvme_stat_t curr, prev;
875
876 curr = libnvme_path_get_stat(p, p->curr_idx);
877 prev = libnvme_path_get_stat(p, !p->curr_idx);
878
879 if (!curr || !prev)
880 return 0;
881
882 return libnvme_stat_get_io_ticks(curr, prev, p->diffstat);
883}
884
885__libnvme_public__attribute__((visibility("default"))) unsigned int libnvme_ns_get_io_ticks(libnvme_ns_t n)
886{
887 libnvme_stat_t curr, prev;
888
889 curr = libnvme_ns_get_stat(n, n->curr_idx);
890 prev = libnvme_ns_get_stat(n, !n->curr_idx);
891
892 if (!curr || !prev)
893 return 0;
894
895 return libnvme_stat_get_io_ticks(curr, prev, n->diffstat);
896}
897
898static unsigned int libnvme_stat_get_ticks(libnvme_stat_t curr,
899 libnvme_stat_t prev, enum libnvme_stat_group grp, bool_Bool diffstat)
900{
901 unsigned int delta = 0;
902
903 if (!diffstat)
904 return curr->group[grp].ticks;
905
906 if (curr->group[grp].ticks > prev->group[grp].ticks)
907 delta = curr->group[grp].ticks - prev->group[grp].ticks;
908
909 return delta;
910}
911
912static unsigned int __libnvme_path_get_ticks(libnvme_path_t p,
913 enum libnvme_stat_group grp)
914{
915 libnvme_stat_t curr, prev;
916
917 curr = libnvme_path_get_stat(p, p->curr_idx);
918 prev = libnvme_path_get_stat(p, !p->curr_idx);
919
920 if (!curr || !prev)
921 return 0;
922
923 return libnvme_stat_get_ticks(curr, prev, grp, p->diffstat);
924}
925
926__libnvme_public__attribute__((visibility("default"))) unsigned int libnvme_path_get_read_ticks(libnvme_path_t p)
927{
928 return __libnvme_path_get_ticks(p, READ);
929}
930
931__libnvme_public__attribute__((visibility("default"))) unsigned int libnvme_path_get_write_ticks(libnvme_path_t p)
932{
933 return __libnvme_path_get_ticks(p, WRITE);
934}
935
936static unsigned int __libnvme_ns_get_ticks(libnvme_ns_t n,
937 enum libnvme_stat_group grp)
938{
939 libnvme_stat_t curr, prev;
940
941 curr = libnvme_ns_get_stat(n, n->curr_idx);
942 prev = libnvme_ns_get_stat(n, !n->curr_idx);
943
944 if (!curr || !prev)
945 return 0;
946
947 return libnvme_stat_get_ticks(curr, prev, grp, n->diffstat);
948}
949
950__libnvme_public__attribute__((visibility("default"))) unsigned int libnvme_ns_get_read_ticks(libnvme_ns_t n)
951{
952 return __libnvme_ns_get_ticks(n, READ);
953}
954
955__libnvme_public__attribute__((visibility("default"))) unsigned int libnvme_ns_get_write_ticks(libnvme_ns_t n)
956{
957 return __libnvme_ns_get_ticks(n, WRITE);
958}
959
960static double libnvme_stat_get_interval(libnvme_stat_t curr,
961 libnvme_stat_t prev)
962{
963 double delta = 0.0;
964
965 if (prev->ts_ms && curr->ts_ms > prev->ts_ms)
966 delta = curr->ts_ms - prev->ts_ms;
967
968 return delta;
969}
970
971__libnvme_public__attribute__((visibility("default"))) double libnvme_path_get_stat_interval(libnvme_path_t p)
972{
973 libnvme_stat_t curr, prev;
974
975 curr = libnvme_path_get_stat(p, p->curr_idx);
976 prev = libnvme_path_get_stat(p, !p->curr_idx);
977
978 if (!curr || !prev)
979 return 0;
980
981 return libnvme_stat_get_interval(curr, prev);
982}
983
984__libnvme_public__attribute__((visibility("default"))) double libnvme_ns_get_stat_interval(libnvme_ns_t n)
985{
986 libnvme_stat_t curr, prev;
987
988 curr = libnvme_ns_get_stat(n, n->curr_idx);
989 prev = libnvme_ns_get_stat(n, !n->curr_idx);
990
991 if (!curr || !prev)
992 return 0;
993
994 return libnvme_stat_get_interval(curr, prev);
995}
996
997static unsigned long libnvme_stat_get_ios(libnvme_stat_t curr,
998 libnvme_stat_t prev, enum libnvme_stat_group grp, bool_Bool diffstat)
999{
1000 unsigned long ios = 0;
1001
1002 if (!diffstat)
1003 return curr->group[grp].ios;
1004
1005 if (curr->group[grp].ios > prev->group[grp].ios)
1006 ios = curr->group[grp].ios - prev->group[grp].ios;
1007
1008 return ios;
1009}
1010
1011static unsigned long __libnvme_path_get_ios(libnvme_path_t p,
1012 enum libnvme_stat_group grp)
1013{
1014 libnvme_stat_t curr, prev;
1015
1016 curr = libnvme_path_get_stat(p, p->curr_idx);
1017 prev = libnvme_path_get_stat(p, !p->curr_idx);
1018
1019 if (!curr || !prev)
1020 return 0;
1021
1022 return libnvme_stat_get_ios(curr, prev, grp, p->diffstat);
1023}
1024
1025__libnvme_public__attribute__((visibility("default"))) unsigned long libnvme_path_get_read_ios(libnvme_path_t p)
1026{
1027 return __libnvme_path_get_ios(p, READ);
1028}
1029
1030__libnvme_public__attribute__((visibility("default"))) unsigned long libnvme_path_get_write_ios(libnvme_path_t p)
1031{
1032 return __libnvme_path_get_ios(p, WRITE);
1033}
1034
1035static unsigned long __libnvme_ns_get_ios(libnvme_ns_t n,
1036 enum libnvme_stat_group grp)
1037{
1038 libnvme_stat_t curr, prev;
1039
1040 curr = libnvme_ns_get_stat(n, n->curr_idx);
1041 prev = libnvme_ns_get_stat(n, !n->curr_idx);
1042
1043 if (!curr || !prev)
1044 return 0;
1045
1046 return libnvme_stat_get_ios(curr, prev, grp, n->diffstat);
1047}
1048
1049__libnvme_public__attribute__((visibility("default"))) unsigned long libnvme_ns_get_read_ios(libnvme_ns_t n)
1050{
1051 return __libnvme_ns_get_ios(n, READ);
1052}
1053
1054__libnvme_public__attribute__((visibility("default"))) unsigned long libnvme_ns_get_write_ios(libnvme_ns_t n)
1055{
1056 return __libnvme_ns_get_ios(n, WRITE);
1057}
1058
1059static unsigned long long libnvme_stat_get_sectors(libnvme_stat_t curr,
1060 libnvme_stat_t prev, enum libnvme_stat_group grp, bool_Bool diffstat)
1061{
1062 unsigned long long sec = 0;
1063
1064 if (!diffstat)
1065 return curr->group[grp].sectors;
1066
1067 if (curr->group[grp].sectors > prev->group[grp].sectors)
1068 sec = curr->group[grp].sectors - prev->group[grp].sectors;
1069
1070 return sec;
1071}
1072
1073static unsigned long long __libnvme_path_get_sectors(libnvme_path_t p,
1074 enum libnvme_stat_group grp)
1075{
1076 libnvme_stat_t curr, prev;
1077
1078 curr = libnvme_path_get_stat(p, p->curr_idx);
1079 prev = libnvme_path_get_stat(p, !p->curr_idx);
1080
1081 if (!curr || !prev)
1082 return 0;
1083
1084 return libnvme_stat_get_sectors(curr, prev, grp, p->diffstat);
1085}
1086
1087__libnvme_public__attribute__((visibility("default"))) unsigned long long libnvme_path_get_read_sectors(
1088 libnvme_path_t p)
1089{
1090 return __libnvme_path_get_sectors(p, READ);
1091}
1092
1093__libnvme_public__attribute__((visibility("default"))) unsigned long long libnvme_path_get_write_sectors(
1094 libnvme_path_t p)
1095{
1096 return __libnvme_path_get_sectors(p, WRITE);
1097}
1098
1099static unsigned long long __libnvme_ns_get_sectors(libnvme_ns_t n,
1100 enum libnvme_stat_group grp)
1101{
1102 libnvme_stat_t curr, prev;
1103
1104 curr = libnvme_ns_get_stat(n, n->curr_idx);
1105 prev = libnvme_ns_get_stat(n, !n->curr_idx);
1106
1107 if (!curr || !prev)
1108 return 0;
1109
1110 return libnvme_stat_get_sectors(curr, prev, grp, n->diffstat);
1111}
1112
1113__libnvme_public__attribute__((visibility("default"))) unsigned long long libnvme_ns_get_read_sectors(libnvme_ns_t n)
1114{
1115 return __libnvme_ns_get_sectors(n, READ);
1116}
1117
1118__libnvme_public__attribute__((visibility("default"))) unsigned long long libnvme_ns_get_write_sectors(libnvme_ns_t n)
1119{
1120 return __libnvme_ns_get_sectors(n, WRITE);
1121}
1122
1123void nvme_free_path(struct libnvme_path *p)
1124{
1125 if (!p)
1126 return;
1127
1128 list_del_init(&p->entry)list_del_init_(&p->entry, "../libnvme/src/nvme/tree.c"
":" "1128")
;
1129 list_del_init(&p->nentry)list_del_init_(&p->nentry, "../libnvme/src/nvme/tree.c"
":" "1129")
;
1130 free(p->name);
1131 free(p->sysfs_dir);
1132 free(p->ana_state);
1133 free(p->numa_nodes);
1134 free(p);
1135}
1136
1137static int libnvme_ctrl_scan_path(struct libnvme_global_ctx *ctx,
1138 struct libnvme_ctrl *c, char *name)
1139{
1140 struct libnvme_path *p;
1141 __cleanup_free__attribute__((cleanup(freep))) char *path = NULL((void*)0), *grpid = NULL((void*)0), *queue_depth = NULL((void*)0);
1142 int ret;
1143
1144 libnvme_msg(ctx, LIBNVME_LOG_DEBUG, "scan controller %s path %s\n",__libnvme_msg(ctx, LIBNVME_LOG_DEBUG, ((void*)0), "scan controller %s path %s\n"
, c->name, name)
1145 c->name, name)__libnvme_msg(ctx, LIBNVME_LOG_DEBUG, ((void*)0), "scan controller %s path %s\n"
, c->name, name)
;
1146 if (!c->s)
1147 return -ENXIO6;
1148
1149 ret = asprintf(&path, "%s/%s", c->sysfs_dir, name);
1150 if (ret < 0)
1151 return -ENOMEM12;
1152
1153 p = calloc(1, sizeof(*p));
1154 if (!p)
1155 return -ENOMEM12;
1156
1157 p->c = c;
1158 p->name = strdup(name);
1159 p->sysfs_dir = path;
1160 path = NULL((void*)0);
1161 p->ana_state = libnvme_get_path_attr(p, "ana_state");
1162 if (!p->ana_state)
1163 p->ana_state = strdup("optimized");
1164
1165 p->numa_nodes = libnvme_get_path_attr(p, "numa_nodes");
1166 if (!p->numa_nodes)
1167 p->numa_nodes = strdup("-1");
1168
1169 grpid = libnvme_get_path_attr(p, "ana_grpid");
1170 if (grpid) {
1171 sscanf(grpid, "%d", &p->grpid);
1172 }
1173
1174 queue_depth = libnvme_get_path_attr(p, "queue_depth");
1175 if (queue_depth) {
1176 sscanf(queue_depth, "%d", &p->queue_depth);
1177 }
1178
1179 list_node_init(&p->nentry);
1180 list_node_init(&p->entry);
1181 list_add_tail(&c->paths, &p->entry)list_add_tail_(&c->paths, &p->entry, "../libnvme/src/nvme/tree.c"
":" "1181")
;
1182 return 0;
1183}
1184
1185__libnvme_public__attribute__((visibility("default"))) struct libnvme_transport_handle *libnvme_ctrl_get_transport_handle(
1186 libnvme_ctrl_t c)
1187{
1188 if (!c->hdl) {
1189 int err;
1190
1191 err = libnvme_open(c->ctx, c->name, &c->hdl);
1192 if (err)
1193 libnvme_msg(c->ctx, LIBNVME_LOG_ERR,__libnvme_msg(c->ctx, LIBNVME_LOG_ERR, ((void*)0), "Failed to open ctrl %s, errno %d\n"
, c->name, err)
1194 "Failed to open ctrl %s, errno %d\n",__libnvme_msg(c->ctx, LIBNVME_LOG_ERR, ((void*)0), "Failed to open ctrl %s, errno %d\n"
, c->name, err)
1195 c->name, err)__libnvme_msg(c->ctx, LIBNVME_LOG_ERR, ((void*)0), "Failed to open ctrl %s, errno %d\n"
, c->name, err)
;
1196 }
1197 return c->hdl;
1198}
1199
1200__libnvme_public__attribute__((visibility("default"))) void libnvme_ctrl_release_transport_handle(libnvme_ctrl_t c)
1201{
1202 if (!c->hdl)
1203 return;
1204
1205 libnvme_close(c->hdl);
1206 c->hdl = NULL((void*)0);
1207}
1208
1209__libnvme_public__attribute__((visibility("default"))) libnvme_subsystem_t libnvme_ctrl_get_subsystem(
1210 libnvme_ctrl_t c)
1211{
1212 return c->s;
1213}
1214
1215
1216__libnvme_public__attribute__((visibility("default"))) char *libnvme_ctrl_get_src_addr(
1217 libnvme_ctrl_t c, char *src_addr, size_t src_addr_len)
1218{
1219 size_t l;
1220 char *p;
1221
1222 if (!c->address)
1223 return NULL((void*)0);
1224
1225 p = strstr(c->address, "src_addr=");
1226 if (!p)
1227 return NULL((void*)0);
1228
1229 p += strlen("src_addr=");
1230 l = strcspn(p, ",%"); /* % to eliminate IPv6 scope (if present) */
1231 if (l >= src_addr_len) {
1232 libnvme_msg(c->ctx, LIBNVME_LOG_ERR,__libnvme_msg(c->ctx, LIBNVME_LOG_ERR, ((void*)0), "Buffer for src_addr is too small (%zu must be > %zu)\n"
, src_addr_len, l)
1233 "Buffer for src_addr is too small (%zu must be > %zu)\n",__libnvme_msg(c->ctx, LIBNVME_LOG_ERR, ((void*)0), "Buffer for src_addr is too small (%zu must be > %zu)\n"
, src_addr_len, l)
1234 src_addr_len, l)__libnvme_msg(c->ctx, LIBNVME_LOG_ERR, ((void*)0), "Buffer for src_addr is too small (%zu must be > %zu)\n"
, src_addr_len, l)
;
1235 return NULL((void*)0);
1236 }
1237
1238 strncpy(src_addr, p, l);
1239 src_addr[l] = '\0';
1240 return src_addr;
1241}
1242
1243__libnvme_public__attribute__((visibility("default"))) long libnvme_ctrl_get_command_error_count(libnvme_ctrl_t c)
1244{
1245 __cleanup_free__attribute__((cleanup(freep))) char *error_count = NULL((void*)0);
1246
1247 error_count = libnvme_get_ctrl_attr(c, "diag/command_error_count");
1248 if (error_count)
1249 sscanf(error_count, "%ld", &c->command_error_count);
1250
1251 return c->command_error_count;
1252}
1253
1254__libnvme_public__attribute__((visibility("default"))) long libnvme_ctrl_get_reset_count(libnvme_ctrl_t c)
1255{
1256 __cleanup_free__attribute__((cleanup(freep))) char *reset_count = NULL((void*)0);
1257
1258 reset_count = libnvme_get_ctrl_attr(c, "diag/reset_count");
1259 if (reset_count)
1260 sscanf(reset_count, "%ld", &c->reset_count);
1261
1262 return c->reset_count;
1263}
1264
1265__libnvme_public__attribute__((visibility("default"))) long libnvme_ctrl_get_reconnect_count(libnvme_ctrl_t c)
1266{
1267 __cleanup_free__attribute__((cleanup(freep))) char *reconnect_count = NULL((void*)0);
1268
1269 reconnect_count = libnvme_get_ctrl_attr(c, "diag/reconnect_count");
1270 if (reconnect_count)
1271 sscanf(reconnect_count, "%ld", &c->reconnect_count);
1272
1273 return c->reconnect_count;
1274}
1275
1276__libnvme_public__attribute__((visibility("default"))) int libnvme_ctrl_identify(
1277 libnvme_ctrl_t c, struct nvme_id_ctrl *id)
1278{
1279 struct libnvme_transport_handle *hdl =
1280 libnvme_ctrl_get_transport_handle(c);
1281 struct libnvme_passthru_cmd cmd;
1282
1283 nvme_init_identify_ctrl(&cmd, id);
1284 return libnvme_exec_admin_passthru(hdl, &cmd);
1285}
1286
1287__libnvme_public__attribute__((visibility("default"))) libnvme_ns_t libnvme_ctrl_first_ns(libnvme_ctrl_t c)
1288{
1289 return list_top(&c->namespaces, struct libnvme_ns, entry)((struct libnvme_ns *)list_top_((&c->namespaces), (__builtin_offsetof
(struct libnvme_ns, entry) + ((typeof(((struct libnvme_ns *)0
)->entry) *)0 != (struct list_node *)0))))
;
1290}
1291
1292__libnvme_public__attribute__((visibility("default"))) libnvme_ns_t libnvme_ctrl_next_ns(
1293 libnvme_ctrl_t c, libnvme_ns_t n)
1294{
1295 return n ? list_next(&c->namespaces, n, entry)((typeof(n))list_entry_or_null(((void)"../libnvme/src/nvme/tree.c"
":" "1295", &c->namespaces), (n)->entry.next, (__builtin_offsetof
(typeof(*(n)), entry) + ((typeof((n)->entry) *)0 != (struct
list_node *)0))))
: NULL((void*)0);
1296}
1297
1298__libnvme_public__attribute__((visibility("default"))) libnvme_path_t libnvme_ctrl_first_path(libnvme_ctrl_t c)
1299{
1300 return list_top(&c->paths, struct libnvme_path, entry)((struct libnvme_path *)list_top_((&c->paths), (__builtin_offsetof
(struct libnvme_path, entry) + ((typeof(((struct libnvme_path
*)0)->entry) *)0 != (struct list_node *)0))))
;
1301}
1302
1303__libnvme_public__attribute__((visibility("default"))) libnvme_path_t libnvme_ctrl_next_path(libnvme_ctrl_t c,
1304 libnvme_path_t p)
1305{
1306 return p ? list_next(&c->paths, p, entry)((typeof(p))list_entry_or_null(((void)"../libnvme/src/nvme/tree.c"
":" "1306", &c->paths), (p)->entry.next, (__builtin_offsetof
(typeof(*(p)), entry) + ((typeof((p)->entry) *)0 != (struct
list_node *)0))))
: NULL((void*)0);
1307}
1308
1309void nvme_deconfigure_ctrl(libnvme_ctrl_t c)
1310{
1311 libnvme_ctrl_release_transport_handle(c);
1312 FREE_CTRL_ATTR(c->name)do { free(c->name); (c->name) = ((void*)0); } while (0);
1313 FREE_CTRL_ATTR(c->sysfs_dir)do { free(c->sysfs_dir); (c->sysfs_dir) = ((void*)0); }
while (0)
;
1314 FREE_CTRL_ATTR(c->firmware)do { free(c->firmware); (c->firmware) = ((void*)0); } while
(0)
;
1315 FREE_CTRL_ATTR(c->model)do { free(c->model); (c->model) = ((void*)0); } while (
0)
;
1316 FREE_CTRL_ATTR(c->state)do { free(c->state); (c->state) = ((void*)0); } while (
0)
;
1317 FREE_CTRL_ATTR(c->numa_node)do { free(c->numa_node); (c->numa_node) = ((void*)0); }
while (0)
;
1318 FREE_CTRL_ATTR(c->queue_count)do { free(c->queue_count); (c->queue_count) = ((void*)0
); } while (0)
;
1319 FREE_CTRL_ATTR(c->serial)do { free(c->serial); (c->serial) = ((void*)0); } while
(0)
;
1320 FREE_CTRL_ATTR(c->sqsize)do { free(c->sqsize); (c->sqsize) = ((void*)0); } while
(0)
;
1321 FREE_CTRL_ATTR(c->dhchap_host_key)do { free(c->dhchap_host_key); (c->dhchap_host_key) = (
(void*)0); } while (0)
;
1322 FREE_CTRL_ATTR(c->dhchap_ctrl_key)do { free(c->dhchap_ctrl_key); (c->dhchap_ctrl_key) = (
(void*)0); } while (0)
;
1323 FREE_CTRL_ATTR(c->keyring)do { free(c->keyring); (c->keyring) = ((void*)0); } while
(0)
;
1324 FREE_CTRL_ATTR(c->tls_key_identity)do { free(c->tls_key_identity); (c->tls_key_identity) =
((void*)0); } while (0)
;
1325 FREE_CTRL_ATTR(c->tls_key)do { free(c->tls_key); (c->tls_key) = ((void*)0); } while
(0)
;
1326 FREE_CTRL_ATTR(c->address)do { free(c->address); (c->address) = ((void*)0); } while
(0)
;
1327 FREE_CTRL_ATTR(c->dctype)do { free(c->dctype); (c->dctype) = ((void*)0); } while
(0)
;
1328 FREE_CTRL_ATTR(c->cntrltype)do { free(c->cntrltype); (c->cntrltype) = ((void*)0); }
while (0)
;
1329 FREE_CTRL_ATTR(c->cntlid)do { free(c->cntlid); (c->cntlid) = ((void*)0); } while
(0)
;
1330 FREE_CTRL_ATTR(c->phy_slot)do { free(c->phy_slot); (c->phy_slot) = ((void*)0); } while
(0)
;
1331}
1332
1333__libnvme_public__attribute__((visibility("default"))) void libnvme_unlink_ctrl(libnvme_ctrl_t c)
1334{
1335 list_del_init(&c->entry)list_del_init_(&c->entry, "../libnvme/src/nvme/tree.c"
":" "1335")
;
1336 c->s = NULL((void*)0);
1337}
1338
1339static void __libnvme_free_ctrl(libnvme_ctrl_t c)
1340{
1341 struct libnvme_path *p, *_p;
1342 struct libnvme_ns *n, *_n;
1343
1344 libnvme_unlink_ctrl(c);
1345
1346 libnvme_ctrl_for_each_path_safe(c, p, _p)for (p = libnvme_ctrl_first_path(c), _p = libnvme_ctrl_next_path
(c, p); p != ((void*)0); p = _p, _p = libnvme_ctrl_next_path(
c, p))
1347 nvme_free_path(p);
1348
1349 libnvme_ctrl_for_each_ns_safe(c, n, _n)for (n = libnvme_ctrl_first_ns(c), _n = libnvme_ctrl_next_ns(
c, n); n != ((void*)0); n = _n, _n = libnvme_ctrl_next_ns(c, n
))
1350 __nvme_free_ns(n);
1351
1352 nvme_deconfigure_ctrl(c);
1353
1354 FREE_CTRL_ATTR(c->transport)do { free(c->transport); (c->transport) = ((void*)0); }
while (0)
;
1355 FREE_CTRL_ATTR(c->subsysnqn)do { free(c->subsysnqn); (c->subsysnqn) = ((void*)0); }
while (0)
;
1356 FREE_CTRL_ATTR(c->traddr)do { free(c->traddr); (c->traddr) = ((void*)0); } while
(0)
;
1357 FREE_CTRL_ATTR(c->host_traddr)do { free(c->host_traddr); (c->host_traddr) = ((void*)0
); } while (0)
;
1358 FREE_CTRL_ATTR(c->host_iface)do { free(c->host_iface); (c->host_iface) = ((void*)0);
} while (0)
;
1359 FREE_CTRL_ATTR(c->trsvcid)do { free(c->trsvcid); (c->trsvcid) = ((void*)0); } while
(0)
;
1360 free(c);
1361}
1362
1363__libnvme_public__attribute__((visibility("default"))) void libnvme_free_ctrl(libnvme_ctrl_t c)
1364{
1365 if (!c)
1366 return;
1367
1368 __libnvme_free_ctrl(c);
1369}
1370
1371int libnvme_create_ctrl(struct libnvme_global_ctx *ctx,
1372 const struct libnvme_ctrl_params *params, libnvme_ctrl_t *cp)
1373{
1374 struct libnvme_ctrl *c;
1375
1376 if (!params->transport) {
1377 libnvme_msg(ctx, LIBNVME_LOG_ERR, "No transport specified\n")__libnvme_msg(ctx, LIBNVME_LOG_ERR, ((void*)0), "No transport specified\n"
)
;
1378 return -EINVAL22;
1379 }
1380 if (strncmp(params->transport, "loop", 4) &&
1381 strncmp(params->transport, "pcie", 4) &&
1382 strncmp(params->transport, "apple-nvme", 10) && !params->traddr) {
1383 libnvme_msg(ctx, LIBNVME_LOG_ERR,__libnvme_msg(ctx, LIBNVME_LOG_ERR, ((void*)0), "No transport address for '%s'\n"
, params->transport)
1384 "No transport address for '%s'\n", params->transport)__libnvme_msg(ctx, LIBNVME_LOG_ERR, ((void*)0), "No transport address for '%s'\n"
, params->transport)
;
1385 return -EINVAL22;
1386 }
1387 if (!params->subsysnqn) {
1388 libnvme_msg(ctx, LIBNVME_LOG_ERR, "No subsystem NQN specified\n")__libnvme_msg(ctx, LIBNVME_LOG_ERR, ((void*)0), "No subsystem NQN specified\n"
)
;
1389 return -EINVAL22;
1390 }
1391 c = calloc(1, sizeof(*c));
1392 if (!c)
1393 return -ENOMEM12;
1394
1395 c->ctx = ctx;
1396 c->hdl = NULL((void*)0);
1397 libnvme_fabrics_config_copy(&c->cfg, &params->cfg);
1398 list_head_init(&c->namespaces);
1399 list_head_init(&c->paths);
1400 list_node_init(&c->entry);
1401 c->transport = strdup(params->transport);
1402 c->subsysnqn = strdup(params->subsysnqn);
1403 if (params->traddr)
1404 c->traddr = strdup(params->traddr);
1405 if (params->host_traddr) {
1406 if (traddr_is_hostname(ctx, params->transport,
1407 params->host_traddr))
1408 hostname2traddr(ctx, params->host_traddr,
1409 &c->host_traddr);
1410 if (!c->host_traddr)
1411 c->host_traddr = strdup(params->host_traddr);
1412 }
1413 if (params->host_iface)
1414 c->host_iface = strdup(params->host_iface);
1415 if (params->trsvcid)
1416 c->trsvcid = strdup(params->trsvcid);
1417
1418 *cp = c;
1419 return 0;
1420}
1421
1422libnvme_ctrl_t libnvme_lookup_ctrl(libnvme_subsystem_t s,
1423 const struct libnvme_ctrl_params *in,
1424 libnvme_ctrl_t p)
1425{
1426 struct libnvme_global_ctx *ctx;
1427 struct libnvme_ctrl_params search;
1428 struct libnvme_ctrl *c;
1429 int ret;
1430
1431 if (!s || !in->transport)
1432 return NULL((void*)0);
1433
1434 /*
1435 * Clear subsysnqn for the initial search; discovery subsystems
1436 * may report a different NQN than the one used to connect.
1437 */
1438 search = *in;
1439 libnvme_fabrics_config_copy(&search.cfg, &in->cfg);
1440 search.subsysnqn = NULL((void*)0);
1441 c = libnvme_ctrl_find(s, &search, p);
1442 if (c)
1443 return c;
1444
1445 ctx = s->h ? s->h->ctx : NULL((void*)0);
1446 search.subsysnqn = s->subsysnqn;
1447 libnvmf_default_config(&search.cfg);
1448 ret = libnvme_create_ctrl(ctx, &search, &c);
1449 if (ret)
1450 return NULL((void*)0);
1451
1452 c->s = s;
1453 list_add_tail(&s->ctrls, &c->entry)list_add_tail_(&s->ctrls, &c->entry, "../libnvme/src/nvme/tree.c"
":" "1453")
;
1454
1455 return c;
1456}
1457
1458int libnvme_ctrl_scan_paths(struct libnvme_global_ctx *ctx,
1459 struct libnvme_ctrl *c)
1460{
1461 __cleanup_dirents__attribute__((cleanup(cleanup_dirents))) struct dirents paths = {};
1462 int err, i;
1463
1464 if (ctx->create_only) {
1465 libnvme_msg(ctx, LIBNVME_LOG_DEBUG,__libnvme_msg(ctx, LIBNVME_LOG_DEBUG, ((void*)0), "skipping path scan for ctrl %s\n"
, c->name)
1466 "skipping path scan for ctrl %s\n", c->name)__libnvme_msg(ctx, LIBNVME_LOG_DEBUG, ((void*)0), "skipping path scan for ctrl %s\n"
, c->name)
;
1467 return 0;
1468 }
1469 paths.num = libnvme_scan_ctrl_namespace_paths(c, &paths.ents);
1470 if (paths.num < 0)
1471 return paths.num;
1472
1473 for (i = 0; i < paths.num; i++) {
1474 err = libnvme_ctrl_scan_path(ctx, c, paths.ents[i]->d_name);
1475 if (err)
1476 return err;
1477 }
1478
1479 return 0;
1480}
1481
1482int libnvme_ctrl_scan_namespaces(struct libnvme_global_ctx *ctx,
1483 struct libnvme_ctrl *c)
1484{
1485 __cleanup_dirents__attribute__((cleanup(cleanup_dirents))) struct dirents namespaces = {};
1486 int err, i;
1487
1488 if (ctx->create_only) {
8
Access to field 'create_only' results in a dereference of a null pointer (loaded from variable 'ctx')
1489 libnvme_msg(ctx, LIBNVME_LOG_DEBUG,__libnvme_msg(ctx, LIBNVME_LOG_DEBUG, ((void*)0), "skipping namespace scan for ctrl %s\n"
, c->name)
1490 "skipping namespace scan for ctrl %s\n", c->name)__libnvme_msg(ctx, LIBNVME_LOG_DEBUG, ((void*)0), "skipping namespace scan for ctrl %s\n"
, c->name)
;
1491 return 0;
1492 }
1493 namespaces.num = libnvme_scan_ctrl_namespaces(c, &namespaces.ents);
1494 for (i = 0; i < namespaces.num; i++) {
1495 err = libnvme_ctrl_scan_namespace(ctx, c,
1496 namespaces.ents[i]->d_name);
1497 if (err)
1498 return err;
1499 }
1500
1501 return 0;
1502}
1503
1504/*
1505 * Fabrics = any transport that is not a known local one (pcie/apple-nvme).
1506 * Testing by exclusion means a newly added transport defaults to fabrics.
1507 */
1508__libnvme_public__attribute__((visibility("default"))) bool_Bool libnvme_ctrl_is_transport_fabric(libnvme_ctrl_t c)
1509{
1510 return c && c->transport &&
1511 strcmp(c->transport, "pcie") &&
1512 strcmp(c->transport, "apple-nvme");
1513}
1514
1515int libnvme_ctrl_alloc(struct libnvme_global_ctx *ctx, libnvme_subsystem_t s,
1516 const char *path, const char *name, libnvme_ctrl_t *cp)
1517{
1518 __cleanup_free__attribute__((cleanup(freep))) char *addr = NULL((void*)0), *transport = NULL((void*)0);
1519 __cleanup_free__attribute__((cleanup(freep))) char *host_traddr = NULL((void*)0), *host_iface = NULL((void*)0);
1520 __cleanup_free__attribute__((cleanup(freep))) char *traddr = NULL((void*)0), *trsvcid = NULL((void*)0);
1521 libnvme_ctrl_t c, p;
1522 int ret;
1523
1524 ret = libnvme_get_ctrl_transport(path, name, &transport, &traddr, &addr,
1525 &trsvcid, &host_traddr, &host_iface);
1526 if (ret)
1527 return ret;
1528
1529 p = NULL((void*)0);
1530 do {
1531 struct libnvme_ctrl_params params = {
1532 .transport = transport,
1533 .traddr = traddr,
1534 .host_traddr = host_traddr,
1535 .host_iface = host_iface,
1536 .trsvcid = trsvcid,
1537 };
1538 c = libnvme_lookup_ctrl(s, &params, p);
1539 if (c) {
1540 if (!c->name)
1541 break;
1542 if (!strcmp(c->name, name)) {
1543 libnvme_msg(ctx, LIBNVME_LOG_DEBUG,__libnvme_msg(ctx, LIBNVME_LOG_DEBUG, ((void*)0), "found existing ctrl %s\n"
, c->name)
1544 "found existing ctrl %s\n", c->name)__libnvme_msg(ctx, LIBNVME_LOG_DEBUG, ((void*)0), "found existing ctrl %s\n"
, c->name)
;
1545 break;
1546 }
1547 libnvme_msg(ctx, LIBNVME_LOG_DEBUG,__libnvme_msg(ctx, LIBNVME_LOG_DEBUG, ((void*)0), "skipping ctrl %s\n"
, c->name)
1548 "skipping ctrl %s\n", c->name)__libnvme_msg(ctx, LIBNVME_LOG_DEBUG, ((void*)0), "skipping ctrl %s\n"
, c->name)
;
1549 p = c;
1550 }
1551 } while (c);
1552 if (!c)
1553 c = p;
1554 if (!c && !p) {
1555 libnvme_msg(ctx, LIBNVME_LOG_ERR, "failed to lookup ctrl\n")__libnvme_msg(ctx, LIBNVME_LOG_ERR, ((void*)0), "failed to lookup ctrl\n"
)
;
1556 return -ENODEV19;
1557 }
1558 FREE_CTRL_ATTR(c->address)do { free(c->address); (c->address) = ((void*)0); } while
(0)
;
1559 c->address = xstrdup(addr);
1560 if (s->subsystype && !strcmp(s->subsystype, "discovery"))
1561 c->discovery_ctrl = true1;
1562 ret = libnvme_reconfigure_ctrl(ctx, c, path, name);
1563 if (ret)
1564 return ret;
1565
1566 *cp = c;
1567 return 0;
1568}
1569
1570__libnvme_public__attribute__((visibility("default"))) void libnvme_rescan_ctrl(struct libnvme_ctrl *c)
1571{
1572 struct libnvme_global_ctx *ctx = c->s && c->s->h ? c->s->h->ctx : NULL((void*)0);
1
Assuming field 's' is non-null
2
Assuming field 'h' is null
3
'?' condition is false
4
'ctx' initialized to a null pointer value
1573 if (!c->s
4.1
Field 's' is non-null
)
5
Taking false branch
1574 return;
1575 libnvme_ctrl_scan_namespaces(ctx, c);
6
Passing null pointer value via 1st parameter 'ctx'
7
Calling 'libnvme_ctrl_scan_namespaces'
1576 libnvme_ctrl_scan_paths(ctx, c);
1577 nvme_subsystem_scan_namespaces(ctx, c->s);
1578}
1579
1580static int libnvme_bytes_to_lba(libnvme_ns_t n, off_t offset, size_t count,
1581 __u64 *lba, __u16 *nlb)
1582{
1583 int bs;
1584
1585 bs = libnvme_ns_get_lba_size(n);
1586 if (!count || offset & (bs - 1) || count & (bs - 1))
1587 return -EINVAL22;
1588
1589 *lba = offset >> n->lba_shift;
1590 *nlb = (count >> n->lba_shift) - 1;
1591
1592 return 0;
1593}
1594
1595int libnvme_ns_get_transport_handle(libnvme_ns_t n,
1596 struct libnvme_transport_handle **hdl)
1597{
1598 int err;
1599
1600 if (n->hdl)
1601 goto valid;
1602
1603 err = libnvme_open(n->ctx, n->name, &n->hdl);
1604 if (err) {
1605 libnvme_msg(n->ctx, LIBNVME_LOG_ERR, "Failed to open ns %s, error %d\n",__libnvme_msg(n->ctx, LIBNVME_LOG_ERR, ((void*)0), "Failed to open ns %s, error %d\n"
, n->name, err)
1606 n->name, err)__libnvme_msg(n->ctx, LIBNVME_LOG_ERR, ((void*)0), "Failed to open ns %s, error %d\n"
, n->name, err)
;
1607 return err;
1608 }
1609
1610valid:
1611 *hdl = n->hdl;
1612 return 0;
1613}
1614
1615void libnvme_ns_release_transport_handle(libnvme_ns_t n)
1616{
1617 if (!n->hdl)
1618 return;
1619
1620 libnvme_close(n->hdl);
1621 n->hdl = NULL((void*)0);
1622}
1623
1624__libnvme_public__attribute__((visibility("default"))) libnvme_subsystem_t libnvme_ns_get_subsystem(libnvme_ns_t n)
1625{
1626 return n->s;
1627}
1628
1629__libnvme_public__attribute__((visibility("default"))) libnvme_ctrl_t libnvme_ns_get_ctrl(libnvme_ns_t n)
1630{
1631 return n->c;
1632}
1633
1634const char *libnvme_ns_head_get_sysfs_dir(libnvme_ns_head_t head)
1635{
1636 return head->sysfs_dir;
1637}
1638
1639__libnvme_public__attribute__((visibility("default"))) const char *libnvme_ns_get_model(libnvme_ns_t n)
1640{
1641 return n->c ? n->c->model : n->s->model;
1642}
1643
1644__libnvme_public__attribute__((visibility("default"))) const char *libnvme_ns_get_serial(libnvme_ns_t n)
1645{
1646 return n->c ? n->c->serial : n->s->serial;
1647}
1648
1649__libnvme_public__attribute__((visibility("default"))) const char *libnvme_ns_get_firmware(libnvme_ns_t n)
1650{
1651 return n->c ? n->c->firmware : n->s->firmware;
1652}
1653
1654__libnvme_public__attribute__((visibility("default"))) void libnvme_ns_copy_uuid(libnvme_ns_t n,
1655 unsigned char out[NVME_UUID_LEN16])
1656{
1657 memcpy(out, n->uuid, NVME_UUID_LEN16);
1658}
1659
1660__libnvme_public__attribute__((visibility("default"))) long libnvme_ns_get_command_retry_count(libnvme_ns_t n)
1661{
1662 __cleanup_free__attribute__((cleanup(freep))) char *retry_count = NULL((void*)0);
1663
1664 retry_count = libnvme_get_ns_attr(n, "diag/command_retry_count");
1665 if (retry_count)
1666 sscanf(retry_count, "%ld", &n->command_retry_count);
1667
1668 return n->command_retry_count;
1669}
1670
1671__libnvme_public__attribute__((visibility("default"))) long libnvme_ns_get_command_error_count(libnvme_ns_t n)
1672{
1673 __cleanup_free__attribute__((cleanup(freep))) char *error_count = NULL((void*)0);
1674
1675 error_count = libnvme_get_ns_attr(n, "diag/command_error_count");
1676 if (error_count)
1677 sscanf(error_count, "%ld", &n->command_error_count);
1678
1679 return n->command_error_count;
1680}
1681
1682__libnvme_public__attribute__((visibility("default"))) long libnvme_ns_get_io_requeue_no_usable_path_count(
1683 libnvme_ns_t n)
1684{
1685 __cleanup_free__attribute__((cleanup(freep))) char *requeue_count = NULL((void*)0);
1686
1687 requeue_count = libnvme_get_ns_attr(n,
1688 "diag/io_requeue_no_usable_path_count");
1689 if (requeue_count)
1690 sscanf(requeue_count, "%ld",
1691 &n->io_requeue_no_usable_path_count);
1692
1693 return n->io_requeue_no_usable_path_count;
1694}
1695
1696__libnvme_public__attribute__((visibility("default"))) long libnvme_ns_get_io_fail_no_available_path_count(
1697 libnvme_ns_t n)
1698{
1699 __cleanup_free__attribute__((cleanup(freep))) char *fail_count = NULL((void*)0);
1700
1701 fail_count = libnvme_get_ns_attr(n,
1702 "diag/io_fail_no_available_path_count");
1703 if (fail_count)
1704 sscanf(fail_count, "%ld", &n->io_fail_no_available_path_count);
1705
1706 return n->io_fail_no_available_path_count;
1707}
1708
1709__libnvme_public__attribute__((visibility("default"))) int libnvme_ns_identify(libnvme_ns_t n, struct nvme_id_ns *ns)
1710{
1711 struct libnvme_transport_handle *hdl;
1712 struct libnvme_passthru_cmd cmd;
1713 int err;
1714
1715 err = libnvme_ns_get_transport_handle(n, &hdl);
1716 if (err)
1717 return err;
1718
1719 nvme_init_identify_ns(&cmd, libnvme_ns_get_nsid(n), ns);
1720 return libnvme_exec_admin_passthru(hdl, &cmd);
1721}
1722
1723int libnvme_ns_identify_descs(libnvme_ns_t n, struct nvme_ns_id_desc *descs)
1724{
1725 struct libnvme_transport_handle *hdl;
1726 struct libnvme_passthru_cmd cmd;
1727 int err;
1728
1729 err = libnvme_ns_get_transport_handle(n, &hdl);
1730 if (err)
1731 return err;
1732
1733 nvme_init_identify_ns_descs_list(&cmd, libnvme_ns_get_nsid(n), descs);
1734 return libnvme_exec_admin_passthru(hdl, &cmd);
1735}
1736
1737__libnvme_public__attribute__((visibility("default"))) int libnvme_ns_verify(
1738 libnvme_ns_t n, off_t offset, size_t count)
1739{
1740 struct libnvme_transport_handle *hdl;
1741 struct libnvme_passthru_cmd cmd;
1742 __u64 slba;
1743 __u16 nlb;
1744 int err;
1745
1746 err = libnvme_ns_get_transport_handle(n, &hdl);
1747 if (err)
1748 return err;
1749
1750 if (libnvme_bytes_to_lba(n, offset, count, &slba, &nlb))
1751 return -1;
1752
1753 nvme_init_verify(&cmd, libnvme_ns_get_nsid(n), slba, nlb,
1754 0, 0, NULL((void*)0), 0, NULL((void*)0), 0);
1755
1756 return libnvme_submit_io_passthru(hdl, &cmd);
1757}
1758
1759__libnvme_public__attribute__((visibility("default"))) int libnvme_ns_write_uncorrectable(
1760 libnvme_ns_t n, off_t offset, size_t count)
1761{
1762 struct libnvme_transport_handle *hdl;
1763 struct libnvme_passthru_cmd cmd;
1764 __u64 slba;
1765 __u16 nlb;
1766 int err;
1767
1768 err = libnvme_ns_get_transport_handle(n, &hdl);
1769 if (err)
1770 return err;
1771
1772 if (libnvme_bytes_to_lba(n, offset, count, &slba, &nlb))
1773 return -1;
1774
1775 nvme_init_write_uncorrectable(&cmd, libnvme_ns_get_nsid(n), slba, nlb,
1776 0, 0);
1777
1778 return libnvme_submit_io_passthru(hdl, &cmd);
1779}
1780
1781__libnvme_public__attribute__((visibility("default"))) int libnvme_ns_write_zeros(
1782 libnvme_ns_t n, off_t offset, size_t count)
1783{
1784 struct libnvme_transport_handle *hdl;
1785 struct libnvme_passthru_cmd cmd;
1786 __u64 slba;
1787 __u16 nlb;
1788 int err;
1789
1790 err = libnvme_ns_get_transport_handle(n, &hdl);
1791 if (err)
1792 return err;
1793
1794 if (libnvme_bytes_to_lba(n, offset, count, &slba, &nlb))
1795 return -1;
1796
1797 nvme_init_write_zeros(&cmd, libnvme_ns_get_nsid(n),
1798 slba, nlb, 0, 0, 0, 0);
1799
1800 return libnvme_submit_io_passthru(hdl, &cmd);
1801}
1802
1803__libnvme_public__attribute__((visibility("default"))) int libnvme_ns_write(libnvme_ns_t n, void *buf, off_t offset,
1804 size_t count)
1805{
1806 struct libnvme_transport_handle *hdl;
1807 struct libnvme_passthru_cmd cmd;
1808 __u64 slba;
1809 __u16 nlb;
1810 int err;
1811
1812 err = libnvme_ns_get_transport_handle(n, &hdl);
1813 if (err)
1814 return err;
1815
1816 if (libnvme_bytes_to_lba(n, offset, count, &slba, &nlb))
1817 return -1;
1818
1819 nvme_init_write(&cmd, libnvme_ns_get_nsid(n), slba, nlb,
1820 0, 0, 0, 0, buf, count, NULL((void*)0), 0);
1821
1822 return libnvme_submit_io_passthru(hdl, &cmd);
1823}
1824
1825__libnvme_public__attribute__((visibility("default"))) int libnvme_ns_read(libnvme_ns_t n, void *buf, off_t offset,
1826 size_t count)
1827{
1828 struct libnvme_transport_handle *hdl;
1829 struct libnvme_passthru_cmd cmd;
1830 __u64 slba;
1831 __u16 nlb;
1832 int err;
1833
1834 err = libnvme_ns_get_transport_handle(n, &hdl);
1835 if (err)
1836 return err;
1837
1838 if (libnvme_bytes_to_lba(n, offset, count, &slba, &nlb))
1839 return -1;
1840
1841 nvme_init_read(&cmd, libnvme_ns_get_nsid(n), slba, nlb,
1842 0, 0, 0, buf, count, NULL((void*)0), 0);
1843
1844 return libnvme_submit_io_passthru(hdl, &cmd);
1845}
1846
1847__libnvme_public__attribute__((visibility("default"))) int libnvme_ns_compare(libnvme_ns_t n, void *buf, off_t offset,
1848 size_t count)
1849{
1850 struct libnvme_transport_handle *hdl;
1851 struct libnvme_passthru_cmd cmd;
1852 __u64 slba;
1853 __u16 nlb;
1854 int err;
1855
1856 err = libnvme_ns_get_transport_handle(n, &hdl);
1857 if (err)
1858 return err;
1859
1860 if (libnvme_bytes_to_lba(n, offset, count, &slba, &nlb))
1861 return -1;
1862
1863 nvme_init_compare(&cmd, libnvme_ns_get_nsid(n), slba, nlb,
1864 0, 0, buf, count, NULL((void*)0), 0);
1865
1866 return libnvme_submit_io_passthru(hdl, &cmd);
1867}
1868
1869__libnvme_public__attribute__((visibility("default"))) int libnvme_ns_flush(libnvme_ns_t n)
1870{
1871 struct libnvme_transport_handle *hdl;
1872 struct libnvme_passthru_cmd cmd;
1873 int err;
1874
1875 err = libnvme_ns_get_transport_handle(n, &hdl);
1876 if (err)
1877 return err;
1878
1879 nvme_init_flush(&cmd, libnvme_ns_get_nsid(n));
1880 return libnvme_submit_io_passthru(hdl, &cmd);
1881}
1882
1883__libnvme_public__attribute__((visibility("default"))) int libnvme_scan_namespace(struct libnvme_global_ctx *ctx,
1884 const char *name, libnvme_ns_t *ns)
1885{
1886 return __libnvme_scan_namespace(ctx, libnvme_ns_sysfs_dir(), name, ns);
1887}
1888
1889
1890static void libnvme_ns_head_scan_path(libnvme_subsystem_t s,
1891 libnvme_ns_t n, char *name)
1892{
1893 libnvme_ctrl_t c;
1894 libnvme_path_t p;
1895
1896 libnvme_subsystem_for_each_ctrl(s, c)for (c = libnvme_subsystem_first_ctrl(s); c != ((void*)0); c =
libnvme_subsystem_next_ctrl(s, c))
{
1897 libnvme_ctrl_for_each_path(c, p)for (p = libnvme_ctrl_first_path(c); p != ((void*)0); p = libnvme_ctrl_next_path
(c, p))
{
1898 if (!strcmp(libnvme_path_get_name(p), name)) {
1899 list_add_tail(&n->head->paths, &p->nentry)list_add_tail_(&n->head->paths, &p->nentry, "../libnvme/src/nvme/tree.c"
":" "1899")
;
1900 p->n = n;
1901 return;
1902 }
1903 }
1904 }
1905}
1906
1907static void libnvme_subsystem_set_ns_path(libnvme_subsystem_t s, libnvme_ns_t n)
1908{
1909 struct libnvme_ns_head *head = n->head;
1910
1911 if (libnvme_ns_head_get_sysfs_dir(head)) {
1912 __cleanup_dirents__attribute__((cleanup(cleanup_dirents))) struct dirents paths = {};
1913 int i;
1914
1915 /*
1916 * When multipath is configured on kernel version >= 6.15,
1917 * we use multipath sysfs link to get each path of a namespace.
1918 */
1919 paths.num = libnvme_scan_ns_head_paths(head, &paths.ents);
1920
1921 for (i = 0; i < paths.num; i++)
1922 libnvme_ns_head_scan_path(s, n, paths.ents[i]->d_name);
1923 } else {
1924 libnvme_ctrl_t c;
1925 libnvme_path_t p;
1926 int ns_ctrl, ns_nsid, ret;
1927
1928 /*
1929 * If multipath is not configured or we're running on kernel
1930 * version < 6.15, fallback to the old way.
1931 */
1932 ret = sscanf(libnvme_ns_get_name(n), "nvme%dn%d",
1933 &ns_ctrl, &ns_nsid);
1934 if (ret != 2)
1935 return;
1936
1937 libnvme_subsystem_for_each_ctrl(s, c)for (c = libnvme_subsystem_first_ctrl(s); c != ((void*)0); c =
libnvme_subsystem_next_ctrl(s, c))
{
1938 libnvme_ctrl_for_each_path(c, p)for (p = libnvme_ctrl_first_path(c); p != ((void*)0); p = libnvme_ctrl_next_path
(c, p))
{
1939 int p_subsys, p_ctrl, p_nsid;
1940
1941 ret = sscanf(libnvme_path_get_name(p),
1942 "nvme%dc%dn%d",
1943 &p_subsys, &p_ctrl, &p_nsid);
1944 if (ret != 3)
1945 continue;
1946 if (ns_ctrl == p_subsys && ns_nsid == p_nsid) {
1947 list_add_tail(&head->paths, &p->nentry)list_add_tail_(&head->paths, &p->nentry, "../libnvme/src/nvme/tree.c"
":" "1947")
;
1948 p->n = n;
1949 }
1950 }
1951 }
1952 }
1953}
1954
1955static int libnvme_ctrl_scan_namespace(struct libnvme_global_ctx *ctx,
1956 struct libnvme_ctrl *c, char *name)
1957{
1958 struct libnvme_ns *n, *_n, *__n;
1959 int ret;
1960
1961 libnvme_msg(ctx, LIBNVME_LOG_DEBUG, "scan controller %s namespace %s\n",__libnvme_msg(ctx, LIBNVME_LOG_DEBUG, ((void*)0), "scan controller %s namespace %s\n"
, c->name, name)
1962 c->name, name)__libnvme_msg(ctx, LIBNVME_LOG_DEBUG, ((void*)0), "scan controller %s namespace %s\n"
, c->name, name)
;
1963 if (!c->s) {
1964 libnvme_msg(ctx, LIBNVME_LOG_DEBUG, "no subsystem for %s\n", name)__libnvme_msg(ctx, LIBNVME_LOG_DEBUG, ((void*)0), "no subsystem for %s\n"
, name)
;
1965 return -EINVAL22;
1966 }
1967 ret = __libnvme_scan_namespace(ctx, c->sysfs_dir, name, &n);
1968 if (ret) {
1969 libnvme_msg(ctx, LIBNVME_LOG_DEBUG, "failed to scan namespace %s\n", name)__libnvme_msg(ctx, LIBNVME_LOG_DEBUG, ((void*)0), "failed to scan namespace %s\n"
, name)
;
1970 return ret;
1971 }
1972 libnvme_ctrl_for_each_ns_safe(c, _n, __n)for (_n = libnvme_ctrl_first_ns(c), __n = libnvme_ctrl_next_ns
(c, _n); _n != ((void*)0); _n = __n, __n = libnvme_ctrl_next_ns
(c, _n))
{
1973 if (strcmp(n->name, _n->name))
1974 continue;
1975 __nvme_free_ns(_n);
1976 }
1977 n->s = c->s;
1978 n->c = c;
1979 list_add_tail(&c->namespaces, &n->entry)list_add_tail_(&c->namespaces, &n->entry, "../libnvme/src/nvme/tree.c"
":" "1979")
;
1980 libnvme_subsystem_set_ns_path(c->s, n);
1981
1982 return 0;
1983}
1984
1985static int libnvme_subsystem_scan_namespace(struct libnvme_global_ctx *ctx,
1986 libnvme_subsystem_t s, char *name)
1987{
1988 struct libnvme_ns *n, *_n, *__n;
1989 int ret;
1990
1991 libnvme_msg(ctx, LIBNVME_LOG_DEBUG, "scan subsystem %s namespace %s\n",__libnvme_msg(ctx, LIBNVME_LOG_DEBUG, ((void*)0), "scan subsystem %s namespace %s\n"
, s->name, name)
1992 s->name, name)__libnvme_msg(ctx, LIBNVME_LOG_DEBUG, ((void*)0), "scan subsystem %s namespace %s\n"
, s->name, name)
;
1993 ret = __libnvme_scan_namespace(ctx, s->sysfs_dir, name, &n);
1994 if (ret) {
1995 libnvme_msg(ctx, LIBNVME_LOG_DEBUG, "failed to scan namespace %s\n", name)__libnvme_msg(ctx, LIBNVME_LOG_DEBUG, ((void*)0), "failed to scan namespace %s\n"
, name)
;
1996 return ret;
1997 }
1998 libnvme_subsystem_for_each_ns_safe(s, _n, __n)for (_n = libnvme_subsystem_first_ns(s), __n = libnvme_subsystem_next_ns
(s, _n); _n != ((void*)0); _n = __n, __n = libnvme_subsystem_next_ns
(s, _n))
{
1999 if (strcmp(n->name, _n->name))
2000 continue;
2001 __nvme_free_ns(_n);
2002 }
2003 n->s = s;
2004 list_add_tail(&s->namespaces, &n->entry)list_add_tail_(&s->namespaces, &n->entry, "../libnvme/src/nvme/tree.c"
":" "2004")
;
2005 libnvme_subsystem_set_ns_path(s, n);
2006 return 0;
2007}
2008
2009__libnvme_public__attribute__((visibility("default"))) struct libnvme_ns *libnvme_subsystem_lookup_namespace(
2010 struct libnvme_subsystem *s, __u32 nsid)
2011{
2012 struct libnvme_ns *n;
2013
2014 libnvme_subsystem_for_each_ns(s, n)for (n = libnvme_subsystem_first_ns(s); n != ((void*)0); n = libnvme_subsystem_next_ns
(s, n))
{
2015 if (libnvme_ns_get_nsid(n) == nsid)
2016 return n;
2017 }
2018 return NULL((void*)0);
2019}