一. chunk的分配过程
1. 分配概述
fs/yaffs/yaffs_guts.c中,yaffs_alloc_chunk的过程是:
如果当前block上没有可以分配的chunk就分配一个block,
如果有可用的chunk, a.在chunk的bitmap中标识一下; b,把chunk号返回
注意:这里没有Nand flash什么事.
1.0 yaffs_alloc_chunk
1.1 如果当前的block没有可以用于分配的chunk,就需要重新分配一个block
yaffs_alloc_chunk
--> yaffs_find_alloc_block
1.2 获取blk_info结构体
yaffs_alloc_chunk
--> yaffs_get_block_info
1.3 当分配了一个chunk之后,需要在bitmap中标记该chunk的状态为1
yaffs_alloc_chunk
--> yaffs_set_chunk_bit
二. chunk的释放过程
2. 释放概述
2.0 在fs/yaffs2/yaffs_guts.c中
2.1 清除该chunk在位图中的bit
yaffs_chunk_del
--> yaffs_clear_chunk_bit
2.2 擦除一个块,如果成功回收空间,不成功则标志一下
yaffs_chunk_del
--> yaffs_block_became_dirty
2.2.1
如果该块上没有数据是有效的,就调用yaffs_erase_block把这个块擦除
yaffs_chunk_del
--> yaffs_block_became_dirty
--> yaffs_erase_block 真正的擦除函数
1. 分配概述
fs/yaffs/yaffs_guts.c中,yaffs_alloc_chunk的过程是:
如果当前block上没有可以分配的chunk就分配一个block,
如果有可用的chunk, a.在chunk的bitmap中标识一下; b,把chunk号返回
注意:这里没有Nand flash什么事.
- struct yaffs_dev {
- int n_erased_blocks; //未分配的block数量, -1表示所有的block都己分配
- int alloc_block; //当前chunk所在的block num,-1表示该block己満没有可以分配的chunk了
- u32 alloc_page; //当前block上己分配的chunk数,取值范围[0-chunks_per_block]
- int alloc_block_finder; //记录着上次寻找到的未使用的block的num
- }
- static int yaffs_alloc_chunk(struct yaffs_dev *dev, int use_reserver, struct yaffs_block_info **block_ptr)
- {
- int ret_val;
- struct yaffs_block_info *bi;
- //如果当前的block没有可以分配的chunk,重新找一个block
- if (dev->alloc_block < 0) {
- /* Get next block to allocate off */
- dev->alloc_block = yaffs_find_alloc_block(dev); //---> 1.1
- dev->alloc_page = 0;
- }
-
- //useReserve 表示是否使用保留空间
- if (!use_reserver && !yaffs_check_alloc_available(dev, 1)) {
- /* No space unless we're allowed to use the reserve. */
- return -1;
- }
-
- //
- if (dev->n_erased_blocks < dev->param.n_reserved_blocks && dev->alloc_page == 0)
- yaffs_trace(YAFFS_TRACE_ALLOCATE, "Allocating reserve");
-
-
- //问题: 一个接一个顺序分配的,删除了是不是留下磁盘碎片????
- //如果当前block中还有可以分配的chunk
- if (dev->alloc_block >= 0) {
- bi = yaffs_get_block_info(dev, dev->alloc_block); //---> 1.2
- //alloc_page:当前block上己分配的chunk数,
- //因为chunk是一个接一个顺序分配的,所以这个alloc_page也即下一个空闲的chunk
- //注意: 逻辑chunk号的计算方法: 当前的block号*每个block的chunk数+当前block的alloc_page
- ret_val = (dev->alloc_block * dev->param.chunks_per_block) + dev->alloc_page;
- bi->pages_in_use++;
- yaffs_set_chunk_bit(dev, dev->alloc_block, dev->alloc_page); //---> 1.3
-
- dev->alloc_page++; //allc_page当前block中己分配的chunk数
-
- dev->n_free_chunks--; //空闲的block就数少了一个
-
- //分配了一个chunk之后,发现当前block中没有空闲的chunk了,就标记为-1
- if (dev->alloc_page >= dev->param.chunks_per_block) {
- bi->block_state = YAFFS_BLOCK_STATE_FULL;
- dev->alloc_block = -1;
- }
-
- if (block_ptr)
- *block_ptr = bi;
-
- return ret_val; //返回逻辑chunk号
- }
-
- return -1;
- }
1.1 如果当前的block没有可以用于分配的chunk,就需要重新分配一个block
yaffs_alloc_chunk
--> yaffs_find_alloc_block
- static int yaffs_find_alloc_block(struct yaffs_dev *dev)
- {
- int i;
- struct yaffs_block_info *bi;
-
- //n_erased_blocks: 未分配的block数量, -1表示所有的block都己分配
- if (dev->n_erased_blocks < 1)
- return -1;
-
- //寻找一个空的block
- //注意: 并不是"从第一个到最后一个看哪个block没有用选哪个"
- //而是记录本次寻找的结果,下一次从这个结果处开始寻找
- //这样就保证了块可以平均使用,而不是某些块频繁使用
- for (i = dev->internal_start_block; i <= dev->internal_end_block; i++) {
- dev->alloc_block_finder++;
- //从上一次的结果处开始寻找未使用的块
- if (dev->alloc_block_finder < dev->internal_start_block
- || dev->alloc_block_finder > dev->internal_end_block) {
- dev->alloc_block_finder = dev->internal_start_block;
- }
-
- bi = yaffs_get_block_info(dev, dev->alloc_block_finder);
- //如果标志是EMPTY,就说明找到了
- if (bi->block_state == YAFFS_BLOCK_STATE_EMPTY) {
- //找到之后就在block_info数组中把这一项的状态设置一下
- bi->block_state = YAFFS_BLOCK_STATE_ALLOCATING;
- dev->seq_number++;
- bi->seq_number = dev->seq_number;
- dev->n_erased_blocks--;
- return dev->alloc_block_finder;
- }
- }
- return -1;
- }
yaffs_alloc_chunk
--> yaffs_get_block_info
- static inline struct yaffs_block_info *yaffs_get_block_info(struct yaffs_dev *dev, int blk)
- {
- //blk是chunk的num
- if (blk < dev->internal_start_block || blk > dev->internal_end_block) {
- }
- //block_info是一个数组,size是[internal_start_block, internal_end_block]
- //blk在数组中的项就是blk - dev->internal_start_block
- return &dev->block_info[blk - dev->internal_start_block];
- }
yaffs_alloc_chunk
--> yaffs_set_chunk_bit
- yaffs_set_chunk_bit(dev, dev->alloc_block, dev->alloc_page);
- {
- //参数: dev
- // dev->alloc_block: 要分配chunk的block
- // dev->alloc_page: 要分配的chunk号
- //返回: 当前block在chunk_bits数组中的地址
- u8 *blk_bits = yaffs_block_bits(dev, blk);
- {
- if (blk < dev->internal_start_block || blk > dev->internal_end_block)
- ;
- //yaffs_init_blocks中赋值:
- //dev->chunk_bit_stride = (dev->param.chunks_per_block + 7) / 8;
- return dev->chunk_bits + (dev->chunk_bit_stride * (blk - dev->internal_start_block));
- }
-
- yaffs_verify_chunk_bit_id(dev, blk, chunk);
- //此处chunk: 当前block上的第几个chunk
- blk_bits[chunk / 8] |= (1 << (chunk & 7));
- }
二. chunk的释放过程
2. 释放概述
2.0 在fs/yaffs2/yaffs_guts.c中
- void yaffs_chunk_del(struct yaffs_dev *dev, int chunk_id, int mark_flash, int lyn)
- {
- int block;
- int page;
- struct yaffs_ext_tags tags;
- struct yaffs_block_info *bi;
-
- if (chunk_id <= 0)
- return;
-
- dev->n_deletions++;
- block = chunk_id / dev->param.chunks_per_block; //将chunk_id转为block:page的形式
- page = chunk_id % dev->param.chunks_per_block;
-
- if (!yaffs_check_chunk_bit(dev, block, page))
- ;
-
- bi = yaffs_get_block_info(dev, block); //yaffs_block_info结构体表示了该block的信息,存于block_info数组中
-
- yaffs2_update_oldest_dirty_seq(dev, block, bi);
-
- if (!dev->param.is_yaffs2 && mark_flash &&
- bi->block_state != YAFFS_BLOCK_STATE_COLLECTING) {
- memset(&tags, 0, sizeof(tags));
- tags.is_deleted = 1;
- yaffs_wr_chunk_tags_nand(dev, chunk_id, NULL, &tags);
- yaffs_handle_chunk_update(dev, chunk_id, &tags);
- } else {
- dev->n_unmarked_deletions++;
- }
-
- /* Pull out of the management area.
- * If the whole block became dirty, this will kick off an erasure.
- */
- if (bi->block_state == YAFFS_BLOCK_STATE_ALLOCATING ||
- bi->block_state == YAFFS_BLOCK_STATE_FULL ||
- bi->block_state == YAFFS_BLOCK_STATE_NEEDS_SCAN ||
- bi->block_state == YAFFS_BLOCK_STATE_COLLECTING) {
- dev->n_free_chunks++;
- yaffs_clear_chunk_bit(dev, block, page); //---> 2.1清除该chunk在位图中的bit
- bi->pages_in_use--; //将该block上的chunk使用计数减1
-
- if (bi->pages_in_use == 0 && !bi->has_shrink_hdr && bi->block_state != YAFFS_BLOCK_STATE_ALLOCATING &&
- bi->block_state != YAFFS_BLOCK_STATE_NEEDS_SCAN) { //如果该block上的chunk使用计数变为0,说明该block上没有分配过chunk
- yaffs_block_became_dirty(dev, block); //---> 2.2,将该block信息重置为未使用状态
- }
- }
- }
yaffs_chunk_del
--> yaffs_clear_chunk_bit
- void yaffs_clear_chunk_bit(struct yaffs_dev *dev, int blk, int chunk)
- {
- u8 *blk_bits = yaffs_block_bits(dev, blk);
-
- yaffs_verify_chunk_bit_id(dev, blk, chunk);
- blk_bits[chunk / 8] &= ~(1 << (chunk & 7)); //不多说,见下篇分析
- }
yaffs_chunk_del
--> yaffs_block_became_dirty
- void yaffs_block_became_dirty(struct yaffs_dev *dev, int block_no)
- {
- struct yaffs_block_info *bi = yaffs_get_block_info(dev, block_no);
- int erased_ok = 0;
- int i;
-
- /* If the block is still healthy erase it and mark as clean.
- * If the block has had a data failure, then retire it.
- */
- yaffs2_clear_oldest_dirty_seq(dev, bi); //dev->oldest_dirty_seq=0, dev->oldest_dirty_block = 0;
-
- bi->block_state = YAFFS_BLOCK_STATE_DIRTY; //erase and reuse 这个block
-
- /* If this is the block being garbage collected then stop gc'ing */
- if (block_no == dev->gc_block)
- dev->gc_block = 0;
-
- /* If this block is currently the best candidate for gc then drop as a candidate */
- if (block_no == dev->gc_dirtiest) {
- dev->gc_dirtiest = 0;
- dev->gc_pages_in_use = 0;
- }
-
- if (!bi->needs_retiring) {
- yaffs2_checkpt_invalidate(dev);
- erased_ok = yaffs_erase_block(dev, block_no); //1.调用mtd的nand flash接口擦除块
- }
-
- //检查是否擦除成功
- if (erased_ok &&
- ((yaffs_trace_mask & YAFFS_TRACE_ERASE) ||
- !yaffs_skip_verification(dev))) {
- for (i = 0; i < dev->param.chunks_per_block; i++) {
- if (!yaffs_check_chunk_erased(dev,
- block_no * dev->param.chunks_per_block + i)) {
- yaffs_trace(YAFFS_TRACE_ERROR,
- ">>Block %d erasure supposedly OK, but chunk %d not erased",
- block_no, i);
- }
- }
- }
-
- //如果擦除不成功,悲剧了,这个块不能用了
if (!erased_ok) {
- dev->n_free_chunks -= dev->param.chunks_per_block;
- yaffs_retire_block(dev, block_no);
- return;
- }
-
- bi->block_state = YAFFS_BLOCK_STATE_EMPTY; //block状态为空
- bi->seq_number = 0;
- dev->n_erased_blocks++;
- bi->pages_in_use = 0;
- bi->soft_del_pages = 0;
- bi->has_shrink_hdr = 0;
- bi->skip_erased_check = 1; /* Clean, so no need to check */
- bi->gc_prioritise = 0;
- bi->has_summary=0;
-
- yaffs_clear_chunk_bits(dev, block_no); //将刚才擦除block的chunk位图清0,表示可用
- }
yaffs_chunk_del
--> yaffs_block_became_dirty
--> yaffs_erase_block 真正的擦除函数
- int yaffs_erase_block(struct yaffs_dev *dev, int flash_block)
- {
- int result;
- flash_block -= dev->block_offset;
- dev->n_erasures++;
- result = dev->param.erase_fn(dev, flash_block);
- return result;
- }