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: 212 252 84.1 %
Date: 2024-07-13 08:38:25 Functions: 30 31 96.8 %

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

Generated by: LCOV version 1.15