LCOV - code coverage report
Current view: top level - module/accel/error - accel_error.c (source / functions) Hit Total Coverage
Test: ut_cov_unit.info Lines: 0 171 0.0 %
Date: 2024-12-09 13:57:54 Functions: 0 21 0.0 %

          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           0 : accel_error_get_task_ctx(struct spdk_accel_task *task)
      46             : {
      47           0 :         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           0 : accel_error_corrupt_task(struct spdk_accel_task *task)
      58             : {
      59           0 :         switch (task->op_code) {
      60             :         case SPDK_ACCEL_OPC_CRC32C:
      61           0 :                 *task->crc_dst += 1;
      62           0 :                 break;
      63             :         default:
      64           0 :                 break;
      65             :         }
      66           0 : }
      67             : 
      68             : static void
      69           0 : accel_error_corrupt_cb(void *arg, int status)
      70             : {
      71           0 :         struct spdk_accel_task *task = arg;
      72           0 :         struct accel_error_task *errtask = accel_error_get_task_ctx(task);
      73           0 :         spdk_accel_completion_cb cb_fn = errtask->cb_fn.cpl;
      74           0 :         void *cb_arg = errtask->cb_arg;
      75             : 
      76           0 :         accel_error_corrupt_task(task);
      77           0 :         cb_fn(cb_arg, status);
      78           0 : }
      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           0 : accel_error_should_inject(struct spdk_io_channel *ch, struct spdk_accel_task *task)
      95             : {
      96           0 :         struct accel_error_channel *errch = spdk_io_channel_get_ctx(ch);
      97           0 :         struct accel_error_inject_info *info = &errch->injects[task->op_code];
      98             : 
      99           0 :         if (info->opts.type == ACCEL_ERROR_INJECT_DISABLE) {
     100           0 :                 return false;
     101             :         }
     102             : 
     103           0 :         info->interval++;
     104           0 :         if (info->interval >= info->opts.interval) {
     105           0 :                 info->interval = 0;
     106           0 :                 info->count++;
     107             : 
     108           0 :                 if (info->count <= info->opts.count) {
     109           0 :                         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           0 :         return false;
     118           0 : }
     119             : 
     120             : static int
     121           0 : accel_error_submit_tasks(struct spdk_io_channel *ch, struct spdk_accel_task *task)
     122             : {
     123           0 :         struct accel_error_channel *errch = spdk_io_channel_get_ctx(ch);
     124           0 :         struct accel_error_task *errtask = accel_error_get_task_ctx(task);
     125           0 :         struct accel_error_inject_info *info = &errch->injects[task->op_code];
     126             : 
     127           0 :         if (!accel_error_should_inject(ch, task)) {
     128           0 :                 goto submit;
     129             :         }
     130             : 
     131           0 :         switch (info->opts.type) {
     132             :         case ACCEL_ERROR_INJECT_CORRUPT:
     133           0 :                 errtask->ch = errch;
     134           0 :                 errtask->cb_arg = task->cb_arg;
     135           0 :                 task->cb_arg = task;
     136           0 :                 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           0 :                         errtask->cb_fn.cpl = task->cb_fn;
     141           0 :                         task->cb_fn = accel_error_corrupt_cb;
     142             :                 }
     143           0 :                 break;
     144             :         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             :         default:
     149           0 :                 break;
     150           0 :         }
     151             : submit:
     152           0 :         return g_sw_module->submit_tasks(errch->swch, task);
     153           0 : }
     154             : 
     155             : static int
     156           0 : accel_error_poller(void *arg)
     157             : {
     158           0 :         struct accel_error_channel *errch = arg;
     159             :         struct accel_error_task *errtask;
     160             :         STAILQ_HEAD(, accel_error_task) tasks;
     161             :         struct spdk_accel_task *task;
     162             : 
     163           0 :         if (STAILQ_EMPTY(&errch->tasks)) {
     164           0 :                 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           0 : accel_error_inject_channel(struct spdk_io_channel_iter *iter)
     183             : {
     184           0 :         struct spdk_io_channel *ch = spdk_io_channel_iter_get_channel(iter);
     185           0 :         struct accel_error_channel *errch = spdk_io_channel_get_ctx(ch);
     186           0 :         struct accel_error_inject_opts *opts = spdk_io_channel_iter_get_ctx(iter);
     187           0 :         struct accel_error_inject_info *info = &errch->injects[opts->opcode];
     188             : 
     189           0 :         info->count = 0;
     190           0 :         memcpy(&info->opts, opts, sizeof(info->opts));
     191             : 
     192           0 :         spdk_for_each_channel_continue(iter, 0);
     193           0 : }
     194             : 
     195             : static bool accel_error_supports_opcode(enum spdk_accel_opcode opcode);
     196             : 
     197             : int
     198           0 : accel_error_inject_error(struct accel_error_inject_opts *opts)
     199             : {
     200           0 :         struct accel_error_inject_opts *curr = &g_injects[opts->opcode];
     201             : 
     202           0 :         if (!accel_error_supports_opcode(opts->opcode)) {
     203           0 :                 return -EINVAL;
     204             :         }
     205             : 
     206           0 :         memcpy(curr, opts, sizeof(*opts));
     207           0 :         if (curr->type == ACCEL_ERROR_INJECT_DISABLE) {
     208           0 :                 curr->count = 0;
     209           0 :         }
     210           0 :         if (curr->count == 0) {
     211           0 :                 curr->type = ACCEL_ERROR_INJECT_DISABLE;
     212           0 :         }
     213             : 
     214           0 :         spdk_for_each_channel(&g_sw_module, accel_error_inject_channel, curr, NULL);
     215             : 
     216           0 :         return 0;
     217           0 : }
     218             : 
     219             : static int
     220           0 : accel_error_channel_create_cb(void *io_device, void *ctx)
     221             : {
     222           0 :         struct accel_error_channel *errch = ctx;
     223             :         size_t i;
     224             : 
     225           0 :         STAILQ_INIT(&errch->tasks);
     226           0 :         errch->poller = SPDK_POLLER_REGISTER(accel_error_poller, errch, 0);
     227           0 :         if (errch->poller == NULL) {
     228           0 :                 return -ENOMEM;
     229             :         }
     230             : 
     231           0 :         errch->swch = g_sw_module->get_io_channel();
     232           0 :         if (errch->swch == NULL) {
     233           0 :                 spdk_poller_unregister(&errch->poller);
     234           0 :                 return -ENOMEM;
     235             :         }
     236             : 
     237           0 :         for (i = 0; i < SPDK_COUNTOF(errch->injects); ++i) {
     238           0 :                 memcpy(&errch->injects[i].opts, &g_injects[i], sizeof(g_injects[i]));
     239           0 :                 errch->injects[i].count = 0;
     240           0 :         }
     241             : 
     242           0 :         return 0;
     243           0 : }
     244             : 
     245             : static void
     246           0 : accel_error_channel_destroy_cb(void *io_device, void *ctx)
     247             : {
     248           0 :         struct accel_error_channel *errch = ctx;
     249             : 
     250           0 :         assert(STAILQ_EMPTY(&errch->tasks));
     251           0 :         spdk_poller_unregister(&errch->poller);
     252           0 :         spdk_put_io_channel(errch->swch);
     253           0 : }
     254             : 
     255             : static int
     256           0 : accel_error_module_init(void)
     257             : {
     258           0 :         g_sw_module = spdk_accel_get_module("software");
     259           0 :         if (g_sw_module == NULL) {
     260             :                 /* Should never really happen */
     261           0 :                 return -ENOTSUP;
     262             :         }
     263             : 
     264           0 :         g_task_offset = g_sw_module->get_ctx_size();
     265             : 
     266           0 :         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           0 :         return 0;
     271           0 : }
     272             : 
     273             : static void
     274           0 : accel_error_unregister_cb(void *unused)
     275             : {
     276           0 :         spdk_accel_module_finish();
     277           0 : }
     278             : 
     279             : static void
     280           0 : accel_error_module_fini(void *unused)
     281             : {
     282           0 :         spdk_io_device_unregister(&g_sw_module, accel_error_unregister_cb);
     283           0 : }
     284             : 
     285             : static bool
     286           0 : accel_error_supports_opcode(enum spdk_accel_opcode opcode)
     287             : {
     288           0 :         switch (opcode) {
     289             :         case SPDK_ACCEL_OPC_CRC32C:
     290           0 :                 return true;
     291             :         default:
     292           0 :                 return false;
     293             :         }
     294           0 : }
     295             : 
     296             : static struct spdk_io_channel *
     297           0 : accel_error_get_io_channel(void)
     298             : {
     299           0 :         return spdk_get_io_channel(&g_sw_module);
     300             : }
     301             : 
     302             : static size_t
     303           0 : accel_error_get_ctx_size(void)
     304             : {
     305           0 :         return g_task_offset + sizeof(struct accel_error_task);
     306             : }
     307             : 
     308             : const char *
     309           0 : accel_error_get_type_name(enum accel_error_inject_type type)
     310             : {
     311           0 :         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           0 :         if ((int)type >= ACCEL_ERROR_INJECT_MAX) {
     319           0 :                 return NULL;
     320             :         }
     321             : 
     322           0 :         return typenames[type];
     323           0 : }
     324             : 
     325             : static void
     326           0 : accel_error_write_config_json(struct spdk_json_write_ctx *w)
     327             : {
     328             :         struct accel_error_inject_opts *opts;
     329             :         int opcode;
     330             : 
     331           0 :         for (opcode = 0; opcode < SPDK_ACCEL_OPC_LAST; ++opcode) {
     332           0 :                 opts = &g_injects[opcode];
     333           0 :                 if (opts->type == ACCEL_ERROR_INJECT_DISABLE) {
     334           0 :                         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           0 : }
     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           0 : SPDK_ACCEL_MODULE_REGISTER(error, &g_accel_error_module)

Generated by: LCOV version 1.15