LCOV - code coverage report
Current view: top level - lib/ftl/mngt - ftl_mngt.c (source / functions) Hit Total Coverage
Test: ut_cov_unit.info Lines: 228 264 86.4 %
Date: 2024-12-06 08:20:53 Functions: 31 32 96.9 %

          Line data    Source code
       1             : /*   SPDX-License-Identifier: BSD-3-Clause
       2             :  *   Copyright (C) 2022 Intel Corporation.
       3             :  *   All rights reserved.
       4             :  */
       5             : 
       6             : #include "spdk/queue.h"
       7             : #include "spdk/assert.h"
       8             : #include "spdk/env.h"
       9             : 
      10             : #include "ftl_mngt.h"
      11             : #include "ftl_core.h"
      12             : 
      13             : struct ftl_mngt_step_status {
      14             :         uint64_t start;
      15             :         uint64_t stop;
      16             :         int status;
      17             :         int silent;
      18             :         TAILQ_ENTRY(ftl_mngt_step) entry;
      19             : };
      20             : 
      21             : struct ftl_mngt_step {
      22             :         void *ctx;
      23             :         const struct ftl_mngt_step_desc *desc;
      24             :         struct ftl_mngt_step_status action;
      25             :         struct ftl_mngt_step_status rollback;
      26             : };
      27             : 
      28             : struct ftl_mngt_process {
      29             :         struct spdk_ftl_dev *dev;
      30             :         int status;
      31             :         bool silent;
      32             :         bool rollback;
      33             :         bool continuing;
      34             :         struct  {
      35             :                 ftl_mngt_completion cb;
      36             :                 void *cb_ctx;
      37             :                 struct spdk_thread *thread;
      38             :         } caller;
      39             :         void *ctx;
      40             :         uint64_t tsc_start;
      41             :         uint64_t tsc_stop;
      42             :         const struct ftl_mngt_process_desc *desc;
      43             :         TAILQ_HEAD(, ftl_mngt_step) action_queue_todo;
      44             :         TAILQ_HEAD(, ftl_mngt_step) action_queue_done;
      45             :         TAILQ_HEAD(, ftl_mngt_step) rollback_queue_todo;
      46             :         TAILQ_HEAD(, ftl_mngt_step) rollback_queue_done;
      47             :         struct {
      48             :                 struct ftl_mngt_step step;
      49             :                 struct ftl_mngt_step_desc desc;
      50             :         } cleanup;
      51             :         struct ftl_mng_tracer *tracer;
      52             : };
      53             : 
      54             : static void action_next(struct ftl_mngt_process *mngt);
      55             : static void action_msg(void *ctx);
      56             : static void action_execute(struct ftl_mngt_process *mngt);
      57             : static void action_done(struct ftl_mngt_process *mngt, int status);
      58             : static void rollback_next(struct ftl_mngt_process *mngt);
      59             : static void rollback_msg(void *ctx);
      60             : static void rollback_execute(struct ftl_mngt_process *mngt);
      61             : static void rollback_done(struct ftl_mngt_process *mngt, int status);
      62             : 
      63             : static inline struct ftl_mngt_step *
      64          22 : get_current_step(struct ftl_mngt_process *mngt)
      65             : {
      66          22 :         if (!mngt->rollback) {
      67          12 :                 return TAILQ_FIRST(&mngt->action_queue_todo);
      68             :         } else {
      69          10 :                 return TAILQ_FIRST(&mngt->rollback_queue_todo);
      70             :         }
      71             : }
      72             : 
      73             : static int
      74          41 : init_step(struct ftl_mngt_process *mngt,
      75             :           const struct ftl_mngt_step_desc *desc)
      76             : {
      77             :         struct ftl_mngt_step *step;
      78             : 
      79          41 :         step = calloc(1, sizeof(*step));
      80          41 :         if (!step) {
      81           0 :                 return -ENOMEM;
      82             :         }
      83             : 
      84             :         /* Initialize the step's argument */
      85          41 :         if (desc->ctx_size) {
      86           2 :                 step->ctx = calloc(1, desc->ctx_size);
      87           2 :                 if (!step->ctx) {
      88           0 :                         free(step);
      89           0 :                         return -ENOMEM;
      90             :                 }
      91             :         }
      92          41 :         step->desc = desc;
      93          41 :         TAILQ_INSERT_TAIL(&mngt->action_queue_todo, step, action.entry);
      94             : 
      95          41 :         return 0;
      96             : }
      97             : 
      98             : static void
      99          19 : free_mngt(struct ftl_mngt_process *mngt)
     100             : {
     101          19 :         TAILQ_HEAD(, ftl_mngt_step) steps;
     102             : 
     103          19 :         if (!mngt) {
     104           0 :                 return;
     105             :         }
     106             : 
     107          19 :         TAILQ_INIT(&steps);
     108          19 :         TAILQ_CONCAT(&steps, &mngt->action_queue_todo, action.entry);
     109          19 :         TAILQ_CONCAT(&steps, &mngt->action_queue_done, action.entry);
     110             : 
     111          60 :         while (!TAILQ_EMPTY(&steps)) {
     112          41 :                 struct ftl_mngt_step *step = TAILQ_FIRST(&steps);
     113          41 :                 TAILQ_REMOVE(&steps, step, action.entry);
     114             : 
     115          41 :                 free(step->ctx);
     116          41 :                 free(step);
     117             :         }
     118             : 
     119          19 :         free(mngt->ctx);
     120          19 :         free(mngt);
     121             : }
     122             : 
     123             : static struct ftl_mngt_process *
     124          19 : allocate_mngt(struct spdk_ftl_dev *dev, const struct ftl_mngt_process_desc *pdesc,
     125             :               ftl_mngt_completion cb, void *cb_ctx, bool silent)
     126             : {
     127             :         struct ftl_mngt_process *mngt;
     128             : 
     129             :         /* Initialize management process */
     130          19 :         mngt = calloc(1, sizeof(*mngt));
     131          19 :         if (!mngt) {
     132           0 :                 goto error;
     133             :         }
     134          19 :         mngt->dev = dev;
     135          19 :         mngt->silent = silent;
     136          19 :         mngt->caller.cb = cb;
     137          19 :         mngt->caller.cb_ctx = cb_ctx;
     138          19 :         mngt->caller.thread = spdk_get_thread();
     139             : 
     140             :         /* Initialize process context */
     141          19 :         if (pdesc->ctx_size) {
     142           2 :                 mngt->ctx = calloc(1, pdesc->ctx_size);
     143           2 :                 if (!mngt->ctx) {
     144           0 :                         goto error;
     145             :                 }
     146             :         }
     147          19 :         mngt->tsc_start = spdk_get_ticks();
     148          19 :         mngt->desc = pdesc;
     149          19 :         TAILQ_INIT(&mngt->action_queue_todo);
     150          19 :         TAILQ_INIT(&mngt->action_queue_done);
     151          19 :         TAILQ_INIT(&mngt->rollback_queue_todo);
     152          19 :         TAILQ_INIT(&mngt->rollback_queue_done);
     153             : 
     154          19 :         return mngt;
     155           0 : error:
     156           0 :         free_mngt(mngt);
     157           0 :         return NULL;
     158             : }
     159             : 
     160             : static int
     161          13 : invoke_init_handler(struct spdk_ftl_dev *dev, struct ftl_mngt_process *mngt,
     162             :                     const struct ftl_mngt_process_desc *pdesc, void *init_ctx)
     163             : {
     164          13 :         int rc = 0;
     165             : 
     166          13 :         if (init_ctx || pdesc->init_handler) {
     167           2 :                 ftl_bug(!init_ctx);
     168           2 :                 ftl_bug(!pdesc->init_handler);
     169           2 :                 rc = pdesc->init_handler(dev, mngt, init_ctx);
     170             :         }
     171             : 
     172          13 :         return rc;
     173             : }
     174             : 
     175             : static int
     176          13 : _ftl_mngt_process_execute(struct spdk_ftl_dev *dev, const struct ftl_mngt_process_desc *pdesc,
     177             :                           ftl_mngt_completion cb, void *cb_ctx, bool silent, void *init_ctx)
     178             : {
     179             :         const struct ftl_mngt_step_desc *sdesc;
     180             :         struct ftl_mngt_process *mngt;
     181          13 :         int rc = 0;
     182             : 
     183          13 :         mngt = allocate_mngt(dev, pdesc, cb, cb_ctx, silent);
     184          13 :         if (!mngt) {
     185           0 :                 rc = -ENOMEM;
     186           0 :                 goto error;
     187             :         }
     188             : 
     189          13 :         if (pdesc->error_handler) {
     190             :                 /* Initialize a step for error handler */
     191           0 :                 mngt->cleanup.step.desc = &mngt->cleanup.desc;
     192           0 :                 mngt->cleanup.desc.name = "Handle ERROR";
     193           0 :                 mngt->cleanup.desc.cleanup = pdesc->error_handler;
     194             : 
     195             :                 /* Queue error handler to the rollback queue, it will be executed at the end */
     196           0 :                 TAILQ_INSERT_HEAD(&mngt->rollback_queue_todo, &mngt->cleanup.step,
     197             :                                   rollback.entry);
     198             :         }
     199             : 
     200             :         /* Initialize steps */
     201          13 :         sdesc = mngt->desc->steps;
     202          41 :         while (sdesc->action) {
     203          28 :                 rc = init_step(mngt, sdesc);
     204          28 :                 if (rc) {
     205           0 :                         goto error;
     206             :                 }
     207          28 :                 sdesc++;
     208             :         }
     209             : 
     210          13 :         rc = invoke_init_handler(dev, mngt, pdesc, init_ctx);
     211          13 :         if (rc) {
     212           1 :                 goto error;
     213             :         }
     214             : 
     215          12 :         action_execute(mngt);
     216          12 :         return 0;
     217           1 : error:
     218           1 :         free_mngt(mngt);
     219           1 :         return rc;
     220             : }
     221             : 
     222             : int
     223           8 : ftl_mngt_process_execute(struct spdk_ftl_dev *dev, const struct ftl_mngt_process_desc *pdesc,
     224             :                          ftl_mngt_completion cb, void *cb_ctx)
     225             : {
     226           8 :         return _ftl_mngt_process_execute(dev, pdesc, cb, cb_ctx, false, NULL);
     227             : }
     228             : 
     229             : int
     230           6 : ftl_mngt_process_rollback(struct spdk_ftl_dev *dev, const struct ftl_mngt_process_desc *pdesc,
     231             :                           ftl_mngt_completion cb, void *cb_ctx)
     232             : {
     233             :         const struct ftl_mngt_step_desc *sdesc;
     234             :         struct ftl_mngt_process *mngt;
     235           6 :         int rc = 0;
     236             : 
     237           6 :         mngt = allocate_mngt(dev, pdesc, cb, cb_ctx, true);
     238           6 :         if (!mngt) {
     239           0 :                 rc = -ENOMEM;
     240           0 :                 goto error;
     241             :         }
     242             : 
     243             :         /* Initialize steps for rollback */
     244           6 :         sdesc = mngt->desc->steps;
     245          20 :         while (sdesc->action) {
     246          14 :                 if (!sdesc->cleanup) {
     247           1 :                         sdesc++;
     248           1 :                         continue;
     249             :                 }
     250          13 :                 rc = init_step(mngt, sdesc);
     251          13 :                 if (rc) {
     252           0 :                         goto error;
     253             :                 }
     254          13 :                 sdesc++;
     255             :         }
     256             : 
     257             :         /* Build rollback list */
     258             :         struct ftl_mngt_step *step;
     259          19 :         TAILQ_FOREACH(step, &mngt->action_queue_todo, action.entry) {
     260          13 :                 step->action.silent = true;
     261          13 :                 TAILQ_INSERT_HEAD(&mngt->rollback_queue_todo, step,
     262             :                                   rollback.entry);
     263             :         }
     264             : 
     265           6 :         mngt->rollback = true;
     266           6 :         rollback_execute(mngt);
     267           6 :         return 0;
     268           0 : error:
     269           0 :         free_mngt(mngt);
     270           0 :         return rc;
     271             : }
     272             : 
     273             : struct spdk_ftl_dev *
     274           8 : ftl_mngt_get_dev(struct ftl_mngt_process *mngt)
     275             : {
     276           8 :         return mngt->dev;
     277             : }
     278             : 
     279             : int
     280           4 : ftl_mngt_alloc_step_ctx(struct ftl_mngt_process *mngt, size_t size)
     281             : {
     282           4 :         struct ftl_mngt_step *step = get_current_step(mngt);
     283           4 :         void *arg = calloc(1, size);
     284             : 
     285           4 :         if (!arg) {
     286           0 :                 return -ENOMEM;
     287             :         }
     288             : 
     289           4 :         free(step->ctx);
     290           4 :         step->ctx = arg;
     291             : 
     292           4 :         return 0;
     293             : }
     294             : 
     295             : void *
     296          12 : ftl_mngt_get_step_ctx(struct ftl_mngt_process *mngt)
     297             : {
     298          12 :         return get_current_step(mngt)->ctx;
     299             : }
     300             : 
     301             : void *
     302           4 : ftl_mngt_get_process_ctx(struct ftl_mngt_process *mngt)
     303             : {
     304           4 :         return mngt->ctx;
     305             : }
     306             : 
     307             : void *
     308           6 : ftl_mngt_get_caller_ctx(struct ftl_mngt_process *mngt)
     309             : {
     310           6 :         return mngt->caller.cb_ctx;
     311             : }
     312             : 
     313             : void
     314          38 : ftl_mngt_next_step(struct ftl_mngt_process *mngt)
     315             : {
     316          38 :         if (false == mngt->rollback) {
     317          20 :                 action_next(mngt);
     318             :         } else {
     319          18 :                 rollback_next(mngt);
     320             :         }
     321          38 : }
     322             : 
     323             : void
     324           0 : ftl_mngt_skip_step(struct ftl_mngt_process *mngt)
     325             : {
     326           0 :         if (mngt->rollback) {
     327           0 :                 get_current_step(mngt)->rollback.silent = true;
     328             :         } else {
     329           0 :                 get_current_step(mngt)->action.silent = true;
     330             :         }
     331           0 :         ftl_mngt_next_step(mngt);
     332           0 : }
     333             : 
     334             : void
     335           8 : ftl_mngt_continue_step(struct ftl_mngt_process *mngt)
     336             : {
     337             : 
     338           8 :         if (!mngt->continuing) {
     339           8 :                 if (false == mngt->rollback) {
     340           4 :                         action_execute(mngt);
     341             :                 } else {
     342           4 :                         rollback_execute(mngt);
     343             :                 }
     344             :         }
     345             : 
     346           8 :         mngt->continuing = true;
     347           8 : }
     348             : 
     349             : static void
     350           6 : child_cb(struct spdk_ftl_dev *dev, void *ctx, int status)
     351             : {
     352           6 :         struct ftl_mngt_process *parent = ctx;
     353             : 
     354           6 :         if (status) {
     355           1 :                 ftl_mngt_fail_step(parent);
     356             :         } else {
     357           5 :                 ftl_mngt_next_step(parent);
     358             :         }
     359           6 : }
     360             : 
     361             : void
     362           5 : ftl_mngt_call_process(struct ftl_mngt_process *mngt,
     363             :                       const struct ftl_mngt_process_desc *pdesc,
     364             :                       void *init_ctx)
     365             : {
     366           5 :         if (_ftl_mngt_process_execute(mngt->dev, pdesc, child_cb, mngt, true, init_ctx)) {
     367           1 :                 ftl_mngt_fail_step(mngt);
     368             :         } else {
     369           4 :                 if (mngt->rollback) {
     370           1 :                         get_current_step(mngt)->rollback.silent = true;
     371             :                 } else {
     372           3 :                         get_current_step(mngt)->action.silent = true;
     373             :                 }
     374             :         }
     375           5 : }
     376             : 
     377             : void
     378           2 : ftl_mngt_call_process_rollback(struct ftl_mngt_process *mngt,
     379             :                                const struct ftl_mngt_process_desc *pdesc)
     380             : {
     381           2 :         if (ftl_mngt_process_rollback(mngt->dev, pdesc, child_cb, mngt)) {
     382           0 :                 ftl_mngt_fail_step(mngt);
     383             :         } else {
     384           2 :                 if (mngt->rollback) {
     385           1 :                         get_current_step(mngt)->rollback.silent = true;
     386             :                 } else {
     387           1 :                         get_current_step(mngt)->action.silent = true;
     388             :                 }
     389             :         }
     390           2 : }
     391             : 
     392             : void
     393           4 : ftl_mngt_fail_step(struct ftl_mngt_process *mngt)
     394             : {
     395           4 :         mngt->status = -1;
     396             : 
     397           4 :         if (false == mngt->rollback) {
     398           4 :                 action_done(mngt, -1);
     399             :         } else {
     400           0 :                 rollback_done(mngt, -1);
     401             :         }
     402             : 
     403           4 :         mngt->rollback = true;
     404           4 :         rollback_execute(mngt);
     405           4 : }
     406             : 
     407             : static inline float
     408          44 : tsc_to_ms(uint64_t tsc)
     409             : {
     410          44 :         float ms = tsc;
     411          44 :         ms /= (float)spdk_get_ticks_hz();
     412          44 :         ms *= 1000.0;
     413          44 :         return ms;
     414             : }
     415             : 
     416             : static void
     417          42 : trace_step(struct spdk_ftl_dev *dev, struct ftl_mngt_step *step, bool rollback)
     418             : {
     419             :         uint64_t duration;
     420          42 :         const char *what = rollback ? "Rollback" : "Action";
     421          42 :         int silent = rollback ? step->rollback.silent : step->action.silent;
     422             : 
     423          42 :         if (silent) {
     424           6 :                 return;
     425             :         }
     426             : 
     427          36 :         FTL_NOTICELOG(dev, "%s\n", what);
     428          36 :         FTL_NOTICELOG(dev, "\t name:     %s\n", step->desc->name);
     429          36 :         duration = step->action.stop - step->action.start;
     430          36 :         FTL_NOTICELOG(dev, "\t duration: %.3f ms\n", tsc_to_ms(duration));
     431          36 :         FTL_NOTICELOG(dev, "\t status:   %d\n", step->action.status);
     432             : }
     433             : 
     434             : static void
     435          18 : finish_msg(void *ctx)
     436             : {
     437          18 :         struct ftl_mngt_process *mngt = ctx;
     438          18 :         char *devname = NULL;
     439             : 
     440          18 :         if (!mngt->silent && mngt->dev->conf.name) {
     441             :                 /* the callback below can free the device so make a temp copy of the name */
     442           0 :                 devname = strdup(mngt->dev->conf.name);
     443             :         }
     444             : 
     445          18 :         mngt->caller.cb(mngt->dev, mngt->caller.cb_ctx, mngt->status);
     446             : 
     447          18 :         if (mngt->desc->deinit_handler) {
     448           1 :                 mngt->desc->deinit_handler(mngt->dev, mngt);
     449             :         }
     450             : 
     451          18 :         if (!mngt->silent) {
     452             :                 /* TODO: refactor the logging macros to pass just the name instead of device */
     453           8 :                 struct spdk_ftl_dev tmpdev = {
     454             :                         .conf = {
     455             :                                 .name = devname
     456             :                         }
     457             :                 };
     458             : 
     459           8 :                 FTL_NOTICELOG(&tmpdev, "Management process finished, name '%s', duration = %.3f ms, result %d\n",
     460             :                               mngt->desc->name,
     461             :                               tsc_to_ms(mngt->tsc_stop - mngt->tsc_start),
     462             :                               mngt->status);
     463             :         }
     464          18 :         free_mngt(mngt);
     465          18 :         free(devname);
     466          18 : }
     467             : 
     468             : void
     469          18 : ftl_mngt_finish(struct ftl_mngt_process *mngt)
     470             : {
     471          18 :         mngt->tsc_stop = spdk_get_ticks();
     472          18 :         spdk_thread_send_msg(mngt->caller.thread, finish_msg, mngt);
     473          18 : }
     474             : 
     475             : /*
     476             :  * Actions
     477             :  */
     478             : static void
     479          20 : action_next(struct ftl_mngt_process *mngt)
     480             : {
     481          20 :         if (TAILQ_EMPTY(&mngt->action_queue_todo)) {
     482             :                 /* Nothing to do, finish the management process */
     483           0 :                 ftl_mngt_finish(mngt);
     484           0 :                 return;
     485             :         } else {
     486          20 :                 action_done(mngt, 0);
     487          20 :                 action_execute(mngt);
     488             :         }
     489             : }
     490             : 
     491             : static void
     492          36 : action_msg(void *ctx)
     493             : {
     494          36 :         struct ftl_mngt_process *mngt = ctx;
     495             :         struct ftl_mngt_step *step;
     496             : 
     497          36 :         mngt->continuing = false;
     498             : 
     499          36 :         if (TAILQ_EMPTY(&mngt->action_queue_todo)) {
     500           8 :                 ftl_mngt_finish(mngt);
     501           8 :                 return;
     502             :         }
     503             : 
     504          28 :         step = TAILQ_FIRST(&mngt->action_queue_todo);
     505          28 :         if (!step->action.start) {
     506          28 :                 step->action.start = spdk_get_ticks();
     507             :         }
     508          28 :         step->desc->action(mngt->dev, mngt);
     509             : }
     510             : 
     511             : static void
     512          36 : action_execute(struct ftl_mngt_process *mngt)
     513             : {
     514          36 :         spdk_thread_send_msg(mngt->dev->core_thread, action_msg, mngt);
     515          36 : }
     516             : 
     517             : static void
     518          24 : action_done(struct ftl_mngt_process *mngt, int status)
     519             : {
     520             :         struct ftl_mngt_step *step;
     521             : 
     522          24 :         assert(!TAILQ_EMPTY(&mngt->action_queue_todo));
     523          24 :         step = TAILQ_FIRST(&mngt->action_queue_todo);
     524          24 :         TAILQ_REMOVE(&mngt->action_queue_todo, step, action.entry);
     525             : 
     526          24 :         TAILQ_INSERT_TAIL(&mngt->action_queue_done, step, action.entry);
     527          24 :         if (step->desc->cleanup) {
     528          18 :                 TAILQ_INSERT_HEAD(&mngt->rollback_queue_todo, step,
     529             :                                   rollback.entry);
     530             :         }
     531             : 
     532          24 :         step->action.stop = spdk_get_ticks();
     533          24 :         step->action.status = status;
     534             : 
     535          24 :         trace_step(mngt->dev, step, false);
     536          24 : }
     537             : 
     538             : /*
     539             :  * Rollback
     540             :  */
     541             : static void
     542          18 : rollback_next(struct ftl_mngt_process *mngt)
     543             : {
     544          18 :         if (TAILQ_EMPTY(&mngt->rollback_queue_todo)) {
     545             :                 /* Nothing to do, finish the management process */
     546           0 :                 ftl_mngt_finish(mngt);
     547           0 :                 return;
     548             :         } else {
     549          18 :                 rollback_done(mngt, 0);
     550          18 :                 rollback_execute(mngt);
     551             :         }
     552             : }
     553             : 
     554             : static void
     555          32 : rollback_msg(void *ctx)
     556             : {
     557          32 :         struct ftl_mngt_process *mngt = ctx;
     558             :         struct ftl_mngt_step *step;
     559             : 
     560          32 :         mngt->continuing = false;
     561             : 
     562          32 :         if (TAILQ_EMPTY(&mngt->rollback_queue_todo)) {
     563          10 :                 ftl_mngt_finish(mngt);
     564          10 :                 return;
     565             :         }
     566             : 
     567          22 :         step = TAILQ_FIRST(&mngt->rollback_queue_todo);
     568          22 :         if (!step->rollback.start) {
     569          22 :                 step->rollback.start = spdk_get_ticks();
     570             :         }
     571          22 :         step->desc->cleanup(mngt->dev, mngt);
     572             : }
     573             : 
     574             : static void
     575          32 : rollback_execute(struct ftl_mngt_process *mngt)
     576             : {
     577          32 :         spdk_thread_send_msg(mngt->dev->core_thread, rollback_msg, mngt);
     578          32 : }
     579             : 
     580             : void
     581          18 : rollback_done(struct ftl_mngt_process *mngt, int status)
     582             : {
     583             :         struct ftl_mngt_step *step;
     584             : 
     585          18 :         assert(!TAILQ_EMPTY(&mngt->rollback_queue_todo));
     586          18 :         step = TAILQ_FIRST(&mngt->rollback_queue_todo);
     587          18 :         TAILQ_REMOVE(&mngt->rollback_queue_todo, step, rollback.entry);
     588          18 :         TAILQ_INSERT_TAIL(&mngt->rollback_queue_done, step, rollback.entry);
     589             : 
     590          18 :         step->rollback.stop = spdk_get_ticks();
     591          18 :         step->rollback.status = status;
     592             : 
     593          18 :         trace_step(mngt->dev, step,  true);
     594          18 : }

Generated by: LCOV version 1.15