struct ftl_nv_cache_chunk_md {
	/* Current lba to write */
	uint32_t write_pointer;
	
	/* Number of blocks written */
	uint32_t blocks_written;
	
	/* Number of skipped block (case when IO size is greater than blocks left in chunk) */
	uint32_t blocks_skipped;
	
	/* Next block to be compacted */
	uint32_t read_pointer;
	
	/* Number of compacted (both valid and invalid) blocks */
	uint32_t blocks_compacted;
	
	/* Chunk state */
	enum ftl_chunk_state state;
	
	/* CRC32 checksum of the associated P2L map when chunk is in closed state */
	uint32_t p2l_map_checksum;
} __attribute__((aligned(FTL_BLOCK_SIZE)));

// 在 ftl_nv_cache_init 中被初始化
struct ftl_nv_cache_chunk {
	struct ftl_nv_cache *nv_cache;

	// 指向的是 nv_cache->md 申请的 memory buffer 区域
	struct ftl_nv_cache_chunk_md *md;
	
	/* Offset from start lba of the cache */
	// 该chunk在 nv_cache 设备的起始lba
	uint64_t offset;
	
	/* P2L map */
	struct ftl_p2l_map p2l_map;
	
	/* Metadata request */
	struct ftl_basic_rq metadata_rq;
	
	TAILQ_ENTRY(ftl_nv_cache_chunk) entry;
	
	/* This flag is used to indicate chunk is used in recovery */
	bool recovery;
	
	/* For writing metadata */
	struct ftl_md_io_entry_ctx md_persist_entry_ctx;
};


struct ftl_nv_cache {
	/* Flag indicating halt request */
	bool halt;
	
	/* Write buffer cache bdev */
	struct spdk_bdev_desc *bdev_desc;
	
	/* Persistent cache IO channel */
	struct spdk_io_channel *cache_ioch;
	
	/* Metadata pool */
	// 在 ftl_nv_cache_init 中被初始化
	// 一次申请 xfer_size(32或者zns自定的写单元大小) 个 md_size(64 B)
	struct ftl_mempool *md_pool;
	
	/* P2L map memory pool */
	// 在 ftl_nv_cache_init 中被初始化
	// 申请了 2(FTL_MAX_OPEN_CHUNKS) 个,每个大小为一个 chunk 的 blocks 数量 * l2p.addr_size(用来放chunk的 l2p 表)
	struct ftl_mempool *p2l_pool;
	
	/* Chunk md memory pool */
	// 在 ftl_nv_cache_init 中被初始化
	// 申请了 2(FTL_MAX_OPEN_CHUNKS) 个,每个大小为一个 struct ftl_nv_cache_chunk_md 的大小
	struct ftl_mempool *chunk_md_pool;
	
	/* Block Metadata size */
	uint64_t md_size;
	
	/* NV cache metadata object handle */
    // 在 ftl_nv_cache_init 中被初始化为 dev->layout.md[FTL_LAYOUT_REGION_TYPE_NVC_MD]
	struct ftl_md *md;
	
	/* Number of blocks in chunk */
	// 在 ftl_nv_cache_init 中被初始化为 dev->layout.nvc.chunk_data_blocks
	uint64_t chunk_blocks;
	
	/* Number of chunks */
	// 在 ftl_nv_cache_init 中被初始化为 dev->layout.nvc.chunk_count
	uint64_t chunk_count;
	
	/* Current processed chunk */
	struct ftl_nv_cache_chunk *chunk_current;

	// 下面3个 list 在 ftl_nv_cache_init 中被初始化
	/* Free chunks list */
	TAILQ_HEAD(, ftl_nv_cache_chunk) chunk_free_list;
	uint64_t chunk_free_count;
	
	/* Open chunks list */
	TAILQ_HEAD(, ftl_nv_cache_chunk) chunk_open_list;
	uint64_t chunk_open_count;
	
	/* Full chunks list */
	TAILQ_HEAD(, ftl_nv_cache_chunk) chunk_full_list;
	uint64_t chunk_full_count;

	// 在 ftl_nv_cache_init 被初始化,申请了 chunk_count 个 struct ftl_nv_cache_chunk 的空间
	struct ftl_nv_cache_chunk *chunks;
};