Yaffs文件系统

Yaffs文件系统

挂载流程

  1. 初始化与VFS层的接口:
    sb->s_op = &yaffs_super_ops;
    inode->i_op = &yaffs_file_inode_operations;
    inode->i_fop = &yaffs_file_operations;
  2. 初始化与驱动层的接口:
    param->write_chunk_tags_fn = nandmtd2_write_chunk_tags;
	param->read_chunk_tags_fn = nandmtd2_read_chunk_tags;
	param->bad_block_fn = nandmtd2_mark_block_bad;
	param->query_block_fn = nandmtd2_query_block;
	param->erase_fn = nandmtd_erase_block;
	param->initialise_flash_fn = nandmtd_initialise;
  1. 初始化yaffs_dev结构:
    主要在yaffs_gus_initialise函数完成,具体包含以下部分:
    初始化擦除块信息:yaffs_init_blocks
    初始化cache和buffer:yaffs_init_tmp_buffers
    初始化tnode和objs:yaffs_init_tnode_and_objs
    初始化根目录:yaffs_create_initial_dir
  2. yaffs2_checkpt_restroe流程:
    -> 基础设施搭建完毕,后面就是扫描falsh内存中建立完整的文件试图,YAFFS2首先尝试从checkpoint中恢复文件系统的信息
    -> yaffs2_rd_checkpt_open 为读出checkpoint信息做一些初始化工作,首先创建一个checkpt_buffer,初始化checkpt_block_list数组
    -> yaffs2_rd_checkpt_validity_marker读取checkpoint头部信息,并判断是否正确
    -> yaffs2_rd_checkpt_dev读取struct yaffs_checkpt_dev结构的信息,用来填充yaffs_dev结构相应的字段,以及flash上各个擦除块yaffs_block_info信息,还有chunk_bits表示flash上各个chunk位图
    -> yaffs2_rd_checkpt_validity_marker读出checkpoint尾部信息,并判断是否正确
    -> yaffs2_rd_checkpt_sum读出校验和,并和计算的比较是否一致
  3. yaffs2_scan_backwards流程:
    如果上述5个步骤都没有错误,则从checkpoint挂载成功,否则就扫描整个flash
    -> 扫描整个flash OOB信息,按照bi->seq_number顺序对block进行排序
    -> 其次从seq_number最大的block开始往seq_number减小的方向扫描
    -> 最后从physical_chunk_index大的chunk开始,并向减少的方向扫描
    -> 读取chunk的tags信息,根据tags.chunk_used判断chunk是空闲的还是被使用:根据tags.chunk_id判断是data_chunk,还是object header
    -> 如果是data chunk,分几种情况:
    a. 根据tags.obj_id查找散列表,找到object对象,则把tags.chunk_id转转成文件的偏移,拿这个偏移和文件对象的shrink_size加入到对应的tnode_tree中,否则删除该chunk:这个一般发生在正常关闭文件的情况下,也即先扫描到到object header,后扫描文件的data chunk,这种情况文件的实际大小应该由扫描碰到的第一个object header所记录的大小的决定
    b. 根据tags.obj_id查到散列表,不存在则创建新的object对象,并插入到散列表中,则把tags.chunk_id转换成文件内的偏移,拿这个偏移和文件对象的shrink_size比较,如果在文件的大小范围内则调用yaffs_put_chunk_in_file把该chunk加入到对应的tnode tree中,否则删除该chunk,这一般发生在非正常文件的情况下,也即先扫描到data chunk,后扫面到文件的object header,这种情况文件大小由扫描到的第一个data chunk决定
    -> 如果是object header,分几种情况:
    a. object header被扫描到,object散列表中并无对应的文件,那么根据tags.obj_id、tags.extra_obj_type或者tags.oject_type或者tags.obj_id、oh->type创建新的object对象,并使用object header的信息初始化object对象,并根据oh->parent_obj_id创建父object对象,把二者联系起来
    b. object header被扫面到,object散列表中已经存在对象的object对象,且对象已经有关联的object header,说明这个object head是过时,所以就直接删除该chunk

打开流程

YAFFS文件的打开主要由yaffs_iget函数完成:
根据yaffs_obj的信息填充inode:
inode->i_size = obj->variant.file_variant.file_size;
indoe->i_ino = obj->obj_id;
如果是普通文件:

    inode->i_op = &yaffs_file_inode_operations;
    inode->i_fop = &yaffs_file_operations;
    inode->i_mapping->a_ops = &yaffs_file_address_operations;

