yaffs2源码学习2:chunk和block
一、Nand Flash介绍
非易失性闪速存储器Flash具有速度快、成本低、密度大的特点,被广泛应用于嵌入式系统中。Flash存储器主要有NOR和NAND两种类型。NOR型比较适合存储程序代码;NAND型则可用作大容量数据存储。
一块Nand Flash芯片被分为了很多block,而每一个block又由很多个chunk构成,每个chunk由data和spare这两个区域组成,data区域存放文件数据,spare区域存放坏块信息,ECC校验等。我们以K9F2G08X0A为例进行介绍,如图:
- K9F2G08X0A是2,112Mbit(2,214,592,512 bit)大小,共包含2048个BLOCK,每个BLOCK包含64个页,每个页包含2112个字节。
- 一个大小为2112的页由数据区域(2K)和SPARE区域(64Bytes)组成,其中SPARE区域用来存储坏块信息、ECC校验等。
- 读数据时可以按字节读取,但擦写单位最小是一个块。
- 器件中的坏块是随机分布的。出厂时坏块被标记在坏块的第一页或第二页,它们被标记为非0xFF的值。第一次使用时应扫描FLASH并记录坏块信息。
- 所有flash器件都受位交换现象的困扰。在使用中应采用错误探测/错误更正(EDC/ECC)算法确保数据可靠性。一旦发现ECC错误,应将数据所在块标记为坏块
对于数据,最基本的存储和删除单元就是chunk和block,所以这一部分我们介绍yaffs2中对于chunk和block相关操作的源码。
二、Chunk相关操作
2.1 chunk记录数据的种类
Nand Flash上共记录着三类数据,check point data、object header与file data。记录chunk状态的数据结构如下:
struct yaffs_ext_tags {
unsigned chunk_used; /* Status of the chunk: used or unused */
unsigned obj_id; /* If 0 this is not used */
unsigned chunk_id; /* If 0 this is a header, else a data chunk */
unsigned n_bytes; /* Only valid for data chunks */
/* The following stuff only has meaning when we read */
enum yaffs_ecc_result ecc_result;
unsigned block_bad;
/* YAFFS 1 stuff */
unsigned is_deleted; /* The chunk is marked deleted */
unsigned serial_number; /* Yaffs1 2-bit serial number */
/* YAFFS2 stuff */
unsigned seq_number; /* The sequence number of this block */
/* Extra info if this is an object header (YAFFS2 only) */
unsigned extra_available; /* Extra info available if not zero */
unsigned extra_parent_id; /* The parent object */
unsigned extra_is_shrink; /* Is it a shrink header? */
unsigned extra_shadows; /* Does this shadow another object? */
enum yaffs_obj_type extra_obj_type; /* What object type? */
loff_t extra_file_size; /* Length if it is a file */
unsigned extra_equiv_id; /* Equivalent object for a hard link */
};
- check point data YAFFS2按照block来分配存储空间记录check point data,即一个block要么全用于记录check point data,要么全用于记录普通数据。而chunk的tag.seq_number被复用于“记录block seq_number”,或“表示block记录着check point data”。这个复用的可能性是建立在block. seq_number的大小是在一个固定的区间内。
- object header tag.chunkId等于0,表示相应chunk的data area记录着object header,并可由tag.objectId找到相应的文件。
- file data tag.chunkId不等于0,则相应chunk的data area记录着file data,并且tag.chunkId表示该chunk在文件内的logical chunk id。此外可由tag.objectId找到相应的文件。
2.2 chunk的使用情况
在dev结构中,有个参数u8 *chunk_bits,记录着chunk的使用情况,每一个bit对应一个chunk,YAFFS2用该数据记录着chunk是否正在被使用。这信息在运行时只存在于内存中,当YAFFS2被unmout时,该数组当作check point data被记录下来,在下一次的mount时被读出并被恢复。关于某一chunk对应的bit的更改函数在文件“yaffs_bitmap.c”中,代码如下,内容比较简单,就不在详细的说明了,根据函数名也大概知道该函数做了什么工作。
static inline u8 *yaffs_block_bits(struct yaffs_dev *dev, int blk)
{
if (blk < (int)dev->internal_start_block ||
blk > (int)dev->internal_end_block) {
yaffs_trace(YAFFS_TRACE_ERROR,
"BlockBits block %d is not valid",
blk);
BUG();
}
return dev->chunk_bits +
(dev->chunk_bit_stride * (blk - dev->internal_start_block));
}
void yaffs_verify_chunk_bit_id(struct yaffs_dev *dev, int blk, int chunk)
{
if (blk < (int)dev->internal_start_block ||
blk > (int)dev->internal_end_block ||
chunk < 0 || chunk >= (int)dev->param.chunks_per_block) {
yaffs_trace(YAFFS_TRACE_ERROR,
"Chunk Id (%d:%d) invalid",
blk, chunk);
BUG();
}
}
void yaffs_clear_chunk_bits(struct yaffs_dev *dev, int blk)
{
u8 *blk_bits = yaffs_block_bits(dev, blk);
memset(blk_bits, 0, dev->chunk_bit_stride);
}
void yaffs_clear_chunk_bit(struct yaffs_dev *dev, int blk, int chunk)
{
u8 *blk_bits