enum ftl_layout_region_type {
    #ifdef SPDK_FTL_VSS_EMU
    /** VSS region for NV cache VSS emulation */
    FTL_LAYOUT_REGION_TYPE_VSS,
    #endif
    /* Superblock describing the basic FTL information */	
    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,
    /* State of chunks */
    FTL_LAYOUT_REGION_TYPE_NVC_MD,
    /* Mirrored instance of the state of chunks */
    FTL_LAYOUT_REGION_TYPE_NVC_MD_MIRROR,
    /* nv_cache设备上的用户数据区域 */
    FTL_LAYOUT_REGION_TYPE_DATA_NVC,
    
    /* base设备上的用户数据区域 */
    FTL_LAYOUT_REGION_TYPE_DATA_BASE,
    
    FTL_LAYOUT_REGION_TYPE_MAX,
};

#define FTL_LAYOUT_REGION_LAST_NVC FTL_LAYOUT_REGION_TYPE_DATA_NVC
#define FTL_LAYOUT_REGION_LAST_BASE FTL_LAYOUT_REGION_TYPE_DATA_BASE
#define FTL_LAYOUT_REGION_TYPE_FREE_BASE (UINT32_MAX - 2)
#define FTL_LAYOUT_REGION_TYPE_FREE_NVC (UINT32_MAX - 1)
#define FTL_LAYOUT_REGION_TYPE_INVALID (UINT32_MAX)

struct ftl_layout_region_descriptor {
   uint64_t version;
   
   /* 以FTL_BLOCK_SIZE为粒度的,该区域处于设备上的位置  */
   uint64_t offset;
   
   /* FTL_BLOCK_SIZE粒度的blocks的数量 */
   uint64_t blocks;
};

/* 描述设备上数据或者元数据区域的抽象 */
struct ftl_layout_region {
   const char *name;
   
   enum ftl_layout_region_type type;
   
   /* 可以对某个区域进行镜像以获得更高的耐用性 */
   // 在ftl_layout_setup中被初始化为FTL_LAYOUT_REGION_TYPE_INVALID
   enum ftl_layout_region_type mirror_type;
   
   /* 最新/上一个区域的desc */
   struct ftl_layout_region_descriptor current;
   struct ftl_layout_region_descriptor prev;
   
   /* 表示一个entry中,以FTL_BLOCK_SIZE为粒度的块数量
    * 一个元数据区域可能会被划分成多个更小的entries
    * 例如:有一个区域用来描述所有的bands,但是你可能需要能够访问其中一个的元数据
    */
   uint64_t entry_size;
   
   uint64_t num_entries;
   
   /* VSS MD 大小,为0则表示不启用VSS */
   uint64_t vss_blksz;
   
   /* 区域所属的设备 */
   struct spdk_bdev_desc *bdev_desc;
   
   /* 区域所属的channel */
   struct spdk_io_channel *ioch;
};

// 这个结构体描述了整个FTL的空间组织
struct ftl_layout {
   struct {
       // 在ftl_layout_setup中初始化,直接调用spdk的接口获取base设备的块数
       uint64_t total_blocks;
       // 在 setup_layout_nvc 中初始化,为 1GB 的 blocks 数量
       uint64_t chunk_data_blocks;
       // 在 setup_layout_nvc 中初始化,chunk元数据的大小,强行对齐成一个 FTL_BLOCK_SIZE
       uint64_t chunk_meta_size;
       // 在 setup_layout_nvc 中初始化,包含 1GiB 的数据和 2 份 nvc_chunk_md 算作一个 chunk,计算有多少个chunk
       uint64_t chunk_count;
       // 在 setup_layout_nvc 中初始化,chunk 尾部要 1GiB data blocks的l2p,计算所有chunk_data_blocks的l2p使用的blocks
       uint64_t chunk_tail_md_num_blocks;
   } nvc;
   
   struct {
       // 在ftl_layout_setup中初始化,直接调用spdk的接口获取nvc设备的块数
       uint64_t total_blocks;
   } base;
   
   /* L2P表的信息 
    * 在ftl_layout_setup中被初始化
    */
   struct {
   	/* bits粒度的地址长度 */
       // 计算是base的total_blocks+nvc的total_blocks取对数
   	uint64_t addr_length;
   	/* bytes粒度的地址大小 */
   	// 计算是根据addr_length的大小来判断:> 32 ? 8 : 4
   	uint64_t addr_size;
   	/* 在一个内存页中的LBAs的数量 */
   	// 计算是FTL_BLOCK_SIZE / layout->l2p.addr_size
   	uint64_t lbas_in_page;
   } l2p;

   /*
    * region[FTL_LAYOUT_REGION_TYPE_DATA_NVC] 和 
    * region[FTL_LAYOUT_REGION_TYPE_NVC_MD] 和 region[FTL_LAYOUT_REGION_TYPE_NVC_MD_MIRROR]
    * 在set_layout_nvc和set_region_bdev_nvc中被初始化
    * region[FTL_LAYOUT_REGION_TYPE_SB] 在 ftl_layout_setup_superblock中被初始化,放在cache设备的最前面
    * 在set_layout_nvc中会跳过superblock这部分
    * current.version和prev.version被设为0,current.offset被设为0,current.blocks被设为layout->nvc.total_blocks
    * bdev_desc 被设为 dev->cache_bdev_desc, ioch 被设为 dev->cache_ioch, vss_blksz被设为cache_md_size
    *
    * region[FTL_LAYOUT_REGION_TYPE_SB] 在 ftl_mngt_superblock_init 中被初始化
    * region[FTL_LAYOUT_REGION_TYPE_SB] 的 mirror type 是 FTL_LAYOUT_REGION_TYPE_SB_BASE
    * region[FTL_LAYOUT_REGION_TYPE_SB_BASE] 的 mirror type 是 FTL_LAYOUT_REGION_TYPE_MAX
    * super block的size是 128 KiB,初始化的时候全部在current上,super block是放在cache的最开头
    * super block mirror是放在base的最末尾
    * 
    * region[FTL_LAYOUT_REGION_TYPE_L2P] 在 set_layout_nvc 中被初始化
    * 其所用的 blocks 计算为 layout->l2p.addr_size * dev->num_lbas
    * 
    * region[FTL_LAYOUT_REGION_TYPE_DATA_BASE]在set_layout_base和set_region_bdev_btm中被初始化
    * 初始化的方式和nv_cache类似, vss_blksz被设为0
    */
   struct ftl_layout_region region[FTL_LAYOUT_REGION_TYPE_MAX];
   /* 
    * 对应区域的元数据对象
    * FTL_LAYOUT_REGION_TYPE_NVC 和 FTL_LAYOUT_REGION_TYPE_BASE 和 FTL_LAYOUT_REGION_L2P
    * 在 ftl_mngt_init_md 中由 ftl_md_create 初始化
    * FTL_LAYOUT_REGION_TYPE_SB 在 ftl_mngt_superblock_init 中被初始化
    * 
    */
   struct ftl_md *md[FTL_LAYOUT_REGION_TYPE_MAX];
};
int ftl_layout_setup(struct spdk_ftl_dev *dev);

void ftl_layout_dump(struct spdk_ftl_dev *dev);
// 要保证两个region互相不会覆盖
int ftl_validate_regions(struct spdk_ftl_dev *dev, struct ftl_layout *layout);