Bug Summary

File:.build-ci/../plugins/lm/lm-nvme.c
Warning:line 360, column 12
Opened stream never closed. Potential resource leak

Annotated Source Code

Press '?' to see keyboard shortcuts

clang -cc1 -cc1 -triple x86_64-redhat-linux-gnu -O3 -analyze -disable-free -clear-ast-before-backend -disable-llvm-verifier -discard-value-names -main-file-name lm-nvme.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 static -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/bin/../lib/clang/22 -include /__w/nvme-cli/nvme-cli/.build-ci/nvme-config.h -I nvme.p -I . -I .. -I src -I ../src -I ccan -I ../ccan -I libnvme/src -I ../libnvme/src -I /usr/include/json-c -D _FILE_OFFSET_BITS=64 -D _GNU_SOURCE -U NDEBUG -internal-isystem /usr/bin/../lib/clang/22/include -internal-isystem /usr/local/include -internal-isystem /usr/bin/../lib/gcc/x86_64-redhat-linux/16/../../../../x86_64-redhat-linux/include -internal-externc-isystem /include -internal-externc-isystem /usr/include -std=gnu11 -ferror-limit 19 -fgnuc-version=4.2.1 -fskip-odr-check-in-gmf -fcolor-diagnostics -vectorize-loops -vectorize-slp -analyzer-opt-analyze-headers -analyzer-output=html -faddrsig -fdwarf2-cfi-asm -o /__w/nvme-cli/nvme-cli/.build-ci/scan-results/2026-10-24-125112-639-1 -x c ../plugins/lm/lm-nvme.c
1// SPDX-License-Identifier: GPL-2.0-or-later
2/*
3 * Copyright (c) 2024 Samsung Electronics Co., LTD.
4 *
5 * Authors: Nate Thornton <n.thornton@samsung.com>
6 */
7
8#include <assert.h>
9#include <errno(*__errno_location ()).h>
10#include <fcntl.h>
11#include <inttypes.h>
12#include <stdio.h>
13#include <stdlib.h>
14#include <string.h>
15#include <sys/stat.h>
16#include <sys/types.h>
17#include <time.h>
18#include <unistd.h>
19
20#include <libnvme.h>
21
22#include <ccan/array_size/array_size.h>
23#include <shared/compiler-attributes-util.h>
24
25#include "global-ctx.h"
26#include "lm-print.h"
27#include "nvme-cmds.h"
28#include "nvme-print.h"
29#include "plugin.h"
30#include "src/cleanup.h"
31
32static inline const char * arg_str(const char * const *strings, size_t array_size, size_t idx)
33{
34 if (idx < array_size && strings[idx])
35 return strings[idx];
36 return "unrecognized";
37}
38
39#define ARGSTR(s, i)arg_str(s, (sizeof(s) / sizeof((s)[0]) + 0), i) arg_str(s, ARRAY_SIZE(s)(sizeof(s) / sizeof((s)[0]) + 0), i)
40
41static int lm_create_cdq(int argc, char **argv, struct command *acmd, struct plugin *plugin)
42{
43 const char *desc = "Create Controller Data Queue for controller of specific type and size";
44 const char *sz = "CDQ Size (in dwords)";
45 const char *cntlid = "Controller ID";
46 const char *qt = "Queue Type (default: 0 = User Data Migration Queue)";
47 const char *consent = "I consent this will not work and understand a CDQ cannot be mapped "
48 "to user space. If I proceed with the creation of a CDQ, the device "
49 "will write to invalid memory, inevitably leading to MMU faults or "
50 "worse.";
51
52 __cleanup_nvme_transport_handle__attribute__((cleanup(cleanup_nvme_transport_handle))) struct libnvme_transport_handle *hdl = NULL((void*)0);
53 __cleanup_nvme_global_ctx__attribute__((cleanup(cleanup_nvme_global_ctx))) struct libnvme_global_ctx *ctx = NULL((void*)0);
54 struct lba_migration_queue_entry_type_0 *queue = NULL((void*)0);
55 __cleanup_huge__attribute__((cleanup(libnvme_free_huge))) struct libnvme_mem_huge mh = { 0, };
56 struct libnvme_passthru_cmd cmd;
57 int err = -1;
58
59 struct config {
60 __u32 sz;
61 __u16 cntlid;
62 __u8 qt;
63 bool_Bool consent;
64 char *file;
65 };
66
67 struct config cfg = {
68 .sz = 0,
69 .cntlid = 0,
70 .qt = 0,
71 .consent = false0,
72 .file = NULL((void*)0),
73 };
74
75 OPT_ARGS(opts)struct argconfig_commandline_options opts[] = {
76 OPT_UINT("size", 's', &cfg.sz, sz){"size", 's', "NUM", CFG_POSITIVE, _Generic(&cfg.sz, uint32_t
* : (&cfg.sz)), ARGCONFIG_ARG_REQUIRED, sz, 0, }
,
77 OPT_SHRT("cntlid", 'c', &cfg.cntlid, cntlid){"cntlid", 'c', "NUM", CFG_SHORT, _Generic(&cfg.cntlid, uint16_t
* : (&cfg.cntlid)), ARGCONFIG_ARG_REQUIRED, cntlid, 0, }
,
78 OPT_BYTE("queue-type", 'q', &cfg.qt, qt){"queue-type", 'q', "NUM", CFG_BYTE, _Generic(&cfg.qt, uint8_t
* : (&cfg.qt)), ARGCONFIG_ARG_REQUIRED, qt, 0, }
,
79 OPT_FLAG("consent", 0, &cfg.consent, consent){"consent", 0, ((void*)0), CFG_FLAG, _Generic(&cfg.consent
, _Bool * : (&cfg.consent)), ARGCONFIG_ARG_NONE, consent,
0, }
,
80 OPT_END(){ ((void*)0) }
81 };
82
83 err = parse_and_open(&ctx, &hdl, argc, argv, desc, opts);
84 if (err)
85 return err;
86
87 if (!consent) {
88 nvme_show_error("ERROR: consent required")nvme_show_message(1, "ERROR: consent required");
89 return -EINVAL22;
90 }
91
92 // Not that it really matters, but we setup memory as if the CDQ can be held
93 // in user space regardless.
94 queue = libnvme_alloc_huge(cfg.sz << 2, &mh);
95 if (!queue) {
96 nvme_show_error("ERROR: libnvme_alloc of size %dB failed %s", cfg.sz << 2,nvme_show_message(1, "ERROR: libnvme_alloc of size %dB failed %s"
, cfg.sz << 2, libnvme_strerror((*__errno_location ()))
)
97 libnvme_strerror(errno))nvme_show_message(1, "ERROR: libnvme_alloc of size %dB failed %s"
, cfg.sz << 2, libnvme_strerror((*__errno_location ()))
)
;
98 return -ENOMEM12;
99 }
100
101 nvme_init_lm_cdq_create(&cmd, NVME_SET(cfg.qt, LM_QT)(((__u32)(cfg.qt) & NVME_LM_QT_MASK) << NVME_LM_QT_SHIFT
)
,
102 cfg.cntlid, cfg.sz, queue);
103 err = libnvme_exec_admin_passthru(hdl, &cmd);
104 if (err < 0)
105 nvme_show_error("ERROR: nvme_lm_cdq() failed: %s", libnvme_strerror(errno))nvme_show_message(1, "ERROR: nvme_lm_cdq() failed: %s", libnvme_strerror
((*__errno_location ())))
;
106 else if (err)
107 nvme_show_status(err);
108 else
109 nvme_show_verbose_result("Create CDQ Successful: CDQID=0x%04x",nvme_show_verbose_message("Create CDQ Successful: CDQID=0x%04x"
, ((((__u32)cmd.result) >> NVME_LM_CREATE_CDQ_CDQID_SHIFT
) & NVME_LM_CREATE_CDQ_CDQID_MASK))
110 NVME_GET((__u32)cmd.result, LM_CREATE_CDQ_CDQID))nvme_show_verbose_message("Create CDQ Successful: CDQID=0x%04x"
, ((((__u32)cmd.result) >> NVME_LM_CREATE_CDQ_CDQID_SHIFT
) & NVME_LM_CREATE_CDQ_CDQID_MASK))
;
111
112 return err;
113}
114
115static int lm_delete_cdq(int argc, char **argv, struct command *acmd, struct plugin *plugin)
116{
117 const char *desc = "Delete Controller Data Queue";
118 const char *cdqid = "Controller Data Queue ID";
119
120 __cleanup_nvme_transport_handle__attribute__((cleanup(cleanup_nvme_transport_handle))) struct libnvme_transport_handle *hdl = NULL((void*)0);
121 __cleanup_nvme_global_ctx__attribute__((cleanup(cleanup_nvme_global_ctx))) struct libnvme_global_ctx *ctx = NULL((void*)0);
122 struct libnvme_passthru_cmd cmd;
123 int err = -1;
124
125 struct config {
126 __u16 cdqid;
127 };
128
129 struct config cfg = {
130 .cdqid = 0
131 };
132
133 OPT_ARGS(opts)struct argconfig_commandline_options opts[] = {
134 OPT_SHRT("cdqid", 'C', &cfg.cdqid, cdqid){"cdqid", 'C', "NUM", CFG_SHORT, _Generic(&cfg.cdqid, uint16_t
* : (&cfg.cdqid)), ARGCONFIG_ARG_REQUIRED, cdqid, 0, }
,
135 OPT_END(){ ((void*)0) }
136 };
137
138 err = parse_and_open(&ctx, &hdl, argc, argv, desc, opts);
139 if (err)
140 return err;
141
142 nvme_init_lm_cdq_delete(&cmd, 0, cfg.cdqid);
143 err = libnvme_exec_admin_passthru(hdl, &cmd);
144 if (err < 0)
145 nvme_show_error("ERROR: nvme_lm_cdq() failed: %s", libnvme_strerror(errno))nvme_show_message(1, "ERROR: nvme_lm_cdq() failed: %s", libnvme_strerror
((*__errno_location ())))
;
146 else if (err > 0)
147 nvme_show_status(err);
148 else
149 nvme_show_verbose_result("Delete CDQ Successful: CDQID=0x%04x", cfg.cdqid)nvme_show_verbose_message("Delete CDQ Successful: CDQID=0x%04x"
, cfg.cdqid)
;
150
151 return err;
152}
153
154static const char * const lm_track_send_select_argstr[] = {
155 [NVME_LM_SEL_LOG_USER_DATA_CHANGES] = "Log User Data Changes",
156 [NVME_LM_SEL_TRACK_MEMORY_CHANGES] = "Track Memory Changes"
157};
158
159static int lm_track_send(int argc, char **argv, struct command *acmd, struct plugin *plugin)
160{
161 const char *desc = "Track Send command used to manage the tracking of information by a "
162 "controller";
163 const char *sel = "Type of management operation to perform\n"
164 " 0h = Log User Data Changes\n"
165 " 1h = Track Memory Changes";
166 const char *mos = "Management operation specific";
167 const char *cdqid = "Controller Data Queue ID";
168 const char *start = "Equivalent to start tracking with defaults";
169 const char *stop = "Equivalent to stop tracking with defaults";
170
171
172 __cleanup_nvme_transport_handle__attribute__((cleanup(cleanup_nvme_transport_handle))) struct libnvme_transport_handle *hdl = NULL((void*)0);
173 __cleanup_nvme_global_ctx__attribute__((cleanup(cleanup_nvme_global_ctx))) struct libnvme_global_ctx *ctx = NULL((void*)0);
174 struct libnvme_passthru_cmd cmd;
175 int err = -1;
176
177 struct config {
178 __u8 sel;
179 __u8 mos;
180 __u16 cdqid;
181 bool_Bool start;
182 bool_Bool stop;
183 };
184
185 struct config cfg = {
186 .sel = 0,
187 .mos = 0,
188 .cdqid = 0,
189 .start = false0,
190 .stop = false0,
191 };
192
193 OPT_ARGS(opts)struct argconfig_commandline_options opts[] = {
194 OPT_BYTE("sel", 's', &cfg.sel, sel){"sel", 's', "NUM", CFG_BYTE, _Generic(&cfg.sel, uint8_t *
: (&cfg.sel)), ARGCONFIG_ARG_REQUIRED, sel, 0, }
,
195 OPT_BYTE("mos", 'm', &cfg.mos, mos){"mos", 'm', "NUM", CFG_BYTE, _Generic(&cfg.mos, uint8_t *
: (&cfg.mos)), ARGCONFIG_ARG_REQUIRED, mos, 0, }
,
196 OPT_SHRT("cdqid", 'C', &cfg.cdqid, cdqid){"cdqid", 'C', "NUM", CFG_SHORT, _Generic(&cfg.cdqid, uint16_t
* : (&cfg.cdqid)), ARGCONFIG_ARG_REQUIRED, cdqid, 0, }
,
197 OPT_FLAG("start", 0, &cfg.start, start){"start", 0, ((void*)0), CFG_FLAG, _Generic(&cfg.start, _Bool
* : (&cfg.start)), ARGCONFIG_ARG_NONE, start, 0, }
,
198 OPT_FLAG("stop", 0, &cfg.stop, stop){"stop", 0, ((void*)0), CFG_FLAG, _Generic(&cfg.stop, _Bool
* : (&cfg.stop)), ARGCONFIG_ARG_NONE, stop, 0, }
,
199 OPT_END(){ ((void*)0) }
200 };
201
202 err = parse_and_open(&ctx, &hdl, argc, argv, desc, opts);
203 if (err)
204 return err;
205
206 if (!argconfig_given(opts, &cfg.sel)) {
207 nvme_show_error("Select field required")nvme_show_message(1, "Select field required");
208 return -EINVAL22;
209 }
210
211 if (cfg.sel != NVME_LM_SEL_LOG_USER_DATA_CHANGES) {
212 nvme_show_error("Unsupported select option %d (%s)", cfg.sel,nvme_show_message(1, "Unsupported select option %d (%s)", cfg
.sel, arg_str(lm_track_send_select_argstr, (sizeof(lm_track_send_select_argstr
) / sizeof((lm_track_send_select_argstr)[0]) + 0), cfg.sel))
213 ARGSTR(lm_track_send_select_argstr, cfg.sel))nvme_show_message(1, "Unsupported select option %d (%s)", cfg
.sel, arg_str(lm_track_send_select_argstr, (sizeof(lm_track_send_select_argstr
) / sizeof((lm_track_send_select_argstr)[0]) + 0), cfg.sel))
;
214 return -EINVAL22;
215 }
216
217 if (cfg.start && cfg.stop) {
218 nvme_show_error("Must select one of start & stop, not both")nvme_show_message(1, "Must select one of start & stop, not both"
)
;
219 return -EINVAL22;
220 } else if (cfg.sel == NVME_LM_SEL_LOG_USER_DATA_CHANGES) {
221 if (cfg.start)
222 cfg.mos = NVME_SET(NVME_LM_LACT_START_LOGGING, LM_LACT)(((__u32)(NVME_LM_LACT_START_LOGGING) & NVME_LM_LACT_MASK
) << NVME_LM_LACT_SHIFT)
;
223 else if (cfg.stop)
224 cfg.mos = NVME_SET(NVME_LM_LACT_STOP_LOGGING, LM_LACT)(((__u32)(NVME_LM_LACT_STOP_LOGGING) & NVME_LM_LACT_MASK)
<< NVME_LM_LACT_SHIFT)
;
225 }
226
227 nvme_init_lm_track_send(&cmd, cfg.sel, cfg.mos, cfg.cdqid, NULL((void*)0), 0);
228 err = libnvme_exec_admin_passthru(hdl, &cmd);
229 if (err < 0)
230 nvme_show_error("ERROR: nvme_lm_track_send() failed %s", libnvme_strerror(errno))nvme_show_message(1, "ERROR: nvme_lm_track_send() failed %s",
libnvme_strerror((*__errno_location ())))
;
231 else if (err)
232 nvme_show_status(err);
233 else
234 nvme_show_verbose_result("Track Send (%s) Successful",nvme_show_verbose_message("Track Send (%s) Successful", arg_str
(lm_track_send_select_argstr, (sizeof(lm_track_send_select_argstr
) / sizeof((lm_track_send_select_argstr)[0]) + 0), cfg.sel))
235 ARGSTR(lm_track_send_select_argstr, cfg.sel))nvme_show_verbose_message("Track Send (%s) Successful", arg_str
(lm_track_send_select_argstr, (sizeof(lm_track_send_select_argstr
) / sizeof((lm_track_send_select_argstr)[0]) + 0), cfg.sel))
;
236
237 return err;
238}
239
240static const char * const lm_migration_send_select_argstr[] = {
241 [NVME_LM_SEL_SUSPEND] = "Suspend",
242 [NVME_LM_SEL_RESUME] = "Resume",
243 [NVME_LM_SEL_SET_CONTROLLER_STATE] = "Set Controller State"
244};
245
246static int lm_migration_send(int argc, char **argv, struct command *acmd, struct plugin *plugin)
247{
248 const char *desc = "Migration Send command is used to manage the migration of a controller";
249 const char *sel = "Select (SEL) the type of management operation to perform "
250 "(CDW10[07:00])\n"
251 " 0h = Suspend\n"
252 " 1h = Resume\n"
253 " 2h = Set Controller State";
254 const char *cntlid = "Controller Identifier (CDW11[15:00])";
255 const char *stype = "Type of suspend (STYPE) (CDW11[23:16]\n"
256 " 0h = Suspend Notification\n"
257 " 1h = Suspend";
258 const char *dudmq = "Delete user data migration queue (DUDMQ) as part of suspend operation "
259 "(CDW11[31])";
260 const char *seqind = "Sequence Indicator (CDW10[17:16])\n"
261 " 0h = Not first not last\n"
262 " 1h = First in two or more\n"
263 " 2h = Last in two or more\n"
264 " 3h = Entire state info";
265 const char *csuuidi = "Controller State UUID Index (CSUUIDI) (CDW11[31:24])";
266 const char *csvi = "Controller State Version Index (CSVI) (CDW11[23:16])";
267 const char *uidx = "UUID Index (UIDX) (CDW14[16:00])";
268 const char *offset = "Controller State Offset";
269 const char *numd = "Number of Dwords (NUMD)";
270 const char *input = "Controller State Data input file";
271
272 __cleanup_nvme_transport_handle__attribute__((cleanup(cleanup_nvme_transport_handle))) struct libnvme_transport_handle *hdl = NULL((void*)0);
273 __cleanup_nvme_global_ctx__attribute__((cleanup(cleanup_nvme_global_ctx))) struct libnvme_global_ctx *ctx = NULL((void*)0);
274 __cleanup_huge__attribute__((cleanup(libnvme_free_huge))) struct libnvme_mem_huge mh = { 0, };
275 __cleanup_file__attribute__((cleanup(shr_cleanup_file))) FILE *file = NULL((void*)0);
276 struct libnvme_passthru_cmd cmd;
277 void *data = NULL((void*)0);
278 int err = -1;
279
280 struct config {
281 __u8 sel;
282 __u16 cntlid;
283 __u8 stype;
284 __u8 seqind;
285 __u8 csuuidi;
286 __u8 csvi;
287 __u8 uidx;
288 __u64 offset;
289 __u32 numd;
290 char *input;
291 bool_Bool dudmq;
292 };
293
294 struct config cfg = {
295 .sel = 0,
296 .cntlid = 0,
297 .stype = 0,
298 .seqind = 0,
299 .csuuidi = 0,
300 .csvi = 0,
301 .uidx = 0,
302 .offset = 0,
303 .numd = 0,
304 .input = NULL((void*)0),
305 .dudmq = false0
306 };
307
308 OPT_ARGS(opts)struct argconfig_commandline_options opts[] = {
309 OPT_BYTE("sel", 's', &cfg.sel, sel){"sel", 's', "NUM", CFG_BYTE, _Generic(&cfg.sel, uint8_t *
: (&cfg.sel)), ARGCONFIG_ARG_REQUIRED, sel, 0, }
,
310 OPT_SHRT("cntlid", 'c', &cfg.cntlid, cntlid){"cntlid", 'c', "NUM", CFG_SHORT, _Generic(&cfg.cntlid, uint16_t
* : (&cfg.cntlid)), ARGCONFIG_ARG_REQUIRED, cntlid, 0, }
,
311 OPT_BYTE("stype", 't', &cfg.stype, stype){"stype", 't', "NUM", CFG_BYTE, _Generic(&cfg.stype, uint8_t
* : (&cfg.stype)), ARGCONFIG_ARG_REQUIRED, stype, 0, }
,
312 OPT_FLAG("dudmq", 'd', &cfg.dudmq, dudmq){"dudmq", 'd', ((void*)0), CFG_FLAG, _Generic(&cfg.dudmq,
_Bool * : (&cfg.dudmq)), ARGCONFIG_ARG_NONE, dudmq, 0, }
,
313 OPT_BYTE("seq-ind", 'S', &cfg.seqind, seqind){"seq-ind", 'S', "NUM", CFG_BYTE, _Generic(&cfg.seqind, uint8_t
* : (&cfg.seqind)), ARGCONFIG_ARG_REQUIRED, seqind, 0, }
,
314 OPT_BYTE("csuuidi", 'U', &cfg.csuuidi, csuuidi){"csuuidi", 'U', "NUM", CFG_BYTE, _Generic(&cfg.csuuidi, uint8_t
* : (&cfg.csuuidi)), ARGCONFIG_ARG_REQUIRED, csuuidi, 0,
}
,
315 OPT_BYTE("csvi", 'V', &cfg.csvi, csvi){"csvi", 'V', "NUM", CFG_BYTE, _Generic(&cfg.csvi, uint8_t
* : (&cfg.csvi)), ARGCONFIG_ARG_REQUIRED, csvi, 0, }
,
316 OPT_BYTE("uidx", 'u', &cfg.uidx, uidx){"uidx", 'u', "NUM", CFG_BYTE, _Generic(&cfg.uidx, uint8_t
* : (&cfg.uidx)), ARGCONFIG_ARG_REQUIRED, uidx, 0, }
,
317 OPT_LONG("offset", 'O', &cfg.offset, offset){"offset", 'O', "NUM", CFG_LONG, _Generic(&cfg.offset, uint64_t
* : (&cfg.offset), default : _Generic(&cfg.offset, unsigned
long long * : (&cfg.offset), default : (void)0)), ARGCONFIG_ARG_REQUIRED
, offset, 0, }
,
318 OPT_UINT("numd", 'n', &cfg.numd, numd){"numd", 'n', "NUM", CFG_POSITIVE, _Generic(&cfg.numd, uint32_t
* : (&cfg.numd)), ARGCONFIG_ARG_REQUIRED, numd, 0, }
,
319 OPT_FILE("input-file", 'f', &cfg.input, input){"input-file", 'f', "FILE", CFG_FILE, _Generic(&cfg.input
, char ** : (&cfg.input), const char ** : (&cfg.input
)), ARGCONFIG_ARG_REQUIRED, input, 0, }
,
320 OPT_END(){ ((void*)0) }
321 };
322
323 err = parse_and_open(&ctx, &hdl, argc, argv, desc, opts);
324 if (err)
1
Assuming 'err' is 0
2
Taking false branch
325 return err;
326
327 if (!argconfig_given(opts, &cfg.sel)) {
3
Assuming the condition is false
328 nvme_show_error("Select field required")nvme_show_message(1, "Select field required");
329 return -EINVAL22;
330 }
331
332 // Sanity check input parameters
333 if (cfg.sel == NVME_LM_SEL_SUSPEND || cfg.sel == NVME_LM_SEL_RESUME) {
4
Assuming field 'sel' is not equal to NVME_LM_SEL_SUSPEND
5
Assuming field 'sel' is not equal to NVME_LM_SEL_RESUME
6
Taking false branch
334 if (cfg.csuuidi != 0 || cfg.csvi != 0) {
335 nvme_show_error("Unexpected fields for %s",nvme_show_message(1, "Unexpected fields for %s", arg_str(lm_migration_send_select_argstr
, (sizeof(lm_migration_send_select_argstr) / sizeof((lm_migration_send_select_argstr
)[0]) + 0), cfg.sel))
336 ARGSTR(lm_migration_send_select_argstr, cfg.sel))nvme_show_message(1, "Unexpected fields for %s", arg_str(lm_migration_send_select_argstr
, (sizeof(lm_migration_send_select_argstr) / sizeof((lm_migration_send_select_argstr
)[0]) + 0), cfg.sel))
;
337 return -EINVAL22;
338 }
339 } else if (cfg.sel == NVME_LM_SEL_SET_CONTROLLER_STATE) {
7
Assuming field 'sel' is not equal to NVME_LM_SEL_SET_CONTROLLER_STATE
340 if (cfg.dudmq || cfg.stype != 0) {
341 nvme_show_error("Unexpected fields for %s",nvme_show_message(1, "Unexpected fields for %s", arg_str(lm_migration_send_select_argstr
, (sizeof(lm_migration_send_select_argstr) / sizeof((lm_migration_send_select_argstr
)[0]) + 0), cfg.sel))
342 ARGSTR(lm_migration_send_select_argstr, cfg.sel))nvme_show_message(1, "Unexpected fields for %s", arg_str(lm_migration_send_select_argstr
, (sizeof(lm_migration_send_select_argstr) / sizeof((lm_migration_send_select_argstr
)[0]) + 0), cfg.sel))
;
343 return -EINVAL22;
344 } else if (!strlen(cfg.input)) {
345 nvme_show_error("Expected file for %s",nvme_show_message(1, "Expected file for %s", arg_str(lm_migration_send_select_argstr
, (sizeof(lm_migration_send_select_argstr) / sizeof((lm_migration_send_select_argstr
)[0]) + 0), cfg.sel))
346 ARGSTR(lm_migration_send_select_argstr, cfg.sel))nvme_show_message(1, "Expected file for %s", arg_str(lm_migration_send_select_argstr
, (sizeof(lm_migration_send_select_argstr) / sizeof((lm_migration_send_select_argstr
)[0]) + 0), cfg.sel))
;
347 return -EINVAL22;
348 }
349 }
350
351 if (cfg.input && strlen(cfg.input)) {
8
Assuming field 'input' is non-null
9
Assuming the condition is true
10
Taking true branch
352 file = fopen(cfg.input, "r");
11
Stream opened here
12
Assuming that 'fopen' is successful
353 if (file
12.1
'file' is not equal to NULL
== NULL((void*)0)) {
13
Taking false branch
354 nvme_show_perror(cfg.input);
355 return -EINVAL22;
356 }
357
358 data = libnvme_alloc_huge(cfg.numd << 2, &mh);
359 if (!data)
14
Assuming 'data' is null
15
Taking true branch
360 return -ENOMEM12;
16
Opened stream never closed. Potential resource leak
361
362 size_t n_data = fread(data, 1, cfg.numd << 2, file);
363
364 if (n_data != (size_t)(cfg.numd << 2)) {
365 nvme_show_error("failed to read controller state data %s", libnvme_strerror(errno))nvme_show_message(1, "failed to read controller state data %s"
, libnvme_strerror((*__errno_location ())))
;
366 return -errno(*__errno_location ());
367 }
368 }
369
370 nvme_init_lm_migration_send(&cmd, cfg.sel,
371 NVME_SET(cfg.seqind, LM_SEQIND)(((__u32)(cfg.seqind) & NVME_LM_SEQIND_MASK) << NVME_LM_SEQIND_SHIFT
)
, cfg.cntlid,
372 cfg.stype, cfg.dudmq, cfg.csvi, cfg.csuuidi,
373 cfg.offset, cfg.uidx, data,
374 (cfg.numd << 2));
375 err = libnvme_exec_admin_passthru(hdl, &cmd);
376 if (err < 0)
377 nvme_show_error("ERROR: nvme_lm_migration_send() failed %s", libnvme_strerror(errno))nvme_show_message(1, "ERROR: nvme_lm_migration_send() failed %s"
, libnvme_strerror((*__errno_location ())))
;
378 else if (err > 0)
379 nvme_show_status(err);
380 else
381 nvme_show_verbose_result("Migration Send (%s) Successful",nvme_show_verbose_message("Migration Send (%s) Successful", arg_str
(lm_migration_send_select_argstr, (sizeof(lm_migration_send_select_argstr
) / sizeof((lm_migration_send_select_argstr)[0]) + 0), cfg.sel
))
382 ARGSTR(lm_migration_send_select_argstr, cfg.sel))nvme_show_verbose_message("Migration Send (%s) Successful", arg_str
(lm_migration_send_select_argstr, (sizeof(lm_migration_send_select_argstr
) / sizeof((lm_migration_send_select_argstr)[0]) + 0), cfg.sel
))
;
383
384
385 return err;
386}
387
388static int lm_migration_recv(int argc, char **argv, struct command *acmd, struct plugin *plugin)
389{
390 const char *desc = "Migration Receive command is used to obtain information used to manage "
391 " a migratable controller";
392 const char *sel = "Select (SEL) the type of management operation to perform "
393 "(CDW10[07:00])\n"
394 " 0h = Get Controller State";
395 const char *cntlid = "Controller Identifier (CDW10[31:16])";
396 const char *csuuidi = "Controller State UUID Index (CSUUIDI) (CDW11[23:16])";
397 const char *csvi = "Controller State Version Index (CSVI) (CDW11[7:0])";
398 const char *uidx = "UUID Index (UIDX) (CDW14[16:00])";
399 const char *offset = "Controller State Offset";
400 const char *numd = "Number of Dwords (NUMD)";
401 const char *output = "Controller State Data output file";
402
403 __cleanup_nvme_transport_handle__attribute__((cleanup(cleanup_nvme_transport_handle))) struct libnvme_transport_handle *hdl = NULL((void*)0);
404 __cleanup_nvme_global_ctx__attribute__((cleanup(cleanup_nvme_global_ctx))) struct libnvme_global_ctx *ctx = NULL((void*)0);
405 __cleanup_huge__attribute__((cleanup(libnvme_free_huge))) struct libnvme_mem_huge mh = { 0, };
406 __cleanup_file__attribute__((cleanup(shr_cleanup_file))) FILE *fd = NULL((void*)0);
407 struct libnvme_passthru_cmd cmd;
408 nvme_print_flags_t flags;
409 void *data = NULL((void*)0);
410 int err = -1;
411 __u16 mos;
412
413 struct config {
414 __u8 sel;
415 __u16 cntlid;
416 __u8 csuuidi;
417 __u8 csvi;
418 __u8 uidx;
419 __u64 offset;
420 __u32 numd;
421 char *output;
422 };
423
424 struct config cfg = {
425 .sel = 0,
426 .cntlid = 0,
427 .csuuidi = 0,
428 .csvi = 0,
429 .uidx = 0,
430 .offset = 0,
431 .numd = 0,
432 .output = NULL((void*)0),
433 };
434
435 OPT_ARGS(opts)struct argconfig_commandline_options opts[] = {
436 OPT_BYTE("sel", 's', &cfg.sel, sel){"sel", 's', "NUM", CFG_BYTE, _Generic(&cfg.sel, uint8_t *
: (&cfg.sel)), ARGCONFIG_ARG_REQUIRED, sel, 0, }
,
437 OPT_SHRT("cntlid", 'c', &cfg.cntlid, cntlid){"cntlid", 'c', "NUM", CFG_SHORT, _Generic(&cfg.cntlid, uint16_t
* : (&cfg.cntlid)), ARGCONFIG_ARG_REQUIRED, cntlid, 0, }
,
438 OPT_BYTE("csuuidi", 'U', &cfg.csuuidi, csuuidi){"csuuidi", 'U', "NUM", CFG_BYTE, _Generic(&cfg.csuuidi, uint8_t
* : (&cfg.csuuidi)), ARGCONFIG_ARG_REQUIRED, csuuidi, 0,
}
,
439 OPT_BYTE("csvi", 'V', &cfg.csvi, csvi){"csvi", 'V', "NUM", CFG_BYTE, _Generic(&cfg.csvi, uint8_t
* : (&cfg.csvi)), ARGCONFIG_ARG_REQUIRED, csvi, 0, }
,
440 OPT_BYTE("uidx", 'u', &cfg.uidx, uidx){"uidx", 'u', "NUM", CFG_BYTE, _Generic(&cfg.uidx, uint8_t
* : (&cfg.uidx)), ARGCONFIG_ARG_REQUIRED, uidx, 0, }
,
441 OPT_LONG("offset", 'O', &cfg.offset, offset){"offset", 'O', "NUM", CFG_LONG, _Generic(&cfg.offset, uint64_t
* : (&cfg.offset), default : _Generic(&cfg.offset, unsigned
long long * : (&cfg.offset), default : (void)0)), ARGCONFIG_ARG_REQUIRED
, offset, 0, }
,
442 OPT_UINT("numd", 'n', &cfg.numd, numd){"numd", 'n', "NUM", CFG_POSITIVE, _Generic(&cfg.numd, uint32_t
* : (&cfg.numd)), ARGCONFIG_ARG_REQUIRED, numd, 0, }
,
443 OPT_FILE("output-file", 'f', &cfg.output, output){"output-file", 'f', "FILE", CFG_FILE, _Generic(&cfg.output
, char ** : (&cfg.output), const char ** : (&cfg.output
)), ARGCONFIG_ARG_REQUIRED, output, 0, }
,
444 OPT_END(){ ((void*)0) }
445 };
446
447 err = parse_and_open(&ctx, &hdl, argc, argv, desc, opts);
448 if (err)
449 return err;
450
451 if (!argconfig_given(opts, &cfg.sel)) {
452 nvme_show_error("Select field required")nvme_show_message(1, "Select field required");
453 return -EINVAL22;
454 }
455
456 flags = nvme_args.output_flags;
457
458 if (nvme_args.output_format && cfg.offset != 0 && !(flags & BINARY)) {
459 nvme_show_error("cannot parse non-zero offset")nvme_show_message(1, "cannot parse non-zero offset");
460 return -EINVAL22;
461 }
462
463 if (nvme_args.verbose)
464 flags |= VERBOSE;
465
466 if (cfg.output && strlen(cfg.output)) {
467 fd = fopen(cfg.output, "w");
468 if (!fd) {
469 nvme_show_perror(cfg.output);
470 return -errno(*__errno_location ());
471 }
472 }
473
474 data = libnvme_alloc_huge((cfg.numd + 1) << 2, &mh);
475 if (!data)
476 return -ENOMEM12;
477
478 mos = NVME_SET(cfg.csvi, LM_GET_CONTROLLER_STATE_CSVI)(((__u32)(cfg.csvi) & NVME_LM_GET_CONTROLLER_STATE_CSVI_MASK
) << NVME_LM_GET_CONTROLLER_STATE_CSVI_SHIFT)
;
479 nvme_init_lm_migration_recv(&cmd, cfg.offset, mos, cfg.cntlid,
480 cfg.csuuidi, cfg.sel, cfg.uidx, 0, data,
481 (cfg.numd + 1) << 2);
482 err = libnvme_exec_admin_passthru(hdl, &cmd);
483 if (err < 0)
484 nvme_show_error("ERROR: nvme_lm_migration_recv() failed %s", libnvme_strerror(errno))nvme_show_message(1, "ERROR: nvme_lm_migration_recv() failed %s"
, libnvme_strerror((*__errno_location ())))
;
485 else if (err)
486 nvme_show_status(err);
487 else if (cfg.sel == NVME_LM_SEL_GET_CONTROLLER_STATE) {
488 if (flags == NORMAL)
489 printf("CDW0: 0x%"PRIu64"l" "u"": Controller %sSuspended\n",
490 (uint64_t)cmd.result,
491 (cmd.result & NVME_LM_GET_CONTROLLER_STATE_CSUP) ?
492 "" : "NOT ");
493
494 if (cfg.output && strlen(cfg.output)) {
495 if (fwrite(data, 1, cfg.numd << 2, fd) != (cfg.numd << 2)) {
496 nvme_show_error("ERROR: %s: failed to write buffer to output file",nvme_show_message(1, "ERROR: %s: failed to write buffer to output file"
, libnvme_strerror((*__errno_location ())))
497 libnvme_strerror(errno))nvme_show_message(1, "ERROR: %s: failed to write buffer to output file"
, libnvme_strerror((*__errno_location ())))
;
498 err = -errno(*__errno_location ());
499 }
500 } else {
501 lm_show_controller_state_data((struct nvme_lm_controller_state_data *)data,
502 (cfg.numd + 1) << 2, cfg.offset, flags);
503 }
504 }
505
506 return err;
507}
508
509enum lm_controller_data_queue_feature_id {
510 lm_cdq_feature_id = 0x21
511};
512
513static int lm_set_cdq(int argc, char **argv, struct command *acmd, struct plugin *plugin)
514{
515 const char *desc = "This Feature allows a host to update the status of the head pointer "
516 "of a CDQ and specify the configuration of a CDQ Tail event.";
517 const char *cdqid = "Controller Data Queue ID";
518 const char *hp = "The slot of the head pointer for the specified CDQ";
519 const char *tpt = "If specified, the slot that causes the controller "
520 " to issue a CDQ Tail Pointer event";
521
522 __cleanup_nvme_global_ctx__attribute__((cleanup(cleanup_nvme_global_ctx))) struct libnvme_global_ctx *ctx = NULL((void*)0);
523 __cleanup_nvme_transport_handle__attribute__((cleanup(cleanup_nvme_transport_handle))) struct libnvme_transport_handle *hdl = NULL((void*)0);
524 int err = -1;
525
526 struct config {
527 __u16 cdqid;
528 __u32 hp;
529 __u32 tpt;
530 };
531
532 struct config cfg = {
533 .cdqid = 0,
534 .hp = 0,
535 .tpt = 0,
536 };
537
538 OPT_ARGS(opts)struct argconfig_commandline_options opts[] = {
539 OPT_SHRT("cdqid", 'C', &cfg.cdqid, cdqid){"cdqid", 'C', "NUM", CFG_SHORT, _Generic(&cfg.cdqid, uint16_t
* : (&cfg.cdqid)), ARGCONFIG_ARG_REQUIRED, cdqid, 0, }
,
540 OPT_UINT("hp", 0, &cfg.hp, hp){"hp", 0, "NUM", CFG_POSITIVE, _Generic(&cfg.hp, uint32_t
* : (&cfg.hp)), ARGCONFIG_ARG_REQUIRED, hp, 0, }
,
541 OPT_UINT("tpt", 'T', &cfg.tpt, tpt){"tpt", 'T', "NUM", CFG_POSITIVE, _Generic(&cfg.tpt, uint32_t
* : (&cfg.tpt)), ARGCONFIG_ARG_REQUIRED, tpt, 0, }
,
542 OPT_END(){ ((void*)0) }
543 };
544
545 err = parse_and_open(&ctx, &hdl, argc, argv, desc, opts);
546 if (err)
547 return err;
548
549 err = nvme_set_features(hdl, 0, lm_cdq_feature_id, 0, cfg.cdqid |
550 (argconfig_given(opts, &cfg.tpt) ?
551 NVME_SET(1, LM_CTRL_DATA_QUEUE_ETPT)(((__u32)(1) & NVME_LM_CTRL_DATA_QUEUE_ETPT_MASK) <<
NVME_LM_CTRL_DATA_QUEUE_ETPT_SHIFT)
: 0),
552 cfg.hp, cfg.tpt, 0, 0, NULL((void*)0), 0, NULL((void*)0));
553 if (err < 0)
554 nvme_show_error("ERROR: nvme_set_features() failed %s", libnvme_strerror(errno))nvme_show_message(1, "ERROR: nvme_set_features() failed %s", libnvme_strerror
((*__errno_location ())))
;
555 else if (err)
556 nvme_show_status(err);
557 else
558 nvme_show_verbose_result("Success. Head Pointer: %d", cfg.hp)nvme_show_verbose_message("Success. Head Pointer: %d", cfg.hp
)
;
559
560 return err;
561}
562
563static int lm_get_cdq(int argc, char **argv, struct command *acmd, struct plugin *plugin)
564{
565 const char *desc = "This Feature allows a host to retrieve the status of the head pointer "
566 "of a CDQ and specify the configuration of a CDQ Tail event.";
567 const char *cdqid = "Controller Data Queue ID";
568
569 __cleanup_nvme_global_ctx__attribute__((cleanup(cleanup_nvme_global_ctx))) struct libnvme_global_ctx *ctx = NULL((void*)0);
570 __cleanup_nvme_transport_handle__attribute__((cleanup(cleanup_nvme_transport_handle))) struct libnvme_transport_handle *hdl = NULL((void*)0);
571 nvme_print_flags_t flags;
572 int err = -1;
573
574 struct config {
575 __u16 cdqid;
576 };
577
578 struct config cfg = {
579 .cdqid = 0,
580 };
581
582 OPT_ARGS(opts)struct argconfig_commandline_options opts[] = {
583 OPT_SHRT("cdqid", 'C', &cfg.cdqid, cdqid){"cdqid", 'C', "NUM", CFG_SHORT, _Generic(&cfg.cdqid, uint16_t
* : (&cfg.cdqid)), ARGCONFIG_ARG_REQUIRED, cdqid, 0, }
,
584 OPT_END(){ ((void*)0) }
585 };
586
587 err = parse_and_open(&ctx, &hdl, argc, argv, desc, opts);
588 if (err)
589 return err;
590
591 flags = nvme_args.output_flags;
592
593 struct nvme_lm_ctrl_data_queue_fid_data data;
594
595 err = nvme_get_features(hdl, 0, lm_cdq_feature_id, 0, cfg.cdqid, 0,
596 &data, sizeof(data), NULL((void*)0));
597 if (err < 0)
598 nvme_show_error("ERROR: nvme_get_features() failed %s", libnvme_strerror(errno))nvme_show_message(1, "ERROR: nvme_get_features() failed %s", libnvme_strerror
((*__errno_location ())))
;
599 else if (err)
600 nvme_show_status(err);
601 else
602 lm_show_controller_data_queue(&data, flags);
603
604 return err;
605}
606
607static struct command lm_create_cdq_cmd = {
608 .name = "create-cdq",
609 .help = "Create Controller Data Queue",
610 .fn = lm_create_cdq,
611};
612
613static struct command lm_delete_cdq_cmd = {
614 .name = "delete-cdq",
615 .help = "Delete Controller Data Queue",
616 .fn = lm_delete_cdq,
617};
618
619static struct command lm_track_send_cmd = {
620 .name = "track-send",
621 .help = "Track Send Command",
622 .fn = lm_track_send,
623};
624
625static struct command lm_migration_send_cmd = {
626 .name = "migration-send",
627 .help = "Migration Send",
628 .fn = lm_migration_send,
629};
630
631static struct command lm_migration_recv_cmd = {
632 .name = "migration-recv",
633 .help = "Migration Receive",
634 .fn = lm_migration_recv,
635};
636
637static struct command lm_set_cdq_cmd = {
638 .name = "set-cdq",
639 .help = "Set Feature - Controller Data Queue (FID 21h)",
640 .fn = lm_set_cdq,
641};
642
643static struct command lm_get_cdq_cmd = {
644 .name = "get-cdq",
645 .help = "Get Feature - Controller Data Queue (FID 21h)",
646 .fn = lm_get_cdq,
647};
648
649static struct command *commands[] = {
650 &lm_create_cdq_cmd,
651 &lm_delete_cdq_cmd,
652 &lm_track_send_cmd,
653 &lm_migration_send_cmd,
654 &lm_migration_recv_cmd,
655 &lm_set_cdq_cmd,
656 &lm_get_cdq_cmd,
657 NULL((void*)0),
658};
659
660static struct plugin plugin = {
661 .name = "lm",
662 .desc = "Live Migration NVMe extensions",
663 .version = NVME_VERSION"3.1",
664 .core = true1,
665 .group = "Controller Management",
666};
667
668static void __shr_constructor__attribute__((constructor)) register_plugin(void)
669{
670 plugin_add_group(&plugin, NULL((void*)0), commands);
671 register_extension(&plugin);
672}