ftl: management framework
Signed-off-by: Artur Paszkiewicz <artur.paszkiewicz@intel.com> Signed-off-by: Kozlowski Mateusz <mateusz.kozlowski@intel.com> Change-Id: I8261863e80a53a37183b0148d4a08fa97e208dda Reviewed-on: https://review.spdk.io/gerrit/c/spdk/spdk/+/13289 Tested-by: SPDK CI Jenkins <sys_sgci@intel.com> Reviewed-by: Jim Harris <james.r.harris@intel.com> Reviewed-by: Ben Walker <benjamin.walker@intel.com> Community-CI: Mellanox Build Bot
This commit is contained in:
parent
5140958837
commit
293cdc484b
@ -11,9 +11,10 @@ SO_MINOR := 0
|
||||
|
||||
CFLAGS += -I.
|
||||
|
||||
FTL_SUBDIRS := utils
|
||||
FTL_SUBDIRS := mngt utils
|
||||
|
||||
C_SRCS = ftl_core.c
|
||||
C_SRCS += mngt/ftl_mngt.c
|
||||
|
||||
SPDK_MAP_FILE = $(abspath $(CURDIR)/spdk_ftl.map)
|
||||
|
||||
|
@ -14,5 +14,6 @@
|
||||
|
||||
#include "ftl_core.h"
|
||||
#include "ftl_internal.h"
|
||||
#include "mngt/ftl_mngt.h"
|
||||
|
||||
SPDK_LOG_REGISTER_COMPONENT(ftl_core)
|
||||
|
570
lib/ftl/mngt/ftl_mngt.c
Normal file
570
lib/ftl/mngt/ftl_mngt.c
Normal file
@ -0,0 +1,570 @@
|
||||
/* 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;
|
||||
int silent;
|
||||
bool rollback;
|
||||
bool continuing;
|
||||
struct {
|
||||
ftl_mngt_fn cb;
|
||||
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 *
|
||||
allocate_mngt(struct spdk_ftl_dev *dev,
|
||||
const struct ftl_mngt_process_desc *pdesc,
|
||||
ftl_mngt_fn cb, void *cb_ctx)
|
||||
{
|
||||
struct ftl_mngt_process *mngt;
|
||||
|
||||
/* Initialize management process */
|
||||
mngt = calloc(1, sizeof(*mngt));
|
||||
if (!mngt) {
|
||||
goto error;
|
||||
}
|
||||
mngt->dev = dev;
|
||||
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;
|
||||
}
|
||||
|
||||
int
|
||||
ftl_mngt_process_execute(struct spdk_ftl_dev *dev,
|
||||
const struct ftl_mngt_process_desc *pdesc,
|
||||
ftl_mngt_fn cb, void *cb_ctx)
|
||||
{
|
||||
const struct ftl_mngt_step_desc *sdesc;
|
||||
struct ftl_mngt_process *mngt;
|
||||
int rc = 0;
|
||||
|
||||
mngt = allocate_mngt(dev, pdesc, cb, cb_ctx);
|
||||
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
|
||||
ftl_mngt_process_rollback(struct spdk_ftl_dev *dev,
|
||||
const struct ftl_mngt_process_desc *pdesc,
|
||||
ftl_mngt_fn cb, void *cb_ctx)
|
||||
{
|
||||
const struct ftl_mngt_step_desc *sdesc;
|
||||
struct ftl_mngt_process *mngt;
|
||||
int rc = 0;
|
||||
|
||||
mngt = allocate_mngt(dev, pdesc, cb, cb_ctx);
|
||||
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;
|
||||
}
|
||||
|
||||
int
|
||||
ftl_mngt_get_status(struct ftl_mngt_process *mngt)
|
||||
{
|
||||
return mngt->status;
|
||||
}
|
||||
|
||||
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
|
||||
child_cb(struct spdk_ftl_dev *dev, struct ftl_mngt_process *child)
|
||||
{
|
||||
int status = ftl_mngt_get_status(child);
|
||||
struct ftl_mngt_process *parent = ftl_mngt_get_caller_ctx(child);
|
||||
|
||||
child->silent = true;
|
||||
|
||||
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)
|
||||
{
|
||||
if (ftl_mngt_process_execute(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_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;
|
||||
|
||||
mngt->caller.cb(mngt->dev, mngt);
|
||||
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);
|
||||
}
|
294
lib/ftl/mngt/ftl_mngt.h
Normal file
294
lib/ftl/mngt/ftl_mngt.h
Normal file
@ -0,0 +1,294 @@
|
||||
/* SPDX-License-Identifier: BSD-3-Clause
|
||||
* Copyright (c) Intel Corporation.
|
||||
* All rights reserved.
|
||||
*/
|
||||
|
||||
#ifndef FTL_MNGT_H
|
||||
#define FTL_MNGT_H
|
||||
|
||||
#include "spdk/stdinc.h"
|
||||
#include "spdk/ftl.h"
|
||||
|
||||
struct spdk_ftl_dev;
|
||||
struct ftl_mngt_process;
|
||||
|
||||
/**
|
||||
* The FTL management callback function
|
||||
*
|
||||
* @param dev FTL device
|
||||
* @param mngt FTL management handle
|
||||
*/
|
||||
typedef void (*ftl_mngt_fn)(struct spdk_ftl_dev *dev, struct ftl_mngt_process *mngt);
|
||||
|
||||
/**
|
||||
* The FTL management step descriptior
|
||||
*/
|
||||
struct ftl_mngt_step_desc {
|
||||
/**
|
||||
* Name of the step
|
||||
*/
|
||||
const char *name;
|
||||
|
||||
/**
|
||||
* Size of the step argument (context)
|
||||
*
|
||||
* The step context will be allocated before execution of step's
|
||||
* callback.
|
||||
*
|
||||
* @note The context can be reallocated (freed and newly allocated
|
||||
* when calling ftl_mngt_alloc_step_ctx). The main usage is the ability
|
||||
* to set this value to 0 and only allocate as needed if the step is
|
||||
* going to be extremely similar - eg. recovery from shared memory and
|
||||
* disk - in case of shm all the data is already available in memory, while
|
||||
* recovery from disk needs extra context to be able to synchronize IO. This
|
||||
* allows for saving a little bit of time on alloc/dealloc in the cases where
|
||||
* execution time may be critical.
|
||||
* @note It doesn't work like realloc
|
||||
* @note The context can be retrieved within callback when calling
|
||||
* ftl_mngt_get_step_ctx
|
||||
*/
|
||||
size_t ctx_size;
|
||||
|
||||
/**
|
||||
* Step callback function
|
||||
*/
|
||||
ftl_mngt_fn action;
|
||||
|
||||
/**
|
||||
* It the step requires cleanup this is right place to put your handler.
|
||||
* When a FTL management process fails cleanup callbacks are executed
|
||||
* in rollback procedure. Cleanup functions are executed in reverse
|
||||
* order to actions already called.
|
||||
*/
|
||||
ftl_mngt_fn cleanup;
|
||||
};
|
||||
|
||||
/**
|
||||
* The FTL management process descriptor
|
||||
*/
|
||||
struct ftl_mngt_process_desc {
|
||||
/**
|
||||
* The name of the process
|
||||
*/
|
||||
const char *name;
|
||||
|
||||
/**
|
||||
* Size of the process argument (context)
|
||||
*
|
||||
* The process context will be allocated before execution of the first
|
||||
* step
|
||||
*
|
||||
* @note To get context of the process within FTL management callback,
|
||||
* execute ftl_mngt_get_process_ctx
|
||||
*/
|
||||
size_t ctx_size;
|
||||
|
||||
/**
|
||||
* Pointer to the additional error handler when the process fails
|
||||
*/
|
||||
ftl_mngt_fn error_handler;
|
||||
|
||||
/**
|
||||
* The FTL process steps
|
||||
*
|
||||
* The process context will be allocated before execution of the first
|
||||
* step
|
||||
*
|
||||
* @note The step array terminator shall end with action equals NULL
|
||||
*/
|
||||
struct ftl_mngt_step_desc steps[];
|
||||
};
|
||||
|
||||
/**
|
||||
* @brief Executes the FTL management process defined by the process descriptor
|
||||
*
|
||||
* In case of an error all already executed steps will have their rollback functions
|
||||
* called in reverse order.
|
||||
*
|
||||
* @param dev FTL device
|
||||
* @param process The descriptor of process to be executed
|
||||
* @param cb Caller callback
|
||||
* @param cb_ctx Caller context
|
||||
*
|
||||
* @return Result of invoking the operation
|
||||
* @retval 0 - The FTL management process has been started
|
||||
* @retval Non-zero An error occurred when starting The FTL management process
|
||||
*/
|
||||
int ftl_mngt_process_execute(struct spdk_ftl_dev *dev,
|
||||
const struct ftl_mngt_process_desc *process,
|
||||
ftl_mngt_fn cb, void *cb_ctx);
|
||||
|
||||
/**
|
||||
* @brief Executes rollback on the FTL management process defined by the process
|
||||
* descriptor
|
||||
*
|
||||
* All cleanup function from steps will be executed in reversed order
|
||||
*
|
||||
* @param dev FTL device
|
||||
* @param process The descriptor of process to be rollback
|
||||
* @param cb Caller callback
|
||||
* @param cb_ctx Caller context
|
||||
*
|
||||
* @return Result of invoking the rollback operation
|
||||
* @retval 0 - Rollback of the FTL management process has been started
|
||||
* @retval Non-zero An error occurred when starting the rollback
|
||||
*/
|
||||
int ftl_mngt_process_rollback(struct spdk_ftl_dev *dev,
|
||||
const struct ftl_mngt_process_desc *process,
|
||||
ftl_mngt_fn cb, void *cb_ctx);
|
||||
|
||||
/*
|
||||
* FTL management API for steps
|
||||
*/
|
||||
|
||||
/**
|
||||
* @brief Gets FTL device
|
||||
*
|
||||
* @param mngt FTL management handle
|
||||
*
|
||||
* @note This function can be invoked within step handler only
|
||||
*
|
||||
* @return FTL device
|
||||
*/
|
||||
struct spdk_ftl_dev *ftl_mngt_get_dev(struct ftl_mngt_process *mngt);
|
||||
|
||||
/**
|
||||
* @brief Allocates a context for the management step
|
||||
*
|
||||
* @param mngt FTL management handle
|
||||
* @param size Size of the step context
|
||||
*
|
||||
* @note This function can be invoked within ftl_mngt_fn callback only
|
||||
*
|
||||
* @return Operation result
|
||||
* @retval 0 Operation successful
|
||||
* @retval Non-zero Operation failure
|
||||
*/
|
||||
int ftl_mngt_alloc_step_ctx(struct ftl_mngt_process *mngt, size_t size);
|
||||
|
||||
/**
|
||||
* @brief Gets the management step context
|
||||
*
|
||||
* @param mngt FTL management handle
|
||||
*
|
||||
* @note This function can be invoked within ftl_mngt_fn callback only
|
||||
*
|
||||
* @return Context of the step containing pointer to buffer and its size
|
||||
*/
|
||||
void *ftl_mngt_get_step_ctx(struct ftl_mngt_process *mngt);
|
||||
|
||||
/**
|
||||
* @brief Gets the management process context
|
||||
*
|
||||
* @param mngt FTL management handle
|
||||
*
|
||||
* @note This function can be invoked within ftl_mngt_fn callback only
|
||||
*
|
||||
* @return Context of the process containing pointer to buffer and its size
|
||||
*/
|
||||
void *ftl_mngt_get_process_ctx(struct ftl_mngt_process *mngt);
|
||||
|
||||
/**
|
||||
* @brief Gets the caller context
|
||||
*
|
||||
* @param mngt FTL management handle
|
||||
*
|
||||
* @note This function can be invoked within ftl_mngt_fn callback only
|
||||
*
|
||||
* @return Pointer to the caller context
|
||||
*/
|
||||
void *ftl_mngt_get_caller_ctx(struct ftl_mngt_process *mngt);
|
||||
|
||||
/**
|
||||
* @brief Gets the status of executed management process
|
||||
*
|
||||
* @param mngt FTL management handle
|
||||
*
|
||||
* @note This function can be invoked within ftl_mngt_fn callback only
|
||||
*
|
||||
* @return The operation result of the management process
|
||||
* @retval 0 Operation successful
|
||||
* @retval Non-zero Operation failure
|
||||
*/
|
||||
int ftl_mngt_get_status(struct ftl_mngt_process *mngt);
|
||||
|
||||
/**
|
||||
* @brief Finishes the management process immediately
|
||||
*
|
||||
* @note This function can be invoked within ftl_mngt_fn callback only
|
||||
*
|
||||
* @param mngt FTL management handle of process to be finished
|
||||
*/
|
||||
void ftl_mngt_finish(struct ftl_mngt_process *mngt);
|
||||
|
||||
/**
|
||||
* @brief Completes the step currently in progress and jump to a next one
|
||||
*
|
||||
* If no more steps to be executed then the management process is finished and
|
||||
* caller callback is invoked
|
||||
*
|
||||
* @note This function can be invoked within ftl_mngt_fn callback only
|
||||
*
|
||||
* @param mngt FTL management handle
|
||||
*/
|
||||
void ftl_mngt_next_step(struct ftl_mngt_process *mngt);
|
||||
|
||||
/**
|
||||
* @brief Skips the step currently in progress and jump to a next one
|
||||
*
|
||||
* @note This function can be invoked within ftl_mngt_fn callback only
|
||||
*
|
||||
* @param mngt FTL management handle
|
||||
*/
|
||||
void ftl_mngt_skip_step(struct ftl_mngt_process *mngt);
|
||||
|
||||
/**
|
||||
* @brief Continue the step currently in progress
|
||||
*
|
||||
* This causes invoking the same step handler in next iteration of the
|
||||
* management process. This mechanism can be used by a job when polling for
|
||||
* something.
|
||||
*
|
||||
* @note This function can be invoked within ftl_mngt_fn callback only
|
||||
*
|
||||
* @param mngt FTL management handle
|
||||
*/
|
||||
void ftl_mngt_continue_step(struct ftl_mngt_process *mngt);
|
||||
|
||||
/**
|
||||
* @brief Fail the step currently in progress.
|
||||
*
|
||||
* It stops executing all steps and starts the rollback procedure (calling
|
||||
* the cleanup functions of all already executed steps).
|
||||
* If executed from a cleanup function, it will stop executing and the following
|
||||
* cleanup functions (if any) will be executed.
|
||||
*
|
||||
* @param mngt FTL management handle
|
||||
*/
|
||||
void ftl_mngt_fail_step(struct ftl_mngt_process *mngt);
|
||||
|
||||
/**
|
||||
* @brief Calls another management process
|
||||
*
|
||||
* Ends the current step and executes specified process and finally continues
|
||||
* executing the the remaining steps
|
||||
*
|
||||
* @param mngt The management handle
|
||||
* @param process The management process to be called
|
||||
*/
|
||||
void ftl_mngt_call_process(struct ftl_mngt_process *mngt,
|
||||
const struct ftl_mngt_process_desc *process);
|
||||
|
||||
/**
|
||||
* @brief Calls rollback steps of another management process
|
||||
*
|
||||
* Ends the current step and executes rollback steps of specified process
|
||||
* and finally continues executing the remaining steps in the original process
|
||||
*
|
||||
* @param mngt The management handle
|
||||
* @param process The management process to be called to execute rollback
|
||||
*/
|
||||
void ftl_mngt_call_process_rollback(struct ftl_mngt_process *mngt,
|
||||
const struct ftl_mngt_process_desc *process);
|
||||
|
||||
#endif /* LIB_FTL_FTL_MNGT_H */
|
@ -60,7 +60,7 @@ DEPDIRS-blobfs := log thread blob trace util
|
||||
DEPDIRS-event := log util thread $(JSON_LIBS) trace init
|
||||
DEPDIRS-init := jsonrpc json log rpc thread util
|
||||
|
||||
DEPDIRS-ftl := log
|
||||
DEPDIRS-ftl := log thread
|
||||
DEPDIRS-nbd := log util thread $(JSON_LIBS) bdev
|
||||
DEPDIRS-nvmf := accel log sock util nvme thread $(JSON_LIBS) trace bdev
|
||||
ifeq ($(CONFIG_RDMA),y)
|
||||
|
@ -12,6 +12,7 @@ DIRS-$(CONFIG_IDXD) += idxd
|
||||
DIRS-$(CONFIG_REDUCE) += reduce
|
||||
ifeq ($(OS),Linux)
|
||||
DIRS-$(CONFIG_VHOST) += vhost
|
||||
DIRS-y += ftl
|
||||
endif
|
||||
|
||||
.PHONY: all clean $(DIRS-y)
|
||||
|
16
test/unit/lib/ftl/Makefile
Normal file
16
test/unit/lib/ftl/Makefile
Normal file
@ -0,0 +1,16 @@
|
||||
# SPDX-License-Identifier: BSD-3-Clause
|
||||
# Copyright (c) Intel Corporation.
|
||||
# All rights reserved.
|
||||
#
|
||||
|
||||
SPDK_ROOT_DIR := $(abspath $(CURDIR)/../../../..)
|
||||
include $(SPDK_ROOT_DIR)/mk/spdk.common.mk
|
||||
|
||||
DIRS-y = ftl_mngt
|
||||
|
||||
.PHONY: all clean $(DIRS-y)
|
||||
|
||||
all: $(DIRS-y)
|
||||
clean: $(DIRS-y)
|
||||
|
||||
include $(SPDK_ROOT_DIR)/mk/spdk.subdirs.mk
|
1
test/unit/lib/ftl/ftl_mngt/.gitignore
vendored
Normal file
1
test/unit/lib/ftl/ftl_mngt/.gitignore
vendored
Normal file
@ -0,0 +1 @@
|
||||
ftl_mngt_ut
|
12
test/unit/lib/ftl/ftl_mngt/Makefile
Normal file
12
test/unit/lib/ftl/ftl_mngt/Makefile
Normal file
@ -0,0 +1,12 @@
|
||||
# SPDX-License-Identifier: BSD-3-Clause
|
||||
# Copyright (c) Intel Corporation.
|
||||
# All rights reserved.
|
||||
#
|
||||
|
||||
SPDK_ROOT_DIR := $(abspath $(CURDIR)/../../../../..)
|
||||
|
||||
TEST_FILE = ftl_mngt_ut.c
|
||||
|
||||
include $(SPDK_ROOT_DIR)/mk/spdk.unittest.mk
|
||||
|
||||
CFLAGS += -I$(SPDK_ROOT_DIR)/lib/ftl
|
1110
test/unit/lib/ftl/ftl_mngt/ftl_mngt_ut.c
Normal file
1110
test/unit/lib/ftl/ftl_mngt/ftl_mngt_ut.c
Normal file
File diff suppressed because it is too large
Load Diff
@ -44,6 +44,10 @@ function unittest_event() {
|
||||
$valgrind $testdir/lib/event/reactor.c/reactor_ut
|
||||
}
|
||||
|
||||
function unittest_ftl() {
|
||||
$valgrind $testdir/lib/ftl/ftl_mngt/ftl_mngt_ut
|
||||
}
|
||||
|
||||
function unittest_iscsi() {
|
||||
$valgrind $testdir/lib/iscsi/conn.c/conn_ut
|
||||
$valgrind $testdir/lib/iscsi/param.c/param_ut
|
||||
@ -206,6 +210,9 @@ fi
|
||||
|
||||
run_test "unittest_blob_blobfs" unittest_blob
|
||||
run_test "unittest_event" unittest_event
|
||||
if [ $(uname -s) = Linux ]; then
|
||||
run_test "unittest_ftl" unittest_ftl
|
||||
fi
|
||||
|
||||
run_test "unittest_accel" $valgrind $testdir/lib/accel/accel.c/accel_engine_ut
|
||||
run_test "unittest_ioat" $valgrind $testdir/lib/ioat/ioat.c/ioat_ut
|
||||
|
Loading…
Reference in New Issue
Block a user