LCOV - code coverage report
Current view: top level - spdk/module/accel/error - accel_error.c (source / functions) Hit Total Coverage
Test: Combined Lines: 120 180 66.7 %
Date: 2024-12-08 06:56:26 Functions: 19 21 90.5 %
Legend: Lines: hit not hit | Branches: + taken - not taken # not executed Branches: 45 505 8.9 %

           Branch data     Line data    Source code
       1                 :            : /* SPDX-License-Identifier: BSD-3-Clause
       2                 :            :  * Copyright (C) 2023 Intel Corporation. All rights reserved.
       3                 :            :  */
       4                 :            : 
       5                 :            : #include "accel_error.h"
       6                 :            : #include "spdk/accel.h"
       7                 :            : #include "spdk/accel_module.h"
       8                 :            : #include "spdk/json.h"
       9                 :            : #include "spdk/thread.h"
      10                 :            : 
      11                 :            : struct accel_error_inject_info {
      12                 :            :         /* Error injection options */
      13                 :            :         struct accel_error_inject_opts  opts;
      14                 :            :         /* Number of errors already injected on this channel */
      15                 :            :         uint64_t                        count;
      16                 :            :         /* Number of operations executed since last error injection */
      17                 :            :         uint64_t                        interval;
      18                 :            : };
      19                 :            : 
      20                 :            : struct accel_error_task;
      21                 :            : 
      22                 :            : struct accel_error_channel {
      23                 :            :         struct spdk_io_channel          *swch;
      24                 :            :         struct spdk_poller              *poller;
      25                 :            :         struct accel_error_inject_info  injects[SPDK_ACCEL_OPC_LAST];
      26                 :            :         STAILQ_HEAD(, accel_error_task) tasks;
      27                 :            : };
      28                 :            : 
      29                 :            : struct accel_error_task {
      30                 :            :         struct accel_error_channel              *ch;
      31                 :            :         union {
      32                 :            :                 spdk_accel_completion_cb        cpl;
      33                 :            :                 spdk_accel_step_cb              step;
      34                 :            :         } cb_fn;
      35                 :            :         void                                    *cb_arg;
      36                 :            :         int                                     status;
      37                 :            :         STAILQ_ENTRY(accel_error_task)          link;
      38                 :            : };
      39                 :            : 
      40                 :            : static struct spdk_accel_module_if *g_sw_module;
      41                 :            : static struct accel_error_inject_opts g_injects[SPDK_ACCEL_OPC_LAST];
      42                 :            : static size_t g_task_offset;
      43                 :            : 
      44                 :            : static struct accel_error_task *
      45                 :     317831 : accel_error_get_task_ctx(struct spdk_accel_task *task)
      46                 :            : {
      47         [ #  # ]:     317831 :         return (void *)((uint8_t *)task + g_task_offset);
      48                 :            : }
      49                 :            : 
      50                 :            : static struct spdk_accel_task *
      51                 :          0 : accel_error_get_task_from_ctx(struct accel_error_task *errtask)
      52                 :            : {
      53         [ #  # ]:          0 :         return (void *)((uint8_t *)errtask - g_task_offset);
      54                 :            : }
      55                 :            : 
      56                 :            : static void
      57                 :       3642 : accel_error_corrupt_task(struct spdk_accel_task *task)
      58                 :            : {
      59   [ +  -  #  #  :       3642 :         switch (task->op_code) {
                   #  # ]
      60                 :       3642 :         case SPDK_ACCEL_OPC_CRC32C:
      61   [ #  #  #  #  :       3642 :                 *task->crc_dst += 1;
             #  #  #  # ]
      62                 :       3642 :                 break;
      63                 :          0 :         default:
      64                 :          0 :                 break;
      65                 :            :         }
      66                 :       3642 : }
      67                 :            : 
      68                 :            : static void
      69                 :       3642 : accel_error_corrupt_cb(void *arg, int status)
      70                 :            : {
      71                 :       3642 :         struct spdk_accel_task *task = arg;
      72                 :       3642 :         struct accel_error_task *errtask = accel_error_get_task_ctx(task);
      73   [ #  #  #  #  :       3642 :         spdk_accel_completion_cb cb_fn = errtask->cb_fn.cpl;
                   #  # ]
      74   [ #  #  #  # ]:       3642 :         void *cb_arg = errtask->cb_arg;
      75                 :            : 
      76                 :       3642 :         accel_error_corrupt_task(task);
      77   [ #  #  #  # ]:       3642 :         cb_fn(cb_arg, status);
      78                 :       3642 : }
      79                 :            : 
      80                 :            : static void
      81                 :          0 : accel_error_corrupt_step_cb(void *arg)
      82                 :            : {
      83                 :          0 :         struct spdk_accel_task *task = arg;
      84                 :          0 :         struct accel_error_task *errtask = accel_error_get_task_ctx(task);
      85   [ #  #  #  #  :          0 :         spdk_accel_step_cb cb_fn = errtask->cb_fn.step;
                   #  # ]
      86   [ #  #  #  # ]:          0 :         void *cb_arg = errtask->cb_arg;
      87                 :            : 
      88                 :          0 :         accel_error_corrupt_task(task);
      89                 :            : 
      90   [ #  #  #  # ]:          0 :         cb_fn(cb_arg);
      91                 :          0 : }
      92                 :            : 
      93                 :            : static bool
      94                 :     314189 : accel_error_should_inject(struct spdk_io_channel *ch, struct spdk_accel_task *task)
      95                 :            : {
      96                 :     314189 :         struct accel_error_channel *errch = spdk_io_channel_get_ctx(ch);
      97   [ #  #  #  #  :     314189 :         struct accel_error_inject_info *info = &errch->injects[task->op_code];
          #  #  #  #  #  
                      # ]
      98                 :            : 
      99   [ +  +  #  #  :     314189 :         if (info->opts.type == ACCEL_ERROR_INJECT_DISABLE) {
             #  #  #  # ]
     100                 :         84 :                 return false;
     101                 :            :         }
     102                 :            : 
     103         [ #  # ]:     314105 :         info->interval++;
     104   [ +  +  #  #  :     314105 :         if (info->interval >= info->opts.interval) {
          #  #  #  #  #  
                #  #  # ]
     105   [ #  #  #  # ]:       3642 :                 info->interval = 0;
     106         [ #  # ]:       3642 :                 info->count++;
     107                 :            : 
     108   [ +  -  #  #  :       3642 :                 if (info->count <= info->opts.count) {
          #  #  #  #  #  
                #  #  # ]
     109                 :       3642 :                         return true;
     110                 :            :                 } else {
     111   [ #  #  #  #  :          0 :                         info->opts.type = ACCEL_ERROR_INJECT_DISABLE;
                   #  # ]
     112   [ #  #  #  # ]:          0 :                         info->interval = 0;
     113   [ #  #  #  # ]:          0 :                         info->count = 0;
     114                 :            :                 }
     115                 :          0 :         }
     116                 :            : 
     117                 :     310463 :         return false;
     118                 :          0 : }
     119                 :            : 
     120                 :            : static int
     121                 :     314189 : accel_error_submit_tasks(struct spdk_io_channel *ch, struct spdk_accel_task *task)
     122                 :            : {
     123                 :     314189 :         struct accel_error_channel *errch = spdk_io_channel_get_ctx(ch);
     124                 :     314189 :         struct accel_error_task *errtask = accel_error_get_task_ctx(task);
     125   [ #  #  #  #  :     314189 :         struct accel_error_inject_info *info = &errch->injects[task->op_code];
          #  #  #  #  #  
                      # ]
     126                 :            : 
     127         [ +  + ]:     314189 :         if (!accel_error_should_inject(ch, task)) {
     128                 :     310547 :                 goto submit;
     129                 :            :         }
     130                 :            : 
     131   [ +  -  -  #  :       3642 :         switch (info->opts.type) {
             #  #  #  #  
                      # ]
     132                 :       3642 :         case ACCEL_ERROR_INJECT_CORRUPT:
     133   [ #  #  #  # ]:       3642 :                 errtask->ch = errch;
     134   [ #  #  #  #  :       3642 :                 errtask->cb_arg = task->cb_arg;
             #  #  #  # ]
     135   [ #  #  #  # ]:       3642 :                 task->cb_arg = task;
     136   [ -  +  #  #  :       3642 :                 if (task->seq != NULL) {
                   #  # ]
     137   [ #  #  #  #  :          0 :                         errtask->cb_fn.step = task->step_cb_fn;
          #  #  #  #  #  
                #  #  # ]
     138   [ #  #  #  #  :          0 :                         task->step_cb_fn = accel_error_corrupt_step_cb;
                   #  # ]
     139                 :          0 :                 } else {
     140   [ #  #  #  #  :       3642 :                         errtask->cb_fn.cpl = task->cb_fn;
          #  #  #  #  #  
                #  #  # ]
     141   [ #  #  #  #  :       3642 :                         task->cb_fn = accel_error_corrupt_cb;
                   #  # ]
     142                 :            :                 }
     143                 :       3642 :                 break;
     144                 :          0 :         case ACCEL_ERROR_INJECT_FAILURE:
     145   [ #  #  #  #  :          0 :                 errtask->status = info->opts.errcode;
          #  #  #  #  #  
                      # ]
     146   [ #  #  #  #  :          0 :                 STAILQ_INSERT_TAIL(&errch->tasks, errtask, link);
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
             #  #  #  #  
                      # ]
     147                 :          0 :                 return 0;
     148                 :          0 :         default:
     149                 :          0 :                 break;
     150                 :          0 :         }
     151                 :     314189 : submit:
     152   [ #  #  #  #  :     314189 :         return g_sw_module->submit_tasks(errch->swch, task);
          #  #  #  #  #  
                #  #  # ]
     153                 :          0 : }
     154                 :            : 
     155                 :            : static int
     156                 :    8258072 : accel_error_poller(void *arg)
     157                 :            : {
     158                 :    8258072 :         struct accel_error_channel *errch = arg;
     159                 :            :         struct accel_error_task *errtask;
     160                 :          0 :         STAILQ_HEAD(, accel_error_task) tasks;
     161                 :            :         struct spdk_accel_task *task;
     162                 :            : 
     163   [ +  -  #  #  :    8258072 :         if (STAILQ_EMPTY(&errch->tasks)) {
             #  #  #  # ]
     164                 :    8258072 :                 return SPDK_POLLER_IDLE;
     165                 :            :         }
     166                 :            : 
     167         [ #  # ]:          0 :         STAILQ_INIT(&tasks);
     168   [ #  #  #  #  :          0 :         STAILQ_SWAP(&tasks, &errch->tasks, accel_error_task);
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
                      # ]
     169                 :            : 
     170         [ #  # ]:          0 :         while (!STAILQ_EMPTY(&tasks)) {
     171                 :          0 :                 errtask = STAILQ_FIRST(&tasks);
     172   [ #  #  #  #  :          0 :                 STAILQ_REMOVE_HEAD(&tasks, link);
          #  #  #  #  #  
                      # ]
     173                 :            : 
     174                 :          0 :                 task = accel_error_get_task_from_ctx(errtask);
     175   [ #  #  #  # ]:          0 :                 spdk_accel_task_complete(task, errtask->status);
     176                 :            :         }
     177                 :            : 
     178                 :          0 :         return SPDK_POLLER_BUSY;
     179                 :          0 : }
     180                 :            : 
     181                 :            : static void
     182                 :         24 : accel_error_inject_channel(struct spdk_io_channel_iter *iter)
     183                 :            : {
     184                 :         24 :         struct spdk_io_channel *ch = spdk_io_channel_iter_get_channel(iter);
     185                 :         24 :         struct accel_error_channel *errch = spdk_io_channel_get_ctx(ch);
     186                 :         24 :         struct accel_error_inject_opts *opts = spdk_io_channel_iter_get_ctx(iter);
     187   [ #  #  #  #  :         24 :         struct accel_error_inject_info *info = &errch->injects[opts->opcode];
          #  #  #  #  #  
                      # ]
     188                 :            : 
     189   [ #  #  #  # ]:         24 :         info->count = 0;
     190   [ -  +  -  +  :         24 :         memcpy(&info->opts, opts, sizeof(info->opts));
                   #  # ]
     191                 :            : 
     192                 :         24 :         spdk_for_each_channel_continue(iter, 0);
     193                 :         24 : }
     194                 :            : 
     195                 :            : static bool accel_error_supports_opcode(enum spdk_accel_opcode opcode);
     196                 :            : 
     197                 :            : int
     198                 :         24 : accel_error_inject_error(struct accel_error_inject_opts *opts)
     199                 :            : {
     200   [ #  #  #  #  :         24 :         struct accel_error_inject_opts *curr = &g_injects[opts->opcode];
             #  #  #  # ]
     201                 :            : 
     202   [ -  +  #  #  :         24 :         if (!accel_error_supports_opcode(opts->opcode)) {
                   #  # ]
     203                 :          0 :                 return -EINVAL;
     204                 :            :         }
     205                 :            : 
     206   [ -  +  -  + ]:         24 :         memcpy(curr, opts, sizeof(*opts));
     207   [ +  +  #  #  :         24 :         if (curr->type == ACCEL_ERROR_INJECT_DISABLE) {
                   #  # ]
     208   [ #  #  #  # ]:         12 :                 curr->count = 0;
     209                 :          0 :         }
     210   [ +  +  #  #  :         24 :         if (curr->count == 0) {
                   #  # ]
     211   [ #  #  #  # ]:         12 :                 curr->type = ACCEL_ERROR_INJECT_DISABLE;
     212                 :          0 :         }
     213                 :            : 
     214                 :         24 :         spdk_for_each_channel(&g_sw_module, accel_error_inject_channel, curr, NULL);
     215                 :            : 
     216                 :         24 :         return 0;
     217                 :          0 : }
     218                 :            : 
     219                 :            : static int
     220                 :          6 : accel_error_channel_create_cb(void *io_device, void *ctx)
     221                 :            : {
     222                 :          6 :         struct accel_error_channel *errch = ctx;
     223                 :            :         size_t i;
     224                 :            : 
     225   [ #  #  #  #  :          6 :         STAILQ_INIT(&errch->tasks);
          #  #  #  #  #  
          #  #  #  #  #  
                   #  # ]
     226   [ #  #  #  # ]:          6 :         errch->poller = SPDK_POLLER_REGISTER(accel_error_poller, errch, 0);
     227   [ -  +  #  #  :          6 :         if (errch->poller == NULL) {
                   #  # ]
     228                 :          0 :                 return -ENOMEM;
     229                 :            :         }
     230                 :            : 
     231   [ #  #  #  #  :          6 :         errch->swch = g_sw_module->get_io_channel();
          #  #  #  #  #  
                #  #  # ]
     232   [ -  +  #  #  :          6 :         if (errch->swch == NULL) {
                   #  # ]
     233         [ #  # ]:          0 :                 spdk_poller_unregister(&errch->poller);
     234                 :          0 :                 return -ENOMEM;
     235                 :            :         }
     236                 :            : 
     237         [ +  + ]:        108 :         for (i = 0; i < SPDK_COUNTOF(errch->injects); ++i) {
     238   [ -  +  -  +  :        102 :                 memcpy(&errch->injects[i].opts, &g_injects[i], sizeof(g_injects[i]));
          #  #  #  #  #  
          #  #  #  #  #  
                   #  # ]
     239   [ #  #  #  #  :        102 :                 errch->injects[i].count = 0;
          #  #  #  #  #  
                      # ]
     240                 :          0 :         }
     241                 :            : 
     242                 :          6 :         return 0;
     243                 :          0 : }
     244                 :            : 
     245                 :            : static void
     246                 :          6 : accel_error_channel_destroy_cb(void *io_device, void *ctx)
     247                 :            : {
     248                 :          6 :         struct accel_error_channel *errch = ctx;
     249                 :            : 
     250   [ -  +  #  #  :          6 :         assert(STAILQ_EMPTY(&errch->tasks));
          #  #  #  #  #  
                      # ]
     251         [ #  # ]:          6 :         spdk_poller_unregister(&errch->poller);
     252   [ #  #  #  # ]:          6 :         spdk_put_io_channel(errch->swch);
     253                 :          6 : }
     254                 :            : 
     255                 :            : static int
     256                 :       2040 : accel_error_module_init(void)
     257                 :            : {
     258                 :       2040 :         g_sw_module = spdk_accel_get_module("software");
     259         [ +  + ]:       2040 :         if (g_sw_module == NULL) {
     260                 :            :                 /* Should never really happen */
     261                 :          0 :                 return -ENOTSUP;
     262                 :            :         }
     263                 :            : 
     264   [ +  -  +  -  :       2040 :         g_task_offset = g_sw_module->get_ctx_size();
             -  +  +  - ]
     265                 :            : 
     266                 :       2040 :         spdk_io_device_register(&g_sw_module, accel_error_channel_create_cb,
     267                 :            :                                 accel_error_channel_destroy_cb,
     268                 :            :                                 sizeof(struct accel_error_channel), "accel_error");
     269                 :            : 
     270                 :       2040 :         return 0;
     271                 :         92 : }
     272                 :            : 
     273                 :            : static void
     274                 :       2040 : accel_error_unregister_cb(void *unused)
     275                 :            : {
     276                 :       2040 :         spdk_accel_module_finish();
     277                 :       2040 : }
     278                 :            : 
     279                 :            : static void
     280                 :       2040 : accel_error_module_fini(void *unused)
     281                 :            : {
     282                 :       2040 :         spdk_io_device_unregister(&g_sw_module, accel_error_unregister_cb);
     283                 :       2040 : }
     284                 :            : 
     285                 :            : static bool
     286                 :      34707 : accel_error_supports_opcode(enum spdk_accel_opcode opcode)
     287                 :            : {
     288         [ +  + ]:      34707 :         switch (opcode) {
     289                 :       1975 :         case SPDK_ACCEL_OPC_CRC32C:
     290                 :       2067 :                 return true;
     291                 :      31168 :         default:
     292                 :      32640 :                 return false;
     293                 :            :         }
     294                 :       1564 : }
     295                 :            : 
     296                 :            : static struct spdk_io_channel *
     297                 :          6 : accel_error_get_io_channel(void)
     298                 :            : {
     299                 :          6 :         return spdk_get_io_channel(&g_sw_module);
     300                 :            : }
     301                 :            : 
     302                 :            : static size_t
     303                 :       4080 : accel_error_get_ctx_size(void)
     304                 :            : {
     305                 :       4080 :         return g_task_offset + sizeof(struct accel_error_task);
     306                 :            : }
     307                 :            : 
     308                 :            : const char *
     309                 :         36 : accel_error_get_type_name(enum accel_error_inject_type type)
     310                 :            : {
     311                 :         36 :         const char *typenames[] = {
     312                 :            :                 [ACCEL_ERROR_INJECT_DISABLE] = "disable",
     313                 :            :                 [ACCEL_ERROR_INJECT_CORRUPT] = "corrupt",
     314                 :            :                 [ACCEL_ERROR_INJECT_FAILURE] = "failure",
     315                 :            :                 [ACCEL_ERROR_INJECT_MAX] = NULL
     316                 :            :         };
     317                 :            : 
     318         [ -  + ]:         36 :         if ((int)type >= ACCEL_ERROR_INJECT_MAX) {
     319                 :          0 :                 return NULL;
     320                 :            :         }
     321                 :            : 
     322   [ #  #  #  #  :         36 :         return typenames[type];
                   #  # ]
     323                 :          0 : }
     324                 :            : 
     325                 :            : static void
     326                 :        152 : accel_error_write_config_json(struct spdk_json_write_ctx *w)
     327                 :            : {
     328                 :            :         struct accel_error_inject_opts *opts;
     329                 :            :         int opcode;
     330                 :            : 
     331   [ +  +  +  - ]:       2736 :         for (opcode = 0; opcode < SPDK_ACCEL_OPC_LAST; ++opcode) {
     332   [ +  -  +  - ]:       2584 :                 opts = &g_injects[opcode];
     333   [ +  +  +  -  :       2584 :                 if (opts->type == ACCEL_ERROR_INJECT_DISABLE) {
                   -  + ]
     334                 :       2584 :                         continue;
     335                 :            :                 }
     336                 :          0 :                 spdk_json_write_object_begin(w);
     337                 :          0 :                 spdk_json_write_named_string(w, "method", "accel_error_inject_error");
     338                 :          0 :                 spdk_json_write_named_object_begin(w, "params");
     339                 :          0 :                 spdk_json_write_named_string(w, "opcode", spdk_accel_get_opcode_name(opcode));
     340   [ #  #  #  # ]:          0 :                 spdk_json_write_named_string(w, "type", accel_error_get_type_name(opts->type));
     341   [ #  #  #  # ]:          0 :                 spdk_json_write_named_uint64(w, "count", opts->count);
     342   [ #  #  #  # ]:          0 :                 spdk_json_write_named_uint64(w, "interval", opts->interval);
     343                 :          0 :                 spdk_json_write_object_end(w);
     344                 :          0 :                 spdk_json_write_object_end(w);
     345                 :          0 :         }
     346                 :        152 : }
     347                 :            : 
     348                 :            : static struct spdk_accel_module_if g_accel_error_module = {
     349                 :            :         .name                   = "error",
     350                 :            :         .priority               = INT_MIN,
     351                 :            :         .module_init            = accel_error_module_init,
     352                 :            :         .module_fini            = accel_error_module_fini,
     353                 :            :         .supports_opcode        = accel_error_supports_opcode,
     354                 :            :         .get_ctx_size           = accel_error_get_ctx_size,
     355                 :            :         .get_io_channel         = accel_error_get_io_channel,
     356                 :            :         .submit_tasks           = accel_error_submit_tasks,
     357                 :            :         .write_config_json      = accel_error_write_config_json,
     358                 :            : };
     359                 :       2234 : SPDK_ACCEL_MODULE_REGISTER(error, &g_accel_error_module)

Generated by: LCOV version 1.15