Bug Summary

File:.build-ci/../libnvme/src/nvme/tree-linux.c
Warning:line 75, column 12
Potential leak of memory pointed to by 'hnqn'

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-linux.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-linux.c

../libnvme/src/nvme/tree-linux.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
34__libnvme_public__attribute__((visibility("default"))) int libnvme_host_get_ids(struct libnvme_global_ctx *ctx,
35 const char *hostnqn_arg, const char *hostid_arg,
36 char **hostnqn, char **hostid)
37{
38 __cleanup_free__attribute__((cleanup(freep))) char *nqn = NULL((void*)0);
39 __cleanup_free__attribute__((cleanup(freep))) char *hid = NULL((void*)0);
40 __cleanup_free__attribute__((cleanup(freep))) char *hnqn = NULL((void*)0);
41 libnvme_host_t h;
42
43 /* command line argumments */
44 if (hostid_arg)
5
Assuming 'hostid_arg' is null
6
Taking false branch
45 hid = strdup(hostid_arg);
46 if (hostnqn_arg)
7
Assuming 'hostnqn_arg' is null
8
Taking false branch
47 hnqn = strdup(hostnqn_arg);
48
49 /* JSON config: assume the first entry is the default host */
50 h = libnvme_first_host(ctx);
51 if (h) {
9
Assuming 'h' is non-null
10
Taking true branch
52 if (!hid
10.1
'hid' is null
10.1
'hid' is null
)
11
Taking true branch
53 hid = xstrdup(libnvme_host_get_hostid(h));
54 if (!hnqn
11.1
'hnqn' is null
11.1
'hnqn' is null
)
12
Taking true branch
55 hnqn = xstrdup(libnvme_host_get_hostnqn(h));
13
Calling 'xstrdup'
17
Returned allocated memory
56 }
57
58 /* /etc/nvme/hostid and/or /etc/nvme/hostnqn */
59 if (!hid
17.1
'hid' is null
17.1
'hid' is null
)
18
Taking true branch
60 hid = libnvme_read_hostid();
61 if (!hnqn)
19
Assuming 'hnqn' is non-null
62 hnqn = libnvme_read_hostnqn();
63
64 /* incomplete configuration, thus derive hostid from hostnqn */
65 if (!hid && hnqn
20.1
'hnqn' is non-null
20.1
'hnqn' is non-null
)
20
Assuming 'hid' is null
21
Taking true branch
66 hid = libnvme_hostid_from_hostnqn(hnqn);
67
68 /*
69 * fallback to use either DMI information or device-tree. If all
70 * fails generate one
71 */
72 if (!hid) {
22
Assuming 'hid' is null
23
Taking true branch
73 hid = libnvme_generate_hostid();
74 if (!hid)
24
Assuming 'hid' is null
25
Taking true branch
75 return -ENOMEM12;
26
Potential leak of memory pointed to by 'hnqn'
76
77 libnvme_msg(ctx, LIBNVME_LOG_DEBUG,__libnvme_msg(ctx, LIBNVME_LOG_DEBUG, ((void*)0), "warning: using auto generated hostid and hostnqn\n"
)
78 "warning: using auto generated hostid and hostnqn\n")__libnvme_msg(ctx, LIBNVME_LOG_DEBUG, ((void*)0), "warning: using auto generated hostid and hostnqn\n"
)
;
79 }
80
81 /* incomplete configuration, thus derive hostnqn from hostid */
82 if (!hnqn) {
83 hnqn = libnvme_generate_hostnqn_from_hostid(hid);
84 if (!hnqn)
85 return -ENOMEM12;
86 }
87
88 /* sanity checks */
89 nqn = libnvme_hostid_from_hostnqn(hnqn);
90 if (nqn && strcmp(nqn, hid)) {
91 libnvme_msg(ctx, LIBNVME_LOG_DEBUG,__libnvme_msg(ctx, LIBNVME_LOG_DEBUG, ((void*)0), "warning: use hostid '%s' which does not match uuid in hostnqn '%s'\n"
, hid, hnqn)
92 "warning: use hostid '%s' which does not match uuid in hostnqn '%s'\n",__libnvme_msg(ctx, LIBNVME_LOG_DEBUG, ((void*)0), "warning: use hostid '%s' which does not match uuid in hostnqn '%s'\n"
, hid, hnqn)
93 hid, hnqn)__libnvme_msg(ctx, LIBNVME_LOG_DEBUG, ((void*)0), "warning: use hostid '%s' which does not match uuid in hostnqn '%s'\n"
, hid, hnqn)
;
94 }
95
96 *hostid = hid;
97 *hostnqn = hnqn;
98 hid = NULL((void*)0);
99 hnqn = NULL((void*)0);
100
101 return 0;
102}
103
104__libnvme_public__attribute__((visibility("default"))) int libnvme_get_host(
105 struct libnvme_global_ctx *ctx, const char *hostnqn,
106 const char *hostid, libnvme_host_t *host)
107{
108 __cleanup_free__attribute__((cleanup(freep))) char *hnqn = NULL((void*)0);
109 __cleanup_free__attribute__((cleanup(freep))) char *hid = NULL((void*)0);
110 struct libnvme_host *h;
111 int err;
112
113 err = libnvme_host_get_ids(ctx, hostnqn, hostid, &hnqn, &hid);
4
Calling 'libnvme_host_get_ids'
114 if (err)
115 return err;
116
117 h = libnvme_lookup_host(ctx, hnqn, hid);
118 if (!h)
119 return -ENOMEM12;
120
121 libnvme_host_set_hostsymname(h, NULL((void*)0));
122
123 *host = h;
124 return 0;
125}
126
127__libnvme_public__attribute__((visibility("default"))) const char *libnvme_ctrl_get_state(libnvme_ctrl_t c)
128{
129 char *state = c->state;
130
131 c->state = libnvme_get_ctrl_attr(c, "state");
132 free(state);
133 return c->state;
134}
135
136static int libnvme_ctrl_lookup_subsystem_name(struct libnvme_global_ctx *ctx,
137 const char *ctrl_name, char **name)
138{
139 const char *subsys_dir = libnvme_subsys_sysfs_dir();
140 __cleanup_dirents__attribute__((cleanup(cleanup_dirents))) struct dirents subsys = {};
141 int i;
142
143 subsys.num = libnvme_scan_subsystems(&subsys.ents);
144 if (subsys.num < 0)
145 return subsys.num;
146
147 for (i = 0; i < subsys.num; i++) {
148 struct stat st;
149 __cleanup_free__attribute__((cleanup(freep))) char *path = NULL((void*)0);
150
151 if (asprintf(&path, "%s/%s/%s", subsys_dir,
152 subsys.ents[i]->d_name, ctrl_name) < 0)
153 return -ENOMEM12;
154 libnvme_msg(ctx, LIBNVME_LOG_DEBUG, "lookup subsystem %s\n", path)__libnvme_msg(ctx, LIBNVME_LOG_DEBUG, ((void*)0), "lookup subsystem %s\n"
, path)
;
155 if (stat(path, &st) < 0) {
156 continue;
157 }
158
159 *name = strdup(subsys.ents[i]->d_name);
160 if (!*name)
161 return -ENOMEM12;
162
163 return 0;
164 }
165 return -ENOENT2;
166}
167
168static int libnvme_ctrl_lookup_phy_slot(struct libnvme_global_ctx *ctx,
169 libnvme_ctrl_t c)
170{
171 const char *slots_sysfs_dir = libnvme_slots_sysfs_dir();
172 __cleanup_free__attribute__((cleanup(freep))) char *target_addr = NULL((void*)0);
173 __cleanup_dir__attribute__((cleanup(cleanup_dir))) DIR *slots_dir = NULL((void*)0);
174 struct dirent *entry;
175 char *slot;
176 int ret;
177
178 if (!c->address)
179 return -EINVAL22;
180
181 slots_dir = opendir(slots_sysfs_dir);
182 if (!slots_dir) {
183 libnvme_msg(ctx, LIBNVME_LOG_WARN, "failed to open slots dir %s\n",__libnvme_msg(ctx, LIBNVME_LOG_WARN, ((void*)0), "failed to open slots dir %s\n"
, slots_sysfs_dir)
184 slots_sysfs_dir)__libnvme_msg(ctx, LIBNVME_LOG_WARN, ((void*)0), "failed to open slots dir %s\n"
, slots_sysfs_dir)
;
185 return -errno(*__errno_location ());
186 }
187
188 target_addr = strndup(c->address, 10);
189 while ((entry = readdir(slots_dir))) {
190 if (entry->d_type == DT_DIRDT_DIR &&
191 strncmp(entry->d_name, ".", 1) != 0 &&
192 strncmp(entry->d_name, "..", 2) != 0) {
193 __cleanup_free__attribute__((cleanup(freep))) char *path = NULL((void*)0);
194 __cleanup_free__attribute__((cleanup(freep))) char *addr = NULL((void*)0);
195
196 ret = asprintf(&path, "%s/%s",
197 slots_sysfs_dir, entry->d_name);
198 if (ret < 0)
199 return -ENOMEM12;
200 addr = libnvme_get_attr(path, "address");
201
202 /* some directories don't have an address entry */
203 if (!addr)
204 continue;
205 if (strcmp(addr, target_addr))
206 continue;
207
208 slot = strdup(entry->d_name);
209 if (!slot)
210 return -ENOMEM12;
211
212 c->phy_slot = slot;
213 return 0;
214 }
215 }
216 return -ENOENT2;
217}
218
219int libnvme_reconfigure_ctrl(struct libnvme_global_ctx *ctx,
220 libnvme_ctrl_t c, const char *path, const char *name)
221{
222 DIR *d;
223
224 /*
225 * It's necesssary to release any resources first because a ctrl
226 * can be reused.
227 */
228 libnvme_ctrl_release_transport_handle(c);
229 FREE_CTRL_ATTR(c->name)do { free(c->name); (c->name) = ((void*)0); } while (0);
230 FREE_CTRL_ATTR(c->sysfs_dir)do { free(c->sysfs_dir); (c->sysfs_dir) = ((void*)0); }
while (0)
;
231 FREE_CTRL_ATTR(c->firmware)do { free(c->firmware); (c->firmware) = ((void*)0); } while
(0)
;
232 FREE_CTRL_ATTR(c->model)do { free(c->model); (c->model) = ((void*)0); } while (
0)
;
233 FREE_CTRL_ATTR(c->state)do { free(c->state); (c->state) = ((void*)0); } while (
0)
;
234 FREE_CTRL_ATTR(c->numa_node)do { free(c->numa_node); (c->numa_node) = ((void*)0); }
while (0)
;
235 FREE_CTRL_ATTR(c->queue_count)do { free(c->queue_count); (c->queue_count) = ((void*)0
); } while (0)
;
236 FREE_CTRL_ATTR(c->serial)do { free(c->serial); (c->serial) = ((void*)0); } while
(0)
;
237 FREE_CTRL_ATTR(c->sqsize)do { free(c->sqsize); (c->sqsize) = ((void*)0); } while
(0)
;
238 FREE_CTRL_ATTR(c->cntrltype)do { free(c->cntrltype); (c->cntrltype) = ((void*)0); }
while (0)
;
239 FREE_CTRL_ATTR(c->cntlid)do { free(c->cntlid); (c->cntlid) = ((void*)0); } while
(0)
;
240 FREE_CTRL_ATTR(c->dctype)do { free(c->dctype); (c->dctype) = ((void*)0); } while
(0)
;
241 FREE_CTRL_ATTR(c->phy_slot)do { free(c->phy_slot); (c->phy_slot) = ((void*)0); } while
(0)
;
242
243 d = opendir(path);
244 if (!d) {
245 libnvme_msg(ctx, LIBNVME_LOG_ERR,__libnvme_msg(ctx, LIBNVME_LOG_ERR, ((void*)0), "Failed to open ctrl dir %s, error %d\n"
, path, (*__errno_location ()))
246 "Failed to open ctrl dir %s, error %d\n", path, errno)__libnvme_msg(ctx, LIBNVME_LOG_ERR, ((void*)0), "Failed to open ctrl dir %s, error %d\n"
, path, (*__errno_location ()))
;
247 return -ENODEV19;
248 }
249 closedir(d);
250
251 c->hdl = NULL((void*)0);
252 c->name = xstrdup(name);
253 c->sysfs_dir = xstrdup(path);
254 c->firmware = libnvme_get_ctrl_attr(c, "firmware_rev");
255 c->model = libnvme_get_ctrl_attr(c, "model");
256 c->state = libnvme_get_ctrl_attr(c, "state");
257 c->numa_node = libnvme_get_ctrl_attr(c, "numa_node");
258 c->queue_count = libnvme_get_ctrl_attr(c, "queue_count");
259 c->serial = libnvme_get_ctrl_attr(c, "serial");
260 c->sqsize = libnvme_get_ctrl_attr(c, "sqsize");
261 c->cntrltype = libnvme_get_ctrl_attr(c, "cntrltype");
262 c->cntlid = libnvme_get_ctrl_attr(c, "cntlid");
263 c->dctype = libnvme_get_ctrl_attr(c, "dctype");
264 libnvme_ctrl_lookup_phy_slot(ctx, c);
265 libnvmf_read_sysfs_fabrics_attrs(ctx, c);
266
267 return 0;
268}
269
270__libnvme_public__attribute__((visibility("default"))) int libnvme_init_ctrl(
271 libnvme_host_t h, libnvme_ctrl_t c, int instance)
272{
273 __cleanup_free__attribute__((cleanup(freep))) char *subsys_name = NULL((void*)0), *name = NULL((void*)0), *path = NULL((void*)0);
274 libnvme_subsystem_t s;
275 int ret;
276
277 ret = asprintf(&name, "nvme%d", instance);
278 if (ret < 0)
279 return -ENOMEM12;
280
281 ret = asprintf(&path, "%s/%s", libnvme_ctrl_sysfs_dir(), name);
282 if (ret < 0)
283 return -ENOMEM12;
284
285 ret = libnvme_reconfigure_ctrl(h->ctx, c, path, name);
286 if (ret < 0)
287 return ret;
288
289 c->address = libnvme_get_attr(path, "address");
290 if (!c->address && strcmp(c->transport, "loop"))
291 return -ENVME_CONNECT_INVAL_TR;
292
293 ret = libnvme_ctrl_lookup_subsystem_name(h->ctx, name, &subsys_name);
294 if (ret) {
295 libnvme_msg(h->ctx, LIBNVME_LOG_ERR,__libnvme_msg(h->ctx, LIBNVME_LOG_ERR, ((void*)0), "Failed to lookup subsystem name for %s\n"
, c->name)
296 "Failed to lookup subsystem name for %s\n",__libnvme_msg(h->ctx, LIBNVME_LOG_ERR, ((void*)0), "Failed to lookup subsystem name for %s\n"
, c->name)
297 c->name)__libnvme_msg(h->ctx, LIBNVME_LOG_ERR, ((void*)0), "Failed to lookup subsystem name for %s\n"
, c->name)
;
298 return ENVME_CONNECT_LOOKUP_SUBSYS_NAME;
299 }
300
301 s = libnvme_lookup_subsystem(h, subsys_name, c->subsysnqn);
302 if (!s)
303 return -ENVME_CONNECT_LOOKUP_SUBSYS;
304
305 if (s->subsystype && !strcmp(s->subsystype, "discovery"))
306 c->discovery_ctrl = true1;
307
308 c->s = s;
309 list_add_tail(&s->ctrls, &c->entry)list_add_tail_(&s->ctrls, &c->entry, "../libnvme/src/nvme/tree-linux.c"
":" "309")
;
310
311 return ret;
312}
313
314__libnvme_public__attribute__((visibility("default"))) int libnvme_scan_ctrl(
315 struct libnvme_global_ctx *ctx, const char *name,
316 libnvme_ctrl_t *cp)
317{
318 __cleanup_free__attribute__((cleanup(freep))) char *subsysnqn = NULL((void*)0), *subsysname = NULL((void*)0);
319 __cleanup_free__attribute__((cleanup(freep))) char *hostnqn = NULL((void*)0), *hostid = NULL((void*)0);
320 __cleanup_free__attribute__((cleanup(freep))) char *path = NULL((void*)0);
321 char *host_key;
322 libnvme_host_t h;
323 libnvme_subsystem_t s;
324 libnvme_ctrl_t c;
325 int ret;
326
327 libnvme_msg(ctx, LIBNVME_LOG_DEBUG, "scan controller %s\n", name)__libnvme_msg(ctx, LIBNVME_LOG_DEBUG, ((void*)0), "scan controller %s\n"
, name)
;
328 ret = asprintf(&path, "%s/%s", libnvme_ctrl_sysfs_dir(), name);
329 if (ret < 0)
1
Assuming 'ret' is >= 0
2
Taking false branch
330 return -ENOMEM12;
331
332 hostnqn = libnvme_get_attr(path, "hostnqn");
333 hostid = libnvme_get_attr(path, "hostid");
334 ret = libnvme_get_host(ctx, hostnqn, hostid, &h);
3
Calling 'libnvme_get_host'
335 if (ret)
336 return ret;
337
338 host_key = libnvme_get_attr(path, "dhchap_secret");
339 if (host_key && strcmp(host_key, "none")) {
340 free(h->dhchap_host_key);
341 h->dhchap_host_key = host_key;
342 host_key = NULL((void*)0);
343 }
344 free(host_key);
345
346 subsysnqn = libnvme_get_attr(path, "subsysnqn");
347 if (!subsysnqn)
348 return -ENXIO6;
349
350 ret = libnvme_ctrl_lookup_subsystem_name(ctx, name, &subsysname);
351 if (ret) {
352 libnvme_msg(ctx, LIBNVME_LOG_DEBUG,__libnvme_msg(ctx, LIBNVME_LOG_DEBUG, ((void*)0), "failed to lookup subsystem for controller %s\n"
, name)
353 "failed to lookup subsystem for controller %s\n",__libnvme_msg(ctx, LIBNVME_LOG_DEBUG, ((void*)0), "failed to lookup subsystem for controller %s\n"
, name)
354 name)__libnvme_msg(ctx, LIBNVME_LOG_DEBUG, ((void*)0), "failed to lookup subsystem for controller %s\n"
, name)
;
355 return ret;
356 }
357
358 s = libnvme_lookup_subsystem(h, subsysname, subsysnqn);
359 if (!s)
360 return -ENOMEM12;
361
362 ret = libnvme_ctrl_alloc(ctx, s, path, name, &c);
363 if (ret)
364 return ret;
365
366 ret = libnvme_ctrl_scan_paths(ctx, c);
367 if (ret) {
368 libnvme_free_ctrl(c);
369 return ret;
370 }
371
372 ret = libnvme_ctrl_scan_namespaces(ctx, c);
373 if (ret) {
374 libnvme_free_ctrl(c);
375 return ret;
376 }
377
378 *cp = c;
379 return 0;
380}
381
382static int libnvme_strtou64(const char *str, void *res)
383{
384 char *endptr;
385 __u64 v;
386
387 errno(*__errno_location ()) = 0;
388 v = strtoull(str, &endptr, 0);
389
390 if (errno(*__errno_location ()) != 0)
391 return -errno(*__errno_location ());
392
393 if (endptr == str) {
394 /* no digits found */
395 return -EINVAL22;
396 }
397
398 *(__u64 *)res = v;
399 return 0;
400}
401
402static int libnvme_strtou32(const char *str, void *res)
403{
404 char *endptr;
405 __u32 v;
406
407 errno(*__errno_location ()) = 0;
408 v = strtol(str, &endptr, 0);
409
410 if (errno(*__errno_location ()) != 0)
411 return -errno(*__errno_location ());
412
413 if (endptr == str) {
414 /* no digits found */
415 return -EINVAL22;
416 }
417
418 *(__u32 *)res = v;
419 return 0;
420}
421
422static int libnvme_strtoi(const char *str, void *res)
423{
424 char *endptr;
425 int v;
426
427 errno(*__errno_location ()) = 0;
428 v = strtol(str, &endptr, 0);
429
430 if (errno(*__errno_location ()) != 0)
431 return -errno(*__errno_location ());
432
433 if (endptr == str) {
434 /* no digits found */
435 return -EINVAL22;
436 }
437
438 *(int *)res = v;
439 return 0;
440}
441
442static int libnvme_strtoeuid(const char *str, void *res)
443{
444 memcpy(res, str, 8);
445 return 0;
446}
447
448static int libnvme_strtouuid(const char *str, void *res)
449{
450 memcpy(res, str, NVME_UUID_LEN16);
451 return 0;
452}
453
454struct sysfs_attr_table {
455 void *var;
456 int (*parse)(const char *str, void *res);
457 bool_Bool mandatory;
458 const char *name;
459};
460
461#define GETSHIFT(x)(__builtin_ffsll(x) - 1) (__builtin_ffsll(x) - 1)
462#define ARRAY_SIZE(arr)(sizeof(arr) / sizeof((arr)[0])) (sizeof(arr) / sizeof((arr)[0]))
463
464static int parse_attrs(const char *path, struct sysfs_attr_table *tbl, int size)
465{
466 char *str;
467 int ret, i;
468
469 for (i = 0; i < size; i++) {
470 struct sysfs_attr_table *e = &tbl[i];
471
472 str = libnvme_get_attr(path, e->name);
473 if (!str) {
474 if (!e->mandatory)
475 continue;
476 return -ENOENT2;
477 }
478 ret = e->parse(str, e->var);
479 free(str);
480 if (ret)
481 return ret;
482 }
483
484 return 0;
485}
486
487int libnvme_ns_init(const char *path, struct libnvme_ns *ns)
488{
489 __cleanup_free__attribute__((cleanup(freep))) char *attr = NULL((void*)0);
490 struct stat sb;
491 uint64_t size;
492 int ret;
493
494 struct sysfs_attr_table base[] = {
495 { &ns->nsid, libnvme_strtou32, true1, "nsid" },
496 { &size, libnvme_strtou64, true1, "size" },
497 { &ns->lba_size, libnvme_strtou32, true1, "queue/logical_block_size" },
498 { ns->eui64, libnvme_strtoeuid, false0, "eui" },
499 { ns->nguid, libnvme_strtouuid, false0, "nguid" },
500 { ns->uuid, libnvme_strtouuid, false0, "uuid" }
501 };
502
503 ret = parse_attrs(path, base, ARRAY_SIZE(base)(sizeof(base) / sizeof((base)[0])));
504 if (ret)
505 return ret;
506
507 ns->lba_shift = GETSHIFT(ns->lba_size)(__builtin_ffsll(ns->lba_size) - 1);
508 /*
509 * size is in 512 bytes units and lba_count is in lba_size which are not
510 * necessarily the same.
511 */
512 ns->lba_count = size >> (ns->lba_shift - SECTOR_SHIFT9);
513
514 if (asprintf(&attr, "%s/csi", path) < 0)
515 return -ENOMEM12;
516
517 ret = stat(attr, &sb);
518 if (ret == 0) {
519 /* only available on kernels >= 6.8 */
520 struct sysfs_attr_table ext[] = {
521 { &ns->csi, libnvme_strtoi, true1, "csi" },
522 { &ns->lba_util, libnvme_strtou64, true1, "nuse" },
523 { &ns->meta_size, libnvme_strtoi, true1, "metadata_bytes"},
524
525 };
526
527 ret = parse_attrs(path, ext, ARRAY_SIZE(ext)(sizeof(ext) / sizeof((ext)[0])));
528 if (ret)
529 return ret;
530 } else {
531 __cleanup_libnvme_free__attribute__((cleanup(libnvme_freep))) struct nvme_id_ns *id = NULL((void*)0);
532 uint8_t flbas;
533
534 id = libnvme_alloc(sizeof(*id));
535 if (!id)
536 return -ENOMEM12;
537
538 ret = libnvme_ns_identify(ns, id);
539 if (ret)
540 return ret;
541
542 nvme_id_ns_flbas_to_lbaf_inuse(id->flbas, &flbas);
543 ns->lba_count = le64_to_cpu(id->nsze);
544 ns->lba_util = le64_to_cpu(id->nuse);
545 ns->meta_size = le16_to_cpu(id->lbaf[flbas].ms);
546 }
547
548 return 0;
549}
550
551static void libnvme_ns_set_generic_name(struct libnvme_ns *n, const char *name)
552{
553 char generic_name[PATH_MAX4096];
554 int instance, head_instance;
555 int ret;
556
557 ret = sscanf(name, "nvme%dn%d", &instance, &head_instance);
558 if (ret != 2)
559 return;
560
561 sprintf(generic_name, "ng%dn%d", instance, head_instance);
562 n->generic_name = strdup(generic_name);
563}
564
565int libnvme_ns_open(struct libnvme_global_ctx *ctx, const char *sys_path,
566 const char *name, libnvme_ns_t *ns)
567{
568 int ret;
569 struct libnvme_ns *n;
570 struct libnvme_ns_head *head;
571 struct stat arg;
572 __cleanup_free__attribute__((cleanup(freep))) char *path = NULL((void*)0);
573
574 n = calloc(1, sizeof(*n));
575 if (!n)
576 return -ENOMEM12;
577
578 head = calloc(1, sizeof(*head));
579 if (!head) {
580 free(n);
581 return -ENOMEM12;
582 }
583
584 head->n = n;
585 list_head_init(&head->paths);
586 ret = asprintf(&path, "%s/%s", sys_path, "multipath");
587 if (ret < 0) {
588 ret = -ENOMEM12;
589 goto free_ns_head;
590 }
591
592 /*
593 * The sysfs-dir "multipath" is available only when nvme multipath
594 * is configured and we're running kernel version >= 6.14.
595 */
596 ret = stat(path, &arg);
597 if (ret == 0) {
598 head->sysfs_dir = path;
599 path = NULL((void*)0);
600 } else
601 head->sysfs_dir = NULL((void*)0);
602
603 n->ctx = ctx;
604 n->head = head;
605 n->hdl = NULL((void*)0);
606 n->name = strdup(name);
607
608 libnvme_ns_set_generic_name(n, name);
609
610 ret = libnvme_ns_init(sys_path, n);
611 if (ret)
612 goto free_ns;
613
614 list_node_init(&n->entry);
615
616 libnvme_ns_release_transport_handle(n);
617
618 *ns = n;
619 return 0;
620
621free_ns:
622 free(n->generic_name);
623 free(n->name);
624free_ns_head:
625 free(head);
626 free(n);
627 return ret;
628}
629
630static inline bool_Bool libnvme_ns_is_generic(const char *name)
631{
632 int instance, head_instance;
633
634 if (sscanf(name, "ng%dn%d", &instance, &head_instance) != 2)
635 return false0;
636 return true1;
637}
638
639static char *libnvme_ns_generic_to_blkdev(const char *generic)
640{
641
642 int instance, head_instance;
643 char blkdev[PATH_MAX4096];
644
645 if (!libnvme_ns_is_generic(generic))
646 return strdup(generic);
647
648 sscanf(generic, "ng%dn%d", &instance, &head_instance);
649 sprintf(blkdev, "nvme%dn%d", instance, head_instance);
650
651 return strdup(blkdev);
652}
653
654int __libnvme_scan_namespace(struct libnvme_global_ctx *ctx,
655 const char *sysfs_dir, const char *name, libnvme_ns_t *ns)
656{
657 __cleanup_free__attribute__((cleanup(freep))) char *blkdev = NULL((void*)0);
658 __cleanup_free__attribute__((cleanup(freep))) char *path = NULL((void*)0);
659 struct libnvme_ns *n = NULL((void*)0);
660 int ret;
661
662 blkdev = libnvme_ns_generic_to_blkdev(name);
663 if (!blkdev)
664 return -ENOMEM12;
665
666 ret = asprintf(&path, "%s/%s", sysfs_dir, blkdev);
667 if (ret < 0)
668 return -ENOMEM12;
669
670 ret = libnvme_ns_open(ctx, path, blkdev, &n);
671 if (ret)
672 return ret;
673
674 n->sysfs_dir = path;
675 path = NULL((void*)0);
676
677 *ns = n;
678 return 0;
679}
680
681int libnvme_get_ctrl_transport(const char *path, const char *name,
682 char **transport, char **traddr, char **addr, char **trsvcid,
683 char **host_traddr, char **host_iface)
684{
685 char *a = NULL((void*)0), *e = NULL((void*)0);
686
687 *transport = libnvme_get_attr(path, "transport");
688 if (!*transport)
689 return -ENXIO6;
690
691 /* Parse 'address' string into components */
692 *addr = libnvme_get_attr(path, "address");
693 if (!*addr) {
694 __cleanup_free__attribute__((cleanup(freep))) char *rpath = NULL((void*)0);
695 char *p = NULL((void*)0), *_a = NULL((void*)0);
696
697 /* loop transport might not have an address */
698 if (!strcmp(*transport, "loop"))
699 goto skip_address;
700
701 /* Older kernels don't support pcie transport addresses */
702 if (strcmp(*transport, "pcie") &&
703 strcmp(*transport, "apple-nvme"))
704 return -ENXIO6;
705 /* Figure out the PCI address from the attribute path */
706 rpath = realpath(path, NULL((void*)0));
707 if (!rpath)
708 return -ENOMEM12;
709 a = strtok_r(rpath, "/", &e);
710 while (a && strlen(a)) {
711 if (_a)
712 p = _a;
713 _a = a;
714 if (!strncmp(a, "nvme", 4))
715 break;
716 a = strtok_r(NULL((void*)0), "/", &e);
717 }
718 if (p)
719 *addr = strdup(p);
720 } else if (!strcmp(*transport, "pcie") ||
721 !strcmp(*transport, "apple-nvme")) {
722 /* The 'address' string is the transport address */
723 *traddr = strdup(*addr);
724 if (!*traddr)
725 return -ENOMEM12;
726 } else {
727 __cleanup_free__attribute__((cleanup(freep))) char *address = strdup(*addr);
728 if (!address)
729 return -ENOMEM12;
730
731 a = strtok_r(address, ",", &e);
732 while (a && strlen(a)) {
733 if (!strncmp(a, "traddr=", 7))
734 *traddr = strdup(a + 7);
735 else if (!strncmp(a, "trsvcid=", 8))
736 *trsvcid = strdup(a + 8);
737 else if (!strncmp(a, "host_traddr=", 12))
738 *host_traddr = strdup(a + 12);
739 else if (!strncmp(a, "host_iface=", 11))
740 *host_iface = strdup(a + 11);
741 a = strtok_r(NULL((void*)0), ",", &e);
742 }
743 }
744skip_address:
745 return 0;
746}
747
748int libnvme_init_subsystem(libnvme_subsystem_t s, const char *name)
749{
750 char *path;
751
752 if (asprintf(&path, "%s/%s", libnvme_subsys_sysfs_dir(), name) < 0)
753 return -ENOMEM12;
754
755 s->model = libnvme_get_attr(path, "model");
756 if (!s->model)
757 s->model = strdup("undefined");
758 s->serial = libnvme_get_attr(path, "serial");
759 s->firmware = libnvme_get_attr(path, "firmware_rev");
760 s->subsystype = libnvme_get_attr(path, "subsystype");
761 if (!s->subsystype) {
762 if (!strcmp(s->subsysnqn, NVME_DISC_SUBSYS_NAME"nqn.2014-08.org.nvmexpress.discovery"))
763 s->subsystype = strdup("discovery");
764 else
765 s->subsystype = strdup("nvm");
766 }
767 s->name = strdup(name);
768 s->sysfs_dir = (char *)path;
769 s->iopolicy = libnvme_get_attr(path, "iopolicy");
770
771 return 0;
772}

