2022-06-22 10:11:47 +00:00
|
|
|
/* SPDX-License-Identifier: BSD-3-Clause
|
|
|
|
* Copyright (c) Intel Corporation.
|
|
|
|
* All rights reserved.
|
|
|
|
*/
|
|
|
|
|
|
|
|
#include "spdk/queue.h"
|
|
|
|
#include "spdk/assert.h"
|
|
|
|
#include "spdk/env.h"
|
|
|
|
|
|
|
|
#include "ftl_mngt.h"
|
|
|
|
#include "ftl_core.h"
|
|
|
|
|
|
|
|
struct ftl_mngt_step_status {
|
|
|
|
uint64_t start;
|
|
|
|
uint64_t stop;
|
|
|
|
int status;
|
|
|
|
int silent;
|
|
|
|
TAILQ_ENTRY(ftl_mngt_step) entry;
|
|
|
|
};
|
|
|
|
|
|
|
|
struct ftl_mngt_step {
|
|
|
|
void *ctx;
|
|
|
|
const struct ftl_mngt_step_desc *desc;
|
|
|
|
struct ftl_mngt_step_status action;
|
|
|
|
struct ftl_mngt_step_status rollback;
|
|
|
|
};
|
|
|
|
|
|
|
|
struct ftl_mngt_process {
|
|
|
|
struct spdk_ftl_dev *dev;
|
|
|
|
int status;
|
2022-07-12 22:03:37 +00:00
|
|
|
bool silent;
|
2022-06-22 10:11:47 +00:00
|
|
|
bool rollback;
|
|
|
|
bool continuing;
|
|
|
|
struct {
|
2022-07-12 22:03:37 +00:00
|
|
|
ftl_mngt_completion cb;
|
2022-06-22 10:11:47 +00:00
|
|
|
void *cb_ctx;
|
|
|
|
struct spdk_thread *thread;
|
|
|
|
} caller;
|
|
|
|
void *ctx;
|
|
|
|
uint64_t tsc_start;
|
|
|
|
uint64_t tsc_stop;
|
|
|
|
const struct ftl_mngt_process_desc *desc;
|
|
|
|
TAILQ_HEAD(, ftl_mngt_step) action_queue_todo;
|
|
|
|
TAILQ_HEAD(, ftl_mngt_step) action_queue_done;
|
|
|
|
TAILQ_HEAD(, ftl_mngt_step) rollback_queue_todo;
|
|
|
|
TAILQ_HEAD(, ftl_mngt_step) rollback_queue_done;
|
|
|
|
struct {
|
|
|
|
struct ftl_mngt_step step;
|
|
|
|
struct ftl_mngt_step_desc desc;
|
|
|
|
} cleanup;
|
|
|
|
struct ftl_mng_tracer *tracer;
|
|
|
|
};
|
|
|
|
|
|
|
|
static void action_next(struct ftl_mngt_process *mngt);
|
|
|
|
static void action_msg(void *ctx);
|
|
|
|
static void action_execute(struct ftl_mngt_process *mngt);
|
|
|
|
static void action_done(struct ftl_mngt_process *mngt, int status);
|
|
|
|
static void rollback_next(struct ftl_mngt_process *mngt);
|
|
|
|
static void rollback_msg(void *ctx);
|
|
|
|
static void rollback_execute(struct ftl_mngt_process *mngt);
|
|
|
|
static void rollback_done(struct ftl_mngt_process *mngt, int status);
|
|
|
|
|
|
|
|
static inline struct ftl_mngt_step *
|
|
|
|
get_current_step(struct ftl_mngt_process *mngt)
|
|
|
|
{
|
|
|
|
if (!mngt->rollback) {
|
|
|
|
return TAILQ_FIRST(&mngt->action_queue_todo);
|
|
|
|
} else {
|
|
|
|
return TAILQ_FIRST(&mngt->rollback_queue_todo);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
static int
|
|
|
|
init_step(struct ftl_mngt_process *mngt,
|
|
|
|
const struct ftl_mngt_step_desc *desc)
|
|
|
|
{
|
|
|
|
struct ftl_mngt_step *step;
|
|
|
|
|
|
|
|
step = calloc(1, sizeof(*step));
|
|
|
|
if (!step) {
|
|
|
|
return -ENOMEM;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Initialize the step's argument */
|
|
|
|
if (desc->ctx_size) {
|
|
|
|
step->ctx = calloc(1, desc->ctx_size);
|
|
|
|
if (!step->ctx) {
|
|
|
|
free(step);
|
|
|
|
return -ENOMEM;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
step->desc = desc;
|
|
|
|
TAILQ_INSERT_TAIL(&mngt->action_queue_todo, step, action.entry);
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
static void
|
|
|
|
free_mngt(struct ftl_mngt_process *mngt)
|
|
|
|
{
|
|
|
|
TAILQ_HEAD(, ftl_mngt_step) steps;
|
|
|
|
|
|
|
|
if (!mngt) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
TAILQ_INIT(&steps);
|
|
|
|
TAILQ_CONCAT(&steps, &mngt->action_queue_todo, action.entry);
|
|
|
|
TAILQ_CONCAT(&steps, &mngt->action_queue_done, action.entry);
|
|
|
|
|
|
|
|
while (!TAILQ_EMPTY(&steps)) {
|
|
|
|
struct ftl_mngt_step *step = TAILQ_FIRST(&steps);
|
|
|
|
TAILQ_REMOVE(&steps, step, action.entry);
|
|
|
|
|
|
|
|
free(step->ctx);
|
|
|
|
free(step);
|
|
|
|
}
|
|
|
|
|
|
|
|
free(mngt->ctx);
|
|
|
|
free(mngt);
|
|
|
|
}
|
|
|
|
|
|
|
|
static struct ftl_mngt_process *
|
2022-07-12 22:03:37 +00:00
|
|
|
allocate_mngt(struct spdk_ftl_dev *dev, const struct ftl_mngt_process_desc *pdesc,
|
|
|
|
ftl_mngt_completion cb, void *cb_ctx, bool silent)
|
2022-06-22 10:11:47 +00:00
|
|
|
{
|
|
|
|
struct ftl_mngt_process *mngt;
|
|
|
|
|
|
|
|
/* Initialize management process */
|
|
|
|
mngt = calloc(1, sizeof(*mngt));
|
|
|
|
if (!mngt) {
|
|
|
|
goto error;
|
|
|
|
}
|
|
|
|
mngt->dev = dev;
|
2022-07-12 22:03:37 +00:00
|
|
|
mngt->silent = silent;
|
2022-06-22 10:11:47 +00:00
|
|
|
mngt->caller.cb = cb;
|
|
|
|
mngt->caller.cb_ctx = cb_ctx;
|
|
|
|
mngt->caller.thread = spdk_get_thread();
|
|
|
|
|
|
|
|
/* Initialize process context */
|
|
|
|
if (pdesc->ctx_size) {
|
|
|
|
mngt->ctx = calloc(1, pdesc->ctx_size);
|
|
|
|
if (!mngt->ctx) {
|
|
|
|
goto error;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
mngt->tsc_start = spdk_get_ticks();
|
|
|
|
mngt->desc = pdesc;
|
|
|
|
TAILQ_INIT(&mngt->action_queue_todo);
|
|
|
|
TAILQ_INIT(&mngt->action_queue_done);
|
|
|
|
TAILQ_INIT(&mngt->rollback_queue_todo);
|
|
|
|
TAILQ_INIT(&mngt->rollback_queue_done);
|
|
|
|
|
|
|
|
return mngt;
|
|
|
|
error:
|
|
|
|
free_mngt(mngt);
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
2022-07-12 22:03:37 +00:00
|
|
|
static int
|
|
|
|
_ftl_mngt_process_execute(struct spdk_ftl_dev *dev, const struct ftl_mngt_process_desc *pdesc,
|
|
|
|
ftl_mngt_completion cb, void *cb_ctx, bool silent)
|
2022-06-22 10:11:47 +00:00
|
|
|
{
|
|
|
|
const struct ftl_mngt_step_desc *sdesc;
|
|
|
|
struct ftl_mngt_process *mngt;
|
|
|
|
int rc = 0;
|
|
|
|
|
2022-07-12 22:03:37 +00:00
|
|
|
mngt = allocate_mngt(dev, pdesc, cb, cb_ctx, silent);
|
2022-06-22 10:11:47 +00:00
|
|
|
if (!mngt) {
|
|
|
|
rc = -ENOMEM;
|
|
|
|
goto error;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (pdesc->error_handler) {
|
|
|
|
/* Initialize a step for error handler */
|
|
|
|
mngt->cleanup.step.desc = &mngt->cleanup.desc;
|
|
|
|
mngt->cleanup.desc.name = "Handle ERROR";
|
|
|
|
mngt->cleanup.desc.cleanup = pdesc->error_handler;
|
|
|
|
|
|
|
|
/* Queue error handler to the rollback queue, it will be executed at the end */
|
|
|
|
TAILQ_INSERT_HEAD(&mngt->rollback_queue_todo, &mngt->cleanup.step,
|
|
|
|
rollback.entry);
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Initialize steps */
|
|
|
|
sdesc = mngt->desc->steps;
|
|
|
|
while (sdesc->action) {
|
|
|
|
rc = init_step(mngt, sdesc);
|
|
|
|
if (rc) {
|
|
|
|
goto error;
|
|
|
|
}
|
|
|
|
sdesc++;
|
|
|
|
}
|
|
|
|
|
|
|
|
action_execute(mngt);
|
|
|
|
return 0;
|
|
|
|
error:
|
|
|
|
free_mngt(mngt);
|
|
|
|
return rc;
|
|
|
|
}
|
|
|
|
|
|
|
|
int
|
2022-07-12 22:03:37 +00:00
|
|
|
ftl_mngt_process_execute(struct spdk_ftl_dev *dev, const struct ftl_mngt_process_desc *pdesc,
|
|
|
|
ftl_mngt_completion cb, void *cb_ctx)
|
|
|
|
{
|
|
|
|
return _ftl_mngt_process_execute(dev, pdesc, cb, cb_ctx, false);
|
|
|
|
}
|
|
|
|
|
|
|
|
int
|
|
|
|
ftl_mngt_process_rollback(struct spdk_ftl_dev *dev, const struct ftl_mngt_process_desc *pdesc,
|
|
|
|
ftl_mngt_completion cb, void *cb_ctx)
|
2022-06-22 10:11:47 +00:00
|
|
|
{
|
|
|
|
const struct ftl_mngt_step_desc *sdesc;
|
|
|
|
struct ftl_mngt_process *mngt;
|
|
|
|
int rc = 0;
|
|
|
|
|
2022-07-12 22:03:37 +00:00
|
|
|
mngt = allocate_mngt(dev, pdesc, cb, cb_ctx, true);
|
2022-06-22 10:11:47 +00:00
|
|
|
if (!mngt) {
|
|
|
|
rc = -ENOMEM;
|
|
|
|
goto error;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Initialize steps for rollback */
|
|
|
|
sdesc = mngt->desc->steps;
|
|
|
|
while (sdesc->action) {
|
|
|
|
if (!sdesc->cleanup) {
|
|
|
|
sdesc++;
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
rc = init_step(mngt, sdesc);
|
|
|
|
if (rc) {
|
|
|
|
goto error;
|
|
|
|
}
|
|
|
|
sdesc++;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Build rollback list */
|
|
|
|
struct ftl_mngt_step *step;
|
|
|
|
TAILQ_FOREACH(step, &mngt->action_queue_todo, action.entry) {
|
|
|
|
step->action.silent = true;
|
|
|
|
TAILQ_INSERT_HEAD(&mngt->rollback_queue_todo, step,
|
|
|
|
rollback.entry);
|
|
|
|
}
|
|
|
|
|
|
|
|
mngt->rollback = true;
|
|
|
|
rollback_execute(mngt);
|
|
|
|
return 0;
|
|
|
|
error:
|
|
|
|
free_mngt(mngt);
|
|
|
|
return rc;
|
|
|
|
}
|
|
|
|
|
|
|
|
struct spdk_ftl_dev *
|
|
|
|
ftl_mngt_get_dev(struct ftl_mngt_process *mngt)
|
|
|
|
{
|
|
|
|
return mngt->dev;
|
|
|
|
}
|
|
|
|
|
|
|
|
int
|
|
|
|
ftl_mngt_alloc_step_ctx(struct ftl_mngt_process *mngt, size_t size)
|
|
|
|
{
|
|
|
|
struct ftl_mngt_step *step = get_current_step(mngt);
|
|
|
|
void *arg = calloc(1, size);
|
|
|
|
|
|
|
|
if (!arg) {
|
|
|
|
return -ENOMEM;
|
|
|
|
}
|
|
|
|
|
|
|
|
free(step->ctx);
|
|
|
|
step->ctx = arg;
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
void *
|
|
|
|
ftl_mngt_get_step_ctx(struct ftl_mngt_process *mngt)
|
|
|
|
{
|
|
|
|
return get_current_step(mngt)->ctx;
|
|
|
|
}
|
|
|
|
|
|
|
|
void *
|
|
|
|
ftl_mngt_get_process_ctx(struct ftl_mngt_process *mngt)
|
|
|
|
{
|
|
|
|
return mngt->ctx;
|
|
|
|
}
|
|
|
|
|
|
|
|
void *
|
|
|
|
ftl_mngt_get_caller_ctx(struct ftl_mngt_process *mngt)
|
|
|
|
{
|
|
|
|
return mngt->caller.cb_ctx;
|
|
|
|
}
|
|
|
|
|
|
|
|
void
|
|
|
|
ftl_mngt_next_step(struct ftl_mngt_process *mngt)
|
|
|
|
{
|
|
|
|
if (false == mngt->rollback) {
|
|
|
|
action_next(mngt);
|
|
|
|
} else {
|
|
|
|
rollback_next(mngt);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void
|
|
|
|
ftl_mngt_skip_step(struct ftl_mngt_process *mngt)
|
|
|
|
{
|
|
|
|
if (mngt->rollback) {
|
|
|
|
get_current_step(mngt)->rollback.silent = true;
|
|
|
|
} else {
|
|
|
|
get_current_step(mngt)->action.silent = true;
|
|
|
|
}
|
|
|
|
ftl_mngt_next_step(mngt);
|
|
|
|
}
|
|
|
|
|
|
|
|
void
|
|
|
|
ftl_mngt_continue_step(struct ftl_mngt_process *mngt)
|
|
|
|
{
|
|
|
|
|
|
|
|
if (!mngt->continuing) {
|
|
|
|
if (false == mngt->rollback) {
|
|
|
|
action_execute(mngt);
|
|
|
|
} else {
|
|
|
|
rollback_execute(mngt);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
mngt->continuing = true;
|
|
|
|
}
|
|
|
|
|
|
|
|
static void
|
2022-07-12 22:03:37 +00:00
|
|
|
child_cb(struct spdk_ftl_dev *dev, void *ctx, int status)
|
2022-06-22 10:11:47 +00:00
|
|
|
{
|
2022-07-12 22:03:37 +00:00
|
|
|
struct ftl_mngt_process *parent = ctx;
|
2022-06-22 10:11:47 +00:00
|
|
|
|
|
|
|
if (status) {
|
|
|
|
ftl_mngt_fail_step(parent);
|
|
|
|
} else {
|
|
|
|
ftl_mngt_next_step(parent);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void
|
|
|
|
ftl_mngt_call_process(struct ftl_mngt_process *mngt,
|
|
|
|
const struct ftl_mngt_process_desc *pdesc)
|
|
|
|
{
|
2022-07-12 22:03:37 +00:00
|
|
|
if (_ftl_mngt_process_execute(mngt->dev, pdesc, child_cb, mngt, true)) {
|
2022-06-22 10:11:47 +00:00
|
|
|
ftl_mngt_fail_step(mngt);
|
|
|
|
} else {
|
|
|
|
if (mngt->rollback) {
|
|
|
|
get_current_step(mngt)->rollback.silent = true;
|
|
|
|
} else {
|
|
|
|
get_current_step(mngt)->action.silent = true;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void
|
|
|
|
ftl_mngt_call_process_rollback(struct ftl_mngt_process *mngt,
|
|
|
|
const struct ftl_mngt_process_desc *pdesc)
|
|
|
|
{
|
|
|
|
if (ftl_mngt_process_rollback(mngt->dev, pdesc, child_cb, mngt)) {
|
|
|
|
ftl_mngt_fail_step(mngt);
|
|
|
|
} else {
|
|
|
|
if (mngt->rollback) {
|
|
|
|
get_current_step(mngt)->rollback.silent = true;
|
|
|
|
} else {
|
|
|
|
get_current_step(mngt)->action.silent = true;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void
|
|
|
|
ftl_mngt_fail_step(struct ftl_mngt_process *mngt)
|
|
|
|
{
|
|
|
|
mngt->status = -1;
|
|
|
|
|
|
|
|
if (false == mngt->rollback) {
|
|
|
|
action_done(mngt, -1);
|
|
|
|
} else {
|
|
|
|
rollback_done(mngt, -1);
|
|
|
|
}
|
|
|
|
|
|
|
|
mngt->rollback = true;
|
|
|
|
rollback_execute(mngt);
|
|
|
|
}
|
|
|
|
|
|
|
|
static inline float
|
|
|
|
tsc_to_ms(uint64_t tsc)
|
|
|
|
{
|
|
|
|
float ms = tsc;
|
|
|
|
ms /= (float)spdk_get_ticks_hz();
|
|
|
|
ms *= 1000.0;
|
|
|
|
return ms;
|
|
|
|
}
|
|
|
|
|
|
|
|
static void
|
|
|
|
trace_step(struct spdk_ftl_dev *dev, struct ftl_mngt_step *step, bool rollback)
|
|
|
|
{
|
|
|
|
uint64_t duration;
|
|
|
|
const char *what = rollback ? "Rollback" : "Action";
|
|
|
|
int silent = rollback ? step->rollback.silent : step->action.silent;
|
|
|
|
|
|
|
|
if (silent) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
FTL_NOTICELOG(dev, "%s\n", what);
|
|
|
|
FTL_NOTICELOG(dev, "\t name: %s\n", step->desc->name);
|
|
|
|
duration = step->action.stop - step->action.start;
|
|
|
|
FTL_NOTICELOG(dev, "\t duration: %.3f ms\n", tsc_to_ms(duration));
|
|
|
|
FTL_NOTICELOG(dev, "\t status: %d\n", step->action.status);
|
|
|
|
}
|
|
|
|
|
|
|
|
static void
|
|
|
|
process_summary(struct ftl_mngt_process *mngt)
|
|
|
|
{
|
|
|
|
uint64_t duration;
|
|
|
|
|
|
|
|
if (mngt->silent) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
duration = mngt->tsc_stop - mngt->tsc_start;
|
|
|
|
FTL_NOTICELOG(mngt->dev, "Management process finished, "
|
|
|
|
"name '%s', duration = %.3f ms, result %d\n",
|
|
|
|
mngt->desc->name,
|
|
|
|
tsc_to_ms(duration),
|
|
|
|
mngt->status);
|
|
|
|
}
|
|
|
|
|
|
|
|
static void
|
|
|
|
finish_msg(void *ctx)
|
|
|
|
{
|
|
|
|
struct ftl_mngt_process *mngt = ctx;
|
|
|
|
|
2022-07-12 22:03:37 +00:00
|
|
|
mngt->caller.cb(mngt->dev, mngt->caller.cb_ctx, mngt->status);
|
2022-06-22 10:11:47 +00:00
|
|
|
process_summary(mngt);
|
|
|
|
free_mngt(mngt);
|
|
|
|
}
|
|
|
|
|
|
|
|
void
|
|
|
|
ftl_mngt_finish(struct ftl_mngt_process *mngt)
|
|
|
|
{
|
|
|
|
mngt->tsc_stop = spdk_get_ticks();
|
|
|
|
spdk_thread_send_msg(mngt->caller.thread, finish_msg, mngt);
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Actions
|
|
|
|
*/
|
|
|
|
static void
|
|
|
|
action_next(struct ftl_mngt_process *mngt)
|
|
|
|
{
|
|
|
|
if (TAILQ_EMPTY(&mngt->action_queue_todo)) {
|
|
|
|
/* Nothing to do, finish the management process */
|
|
|
|
ftl_mngt_finish(mngt);
|
|
|
|
return;
|
|
|
|
} else {
|
|
|
|
action_done(mngt, 0);
|
|
|
|
action_execute(mngt);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
static void
|
|
|
|
action_msg(void *ctx)
|
|
|
|
{
|
|
|
|
struct ftl_mngt_process *mngt = ctx;
|
|
|
|
struct ftl_mngt_step *step;
|
|
|
|
|
|
|
|
mngt->continuing = false;
|
|
|
|
|
|
|
|
if (TAILQ_EMPTY(&mngt->action_queue_todo)) {
|
|
|
|
ftl_mngt_finish(mngt);
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
step = TAILQ_FIRST(&mngt->action_queue_todo);
|
|
|
|
if (!step->action.start) {
|
|
|
|
step->action.start = spdk_get_ticks();
|
|
|
|
}
|
|
|
|
step->desc->action(mngt->dev, mngt);
|
|
|
|
}
|
|
|
|
|
|
|
|
static void
|
|
|
|
action_execute(struct ftl_mngt_process *mngt)
|
|
|
|
{
|
|
|
|
spdk_thread_send_msg(mngt->dev->core_thread, action_msg, mngt);
|
|
|
|
}
|
|
|
|
|
|
|
|
static void
|
|
|
|
action_done(struct ftl_mngt_process *mngt, int status)
|
|
|
|
{
|
|
|
|
struct ftl_mngt_step *step;
|
|
|
|
|
|
|
|
assert(!TAILQ_EMPTY(&mngt->action_queue_todo));
|
|
|
|
step = TAILQ_FIRST(&mngt->action_queue_todo);
|
|
|
|
TAILQ_REMOVE(&mngt->action_queue_todo, step, action.entry);
|
|
|
|
|
|
|
|
TAILQ_INSERT_TAIL(&mngt->action_queue_done, step, action.entry);
|
|
|
|
if (step->desc->cleanup) {
|
|
|
|
TAILQ_INSERT_HEAD(&mngt->rollback_queue_todo, step,
|
|
|
|
rollback.entry);
|
|
|
|
}
|
|
|
|
|
|
|
|
step->action.stop = spdk_get_ticks();
|
|
|
|
step->action.status = status;
|
|
|
|
|
|
|
|
trace_step(mngt->dev, step, false);
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Rollback
|
|
|
|
*/
|
|
|
|
static void
|
|
|
|
rollback_next(struct ftl_mngt_process *mngt)
|
|
|
|
{
|
|
|
|
if (TAILQ_EMPTY(&mngt->rollback_queue_todo)) {
|
|
|
|
/* Nothing to do, finish the management process */
|
|
|
|
ftl_mngt_finish(mngt);
|
|
|
|
return;
|
|
|
|
} else {
|
|
|
|
rollback_done(mngt, 0);
|
|
|
|
rollback_execute(mngt);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
static void
|
|
|
|
rollback_msg(void *ctx)
|
|
|
|
{
|
|
|
|
struct ftl_mngt_process *mngt = ctx;
|
|
|
|
struct ftl_mngt_step *step;
|
|
|
|
|
|
|
|
mngt->continuing = false;
|
|
|
|
|
|
|
|
if (TAILQ_EMPTY(&mngt->rollback_queue_todo)) {
|
|
|
|
ftl_mngt_finish(mngt);
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
step = TAILQ_FIRST(&mngt->rollback_queue_todo);
|
|
|
|
if (!step->rollback.start) {
|
|
|
|
step->rollback.start = spdk_get_ticks();
|
|
|
|
}
|
|
|
|
step->desc->cleanup(mngt->dev, mngt);
|
|
|
|
}
|
|
|
|
|
|
|
|
static void
|
|
|
|
rollback_execute(struct ftl_mngt_process *mngt)
|
|
|
|
{
|
|
|
|
spdk_thread_send_msg(mngt->dev->core_thread, rollback_msg, mngt);
|
|
|
|
}
|
|
|
|
|
|
|
|
void
|
|
|
|
rollback_done(struct ftl_mngt_process *mngt, int status)
|
|
|
|
{
|
|
|
|
struct ftl_mngt_step *step;
|
|
|
|
|
|
|
|
assert(!TAILQ_EMPTY(&mngt->rollback_queue_todo));
|
|
|
|
step = TAILQ_FIRST(&mngt->rollback_queue_todo);
|
|
|
|
TAILQ_REMOVE(&mngt->rollback_queue_todo, step, rollback.entry);
|
|
|
|
TAILQ_INSERT_TAIL(&mngt->rollback_queue_done, step, rollback.entry);
|
|
|
|
|
|
|
|
step->rollback.stop = spdk_get_ticks();
|
|
|
|
step->rollback.status = status;
|
|
|
|
|
|
|
|
trace_step(mngt->dev, step, true);
|
|
|
|
}
|