如果是目录文件:

    inode->i_op = &yaffs_dir_inode_operations;
    inode->i_fop = &yaffs_dir_operations;

读取流程

YAFFS2文件的读取主要由yaffs_readpage函数完成:根据pg->index计算文件内偏移,然后转换成logical chunk index,最后在Tnode tree中找到相应的physical chunk index,读取该chunk的数据到页缓存中
读取的过程涉及到YAFFS2内部的cache,首先检测读取的数据是边界否chunk对齐,大小是否data_bytes_per_chunk对齐,如果边界对齐就是不需要内部的cache,如果有就直接从cache读取,没有对应的cache则分配一个cache。从chunk中读取cache中,然后再从cache到页缓存中

写入流程

YAFFS2文件的写入操作主要由yaffs_file_write函数完成:根据pg->index计算文件内偏移,然后转换成logical chunk index:然后分配空闲chunk,建立logical chunk index和physical chunk index,把页缓存中的写入数据到分配的chunk,并把chunk插汝到tnode tree
写入的流程页涉及到YAFFS内存的cache,首先检测写入的数据是否边界chunk对齐,大小是否data_bytes_per_chunk对齐,如果边界对齐就不需要内部的cache直接从页缓存写入chunk中,否则再cache查找该文件是否有对应的cache,如果有就直接写入cache中,如果cache中的数据达到data_bytes_per_chunk就同步到flash;没有对应的cache则分配一个cache,chunk中读取cache中,然后再把数据写入cache中

删除流程

YAFFS2文件的删除采取软删除主要由yaffs_unlink函数完成,对于不同的文件具体划分:普通文件对应yaffs_del_file函数,目录文件对应yaffs_del_dir函数。普通文件如果对应的有数据即n_data_chunk大于0,则把文件移到unlink目录,并释放内存中tnode tree,in->deleted置1,obj_dirty置1,obj->unlinked置1,并写入一个新的object header,oh->file_szie = 0,chunk留待垃圾回收擦除;如果没有对应 的数据则把文件移到deleted目录,则删除空的tnode tree,最后释放object,并写入一个新的object header,oh->file_szie = 0。目录文件比较简单,最后释放object,并写入一个新的object header表示文件被删除

垃圾回收

  1. 回收时机
    -> 在yafffs_wr_data_obj入口调用yaffs_check_gc进行垃圾回收
    -> 在yaffs_bg_thread_fn垃圾回收线程中进行回收,该线程会定时被唤醒,根据剩余空间的多少,定时间隔会动态调整,该线程是非实时的,最后调用yaffs_check_gc进行垃圾回收
  2. 回收策略
    根据空闲擦除块的数量判断空间是否紧张,分为如下两种策略:
    ->aggressive garbage collection,比较紧急的回收,yaffs_find_gc_block找到符合条件的擦除块条件比较宽裕,具体体现以下两个指标的计算上:
   /* 表示擦除块dev->gc_page_in_use的阈值,这个阈值越大擦除块越好选择 */
    threshold = dev->param.chunks_per_block;
    /* 表示选择擦除块的范围,比较紧急的时候要搜索所有的擦除块找合适 的进行回收 */
    iterations = dev->internal_end_block - dev->internal_start_block + 1;

->“leasurely” garbage collection,非紧急的回收,yaffs_find_gc_block找到符合条件的擦除块条件比较严格,具体体现在以下两个指标的计算上:

    /* 表示找全脏的,无效chunk的块进行回收 */
    threshold = background ? (dev->gc_not_done + 2) * 2 : 0;
    /* 表示只在很小的范围内搜索这样的擦除块 */
    iterations = (dev->internal_end_block - dev->internal_start_block + 1) / 16 + 1;
  1. 回收过程
    -> 首先选择合适进行回收的擦除块,由yaffs_find_gc_block来完成,当block不包含shrink flag时,则它适合gc;如果擦除块包含shrink flag标志,则已完成chunk分配且最早被使用的block合适gc
    -> 如果该擦除块还有有效的chunk,则要将正使用的chunk挪到空闲的block上,来腾出这个比较脏的block,由yaffs_gc_process_chunk完成
    -> 当整个擦除块无有效chunk时,yaffs_block_became_dirty调用yaffs_erase_block把该擦除块擦除掉
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值