Branch data Line data Source code
1 : : /* SPDX-License-Identifier: BSD-3-Clause
2 : : * Copyright (C) 2016 Intel Corporation. All rights reserved.
3 : : * Copyright (c) 2019 Mellanox Technologies LTD. All rights reserved.
4 : : */
5 : :
6 : : #include "spdk/stdinc.h"
7 : :
8 : : #include "spdk/nvme.h"
9 : : #include "spdk/nvme_zns.h"
10 : : #include "spdk/vmd.h"
11 : : #include "spdk/env.h"
12 : : #include "spdk/string.h"
13 : : #include "spdk/log.h"
14 : : #include "spdk/likely.h"
15 : : #include "spdk/endian.h"
16 : : #include "spdk/dif.h"
17 : : #include "spdk/util.h"
18 : : #include "spdk/trace.h"
19 : :
20 : : #include "config-host.h"
21 : : #include "fio.h"
22 : : #include "optgroup.h"
23 : :
24 : : #ifdef for_each_rw_ddir
25 : : #define FIO_HAS_ZBD (FIO_IOOPS_VERSION >= 26)
26 : : #define FIO_HAS_FDP (FIO_IOOPS_VERSION >= 32)
27 : : #define FIO_HAS_MRT (FIO_IOOPS_VERSION >= 34)
28 : : #else
29 : : #define FIO_HAS_ZBD (0)
30 : : #define FIO_HAS_FDP (0)
31 : : #define FIO_HAS_MRT (0)
32 : : #endif
33 : :
34 : : /* FreeBSD is missing CLOCK_MONOTONIC_RAW,
35 : : * so alternative is provided. */
36 : : #ifndef CLOCK_MONOTONIC_RAW /* Defined in glibc bits/time.h */
37 : : #define CLOCK_MONOTONIC_RAW CLOCK_MONOTONIC
38 : : #endif
39 : :
40 : : #define NVME_IO_ALIGN 4096
41 : :
42 : : static bool g_spdk_env_initialized;
43 : : static bool g_log_flag_error;
44 : : static int g_spdk_enable_sgl = 0;
45 : : static uint32_t g_spdk_sge_size = 4096;
46 : : static uint32_t g_spdk_bit_bucket_data_len = 0;
47 : : static uint32_t g_spdk_pract_flag;
48 : : static uint32_t g_spdk_prchk_flags;
49 : : static uint32_t g_spdk_md_per_io_size = 4096;
50 : : static uint16_t g_spdk_apptag;
51 : : static uint16_t g_spdk_apptag_mask;
52 : :
53 : : struct spdk_fio_options {
54 : : void *pad; /* off1 used in option descriptions may not be 0 */
55 : : int enable_wrr;
56 : : int arbitration_burst;
57 : : int low_weight;
58 : : int medium_weight;
59 : : int high_weight;
60 : : int wrr_priority;
61 : : int mem_size;
62 : : int shm_id;
63 : : int enable_sgl;
64 : : int sge_size;
65 : : int bit_bucket_data_len;
66 : : char *hostnqn;
67 : : int pi_act;
68 : : char *pi_chk;
69 : : int md_per_io_size;
70 : : int apptag;
71 : : int apptag_mask;
72 : : char *digest_enable;
73 : : int enable_vmd;
74 : : int initial_zone_reset;
75 : : int zone_append;
76 : : int print_qid_mappings;
77 : : int spdk_tracing;
78 : : char *log_flags;
79 : : };
80 : :
81 : : struct spdk_fio_request {
82 : : struct io_u *io;
83 : : /** Offset in current iovec, fio only uses 1 vector */
84 : : uint32_t iov_offset;
85 : :
86 : : /** Amount of data used for Bit Bucket SGL */
87 : : uint32_t bit_bucket_data_len;
88 : :
89 : : /** Context for NVMe PI */
90 : : struct spdk_dif_ctx dif_ctx;
91 : : /** Separate metadata buffer pointer */
92 : : void *md_buf;
93 : :
94 : : /** Dataset management range information */
95 : : struct spdk_nvme_dsm_range *dsm_range;
96 : :
97 : : struct spdk_fio_thread *fio_thread;
98 : : struct spdk_fio_qpair *fio_qpair;
99 : : };
100 : :
101 : : struct spdk_fio_ctrlr {
102 : : struct spdk_nvme_transport_id tr_id;
103 : : struct spdk_nvme_ctrlr_opts opts;
104 : : struct spdk_nvme_ctrlr *ctrlr;
105 : : TAILQ_ENTRY(spdk_fio_ctrlr) link;
106 : : };
107 : :
108 : : static TAILQ_HEAD(, spdk_fio_ctrlr) g_ctrlrs = TAILQ_HEAD_INITIALIZER(g_ctrlrs);
109 : : static int g_td_count;
110 : : static pthread_t g_ctrlr_thread_id = 0;
111 : : static pthread_mutex_t g_mutex = PTHREAD_MUTEX_INITIALIZER;
112 : : static bool g_error;
113 : :
114 : : struct spdk_fio_qpair {
115 : : struct fio_file *f;
116 : : struct spdk_nvme_qpair *qpair;
117 : : struct spdk_nvme_ns *ns;
118 : : uint32_t io_flags;
119 : : bool zone_append_enabled;
120 : : bool nvme_pi_enabled;
121 : : /* True for DIF and false for DIX, and this is valid only if nvme_pi_enabled is true. */
122 : : bool extended_lba;
123 : : /* True for protection info transferred at start of metadata,
124 : : * false for protection info transferred at end of metadata, and
125 : : * this is valid only if nvme_pi_enabled is true.
126 : : */
127 : : bool md_start;
128 : : TAILQ_ENTRY(spdk_fio_qpair) link;
129 : : struct spdk_fio_ctrlr *fio_ctrlr;
130 : : };
131 : :
132 : : struct spdk_fio_thread {
133 : : struct thread_data *td;
134 : :
135 : : TAILQ_HEAD(, spdk_fio_qpair) fio_qpair;
136 : : struct spdk_fio_qpair *fio_qpair_current; /* the current fio_qpair to be handled. */
137 : :
138 : : struct io_u **iocq; /* io completion queue */
139 : : unsigned int iocq_count; /* number of iocq entries filled by last getevents */
140 : : unsigned int iocq_size; /* number of iocq entries allocated */
141 : :
142 : : };
143 : :
144 : : struct spdk_fio_probe_ctx {
145 : : struct thread_data *td;
146 : : char hostnqn[SPDK_NVMF_NQN_MAX_LEN + 1];
147 : : struct fio_file *f; /* fio_file given by user */
148 : : };
149 : :
150 : : static void *
151 : 18 : spdk_fio_poll_ctrlrs(void *arg)
152 : : {
153 : : struct spdk_fio_ctrlr *fio_ctrlr;
154 : 6 : int oldstate;
155 : : int rc;
156 : :
157 : : /* Loop until the thread is cancelled */
158 : : while (true) {
159 : 62 : rc = pthread_setcancelstate(PTHREAD_CANCEL_DISABLE, &oldstate);
160 [ - + ]: 62 : if (rc != 0) {
161 : 0 : SPDK_ERRLOG("Unable to set cancel state disabled on g_init_thread (%d): %s\n",
162 : : rc, spdk_strerror(rc));
163 : : }
164 : :
165 [ - + ]: 62 : pthread_mutex_lock(&g_mutex);
166 : :
167 [ + + ]: 99 : TAILQ_FOREACH(fio_ctrlr, &g_ctrlrs, link) {
168 : 37 : spdk_nvme_ctrlr_process_admin_completions(fio_ctrlr->ctrlr);
169 : : }
170 : :
171 [ - + ]: 62 : pthread_mutex_unlock(&g_mutex);
172 : :
173 : 62 : rc = pthread_setcancelstate(PTHREAD_CANCEL_ENABLE, &oldstate);
174 [ - + ]: 62 : if (rc != 0) {
175 : 0 : SPDK_ERRLOG("Unable to set cancel state enabled on g_init_thread (%d): %s\n",
176 : : rc, spdk_strerror(rc));
177 : : }
178 : :
179 : : /* This is a pthread cancellation point and cannot be removed. */
180 : 62 : sleep(1);
181 : : }
182 : :
183 : : return NULL;
184 : : }
185 : :
186 : : static bool
187 : 18 : probe_cb(void *cb_ctx, const struct spdk_nvme_transport_id *trid,
188 : : struct spdk_nvme_ctrlr_opts *opts)
189 : : {
190 : 18 : struct spdk_fio_probe_ctx *ctx = cb_ctx;
191 : 18 : struct thread_data *td = ctx->td;
192 : 18 : struct spdk_fio_options *fio_options = td->eo;
193 : :
194 [ - + ]: 18 : if (ctx->hostnqn[0] != '\0') {
195 [ # # # # ]: 0 : memcpy(opts->hostnqn, ctx->hostnqn, sizeof(opts->hostnqn));
196 [ - + ]: 18 : } else if (fio_options->hostnqn) {
197 : 0 : snprintf(opts->hostnqn, sizeof(opts->hostnqn), "%s", fio_options->hostnqn);
198 : : }
199 : :
200 [ - + ]: 18 : if (fio_options->enable_wrr) {
201 : 0 : opts->arb_mechanism = SPDK_NVME_CC_AMS_WRR;
202 : 0 : opts->arbitration_burst = fio_options->arbitration_burst;
203 : 0 : opts->low_priority_weight = fio_options->low_weight;
204 : 0 : opts->medium_priority_weight = fio_options->medium_weight;
205 : 0 : opts->high_priority_weight = fio_options->high_weight;
206 : : }
207 : :
208 [ - + ]: 18 : if (fio_options->digest_enable) {
209 [ # # # # ]: 0 : if (strcasecmp(fio_options->digest_enable, "HEADER") == 0) {
210 : 0 : opts->header_digest = true;
211 [ # # # # ]: 0 : } else if (strcasecmp(fio_options->digest_enable, "DATA") == 0) {
212 : 0 : opts->data_digest = true;
213 [ # # # # ]: 0 : } else if (strcasecmp(fio_options->digest_enable, "BOTH") == 0) {
214 : 0 : opts->header_digest = true;
215 : 0 : opts->data_digest = true;
216 : : }
217 : : }
218 : :
219 : 18 : return true;
220 : : }
221 : :
222 : : static struct spdk_fio_ctrlr *
223 : 36 : get_fio_ctrlr(const struct spdk_nvme_transport_id *trid)
224 : : {
225 : : struct spdk_fio_ctrlr *fio_ctrlr;
226 : :
227 [ - + ]: 36 : TAILQ_FOREACH(fio_ctrlr, &g_ctrlrs, link) {
228 [ # # ]: 0 : if (spdk_nvme_transport_id_compare(trid, &fio_ctrlr->tr_id) == 0) {
229 : 0 : return fio_ctrlr;
230 : : }
231 : : }
232 : :
233 : 36 : return NULL;
234 : : }
235 : :
236 : : /**
237 : : * Returns the fio_qpair matching the given fio_file and has an associated ns
238 : : */
239 : : static struct spdk_fio_qpair *
240 : 1337630 : get_fio_qpair(struct spdk_fio_thread *fio_thread, struct fio_file *f)
241 : : {
242 : : struct spdk_fio_qpair *fio_qpair;
243 : :
244 [ + - ]: 1337630 : TAILQ_FOREACH(fio_qpair, &fio_thread->fio_qpair, link) {
245 [ + - + - ]: 1337630 : if ((fio_qpair->f == f) && fio_qpair->ns) {
246 : 1337630 : return fio_qpair;
247 : : }
248 : : }
249 : :
250 : 0 : return NULL;
251 : : }
252 : :
253 : : #if FIO_HAS_ZBD
254 : : /**
255 : : * Callback function to use while processing completions until completion-indicator turns non-zero
256 : : */
257 : : static void
258 : 0 : pcu_cb(void *ctx, const struct spdk_nvme_cpl *cpl)
259 : : {
260 : 0 : int *completed = ctx;
261 : :
262 [ # # # # ]: 0 : *completed = spdk_nvme_cpl_is_error(cpl) ? -1 : 1;
263 : 0 : }
264 : :
265 : : /**
266 : : * Process Completions Until the given 'completed' indicator turns non-zero or an error occurs
267 : : */
268 : : static int32_t
269 : 0 : pcu(struct spdk_nvme_qpair *qpair, int *completed)
270 : : {
271 : : int32_t ret;
272 : :
273 [ # # ]: 0 : while (!*completed) {
274 : 0 : ret = spdk_nvme_qpair_process_completions(qpair, 1);
275 [ # # ]: 0 : if (ret < 0) {
276 : 0 : log_err("spdk/nvme: process_compl(): ret: %d\n", ret);
277 : 0 : return ret;
278 : : }
279 : : }
280 : :
281 : 0 : return 0;
282 : : }
283 : : #endif
284 : :
285 : : static inline uint32_t
286 : 1337648 : _nvme_get_host_buffer_sector_size(struct spdk_nvme_ns *ns, uint32_t io_flags)
287 : : {
288 : 1337648 : bool md_excluded_from_xfer = false;
289 : : uint32_t md_size;
290 : : uint32_t ns_flags;
291 : :
292 : 1337648 : ns_flags = spdk_nvme_ns_get_flags(ns);
293 : 1337648 : md_size = spdk_nvme_ns_get_md_size(ns);
294 : :
295 : : /* For extended LBA format, if the metadata size is 8 bytes and PRACT is
296 : : * enabled(controller inserts/strips PI), we should reduce metadata size
297 : : * from block size.
298 : : */
299 : 2675296 : md_excluded_from_xfer = ((io_flags & SPDK_NVME_IO_FLAGS_PRACT) &&
300 [ # # ]: 0 : (ns_flags & SPDK_NVME_NS_EXTENDED_LBA_SUPPORTED) &&
301 [ - + - - : 1337648 : (ns_flags & SPDK_NVME_NS_DPS_PI_SUPPORTED) &&
- - ]
302 : : (md_size == 8));
303 : :
304 [ - + ]: 2675296 : return md_excluded_from_xfer ? spdk_nvme_ns_get_sector_size(ns) :
305 : 1337648 : spdk_nvme_ns_get_extended_sector_size(ns);
306 : : }
307 : :
308 : : static void
309 : 18 : attach_cb(void *cb_ctx, const struct spdk_nvme_transport_id *trid,
310 : : struct spdk_nvme_ctrlr *ctrlr, const struct spdk_nvme_ctrlr_opts *opts)
311 : : {
312 : 18 : struct spdk_fio_probe_ctx *ctx = cb_ctx;
313 : 18 : struct thread_data *td = ctx->td;
314 : 18 : struct spdk_fio_thread *fio_thread = td->io_ops_data;
315 : : struct spdk_fio_ctrlr *fio_ctrlr;
316 : : struct spdk_fio_qpair *fio_qpair;
317 : : struct spdk_nvme_ns *ns;
318 : : const struct spdk_nvme_ns_data *nsdata;
319 : 18 : struct fio_file *f = ctx->f;
320 : : uint32_t ns_id;
321 : : char *p;
322 : : long int tmp;
323 : : uint32_t block_size;
324 : 18 : struct spdk_fio_options *fio_options = td->eo;
325 : :
326 [ - + ]: 18 : p = strstr(f->file_name, "ns=");
327 [ + + ]: 18 : if (p != NULL) {
328 : 8 : tmp = spdk_strtol(p + 3, 10);
329 [ - + ]: 8 : if (tmp <= 0) {
330 : 0 : SPDK_ERRLOG("namespace id should be >=1, but was invalid: %ld\n", tmp);
331 : 0 : g_error = true;
332 : 0 : return;
333 : : }
334 : 8 : ns_id = (uint32_t)tmp;
335 : : } else {
336 : 10 : ns_id = spdk_nvme_ctrlr_get_first_active_ns(ctrlr);
337 [ - + ]: 10 : if (ns_id == 0) {
338 : : /* The ctrlr has no active namespaces and we didn't specify any so nothing to do. */
339 : 0 : return;
340 : : }
341 : : }
342 : :
343 : 18 : pthread_mutex_lock(&g_mutex);
344 : 18 : fio_ctrlr = get_fio_ctrlr(trid);
345 : : /* it is a new ctrlr and needs to be added */
346 [ + - ]: 18 : if (!fio_ctrlr) {
347 : : /* Create an fio_ctrlr and add it to the list */
348 : 18 : fio_ctrlr = calloc(1, sizeof(*fio_ctrlr));
349 [ - + ]: 18 : if (!fio_ctrlr) {
350 : 0 : SPDK_ERRLOG("Cannot allocate space for fio_ctrlr\n");
351 : 0 : g_error = true;
352 : 0 : pthread_mutex_unlock(&g_mutex);
353 : 0 : return;
354 : : }
355 : 18 : fio_ctrlr->opts = *opts;
356 : 18 : fio_ctrlr->ctrlr = ctrlr;
357 : 18 : fio_ctrlr->tr_id = *trid;
358 : 18 : TAILQ_INSERT_TAIL(&g_ctrlrs, fio_ctrlr, link);
359 : : }
360 : 18 : pthread_mutex_unlock(&g_mutex);
361 : :
362 : 18 : ns = spdk_nvme_ctrlr_get_ns(fio_ctrlr->ctrlr, ns_id);
363 [ - + ]: 18 : if (ns == NULL) {
364 : 0 : SPDK_ERRLOG("Cannot get namespace by ns_id=%d\n", ns_id);
365 : 0 : g_error = true;
366 : 0 : return;
367 : : }
368 : :
369 [ - + ]: 18 : if (!spdk_nvme_ns_is_active(ns)) {
370 : 0 : SPDK_ERRLOG("Inactive namespace by ns_id=%d\n", ns_id);
371 : 0 : g_error = true;
372 : 0 : return;
373 : : }
374 : 18 : nsdata = spdk_nvme_ns_get_data(ns);
375 : :
376 [ - + ]: 18 : TAILQ_FOREACH(fio_qpair, &fio_thread->fio_qpair, link) {
377 [ # # # # ]: 0 : if ((fio_qpair->f == f) ||
378 [ # # ]: 0 : ((spdk_nvme_transport_id_compare(trid, &fio_qpair->fio_ctrlr->tr_id) == 0) &&
379 : 0 : (spdk_nvme_ns_get_id(fio_qpair->ns) == ns_id))) {
380 : : /* Not the error case. Avoid duplicated connection */
381 : 0 : return;
382 : : }
383 : : }
384 : :
385 : : /* create a new qpair */
386 : 18 : fio_qpair = calloc(1, sizeof(*fio_qpair));
387 [ - + ]: 18 : if (!fio_qpair) {
388 : 0 : g_error = true;
389 : 0 : SPDK_ERRLOG("Cannot allocate space for fio_qpair\n");
390 : 0 : return;
391 : : }
392 : :
393 : 18 : f->engine_data = fio_qpair;
394 : 18 : fio_qpair->ns = ns;
395 : 18 : fio_qpair->f = f;
396 : 18 : fio_qpair->fio_ctrlr = fio_ctrlr;
397 : 18 : TAILQ_INSERT_TAIL(&fio_thread->fio_qpair, fio_qpair, link);
398 : :
399 [ - + ]: 18 : if (spdk_nvme_ns_get_flags(ns) & SPDK_NVME_NS_DPS_PI_SUPPORTED) {
400 [ # # ]: 0 : assert(spdk_nvme_ns_get_pi_type(ns) != SPDK_NVME_FMT_NVM_PROTECTION_DISABLE);
401 : 0 : fio_qpair->io_flags = g_spdk_pract_flag | g_spdk_prchk_flags;
402 : 0 : fio_qpair->nvme_pi_enabled = true;
403 : 0 : fio_qpair->md_start = nsdata->dps.md_start;
404 : 0 : fio_qpair->extended_lba = spdk_nvme_ns_supports_extended_lba(ns);
405 [ # # ]: 0 : fprintf(stdout, "PI type%u enabled with %s\n", spdk_nvme_ns_get_pi_type(ns),
406 [ # # # # ]: 0 : fio_qpair->extended_lba ? "extended lba" : "separate metadata");
407 : : }
408 : :
409 : 18 : block_size = _nvme_get_host_buffer_sector_size(ns, fio_qpair->io_flags);
410 [ + + ]: 72 : for_each_rw_ddir(ddir) {
411 [ + + + + : 54 : if (td->o.min_bs[ddir] % block_size != 0 || td->o.max_bs[ddir] % block_size != 0) {
- + - + ]
412 [ # # ]: 0 : if (spdk_nvme_ns_supports_extended_lba(ns)) {
413 : 0 : SPDK_ERRLOG("--bs or other block size related option has to be a multiple of (LBA data size + Metadata size)\n");
414 : : } else {
415 : 0 : SPDK_ERRLOG("--bs or other block size related option has to be a multiple of LBA data size\n");
416 : : }
417 : 0 : g_error = true;
418 : 0 : return;
419 : : }
420 : : }
421 : :
422 [ - + - - ]: 18 : if (fio_options->zone_append && spdk_nvme_ns_get_csi(ns) == SPDK_NVME_CSI_ZNS) {
423 [ # # ]: 0 : if (spdk_nvme_ctrlr_get_flags(ctrlr) & SPDK_NVME_CTRLR_ZONE_APPEND_SUPPORTED) {
424 [ # # # # ]: 0 : SPDK_DEBUGLOG(fio_nvme, "Using zone appends instead of writes on: '%s'\n",
425 : : f->file_name);
426 : 0 : fio_qpair->zone_append_enabled = true;
427 : : } else {
428 : 0 : SPDK_WARNLOG("Falling back to writes on: '%s' - ns lacks zone append cmd\n",
429 : : f->file_name);
430 : : }
431 : : }
432 : :
433 : : #if FIO_HAS_ZBD
434 [ - + - - ]: 18 : if (td_trim(td) && td->o.zone_mode == ZONE_MODE_ZBD) {
435 : 0 : td->io_ops->flags |= FIO_ASYNCIO_SYNC_TRIM;
436 : : }
437 : : #endif
438 : :
439 [ - + - - ]: 18 : if (fio_options->initial_zone_reset == 1 && spdk_nvme_ns_get_csi(ns) == SPDK_NVME_CSI_ZNS) {
440 : : #if FIO_HAS_ZBD
441 : : struct spdk_nvme_qpair *tmp_qpair;
442 : 0 : int completed = 0, err;
443 : :
444 : : /* qpair has not been allocated yet (it gets allocated in spdk_fio_open()).
445 : : * Create a temporary qpair in order to perform the initial zone reset.
446 : : */
447 [ # # ]: 0 : assert(!fio_qpair->qpair);
448 : :
449 : 0 : tmp_qpair = spdk_nvme_ctrlr_alloc_io_qpair(ctrlr, NULL, 0);
450 [ # # ]: 0 : if (!tmp_qpair) {
451 : 0 : SPDK_ERRLOG("Cannot allocate a temporary qpair\n");
452 : 0 : g_error = true;
453 : 0 : return;
454 : : }
455 : :
456 : 0 : err = spdk_nvme_zns_reset_zone(ns, tmp_qpair, 0x0, true, pcu_cb, &completed);
457 [ # # # # : 0 : if (err || pcu(tmp_qpair, &completed) || completed < 0) {
# # ]
458 : 0 : log_err("spdk/nvme: warn: initial_zone_reset: err: %d, cpl: %d\n",
459 : : err, completed);
460 : : }
461 : :
462 : 0 : spdk_nvme_ctrlr_free_io_qpair(tmp_qpair);
463 : : #else
464 : : log_err("spdk/nvme: ZBD/ZNS is not supported\n");
465 : : #endif
466 : : }
467 : :
468 : 18 : f->real_file_size = spdk_nvme_ns_get_size(fio_qpair->ns);
469 [ - + ]: 18 : if (f->real_file_size <= 0) {
470 : 0 : g_error = true;
471 : 0 : SPDK_ERRLOG("Cannot get namespace size by ns=%p\n", ns);
472 : 0 : return;
473 : : }
474 : :
475 : 18 : f->filetype = FIO_TYPE_BLOCK;
476 : 18 : fio_file_set_size_known(f);
477 : : }
478 : :
479 : : static void
480 : 18 : parse_prchk_flags(const char *prchk_str)
481 : : {
482 [ + - ]: 18 : if (!prchk_str) {
483 : 18 : return;
484 : : }
485 : :
486 [ # # # # ]: 0 : if (strstr(prchk_str, "GUARD") != NULL) {
487 : 0 : g_spdk_prchk_flags = SPDK_NVME_IO_FLAGS_PRCHK_GUARD;
488 : : }
489 [ # # # # ]: 0 : if (strstr(prchk_str, "REFTAG") != NULL) {
490 : 0 : g_spdk_prchk_flags |= SPDK_NVME_IO_FLAGS_PRCHK_REFTAG;
491 : : }
492 [ # # # # ]: 0 : if (strstr(prchk_str, "APPTAG") != NULL) {
493 : 0 : g_spdk_prchk_flags |= SPDK_NVME_IO_FLAGS_PRCHK_APPTAG;
494 : : }
495 : : }
496 : :
497 : : static void
498 : 18 : parse_pract_flag(int pract)
499 : : {
500 [ + - ]: 18 : if (pract == 1) {
501 : 18 : g_spdk_pract_flag = SPDK_NVME_IO_FLAGS_PRACT;
502 : : } else {
503 : 0 : g_spdk_pract_flag = 0;
504 : : }
505 : 18 : }
506 : :
507 : : static bool
508 : 0 : fio_redirected_to_dev_null(void)
509 : : {
510 : 0 : char path[PATH_MAX] = "";
511 : : ssize_t ret;
512 : :
513 : 0 : ret = readlink("/proc/self/fd/1", path, sizeof(path));
514 : :
515 [ # # # # ]: 0 : if (ret == -1 || strcmp(path, "/dev/null") != 0) {
516 : 0 : return false;
517 : : }
518 : :
519 : 0 : ret = readlink("/proc/self/fd/2", path, sizeof(path));
520 : :
521 [ # # # # ]: 0 : if (ret == -1 || strcmp(path, "/dev/null") != 0) {
522 : 0 : return false;
523 : : }
524 : :
525 : 0 : return true;
526 : : }
527 : :
528 : : static int
529 : 18 : spdk_fio_init(struct thread_data *td)
530 : : {
531 : 18 : int ret = 0;
532 : 18 : struct spdk_fio_options *fio_options = td->eo;
533 : :
534 [ - + ]: 18 : if (fio_options->spdk_tracing) {
535 : 0 : ret = spdk_trace_register_user_thread();
536 : : }
537 : :
538 : 18 : return ret;
539 : : }
540 : :
541 : : /* Called once at initialization. This is responsible for gathering the size of
542 : : * each "file", which in our case are in the form
543 : : * 'key=value [key=value] ... ns=value'
544 : : * For example, For local PCIe NVMe device - 'trtype=PCIe traddr=0000.04.00.0 ns=1'
545 : : * For remote exported by NVMe-oF target, 'trtype=RDMA adrfam=IPv4 traddr=192.168.100.8 trsvcid=4420 ns=1' */
546 : : static int
547 : 18 : spdk_fio_setup(struct thread_data *td)
548 : : {
549 : : struct spdk_fio_thread *fio_thread;
550 : 18 : struct spdk_fio_options *fio_options = td->eo;
551 : 6 : struct spdk_fio_probe_ctx ctx;
552 : 6 : struct spdk_env_opts opts;
553 : : struct fio_file *f;
554 : : char *p;
555 : 18 : int rc = 0;
556 : 6 : struct spdk_nvme_transport_id trid;
557 : : struct spdk_fio_ctrlr *fio_ctrlr;
558 : : char *trid_info;
559 : : unsigned int i;
560 : : size_t size;
561 : :
562 : : /*
563 : : * If we're running in a daemonized FIO instance, it's possible
564 : : * fd 1/2 were re-used for something important by FIO. Newer fio
565 : : * versions are careful to redirect those to /dev/null, but if we're
566 : : * not, we'll abort early, so we don't accidentally write messages to
567 : : * an important file, etc.
568 : : */
569 [ - + - + : 18 : if (is_backend && !fio_redirected_to_dev_null()) {
- - ]
570 : 0 : char buf[1024];
571 : 0 : snprintf(buf, sizeof(buf),
572 : : "SPDK FIO plugin is in daemon mode, but stdout/stderr "
573 : : "aren't redirected to /dev/null. Aborting.");
574 : 0 : fio_server_text_output(FIO_LOG_ERR, buf, sizeof(buf));
575 : 0 : return -1;
576 : : }
577 : :
578 [ - + ]: 18 : if (!td->o.use_thread) {
579 : 0 : log_err("spdk: must set thread=1 when using spdk plugin\n");
580 : 0 : return 1;
581 : : }
582 : :
583 [ - + - + ]: 18 : if (g_log_flag_error) {
584 : : /* The first thread found an error when parsing log flags, so
585 : : * just return error immediately for all of the other threads.
586 : : */
587 : 0 : return 1;
588 : : }
589 : :
590 : 18 : pthread_mutex_lock(&g_mutex);
591 : :
592 : 18 : fio_thread = calloc(1, sizeof(*fio_thread));
593 [ - + ]: 18 : assert(fio_thread != NULL);
594 : :
595 : 18 : td->io_ops_data = fio_thread;
596 : 18 : fio_thread->td = td;
597 : :
598 : 18 : fio_thread->iocq_size = td->o.iodepth;
599 : 18 : fio_thread->iocq = calloc(fio_thread->iocq_size, sizeof(struct io_u *));
600 [ - + ]: 18 : assert(fio_thread->iocq != NULL);
601 : :
602 : 18 : TAILQ_INIT(&fio_thread->fio_qpair);
603 : :
604 [ + + + - ]: 18 : if (!g_spdk_env_initialized) {
605 : 18 : spdk_env_opts_init_ext(&opts, sizeof(opts));
606 : 18 : opts.name = "fio";
607 : 18 : opts.mem_size = fio_options->mem_size;
608 : 18 : opts.shm_id = fio_options->shm_id;
609 : 18 : g_spdk_enable_sgl = fio_options->enable_sgl;
610 : 18 : g_spdk_sge_size = fio_options->sge_size;
611 : 18 : g_spdk_bit_bucket_data_len = fio_options->bit_bucket_data_len;
612 : 18 : parse_pract_flag(fio_options->pi_act);
613 : 18 : g_spdk_md_per_io_size = spdk_max(fio_options->md_per_io_size, 4096);
614 : 18 : g_spdk_apptag = (uint16_t)fio_options->apptag;
615 : 18 : g_spdk_apptag_mask = (uint16_t)fio_options->apptag_mask;
616 : 18 : parse_prchk_flags(fio_options->pi_chk);
617 [ - + ]: 18 : if (spdk_env_init_ext(&opts) < 0) {
618 : 0 : SPDK_ERRLOG("Unable to initialize SPDK env\n");
619 : 0 : free(fio_thread->iocq);
620 : 0 : free(fio_thread);
621 : 0 : fio_thread = NULL;
622 : 0 : pthread_mutex_unlock(&g_mutex);
623 : 0 : return 1;
624 : : }
625 : :
626 [ - + ]: 18 : if (fio_options->log_flags) {
627 : 0 : char *tok = strtok(fio_options->log_flags, ",");
628 : : do {
629 : 0 : rc = spdk_log_set_flag(tok);
630 [ # # ]: 0 : if (rc < 0) {
631 : 0 : SPDK_ERRLOG("unknown log flag %s\n", tok);
632 : 0 : g_log_flag_error = true;
633 : 0 : return 1;
634 : : }
635 [ # # ]: 0 : } while ((tok = strtok(NULL, ",")) != NULL);
636 : : #ifdef DEBUG
637 : 0 : spdk_log_set_print_level(SPDK_LOG_DEBUG);
638 : : #endif
639 : : }
640 : :
641 : 18 : g_spdk_env_initialized = true;
642 : 18 : spdk_unaffinitize_thread();
643 : :
644 [ - + ]: 18 : if (fio_options->spdk_tracing) {
645 : 0 : spdk_trace_init("spdk_fio_tracepoints", 65536, td->o.numjobs);
646 : 0 : spdk_trace_enable_tpoint_group("nvme_pcie");
647 : 0 : spdk_trace_enable_tpoint_group("nvme_tcp");
648 : : }
649 : :
650 : : /* Spawn a thread to continue polling the controllers */
651 : 18 : rc = pthread_create(&g_ctrlr_thread_id, NULL, &spdk_fio_poll_ctrlrs, NULL);
652 [ - + ]: 18 : if (rc != 0) {
653 : 0 : SPDK_ERRLOG("Unable to spawn a thread to poll admin queues. They won't be polled.\n");
654 : : }
655 : :
656 [ - + - - ]: 18 : if (fio_options->enable_vmd && spdk_vmd_init()) {
657 : 0 : SPDK_ERRLOG("Failed to initialize VMD. Some NVMe devices can be unavailable.\n");
658 : : }
659 : : }
660 : 18 : pthread_mutex_unlock(&g_mutex);
661 : :
662 [ + - + + : 36 : for_each_file(td, f, i) {
+ - ]
663 : 18 : memset(&trid, 0, sizeof(trid));
664 : 18 : memset(&ctx, 0, sizeof(ctx));
665 : :
666 : 18 : trid.trtype = SPDK_NVME_TRANSPORT_PCIE;
667 : :
668 [ - + ]: 18 : p = strstr(f->file_name, " ns=");
669 [ + + ]: 18 : if (p != NULL) {
670 [ - + ]: 8 : trid_info = strndup(f->file_name, p - f->file_name);
671 : : } else {
672 [ - + - + ]: 10 : trid_info = strndup(f->file_name, strlen(f->file_name));
673 : : }
674 : :
675 [ - + ]: 18 : if (!trid_info) {
676 : 0 : SPDK_ERRLOG("Failed to allocate space for trid_info\n");
677 : 0 : continue;
678 : : }
679 : :
680 : 18 : rc = spdk_nvme_transport_id_parse(&trid, trid_info);
681 [ - + ]: 18 : if (rc < 0) {
682 : 0 : SPDK_ERRLOG("Failed to parse given str: %s\n", trid_info);
683 : 0 : free(trid_info);
684 : 0 : continue;
685 : : }
686 : 18 : free(trid_info);
687 : :
688 [ + + ]: 18 : if (trid.trtype == SPDK_NVME_TRANSPORT_PCIE) {
689 : 6 : struct spdk_pci_addr pci_addr;
690 [ - + ]: 10 : if (spdk_pci_addr_parse(&pci_addr, trid.traddr) < 0) {
691 : 0 : SPDK_ERRLOG("Invalid traddr=%s\n", trid.traddr);
692 : 0 : continue;
693 : : }
694 : 10 : spdk_pci_addr_fmt(trid.traddr, sizeof(trid.traddr), &pci_addr);
695 : : } else {
696 [ + - ]: 8 : if (trid.subnqn[0] == '\0') {
697 : 8 : snprintf(trid.subnqn, sizeof(trid.subnqn), "%s",
698 : : SPDK_NVMF_DISCOVERY_NQN);
699 : : }
700 [ - + + - ]: 8 : if ((p = strcasestr(f->file_name, "hostnqn:")) ||
701 [ - + - + ]: 8 : (p = strcasestr(f->file_name, "hostnqn="))) {
702 : 0 : p += strlen("hostnqn:");
703 [ # # ]: 0 : size = strcspn(p, " \t\n");
704 [ # # ]: 0 : if (size > sizeof(ctx.hostnqn)) {
705 : 0 : SPDK_ERRLOG("Invalid hostnqn: too long\n");
706 : 0 : continue;
707 : : }
708 [ # # ]: 0 : memcpy(ctx.hostnqn, p, size);
709 : : }
710 : : }
711 : :
712 : 18 : ctx.td = td;
713 : 18 : ctx.f = f;
714 : :
715 : 18 : pthread_mutex_lock(&g_mutex);
716 : 18 : fio_ctrlr = get_fio_ctrlr(&trid);
717 : 18 : pthread_mutex_unlock(&g_mutex);
718 [ - + ]: 18 : if (fio_ctrlr) {
719 : 0 : attach_cb(&ctx, &trid, fio_ctrlr->ctrlr, &fio_ctrlr->opts);
720 : : } else {
721 : : /* Enumerate all of the controllers */
722 [ - + ]: 18 : if (spdk_nvme_probe(&trid, &ctx, probe_cb, attach_cb, NULL) != 0) {
723 : 0 : SPDK_ERRLOG("spdk_nvme_probe() failed\n");
724 : 0 : continue;
725 : : }
726 : : }
727 : :
728 [ - + - + ]: 18 : if (g_error) {
729 : 0 : log_err("Failed to initialize spdk fio plugin\n");
730 : 0 : rc = 1;
731 : 0 : break;
732 : : }
733 : : }
734 : :
735 : 18 : pthread_mutex_lock(&g_mutex);
736 : 18 : g_td_count++;
737 : 18 : pthread_mutex_unlock(&g_mutex);
738 : :
739 : 18 : return rc;
740 : : }
741 : :
742 : : static int
743 : 38 : spdk_fio_open(struct thread_data *td, struct fio_file *f)
744 : : {
745 : 38 : struct spdk_fio_qpair *fio_qpair = f->engine_data;
746 : 38 : struct spdk_fio_ctrlr *fio_ctrlr = fio_qpair->fio_ctrlr;
747 : 38 : struct spdk_fio_options *fio_options = td->eo;
748 : 6 : struct spdk_nvme_io_qpair_opts qpopts;
749 : :
750 [ - + ]: 38 : assert(fio_qpair->qpair == NULL);
751 : 38 : spdk_nvme_ctrlr_get_default_io_qpair_opts(fio_ctrlr->ctrlr, &qpopts, sizeof(qpopts));
752 : 38 : qpopts.delay_cmd_submit = true;
753 [ - + ]: 38 : if (fio_options->enable_wrr) {
754 : 0 : qpopts.qprio = fio_options->wrr_priority;
755 : : }
756 : :
757 : 38 : fio_qpair->qpair = spdk_nvme_ctrlr_alloc_io_qpair(fio_ctrlr->ctrlr, &qpopts, sizeof(qpopts));
758 [ - + ]: 38 : if (!fio_qpair->qpair) {
759 : 0 : SPDK_ERRLOG("Cannot allocate nvme io_qpair any more\n");
760 : 0 : g_error = true;
761 : 0 : free(fio_qpair);
762 : 0 : return -1;
763 : : }
764 : :
765 [ - + ]: 38 : if (fio_options->print_qid_mappings == 1) {
766 : 0 : log_info("job %s: %s qid %d\n", td->o.name, f->file_name,
767 : 0 : spdk_nvme_qpair_get_id(fio_qpair->qpair));
768 : : }
769 : :
770 : 38 : return 0;
771 : : }
772 : :
773 : : static int
774 : 38 : spdk_fio_close(struct thread_data *td, struct fio_file *f)
775 : : {
776 : 38 : struct spdk_fio_qpair *fio_qpair = f->engine_data;
777 : :
778 [ - + ]: 38 : assert(fio_qpair->qpair != NULL);
779 : 38 : spdk_nvme_ctrlr_free_io_qpair(fio_qpair->qpair);
780 : 38 : fio_qpair->qpair = NULL;
781 : 38 : return 0;
782 : : }
783 : :
784 : : static int
785 : 18 : spdk_fio_iomem_alloc(struct thread_data *td, size_t total_mem)
786 : : {
787 : 18 : struct spdk_fio_thread *fio_thread = td->io_ops_data;
788 : : struct spdk_fio_qpair *fio_qpair;
789 : : struct spdk_nvme_ctrlr *ctrlr;
790 : 18 : uint32_t socket_id = SPDK_ENV_SOCKET_ID_ANY, tmp_socket_id;
791 : :
792 : : /* If all ctrlrs used by this fio_thread have the same numa socket
793 : : * id, allocate from that socket. If they come from different numa
794 : : * sockets, then don't try to optimize and just use SOCKET_ID_ANY.
795 : : */
796 [ + + ]: 36 : TAILQ_FOREACH(fio_qpair, &fio_thread->fio_qpair, link) {
797 : 18 : ctrlr = fio_qpair->fio_ctrlr->ctrlr;
798 : 18 : tmp_socket_id = spdk_nvme_ctrlr_get_socket_id(ctrlr);
799 [ + - ]: 18 : if (socket_id == (uint32_t)SPDK_ENV_SOCKET_ID_ANY) {
800 : 18 : socket_id = tmp_socket_id;
801 [ # # # # ]: 0 : } else if (tmp_socket_id != socket_id ||
802 : : tmp_socket_id == (uint32_t)SPDK_ENV_SOCKET_ID_ANY) {
803 : 0 : socket_id = SPDK_ENV_SOCKET_ID_ANY;
804 : 0 : break;
805 : : }
806 : : }
807 : :
808 : 18 : td->orig_buffer = spdk_dma_zmalloc_socket(total_mem, NVME_IO_ALIGN, NULL, socket_id);
809 : 18 : return td->orig_buffer == NULL;
810 : : }
811 : :
812 : : static void
813 : 18 : spdk_fio_iomem_free(struct thread_data *td)
814 : : {
815 : 18 : spdk_dma_free(td->orig_buffer);
816 : 18 : }
817 : :
818 : : static int
819 : 2304 : spdk_fio_io_u_init(struct thread_data *td, struct io_u *io_u)
820 : : {
821 : 2304 : struct spdk_fio_thread *fio_thread = td->io_ops_data;
822 : : struct spdk_fio_request *fio_req;
823 : : uint32_t dsm_size;
824 : :
825 : 2304 : io_u->engine_data = NULL;
826 : :
827 : 2304 : fio_req = calloc(1, sizeof(*fio_req));
828 [ - + ]: 2304 : if (fio_req == NULL) {
829 : 0 : return 1;
830 : : }
831 : :
832 [ + - ]: 2304 : if (!(td->io_ops->flags & FIO_ASYNCIO_SYNC_TRIM)) {
833 : : #if FIO_HAS_MRT
834 : : /* By default number of range is set to 1 */
835 : : dsm_size = td->o.num_range * sizeof(struct spdk_nvme_dsm_range);
836 : : #else
837 : 2304 : dsm_size = sizeof(struct spdk_nvme_dsm_range);
838 : : #endif
839 : 2304 : fio_req->dsm_range = calloc(1, dsm_size);
840 [ - + ]: 2304 : if (fio_req->dsm_range == NULL) {
841 : 0 : free(fio_req);
842 : 0 : return 1;
843 : : }
844 : : }
845 : :
846 : 2304 : fio_req->md_buf = spdk_dma_zmalloc(g_spdk_md_per_io_size, NVME_IO_ALIGN, NULL);
847 [ - + ]: 2304 : if (fio_req->md_buf == NULL) {
848 [ # # # # ]: 0 : fprintf(stderr, "Allocate %u metadata failed\n", g_spdk_md_per_io_size);
849 : 0 : free(fio_req->dsm_range);
850 : 0 : free(fio_req);
851 : 0 : return 1;
852 : : }
853 : :
854 : 2304 : fio_req->io = io_u;
855 : 2304 : fio_req->fio_thread = fio_thread;
856 : :
857 : 2304 : io_u->engine_data = fio_req;
858 : :
859 : 2304 : return 0;
860 : : }
861 : :
862 : : static void
863 : 2304 : spdk_fio_io_u_free(struct thread_data *td, struct io_u *io_u)
864 : : {
865 : 2304 : struct spdk_fio_request *fio_req = io_u->engine_data;
866 : :
867 [ + - ]: 2304 : if (fio_req) {
868 [ - + ]: 2304 : assert(fio_req->io == io_u);
869 : 2304 : spdk_dma_free(fio_req->md_buf);
870 : 2304 : free(fio_req->dsm_range);
871 : 2304 : free(fio_req);
872 : 2304 : io_u->engine_data = NULL;
873 : : }
874 : 2304 : }
875 : :
876 : : static inline uint64_t
877 : 0 : fio_offset_to_zslba(unsigned long long offset, struct spdk_nvme_ns *ns)
878 : : {
879 [ # # ]: 0 : return (offset / spdk_nvme_zns_ns_get_zone_size(ns)) * spdk_nvme_zns_ns_get_zone_size_sectors(ns);
880 : : }
881 : :
882 : : static int
883 : 0 : fio_extended_lba_setup_pi(struct spdk_fio_qpair *fio_qpair, struct io_u *io_u)
884 : : {
885 : 0 : struct spdk_nvme_ns *ns = fio_qpair->ns;
886 : 0 : struct spdk_fio_request *fio_req = io_u->engine_data;
887 : : uint32_t md_size, extended_lba_size, lba_count;
888 : : uint64_t lba;
889 : 0 : struct iovec iov;
890 : : int rc;
891 : 0 : struct spdk_dif_ctx_init_ext_opts dif_opts;
892 : :
893 : : /* Set appmask and apptag when PRACT is enabled */
894 [ # # ]: 0 : if (fio_qpair->io_flags & SPDK_NVME_IO_FLAGS_PRACT) {
895 : 0 : fio_req->dif_ctx.apptag_mask = g_spdk_apptag_mask;
896 : 0 : fio_req->dif_ctx.app_tag = g_spdk_apptag;
897 : 0 : return 0;
898 : : }
899 : :
900 : 0 : extended_lba_size = spdk_nvme_ns_get_extended_sector_size(ns);
901 : 0 : md_size = spdk_nvme_ns_get_md_size(ns);
902 [ # # ]: 0 : lba = io_u->offset / extended_lba_size;
903 [ # # ]: 0 : lba_count = io_u->xfer_buflen / extended_lba_size;
904 : :
905 : 0 : dif_opts.size = SPDK_SIZEOF(&dif_opts, dif_pi_format);
906 : 0 : dif_opts.dif_pi_format = SPDK_DIF_PI_FORMAT_16;
907 : 0 : rc = spdk_dif_ctx_init(&fio_req->dif_ctx, extended_lba_size, md_size,
908 [ # # ]: 0 : true, fio_qpair->md_start,
909 : 0 : (enum spdk_dif_type)spdk_nvme_ns_get_pi_type(ns),
910 : : fio_qpair->io_flags, lba, g_spdk_apptag_mask, g_spdk_apptag,
911 : : 0, 0, &dif_opts);
912 [ # # ]: 0 : if (rc != 0) {
913 [ # # # # ]: 0 : fprintf(stderr, "Initialization of DIF context failed\n");
914 : 0 : return rc;
915 : : }
916 : :
917 [ # # ]: 0 : if (io_u->ddir != DDIR_WRITE) {
918 : 0 : return 0;
919 : : }
920 : :
921 : 0 : iov.iov_base = io_u->buf;
922 : 0 : iov.iov_len = io_u->xfer_buflen;
923 : 0 : rc = spdk_dif_generate(&iov, 1, lba_count, &fio_req->dif_ctx);
924 [ # # ]: 0 : if (rc != 0) {
925 [ # # # # ]: 0 : fprintf(stderr, "Generation of DIF failed\n");
926 : : }
927 : :
928 : 0 : return rc;
929 : : }
930 : :
931 : : static int
932 : 0 : fio_separate_md_setup_pi(struct spdk_fio_qpair *fio_qpair, struct io_u *io_u)
933 : : {
934 : 0 : struct spdk_nvme_ns *ns = fio_qpair->ns;
935 : 0 : struct spdk_fio_request *fio_req = io_u->engine_data;
936 : : uint32_t md_size, block_size, lba_count;
937 : : uint64_t lba;
938 : 0 : struct iovec iov, md_iov;
939 : : int rc;
940 : 0 : struct spdk_dif_ctx_init_ext_opts dif_opts;
941 : :
942 : : /* Set appmask and apptag when PRACT is enabled */
943 [ # # ]: 0 : if (fio_qpair->io_flags & SPDK_NVME_IO_FLAGS_PRACT) {
944 : 0 : fio_req->dif_ctx.apptag_mask = g_spdk_apptag_mask;
945 : 0 : fio_req->dif_ctx.app_tag = g_spdk_apptag;
946 : 0 : return 0;
947 : : }
948 : :
949 : 0 : block_size = spdk_nvme_ns_get_sector_size(ns);
950 : 0 : md_size = spdk_nvme_ns_get_md_size(ns);
951 [ # # ]: 0 : lba = io_u->offset / block_size;
952 [ # # ]: 0 : lba_count = io_u->xfer_buflen / block_size;
953 : :
954 : 0 : dif_opts.size = SPDK_SIZEOF(&dif_opts, dif_pi_format);
955 : 0 : dif_opts.dif_pi_format = SPDK_DIF_PI_FORMAT_16;
956 : 0 : rc = spdk_dif_ctx_init(&fio_req->dif_ctx, block_size, md_size,
957 [ # # ]: 0 : false, fio_qpair->md_start,
958 : 0 : (enum spdk_dif_type)spdk_nvme_ns_get_pi_type(ns),
959 : : fio_qpair->io_flags, lba, g_spdk_apptag_mask, g_spdk_apptag,
960 : : 0, 0, &dif_opts);
961 [ # # ]: 0 : if (rc != 0) {
962 [ # # # # ]: 0 : fprintf(stderr, "Initialization of DIF context failed\n");
963 : 0 : return rc;
964 : : }
965 : :
966 [ # # ]: 0 : if (io_u->ddir != DDIR_WRITE) {
967 : 0 : return 0;
968 : : }
969 : :
970 : 0 : iov.iov_base = io_u->buf;
971 : 0 : iov.iov_len = io_u->xfer_buflen;
972 : 0 : md_iov.iov_base = fio_req->md_buf;
973 : 0 : md_iov.iov_len = spdk_min(md_size * lba_count, g_spdk_md_per_io_size);
974 : 0 : rc = spdk_dix_generate(&iov, 1, &md_iov, lba_count, &fio_req->dif_ctx);
975 [ # # ]: 0 : if (rc < 0) {
976 [ # # # # ]: 0 : fprintf(stderr, "Generation of DIX failed\n");
977 : : }
978 : :
979 : 0 : return rc;
980 : : }
981 : :
982 : : static int
983 : 0 : fio_extended_lba_verify_pi(struct spdk_fio_qpair *fio_qpair, struct io_u *io_u)
984 : : {
985 : 0 : struct spdk_nvme_ns *ns = fio_qpair->ns;
986 : 0 : struct spdk_fio_request *fio_req = io_u->engine_data;
987 : : uint32_t lba_count;
988 : 0 : struct iovec iov;
989 : 0 : struct spdk_dif_error err_blk = {};
990 : : int rc;
991 : :
992 : : /* Do nothing when PRACT is enabled */
993 [ # # ]: 0 : if (fio_qpair->io_flags & SPDK_NVME_IO_FLAGS_PRACT) {
994 : 0 : return 0;
995 : : }
996 : :
997 : 0 : iov.iov_base = io_u->buf;
998 : 0 : iov.iov_len = io_u->xfer_buflen;
999 [ # # ]: 0 : lba_count = io_u->xfer_buflen / spdk_nvme_ns_get_extended_sector_size(ns);
1000 : :
1001 : 0 : rc = spdk_dif_verify(&iov, 1, lba_count, &fio_req->dif_ctx, &err_blk);
1002 [ # # ]: 0 : if (rc != 0) {
1003 [ # # ]: 0 : fprintf(stderr, "DIF error detected. type=%d, offset=%" PRIu32 "\n",
1004 [ # # ]: 0 : err_blk.err_type, err_blk.err_offset);
1005 : : }
1006 : :
1007 : 0 : return rc;
1008 : : }
1009 : :
1010 : : static int
1011 : 0 : fio_separate_md_verify_pi(struct spdk_fio_qpair *fio_qpair, struct io_u *io_u)
1012 : : {
1013 : 0 : struct spdk_nvme_ns *ns = fio_qpair->ns;
1014 : 0 : struct spdk_fio_request *fio_req = io_u->engine_data;
1015 : : uint32_t md_size, lba_count;
1016 : 0 : struct iovec iov, md_iov;
1017 : 0 : struct spdk_dif_error err_blk = {};
1018 : : int rc;
1019 : :
1020 : : /* Do nothing when PRACT is enabled */
1021 [ # # ]: 0 : if (fio_qpair->io_flags & SPDK_NVME_IO_FLAGS_PRACT) {
1022 : 0 : return 0;
1023 : : }
1024 : :
1025 : 0 : iov.iov_base = io_u->buf;
1026 : 0 : iov.iov_len = io_u->xfer_buflen;
1027 [ # # ]: 0 : lba_count = io_u->xfer_buflen / spdk_nvme_ns_get_sector_size(ns);
1028 : 0 : md_size = spdk_nvme_ns_get_md_size(ns);
1029 : 0 : md_iov.iov_base = fio_req->md_buf;
1030 : 0 : md_iov.iov_len = spdk_min(md_size * lba_count, g_spdk_md_per_io_size);
1031 : :
1032 : 0 : rc = spdk_dix_verify(&iov, 1, &md_iov, lba_count, &fio_req->dif_ctx, &err_blk);
1033 [ # # ]: 0 : if (rc != 0) {
1034 [ # # ]: 0 : fprintf(stderr, "DIX error detected. type=%d, offset=%" PRIu32 "\n",
1035 [ # # ]: 0 : err_blk.err_type, err_blk.err_offset);
1036 : : }
1037 : :
1038 : 0 : return rc;
1039 : : }
1040 : :
1041 : : static void
1042 : 1337630 : spdk_fio_completion_cb(void *ctx, const struct spdk_nvme_cpl *cpl)
1043 : : {
1044 : 1337630 : struct spdk_fio_request *fio_req = ctx;
1045 : 1337630 : struct spdk_fio_thread *fio_thread = fio_req->fio_thread;
1046 : 1337630 : struct spdk_fio_qpair *fio_qpair = fio_req->fio_qpair;
1047 : : int rc;
1048 : :
1049 [ - + - + : 1337630 : if (fio_qpair->nvme_pi_enabled && fio_req->io->ddir == DDIR_READ) {
- - ]
1050 [ # # # # ]: 0 : if (fio_qpair->extended_lba) {
1051 : 0 : rc = fio_extended_lba_verify_pi(fio_qpair, fio_req->io);
1052 : : } else {
1053 : 0 : rc = fio_separate_md_verify_pi(fio_qpair, fio_req->io);
1054 : : }
1055 [ # # ]: 0 : if (rc != 0) {
1056 : 0 : fio_req->io->error = abs(rc);
1057 : : }
1058 : : }
1059 : :
1060 [ + - - + ]: 1337630 : if (spdk_nvme_cpl_is_error(cpl)) {
1061 : 0 : fio_req->io->error = EIO;
1062 : : }
1063 : :
1064 [ - + ]: 1337630 : assert(fio_thread->iocq_count < fio_thread->iocq_size);
1065 : 1337630 : fio_thread->iocq[fio_thread->iocq_count++] = fio_req->io;
1066 : 1337630 : }
1067 : :
1068 : : static void
1069 : 232428 : spdk_nvme_io_reset_sgl(void *ref, uint32_t sgl_offset)
1070 : : {
1071 : 232428 : struct spdk_fio_request *fio_req = (struct spdk_fio_request *)ref;
1072 : :
1073 : 232428 : fio_req->iov_offset = sgl_offset;
1074 : 232428 : fio_req->bit_bucket_data_len = 0;
1075 : 232428 : }
1076 : :
1077 : : static int
1078 : 929712 : spdk_nvme_io_next_sge(void *ref, void **address, uint32_t *length)
1079 : : {
1080 : 929712 : struct spdk_fio_request *fio_req = (struct spdk_fio_request *)ref;
1081 : 929712 : struct io_u *io_u = fio_req->io;
1082 : : uint32_t iov_len;
1083 : : uint32_t bit_bucket_len;
1084 : :
1085 : 929712 : *address = io_u->buf;
1086 : :
1087 [ + + ]: 929712 : if (fio_req->iov_offset) {
1088 [ - + ]: 697284 : assert(fio_req->iov_offset <= io_u->xfer_buflen);
1089 : 697284 : *address += fio_req->iov_offset;
1090 : : }
1091 : :
1092 : 929712 : iov_len = io_u->xfer_buflen - fio_req->iov_offset;
1093 [ + + ]: 929712 : if (iov_len > g_spdk_sge_size) {
1094 : 697284 : iov_len = g_spdk_sge_size;
1095 : : }
1096 : :
1097 [ - + - - ]: 929712 : if ((fio_req->bit_bucket_data_len < g_spdk_bit_bucket_data_len) && (io_u->ddir == DDIR_READ)) {
1098 [ # # ]: 0 : assert(g_spdk_bit_bucket_data_len < io_u->xfer_buflen);
1099 : 0 : *address = (void *)UINT64_MAX;
1100 : 0 : bit_bucket_len = g_spdk_bit_bucket_data_len - fio_req->bit_bucket_data_len;
1101 [ # # ]: 0 : if (iov_len > bit_bucket_len) {
1102 : 0 : iov_len = bit_bucket_len;
1103 : : }
1104 : 0 : fio_req->bit_bucket_data_len += iov_len;
1105 : : }
1106 : :
1107 : 929712 : fio_req->iov_offset += iov_len;
1108 : 929712 : *length = iov_len;
1109 : :
1110 : 929712 : return 0;
1111 : : }
1112 : :
1113 : : #if FIO_IOOPS_VERSION >= 24
1114 : : typedef enum fio_q_status fio_q_status_t;
1115 : : #else
1116 : : typedef int fio_q_status_t;
1117 : : #endif
1118 : :
1119 : : static fio_q_status_t
1120 : 1337630 : spdk_fio_queue(struct thread_data *td, struct io_u *io_u)
1121 : : {
1122 : 1337630 : int rc = 1;
1123 : 1337630 : struct spdk_fio_thread *fio_thread = td->io_ops_data;
1124 : 1337630 : struct spdk_fio_request *fio_req = io_u->engine_data;
1125 : : struct spdk_fio_qpair *fio_qpair;
1126 : 1337630 : struct spdk_nvme_ns *ns = NULL;
1127 : 1337630 : void *md_buf = NULL;
1128 : 1337630 : struct spdk_dif_ctx *dif_ctx = &fio_req->dif_ctx;
1129 : : #if FIO_HAS_FDP
1130 : 394182 : struct spdk_nvme_ns_cmd_ext_io_opts ext_opts;
1131 : : #endif
1132 : : struct spdk_nvme_dsm_range *range;
1133 : : uint32_t block_size;
1134 : : uint64_t lba;
1135 : : uint32_t lba_count;
1136 : : uint32_t num_range;
1137 : :
1138 : 1337630 : fio_qpair = get_fio_qpair(fio_thread, io_u->file);
1139 [ - + ]: 1337630 : if (fio_qpair == NULL) {
1140 : 0 : return -ENXIO;
1141 : : }
1142 : 1337630 : ns = fio_qpair->ns;
1143 : :
1144 [ - + - + : 1337630 : if (fio_qpair->nvme_pi_enabled && !fio_qpair->extended_lba) {
- - - - ]
1145 : 0 : md_buf = fio_req->md_buf;
1146 : : }
1147 : 1337630 : fio_req->fio_qpair = fio_qpair;
1148 : :
1149 : 1337630 : block_size = _nvme_get_host_buffer_sector_size(ns, fio_qpair->io_flags);
1150 [ - + ]: 1337630 : lba = io_u->offset / block_size;
1151 [ - + ]: 1337630 : lba_count = io_u->xfer_buflen / block_size;
1152 : :
1153 : : #if FIO_HAS_FDP
1154 : : /* Only SGL support for write command with directives */
1155 [ + + - + : 1337630 : if (io_u->ddir == DDIR_WRITE && io_u->dtype && !g_spdk_enable_sgl) {
- - ]
1156 : 0 : log_err("spdk/nvme: queue() directives require SGL to be enabled\n");
1157 : 0 : io_u->error = -EINVAL;
1158 : 0 : return FIO_Q_COMPLETED;
1159 : : }
1160 : : #endif
1161 : :
1162 : : /* TODO: considering situations that fio will randomize and verify io_u */
1163 [ - + - + ]: 1337630 : if (fio_qpair->nvme_pi_enabled) {
1164 [ # # # # ]: 0 : if (fio_qpair->extended_lba) {
1165 : 0 : rc = fio_extended_lba_setup_pi(fio_qpair, io_u);
1166 : : } else {
1167 : 0 : rc = fio_separate_md_setup_pi(fio_qpair, io_u);
1168 : : }
1169 [ # # ]: 0 : if (rc < 0) {
1170 : 0 : io_u->error = -rc;
1171 : 0 : return FIO_Q_COMPLETED;
1172 : : }
1173 : : }
1174 : :
1175 [ + + - - ]: 1337630 : switch (io_u->ddir) {
1176 : 687126 : case DDIR_READ:
1177 [ + + ]: 687126 : if (!g_spdk_enable_sgl) {
1178 : 611194 : rc = spdk_nvme_ns_cmd_read_with_md(ns, fio_qpair->qpair, io_u->buf, md_buf, lba, lba_count,
1179 : : spdk_fio_completion_cb, fio_req,
1180 : 611194 : fio_qpair->io_flags, dif_ctx->apptag_mask, dif_ctx->app_tag);
1181 : : } else {
1182 : 75932 : rc = spdk_nvme_ns_cmd_readv_with_md(ns, fio_qpair->qpair, lba,
1183 : : lba_count, spdk_fio_completion_cb, fio_req, fio_qpair->io_flags,
1184 : : spdk_nvme_io_reset_sgl, spdk_nvme_io_next_sge, md_buf,
1185 : 75932 : dif_ctx->apptag_mask, dif_ctx->app_tag);
1186 : : }
1187 : 687126 : break;
1188 : 650504 : case DDIR_WRITE:
1189 [ + + ]: 650504 : if (!g_spdk_enable_sgl) {
1190 [ + + + - ]: 610222 : if (!fio_qpair->zone_append_enabled) {
1191 : 610222 : rc = spdk_nvme_ns_cmd_write_with_md(ns, fio_qpair->qpair, io_u->buf, md_buf, lba,
1192 : : lba_count,
1193 : : spdk_fio_completion_cb, fio_req,
1194 : 610222 : fio_qpair->io_flags, dif_ctx->apptag_mask, dif_ctx->app_tag);
1195 : : } else {
1196 : 0 : uint64_t zslba = fio_offset_to_zslba(io_u->offset, ns);
1197 : 0 : rc = spdk_nvme_zns_zone_append_with_md(ns, fio_qpair->qpair, io_u->buf, md_buf, zslba,
1198 : : lba_count,
1199 : : spdk_fio_completion_cb, fio_req,
1200 : 0 : fio_qpair->io_flags, dif_ctx->apptag_mask, dif_ctx->app_tag);
1201 : : }
1202 : : } else {
1203 [ - + + - ]: 40282 : if (!fio_qpair->zone_append_enabled) {
1204 : : #if FIO_HAS_FDP
1205 [ - + ]: 40282 : if (spdk_unlikely(io_u->dtype)) {
1206 : 0 : ext_opts.size = SPDK_SIZEOF(&ext_opts, cdw13);
1207 : 0 : ext_opts.io_flags = fio_qpair->io_flags | (io_u->dtype << 20);
1208 : 0 : ext_opts.metadata = md_buf;
1209 : 0 : ext_opts.cdw13 = (io_u->dspec << 16);
1210 : 0 : ext_opts.apptag = dif_ctx->app_tag;
1211 : 0 : ext_opts.apptag_mask = dif_ctx->apptag_mask;
1212 : 0 : rc = spdk_nvme_ns_cmd_writev_ext(ns, fio_qpair->qpair, lba, lba_count,
1213 : : spdk_fio_completion_cb, fio_req,
1214 : : spdk_nvme_io_reset_sgl, spdk_nvme_io_next_sge, &ext_opts);
1215 : 0 : break;
1216 : : }
1217 : : #endif
1218 : 40282 : rc = spdk_nvme_ns_cmd_writev_with_md(ns, fio_qpair->qpair, lba,
1219 : : lba_count, spdk_fio_completion_cb, fio_req, fio_qpair->io_flags,
1220 : : spdk_nvme_io_reset_sgl, spdk_nvme_io_next_sge, md_buf,
1221 : 40282 : dif_ctx->apptag_mask, dif_ctx->app_tag);
1222 : : } else {
1223 : 0 : uint64_t zslba = fio_offset_to_zslba(io_u->offset, ns);
1224 : 0 : rc = spdk_nvme_zns_zone_appendv_with_md(ns, fio_qpair->qpair, zslba,
1225 : : lba_count, spdk_fio_completion_cb, fio_req, fio_qpair->io_flags,
1226 : : spdk_nvme_io_reset_sgl, spdk_nvme_io_next_sge, md_buf,
1227 : 0 : dif_ctx->apptag_mask, dif_ctx->app_tag);
1228 : : }
1229 : : }
1230 : 650504 : break;
1231 : 0 : case DDIR_TRIM:
1232 [ # # ]: 0 : if (td->io_ops->flags & FIO_ASYNCIO_SYNC_TRIM) {
1233 : 0 : do_io_u_trim(td, io_u);
1234 : 0 : io_u_mark_submit(td, 1);
1235 : 0 : io_u_mark_complete(td, 1);
1236 : 0 : return FIO_Q_COMPLETED;
1237 : : }
1238 : :
1239 : 0 : range = fio_req->dsm_range;
1240 : : #if FIO_HAS_MRT
1241 : : if (td->o.num_range == 1) {
1242 : : range->attributes.raw = 0;
1243 : : range->length = lba_count;
1244 : : range->starting_lba = lba;
1245 : : num_range = 1;
1246 : : } else {
1247 : : struct trim_range *tr = (struct trim_range *)io_u->xfer_buf;
1248 : : for (uint32_t i = 0; i < io_u->number_trim; i++) {
1249 : : range->attributes.raw = 0;
1250 : : range->length = tr->len / block_size;
1251 : : range->starting_lba = tr->start / block_size;
1252 : : range++;
1253 : : tr++;
1254 : : }
1255 : : num_range = io_u->number_trim;
1256 : : range = fio_req->dsm_range;
1257 : : }
1258 : : #else
1259 : 0 : range->attributes.raw = 0;
1260 : 0 : range->length = lba_count;
1261 : 0 : range->starting_lba = lba;
1262 : 0 : num_range = 1;
1263 : : #endif
1264 : :
1265 : 0 : rc = spdk_nvme_ns_cmd_dataset_management(ns, fio_qpair->qpair,
1266 : : SPDK_NVME_DSM_ATTR_DEALLOCATE, range, num_range,
1267 : : spdk_fio_completion_cb, fio_req);
1268 : 0 : break;
1269 : 0 : default:
1270 : 0 : assert(false);
1271 : : break;
1272 : : }
1273 : :
1274 : : /* NVMe read/write functions return -ENOMEM if there are no free requests. */
1275 [ - + ]: 1337630 : if (rc == -ENOMEM) {
1276 : 0 : return FIO_Q_BUSY;
1277 : : }
1278 : :
1279 [ - + ]: 1337630 : if (rc != 0) {
1280 : 0 : io_u->error = abs(rc);
1281 : 0 : return FIO_Q_COMPLETED;
1282 : : }
1283 : :
1284 : 1337630 : return FIO_Q_QUEUED;
1285 : : }
1286 : :
1287 : : static struct io_u *
1288 : 1337630 : spdk_fio_event(struct thread_data *td, int event)
1289 : : {
1290 : 1337630 : struct spdk_fio_thread *fio_thread = td->io_ops_data;
1291 : :
1292 [ - + ]: 1337630 : assert(event >= 0);
1293 [ - + ]: 1337630 : assert((unsigned)event < fio_thread->iocq_count);
1294 : 1337630 : return fio_thread->iocq[event];
1295 : : }
1296 : :
1297 : : static int
1298 : 1332842 : spdk_fio_getevents(struct thread_data *td, unsigned int min,
1299 : : unsigned int max, const struct timespec *t)
1300 : : {
1301 : 1332842 : struct spdk_fio_thread *fio_thread = td->io_ops_data;
1302 : 1332842 : struct spdk_fio_qpair *fio_qpair = NULL;
1303 : 393426 : struct timespec t0, t1;
1304 : 1332842 : uint64_t timeout = 0;
1305 : :
1306 [ - + ]: 1332842 : if (t) {
1307 : 0 : timeout = t->tv_sec * 1000000000L + t->tv_nsec;
1308 [ # # ]: 0 : clock_gettime(CLOCK_MONOTONIC_RAW, &t0);
1309 : : }
1310 : :
1311 : 1332842 : fio_thread->iocq_count = 0;
1312 : :
1313 : : /* fetch the next qpair */
1314 [ + + ]: 1332842 : if (fio_thread->fio_qpair_current) {
1315 : 1332824 : fio_qpair = TAILQ_NEXT(fio_thread->fio_qpair_current, link);
1316 : : }
1317 : :
1318 : : for (;;) {
1319 [ + - ]: 8828624 : if (fio_qpair == NULL) {
1320 : 8828624 : fio_qpair = TAILQ_FIRST(&fio_thread->fio_qpair);
1321 : : }
1322 : :
1323 [ + + ]: 16324406 : while (fio_qpair != NULL) {
1324 : : /*
1325 : : * We can be called while spdk_fio_open()s are still
1326 : : * ongoing, in which case, ->qpair can still be NULL.
1327 : : */
1328 [ - + ]: 8828624 : if (fio_qpair->qpair == NULL) {
1329 : 0 : fio_qpair = TAILQ_NEXT(fio_qpair, link);
1330 : 0 : continue;
1331 : : }
1332 : :
1333 : 8828624 : spdk_nvme_qpair_process_completions(fio_qpair->qpair, max - fio_thread->iocq_count);
1334 : :
1335 [ + + ]: 8828624 : if (fio_thread->iocq_count >= min) {
1336 : : /* reset the current handling qpair */
1337 : 1332842 : fio_thread->fio_qpair_current = fio_qpair;
1338 : 1332842 : return fio_thread->iocq_count;
1339 : : }
1340 : :
1341 : 7495782 : fio_qpair = TAILQ_NEXT(fio_qpair, link);
1342 : : }
1343 : :
1344 [ - + ]: 7495782 : if (t) {
1345 : : uint64_t elapse;
1346 : :
1347 [ # # ]: 0 : clock_gettime(CLOCK_MONOTONIC_RAW, &t1);
1348 : 0 : elapse = ((t1.tv_sec - t0.tv_sec) * 1000000000L)
1349 : 0 : + t1.tv_nsec - t0.tv_nsec;
1350 [ # # ]: 0 : if (elapse > timeout) {
1351 : 0 : break;
1352 : : }
1353 : : }
1354 : : }
1355 : :
1356 : : /* reset the current handling qpair */
1357 : 0 : fio_thread->fio_qpair_current = fio_qpair;
1358 : 0 : return fio_thread->iocq_count;
1359 : : }
1360 : :
1361 : : static int
1362 : 0 : spdk_fio_invalidate(struct thread_data *td, struct fio_file *f)
1363 : : {
1364 : : /* TODO: This should probably send a flush to the device, but for now just return successful. */
1365 : 0 : return 0;
1366 : : }
1367 : :
1368 : : #if FIO_HAS_ZBD
1369 : : static int
1370 : 0 : spdk_fio_get_zoned_model(struct thread_data *td, struct fio_file *f, enum zbd_zoned_model *model)
1371 : : {
1372 : 0 : struct spdk_fio_thread *fio_thread = td->io_ops_data;
1373 : 0 : struct spdk_fio_qpair *fio_qpair = NULL;
1374 : 0 : const struct spdk_nvme_zns_ns_data *zns_data = NULL;
1375 : :
1376 [ # # ]: 0 : if (f->filetype != FIO_TYPE_BLOCK) {
1377 : 0 : log_info("spdk/nvme: unsupported filetype: %d\n", f->filetype);
1378 : 0 : return -EINVAL;
1379 : : }
1380 : :
1381 : 0 : fio_qpair = get_fio_qpair(fio_thread, f);
1382 [ # # ]: 0 : if (!fio_qpair) {
1383 : 0 : log_err("spdk/nvme: no ns/qpair or file_name: '%s'\n", f->file_name);
1384 : 0 : return -ENODEV;
1385 : : }
1386 : :
1387 [ # # # # ]: 0 : switch (spdk_nvme_ns_get_csi(fio_qpair->ns)) {
1388 : 0 : case SPDK_NVME_CSI_NVM:
1389 : 0 : *model = ZBD_NONE;
1390 : 0 : return 0;
1391 : :
1392 : 0 : case SPDK_NVME_CSI_KV:
1393 : 0 : log_err("spdk/nvme: KV namespace is currently not supported\n");
1394 : 0 : return -ENOSYS;
1395 : :
1396 : 0 : case SPDK_NVME_CSI_ZNS:
1397 : 0 : zns_data = spdk_nvme_zns_ns_get_data(fio_qpair->ns);
1398 [ # # ]: 0 : if (!zns_data) {
1399 : 0 : log_err("spdk/nvme: file_name: '%s', ZNS is not enabled\n", f->file_name);
1400 : 0 : return -EINVAL;
1401 : : }
1402 : :
1403 : 0 : *model = ZBD_HOST_MANAGED;
1404 : :
1405 : 0 : return 0;
1406 : : }
1407 : :
1408 : 0 : return -EINVAL;
1409 : : }
1410 : :
1411 : : static int
1412 : 0 : spdk_fio_report_zones(struct thread_data *td, struct fio_file *f, uint64_t offset,
1413 : : struct zbd_zone *zbdz, unsigned int nr_zones)
1414 : : {
1415 : 0 : struct spdk_fio_thread *fio_thread = td->io_ops_data;
1416 : 0 : struct spdk_fio_qpair *fio_qpair = NULL;
1417 : 0 : const struct spdk_nvme_zns_ns_data *zns = NULL;
1418 : : struct spdk_nvme_zns_zone_report *report;
1419 : : struct spdk_nvme_qpair *tmp_qpair;
1420 : 0 : uint32_t report_nzones = 0, report_nzones_max, report_nbytes, mdts_nbytes;
1421 : : uint64_t zsze_nbytes, ns_nzones, lba_nbytes;
1422 : 0 : int completed = 0, err;
1423 : :
1424 : 0 : fio_qpair = get_fio_qpair(fio_thread, f);
1425 [ # # ]: 0 : if (!fio_qpair) {
1426 : 0 : log_err("spdk/nvme: no ns/qpair or file_name: '%s'\n", f->file_name);
1427 : 0 : return -ENODEV;
1428 : : }
1429 : 0 : zns = spdk_nvme_zns_ns_get_data(fio_qpair->ns);
1430 [ # # ]: 0 : if (!zns) {
1431 : 0 : log_err("spdk/nvme: file_name: '%s', zns is not enabled\n", f->file_name);
1432 : 0 : return -EINVAL;
1433 : : }
1434 : :
1435 : : /* qpair has not been allocated yet (it gets allocated in spdk_fio_open()).
1436 : : * Create a temporary qpair in order to perform report zones.
1437 : : */
1438 [ # # ]: 0 : assert(!fio_qpair->qpair);
1439 : :
1440 : 0 : tmp_qpair = spdk_nvme_ctrlr_alloc_io_qpair(fio_qpair->fio_ctrlr->ctrlr, NULL, 0);
1441 [ # # ]: 0 : if (!tmp_qpair) {
1442 : 0 : log_err("spdk/nvme: cannot allocate a temporary qpair\n");
1443 : 0 : return -EIO;
1444 : : }
1445 : :
1446 : : /** Retrieve device parameters */
1447 : 0 : mdts_nbytes = spdk_nvme_ns_get_max_io_xfer_size(fio_qpair->ns);
1448 : 0 : lba_nbytes = spdk_nvme_ns_get_sector_size(fio_qpair->ns);
1449 : 0 : zsze_nbytes = spdk_nvme_zns_ns_get_zone_size(fio_qpair->ns);
1450 : 0 : ns_nzones = spdk_nvme_zns_ns_get_num_zones(fio_qpair->ns);
1451 : :
1452 : : /** Allocate report-buffer without exceeding mdts, zbdz-storage, and what is needed */
1453 : 0 : report_nzones_max = (mdts_nbytes - sizeof(*report)) / sizeof(report->descs[0]);
1454 : 0 : report_nzones_max = spdk_min(spdk_min(report_nzones_max, nr_zones), ns_nzones);
1455 : 0 : report_nbytes = sizeof(report->descs[0]) * report_nzones_max + sizeof(*report);
1456 : 0 : report = calloc(1, report_nbytes);
1457 [ # # ]: 0 : if (!report) {
1458 : 0 : log_err("spdk/nvme: failed report_zones(): ENOMEM\n");
1459 : 0 : err = -ENOMEM;
1460 : 0 : goto exit;
1461 : : }
1462 : :
1463 [ # # ]: 0 : err = spdk_nvme_zns_report_zones(fio_qpair->ns, tmp_qpair, report, report_nbytes,
1464 : 0 : offset / lba_nbytes, SPDK_NVME_ZRA_LIST_ALL, true, pcu_cb,
1465 : : &completed);
1466 [ # # # # : 0 : if (err || pcu(tmp_qpair, &completed) || completed < 0) {
# # ]
1467 : 0 : log_err("spdk/nvme: report_zones(): err: %d, cpl: %d\n", err, completed);
1468 [ # # ]: 0 : err = err ? err : -EIO;
1469 : 0 : goto exit;
1470 : : }
1471 [ # # ]: 0 : assert(report->nr_zones <= report_nzones_max);
1472 : 0 : report_nzones = report->nr_zones;
1473 : :
1474 [ # # ]: 0 : for (uint64_t idx = 0; idx < report->nr_zones; ++idx) {
1475 : 0 : struct spdk_nvme_zns_zone_desc *zdesc = &report->descs[idx];
1476 : :
1477 : 0 : zbdz[idx].start = zdesc->zslba * lba_nbytes;
1478 : 0 : zbdz[idx].len = zsze_nbytes;
1479 : 0 : zbdz[idx].capacity = zdesc->zcap * lba_nbytes;
1480 : 0 : zbdz[idx].wp = zdesc->wp * lba_nbytes;
1481 : :
1482 [ # # ]: 0 : switch (zdesc->zt) {
1483 : 0 : case SPDK_NVME_ZONE_TYPE_SEQWR:
1484 : 0 : zbdz[idx].type = ZBD_ZONE_TYPE_SWR;
1485 : 0 : break;
1486 : :
1487 : 0 : default:
1488 : 0 : log_err("spdk/nvme: %s: inv. zone-type: 0x%x\n", f->file_name, zdesc->zt);
1489 : 0 : err = -EIO;
1490 : 0 : goto exit;
1491 : : }
1492 : :
1493 [ # # # # : 0 : switch (zdesc->zs) {
# # # # ]
1494 : 0 : case SPDK_NVME_ZONE_STATE_EMPTY:
1495 : 0 : zbdz[idx].cond = ZBD_ZONE_COND_EMPTY;
1496 : 0 : break;
1497 : 0 : case SPDK_NVME_ZONE_STATE_IOPEN:
1498 : 0 : zbdz[idx].cond = ZBD_ZONE_COND_IMP_OPEN;
1499 : 0 : break;
1500 : 0 : case SPDK_NVME_ZONE_STATE_EOPEN:
1501 : 0 : zbdz[idx].cond = ZBD_ZONE_COND_EXP_OPEN;
1502 : 0 : break;
1503 : 0 : case SPDK_NVME_ZONE_STATE_CLOSED:
1504 : 0 : zbdz[idx].cond = ZBD_ZONE_COND_CLOSED;
1505 : 0 : break;
1506 : 0 : case SPDK_NVME_ZONE_STATE_RONLY:
1507 : 0 : zbdz[idx].cond = ZBD_ZONE_COND_READONLY;
1508 : 0 : break;
1509 : 0 : case SPDK_NVME_ZONE_STATE_FULL:
1510 : 0 : zbdz[idx].cond = ZBD_ZONE_COND_FULL;
1511 : 0 : break;
1512 : 0 : case SPDK_NVME_ZONE_STATE_OFFLINE:
1513 : 0 : zbdz[idx].cond = ZBD_ZONE_COND_OFFLINE;
1514 : 0 : break;
1515 : :
1516 : 0 : default:
1517 : 0 : log_err("spdk/nvme: %s: inv. zone-state: 0x%x\n", f->file_name, zdesc->zs);
1518 : 0 : err = -EIO;
1519 : 0 : goto exit;
1520 : : }
1521 : : }
1522 : :
1523 : 0 : exit:
1524 : 0 : spdk_nvme_ctrlr_free_io_qpair(tmp_qpair);
1525 : 0 : free(report);
1526 : :
1527 [ # # ]: 0 : return err ? err : (int)report_nzones;
1528 : : }
1529 : :
1530 : : static int
1531 : 0 : spdk_fio_reset_wp(struct thread_data *td, struct fio_file *f, uint64_t offset, uint64_t length)
1532 : : {
1533 : 0 : struct spdk_fio_thread *fio_thread = td->io_ops_data;
1534 : 0 : struct spdk_fio_qpair *fio_qpair = NULL;
1535 : 0 : const struct spdk_nvme_zns_ns_data *zns = NULL;
1536 : : uint64_t zsze_nbytes, lba_nbytes;
1537 : 0 : int err = 0;
1538 : :
1539 : 0 : fio_qpair = get_fio_qpair(fio_thread, f);
1540 [ # # ]: 0 : if (!fio_qpair) {
1541 : 0 : log_err("spdk/nvme: no ns/qpair or file_name: '%s'\n", f->file_name);
1542 : 0 : return -ENODEV;
1543 : : }
1544 : 0 : zns = spdk_nvme_zns_ns_get_data(fio_qpair->ns);
1545 [ # # ]: 0 : if (!zns) {
1546 : 0 : log_err("spdk/nvme: file_name: '%s', zns is not enabled\n", f->file_name);
1547 : 0 : return -EINVAL;
1548 : : }
1549 : 0 : zsze_nbytes = spdk_nvme_zns_ns_get_zone_size(fio_qpair->ns);
1550 : 0 : lba_nbytes = spdk_nvme_ns_get_sector_size(fio_qpair->ns);
1551 : :
1552 : : /** check the assumption that offset is valid zone-start lba */
1553 [ # # # # ]: 0 : if (offset % zsze_nbytes) {
1554 : 0 : log_err("spdk/nvme: offset: %zu is not a valid zslba\n", offset);
1555 : 0 : return -EINVAL;
1556 : : }
1557 : :
1558 [ # # ]: 0 : for (uint64_t cur = offset; cur < offset + length; cur += zsze_nbytes) {
1559 : 0 : int completed = 0;
1560 : :
1561 [ # # ]: 0 : err = spdk_nvme_zns_reset_zone(fio_qpair->ns, fio_qpair->qpair, cur / lba_nbytes,
1562 : : false, pcu_cb, &completed);
1563 [ # # # # : 0 : if (err || pcu(fio_qpair->qpair, &completed) || completed < 0) {
# # ]
1564 : 0 : log_err("spdk/nvme: zns_reset_zone(): err: %d, cpl: %d\n", err, completed);
1565 [ # # ]: 0 : err = err ? err : -EIO;
1566 : 0 : break;
1567 : : }
1568 : : }
1569 : :
1570 : 0 : return err;
1571 : : }
1572 : : #endif
1573 : :
1574 : : #if FIO_IOOPS_VERSION >= 30
1575 : : static int
1576 : 0 : spdk_fio_get_max_open_zones(struct thread_data *td, struct fio_file *f,
1577 : : unsigned int *max_open_zones)
1578 : : {
1579 : 0 : struct spdk_fio_thread *fio_thread = td->io_ops_data;
1580 : 0 : struct spdk_fio_qpair *fio_qpair = NULL;
1581 : :
1582 : 0 : fio_qpair = get_fio_qpair(fio_thread, f);
1583 [ # # ]: 0 : if (!fio_qpair) {
1584 : 0 : log_err("spdk/nvme: no ns/qpair or file_name: '%s'\n", f->file_name);
1585 : 0 : return -ENODEV;
1586 : : }
1587 : :
1588 : 0 : *max_open_zones = spdk_nvme_zns_ns_get_max_open_zones(fio_qpair->ns);
1589 : :
1590 : 0 : return 0;
1591 : : }
1592 : : #endif
1593 : :
1594 : : #if FIO_HAS_FDP
1595 : : static int
1596 : 0 : spdk_fio_fdp_fetch_ruhs(struct thread_data *td, struct fio_file *f,
1597 : : struct fio_ruhs_info *fruhs_info)
1598 : : {
1599 : 0 : struct spdk_fio_thread *fio_thread = td->io_ops_data;
1600 : 0 : struct spdk_fio_qpair *fio_qpair = NULL;
1601 : : struct spdk_nvme_qpair *tmp_qpair;
1602 : : struct {
1603 : : struct spdk_nvme_fdp_ruhs ruhs;
1604 : : struct spdk_nvme_fdp_ruhs_desc desc[128];
1605 : 0 : } fdp_ruhs;
1606 : : uint16_t idx;
1607 : 0 : int completed = 0, err;
1608 : :
1609 : 0 : fio_qpair = get_fio_qpair(fio_thread, f);
1610 [ # # ]: 0 : if (!fio_qpair) {
1611 : 0 : log_err("spdk/nvme: no ns/qpair or file_name: '%s'\n", f->file_name);
1612 : 0 : return -ENODEV;
1613 : : }
1614 : :
1615 : : /* qpair has not been allocated yet (it gets allocated in spdk_fio_open()).
1616 : : * Create a temporary qpair in order to perform report zones.
1617 : : */
1618 [ # # ]: 0 : assert(!fio_qpair->qpair);
1619 : :
1620 : 0 : tmp_qpair = spdk_nvme_ctrlr_alloc_io_qpair(fio_qpair->fio_ctrlr->ctrlr, NULL, 0);
1621 [ # # ]: 0 : if (!tmp_qpair) {
1622 : 0 : log_err("spdk/nvme: cannot allocate a temporary qpair\n");
1623 : 0 : return -EIO;
1624 : : }
1625 : :
1626 : 0 : err = spdk_nvme_ns_cmd_io_mgmt_recv(fio_qpair->ns, tmp_qpair, &fdp_ruhs, sizeof(fdp_ruhs),
1627 : : SPDK_NVME_FDP_IO_MGMT_RECV_RUHS, 0, pcu_cb, &completed);
1628 [ # # # # : 0 : if (err || pcu(tmp_qpair, &completed) || completed < 0) {
# # ]
1629 : 0 : log_err("spdk/nvme: fetch_ruhs(): err: %d, cpl: %d\n", err, completed);
1630 [ # # ]: 0 : err = err ? err : -EIO;
1631 : 0 : goto exit;
1632 : : }
1633 : :
1634 : 0 : fruhs_info->nr_ruhs = fdp_ruhs.ruhs.nruhsd;
1635 [ # # ]: 0 : for (idx = 0; idx < fdp_ruhs.ruhs.nruhsd; idx++) {
1636 : 0 : fruhs_info->plis[idx] = fdp_ruhs.desc[idx].pid;
1637 : : }
1638 : :
1639 : 0 : exit:
1640 : 0 : spdk_nvme_ctrlr_free_io_qpair(tmp_qpair);
1641 : :
1642 : 0 : return err;
1643 : : }
1644 : : #endif
1645 : :
1646 : : static void
1647 : 18 : spdk_fio_cleanup(struct thread_data *td)
1648 : : {
1649 : 18 : struct spdk_fio_thread *fio_thread = td->io_ops_data;
1650 : : struct spdk_fio_qpair *fio_qpair, *fio_qpair_tmp;
1651 : 18 : struct spdk_fio_options *fio_options = td->eo;
1652 : :
1653 [ - + ]: 18 : if (fio_options->spdk_tracing) {
1654 : 0 : spdk_trace_unregister_user_thread();
1655 : : }
1656 : :
1657 [ + + ]: 36 : TAILQ_FOREACH_SAFE(fio_qpair, &fio_thread->fio_qpair, link, fio_qpair_tmp) {
1658 [ - + ]: 18 : TAILQ_REMOVE(&fio_thread->fio_qpair, fio_qpair, link);
1659 : 18 : free(fio_qpair);
1660 : : }
1661 : :
1662 : 18 : free(fio_thread->iocq);
1663 : 18 : free(fio_thread);
1664 : :
1665 [ - + ]: 18 : pthread_mutex_lock(&g_mutex);
1666 : 18 : g_td_count--;
1667 [ + - ]: 18 : if (g_td_count == 0) {
1668 : : struct spdk_fio_ctrlr *fio_ctrlr, *fio_ctrlr_tmp;
1669 : 18 : struct spdk_nvme_detach_ctx *detach_ctx = NULL;
1670 : :
1671 [ + + ]: 36 : TAILQ_FOREACH_SAFE(fio_ctrlr, &g_ctrlrs, link, fio_ctrlr_tmp) {
1672 [ - + ]: 18 : TAILQ_REMOVE(&g_ctrlrs, fio_ctrlr, link);
1673 : 18 : spdk_nvme_detach_async(fio_ctrlr->ctrlr, &detach_ctx);
1674 : 18 : free(fio_ctrlr);
1675 : : }
1676 : :
1677 [ + - ]: 18 : if (detach_ctx) {
1678 : 18 : spdk_nvme_detach_poll(detach_ctx);
1679 : : }
1680 : :
1681 [ - + ]: 18 : if (fio_options->enable_vmd) {
1682 : 0 : spdk_vmd_fini();
1683 : : }
1684 : : }
1685 [ - + ]: 18 : pthread_mutex_unlock(&g_mutex);
1686 [ + - ]: 18 : if (TAILQ_EMPTY(&g_ctrlrs)) {
1687 [ + - ]: 18 : if (pthread_cancel(g_ctrlr_thread_id) == 0) {
1688 : 18 : pthread_join(g_ctrlr_thread_id, NULL);
1689 : : }
1690 : : }
1691 : 18 : }
1692 : :
1693 : : /* This function enables addition of SPDK parameters to the fio config
1694 : : * Adding new parameters by defining them here and defining a callback
1695 : : * function to read the parameter value. */
1696 : : static struct fio_option options[] = {
1697 : : {
1698 : : .name = "enable_wrr",
1699 : : .lname = "Enable weighted round robin (WRR) for IO submission queues",
1700 : : .type = FIO_OPT_INT,
1701 : : .off1 = offsetof(struct spdk_fio_options, enable_wrr),
1702 : : .def = "0",
1703 : : .help = "Enable weighted round robin (WRR) for IO submission queues",
1704 : : .category = FIO_OPT_C_ENGINE,
1705 : : .group = FIO_OPT_G_INVALID,
1706 : : },
1707 : : {
1708 : : .name = "arbitration_burst",
1709 : : .lname = "Arbitration Burst",
1710 : : .type = FIO_OPT_INT,
1711 : : .off1 = offsetof(struct spdk_fio_options, arbitration_burst),
1712 : : .def = "0",
1713 : : .help = "Arbitration Burst used for WRR (valid range from 0 - 7)",
1714 : : .category = FIO_OPT_C_ENGINE,
1715 : : .group = FIO_OPT_G_INVALID,
1716 : : },
1717 : : {
1718 : : .name = "low_weight",
1719 : : .lname = "low_weight for WRR",
1720 : : .type = FIO_OPT_INT,
1721 : : .off1 = offsetof(struct spdk_fio_options, low_weight),
1722 : : .def = "0",
1723 : : .help = "low_weight used for WRR (valid range from 0 - 255)",
1724 : : .category = FIO_OPT_C_ENGINE,
1725 : : .group = FIO_OPT_G_INVALID,
1726 : : },
1727 : : {
1728 : : .name = "medium_weight",
1729 : : .lname = "medium_weight for WRR",
1730 : : .type = FIO_OPT_INT,
1731 : : .off1 = offsetof(struct spdk_fio_options, medium_weight),
1732 : : .def = "0",
1733 : : .help = "medium weight used for WRR (valid range from 0 - 255)",
1734 : : .category = FIO_OPT_C_ENGINE,
1735 : : .group = FIO_OPT_G_INVALID,
1736 : : },
1737 : : {
1738 : : .name = "high_weight",
1739 : : .lname = "high_weight for WRR",
1740 : : .type = FIO_OPT_INT,
1741 : : .off1 = offsetof(struct spdk_fio_options, high_weight),
1742 : : .def = "0",
1743 : : .help = "high weight used for WRR (valid range from 0 - 255)",
1744 : : .category = FIO_OPT_C_ENGINE,
1745 : : .group = FIO_OPT_G_INVALID,
1746 : : },
1747 : : {
1748 : : .name = "wrr_priority",
1749 : : .lname = "priority used for WRR",
1750 : : .type = FIO_OPT_INT,
1751 : : .off1 = offsetof(struct spdk_fio_options, wrr_priority),
1752 : : .def = "0",
1753 : : .help = "priority used for WRR (valid range from 0-3)",
1754 : : .category = FIO_OPT_C_ENGINE,
1755 : : .group = FIO_OPT_G_INVALID,
1756 : : },
1757 : : {
1758 : : .name = "mem_size_mb",
1759 : : .lname = "Memory size in MB",
1760 : : .type = FIO_OPT_INT,
1761 : : .off1 = offsetof(struct spdk_fio_options, mem_size),
1762 : : .def = "0",
1763 : : .help = "Memory Size for SPDK (MB)",
1764 : : .category = FIO_OPT_C_ENGINE,
1765 : : .group = FIO_OPT_G_INVALID,
1766 : : },
1767 : : {
1768 : : .name = "shm_id",
1769 : : .lname = "shared memory ID",
1770 : : .type = FIO_OPT_INT,
1771 : : .off1 = offsetof(struct spdk_fio_options, shm_id),
1772 : : .def = "-1",
1773 : : .help = "Shared Memory ID",
1774 : : .category = FIO_OPT_C_ENGINE,
1775 : : .group = FIO_OPT_G_INVALID,
1776 : : },
1777 : : {
1778 : : .name = "enable_sgl",
1779 : : .lname = "SGL used for I/O commands",
1780 : : .type = FIO_OPT_INT,
1781 : : .off1 = offsetof(struct spdk_fio_options, enable_sgl),
1782 : : .def = "0",
1783 : : .help = "SGL Used for I/O Commands (enable_sgl=1 or enable_sgl=0)",
1784 : : .category = FIO_OPT_C_ENGINE,
1785 : : .group = FIO_OPT_G_INVALID,
1786 : : },
1787 : : {
1788 : : .name = "sge_size",
1789 : : .lname = "SGL size used for I/O commands",
1790 : : .type = FIO_OPT_INT,
1791 : : .off1 = offsetof(struct spdk_fio_options, sge_size),
1792 : : .def = "4096",
1793 : : .help = "SGL size in bytes for I/O Commands (default 4096)",
1794 : : .category = FIO_OPT_C_ENGINE,
1795 : : .group = FIO_OPT_G_INVALID,
1796 : : },
1797 : : {
1798 : : .name = "bit_bucket_data_len",
1799 : : .lname = "Amount of data used for Bit Bucket",
1800 : : .type = FIO_OPT_INT,
1801 : : .off1 = offsetof(struct spdk_fio_options, bit_bucket_data_len),
1802 : : .def = "0",
1803 : : .help = "Bit Bucket Data Length for READ commands (disabled by default)",
1804 : : .category = FIO_OPT_C_ENGINE,
1805 : : .group = FIO_OPT_G_INVALID,
1806 : : },
1807 : : {
1808 : : .name = "hostnqn",
1809 : : .lname = "Host NQN to use when connecting to controllers.",
1810 : : .type = FIO_OPT_STR_STORE,
1811 : : .off1 = offsetof(struct spdk_fio_options, hostnqn),
1812 : : .help = "Host NQN",
1813 : : .category = FIO_OPT_C_ENGINE,
1814 : : .group = FIO_OPT_G_INVALID,
1815 : : },
1816 : : {
1817 : : .name = "pi_act",
1818 : : .lname = "Protection Information Action",
1819 : : .type = FIO_OPT_INT,
1820 : : .off1 = offsetof(struct spdk_fio_options, pi_act),
1821 : : .def = "1",
1822 : : .help = "Protection Information Action bit (pi_act=1 or pi_act=0)",
1823 : : .category = FIO_OPT_C_ENGINE,
1824 : : .group = FIO_OPT_G_INVALID,
1825 : : },
1826 : : {
1827 : : .name = "pi_chk",
1828 : : .lname = "Protection Information Check(GUARD|REFTAG|APPTAG)",
1829 : : .type = FIO_OPT_STR_STORE,
1830 : : .off1 = offsetof(struct spdk_fio_options, pi_chk),
1831 : : .def = NULL,
1832 : : .help = "Control of Protection Information Checking (pi_chk=GUARD|REFTAG|APPTAG)",
1833 : : .category = FIO_OPT_C_ENGINE,
1834 : : .group = FIO_OPT_G_INVALID,
1835 : : },
1836 : : {
1837 : : .name = "md_per_io_size",
1838 : : .lname = "Separate Metadata Buffer Size per I/O",
1839 : : .type = FIO_OPT_INT,
1840 : : .off1 = offsetof(struct spdk_fio_options, md_per_io_size),
1841 : : .def = "4096",
1842 : : .help = "Size of separate metadata buffer per I/O (Default: 4096)",
1843 : : .category = FIO_OPT_C_ENGINE,
1844 : : .group = FIO_OPT_G_INVALID,
1845 : : },
1846 : : {
1847 : : .name = "apptag",
1848 : : .lname = "Application Tag used in Protection Information",
1849 : : .type = FIO_OPT_INT,
1850 : : .off1 = offsetof(struct spdk_fio_options, apptag),
1851 : : .def = "0x1234",
1852 : : .help = "Application Tag used in Protection Information field (Default: 0x1234)",
1853 : : .category = FIO_OPT_C_ENGINE,
1854 : : .group = FIO_OPT_G_INVALID,
1855 : : },
1856 : : {
1857 : : .name = "apptag_mask",
1858 : : .lname = "Application Tag Mask",
1859 : : .type = FIO_OPT_INT,
1860 : : .off1 = offsetof(struct spdk_fio_options, apptag_mask),
1861 : : .def = "0xffff",
1862 : : .help = "Application Tag Mask used with Application Tag (Default: 0xffff)",
1863 : : .category = FIO_OPT_C_ENGINE,
1864 : : .group = FIO_OPT_G_INVALID,
1865 : : },
1866 : : {
1867 : : .name = "digest_enable",
1868 : : .lname = "PDU digest choice for NVMe/TCP Transport(NONE|HEADER|DATA|BOTH)",
1869 : : .type = FIO_OPT_STR_STORE,
1870 : : .off1 = offsetof(struct spdk_fio_options, digest_enable),
1871 : : .def = NULL,
1872 : : .help = "Control the NVMe/TCP control(digest_enable=NONE|HEADER|DATA|BOTH)",
1873 : : .category = FIO_OPT_C_ENGINE,
1874 : : .group = FIO_OPT_G_INVALID,
1875 : : },
1876 : : {
1877 : : .name = "enable_vmd",
1878 : : .lname = "Enable VMD enumeration",
1879 : : .type = FIO_OPT_INT,
1880 : : .off1 = offsetof(struct spdk_fio_options, enable_vmd),
1881 : : .def = "0",
1882 : : .help = "Enable VMD enumeration (enable_vmd=1 or enable_vmd=0)",
1883 : : .category = FIO_OPT_C_ENGINE,
1884 : : .group = FIO_OPT_G_INVALID,
1885 : : },
1886 : : {
1887 : : .name = "initial_zone_reset",
1888 : : .lname = "Reset Zones on initialization",
1889 : : .type = FIO_OPT_INT,
1890 : : .off1 = offsetof(struct spdk_fio_options, initial_zone_reset),
1891 : : .def = "0",
1892 : : .help = "Reset Zones on initialization (0=disable, 1=Reset All Zones)",
1893 : : .category = FIO_OPT_C_ENGINE,
1894 : : .group = FIO_OPT_G_INVALID,
1895 : : },
1896 : : {
1897 : : .name = "zone_append",
1898 : : .lname = "Use zone append instead of write",
1899 : : .type = FIO_OPT_INT,
1900 : : .off1 = offsetof(struct spdk_fio_options, zone_append),
1901 : : .def = "0",
1902 : : .help = "Use zone append instead of write (1=zone append, 0=write)",
1903 : : .category = FIO_OPT_C_ENGINE,
1904 : : .group = FIO_OPT_G_INVALID,
1905 : : },
1906 : : {
1907 : : .name = "print_qid_mappings",
1908 : : .lname = "Print job-to-qid mappings",
1909 : : .type = FIO_OPT_INT,
1910 : : .off1 = offsetof(struct spdk_fio_options, print_qid_mappings),
1911 : : .def = "0",
1912 : : .help = "Print job-to-qid mappings (0=disable, 1=enable)",
1913 : : .category = FIO_OPT_C_ENGINE,
1914 : : .group = FIO_OPT_G_INVALID,
1915 : : },
1916 : : {
1917 : : .name = "log_flags",
1918 : : .lname = "log_flags",
1919 : : .type = FIO_OPT_STR_STORE,
1920 : : .off1 = offsetof(struct spdk_fio_options, log_flags),
1921 : : .help = "Enable log flags (comma-separated list)",
1922 : : .category = FIO_OPT_C_ENGINE,
1923 : : .group = FIO_OPT_G_INVALID,
1924 : : },
1925 : : {
1926 : : .name = "spdk_tracing",
1927 : : .lname = "Enable SPDK Tracing",
1928 : : .type = FIO_OPT_INT,
1929 : : .off1 = offsetof(struct spdk_fio_options, spdk_tracing),
1930 : : .def = "0",
1931 : : .help = "SPDK Tracing (0=disable, 1=enable)",
1932 : : .category = FIO_OPT_C_ENGINE,
1933 : : .group = FIO_OPT_G_INVALID,
1934 : : },
1935 : : {
1936 : : .name = NULL,
1937 : : },
1938 : : };
1939 : :
1940 : : /* FIO imports this structure using dlsym */
1941 : : struct ioengine_ops ioengine = {
1942 : : .name = "spdk",
1943 : : .version = FIO_IOOPS_VERSION,
1944 : : .queue = spdk_fio_queue,
1945 : : .getevents = spdk_fio_getevents,
1946 : : .event = spdk_fio_event,
1947 : : .cleanup = spdk_fio_cleanup,
1948 : : .open_file = spdk_fio_open,
1949 : : .close_file = spdk_fio_close,
1950 : : .invalidate = spdk_fio_invalidate,
1951 : : .iomem_alloc = spdk_fio_iomem_alloc,
1952 : : .iomem_free = spdk_fio_iomem_free,
1953 : : .setup = spdk_fio_setup,
1954 : : .init = spdk_fio_init,
1955 : : .io_u_init = spdk_fio_io_u_init,
1956 : : .io_u_free = spdk_fio_io_u_free,
1957 : : #if FIO_HAS_ZBD
1958 : : .get_zoned_model = spdk_fio_get_zoned_model,
1959 : : .report_zones = spdk_fio_report_zones,
1960 : : .reset_wp = spdk_fio_reset_wp,
1961 : : #endif
1962 : : #if FIO_IOOPS_VERSION >= 30
1963 : : .get_max_open_zones = spdk_fio_get_max_open_zones,
1964 : : #endif
1965 : : #if FIO_HAS_FDP
1966 : : .fdp_fetch_ruhs = spdk_fio_fdp_fetch_ruhs,
1967 : : #endif
1968 : : #if FIO_HAS_MRT
1969 : : .flags = FIO_RAWIO | FIO_NOEXTEND | FIO_NODISKUTIL | FIO_MEMALIGN | FIO_DISKLESSIO | FIO_MULTI_RANGE_TRIM,
1970 : : #else
1971 : : .flags = FIO_RAWIO | FIO_NOEXTEND | FIO_NODISKUTIL | FIO_MEMALIGN | FIO_DISKLESSIO,
1972 : : #endif
1973 : : .options = options,
1974 : : .option_struct_size = sizeof(struct spdk_fio_options),
1975 : : };
1976 : :
1977 : : static void fio_init
1978 : 18 : fio_spdk_register(void)
1979 : : {
1980 : 18 : register_ioengine(&ioengine);
1981 : 18 : }
1982 : :
1983 : : static void fio_exit
1984 : 18 : fio_spdk_unregister(void)
1985 : : {
1986 [ + + + - ]: 18 : if (g_spdk_env_initialized) {
1987 : 18 : spdk_trace_cleanup();
1988 : 18 : spdk_env_fini();
1989 : : }
1990 : :
1991 : 18 : unregister_ioengine(&ioengine);
1992 : 18 : }
1993 : :
1994 : 18 : SPDK_LOG_REGISTER_COMPONENT(fio_nvme)
|