../libnvme/src/nvme/private.h

1// SPDX-License-Identifier: LGPL-2.1-or-later
2/*
3 * This file is part of libnvme.
4 * Copyright (c) 2021 SUSE Software Solutions
5 *
6 * Authors: Hannes Reinecke <hare@suse.de>
7 */
8#pragma once
9
10#include <sys/stat.h>
11#include <sys/types.h>
12#include <string.h>
13
14#if defined(NVME_HAVE_NETDB) || defined(CONFIG_FABRICS)
15#include <ifaddrs.h>
16#endif
17
18#include <ccan/list/list.h>
19
20#include "nvme/nvme-types.h"
21#include "nvme/lib-types.h"
22
23#include <nvme/tree.h>
24
25struct libnvme_passthru_completion;
26struct libnvme_async_req;
27
28const char *libnvme_subsys_sysfs_dir(void);
29const char *libnvme_ctrl_sysfs_dir(void);
30const char *libnvme_ns_sysfs_dir(void);
31const char *libnvme_slots_sysfs_dir(void);
32const char *libnvme_uuid_ibm_filename(void);
33const char *libnvme_dmi_entries_dir(void);
34
35struct linux_passthru_cmd32 {
36 __u8 opcode;
37 __u8 flags;
38 __u16 rsvd1;
39 __u32 nsid;
40 __u32 cdw2;
41 __u32 cdw3;
42 __u64 metadata;
43 __u64 addr;
44 __u32 metadata_len;
45 __u32 data_len;
46 __u32 cdw10;
47 __u32 cdw11;
48 __u32 cdw12;
49 __u32 cdw13;
50 __u32 cdw14;
51 __u32 cdw15;
52 __u32 timeout_ms;
53 __u32 result;
54};
55
56struct linux_passthru_cmd64 {
57 __u8 opcode;
58 __u8 flags;
59 __u16 rsvd1;
60 __u32 nsid;
61 __u32 cdw2;
62 __u32 cdw3;
63 __u64 metadata;
64 __u64 addr;
65 __u32 metadata_len;
66 __u32 data_len;
67 __u32 cdw10;
68 __u32 cdw11;
69 __u32 cdw12;
70 __u32 cdw13;
71 __u32 cdw14;
72 __u32 cdw15;
73 __u32 timeout_ms;
74 __u32 rsvd2;
75 __u64 result;
76};
77
78#define LIBNVME_IOCTL_ID_IO('N', 0x40) _IO('N', 0x40)
79#define LIBNVME_IOCTL_RESET_IO('N', 0x44) _IO('N', 0x44)
80#define LIBNVME_IOCTL_SUBSYS_RESET_IO('N', 0x45) _IO('N', 0x45)
81#define LIBNVME_IOCTL_RESCAN_IO('N', 0x46) _IO('N', 0x46)
82
83#define LIBNVME_IOCTL_ADMIN_CMD_IOWR('N', 0x41, struct linux_passthru_cmd32) _IOWR('N', 0x41, struct linux_passthru_cmd32)
84#define LIBNVME_IOCTL_IO_CMD_IOWR('N', 0x43, struct linux_passthru_cmd32) _IOWR('N', 0x43, struct linux_passthru_cmd32)
85#define LIBNVME_IOCTL_ADMIN64_CMD_IOWR('N', 0x47, struct linux_passthru_cmd64) _IOWR('N', 0x47, struct linux_passthru_cmd64)
86#define LIBNVME_IOCTL_IO64_CMD_IOWR('N', 0x48, struct linux_passthru_cmd64) _IOWR('N', 0x48, struct linux_passthru_cmd64)
87
88/* io_uring async commands: */
89#define LIBNVME_URING_CMD_IO_IOWR('N', 0x80, struct libnvme_uring_cmd) _IOWR('N', 0x80, struct libnvme_uring_cmd)
90#define LIBNVME_URING_CMD_IO_VEC_IOWR('N', 0x81, struct libnvme_uring_cmd) _IOWR('N', 0x81, struct libnvme_uring_cmd)
91#define LIBNVME_URING_CMD_ADMIN_IOWR('N', 0x82, struct libnvme_uring_cmd) _IOWR('N', 0x82, struct libnvme_uring_cmd)
92#define LIBNVME_URING_CMD_ADMIN_VEC_IOWR('N', 0x83, struct libnvme_uring_cmd) _IOWR('N', 0x83, struct libnvme_uring_cmd)
93
94/**
95 * struct libnvme_fabrics_config - Defines all linux nvme fabrics initiator options
96 * @queue_size: Number of IO queue entries
97 * @nr_io_queues: Number of controller IO queues to establish
98 * @reconnect_delay: Time between two consecutive reconnect attempts.
99 * @ctrl_loss_tmo: Override the default controller reconnect attempt timeout in seconds
100 * @fast_io_fail_tmo: Set the fast I/O fail timeout in seconds.
101 * @keep_alive_tmo: Override the default keep-alive-timeout to this value in seconds
102 * @nr_write_queues: Number of queues to use for exclusively for writing
103 * @nr_poll_queues: Number of queues to reserve for polling completions
104 * @tos: Type of service
105 * @keyring_id: Keyring to store and lookup keys
106 * @tls_key_id: TLS PSK for the connection
107 * @tls_configured_key_id: TLS PSK for connect command for the connection
108 * @duplicate_connect: Allow multiple connections to the same target
109 * @disable_sqflow: Disable controller sq flow control
110 * @hdr_digest: Generate/verify header digest (TCP)
111 * @data_digest: Generate/verify data digest (TCP)
112 * @tls: Start TLS on the connection (TCP)
113 * @concat: Enable secure concatenation (TCP)
114 */
115struct libnvme_fabrics_config { // !generate-dict-table !nested-accessors
116 int queue_size;
117 int nr_io_queues;
118 int reconnect_delay;
119 int ctrl_loss_tmo;
120 int fast_io_fail_tmo;
121 int keep_alive_tmo;
122 int nr_write_queues;
123 int nr_poll_queues;
124 int tos;
125 long keyring_id;
126 long tls_key_id;
127 long tls_configured_key_id;
128
129 bool_Bool duplicate_connect;
130 bool_Bool disable_sqflow;
131 bool_Bool hdr_digest;
132 bool_Bool data_digest;
133 bool_Bool tls;
134 bool_Bool concat;
135};
136
137/**
138 * struct libnvme_ctrl_params - Parameters for creating a controller instance
139 * @transport: Transport type: loop, fc, rdma, tcp, pcie, apple-nvme
140 * @traddr: Transport address (destination address)
141 * @host_traddr: Host transport address (source address)
142 * @host_iface: Host interface for connection (tcp only)
143 * @trsvcid: Transport service ID
144 * @subsysnqn: Subsystem NQN
145 * @cfg: Fabrics tuning parameters
146 */
147struct libnvme_ctrl_params { // !nested-accessors
148 const char *transport;
149 const char *traddr;
150 const char *host_traddr;
151 const char *host_iface;
152 const char *trsvcid;
153 const char *subsysnqn;
154 struct libnvme_fabrics_config cfg; // !access:nested
155};
156
157void libnvme_fabrics_config_copy(struct libnvme_fabrics_config *dst,
158 const struct libnvme_fabrics_config *src);
159
160struct libnvme_log {
161 int fd;
162 int level;
163 bool_Bool pid;
164 bool_Bool timestamp;
165};
166
167enum libnvme_transport_handle_type {
168 LIBNVME_TRANSPORT_HANDLE_TYPE_UNKNOWN = 0,
169 LIBNVME_TRANSPORT_HANDLE_TYPE_DIRECT,
170 LIBNVME_TRANSPORT_HANDLE_TYPE_MI,
171};
172
173enum ioctl_state {
174 IOCTL_STATE_UNKNOWN = 0,
175 IOCTL_STATE_IOCTL32 = 1,
176 IOCTL_STATE_IOCTL64 = 2,
177};
178
179enum libnvme_io_uring_state {
180 LIBNVME_IO_URING_STATE_UNKNOWN = 0,
181 LIBNVME_IO_URING_STATE_NOT_AVAILABLE,
182 LIBNVME_IO_URING_STATE_AVAILABLE,
183};
184
185struct libnvme_transport_handle {
186 struct libnvme_global_ctx *ctx;
187 enum libnvme_transport_handle_type type;
188 char *name;
189
190 void *(*submit_entry)(struct libnvme_transport_handle *hdl,
191 struct libnvme_passthru_cmd *cmd);
192 void (*submit_exit)(struct libnvme_transport_handle *hdl,
193 struct libnvme_passthru_cmd *cmd,
194 int err, void *user_data);
195 bool_Bool (*decide_retry)(struct libnvme_transport_handle *hdl,
196 struct libnvme_passthru_cmd *cmd, int err);
197
198 /* global command timeout */
199 __u32 timeout;
200
201 /* direct */
202 libnvme_fd_t fd;
203 struct stat stat;
204 enum ioctl_state ioctl_admin_state;
205 enum ioctl_state ioctl_io_state;
206 enum libnvme_io_uring_state uring_state;
207#ifdef CONFIG_LIBURING
208 unsigned int uring_pending;
209 struct io_uring *ring;
210 struct libnvme_async_req *dry_run_head;
211 struct libnvme_async_req *dry_run_tail;
212#endif
213
214#ifdef CONFIG_MI
215 /* mi */
216 struct libnvme_mi_ep *ep;
217 __u16 id;
218 struct list_node ep_entry;
219#endif
220
221 struct libnvme_log *log;
222};
223
224enum libnvme_stat_group {
225 READ = 0,
226 WRITE,
227 DISCARD,
228 FLUSH,
229
230 NR_STAT_GROUPS
231};
232
233struct libnvme_stat {
234 struct {
235 unsigned long ios;
236 unsigned long merges;
237 unsigned long long sectors;
238 unsigned int ticks; /* in milliseconds */
239 } group[NR_STAT_GROUPS];
240
241 unsigned int inflights;
242 unsigned int io_ticks; /* in milliseconds */
243 unsigned int tot_ticks; /* in milliseconds */
244
245 double ts_ms; /* timestamp when the stat is updated */
246};
247
248struct libnvme_path { // !generate-accessors:read=generated,write=none
249 struct list_node entry;
250 struct list_node nentry;
251
252 /* Double-buffered gendisk I/O stats: stat[curr_idx] is the latest
253 * snapshot, stat[!curr_idx] the previous one. curr_idx toggles on
254 * each update_stat() call; diffstat selects raw vs. delta for getters.
255 * Managed exclusively by the stat subsystem — do not access directly.
256 */
257 struct libnvme_stat stat[2];
258 unsigned int curr_idx; // !access:read=none
259 bool_Bool diffstat; // !access:read=none
260
261 struct libnvme_ctrl *c;
262 struct libnvme_ns *n;
263
264 char *name; // !access:write=generated
265 char *sysfs_dir; // !access:write=generated
266 char *ana_state; // !access:read=custom
267 char *numa_nodes; // !access:read=custom
268 int grpid; // !access:write=generated
269 int queue_depth; // !access:read=custom
270 long multipath_failover_count; // !access:read=custom
271 long command_retry_count; // !access:read=custom
272 long command_error_count; // !access:read=custom
273};
274
275struct libnvme_ns_head {
276 struct list_head paths;
277 struct libnvme_ns *n;
278
279 char *sysfs_dir;
280};
281
282struct libnvme_ns { // !generate-accessors:read=generated,write=none !generate-python:alias=Namespace
283 struct list_node entry;
284
285 struct libnvme_subsystem *s;
286 struct libnvme_ctrl *c;
287 struct libnvme_ns_head *head;
288
289 struct libnvme_global_ctx *ctx;
290
291 /* Double-buffered gendisk I/O stats: stat[curr_idx] is the latest
292 * snapshot, stat[!curr_idx] the previous one. curr_idx toggles on
293 * each update_stat() call; diffstat selects raw vs. delta for getters.
294 * Managed exclusively by the stat subsystem — do not access directly.
295 */
296 struct libnvme_stat stat[2];
297 unsigned int curr_idx; // !access:read=none
298 bool_Bool diffstat; // !access:read=none
299
300 struct libnvme_transport_handle *hdl;
301 __u32 nsid; // !access:write=generated
302 char *name;
303 char *generic_name;
304 char *sysfs_dir; // !access:write=generated
305
306 int lba_shift; // !access:write=generated
307 int lba_size; // !access:write=generated
308 int meta_size; // !access:write=generated
309 uint64_t lba_count; // !access:write=generated
310 uint64_t lba_util; // !access:write=generated
311
312 uint8_t eui64[8];
313 uint8_t nguid[16];
314 unsigned char uuid[NVME_UUID_LEN16]; // !access:read=none
315 enum nvme_csi csi;
316
317 long command_retry_count; // !access:read=custom
318 long command_error_count; // !access:read=custom
319 long io_requeue_no_usable_path_count;// !access:read=custom
320 long io_fail_no_available_path_count;// !access:read=custom
321};
322
323struct libnvme_ctrl { // !generate-accessors:read=generated,write=none !generate-python:alias=Ctrl
324 struct list_node entry;
325 struct list_head paths;
326 struct list_head namespaces;
327 struct libnvme_subsystem *s;
328
329 struct libnvme_global_ctx *ctx;
330 struct libnvme_transport_handle *hdl;
331 char *name;
332 char *sysfs_dir;
333 char *address;
334 char *firmware;
335 char *model;
336 char *state; // !access:read=custom
337 char *numa_node;
338 char *queue_count;
339 char *serial;
340 char *sqsize;
341 char *transport;
342 char *subsysnqn;
343 char *traddr;
344 char *trsvcid;
345 char *dhchap_host_key; // !access:write=generated
346 char *dhchap_ctrl_key; // !access:write=generated
347 char *keyring; // !access:write=generated
348 char *tls_key_identity; // !access:write=generated
349 char *tls_key; // !access:write=generated
350 char *cntrltype;
351 char *cntlid;
352 char *dctype;
353 char *phy_slot;
354 char *host_traddr;
355 char *host_iface;
356 bool_Bool discovery_ctrl; // !access:write=generated
357 bool_Bool unique_discovery_ctrl; // !access:write=generated
358 bool_Bool discovered; // !access:write=generated
359 bool_Bool persistent; // !access:write=generated
360 long command_error_count; // !access:read=custom
361 long reset_count; // !access:read=custom
362 long reconnect_count; // !access:read=custom
363 struct libnvme_fabrics_config cfg; // !access:nested:write=none
364};
365
366struct libnvme_subsystem { // !generate-accessors:read=generated,write=none !generate-python:alias=Subsystem
367 struct list_node entry;
368 struct list_head ctrls;
369 struct list_head namespaces;
370 struct libnvme_host *h;
371
372 char *name;
373 char *sysfs_dir;
374 char *subsysnqn;
375 char *model;
376 char *serial;
377 char *firmware;
378 char *subsystype;
379 char *iopolicy; // !access:read=custom
380};
381
382struct libnvme_host { // !generate-accessors:read=generated,write=none !generate-python:alias=Host
383 struct list_node entry;
384 struct list_head subsystems;
385 struct libnvme_global_ctx *ctx;
386
387 char *hostnqn;
388 char *hostid;
389 char *dhchap_host_key; // !access:write=generated
390 char *hostsymname; // !access:write=generated
391
392 /* pdc_enabled and pdc_enabled_valid work together. pdc_enabled_valid,
393 * when true, indicates that pdc_enabled has been explicitly defined.
394 * pdc_enabled_valid is internal meta-data for pdc_enabled.
395 */
396 bool_Bool pdc_enabled; // !access:read=none,write=custom
397 bool_Bool pdc_enabled_valid; // !access:read=none
398};
399
400struct libnvme_fabric_options { // !generate-accessors
401 bool_Bool cntlid;
402 bool_Bool concat;
403 bool_Bool ctrl_loss_tmo;
404 bool_Bool data_digest;
405 bool_Bool dhchap_ctrl_secret;
406 bool_Bool dhchap_secret;
407 bool_Bool disable_sqflow;
408 bool_Bool discovery;
409 bool_Bool duplicate_connect;
410 bool_Bool fast_io_fail_tmo;
411 bool_Bool hdr_digest;
412 bool_Bool host_iface;
413 bool_Bool host_traddr;
414 bool_Bool hostid;
415 bool_Bool hostnqn;
416 bool_Bool instance;
417 bool_Bool keep_alive_tmo;
418 bool_Bool keyring;
419 bool_Bool nqn;
420 bool_Bool nr_io_queues;
421 bool_Bool nr_poll_queues;
422 bool_Bool nr_write_queues;
423 bool_Bool queue_size;
424 bool_Bool reconnect_delay;
425 bool_Bool tls;
426 bool_Bool tls_key;
427 bool_Bool tos;
428 bool_Bool traddr;
429 bool_Bool transport;
430 bool_Bool trsvcid;
431};
432
433struct libnvme_global_ctx { // !generate-python:alias=GlobalCtx
434 char *config_file;
435 char *owner; /* orchestrator identity; NULL = unowned */
436 struct list_head endpoints; /* MI endpoints */
437 struct list_head hosts;
438 struct libnvme_log log;
439 bool_Bool mi_probe_enabled;
440 bool_Bool ioctl_probing;
441 bool_Bool create_only;
442 bool_Bool dry_run;
443#ifdef CONFIG_FABRICS
444 struct libnvme_fabric_options *options;
445 struct ifaddrs *ifaddrs_cache; /* init with libnvmf_getifaddrs() */
446#endif
447};
448int libnvme_set_attr(const char *dir, const char *attr, const char *value);
449
450int json_read_config(struct libnvme_global_ctx *ctx, const char *config_file);
451
452int json_update_config(struct libnvme_global_ctx *ctx, int fd);
453
454int json_dump_tree(struct libnvme_global_ctx *ctx);
455
456void *__libnvme_submit_entry(struct libnvme_transport_handle *hdl,
457 struct libnvme_passthru_cmd *cmd);
458void __libnvme_submit_exit(struct libnvme_transport_handle *hdl,
459 struct libnvme_passthru_cmd *cmd, int err, void *user_data);
460bool_Bool __libnvme_decide_retry(struct libnvme_transport_handle *hdl,
461 struct libnvme_passthru_cmd *cmd, int err);
462
463#ifdef CONFIG_MI
464struct nvme_mi_msg_hdr;
465
466void *__libnvme_mi_submit_entry(struct libnvme_mi_ep *ep,
467 __u8 type, const struct nvme_mi_msg_hdr *hdr,
468 size_t hdr_len, const void *data, size_t data_len);
469void __libnvme_mi_submit_exit(struct libnvme_mi_ep *ep,
470 __u8 type, const struct nvme_mi_msg_hdr *hdr,
471 size_t hdr_len, const void *data, size_t data_len,
472 void *user_data);
473#endif
474
475struct libnvme_transport_handle *__libnvme_open(struct libnvme_global_ctx *ctx,
476 const char *name);
477struct libnvme_transport_handle *__libnvme_create_transport_handle(
478 struct libnvme_global_ctx *ctx);
479
480int libnvme_create_ctrl(struct libnvme_global_ctx *ctx,
481 const struct libnvme_ctrl_params *params,
482 struct libnvme_ctrl **cp);
483void nvme_deconfigure_ctrl(struct libnvme_ctrl *c);
484
485struct libnvme_host *libnvme_lookup_host(struct libnvme_global_ctx *ctx,
486 const char *hostnqn, const char *hostid);
487struct libnvme_subsystem *libnvme_lookup_subsystem(struct libnvme_host *h,
488 const char *name, const char *subsysnqn);
489struct libnvme_ctrl *libnvme_lookup_ctrl(struct libnvme_subsystem *s,
490 const struct libnvme_ctrl_params *params,
491 struct libnvme_ctrl *p);
492bool_Bool traddr_is_hostname(struct libnvme_global_ctx *ctx,
493 const char *transport, const char *traddr);
494void libnvmf_default_config(struct libnvme_fabrics_config *cfg);
495libnvme_ctrl_t libnvme_ctrl_find(libnvme_subsystem_t s,
496 const struct libnvme_ctrl_params *params, libnvme_ctrl_t p);
497void libnvmf_read_sysfs_fabrics_attrs(struct libnvme_global_ctx *ctx,
498 libnvme_ctrl_t c);
499
500void __libnvme_free_host(struct libnvme_host * h);
501
502#if (LOG_FUNCNAME == 1)
503#define __libnvme_log_func((void*)0) __func__
504#else
505#define __libnvme_log_func((void*)0) NULL((void*)0)
506#endif
507
508#if (defined(__MINGW32__) || defined(__MINGW64__)) && defined(__GNUC__4)
509/* MinGW GCC requires gnu_printf to correctly validates C99 formats like %zu. */
510#define __libnvme_printf_format(f, a)__attribute__((format(printf, f, a))) __attribute__((format(gnu_printf, f, a)))
511#else
512#define __libnvme_printf_format(f, a)__attribute__((format(printf, f, a))) __attribute__((format(printf, f, a)))
513#endif
514
515void __libnvme_printf_format(4, 5)__attribute__((format(printf, 4, 5)))
516__libnvme_msg(struct libnvme_global_ctx *ctx, int level,
517 const char *func, const char *format, ...);
518
519#define libnvme_msg(ctx, level, format, ...)__libnvme_msg(ctx, level, ((void*)0), format, ...) \
520 __libnvme_msg(ctx, level, __libnvme_log_func((void*)0), format, ##__VA_ARGS__)
521
522#define SECTOR_SIZE512 512
523#define SECTOR_SHIFT9 9
524
525int __libnvme_import_keys_from_config(struct libnvme_host *h,
526 struct libnvme_ctrl *c, long *keyring_id, long *key_id);
527
528static inline char *xstrdup(const char *s)
529{
530 if (!s)
14
Assuming 's' is non-null
15
Taking false branch
531 return NULL((void*)0);
532 return strdup(s);
16
Memory is allocated
533}
534
535static inline bool_Bool streq0(const char *s1, const char *s2)
536{
537 if (s1 == s2)
538 return true1;
539 if (!s1 || !s2)
540 return false0;
541 return !strcmp(s1, s2);
542}
543
544static inline bool_Bool streqcase0(const char *s1, const char *s2)
545{
546 if (s1 == s2)
547 return true1;
548 if (!s1 || !s2)
549 return false0;
550 return !strcasecmp(s1, s2);
551}
552
553/**
554 * libnvme_ipaddrs_eq - Check if 2 IP addresses are equal.
555 * @addr1: IP address (can be IPv4 or IPv6)
556 * @addr2: IP address (can be IPv4 or IPv6)
557 *
558 * Return: true if addr1 == addr2. false otherwise.
559 */
560bool_Bool libnvme_ipaddrs_eq(const char *addr1, const char *addr2);
561
562#if defined(NVME_HAVE_NETDB) || defined(CONFIG_FABRICS)
563/**
564 * libnvme_iface_matching_addr - Get interface matching @addr
565 * @iface_list: Interface list returned by getifaddrs()
566 * @addr: Address to match
567 *
568 * Parse the interface list pointed to by @iface_list looking
569 * for the interface that has @addr as one of its assigned
570 * addresses.
571 *
572 * Return: The name of the interface that owns @addr or NULL.
573 */
574const char *libnvme_iface_matching_addr(const struct ifaddrs *iface_list,
575 const char *addr);
576
577/**
578 * libnvme_iface_primary_addr_matches - Check that interface's primary
579 * address matches
580 * @iface_list: Interface list returned by getifaddrs()
581 * @iface: Interface to match
582 * @addr: Address to match
583 *
584 * Parse the interface list pointed to by @iface_list and looking for
585 * interface @iface. The get its primary address and check if it matches
586 * @addr.
587 *
588 * Return: true if a match is found, false otherwise.
589 */
590bool_Bool libnvme_iface_primary_addr_matches(const struct ifaddrs *iface_list,
591 const char *iface, const char *addr);
592#endif /* NVME_HAVE_NETDB || CONFIG_FABRICS */
593
594int hostname2traddr(struct libnvme_global_ctx *ctx, const char *traddr,
595 char **hostname);
596
597/**
598 * startswith - Checks that a string starts with a given prefix.
599 * @s: The string to check
600 * @prefix: A string that @s could be starting with
601 *
602 * Return: If @s starts with @prefix, then return a pointer within @s at
603 * the first character after the matched @prefix. NULL otherwise.
604 */
605char *startswith(const char *s, const char *prefix);
606
607/**
608 * kv_strip - Strip blanks from key value string
609 * @kv: The key-value string to strip
610 *
611 * Strip leading/trailing blanks as well as trailing comments from the
612 * Key=Value string pointed to by @kv.
613 *
614 * Return: A pointer to the stripped string. Note that the original string,
615 * @kv, gets modified.
616 */
617char *kv_strip(char *kv);
618
619/**
620 * kv_keymatch - Look for key in key value string
621 * @kv: The key=value string to search for the presence of @key
622 * @key: The key to look for
623 *
624 * Look for @key in the Key=Value pair pointed to by @k and return a
625 * pointer to the Value if @key is found.
626 *
627 * Check if @kv starts with @key. If it does then make sure that we
628 * have a whole-word match on the @key, and if we do, return a pointer
629 * to the first character of value (i.e. skip leading spaces, tabs,
630 * and equal sign)
631 *
632 * Return: A pointer to the first character of "value" if a match is found.
633 * NULL otherwise.
634 */
635char *kv_keymatch(const char *kv, const char *key);
636
637#define __round_mask(val, mult)((__typeof__(val))((mult)-1)) ((__typeof__(val))((mult)-1))
638
639/**
640 * round_up - Round a value @val to the next multiple specified by @mult.
641 * @val: Value to round
642 * @mult: Multiple to round to.
643 *
644 * usage: int x = round_up(13, sizeof(__u32)); // 13 -> 16
645 */
646#define round_up(val, mult)((((val)-1) | ((__typeof__((val)))(((mult))-1)))+1) ((((val)-1) | __round_mask((val), (mult))((__typeof__((val)))(((mult))-1)))+1)
647
648/**
649 * libnvme_ns_get_transport_handle() - Get associated transport handle
650 * @n: Namespace instance
651 * @hdl: Transport handle
652 *
653 * libnvme will open() the file (if not already opened) and keep
654 * an internal copy of the link handle. Following calls to
655 * this API retrieve the internal cached copy of the link
656 * handle. The file will remain opened and the device handle will
657 * remain cached until the ns object is deleted or
658 * libnvme_ns_release_transport_handle() is called.
659 *
660 * Return: 0 on success, negative error code otherwise.
661 */
662int libnvme_ns_get_transport_handle(struct libnvme_ns *n,
663 struct libnvme_transport_handle **hdl);
664
665/**
666 * libnvme_ns_release_transport_handle() - Free transport handle from ns object
667 * @n: Namespace instance
668 *
669 */
670void libnvme_ns_release_transport_handle(struct libnvme_ns *n);
671
672/**
673 * libnvme_mi_admin_admin_passthru() - Submit an nvme admin passthrough command
674 * @hdl: Transport handle to send command to
675 * @cmd: The nvme admin command to send
676 *
677 * Send a customized NVMe Admin command request message and get the
678 * corresponding response message.
679 *
680 * This interface supports no data, host to controller and controller to
681 * host but it doesn't support bidirectional data transfer.
682 * Also this interface only supports data transfer size range [0, 4096] (bytes)
683 * so the & data_len parameter must be less than 4097.
684 *
685 * Return: The nvme command status if a response was received (see
686 * &enum nvme_status_field) or negative error code otherwise.
687 */
688int libnvme_mi_admin_admin_passthru(struct libnvme_transport_handle *hdl,
689 struct libnvme_passthru_cmd *cmd);
690
691int libnvme_open_uring(struct libnvme_transport_handle *hdl);
692void libnvme_close_uring(struct libnvme_transport_handle *hdl);
693int __libnvme_transport_handle_open_uring(struct libnvme_transport_handle *hdl);