原文地址:
http://blog.chinaunix.net/uid-26009923-id-3765115.html
一. chunk的分配过程
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
-
}
1.0 yaffs_alloc_chunk
-
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;
-
}
1.2 获取blk_info结构体
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];
-
}
1.3 当分配了一个chunk之后,需要在bitmap中标记该chunk的状态为1
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信息重置为未使用状态
-
}
-
}
-
}
2.1 清除该chunk在位图中的bit
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)); //不多说,见下篇分析
-
}
2.2 擦除一个块,如果成功回收空间,不成功则标志一下
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,表示可用
-
}
2.2.1 如果该块上没有数据是有效的,就调用yaffs_erase_block把这个块擦除
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;
-
}
阅读(842) | 评论(0) | 转发(0) |