⚠ Switch to EXCALIDRAW VIEW in the MORE OPTIONS menu of this document. ⚠ You can decompress Drawing data with the command palette: 'Decompress current Excalidraw file'. For more info check in plugin settings under 'Saving'
Excalidraw Data
Text Elements
ftl_writer_run
close_full_bands
get_band
ftl_band_rq_write
-
修改rq的success, io.band, io.addr
-
调用 ftl_band_rq_bdev_write(rq)
-
记录 band->queue_depth, dev->stat
-
判断band是否被写满,如果写满了
就执行状态机转换
spdk_bdev_write_blocks
(base, cb: write_rq_end)
ENOMEM
- io_waite 的cb设置为ftl_band_rq_bdev_write
- spdk_bdev_queue_io_wait
这里的 rq 应该是连续的一段
write_rq_end
-
ftl_stats_bdev_io_completed:
这里会按照 io 的类型对 io 进行一次统计 -
spdk_bdev_free_io
-
ftl_p2l_ckpt_issue(rq)
rq->owner.cb(rq)
user_writer->rq_queue
rq
ftl_writer_queue_rq(rq)
compaction_process_finish_read
-
for entry in rq:
if entry is invalid:
compaction_process_invalidate_entry -
只要有一个有效的entry,就调用:
compaction_process_pin_lba
valid
invalid
ftl_l2p_pin_skip
ftl_l2p_pin
compaction_process_pin_lba_cb
compaction_process_read_entry
compaction_process_read_entry_cb
compaction_process_read
compaction_process_start
compaction_process
ftl_nv_cache_process
compactor_list
compactor_alloc
-
calloc(compator)
-
compactor->rq =
ftl_rq_new() -
compactor->rq->
owner.cb =
compaction_process_ftl_done;
for entry in rq:
update L2P table
user_writer->rq_queue
rq
ftl_writer_queue_rq(rq)
compaction_process_finish_read
-
for entry in rq:
if entry is invalid:
compaction_process_invalidate_entry -
只要有一个有效的entry,就调用:
compaction_process_pin_lba
valid
invalid
ftl_l2p_pin_skip
ftl_l2p_pin
compaction_process_pin_lba_cb
compaction_process_read_entry
compaction_process_read_entry_cb
compaction_process_read
compaction_process_start
compaction_process
ftl_nv_cache_process
compactor_list
compactor_alloc
-
calloc(compator)
-
compactor->rq =
ftl_rq_new() -
compactor->rq->
owner.cb =
compaction_process_ftl_done;
for entry in rq:
update L2P table
for rq_entry in rq
entry
ftl_io
tfl->wr_sq
user io
compaction io
update nvc l2p
update base l2p
new ftl_io
io->seq_id = ftl_get_next_seq_id
ftl_rq
struct spdk_ftl_dev *dev;
TAILQ_ENTRY(ftl_rq) qentry;
/* Number of block within the request */
uint64_t num_blocks;
/* Extended metadata for IO. Its size is io_md_size * num_blocks */
void *io_md;
/* Size of extended metadata size for one entry */
uint64_t io_md_size;
/* Payload for IO */
void *io_payload;
/* Request result status */
bool success;
/* Fields for owner of this request /
struct {
/ End request callback */
void (*cb)(struct ftl_rq *rq);
/* IO error request callback */
void (*error)(struct ftl_rq *rq, struct ftl_band *band,
uint64_t idx, uint64_t count);
/* Owner context */
void *priv;
/* This is compaction IO */
bool compaction;
} owner;
/* Iterator fields for processing state of the request */
struct {
uint32_t idx;
uint32_t count;
/* Queue depth on this request */
uint32_t qd;
uint32_t remaining;
int status;
} iter;
/* Private fields for issuing IO /
struct {
/ Request physical address, on IO completion set for append device */
ftl_addr addr;
/* Band to which IO is issued */
struct ftl_band *band;
struct spdk_bdev_io_wait_entry bdev_io_wait;
} io;
/* For writing P2L metadata */
struct ftl_md_io_entry_ctx md_persist_entry_ctx;
/* 一个entry是一个block,entry是不连续的,甚至可以跨chunk */
struct ftl_rq_entry entries[];
ftl_rq_new: 初始化为dev->xfer_size(4096/(8+8))=256
ftl_rq
num_blocks
entry
MEMORY
ftl_rq_new: 以DMA方式在内存中申请FTL_BLOCK_SIZE * 256的空间
ftl_rq_new: 初始化为nv_cache.md_size(64B)
ftl_rq_new: 以DMA方式在内存中申请io_md_size * 256的空间
/* Data payload of single entry (block) */
void *io_payload;
void *io_md;
/*
* Physical address of block described by ftl_rq_entry.
* Valid after write command is completed (due to potential append reordering)
*/
ftl_addr addr;
/* Logical block address */
uint64_t lba;
/* Sequence id of original chunk where this user data was written to */
uint64_t seq_id;
/* Index of this entry within FTL request */
const uint64_t index;
struct {
void *priv;
} owner;
/* If request issued in iterative way, it contains IO information */
struct {
struct ftl_band *band;
} io;
/* For l2p pinning */
struct ftl_l2p_pin_ctx l2p_pin_ctx;
struct {
uint64_t offset_blocks;
uint64_t num_blocks;
struct spdk_bdev_io_wait_entry wait_entry;
} bdev_io;
ftl_rq_entry
ftl_rq_new: 初始化为该ftl_rq的第几个entry
ftl_rq_new: 初始化为FTL_ADDR_INVALID
ftl_rq_new: 初始化为FTL_LBA_INVALID
ftl_rq_new: 初始化为ftl_rq申请到的io_payload该entry对应的位置
ftl_rq_new: 初始化为0
ftl_rq_new: 初始化为ftl_rq申请到的io_md该entry对应的位置
compactor_alloc: 初始化为该rq所属的compactor
compactor_alloc: 初始化为compaction_process_ftl_done
compactor_alloc: 通过compaction_process_invalidate_entry设置为NULL
is_compaction_required?
compaction_entry_read_pos
for every entry:
compaction_process_pad: 如果没有需要compaction的chunk,
就把本次rq后面的entry全部设为无效
get_chunk_for_compaction
compaction_chunk_read_pos: 找到第一个valid的block
full Chunk(To be compacted)
...
block
tail md
(l2p)
invalid
valid
skip
write_pointer
read_pointer
compaction_entry_read_pos: 赋值为找到的第一个有效的block在nvc上的addr
compaction_entry_read_pos: 赋值为回收的有效block所在的chunk
compaction_process_start: 初始化为成功获取到回收有效数据地址的entry的个数
compaction_process_start
compaction_process_read: 初始化为rq->iter.count
compaction_process_read: 初始化为 1
compaction_process_read: 初始化为对应的addr在nvc上的offset(ftl_addr_to_nvc_offset)
compaction_process_read: 依次检查连续的entry,如果addr上连续,则num_blocks++,合并entry为一个io去读
compaction_process_read_entry_cb: 减去成功读上来的blocks数
compaction_process_pin_lba: 减到0之后在pin_lba里又重新赋值为count
compaction_process_pin_lba: 初始化为0
ftl_l2p_pin_skip: 初始化为INVALID / ftl_l2p_pin: 初始化为该entry读上来的block的lba/count=1/cb=compaction_process_pin_lba_cb
compaction_process_pin_lba_cb: 每次减小1直到为0
compaction_process_finish_read: 如果entry对应的addr和目前在内存中L2P表的读上来的lba对应的addr匹配,就赋值