Linux内核---24.yaffs2中chunk的分配与释放

一. chunk的分配过程
1. 分配概述
fs/yaffs/yaffs_guts.c中,yaffs_alloc_chunk的过程是:
    如果当前block上没有可以分配的chunk就分配一个block, 
    如果有可用的chunk, a.在chunk的bitmap中标识一下; b,把chunk号返回
注意:这里没有Nand flash什么事.
  1. struct yaffs_dev {
  2.     int n_erased_blocks; //未分配的block数量, -1表示所有的block都己分配
  3.     int alloc_block; //当前chunk所在的block num,-1表示该block己満没有可以分配的chunk了
  4.     u32 alloc_page; //当前block上己分配的chunk数,取值范围[0-chunks_per_block]
  5.     int alloc_block_finder;    //记录着上次寻找到的未使用的block的num
  6. }
1.0 yaffs_alloc_chunk
  1. static int yaffs_alloc_chunk(struct yaffs_dev *dev, int use_reserver, struct yaffs_block_info **block_ptr)
  2. {
  3.     int ret_val;
  4.     struct yaffs_block_info *bi;
  5.     //如果当前的block没有可以分配的chunk,重新找一个block
  6.     if (dev->alloc_block < 0) {
  7.         /* Get next block to allocate off */
  8.         dev->alloc_block = yaffs_find_alloc_block(dev);                        //---> 1.1
  9.         dev->alloc_page = 0;
  10.     }
  11.     
  12.     //useReserve 表示是否使用保留空间
  13.     if (!use_reserver && !yaffs_check_alloc_available(dev, 1)) {
  14.         /* No space unless we're allowed to use the reserve. */
  15.         return -1;
  16.     }
  17.     
  18.     //
  19.     if (dev->n_erased_blocks < dev->param.n_reserved_blocks && dev->alloc_page == 0)
  20.         yaffs_trace(YAFFS_TRACE_ALLOCATE, "Allocating reserve");
  21.     
  22.     
  23.     //问题: 一个接一个顺序分配的,删除了是不是留下磁盘碎片????
  24.     //如果当前block中还有可以分配的chunk
  25.     if (dev->alloc_block >= 0) {
  26.         bi = yaffs_get_block_info(dev, dev->alloc_block);                            //---> 1.2
  27.         //alloc_page:当前block上己分配的chunk数,
  28.        //因为chunk是一个接一个顺序分配的,所以这个alloc_page也即下一个空闲的chunk
  29.        //注意: 逻辑chunk号的计算方法: 当前的block号*每个block的chunk数+当前block的alloc_page
  30.         ret_val = (dev->alloc_block * dev->param.chunks_per_block) + dev->alloc_page;
  31.         bi->pages_in_use++;
  32.         yaffs_set_chunk_bit(dev, dev->alloc_block, dev->alloc_page);                    //---> 1.3

  33.         dev->alloc_page++;            //allc_page当前block中己分配的chunk数

  34.         dev->n_free_chunks--;         //空闲的block就数少了一个

  35.         //分配了一个chunk之后,发现当前block中没有空闲的chunk了,就标记为-1
  36.         if (dev->alloc_page >= dev->param.chunks_per_block) {
  37.             bi->block_state = YAFFS_BLOCK_STATE_FULL;
  38.             dev->alloc_block = -1;
  39.         }

  40.         if (block_ptr)
  41.             *block_ptr = bi;

  42.         return ret_val; //返回逻辑chunk号
  43.     }

  44.     return -1;
  45. }

1.1 如果当前的block没有可以用于分配的chunk,就需要重新分配一个block
yaffs_alloc_chunk
    -->  yaffs_find_alloc_block
  1. static int yaffs_find_alloc_block(struct yaffs_dev *dev)
  2. {
  3.     int i;
  4.     struct yaffs_block_info *bi;
  5.     
  6.     //n_erased_blocks: 未分配的block数量, -1表示所有的block都己分配
  7.     if (dev->n_erased_blocks < 1)
  8.         return -1;    

  9.     //寻找一个空的block
  10.     //注意: 并不是"从第一个到最后一个看哪个block没有用选哪个"
  11.     //而是记录本次寻找的结果,下一次从这个结果处开始寻找
  12.     //这样就保证了块可以平均使用,而不是某些块频繁使用
  13.     for (= dev->internal_start_block; i <= dev->internal_end_block; i++) {
  14.         dev->alloc_block_finder++;
  15.         //从上一次的结果处开始寻找未使用的块
  16.         if (dev->alloc_block_finder < dev->internal_start_block
  17.          || dev->alloc_block_finder > dev->internal_end_block) {
  18.             dev->alloc_block_finder = dev->internal_start_block;
  19.         }

  20.         bi = yaffs_get_block_info(dev, dev->alloc_block_finder);
  21.         //如果标志是EMPTY,就说明找到了
  22.         if (bi->block_state == YAFFS_BLOCK_STATE_EMPTY) {
  23.             //找到之后就在block_info数组中把这一项的状态设置一下
  24.             bi->block_state = YAFFS_BLOCK_STATE_ALLOCATING;
  25.             dev->seq_number++;
  26.             bi->seq_number = dev->seq_number;
  27.             dev->n_erased_blocks--;            
  28.             return dev->alloc_block_finder;
  29.         }
  30.     }
  31.     return -1;
  32. }
