LCOV - code coverage report
Current view: top level - spdk/test/app/fuzz/nvme_fuzz - nvme_fuzz.c (source / functions) Hit Total Coverage
Test: Combined Lines: 253 452 56.0 %
Date: 2024-07-15 20:55:59 Functions: 20 24 83.3 %
Legend: Lines: hit not hit | Branches: + taken - not taken # not executed Branches: 135 507 26.6 %

           Branch data     Line data    Source code
       1                 :            : /*   SPDX-License-Identifier: BSD-3-Clause
       2                 :            :  *   Copyright (C) 2018 Intel Corporation. All rights reserved.
       3                 :            :  *   Copyright (c) 2019 Mellanox Technologies LTD. All rights reserved.
       4                 :            :  */
       5                 :            : 
       6                 :            : #include "spdk/stdinc.h"
       7                 :            : #include "spdk/conf.h"
       8                 :            : #include "spdk/env.h"
       9                 :            : #include "spdk/event.h"
      10                 :            : #include "spdk/util.h"
      11                 :            : #include "spdk/string.h"
      12                 :            : #include "spdk/nvme_spec.h"
      13                 :            : #include "spdk/nvme.h"
      14                 :            : #include "spdk/likely.h"
      15                 :            : #include "spdk/json.h"
      16                 :            : #include "fuzz_common.h"
      17                 :            : 
      18                 :            : #define UNIQUE_OPCODES 256
      19                 :            : 
      20                 :            : const char g_nvme_cmd_json_name[] = "struct spdk_nvme_cmd";
      21                 :            : char *g_json_file = NULL;
      22                 :            : uint64_t g_runtime_ticks;
      23                 :            : unsigned int g_seed_value = 0;
      24                 :            : int g_runtime;
      25                 :            : 
      26                 :            : int g_num_active_threads = 0;
      27                 :            : uint32_t g_admin_depth = 16;
      28                 :            : uint32_t g_io_depth = 128;
      29                 :            : bool g_check_iommu = true;
      30                 :            : 
      31                 :            : bool g_valid_ns_only = false;
      32                 :            : bool g_verbose_mode = false;
      33                 :            : bool g_run_admin_commands = false;
      34                 :            : bool g_run;
      35                 :            : 
      36                 :            : struct spdk_poller *g_app_completion_poller;
      37                 :            : bool g_successful_io_opcodes[UNIQUE_OPCODES] = {0};
      38                 :            : bool g_successful_admin_opcodes[UNIQUE_OPCODES] = {0};
      39                 :            : 
      40                 :            : struct spdk_nvme_cmd *g_cmd_array;
      41                 :            : size_t g_cmd_array_size;
      42                 :            : 
      43                 :            : /* I need context objects here because I need to keep track of all I/O that are in flight. */
      44                 :            : struct nvme_fuzz_request {
      45                 :            :         struct spdk_nvme_cmd            cmd;
      46                 :            :         struct nvme_fuzz_qp             *qp;
      47                 :            :         TAILQ_ENTRY(nvme_fuzz_request)  link;
      48                 :            : };
      49                 :            : 
      50                 :            : struct nvme_fuzz_trid {
      51                 :            :         struct spdk_nvme_transport_id   trid;
      52                 :            :         TAILQ_ENTRY(nvme_fuzz_trid)     tailq;
      53                 :            : };
      54                 :            : 
      55                 :            : struct nvme_fuzz_ctrlr {
      56                 :            :         struct spdk_nvme_ctrlr          *ctrlr;
      57                 :            :         TAILQ_ENTRY(nvme_fuzz_ctrlr)    tailq;
      58                 :            : };
      59                 :            : 
      60                 :            : struct nvme_fuzz_qp {
      61                 :            :         struct spdk_nvme_qpair          *qpair;
      62                 :            :         /* array of context objects equal in length to the queue depth */
      63                 :            :         struct nvme_fuzz_request        *req_ctx;
      64                 :            :         TAILQ_HEAD(, nvme_fuzz_request) free_ctx_objs;
      65                 :            :         TAILQ_HEAD(, nvme_fuzz_request) outstanding_ctx_objs;
      66                 :            :         unsigned int                    random_seed;
      67                 :            :         uint64_t                        completed_cmd_counter;
      68                 :            :         uint64_t                        submitted_cmd_counter;
      69                 :            :         uint64_t                        successful_completed_cmd_counter;
      70                 :            :         uint64_t                        timeout_tsc;
      71                 :            :         uint32_t                        num_cmds_outstanding;
      72                 :            :         bool                            timed_out;
      73                 :            :         bool                            is_admin;
      74                 :            : };
      75                 :            : 
      76                 :            : struct nvme_fuzz_ns {
      77                 :            :         struct spdk_nvme_ns             *ns;
      78                 :            :         struct spdk_nvme_ctrlr          *ctrlr;
      79                 :            :         struct spdk_thread              *thread;
      80                 :            :         struct spdk_poller              *req_poller;
      81                 :            :         struct nvme_fuzz_qp             io_qp;
      82                 :            :         struct nvme_fuzz_qp             a_qp;
      83                 :            :         uint32_t                        nsid;
      84                 :            :         TAILQ_ENTRY(nvme_fuzz_ns)       tailq;
      85                 :            : };
      86                 :            : 
      87                 :            : static TAILQ_HEAD(, nvme_fuzz_ns) g_ns_list = TAILQ_HEAD_INITIALIZER(g_ns_list);
      88                 :            : static TAILQ_HEAD(, nvme_fuzz_ctrlr) g_ctrlr_list = TAILQ_HEAD_INITIALIZER(g_ctrlr_list);
      89                 :            : static TAILQ_HEAD(, nvme_fuzz_trid) g_trid_list = TAILQ_HEAD_INITIALIZER(g_trid_list);
      90                 :            : 
      91                 :            : static bool
      92                 :          0 : parse_nvme_cmd_obj(void *item, struct spdk_json_val *value, size_t num_values)
      93                 :            : {
      94                 :          0 :         struct spdk_nvme_cmd *cmd = item;
      95                 :            :         struct spdk_json_val *next_val;
      96                 :          0 :         uint64_t tmp_val;
      97                 :          0 :         size_t i = 0;
      98                 :            : 
      99         [ #  # ]:          0 :         while (i < num_values) {
     100         [ #  # ]:          0 :                 if (value->type == SPDK_JSON_VAL_NAME) {
     101                 :          0 :                         next_val = value + 1;
     102   [ #  #  #  # ]:          0 :                         if (!strncmp(value->start, "opc", value->len)) {
     103         [ #  # ]:          0 :                                 if (next_val->type == SPDK_JSON_VAL_NUMBER) {
     104         [ #  # ]:          0 :                                         if (fuzz_parse_json_num(next_val, UNSIGNED_8BIT_MAX, &tmp_val)) {
     105                 :          0 :                                                 goto invalid;
     106                 :            :                                         }
     107                 :          0 :                                         cmd->opc = tmp_val;
     108                 :            :                                 }
     109   [ #  #  #  # ]:          0 :                         } else if (!strncmp(value->start, "fuse", value->len)) {
     110         [ #  # ]:          0 :                                 if (next_val->type == SPDK_JSON_VAL_NUMBER) {
     111         [ #  # ]:          0 :                                         if (fuzz_parse_json_num(next_val, UNSIGNED_2BIT_MAX, &tmp_val)) {
     112                 :          0 :                                                 goto invalid;
     113                 :            :                                         }
     114                 :          0 :                                         cmd->fuse = tmp_val;
     115                 :            :                                 }
     116   [ #  #  #  # ]:          0 :                         } else if (!strncmp(value->start, "rsvd1", value->len)) {
     117         [ #  # ]:          0 :                                 if (next_val->type == SPDK_JSON_VAL_NUMBER) {
     118         [ #  # ]:          0 :                                         if (fuzz_parse_json_num(next_val, UNSIGNED_4BIT_MAX, &tmp_val)) {
     119                 :          0 :                                                 goto invalid;
     120                 :            :                                         }
     121                 :          0 :                                         cmd->rsvd1 = tmp_val;
     122                 :            :                                 }
     123   [ #  #  #  # ]:          0 :                         } else if (!strncmp(value->start, "psdt", value->len)) {
     124         [ #  # ]:          0 :                                 if (next_val->type == SPDK_JSON_VAL_NUMBER) {
     125         [ #  # ]:          0 :                                         if (fuzz_parse_json_num(next_val, UNSIGNED_2BIT_MAX, &tmp_val)) {
     126                 :          0 :                                                 goto invalid;
     127                 :            :                                         }
     128                 :          0 :                                         cmd->psdt = tmp_val;
     129                 :            :                                 }
     130   [ #  #  #  # ]:          0 :                         } else if (!strncmp(value->start, "cid", value->len)) {
     131         [ #  # ]:          0 :                                 if (next_val->type == SPDK_JSON_VAL_NUMBER) {
     132         [ #  # ]:          0 :                                         if (fuzz_parse_json_num(next_val, UINT16_MAX, &tmp_val)) {
     133                 :          0 :                                                 goto invalid;
     134                 :            :                                         }
     135                 :          0 :                                         cmd->cid = tmp_val;
     136                 :            :                                 }
     137   [ #  #  #  # ]:          0 :                         } else if (!strncmp(value->start, "nsid", value->len)) {
     138         [ #  # ]:          0 :                                 if (next_val->type == SPDK_JSON_VAL_NUMBER) {
     139         [ #  # ]:          0 :                                         if (fuzz_parse_json_num(next_val, UINT32_MAX, &tmp_val)) {
     140                 :          0 :                                                 goto invalid;
     141                 :            :                                         }
     142                 :          0 :                                         cmd->nsid = tmp_val;
     143                 :            :                                 }
     144   [ #  #  #  # ]:          0 :                         } else if (!strncmp(value->start, "rsvd2", value->len)) {
     145         [ #  # ]:          0 :                                 if (next_val->type == SPDK_JSON_VAL_NUMBER) {
     146         [ #  # ]:          0 :                                         if (fuzz_parse_json_num(next_val, UINT32_MAX, &tmp_val)) {
     147                 :          0 :                                                 goto invalid;
     148                 :            :                                         }
     149                 :          0 :                                         cmd->rsvd2 = tmp_val;
     150                 :            :                                 }
     151   [ #  #  #  # ]:          0 :                         } else if (!strncmp(value->start, "rsvd3", value->len)) {
     152         [ #  # ]:          0 :                                 if (next_val->type == SPDK_JSON_VAL_NUMBER) {
     153         [ #  # ]:          0 :                                         if (fuzz_parse_json_num(next_val, UINT32_MAX, &tmp_val)) {
     154                 :          0 :                                                 goto invalid;
     155                 :            :                                         }
     156                 :          0 :                                         cmd->rsvd3 = tmp_val;
     157                 :            :                                 }
     158   [ #  #  #  # ]:          0 :                         } else if (!strncmp(value->start, "mptr", value->len)) {
     159         [ #  # ]:          0 :                                 if (next_val->type == SPDK_JSON_VAL_NUMBER) {
     160         [ #  # ]:          0 :                                         if (fuzz_parse_json_num(next_val, UINT64_MAX, &tmp_val)) {
     161                 :          0 :                                                 goto invalid;
     162                 :            :                                         }
     163                 :          0 :                                         cmd->mptr = tmp_val;
     164                 :            :                                 }
     165   [ #  #  #  # ]:          0 :                         } else if (!strncmp(value->start, "dptr", value->len)) {
     166         [ #  # ]:          0 :                                 if (next_val->type == SPDK_JSON_VAL_STRING) {
     167         [ #  # ]:          0 :                                         if (fuzz_get_base_64_buffer_value(&cmd->dptr, sizeof(cmd->dptr), (char *)next_val->start,
     168                 :          0 :                                                                           next_val->len)) {
     169                 :          0 :                                                 goto invalid;
     170                 :            :                                         }
     171                 :            :                                 }
     172   [ #  #  #  # ]:          0 :                         } else if (!strncmp(value->start, "cdw10", value->len)) {
     173         [ #  # ]:          0 :                                 if (next_val->type == SPDK_JSON_VAL_NUMBER) {
     174         [ #  # ]:          0 :                                         if (fuzz_parse_json_num(next_val, UINT32_MAX, &tmp_val)) {
     175                 :          0 :                                                 goto invalid;
     176                 :            :                                         }
     177                 :          0 :                                         cmd->cdw10 = tmp_val;
     178                 :            :                                 }
     179   [ #  #  #  # ]:          0 :                         } else if (!strncmp(value->start, "cdw11", value->len)) {
     180         [ #  # ]:          0 :                                 if (next_val->type == SPDK_JSON_VAL_NUMBER) {
     181         [ #  # ]:          0 :                                         if (fuzz_parse_json_num(next_val, UINT32_MAX, &tmp_val)) {
     182                 :          0 :                                                 goto invalid;
     183                 :            :                                         }
     184                 :          0 :                                         cmd->cdw11 = tmp_val;
     185                 :            :                                 }
     186   [ #  #  #  # ]:          0 :                         } else if (!strncmp(value->start, "cdw12", value->len)) {
     187         [ #  # ]:          0 :                                 if (next_val->type == SPDK_JSON_VAL_NUMBER) {
     188         [ #  # ]:          0 :                                         if (fuzz_parse_json_num(next_val, UINT32_MAX, &tmp_val)) {
     189                 :          0 :                                                 goto invalid;
     190                 :            :                                         }
     191                 :          0 :                                         cmd->cdw12 = tmp_val;
     192                 :            :                                 }
     193   [ #  #  #  # ]:          0 :                         } else if (!strncmp(value->start, "cdw13", value->len)) {
     194         [ #  # ]:          0 :                                 if (next_val->type == SPDK_JSON_VAL_NUMBER) {
     195         [ #  # ]:          0 :                                         if (fuzz_parse_json_num(next_val, UINT32_MAX, &tmp_val)) {
     196                 :          0 :                                                 goto invalid;
     197                 :            :                                         }
     198                 :          0 :                                         cmd->cdw13 = tmp_val;
     199                 :            :                                 }
     200   [ #  #  #  # ]:          0 :                         } else if (!strncmp(value->start, "cdw14", value->len)) {
     201         [ #  # ]:          0 :                                 if (next_val->type == SPDK_JSON_VAL_NUMBER) {
     202         [ #  # ]:          0 :                                         if (fuzz_parse_json_num(next_val, UINT32_MAX, &tmp_val)) {
     203                 :          0 :                                                 goto invalid;
     204                 :            :                                         }
     205                 :          0 :                                         cmd->cdw14 = tmp_val;
     206                 :            :                                 }
     207   [ #  #  #  # ]:          0 :                         } else if (!strncmp(value->start, "cdw15", value->len)) {
     208         [ #  # ]:          0 :                                 if (next_val->type == SPDK_JSON_VAL_NUMBER) {
     209         [ #  # ]:          0 :                                         if (fuzz_parse_json_num(next_val, UINT32_MAX, &tmp_val)) {
     210                 :          0 :                                                 goto invalid;
     211                 :            :                                         }
     212                 :          0 :                                         cmd->cdw15 = tmp_val;
     213                 :            :                                 }
     214                 :            :                         }
     215                 :            :                 }
     216                 :          0 :                 i++;
     217                 :          0 :                 value++;
     218                 :            :         }
     219                 :          0 :         return true;
     220                 :            : 
     221                 :          0 : invalid:
     222         [ #  # ]:          0 :         fprintf(stderr, "Invalid value supplied for cmd->%.*s: %.*s\n", value->len, (char *)value->start,
     223                 :          0 :                 next_val->len, (char *)next_val->start);
     224                 :          0 :         return false;
     225                 :            : }
     226                 :            : 
     227                 :            : static void
     228                 :          2 : report_successful_opcodes(bool *array, int length)
     229                 :            : {
     230                 :            :         int i;
     231                 :            : 
     232         [ +  + ]:        514 :         for (i = 0; i < length; i++) {
     233   [ -  +  +  + ]:        512 :                 if (array[i] == true) {
     234         [ -  + ]:          5 :                         printf("%d, ", i);
     235                 :            :                 }
     236                 :            :         }
     237                 :          2 :         printf("\n");
     238                 :          2 : }
     239                 :            : 
     240                 :            : static int
     241                 :       3790 : print_nvme_cmd(void *cb_ctx, const void *data, size_t size)
     242                 :            : {
     243   [ -  +  -  + ]:       3790 :         fprintf(stderr, "%s\n", (const char *)data);
     244                 :       3790 :         return 0;
     245                 :            : }
     246                 :            : 
     247                 :            : static void
     248                 :       3790 : json_dump_nvme_cmd(struct spdk_nvme_cmd *cmd)
     249                 :            : {
     250                 :            :         struct spdk_json_write_ctx *w;
     251                 :            :         char *dptr_value;
     252                 :            : 
     253                 :       3790 :         dptr_value = fuzz_get_value_base_64_buffer(&cmd->dptr, sizeof(cmd->dptr));
     254         [ -  + ]:       3790 :         if (dptr_value == NULL) {
     255   [ #  #  #  # ]:          0 :                 fprintf(stderr, "Unable to allocate buffer context for printing command.\n");
     256                 :          0 :                 return;
     257                 :            :         }
     258                 :            : 
     259                 :       3790 :         w = spdk_json_write_begin(print_nvme_cmd, cmd, SPDK_JSON_WRITE_FLAG_FORMATTED);
     260         [ -  + ]:       3790 :         if (w == NULL) {
     261   [ #  #  #  # ]:          0 :                 fprintf(stderr, "Unable to allocate json context for printing command.\n");
     262                 :          0 :                 free(dptr_value);
     263                 :          0 :                 return;
     264                 :            :         }
     265                 :            : 
     266                 :       3790 :         spdk_json_write_named_object_begin(w, g_nvme_cmd_json_name);
     267                 :       3790 :         spdk_json_write_named_uint32(w, "opc", cmd->opc);
     268                 :       3790 :         spdk_json_write_named_uint32(w, "fuse", cmd->fuse);
     269                 :       3790 :         spdk_json_write_named_uint32(w, "rsvd1", cmd->rsvd1);
     270                 :       3790 :         spdk_json_write_named_uint32(w, "psdt", cmd->psdt);
     271                 :       3790 :         spdk_json_write_named_uint32(w, "cid", cmd->cid);
     272                 :       3790 :         spdk_json_write_named_uint32(w, "nsid", cmd->nsid);
     273                 :       3790 :         spdk_json_write_named_uint32(w, "rsvd2", cmd->rsvd2);
     274                 :       3790 :         spdk_json_write_named_uint32(w, "rsvd3", cmd->rsvd3);
     275                 :       3790 :         spdk_json_write_named_uint32(w, "mptr", cmd->mptr);
     276                 :       3790 :         spdk_json_write_named_string(w, "dptr", dptr_value);
     277                 :       3790 :         spdk_json_write_named_uint32(w, "cdw10", cmd->cdw10);
     278                 :       3790 :         spdk_json_write_named_uint32(w, "cdw11", cmd->cdw11);
     279                 :       3790 :         spdk_json_write_named_uint32(w, "cdw12", cmd->cdw12);
     280                 :       3790 :         spdk_json_write_named_uint32(w, "cdw13", cmd->cdw13);
     281                 :       3790 :         spdk_json_write_named_uint32(w, "cdw14", cmd->cdw14);
     282                 :       3790 :         spdk_json_write_named_uint32(w, "cdw15", cmd->cdw15);
     283                 :       3790 :         spdk_json_write_object_end(w);
     284                 :            : 
     285                 :       3790 :         free(dptr_value);
     286                 :       3790 :         spdk_json_write_end(w);
     287                 :            : }
     288                 :            : 
     289                 :            : static void
     290                 :          0 : json_dump_nvme_cmd_list(struct nvme_fuzz_qp *qp)
     291                 :            : {
     292                 :            :         struct nvme_fuzz_request *ctx;
     293                 :            : 
     294         [ #  # ]:          0 :         TAILQ_FOREACH(ctx, &qp->outstanding_ctx_objs, link) {
     295                 :          0 :                 json_dump_nvme_cmd(&ctx->cmd);
     296                 :            :         }
     297                 :          0 : }
     298                 :            : 
     299                 :            : static void
     300                 :          0 : handle_timeout(struct nvme_fuzz_qp *qp, bool is_admin)
     301                 :            : {
     302   [ #  #  #  #  :          0 :         fprintf(stderr, "An %s queue has timed out. Dumping all outstanding commands from that queue\n",
                   #  # ]
     303                 :            :                 is_admin ? "Admin" : "I/O");
     304                 :          0 :         json_dump_nvme_cmd_list(qp);
     305                 :          0 :         qp->timed_out = true;
     306                 :          0 : }
     307                 :            : 
     308                 :            : static void submit_ns_cmds(struct nvme_fuzz_ns *ns_entry);
     309                 :            : 
     310                 :            : static void
     311                 :     822872 : nvme_fuzz_cpl_cb(void *cb_arg, const struct spdk_nvme_cpl *cpl)
     312                 :            : {
     313                 :     822872 :         struct nvme_fuzz_request *ctx = cb_arg;
     314                 :     822872 :         struct nvme_fuzz_qp *qp = ctx->qp;
     315                 :            : 
     316                 :     822872 :         qp->completed_cmd_counter++;
     317         [ +  + ]:     822872 :         if (spdk_unlikely(cpl->status.sc == SPDK_NVME_SC_SUCCESS)) {
     318         [ -  + ]:       7580 :                 fprintf(stderr, "The following %s command (command num %" PRIu64 ") completed successfully\n",
     319   [ -  +  +  + ]:       3790 :                         qp->is_admin ? "Admin" : "I/O", qp->completed_cmd_counter);
     320                 :       3790 :                 qp->successful_completed_cmd_counter++;
     321                 :       3790 :                 json_dump_nvme_cmd(&ctx->cmd);
     322                 :            : 
     323   [ -  +  +  + ]:       3790 :                 if (qp->is_admin) {
     324                 :       1126 :                         __sync_bool_compare_and_swap(&g_successful_admin_opcodes[ctx->cmd.opc], false, true);
     325                 :            :                 } else {
     326                 :       2664 :                         __sync_bool_compare_and_swap(&g_successful_io_opcodes[ctx->cmd.opc], false, true);
     327                 :            :                 }
     328   [ -  +  -  + ]:     819082 :         } else if (g_verbose_mode == true) {
     329         [ #  # ]:          0 :                 fprintf(stderr, "The following %s command (command num %" PRIu64 ") failed as expected.\n",
     330   [ #  #  #  # ]:          0 :                         qp->is_admin ? "Admin" : "I/O", qp->completed_cmd_counter);
     331                 :          0 :                 json_dump_nvme_cmd(&ctx->cmd);
     332                 :            :         }
     333                 :            : 
     334                 :     822872 :         qp->timeout_tsc = fuzz_refresh_timeout();
     335         [ +  + ]:     822872 :         TAILQ_REMOVE(&qp->outstanding_ctx_objs, ctx, link);
     336         [ +  + ]:     822872 :         TAILQ_INSERT_HEAD(&qp->free_ctx_objs, ctx, link);
     337         [ -  + ]:     822872 :         assert(qp->num_cmds_outstanding > 0);
     338                 :     822872 :         qp->num_cmds_outstanding--;
     339                 :     822872 : }
     340                 :            : 
     341                 :            : static int
     342                 :     998751 : poll_for_completions(void *arg)
     343                 :            : {
     344                 :     998751 :         struct nvme_fuzz_ns *ns_entry = arg;
     345                 :     998751 :         uint64_t current_ticks = spdk_get_ticks();
     346                 :            :         uint64_t *counter;
     347   [ -  +  +  - ]:     998751 :         if (!ns_entry->io_qp.timed_out) {
     348                 :     998751 :                 spdk_nvme_qpair_process_completions(ns_entry->io_qp.qpair, 0);
     349                 :            :                 /* SAlways have to process admin completions for the purposes of keep alive. */
     350                 :     998751 :                 spdk_nvme_ctrlr_process_admin_completions(ns_entry->ctrlr);
     351                 :            :         }
     352                 :            : 
     353         [ -  + ]:     998751 :         if (g_cmd_array) {
     354   [ #  #  #  # ]:          0 :                 if (g_run_admin_commands) {
     355                 :          0 :                         counter = &ns_entry->a_qp.submitted_cmd_counter;
     356                 :            :                 } else {
     357                 :          0 :                         counter = &ns_entry->io_qp.submitted_cmd_counter;
     358                 :            :                 }
     359                 :            : 
     360         [ #  # ]:          0 :                 if (*counter >= g_cmd_array_size) {
     361                 :          0 :                         g_run = false;
     362                 :            :                 }
     363                 :            :         } else {
     364         [ +  + ]:     998751 :                 if (current_ticks > g_runtime_ticks) {
     365                 :          2 :                         g_run = false;
     366                 :            :                 }
     367                 :            :         }
     368                 :            : 
     369   [ -  +  -  -  :     998751 :         if (ns_entry->a_qp.timeout_tsc < current_ticks && !ns_entry->a_qp.timed_out &&
                   -  - ]
     370         [ #  # ]:          0 :             ns_entry->a_qp.num_cmds_outstanding > 0) {
     371                 :          0 :                 handle_timeout(&ns_entry->a_qp, true);
     372                 :            :         }
     373                 :            : 
     374   [ -  +  -  -  :     998751 :         if (ns_entry->io_qp.timeout_tsc < current_ticks && !ns_entry->io_qp.timed_out &&
                   -  - ]
     375         [ #  # ]:          0 :             ns_entry->io_qp.num_cmds_outstanding > 0) {
     376                 :          0 :                 handle_timeout(&ns_entry->io_qp, false);
     377                 :            :         }
     378                 :            : 
     379                 :     998751 :         submit_ns_cmds(ns_entry);
     380                 :            : 
     381   [ -  +  +  + ]:     998751 :         if (g_run) {
     382                 :     998749 :                 return 0;
     383                 :            :         }
     384                 :            :         /*
     385                 :            :          * We either processed all I/O properly and can shut down normally, or we
     386                 :            :          * had a qp time out and we need to exit without reducing the values to 0.
     387                 :            :          */
     388         [ +  + ]:          2 :         if (ns_entry->io_qp.num_cmds_outstanding == 0 &&
     389         [ +  - ]:          1 :             ns_entry->a_qp.num_cmds_outstanding == 0) {
     390                 :          1 :                 goto exit_handler;
     391   [ -  +  -  +  :          1 :         } else if (ns_entry->io_qp.timed_out && (!g_run_admin_commands || ns_entry->a_qp.timed_out)) {
          -  -  -  -  -  
                -  -  - ]
     392                 :          0 :                 goto exit_handler;
     393                 :            :         } else {
     394                 :          1 :                 return 0;
     395                 :            :         }
     396                 :            : 
     397                 :          1 : exit_handler:
     398                 :          1 :         spdk_poller_unregister(&ns_entry->req_poller);
     399                 :          1 :         __sync_sub_and_fetch(&g_num_active_threads, 1);
     400                 :          1 :         spdk_thread_exit(ns_entry->thread);
     401                 :          1 :         return 0;
     402                 :            : }
     403                 :            : 
     404                 :            : static void
     405                 :     823426 : prep_nvme_cmd(struct nvme_fuzz_ns *ns_entry, struct nvme_fuzz_qp *qp, struct nvme_fuzz_request *ctx)
     406                 :            : {
     407         [ -  + ]:     823426 :         if (g_cmd_array) {
     408   [ #  #  #  # ]:          0 :                 memcpy(&ctx->cmd, &g_cmd_array[qp->submitted_cmd_counter], sizeof(ctx->cmd));
     409                 :            :         } else {
     410                 :     823426 :                 fuzz_fill_random_bytes((char *)&ctx->cmd, sizeof(ctx->cmd), &qp->random_seed);
     411                 :            : 
     412   [ -  +  +  - ]:     823426 :                 if (g_valid_ns_only) {
     413                 :     823426 :                         ctx->cmd.nsid = ns_entry->nsid;
     414                 :            :                 }
     415                 :            :         }
     416                 :            : 
     417                 :            :         /* Fuzzing test not support sequential FUSE commands. */
     418                 :     823426 :         ctx->cmd.fuse = 0;
     419                 :     823426 : }
     420                 :            : 
     421                 :            : static int
     422                 :    1997500 : submit_qp_cmds(struct nvme_fuzz_ns *ns, struct nvme_fuzz_qp *qp)
     423                 :            : {
     424                 :            :         struct nvme_fuzz_request *ctx;
     425                 :            :         int rc;
     426                 :            : 
     427   [ -  +  -  + ]:    1997500 :         if (qp->timed_out) {
     428                 :          0 :                 return 0;
     429                 :            :         }
     430                 :            :         /* If we are reading from an array, we need to stop after the last one. */
     431   [ +  -  +  - ]:    2820372 :         while ((qp->submitted_cmd_counter < g_cmd_array_size || g_cmd_array_size == 0) &&
     432         [ +  + ]:    2820372 :                !TAILQ_EMPTY(&qp->free_ctx_objs)) {
     433                 :     822872 :                 ctx = TAILQ_FIRST(&qp->free_ctx_objs);
     434                 :            :                 do {
     435                 :     823426 :                         prep_nvme_cmd(ns, qp, ctx);
     436   [ -  +  +  +  :     823426 :                 } while (qp->is_admin && ctx->cmd.opc == SPDK_NVME_OPC_ASYNC_EVENT_REQUEST);
                   +  + ]
     437                 :            : 
     438         [ +  + ]:     822872 :                 TAILQ_REMOVE(&qp->free_ctx_objs, ctx, link);
     439         [ +  + ]:     822872 :                 TAILQ_INSERT_HEAD(&qp->outstanding_ctx_objs, ctx, link);
     440                 :     822872 :                 qp->num_cmds_outstanding++;
     441                 :     822872 :                 qp->submitted_cmd_counter++;
     442   [ -  +  +  + ]:     822872 :                 if (qp->is_admin) {
     443                 :     138878 :                         rc = spdk_nvme_ctrlr_cmd_admin_raw(ns->ctrlr, &ctx->cmd, NULL, 0, nvme_fuzz_cpl_cb, ctx);
     444                 :            :                 } else {
     445                 :     683994 :                         rc = spdk_nvme_ctrlr_cmd_io_raw(ns->ctrlr, qp->qpair, &ctx->cmd, NULL, 0, nvme_fuzz_cpl_cb, ctx);
     446                 :            :                 }
     447         [ -  + ]:     822872 :                 if (rc) {
     448                 :          0 :                         return rc;
     449                 :            :                 }
     450                 :            :         }
     451                 :    1997500 :         return 0;
     452                 :            : }
     453                 :            : 
     454                 :            : static void
     455                 :     998752 : submit_ns_cmds(struct nvme_fuzz_ns *ns_entry)
     456                 :            : {
     457                 :            :         int rc;
     458                 :            : 
     459   [ -  +  +  + ]:     998752 :         if (!g_run) {
     460                 :          2 :                 return;
     461                 :            :         }
     462                 :            : 
     463   [ -  +  +  - ]:     998750 :         if (g_run_admin_commands) {
     464                 :     998750 :                 rc = submit_qp_cmds(ns_entry, &ns_entry->a_qp);
     465         [ -  + ]:     998750 :                 if (rc) {
     466                 :          0 :                         goto err_exit;
     467                 :            :                 }
     468                 :            :         }
     469                 :            : 
     470   [ -  +  -  -  :     998750 :         if (g_cmd_array == NULL || !g_run_admin_commands) {
                   -  - ]
     471                 :     998750 :                 rc = submit_qp_cmds(ns_entry, &ns_entry->io_qp);
     472                 :            :         }
     473                 :          0 : err_exit:
     474         [ -  + ]:     998750 :         if (rc) {
     475                 :            :                 /*
     476                 :            :                  * I see the prospect of having a broken qpair on one ns as interesting
     477                 :            :                  * enough to recommend stopping the application.
     478                 :            :                  */
     479   [ #  #  #  # ]:          0 :                 fprintf(stderr, "Unable to submit command with rc %d\n", rc);
     480                 :          0 :                 g_run = false;
     481                 :            :         }
     482                 :            : }
     483                 :            : 
     484                 :            : static void
     485                 :          1 : free_namespaces(void)
     486                 :            : {
     487                 :            :         struct nvme_fuzz_ns *ns, *tmp;
     488                 :            : 
     489         [ +  + ]:          2 :         TAILQ_FOREACH_SAFE(ns, &g_ns_list, tailq, tmp) {
     490         [ -  + ]:          1 :                 printf("NS: %p I/O qp, Total commands completed: %" PRIu64 ", total successful commands: %" PRIu64
     491                 :            :                        ", random_seed: %u\n",
     492                 :            :                        ns->ns,
     493                 :            :                        ns->io_qp.completed_cmd_counter, ns->io_qp.successful_completed_cmd_counter, ns->io_qp.random_seed);
     494         [ -  + ]:          1 :                 printf("NS: %p admin qp, Total commands completed: %" PRIu64 ", total successful commands: %" PRIu64
     495                 :            :                        ", random_seed: %u\n",
     496                 :            :                        ns->ns,
     497                 :            :                        ns->a_qp.completed_cmd_counter, ns->a_qp.successful_completed_cmd_counter, ns->a_qp.random_seed);
     498                 :            : 
     499         [ -  + ]:          1 :                 TAILQ_REMOVE(&g_ns_list, ns, tailq);
     500         [ +  - ]:          1 :                 if (ns->io_qp.qpair) {
     501                 :          1 :                         spdk_nvme_ctrlr_free_io_qpair(ns->io_qp.qpair);
     502                 :            :                 }
     503         [ +  - ]:          1 :                 if (ns->io_qp.req_ctx) {
     504                 :          1 :                         free(ns->io_qp.req_ctx);
     505                 :            :                 }
     506         [ +  - ]:          1 :                 if (ns->a_qp.req_ctx) {
     507                 :          1 :                         free(ns->a_qp.req_ctx);
     508                 :            :                 }
     509                 :          1 :                 free(ns);
     510                 :            :         }
     511                 :          1 : }
     512                 :            : 
     513                 :            : static void
     514                 :          1 : free_controllers(void)
     515                 :            : {
     516                 :            :         struct nvme_fuzz_ctrlr *ctrlr, *tmp;
     517                 :          1 :         struct spdk_nvme_detach_ctx *detach_ctx = NULL;
     518                 :            : 
     519         [ +  + ]:          2 :         TAILQ_FOREACH_SAFE(ctrlr, &g_ctrlr_list, tailq, tmp) {
     520         [ -  + ]:          1 :                 TAILQ_REMOVE(&g_ctrlr_list, ctrlr, tailq);
     521                 :          1 :                 spdk_nvme_detach_async(ctrlr->ctrlr, &detach_ctx);
     522                 :          1 :                 free(ctrlr);
     523                 :            :         }
     524                 :            : 
     525         [ +  - ]:          1 :         if (detach_ctx) {
     526                 :          1 :                 spdk_nvme_detach_poll(detach_ctx);
     527                 :            :         }
     528                 :          1 : }
     529                 :            : 
     530                 :            : static void
     531                 :          1 : free_trids(void)
     532                 :            : {
     533                 :            :         struct nvme_fuzz_trid *trid, *tmp;
     534                 :            : 
     535         [ +  + ]:          2 :         TAILQ_FOREACH_SAFE(trid, &g_trid_list, tailq, tmp) {
     536         [ -  + ]:          1 :                 TAILQ_REMOVE(&g_trid_list, trid, tailq);
     537                 :          1 :                 free(trid);
     538                 :            :         }
     539                 :          1 : }
     540                 :            : 
     541                 :            : static void
     542                 :          1 : register_ns(struct spdk_nvme_ctrlr *ctrlr, struct spdk_nvme_ns *ns, uint32_t nsid)
     543                 :            : {
     544                 :            :         struct nvme_fuzz_ns *ns_entry;
     545                 :            : 
     546                 :          1 :         ns_entry = calloc(1, sizeof(struct nvme_fuzz_ns));
     547         [ -  + ]:          1 :         if (ns_entry == NULL) {
     548   [ #  #  #  # ]:          0 :                 fprintf(stderr, "Unable to allocate an entry for a namespace\n");
     549                 :          0 :                 return;
     550                 :            :         }
     551                 :            : 
     552                 :          1 :         ns_entry->ns = ns;
     553                 :          1 :         ns_entry->ctrlr = ctrlr;
     554                 :          1 :         ns_entry->nsid = nsid;
     555                 :            : 
     556                 :          1 :         TAILQ_INIT(&ns_entry->io_qp.free_ctx_objs);
     557                 :          1 :         TAILQ_INIT(&ns_entry->io_qp.outstanding_ctx_objs);
     558                 :          1 :         TAILQ_INIT(&ns_entry->a_qp.free_ctx_objs);
     559                 :          1 :         TAILQ_INIT(&ns_entry->a_qp.outstanding_ctx_objs);
     560                 :          1 :         TAILQ_INSERT_TAIL(&g_ns_list, ns_entry, tailq);
     561                 :            : }
     562                 :            : 
     563                 :            : static void
     564                 :          1 : register_ctrlr(struct spdk_nvme_ctrlr *ctrlr)
     565                 :            : {
     566                 :            :         struct nvme_fuzz_ctrlr *ctrlr_entry;
     567                 :            :         uint32_t nsid;
     568                 :            :         struct spdk_nvme_ns *ns;
     569                 :            : 
     570                 :          1 :         ctrlr_entry = calloc(1, sizeof(struct nvme_fuzz_ctrlr));
     571         [ -  + ]:          1 :         if (ctrlr_entry == NULL) {
     572   [ #  #  #  # ]:          0 :                 fprintf(stderr, "Unable to allocate an entry for a controller\n");
     573                 :          0 :                 return;
     574                 :            :         }
     575                 :            : 
     576                 :          1 :         ctrlr_entry->ctrlr = ctrlr;
     577                 :          1 :         TAILQ_INSERT_TAIL(&g_ctrlr_list, ctrlr_entry, tailq);
     578                 :            : 
     579         [ +  + ]:          2 :         for (nsid = spdk_nvme_ctrlr_get_first_active_ns(ctrlr); nsid != 0;
     580                 :          1 :              nsid = spdk_nvme_ctrlr_get_next_active_ns(ctrlr, nsid)) {
     581                 :          1 :                 ns = spdk_nvme_ctrlr_get_ns(ctrlr, nsid);
     582         [ -  + ]:          1 :                 if (ns == NULL) {
     583                 :          0 :                         continue;
     584                 :            :                 }
     585                 :          1 :                 register_ns(ctrlr, ns, nsid);
     586                 :            :         }
     587                 :            : }
     588                 :            : 
     589                 :            : static int
     590                 :          2 : prep_qpair(struct nvme_fuzz_ns *ns, struct nvme_fuzz_qp *qp, uint32_t max_qdepth)
     591                 :            : {
     592                 :            :         uint32_t i;
     593                 :            : 
     594                 :            :         /* ensure that each qpair gets a unique random seed for maximum command dispersion. */
     595                 :            : 
     596         [ +  - ]:          2 :         if (g_seed_value != 0) {
     597                 :          2 :                 qp->random_seed = g_seed_value;
     598                 :            :         } else {
     599                 :            :                 /* Take the low 32 bits of spdk_get_ticks. This should be more granular than time(). */
     600                 :          0 :                 qp->random_seed = spdk_get_ticks();
     601                 :            :         }
     602                 :            : 
     603                 :          2 :         qp->timeout_tsc = fuzz_refresh_timeout();
     604                 :            : 
     605                 :          2 :         qp->req_ctx = calloc(max_qdepth, sizeof(struct nvme_fuzz_request));
     606         [ -  + ]:          2 :         if (qp->req_ctx == NULL) {
     607   [ #  #  #  # ]:          0 :                 fprintf(stderr, "Unable to allocate I/O contexts for I/O qpair.\n");
     608                 :          0 :                 return -1;
     609                 :            :         }
     610                 :            : 
     611         [ +  + ]:        146 :         for (i = 0; i < max_qdepth; i++) {
     612                 :        144 :                 qp->req_ctx[i].qp = qp;
     613         [ +  + ]:        144 :                 TAILQ_INSERT_HEAD(&qp->free_ctx_objs, &qp->req_ctx[i], link);
     614                 :            :         }
     615                 :            : 
     616                 :          2 :         return 0;
     617                 :            : }
     618                 :            : 
     619                 :            : static int
     620                 :          1 : prepare_qpairs(void)
     621                 :            : {
     622                 :          0 :         struct spdk_nvme_io_qpair_opts opts;
     623                 :            :         struct nvme_fuzz_ns *ns_entry;
     624                 :            : 
     625         [ +  + ]:          2 :         TAILQ_FOREACH(ns_entry, &g_ns_list, tailq) {
     626                 :          1 :                 spdk_nvme_ctrlr_get_default_io_qpair_opts(ns_entry->ctrlr, &opts, sizeof(opts));
     627                 :          1 :                 ns_entry->io_qp.qpair = spdk_nvme_ctrlr_alloc_io_qpair(ns_entry->ctrlr, &opts, sizeof(opts));
     628         [ -  + ]:          1 :                 if (ns_entry->io_qp.qpair == NULL) {
     629   [ #  #  #  # ]:          0 :                         fprintf(stderr, "Unable to create a qpair for a namespace\n");
     630                 :          0 :                         return -1;
     631                 :            :                 }
     632                 :            : 
     633                 :          1 :                 ns_entry->io_qp.is_admin = false;
     634         [ -  + ]:          1 :                 if (prep_qpair(ns_entry, &ns_entry->io_qp, g_io_depth) != 0) {
     635   [ #  #  #  # ]:          0 :                         fprintf(stderr, "Unable to allocate request contexts for I/O qpair.\n");
     636                 :          0 :                         return -1;
     637                 :            :                 }
     638                 :            : 
     639   [ -  +  +  - ]:          1 :                 if (g_run_admin_commands) {
     640                 :          1 :                         ns_entry->a_qp.is_admin = true;
     641         [ -  + ]:          1 :                         if (prep_qpair(ns_entry, &ns_entry->a_qp, g_admin_depth) != 0) {
     642   [ #  #  #  # ]:          0 :                                 fprintf(stderr, "Unable to allocate request contexts for admin qpair.\n");
     643                 :          0 :                                 return -1;
     644                 :            :                         }
     645                 :            :                 }
     646                 :            :         }
     647                 :          1 :         return 0;
     648                 :            : }
     649                 :            : 
     650                 :            : static void
     651                 :          1 : start_ns_poller(void *ctx)
     652                 :            : {
     653                 :          1 :         struct nvme_fuzz_ns *ns_entry = ctx;
     654                 :            : 
     655                 :          1 :         ns_entry->req_poller = SPDK_POLLER_REGISTER(poll_for_completions, ns_entry, 0);
     656                 :          1 :         submit_ns_cmds(ns_entry);
     657                 :          1 : }
     658                 :            : 
     659                 :            : static int
     660                 :         30 : check_app_completion(void *ctx)
     661                 :            : {
     662                 :            : 
     663         [ +  + ]:         30 :         if (g_num_active_threads <= 0) {
     664                 :          1 :                 spdk_poller_unregister(&g_app_completion_poller);
     665         [ -  + ]:          1 :                 if (g_cmd_array) {
     666                 :          0 :                         free(g_cmd_array);
     667                 :            :                 }
     668         [ -  + ]:          1 :                 printf("Fuzzing completed. Shutting down the fuzz application\n\n");
     669         [ -  + ]:          1 :                 printf("Dumping successful admin opcodes:\n");
     670                 :          1 :                 report_successful_opcodes(g_successful_admin_opcodes, UNIQUE_OPCODES);
     671         [ -  + ]:          1 :                 printf("Dumping successful io opcodes:\n");
     672                 :          1 :                 report_successful_opcodes(g_successful_io_opcodes, UNIQUE_OPCODES);
     673                 :          1 :                 free_namespaces();
     674                 :          1 :                 free_controllers();
     675                 :          1 :                 free_trids();
     676                 :          1 :                 spdk_app_stop(0);
     677                 :            :         }
     678                 :         30 :         return 0;
     679                 :            : }
     680                 :            : 
     681                 :            : static void
     682                 :          1 : begin_fuzz(void *ctx)
     683                 :            : {
     684                 :            :         struct nvme_fuzz_ns *ns_entry;
     685                 :            :         struct nvme_fuzz_trid *trid;
     686                 :            :         struct spdk_nvme_ctrlr *ctrlr;
     687                 :            :         int rc;
     688                 :            : 
     689   [ -  +  +  -  :          1 :         if (g_check_iommu && !spdk_iommu_is_enabled()) {
                   -  + ]
     690                 :            :                 /* Don't set rc to an error code here. We don't want to fail an automated test based on this. */
     691   [ #  #  #  # ]:          0 :                 fprintf(stderr, "The IOMMU must be enabled to run this program to avoid unsafe memory accesses.\n");
     692                 :          0 :                 rc = 0;
     693                 :          0 :                 goto out;
     694                 :            :         }
     695                 :            : 
     696         [ +  + ]:          2 :         TAILQ_FOREACH(trid, &g_trid_list, tailq) {
     697                 :          1 :                 ctrlr = spdk_nvme_connect(&trid->trid, NULL, 0);
     698         [ -  + ]:          1 :                 if (ctrlr == NULL) {
     699         [ #  # ]:          0 :                         fprintf(stderr, "spdk_nvme_connect() failed for transport address '%s'\n",
     700         [ #  # ]:          0 :                                 trid->trid.traddr);
     701                 :          0 :                         rc = -1;
     702                 :          0 :                         goto out;
     703                 :            :                 }
     704                 :          1 :                 register_ctrlr(ctrlr);
     705                 :            :         }
     706                 :            : 
     707         [ -  + ]:          1 :         if (TAILQ_EMPTY(&g_ns_list)) {
     708   [ #  #  #  # ]:          0 :                 fprintf(stderr, "No valid NVMe Namespaces to fuzz\n");
     709                 :          0 :                 rc = -EINVAL;
     710                 :          0 :                 goto out;
     711                 :            :         }
     712                 :            : 
     713                 :          1 :         rc = prepare_qpairs();
     714                 :            : 
     715         [ -  + ]:          1 :         if (rc < 0) {
     716   [ #  #  #  # ]:          0 :                 fprintf(stderr, "Unable to prepare the qpairs\n");
     717                 :          0 :                 goto out;
     718                 :            :         }
     719                 :            : 
     720                 :          1 :         g_runtime_ticks = spdk_get_ticks() + g_runtime * spdk_get_ticks_hz();
     721                 :            : 
     722                 :            :         /* Assigning all of the threads and then starting them makes cleanup easier. */
     723         [ +  + ]:          2 :         TAILQ_FOREACH(ns_entry, &g_ns_list, tailq) {
     724                 :          1 :                 ns_entry->thread = spdk_thread_create(NULL, NULL);
     725         [ -  + ]:          1 :                 if (ns_entry->thread == NULL) {
     726   [ #  #  #  # ]:          0 :                         fprintf(stderr, "Failed to allocate thread for namespace.\n");
     727                 :          0 :                         goto out;
     728                 :            :                 }
     729                 :            :         }
     730                 :            : 
     731         [ +  + ]:          2 :         TAILQ_FOREACH(ns_entry, &g_ns_list, tailq) {
     732                 :          1 :                 spdk_thread_send_msg(ns_entry->thread, start_ns_poller, ns_entry);
     733                 :          1 :                 __sync_add_and_fetch(&g_num_active_threads, 1);
     734                 :            :         }
     735                 :            : 
     736                 :          1 :         g_app_completion_poller = SPDK_POLLER_REGISTER(check_app_completion, NULL, 1000000);
     737                 :          1 :         return;
     738                 :          0 : out:
     739         [ #  # ]:          0 :         printf("Shutting down the fuzz application\n");
     740                 :          0 :         free_namespaces();
     741                 :          0 :         free_controllers();
     742                 :          0 :         free_trids();
     743                 :          0 :         spdk_app_stop(rc);
     744                 :            : }
     745                 :            : 
     746                 :            : static void
     747                 :          0 : nvme_fuzz_usage(void)
     748                 :            : {
     749   [ #  #  #  # ]:          0 :         fprintf(stderr, " -a                        Perform admin commands. if -j is specified, \
     750                 :            : only admin commands will run. Otherwise they will be run in tandem with I/O commands.\n");
     751   [ #  #  #  # ]:          0 :         fprintf(stderr, " -F                        Transport ID for subsystem that should be fuzzed.\n");
     752   [ #  #  #  # ]:          0 :         fprintf(stderr,
     753                 :            :                 " -j <path>                 Path to a json file containing named objects of type spdk_nvme_cmd. If this option is specified, -t will be ignored.\n");
     754   [ #  #  #  # ]:          0 :         fprintf(stderr, " -N                        Target only valid namespace with commands. \
     755                 :            : This helps dig deeper into other errors besides invalid namespace.\n");
     756   [ #  #  #  # ]:          0 :         fprintf(stderr, " -S <integer>              Seed value for test.\n");
     757   [ #  #  #  # ]:          0 :         fprintf(stderr,
     758                 :            :                 " -t <integer>              Time in seconds to run the fuzz test. Only valid if -j is not specified.\n");
     759   [ #  #  #  # ]:          0 :         fprintf(stderr, " -U                        Do not check if IOMMU is enabled.\n");
     760   [ #  #  #  # ]:          0 :         fprintf(stderr, " -V                        Enable logging of each submitted command.\n");
     761                 :          0 : }
     762                 :            : 
     763                 :            : static int
     764                 :          5 : nvme_fuzz_parse(int ch, char *arg)
     765                 :            : {
     766                 :            :         struct nvme_fuzz_trid *trid;
     767                 :            :         int64_t error_test;
     768                 :            :         int rc;
     769                 :            : 
     770   [ +  +  -  +  :          5 :         switch (ch) {
             +  +  -  -  
                      - ]
     771                 :          1 :         case 'a':
     772                 :          1 :                 g_run_admin_commands = true;
     773                 :          1 :                 break;
     774                 :          1 :         case 'F':
     775                 :          1 :                 trid = malloc(sizeof(*trid));
     776         [ -  + ]:          1 :                 if (!trid) {
     777   [ #  #  #  # ]:          0 :                         fprintf(stderr, "Unable to allocate memory for transport ID\n");
     778                 :          0 :                         return -1;
     779                 :            :                 }
     780                 :          1 :                 rc = spdk_nvme_transport_id_parse(&trid->trid, optarg);
     781         [ -  + ]:          1 :                 if (rc < 0) {
     782   [ #  #  #  # ]:          0 :                         fprintf(stderr, "failed to parse transport ID: %s\n", optarg);
     783                 :          0 :                         free(trid);
     784                 :          0 :                         return -1;
     785                 :            :                 }
     786                 :          1 :                 TAILQ_INSERT_TAIL(&g_trid_list, trid, tailq);
     787                 :          1 :                 break;
     788                 :          0 :         case 'j':
     789                 :          0 :                 g_json_file = optarg;
     790                 :          0 :                 break;
     791                 :          1 :         case 'N':
     792                 :          1 :                 g_valid_ns_only = true;
     793                 :          1 :                 break;
     794                 :          1 :         case 'S':
     795                 :          1 :                 error_test = spdk_strtol(arg, 10);
     796         [ -  + ]:          1 :                 if (error_test < 0) {
     797   [ #  #  #  # ]:          0 :                         fprintf(stderr, "Invalid value supplied for the random seed.\n");
     798                 :          0 :                         return -1;
     799                 :            :                 } else {
     800                 :          1 :                         g_seed_value = error_test;
     801                 :            :                 }
     802                 :          1 :                 break;
     803                 :          1 :         case 't':
     804                 :          1 :                 g_runtime = spdk_strtol(optarg, 10);
     805   [ +  -  -  + ]:          1 :                 if (g_runtime < 0 || g_runtime > MAX_RUNTIME_S) {
     806   [ #  #  #  # ]:          0 :                         fprintf(stderr, "You must supply a positive runtime value less than 86401.\n");
     807                 :          0 :                         return -1;
     808                 :            :                 }
     809                 :          1 :                 break;
     810                 :          0 :         case 'U':
     811                 :          0 :                 g_check_iommu = false;
     812                 :          0 :                 break;
     813                 :          0 :         case 'V':
     814                 :          0 :                 g_verbose_mode = true;
     815                 :          0 :                 break;
     816                 :          0 :         case '?':
     817                 :            :         default:
     818                 :          0 :                 return -EINVAL;
     819                 :            :         }
     820                 :          5 :         return 0;
     821                 :            : }
     822                 :            : 
     823                 :            : int
     824                 :          1 : main(int argc, char **argv)
     825                 :            : {
     826                 :          1 :         struct spdk_app_opts opts = {};
     827                 :            :         int rc;
     828                 :            : 
     829                 :          1 :         spdk_app_opts_init(&opts, sizeof(opts));
     830                 :          1 :         opts.name = "nvme_fuzz";
     831                 :          1 :         opts.rpc_addr = NULL;
     832                 :            : 
     833                 :          1 :         g_runtime = DEFAULT_RUNTIME;
     834                 :          1 :         g_run = true;
     835                 :            : 
     836                 :          1 :         if ((rc = spdk_app_parse_args(argc, argv, &opts, "aF:j:NS:t:UV", NULL, nvme_fuzz_parse,
     837         [ -  + ]:          1 :                                       nvme_fuzz_usage) != SPDK_APP_PARSE_ARGS_SUCCESS)) {
     838                 :          0 :                 return rc;
     839                 :            :         }
     840                 :            : 
     841         [ -  + ]:          1 :         if (g_json_file != NULL) {
     842                 :          0 :                 g_cmd_array_size = fuzz_parse_args_into_array(g_json_file, (void **)&g_cmd_array,
     843                 :            :                                    sizeof(struct spdk_nvme_cmd), g_nvme_cmd_json_name, parse_nvme_cmd_obj);
     844         [ #  # ]:          0 :                 if (g_cmd_array_size == 0) {
     845   [ #  #  #  # ]:          0 :                         fprintf(stderr, "The provided json file did not contain any valid commands. Exiting.");
     846                 :          0 :                         return -EINVAL;
     847                 :            :                 }
     848                 :            :         }
     849                 :            : 
     850                 :          1 :         rc = spdk_app_start(&opts, begin_fuzz, NULL);
     851                 :            : 
     852                 :          1 :         spdk_app_fini();
     853                 :          1 :         return rc;
     854                 :            : }

Generated by: LCOV version 1.14