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