FTL: Add L2P API and flat L2P implementation
Signed-off-by: Kozlowski Mateusz <mateusz.kozlowski@intel.com> Signed-off-by: Artur Paszkiewicz <artur.paszkiewicz@intel.com> Change-Id: Ifadc8c6986164584235ee6a67799025fa7703b5d Reviewed-on: https://review.spdk.io/gerrit/c/spdk/spdk/+/13315 Tested-by: SPDK CI Jenkins <sys_sgci@intel.com> Community-CI: Mellanox Build Bot Community-CI: Broadcom CI <spdk-ci.pdl@broadcom.com> Reviewed-by: Jim Harris <james.r.harris@intel.com> Reviewed-by: Ben Walker <benjamin.walker@intel.com>
This commit is contained in:
parent
b6eecb21e5
commit
b16bdc6d49
@ -21,9 +21,9 @@ CFLAGS += -I.
|
||||
|
||||
FTL_SUBDIRS := mngt utils
|
||||
|
||||
C_SRCS = ftl_core.c ftl_init.c ftl_layout.c ftl_debug.c ftl_io.c ftl_sb.c
|
||||
C_SRCS = ftl_core.c ftl_init.c ftl_layout.c ftl_debug.c ftl_io.c ftl_sb.c ftl_l2p.c ftl_l2p_flat.c
|
||||
C_SRCS += mngt/ftl_mngt.c mngt/ftl_mngt_bdev.c mngt/ftl_mngt_shutdown.c mngt/ftl_mngt_startup.c
|
||||
C_SRCS += mngt/ftl_mngt_md.c mngt/ftl_mngt_misc.c mngt/ftl_mngt_ioch.c
|
||||
C_SRCS += mngt/ftl_mngt_md.c mngt/ftl_mngt_misc.c mngt/ftl_mngt_ioch.c mngt/ftl_mngt_l2p.c
|
||||
C_SRCS += utils/ftl_conf.c utils/ftl_md.c utils/ftl_mempool.c
|
||||
|
||||
SPDK_MAP_FILE = $(abspath $(CURDIR)/spdk_ftl.map)
|
||||
|
@ -26,14 +26,27 @@ spdk_ftl_io_size(void)
|
||||
return sizeof(struct ftl_io);
|
||||
}
|
||||
|
||||
static int
|
||||
static bool
|
||||
ftl_shutdown_complete(struct spdk_ftl_dev *dev)
|
||||
{
|
||||
if (dev->num_inflight) {
|
||||
return 0;
|
||||
return false;
|
||||
}
|
||||
|
||||
return 1;
|
||||
if (!ftl_l2p_is_halted(dev)) {
|
||||
ftl_l2p_halt(dev);
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void
|
||||
ftl_invalidate_addr(struct spdk_ftl_dev *dev, ftl_addr addr)
|
||||
{
|
||||
if (ftl_addr_in_nvc(dev, addr)) {
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
@ -128,6 +141,7 @@ ftl_core_poller(void *ctx)
|
||||
}
|
||||
|
||||
ftl_process_io_queue(dev);
|
||||
ftl_l2p_process(dev);
|
||||
|
||||
if (io_activity_total_old != dev->io_activity_total) {
|
||||
return SPDK_POLLER_BUSY;
|
||||
|
@ -20,6 +20,7 @@
|
||||
#include "ftl_io.h"
|
||||
#include "ftl_layout.h"
|
||||
#include "ftl_sb.h"
|
||||
#include "ftl_l2p.h"
|
||||
#include "utils/ftl_log.h"
|
||||
|
||||
/* When using VSS on nvcache, FTL sometimes doesn't require the contents of metadata.
|
||||
@ -81,6 +82,12 @@ struct spdk_ftl_dev {
|
||||
/* Number of free bands */
|
||||
uint64_t num_free;
|
||||
|
||||
/* Logical -> physical table */
|
||||
void *l2p;
|
||||
|
||||
/* l2p deferred pins list */
|
||||
TAILQ_HEAD(, ftl_l2p_pin_ctx) l2p_deferred_pins;
|
||||
|
||||
/* Size of the l2p table */
|
||||
uint64_t num_lbas;
|
||||
|
||||
@ -117,6 +124,8 @@ struct spdk_ftl_dev {
|
||||
TAILQ_HEAD(, ftl_io) wr_sq;
|
||||
};
|
||||
|
||||
void ftl_invalidate_addr(struct spdk_ftl_dev *dev, ftl_addr addr);
|
||||
|
||||
int ftl_core_poller(void *ctx);
|
||||
|
||||
int ftl_io_channel_poll(void *arg);
|
||||
|
@ -181,12 +181,47 @@ ftl_io_init(struct spdk_io_channel *_ioch, struct ftl_io *io, uint64_t lba, size
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void
|
||||
ftl_io_complete_verify(struct ftl_io *io)
|
||||
{
|
||||
struct spdk_ftl_dev *dev = io->dev;
|
||||
uint64_t i;
|
||||
uint64_t lba = io->lba;
|
||||
|
||||
assert(io->num_blocks <= dev->xfer_size);
|
||||
|
||||
if (FTL_IO_WRITE == io->type) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (spdk_unlikely(io->status)) {
|
||||
return;
|
||||
}
|
||||
|
||||
for (i = 0; i < io->num_blocks; i++, lba++) {
|
||||
ftl_addr current_addr = ftl_l2p_get(dev, lba);
|
||||
|
||||
/* If user read request gets stuck for whatever reason, then it's possible the LBA
|
||||
* has been relocated by GC or compaction and it may no longer be safe to return data
|
||||
* from that address */
|
||||
if (spdk_unlikely(current_addr != io->map[i])) {
|
||||
io->status = -EAGAIN;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
ftl_io_complete(struct ftl_io *io)
|
||||
{
|
||||
io->flags &= ~FTL_IO_INITIALIZED;
|
||||
io->done = true;
|
||||
|
||||
if (io->flags & FTL_IO_PINNED) {
|
||||
ftl_io_complete_verify(io);
|
||||
ftl_l2p_unpin(io->dev, io->lba, io->num_blocks);
|
||||
}
|
||||
|
||||
ftl_io_cb(io, io->cb_ctx, io->status);
|
||||
}
|
||||
|
||||
|
@ -13,6 +13,7 @@
|
||||
#include "spdk/util.h"
|
||||
|
||||
#include "ftl_internal.h"
|
||||
#include "ftl_l2p.h"
|
||||
#include "utils/ftl_md.h"
|
||||
|
||||
struct spdk_ftl_dev;
|
||||
@ -24,6 +25,8 @@ typedef void (*ftl_io_fn)(struct ftl_io *, void *, int);
|
||||
enum ftl_io_flags {
|
||||
/* Indicates whether IO is already initialized */
|
||||
FTL_IO_INITIALIZED = (1 << 0),
|
||||
/* Indicated whether the user IO pinned the L2P pages containing LBAs */
|
||||
FTL_IO_PINNED = (1 << 1),
|
||||
};
|
||||
|
||||
enum ftl_io_type {
|
||||
@ -111,6 +114,9 @@ struct ftl_io {
|
||||
/* Reference to the chunk within NV cache */
|
||||
struct ftl_nv_cache_chunk *nv_cache_chunk;
|
||||
|
||||
/* For l2p pinning */
|
||||
struct ftl_l2p_pin_ctx l2p_pin_ctx;
|
||||
|
||||
/* Logical to physical mapping for this IO, number of entries equals to
|
||||
* number of transfer blocks */
|
||||
ftl_addr *map;
|
||||
@ -141,6 +147,9 @@ struct ftl_rq_entry {
|
||||
void *priv;
|
||||
} owner;
|
||||
|
||||
/* For l2p pinning */
|
||||
struct ftl_l2p_pin_ctx l2p_pin_ctx;
|
||||
|
||||
struct {
|
||||
uint64_t offset_blocks;
|
||||
uint64_t num_blocks;
|
||||
|
148
lib/ftl/ftl_l2p.c
Normal file
148
lib/ftl/ftl_l2p.c
Normal file
@ -0,0 +1,148 @@
|
||||
/* SPDX-License-Identifier: BSD-3-Clause
|
||||
* Copyright (c) Intel Corporation.
|
||||
* All rights reserved.
|
||||
*/
|
||||
|
||||
#include "ftl_l2p.h"
|
||||
#include "ftl_l2p_flat.h"
|
||||
#include "ftl_core.h"
|
||||
|
||||
|
||||
/* TODO: Verify why function pointers had worse performance than compile time constants */
|
||||
#define FTL_L2P_OP(name) ftl_l2p_flat_ ## name
|
||||
|
||||
|
||||
int
|
||||
ftl_l2p_init(struct spdk_ftl_dev *dev)
|
||||
{
|
||||
TAILQ_INIT(&dev->l2p_deferred_pins);
|
||||
return FTL_L2P_OP(init)(dev);
|
||||
}
|
||||
|
||||
void
|
||||
ftl_l2p_deinit(struct spdk_ftl_dev *dev)
|
||||
{
|
||||
FTL_L2P_OP(deinit)(dev);
|
||||
}
|
||||
|
||||
static inline void
|
||||
ftl_l2p_pin_ctx_init(struct ftl_l2p_pin_ctx *pin_ctx, uint64_t lba, uint64_t count,
|
||||
ftl_l2p_pin_cb cb, void *cb_ctx)
|
||||
{
|
||||
pin_ctx->lba = lba;
|
||||
pin_ctx->count = count;
|
||||
pin_ctx->cb = cb;
|
||||
pin_ctx->cb_ctx = cb_ctx;
|
||||
}
|
||||
|
||||
void
|
||||
ftl_l2p_pin(struct spdk_ftl_dev *dev, uint64_t lba, uint64_t count, ftl_l2p_pin_cb cb, void *cb_ctx,
|
||||
struct ftl_l2p_pin_ctx *pin_ctx)
|
||||
{
|
||||
ftl_l2p_pin_ctx_init(pin_ctx, lba, count, cb, cb_ctx);
|
||||
FTL_L2P_OP(pin)(dev, pin_ctx);
|
||||
}
|
||||
|
||||
void
|
||||
ftl_l2p_unpin(struct spdk_ftl_dev *dev, uint64_t lba, uint64_t count)
|
||||
{
|
||||
FTL_L2P_OP(unpin)(dev, lba, count);
|
||||
}
|
||||
|
||||
void
|
||||
ftl_l2p_pin_skip(struct spdk_ftl_dev *dev, ftl_l2p_pin_cb cb, void *cb_ctx,
|
||||
struct ftl_l2p_pin_ctx *pin_ctx)
|
||||
{
|
||||
ftl_l2p_pin_ctx_init(pin_ctx, FTL_LBA_INVALID, 0, cb, cb_ctx);
|
||||
cb(dev, 0, pin_ctx);
|
||||
}
|
||||
|
||||
void
|
||||
ftl_l2p_set(struct spdk_ftl_dev *dev, uint64_t lba, ftl_addr addr)
|
||||
{
|
||||
FTL_L2P_OP(set)(dev, lba, addr);
|
||||
}
|
||||
|
||||
ftl_addr
|
||||
ftl_l2p_get(struct spdk_ftl_dev *dev, uint64_t lba)
|
||||
{
|
||||
return FTL_L2P_OP(get)(dev, lba);
|
||||
}
|
||||
|
||||
void
|
||||
ftl_l2p_clear(struct spdk_ftl_dev *dev, ftl_l2p_cb cb, void *cb_ctx)
|
||||
{
|
||||
FTL_L2P_OP(clear)(dev, cb, cb_ctx);
|
||||
}
|
||||
|
||||
void
|
||||
ftl_l2p_process(struct spdk_ftl_dev *dev)
|
||||
{
|
||||
struct ftl_l2p_pin_ctx *pin_ctx;
|
||||
|
||||
pin_ctx = TAILQ_FIRST(&dev->l2p_deferred_pins);
|
||||
if (pin_ctx) {
|
||||
TAILQ_REMOVE(&dev->l2p_deferred_pins, pin_ctx, link);
|
||||
FTL_L2P_OP(pin)(dev, pin_ctx);
|
||||
}
|
||||
|
||||
FTL_L2P_OP(process)(dev);
|
||||
}
|
||||
|
||||
bool
|
||||
ftl_l2p_is_halted(struct spdk_ftl_dev *dev)
|
||||
{
|
||||
if (!TAILQ_EMPTY(&dev->l2p_deferred_pins)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return FTL_L2P_OP(is_halted)(dev);
|
||||
}
|
||||
|
||||
void
|
||||
ftl_l2p_halt(struct spdk_ftl_dev *dev)
|
||||
{
|
||||
return FTL_L2P_OP(halt)(dev);
|
||||
}
|
||||
|
||||
void
|
||||
ftl_l2p_update_base(struct spdk_ftl_dev *dev, uint64_t lba, ftl_addr new_addr, ftl_addr old_addr)
|
||||
{
|
||||
ftl_addr current_addr;
|
||||
|
||||
/* Updating L2P for data in base device - used by compaction and GC, may be invalidated by user write.
|
||||
* Split off from updating L2P in cache due to extra edge cases for handling dirty shutdown in the cache case.
|
||||
* Also some assumptions are not the same (can't assign INVALID address for base device - trim cases are done on cache)
|
||||
*/
|
||||
assert(ftl_check_core_thread(dev));
|
||||
assert(new_addr != FTL_ADDR_INVALID);
|
||||
assert(old_addr != FTL_ADDR_INVALID);
|
||||
assert(!ftl_addr_in_nvc(dev, new_addr));
|
||||
|
||||
current_addr = ftl_l2p_get(dev, lba);
|
||||
|
||||
if (current_addr == old_addr) {
|
||||
/* DO NOT CHANGE ORDER - START (need to set L2P (and valid bits), before invalidating old ones,
|
||||
* due to dirty shutdown from shm recovery - it's ok to have too many bits set, but not ok to
|
||||
* have too many cleared) */
|
||||
ftl_l2p_set(dev, lba, new_addr);
|
||||
/* DO NOT CHANGE ORDER - END */
|
||||
} else {
|
||||
/* new addr could be set by running p2l checkpoint but in the time window between
|
||||
* p2l checkpoint completion and l2p set operation new data could be written on
|
||||
* open chunk so this address need to be invalidated */
|
||||
ftl_invalidate_addr(dev, new_addr);
|
||||
}
|
||||
|
||||
ftl_invalidate_addr(dev, old_addr);
|
||||
}
|
||||
|
||||
void
|
||||
ftl_l2p_pin_complete(struct spdk_ftl_dev *dev, int status, struct ftl_l2p_pin_ctx *pin_ctx)
|
||||
{
|
||||
if (spdk_unlikely(status == -EAGAIN)) {
|
||||
TAILQ_INSERT_TAIL(&dev->l2p_deferred_pins, pin_ctx, link);
|
||||
} else {
|
||||
pin_ctx->cb(dev, status, pin_ctx);
|
||||
}
|
||||
}
|
56
lib/ftl/ftl_l2p.h
Normal file
56
lib/ftl/ftl_l2p.h
Normal file
@ -0,0 +1,56 @@
|
||||
/* SPDX-License-Identifier: BSD-3-Clause
|
||||
* Copyright (c) Intel Corporation.
|
||||
* All rights reserved.
|
||||
*/
|
||||
|
||||
#ifndef FTL_L2P_H
|
||||
#define FTL_L2P_H
|
||||
|
||||
#include "spdk/queue.h"
|
||||
|
||||
#include "ftl_internal.h"
|
||||
|
||||
struct spdk_ftl_dev;
|
||||
struct ftl_nv_cache_chunk;
|
||||
struct ftl_rq;
|
||||
struct ftl_io;
|
||||
struct ftl_l2p_pin_ctx;
|
||||
|
||||
typedef void (*ftl_l2p_cb)(struct spdk_ftl_dev *dev, int status, void *ctx);
|
||||
typedef void (*ftl_l2p_pin_cb)(struct spdk_ftl_dev *dev, int status,
|
||||
struct ftl_l2p_pin_ctx *pin_ctx);
|
||||
|
||||
int ftl_l2p_init(struct spdk_ftl_dev *dev);
|
||||
void ftl_l2p_deinit(struct spdk_ftl_dev *dev);
|
||||
|
||||
struct ftl_l2p_pin_ctx {
|
||||
uint64_t lba;
|
||||
uint64_t count;
|
||||
ftl_l2p_pin_cb cb;
|
||||
void *cb_ctx;
|
||||
TAILQ_ENTRY(ftl_l2p_pin_ctx) link;
|
||||
};
|
||||
|
||||
void ftl_l2p_pin(struct spdk_ftl_dev *dev, uint64_t lba, uint64_t count, ftl_l2p_pin_cb cb,
|
||||
void *cb_ctx, struct ftl_l2p_pin_ctx *pin_ctx);
|
||||
void ftl_l2p_unpin(struct spdk_ftl_dev *dev, uint64_t lba, uint64_t count);
|
||||
void ftl_l2p_pin_skip(struct spdk_ftl_dev *dev, ftl_l2p_pin_cb cb, void *cb_ctx,
|
||||
struct ftl_l2p_pin_ctx *pin_ctx);
|
||||
|
||||
void ftl_l2p_set(struct spdk_ftl_dev *dev, uint64_t lba, ftl_addr addr);
|
||||
ftl_addr ftl_l2p_get(struct spdk_ftl_dev *dev, uint64_t lba);
|
||||
|
||||
void ftl_l2p_clear(struct spdk_ftl_dev *dev, ftl_l2p_cb cb, void *cb_ctx);
|
||||
void ftl_l2p_restore(struct spdk_ftl_dev *dev, ftl_l2p_cb cb, void *cb_ctx);
|
||||
void ftl_l2p_process(struct spdk_ftl_dev *dev);
|
||||
bool ftl_l2p_is_halted(struct spdk_ftl_dev *dev);
|
||||
void ftl_l2p_halt(struct spdk_ftl_dev *dev);
|
||||
|
||||
void ftl_l2p_update_cache(struct spdk_ftl_dev *dev, uint64_t lba, ftl_addr new_addr,
|
||||
ftl_addr old_addr);
|
||||
void ftl_l2p_update_base(struct spdk_ftl_dev *dev, uint64_t lba, ftl_addr new_addr,
|
||||
ftl_addr old_addr);
|
||||
|
||||
void ftl_l2p_pin_complete(struct spdk_ftl_dev *dev, int status, struct ftl_l2p_pin_ctx *pin_ctx);
|
||||
|
||||
#endif /* FTL_L2P_H */
|
167
lib/ftl/ftl_l2p_flat.c
Normal file
167
lib/ftl/ftl_l2p_flat.c
Normal file
@ -0,0 +1,167 @@
|
||||
/* SPDX-License-Identifier: BSD-3-Clause
|
||||
* Copyright (c) Intel Corporation.
|
||||
* All rights reserved.
|
||||
*/
|
||||
|
||||
#include "ftl_l2p.h"
|
||||
#include "ftl_core.h"
|
||||
#include "ftl_utils.h"
|
||||
#include "ftl_l2p_flat.h"
|
||||
#include "utils/ftl_addr_utils.h"
|
||||
|
||||
static struct ftl_md *
|
||||
get_l2p_md(struct spdk_ftl_dev *dev)
|
||||
{
|
||||
return dev->layout.md[FTL_LAYOUT_REGION_TYPE_L2P];
|
||||
}
|
||||
|
||||
struct ftl_l2p_flat {
|
||||
void *l2p;
|
||||
bool is_halted;
|
||||
};
|
||||
|
||||
void
|
||||
ftl_l2p_flat_pin(struct spdk_ftl_dev *dev, struct ftl_l2p_pin_ctx *pin_ctx)
|
||||
{
|
||||
assert(dev->num_lbas >= pin_ctx->lba + pin_ctx->count);
|
||||
|
||||
ftl_l2p_pin_complete(dev, 0, pin_ctx);
|
||||
}
|
||||
|
||||
void
|
||||
ftl_l2p_flat_unpin(struct spdk_ftl_dev *dev, uint64_t lba, uint64_t count)
|
||||
{
|
||||
assert(dev->num_lbas >= lba + count);
|
||||
}
|
||||
|
||||
void
|
||||
ftl_l2p_flat_set(struct spdk_ftl_dev *dev, uint64_t lba, ftl_addr addr)
|
||||
{
|
||||
struct ftl_l2p_flat *l2p_flat = dev->l2p;
|
||||
|
||||
assert(dev->num_lbas > lba);
|
||||
|
||||
ftl_addr_store(dev, l2p_flat->l2p, lba, addr);
|
||||
}
|
||||
|
||||
ftl_addr
|
||||
ftl_l2p_flat_get(struct spdk_ftl_dev *dev, uint64_t lba)
|
||||
{
|
||||
struct ftl_l2p_flat *l2p_flat = dev->l2p;
|
||||
|
||||
assert(dev->num_lbas > lba);
|
||||
|
||||
return ftl_addr_load(dev, l2p_flat->l2p, lba);
|
||||
}
|
||||
|
||||
static void
|
||||
md_cb(struct spdk_ftl_dev *dev, struct ftl_md *md, int status)
|
||||
{
|
||||
ftl_l2p_cb cb = md->owner.private;
|
||||
void *cb_ctx = md->owner.cb_ctx;
|
||||
|
||||
cb(dev, status, cb_ctx);
|
||||
}
|
||||
|
||||
void
|
||||
ftl_l2p_flat_clear(struct spdk_ftl_dev *dev, ftl_l2p_cb cb, void *cb_ctx)
|
||||
{
|
||||
struct ftl_l2p_flat *l2p_flat = dev->l2p;
|
||||
struct ftl_md *md;
|
||||
|
||||
memset(l2p_flat->l2p, (int)FTL_ADDR_INVALID,
|
||||
ftl_md_get_buffer_size(get_l2p_md(dev)));
|
||||
|
||||
md = get_l2p_md(dev);
|
||||
md->cb = md_cb;
|
||||
md->owner.cb_ctx = cb_ctx;
|
||||
md->owner.private = cb;
|
||||
ftl_md_persist(md);
|
||||
}
|
||||
|
||||
static int
|
||||
ftl_l2p_flat_init_dram(struct spdk_ftl_dev *dev, struct ftl_l2p_flat *l2p_flat,
|
||||
size_t l2p_size)
|
||||
{
|
||||
struct ftl_md *md = get_l2p_md(dev);
|
||||
|
||||
assert(ftl_md_get_buffer_size(md) >= l2p_size);
|
||||
|
||||
l2p_flat->l2p = ftl_md_get_buffer(md);
|
||||
if (!l2p_flat->l2p) {
|
||||
FTL_ERRLOG(dev, "Failed to allocate l2p table\n");
|
||||
return -1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int
|
||||
ftl_l2p_flat_init(struct spdk_ftl_dev *dev)
|
||||
{
|
||||
size_t l2p_size = dev->num_lbas * dev->layout.l2p.addr_size;
|
||||
struct ftl_l2p_flat *l2p_flat;
|
||||
int ret;
|
||||
|
||||
if (dev->num_lbas == 0) {
|
||||
FTL_ERRLOG(dev, "Invalid l2p table size\n");
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (dev->l2p) {
|
||||
FTL_ERRLOG(dev, "L2p table already allocated\n");
|
||||
return -1;
|
||||
}
|
||||
|
||||
l2p_flat = calloc(1, sizeof(*l2p_flat));
|
||||
if (!l2p_flat) {
|
||||
FTL_ERRLOG(dev, "Failed to allocate l2p_flat\n");
|
||||
return -1;
|
||||
}
|
||||
|
||||
ret = ftl_l2p_flat_init_dram(dev, l2p_flat, l2p_size);
|
||||
|
||||
if (ret) {
|
||||
free(l2p_flat);
|
||||
return ret;
|
||||
}
|
||||
|
||||
dev->l2p = l2p_flat;
|
||||
return 0;
|
||||
}
|
||||
|
||||
void
|
||||
ftl_l2p_flat_deinit(struct spdk_ftl_dev *dev)
|
||||
{
|
||||
struct ftl_l2p_flat *l2p_flat = dev->l2p;
|
||||
|
||||
if (!l2p_flat) {
|
||||
return;
|
||||
}
|
||||
|
||||
free(l2p_flat);
|
||||
|
||||
dev->l2p = NULL;
|
||||
}
|
||||
|
||||
void
|
||||
ftl_l2p_flat_unmap(struct spdk_ftl_dev *dev, ftl_l2p_cb cb, void *cb_ctx)
|
||||
{
|
||||
cb(dev, 0, cb_ctx);
|
||||
}
|
||||
|
||||
void
|
||||
ftl_l2p_flat_process(struct spdk_ftl_dev *dev)
|
||||
{
|
||||
}
|
||||
|
||||
bool
|
||||
ftl_l2p_flat_is_halted(struct spdk_ftl_dev *dev)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
void
|
||||
ftl_l2p_flat_halt(struct spdk_ftl_dev *dev)
|
||||
{
|
||||
}
|
21
lib/ftl/ftl_l2p_flat.h
Normal file
21
lib/ftl/ftl_l2p_flat.h
Normal file
@ -0,0 +1,21 @@
|
||||
/* SPDX-License-Identifier: BSD-3-Clause
|
||||
* Copyright (c) Intel Corporation.
|
||||
* All rights reserved.
|
||||
*/
|
||||
|
||||
#ifndef FTL_L2P_FLAT_H
|
||||
#define FTL_L2P_FLAT_H
|
||||
|
||||
int ftl_l2p_flat_init(struct spdk_ftl_dev *dev);
|
||||
void ftl_l2p_flat_deinit(struct spdk_ftl_dev *dev);
|
||||
void ftl_l2p_flat_pin(struct spdk_ftl_dev *dev, struct ftl_l2p_pin_ctx *pin_ctx);
|
||||
void ftl_l2p_flat_unpin(struct spdk_ftl_dev *dev, uint64_t lba, uint64_t count);
|
||||
ftl_addr ftl_l2p_flat_get(struct spdk_ftl_dev *dev, uint64_t lba);
|
||||
void ftl_l2p_flat_set(struct spdk_ftl_dev *dev, uint64_t lba, ftl_addr addr);
|
||||
void ftl_l2p_flat_unmap(struct spdk_ftl_dev *dev, ftl_l2p_cb cb, void *cb_ctx);
|
||||
void ftl_l2p_flat_clear(struct spdk_ftl_dev *dev, ftl_l2p_cb cb, void *cb_ctx);
|
||||
void ftl_l2p_flat_process(struct spdk_ftl_dev *dev);
|
||||
bool ftl_l2p_flat_is_halted(struct spdk_ftl_dev *dev);
|
||||
void ftl_l2p_flat_halt(struct spdk_ftl_dev *dev);
|
||||
|
||||
#endif /* FTL_L2P_FLAT_H */
|
@ -139,6 +139,20 @@ setup_layout_nvc(struct spdk_ftl_dev *dev)
|
||||
region = &layout->region[FTL_LAYOUT_REGION_TYPE_SB];
|
||||
offset += region->current.blocks;
|
||||
|
||||
/* Initialize L2P region */
|
||||
if (offset >= layout->nvc.total_blocks) {
|
||||
goto error;
|
||||
}
|
||||
region = &layout->region[FTL_LAYOUT_REGION_TYPE_L2P];
|
||||
region->type = FTL_LAYOUT_REGION_TYPE_L2P;
|
||||
region->name = "l2p";
|
||||
region->current.version = 0;
|
||||
region->prev.version = 0;
|
||||
region->current.offset = offset;
|
||||
region->current.blocks = blocks_region(layout->l2p.addr_size * dev->num_lbas);
|
||||
set_region_bdev_nvc(region, dev);
|
||||
offset += region->current.blocks;
|
||||
|
||||
if (offset >= layout->nvc.total_blocks) {
|
||||
goto error;
|
||||
}
|
||||
|
@ -20,6 +20,9 @@ enum ftl_layout_region_type {
|
||||
FTL_LAYOUT_REGION_TYPE_SB,
|
||||
/* Mirrored instance of the superblock on the base device */
|
||||
FTL_LAYOUT_REGION_TYPE_SB_BASE,
|
||||
/* If using cached L2P, this region stores the serialized instance of it */
|
||||
FTL_LAYOUT_REGION_TYPE_L2P,
|
||||
|
||||
/* User data region on the nv cache device */
|
||||
FTL_LAYOUT_REGION_TYPE_DATA_NVC,
|
||||
|
||||
|
46
lib/ftl/mngt/ftl_mngt_l2p.c
Normal file
46
lib/ftl/mngt/ftl_mngt_l2p.c
Normal file
@ -0,0 +1,46 @@
|
||||
/* SPDX-License-Identifier: BSD-3-Clause
|
||||
* Copyright (c) Intel Corporation.
|
||||
* All rights reserved.
|
||||
*/
|
||||
|
||||
#include "spdk/thread.h"
|
||||
|
||||
#include "ftl_core.h"
|
||||
#include "ftl_mngt.h"
|
||||
#include "ftl_mngt_steps.h"
|
||||
#include "ftl_l2p.h"
|
||||
|
||||
static void
|
||||
l2p_cb(struct spdk_ftl_dev *dev, int status, void *ctx)
|
||||
{
|
||||
struct ftl_mngt_process *mngt = ctx;
|
||||
|
||||
if (status) {
|
||||
ftl_mngt_fail_step(mngt);
|
||||
} else {
|
||||
ftl_mngt_next_step(mngt);
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
ftl_mngt_init_l2p(struct spdk_ftl_dev *dev, struct ftl_mngt_process *mngt)
|
||||
{
|
||||
if (ftl_l2p_init(dev)) {
|
||||
ftl_mngt_fail_step(mngt);
|
||||
} else {
|
||||
ftl_mngt_next_step(mngt);
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
ftl_mngt_deinit_l2p(struct spdk_ftl_dev *dev, struct ftl_mngt_process *mngt)
|
||||
{
|
||||
ftl_l2p_deinit(dev);
|
||||
ftl_mngt_next_step(mngt);
|
||||
}
|
||||
|
||||
void
|
||||
ftl_mngt_clear_l2p(struct spdk_ftl_dev *dev, struct ftl_mngt_process *mngt)
|
||||
{
|
||||
ftl_l2p_clear(dev, l2p_cb, mngt);
|
||||
}
|
@ -31,6 +31,10 @@ static const struct ftl_mngt_process_desc desc_shutdown = {
|
||||
.name = "Dump statistics",
|
||||
.action = ftl_mngt_dump_stats
|
||||
},
|
||||
{
|
||||
.name = "Deinitialize L2P",
|
||||
.action = ftl_mngt_deinit_l2p
|
||||
},
|
||||
{
|
||||
.name = "Rollback FTL device",
|
||||
.action = ftl_mngt_rollback_device
|
||||
|
@ -89,6 +89,16 @@ static const struct ftl_mngt_process_desc desc_startup = {
|
||||
static const struct ftl_mngt_process_desc desc_first_start = {
|
||||
.name = "FTL first start",
|
||||
.steps = {
|
||||
{
|
||||
.name = "Initialize L2P",
|
||||
.action = ftl_mngt_init_l2p,
|
||||
.cleanup = ftl_mngt_deinit_l2p
|
||||
},
|
||||
{
|
||||
.name = "Clear L2P",
|
||||
.action = ftl_mngt_clear_l2p,
|
||||
.cleanup = ftl_mngt_clear_l2p
|
||||
},
|
||||
{
|
||||
.name = "Scrub NV cache",
|
||||
.action = ftl_mngt_scrub_nv_cache,
|
||||
|
@ -36,6 +36,12 @@ void ftl_mngt_init_io_channel(struct spdk_ftl_dev *dev, struct ftl_mngt_process
|
||||
|
||||
void ftl_mngt_deinit_io_channel(struct spdk_ftl_dev *dev, struct ftl_mngt_process *mngt);
|
||||
|
||||
void ftl_mngt_init_l2p(struct spdk_ftl_dev *dev, struct ftl_mngt_process *mngt);
|
||||
|
||||
void ftl_mngt_deinit_l2p(struct spdk_ftl_dev *dev, struct ftl_mngt_process *mngt);
|
||||
|
||||
void ftl_mngt_clear_l2p(struct spdk_ftl_dev *dev, struct ftl_mngt_process *mngt);
|
||||
|
||||
void ftl_mngt_scrub_nv_cache(struct spdk_ftl_dev *dev, struct ftl_mngt_process *mngt);
|
||||
|
||||
void ftl_mngt_finalize_startup(struct spdk_ftl_dev *dev, struct ftl_mngt_process *mngt);
|
||||
|
Loading…
Reference in New Issue
Block a user