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