Spdk/lib/ftl/ftl_band.h

203 lines
5.3 KiB
C
Raw Normal View History

/* SPDX-License-Identifier: BSD-3-Clause
* Copyright (c) Intel Corporation.
* All rights reserved.
*/
#ifndef FTL_BAND_H
#define FTL_BAND_H
#include "spdk/stdinc.h"
#include "spdk/bit_array.h"
#include "spdk/queue.h"
#include "spdk/crc32.h"
#include "ftl_io.h"
#include "ftl_internal.h"
#include "ftl_core.h"
#define FTL_MAX_OPEN_BANDS 4
#define FTL_BAND_VERSION_0 0
#define FTL_BAND_VERSION_1 1
#define FTL_BAND_VERSION_CURRENT FTL_BAND_VERSION_1
struct spdk_ftl_dev;
struct ftl_band;
struct ftl_rq;
struct ftl_basic_rq;
enum ftl_band_state {
FTL_BAND_STATE_FREE,
FTL_BAND_STATE_PREP,
FTL_BAND_STATE_OPENING,
FTL_BAND_STATE_OPEN,
FTL_BAND_STATE_FULL,
FTL_BAND_STATE_CLOSING,
FTL_BAND_STATE_CLOSED,
FTL_BAND_STATE_MAX
};
typedef void (*ftl_band_state_change_fn)(struct ftl_band *band);
typedef void (*ftl_band_ops_cb)(struct ftl_band *band, void *ctx, bool status);
typedef void (*ftl_band_md_cb)(struct ftl_band *band, void *ctx, enum ftl_md_status status);
struct ftl_band_md {
/* Band iterator for writing */
struct {
/* Current physical address of the write pointer */
ftl_addr addr;
/* Offset from the band's start of the write pointer */
uint64_t offset;
} iter;
/* Band's state */
enum ftl_band_state state;
/* Band type set during opening */
enum ftl_band_type type;
/* Number of times band was fully written (ie. number of free -> closed state cycles) */
uint64_t wr_cnt;
/* CRC32 checksum of the associated P2L map when band is in closed state */
uint32_t p2l_map_checksum;
} __attribute__((aligned(FTL_BLOCK_SIZE)));
SPDK_STATIC_ASSERT(sizeof(struct ftl_band_md) == FTL_BLOCK_SIZE, "Incorrect metadata size");
struct ftl_band {
/* Device this band belongs to */
struct spdk_ftl_dev *dev;
struct ftl_band_md *md;
/* IO queue depth (outstanding IOs) */
uint64_t queue_depth;
/* Fields for owner of the band - compaction, or gc */
struct {
/* Callback context for the owner */
void *priv;
/* State change callback */
ftl_band_state_change_fn state_change_fn;
/* Callback for the owner */
union {
ftl_band_ops_cb ops_fn;
ftl_band_md_cb md_fn;
};
/* Reference counter */
uint64_t cnt;
} owner;
/* P2L map */
struct ftl_p2l_map p2l_map;
/* Band's index */
uint32_t id;
/* Band's NAND id - a group multiple bands may be part of the same physical band on base device
* This way the write access pattern will match the actual physical layout more closely, leading
* to lower overall write amplification factor
*/
uint32_t phys_id;
/* Band start addr */
ftl_addr start_addr;
/* End metadata start addr */
ftl_addr tail_md_addr;
/* Metadata request */
struct ftl_basic_rq metadata_rq;
/* Free/shut bands' lists
* Open bands are kept and managed directly by the writer (either GC or compaction). Each writer only
* needs to keep two bands (one currently written to, and a pre-assigned reserve band to make sure flow
* of data is always ongoing as the current one is closing).
*/
TAILQ_ENTRY(ftl_band) queue_entry;
/* For writing metadata */
struct ftl_md_io_entry_ctx md_persist_entry_ctx;
};
uint64_t ftl_band_block_offset_from_addr(struct ftl_band *band, ftl_addr addr);
ftl_addr ftl_band_addr_from_block_offset(struct ftl_band *band, uint64_t block_off);
void ftl_band_set_type(struct ftl_band *band, enum ftl_band_type type);
void ftl_band_set_state(struct ftl_band *band, enum ftl_band_state state);
ftl_addr ftl_band_next_xfer_addr(struct ftl_band *band, ftl_addr addr, size_t num_blocks);
ftl_addr ftl_band_next_addr(struct ftl_band *band, ftl_addr addr, size_t offset);
size_t ftl_band_user_blocks_left(const struct ftl_band *band, size_t offset);
struct ftl_band *ftl_band_from_addr(struct spdk_ftl_dev *dev, ftl_addr addr);
ftl_addr ftl_band_tail_md_addr(struct ftl_band *band);
int ftl_band_filled(struct ftl_band *band, size_t offset);
ftl_addr ftl_band_p2l_map_addr(struct ftl_band *band);
static inline void
ftl_band_set_owner(struct ftl_band *band,
ftl_band_state_change_fn fn,
void *priv)
{
assert(NULL == band->owner.priv);
assert(NULL == band->owner.state_change_fn);
band->owner.state_change_fn = fn;
band->owner.priv = priv;
}
static inline void
ftl_band_clear_owner(struct ftl_band *band,
ftl_band_state_change_fn fn,
void *priv)
{
assert(priv == band->owner.priv);
assert(fn == band->owner.state_change_fn);
band->owner.state_change_fn = NULL;
band->owner.priv = NULL;
}
static inline int
ftl_band_empty(const struct ftl_band *band)
{
return band->p2l_map.num_valid == 0;
}
static inline uint64_t
ftl_band_qd(const struct ftl_band *band)
{
return band->queue_depth;
}
static inline void
ftl_band_iter_init(struct ftl_band *band)
{
/* Initialize band iterator to begin state */
band->md->iter.addr = band->start_addr;
band->md->iter.offset = 0;
}
static inline void
ftl_band_iter_advance(struct ftl_band *band, uint64_t num_blocks)
{
band->md->iter.offset += num_blocks;
band->md->iter.addr = ftl_band_next_xfer_addr(band, band->md->iter.addr, num_blocks);
assert(band->md->iter.addr != FTL_ADDR_INVALID);
}
static inline void
ftl_band_iter_set(struct ftl_band *band, uint64_t num_blocks)
{
band->md->iter.offset = num_blocks;
band->md->iter.addr = ftl_band_next_xfer_addr(band, band->md->iter.addr, num_blocks);
assert(band->md->iter.addr != FTL_ADDR_INVALID);
}
#endif /* FTL_BAND_H */