1.2 获取blk_info结构体
yaffs_alloc_chunk
    --> yaffs_get_block_info
  1. static inline struct yaffs_block_info *yaffs_get_block_info(struct yaffs_dev *dev, int blk)
  2. {
  3.     //blk是chunk的num
  4.     if (blk < dev->internal_start_block || blk > dev->internal_end_block) {
  5.     }
  6.     //block_info是一个数组,size是[internal_start_block, internal_end_block]
  7.     //blk在数组中的项就是blk - dev->internal_start_block
  8.     return &dev->block_info[blk - dev->internal_start_block];
  9. }
1.3 当分配了一个chunk之后,需要在bitmap中标记该chunk的状态为1
yaffs_alloc_chunk
    --> yaffs_set_chunk_bit    

  1. yaffs_set_chunk_bit(dev, dev->alloc_block, dev->alloc_page);
  2. {
  3.     //参数: dev
  4.     // dev->alloc_block: 要分配chunk的block
  5.     // dev->alloc_page: 要分配的chunk号
  6.     //返回: 当前block在chunk_bits数组中的地址
  7.     u8 *blk_bits = yaffs_block_bits(dev, blk);
  8.     {
  9.         if (blk < dev->internal_start_block || blk > dev->internal_end_block)
  10.         ;
  11.         //yaffs_init_blocks中赋值:
  12.         //dev->chunk_bit_stride = (dev->param.chunks_per_block + 7) / 8;
  13.         return dev->chunk_bits + (dev->chunk_bit_stride * (blk - dev->internal_start_block));
  14.     }

  15.     yaffs_verify_chunk_bit_id(dev, blk, chunk);
  16.     //此处chunk: 当前block上的第几个chunk
  17.     blk_bits[chunk / 8] |= (<< (chunk & 7));
  18. }

二. chunk的释放过程
2. 释放概述

2.0  在fs/yaffs2/yaffs_guts.c中
  1. void yaffs_chunk_del(struct yaffs_dev *dev, int chunk_id, int mark_flash, int lyn)
  2. {
  3.     int block;
  4.     int page;
  5.     struct yaffs_ext_tags tags;
  6.     struct yaffs_block_info *bi;

  7.     if (chunk_id <= 0)
  8.         return;

  9.     dev->n_deletions++;
  10.     block = chunk_id / dev->param.chunks_per_block;       //将chunk_id转为block:page的形式
  11.     page = chunk_id % dev->param.chunks_per_block;

  12.     if (!yaffs_check_chunk_bit(dev, block, page))
  13.         ;

  14.     bi = yaffs_get_block_info(dev, block);                 //yaffs_block_info结构体表示了该block的信息,存于block_info数组中

  15.     yaffs2_update_oldest_dirty_seq(dev, block, bi);

  16.     if (!dev->param.is_yaffs2 && mark_flash &&
  17.      bi->block_state != YAFFS_BLOCK_STATE_COLLECTING) {
  18.         memset(&tags, 0, sizeof(tags));
  19.         tags.is_deleted = 1;
  20.         yaffs_wr_chunk_tags_nand(dev, chunk_id, NULL, &tags);
  21.         yaffs_handle_chunk_update(dev, chunk_id, &tags);
  22.     } else {
  23.         dev->n_unmarked_deletions++;
  24.     }

  25.     /* Pull out of the management area.
  26.      * If the whole block became dirty, this will kick off an erasure.
  27.      */
  28.     if (bi->block_state == YAFFS_BLOCK_STATE_ALLOCATING ||
  29.      bi->block_state == YAFFS_BLOCK_STATE_FULL ||
  30.      bi->block_state == YAFFS_BLOCK_STATE_NEEDS_SCAN ||
  31.      bi->block_state == YAFFS_BLOCK_STATE_COLLECTING) {
  32.         dev->n_free_chunks++;
  33.         yaffs_clear_chunk_bit(dev, block, page);                    //---> 2.1清除该chunk在位图中的bit           
  34.         bi->pages_in_use--;                                        //将该block上的chunk使用计数减1

  35.         if (bi->pages_in_use == 0 && !bi->has_shrink_hdr && bi->block_state != YAFFS_BLOCK_STATE_ALLOCATING &&
  36.          bi->block_state != YAFFS_BLOCK_STATE_NEEDS_SCAN) {          //如果该block上的chunk使用计数变为0,说明该block上没有分配过chunk
  37.             yaffs_block_became_dirty(dev, block);                    //---> 2.2,将该block信息重置为未使用状态
  38.         }
  39.     }
  40. }
2.1 清除该chunk在位图中的bit
yaffs_chunk_del

    --> yaffs_clear_chunk_bit
  1. void yaffs_clear_chunk_bit(struct yaffs_dev *dev, int blk, int chunk)
  2. {
  3.     u8 *blk_bits = yaffs_block_bits(dev, blk);

  4.     yaffs_verify_chunk_bit_id(dev, blk, chunk);
  5.     blk_bits[chunk / 8] &= ~(<< (chunk & 7));        //不多说,见下篇分析
  6. }
2.2 擦除一个块,如果成功回收空间,不成功则标志一下
yaffs_chunk_del
    -->  yaffs_block_became_dirty  
  1. void yaffs_block_became_dirty(struct yaffs_dev *dev, int block_no)
  2. {
  3.     struct yaffs_block_info *bi = yaffs_get_block_info(dev, block_no);
  4.     int erased_ok = 0;
  5.     int i;

  6.     /* If the block is still healthy erase it and mark as clean.
  7.      * If the block has had a data failure, then retire it.
  8.      */
  9.     yaffs2_clear_oldest_dirty_seq(dev, bi);                    //dev->oldest_dirty_seq=0, dev->oldest_dirty_block = 0;

  10.     bi->block_state = YAFFS_BLOCK_STATE_DIRTY;                 //erase and reuse 这个block

  11.     /* If this is the block being garbage collected then stop gc'ing */
  12.     if (block_no == dev->gc_block)
  13.         dev->gc_block = 0;

  14.     /* If this block is currently the best candidate for gc then drop as a candidate */
  15.     if (block_no == dev->gc_dirtiest) {
  16.         dev->gc_dirtiest = 0;
  17.         dev->gc_pages_in_use = 0;
  18.     }

  19.     if (!bi->needs_retiring) {
  20.         yaffs2_checkpt_invalidate(dev);
  21.         erased_ok = yaffs_erase_block(dev, block_no);                    //1.调用mtd的nand flash接口擦除块        
  22.     }

  23.     //检查是否擦除成功
  24.     if (erased_ok &&
  25.      ((yaffs_trace_mask & YAFFS_TRACE_ERASE) ||
  26.      !yaffs_skip_verification(dev))) {
  27.         for (= 0; i < dev->param.chunks_per_block; i++) {
  28.             if (!yaffs_check_chunk_erased(dev,
  29.                 block_no * dev->param.chunks_per_block + i)) {
  30.                 yaffs_trace(YAFFS_TRACE_ERROR,
  31.                     ">>Block %d erasure supposedly OK, but chunk %d not erased",
  32.                     block_no, i);
  33.             }
  34.         }
  35.     }
  36.     
  37.     //如果擦除不成功,悲剧了,这个块不能用了
        if (!erased_ok) {
  38.         dev->n_free_chunks -= dev->param.chunks_per_block;
  39.         yaffs_retire_block(dev, block_no);        
  40.         return;
  41.     }

  42.     bi->block_state = YAFFS_BLOCK_STATE_EMPTY;                         //block状态为空
  43.     bi->seq_number = 0;
  44.     dev->n_erased_blocks++;
  45.     bi->pages_in_use = 0;
  46.     bi->soft_del_pages = 0;
  47.     bi->has_shrink_hdr = 0;
  48.     bi->skip_erased_check = 1;    /* Clean, so no need to check */
  49.     bi->gc_prioritise = 0;
  50.     bi->has_summary=0;

  51.     yaffs_clear_chunk_bits(dev, block_no);                //将刚才擦除block的chunk位图清0,表示可用
  52. }
2.2.1  如果该块上没有数据是有效的,就调用yaffs_erase_block把这个块擦除
yaffs_chunk_del
    --> yaffs_block_became_dirty 
                                              
        -->  yaffs_erase_block  真正的擦除函数 
  1. int yaffs_erase_block(struct yaffs_dev *dev, int flash_block)
  2. {
  3.     int result;                                
  4.     flash_block -= dev->block_offset;
  5.     dev->n_erasures++;
  6.     result = dev->param.erase_fn(dev, flash_block);
  7.     return result;
  8. }



  • 0
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值