yaffs2源代码分析(经典,值得一阅)

合集下载

yaffs2文件系统实现原理分析_带书签

yaffs2文件系统实现原理分析_带书签

1 概述YAFFS (Yet Another Flash File System )文件系统是专门针对NAND flash 设计的嵌入式文件系统,目前有YAFFS 和Y AFFS2两个版本,两个版本的主要区别之一在于Y AFFS2 能够更好的支持大容量的NAND flash 芯片。

YAFFS 文件系统有些类似于JFFS/JFFS2文件系统,与之不同的是JFFS/JFFS2文件系统最初是针对NOR flash 的应用场合设计的,而NORflash 和NAND flash 本质上有较大的区别,尽管JFFS/JFFS2文件系统也能应用于NANDflash ,但由于它在内存占用和启动时间方面针对NOR 的特性做了一些取舍,所以YAFFS2对NAND flash 来说通常才是最优的选择方案。

2 相关概念分析YAFFS2之前,把NAND flash 相关概念介绍下:NAND flash 由块(block)组成,块又由页(page)构成,擦除时以块为单位,读写时以页为单位,页又包含数据区和空闲区(OOB,Out-Of-Band),而Page 在YAFFS2中被称为Chunk ,其中的数据区用来存放实际的数据,OOB 用来存放附加信息实现NAND flash 的管理。

以T8000 AXMPFUA 单板使用的NANDflash 为例,每块Block: 128 pages ,每页Page: (8K + 448) bytes ,数据区为8K ,OOB 为448bytes ,如图1所示:Plane :4096blocks128 pages(8K+448)bytes图1 NAND flash 物理结构3 数据结构struct yaffs_dev 是YAFFS2文件系统最核心的数据结构,表示Y AFFS2文件系统的超级块,它建立了整个文件系统的层次结构,并衔接VFS 层和MTD 层,与struct super_block 、struct mtd_info 的关系如图2所示:图2 yaffs_dev与super_block、mtd_info层次关系下面围绕struct yaffs_dev这个最核心的数据结构开始,分段介绍它的含义,进而引出其他重要的数据结构:■param:存储文件系统重要的一些参数,以及与MTD层的接口函数□inband_tags:标志位,默认为0,即采用OOB(out of band)方式存储tags,可以通过挂载时指定inband-tags选项改变默认值□total_bytes_per_chunk:每个chunk总的字节数□chunks_per_block:每个block总的chunk数□spare_bytes_per_chunk:每个chunk包含OOB块的字节数□start_block:第一个可以使用的block□end_block:最后一个可以使用的block□n_reserved_blocks:为GC保留的block阈值□n_caches:缓冲区的个数,YAFFS2为减少数据的碎片以及提高性能为每个文件的写入提供了cache□no_tags_ecc:标志位,默认为0,即tags中包括ECC纠错信息,可以通过内核配置改变默认值,CONFIG_YAFFS_DISABLE_TAGS_ECC□is_yaffs2:标志位,默认为0,即Y AFFS,在挂载的过程中会根据识别的mtd->writesize自动转换成YAFFS2□refresh_period:刷新周期,刷新目的主要找出最旧的处于YAFFS_BLOCK_STATE_FULL状态的block,供GC作为gc_block使用□skip_checkpt_rd:标志位,默认为0,支持读取checkpoint,提高挂载速度的一个功能可以通过挂载时指定挂载选项no-checkpoint-read、no-checkpoint修改默认值□skip_checkpt_wr:标志位,默认为0,支持写入checkpoint,提高挂载速度的一个功能可以通过挂载时指定挂载选项no-checkpoint-write、no-checkpoint修改默认值□write_chunk_tags_fn:函数指针,在挂载的文件系统的时候会被初始,NANDflash写入接口函数:param->write_chunk_tags_fn = nandmtd2_write_chunk_tags;□read_chunk_tags_fn:函数指针,在挂载的文件系统的时候会被初始,NANDflash读取接口函数:param->write_chunk_tags_fn = nandmtd2_write_chunk_tags;□erase_fn:函数指针,在挂载的文件系统的时候会被初始,NAND flash擦除block接口函数:param->erase_fn = nandmtd_erase_block;□wide_tnodes_disabled:标志位,默认值为0,采用动态位宽,通过内核配置修改可采用静态位宽CONFIG_YAFFS_DISABLE_WIDE_TNODES■os_context:指向yaffs_linux_context结构指针,该结构存储Y AFFS2运行环境,如下:□context_list:通过该字段加入到yaffs_context_list全局链表中□dev:指向Y AFFS2文件系统超级块的指针□super:指向VFS层超级块的指针□bg_thread:Y AFFS2后台垃圾回收线程的指针□bg_running:启动和停止垃圾回收线程的标志位,1:启动,0:停止□gross_lock:互斥锁,保护整个超级块关键字段的互斥访问,粒度比较大□spare_buffer:OOB块的缓冲区□search_contexts:通过该字段把所有Directory Search Context组成链表□yaffs_mtd_put_super:卸载文件系统时被调用来清理super_block□readdir_process:解决使用NFS死锁问题加入的□mount_id:每个NAND flash分区挂载YAFFS2都分配不同的ID号■driver_context:指向mtd_info结构指针,mtd_info是MTD子系统核心的数据结构,主要是对底层硬件驱动进行封装,这里不再介绍■data_bytes_per_chunk:每个chunk总的字节数,和前面提到的total_bytes_per_chunk一样■chunk_grp_bits :采用静态位宽时超过tnode_width宽度之后的位数,采用动态位宽值恒为0■chunk_grp_size:由chunk_grp_bits转化而来的大小■tnode_width:采用静态位宽默认是16,采用动态位宽是由整个NAND flash中chunk数目计算得到■tnode_mask:位宽的mask,主要用于快速获取chunk id号■tnode_size:YAFFS_NTNODES_LEVEL0节点所占用的内存大小,单位:byte■chunk_shift:主要用来计算logical chunk index以及logical chunk offset■chunk_div:作用同chunk_shift,主要用于chunk大小不是2次幂的情况■chunk_mask:作用同chunk_shift,组合起来计算logical chunk offset■is_mounted:标志位,文件系统挂载时被置位Checkpoint是为提高挂载速度而引入的功能,作用同JFFS2的EBS,以空间来换取时间,卸载时通过在NAND flash上保存文件系统超级块快照,挂载时获取快照信息可以快速还原系统的状态。

YAFFS嵌入式文件系统原理分析

YAFFS嵌入式文件系统原理分析
YAFFs还带有NAND nash芯片驱动,并为嵌入式系统提 供了直接访问文件系统的API,用户可以不使用“nux中的 MTD和VFs,直接对文件进行操作。NAND Flash大多采用 MTD+YAFFs的模式。MTD(Memory Technology Devices,内 存技术设备)是对FIash操作的接口,提供了一系列的标准函 数,将硬件驱动设计和系统程序设计分开。图1列出了嵌入式 系统的文件系统结构。
YAFFs是一种类似于JFFs/JFFs2的专门为NAND Flash 设计的嵌入式文件系统。与专为NOR Flash而设计的JFFs相 比,它减少了一些功能,因此速度更快、占用内存更少。
表1 NAND和NOR两种Flash技术比较
NAND
NOR
性能
读速度慢 写速度快 擦除速度4m8 大多数写入操作前先进行擦 除操作擦除单元更小题。当每次页被 重写时,serialNumber就增加一次,对比不同的seriaINumber就
可以找出当前的页。 chunkId非O值说明这是个数据chunk,并且标示这个
chunk在文件中的位置(除文件头外文件的第一个chunk其 chunkId就是1)。为。表示这个chunk包含的是文件头信息。
表2 chunk中字节分配
字节
用途
0..5ll 512..515 516 517
文件和文件头数据 标记 数据状态。如果超过4位是O,表示这一页是被 丢弃的 块状态
518..519 标记
520..522 523..524
chuIlk中第二个256字节数据的Ecc 标记
525..527 chunk中第一个256字节数据的Ecc
嵌入式蒸巯编程
EMBEDDED SYSTEM PROGRAMMING

深入理解yaffs2文件系统(一)

深入理解yaffs2文件系统(一)

深⼊理解yaffs2⽂件系统(⼀)深⼊理解yaffs2⽂件系统(⼀)1、Flash⽂件系统1.1、背景已经有多种flash⽂件系统(FFSs)或flash块驱动(在之上运⾏⼀个常规的FS),同时都有优点或缺点。

Flash存储器有⾮常多的限制,这⾥就不⼀⼀列举了。

已经有各种⽅法解决这些限制,以提供⼀个⽂件系统。

必须认识到,“flash”,包括NOR和NAND,各⾃有不同的限制。

很容易被专业术语“flash”误导,误以为⽤于NorFlash的⽅法也⽴即适⽤于NandFlash。

Nand块驱动⼀般采⽤FAT16作为⽂件系统,但不够健壮,也不够贴近Flash的特性。

这些块驱动通过⼀个“本地--物理”的映射层来仿真可写的、类似于磁盘扇区的块。

当使⽤FAT16时,这些⽂件系统⼯作的相当好,它们内存消耗⼩,代码尺⼨也很⼩。

但就像所有基于FAT 的系统⼀样,它们很容易损坏(如,丢失簇)。

其他的途径则是设计整个⽂件系统,不是基于块驱动,⽽且是flash友好的,这允许更多的余地来解决上述所提到的问题。

当前有两个linux⽂件系统能⾮常好的⽀持NorFLash,那就是JFFS以及它的升级版本JFFS2。

这两者都提供⽇志机制,⼤⼤的提升了健壮性,这也是嵌⼊式系统特别重要的⼀个特性。

不幸的是,它们在RAM消耗和启动时间⽅⾯都不是很好。

JFFS在flash中的每⼀个journalling⽇志节点,需要⼀个基于RAM的jffs_node结构,每⼀个节点为48字节。

JFFS2做了⼀个⼤改进,通过剪裁相关的结构体(jffs2_raw_node_ref)⽽减少到16字节。

即使如此,在512字节页⼤⼩128M的NandFlash,按平均节点⼤⼩来算,也需要250000字节约4M⼤⼩。

JFFS和JFFS2在启动时,需要扫描整个flash阵列来查找journaling节点,并决定⽂件结构。

由于NAND容量⼤、慢、连续访问、需要ECC校验,这些特性将导致不可接受的、很长的启动时间。

基于Linux的大容量Yaffs文件系统性能优化与实现

基于Linux的大容量Yaffs文件系统性能优化与实现

基于Linux的大容量Yaffs文件系统性能优化与实现刘翠玲;时兴;孙晓荣;梁明全【摘要】针对Yaffs文件系统应用在大容量存储设备时所产生挂载速度慢的问题,提出一种新的改进方法,并在Yaffs2文件系统中进行了实现。

通过在Yaffs2文件系统中增加适当的偏移量,使得在扫描挂载文件系统时减少了不必要的扫描时间,从而加快了挂载的速度。

在最新的Yaffs2文件系统当中,依据该方法修改Yaffs2源代码,同时,在Linux系统上加入了对改进后文件系统的支持。

对改进前后的性能进行分析和实验,表明了该方法的可行性。

%AimingattheproblemofslowmountspeedofYaffsfilesystemoccurredwh entobeappliedinstoragedeviceswithlarge capacity,we propose a new improved method,and implement it in Yaffs2 file system.By adding appropriate offset in Yaffss file system,the unnecessary scanning time is reduced when scanning the mounting file system,thereby the mounting speed is accelerated.In latest Yaffs2 file system,we modify the source code of Yaffs2.Meanwhile,we add the support to the modified Yaffs file systemin the Linux system,and analyse the performance before and after the modification.Experiments demonstrate the feasibility of the method.【期刊名称】《计算机应用与软件》【年(卷),期】2014(000)009【总页数】3页(P37-39)【关键词】Yaffs;文件系统;Linux;Flash【作者】刘翠玲;时兴;孙晓荣;梁明全【作者单位】北京工商大学计算机与信息工程学院北京 100048;北京工商大学计算机与信息工程学院北京 100048;北京工商大学计算机与信息工程学院北京100048;北京工商大学计算机与信息工程学院北京 100048【正文语种】中文【中图分类】TP3150 引言在科技高速发展的今天,尤其是以安卓系统为基础的一系列电子产品不断的发展,智能手机,平板电脑,智能电视,数码相机等等的一系列产品都离不开文件系统的支持。

yaffs2分析(原)

yaffs2分析(原)

yaffs2分析(原)文件系统的重要作用就是对文件或者文件夹的数据进行相应的管理,无论是文件数据还是文件夹里面的内容数据在文件系统看来就是一个个元数据(metadata)。

文件系统就是实现这些元数据的相应管理。

由于yaffs2 是一个相对比较简单的文件系统,下面通过yaffs的启动过程看看yaffs文件元数据的组织。

由于Yaffs是基于nand flash 的,由于nand所特有的一些特性,所以yaffs就有了一些自身文件系统所特有的一些特性。

如文件的结构信息是保存在spare 里面的,无论是文件夹数据还是文件数据,都是保存到spare数据的。

typedef struct {unsigned sequenceNumber;unsigned objectId;unsigned chunkId;unsigned byteCount;} yaffs_PackedTags2TagsPart;保存在spare 里面的yaffs2结构如上。

在yaffs启动时候,如果checkpoint没有响应的保存掉电时的结构的话,就需要进行一下全盘的扫描,其中的扫描主要是在yaffs_scan里面完成的,文件系统结构的创建就是主要在这个scan的过程中实现的。

static int yaffs_Scan(yaffs_Device *dev){1 首先就是要对全盘的block 块进行相应的扫描,主要就是扫描出坏的块/* Scan all the blocks to determine their state */bi = dev->blockInfo;for (blk = dev->internalStartBlock; blk <= dev->internalEndBlock; blk++) {}2 对于坏的块进行相应的标记玩之后,就是逐个对block 里面每一个page进行扫描,并建立相应的结构/* For each chunk in each block that needs scanning....*/for (c = 0; !alloc_failed && c < dev->param.nChunksPerBlock &&state == YAFFS_BLOCK_STATE_NEEDS_SCANNING; c++) {if (!tags.chunkUsed) {如果是一个未被使用的page的话由系统进行回收。

yaffs2源码分析

yaffs2源码分析

狗拿耗子YAFFS2———狗拿耗子第三篇 1、YAFFS2 的背景 YAFFS2 是 Charles Manning 开发的 NAND Flash 文件系统。

可以从 获得详细 的描述和最新的版本。

关于 Nand Flash 与 Nor Flash 的不同之处,网上有很多文章叙述,这 里不再罗嗦。

反正是在嵌入式系统中,一般是 Nor Flash 存放在 Boot 程序,Nand Flash 作为 正式的存储设备使用。

YAFFS (Yet Another Flash File System) was designed and written by Charles Manning, of Whitecliffs, New Zealand, for the company Aleph One. YAFFS is the first file system that was designed specifically for NAND flash. Yaffs1 is the first version of this file system and works on NAND chips that have 512 byte pages + 16 byte spare (OOB;Out-Of-Band) areas. These older chips also generally allow 2 or 3 write cycles per page, which YAFFS takes advantage of - i.e. dirty pages are marked by writing to a specific spare area byte. Newer NAND flash chips have larger pages, 2048 bytes + 64 bytes spare areas, and stricter write requirements. Each page within a block must be written to in sequential order, and each page must be written only once. YAFFS2 was designed to accommodate these newer chips. YAFFS2 is based on the YAFFS1 source code, with the major difference being that internal structures are not fixed to assume 512 byte sizing, and a block sequence number is placed on each written page. In this way older pages can be logically overwritten without violating the "write once" rule. YAFFS is a robust log-structured file system that holds data integrity as a high priority. A secondary YAFFS goal is high performance. YAFFS will typically outperform most alternatives. It is also designed to be portable and has been used on Linux, WinCE, pSOS, eCOS, ThreadX and various special-purpose OSes. A variant 'YAFFS/Direct' is used in situations where there is no OS, embedded OSes and bootloaders: it has the same core filesystem but simpler interfacing to the OS and NAND flash hardware. The filesystem is licensed both under the GPL and under per-product licences available from Aleph One. YAFFS1 YAFFS has no inherent formatting, an erased flash chip is formatted. It follows the smart media scheme of marking the 5th byte of the spare area for bad blocks, and ignores any blocks where the spare area byte 5 is not 0xFF. To write file data, YAFFS initially writes a whole page (chunk in YAFFS terminology) that describes the file metadata, such as timestamps, name, path, etc. The new file is assigned a unique object ID number; every data chunk within the file will contain this unique object ID within the spare area. YAFFS maintains a tree structure in RAM memory of the physical location of these1狗拿耗子chunks. When a chunk is no longer valid (the file is deleted, or parts of the file are overwritten), YAFFS marks a particular byte in the spare area of the chunk as ‘dirty’. When an entire block (32 pages) is marked as dirty, YAFFS can erase the block and reclaim the space. If free space on the device is low, YAFFS may need to choose a block that has some number of dirty pages and some number of good pages, move the good pages to a new block, mark the old pages as dirty and erase the block. The process of moving good pages & erasing blocks is called Garbage Collection. When a YAFFS system mounts a NAND flash device, it must scan the spare areas of every block to check for valid data, whereby it can then reconstitute the tree data structures. YAFFS2 YAFFS2 is similar in concept to YAFFS1, and shares much the same code; and the YAFFS2 code base supports YAFFS1 data formats through backward compatibility. The main difference is that YAFFS2 needs to jump through significant hoops to meet the "write once" requirement of modern NAND flash. YAFFS2 marks every newly written block with a sequence number that is monotonically increasing. The sequence of the chunks can be inferred from the block sequence number and the chunk offset within the block. Thereby when YAFFS2 scans the flash and detects multiple chunks that have identical ObjectIDs and ChunkNumbers, it can choose which to use by taking the greatest sequence number. For efficiency reasons YAFFS2 also introduces the concept of shrink headers. For example when a file is resized to a smaller size, YAFFS1 will mark all of the affected chunks as dirty - YAFFS2 cannot do this due to the "write once" rule. YAFFS2 instead writes a "shrink header", which indicates that a certain number of pages before that point are invalid. This lets YAFFS2 reconstruct the final state of the filesystem when the system reboots. YAFFS2 uses a more abstract definition of the NAND flash allowing it to be used with a wider variety of flash parts with different geometries, bad block handling rules etc. YAFFS2 now supports "checkpointing" which bypasses normal mount scanning, allowing very fast mount times. Mileage will vary, but mount times of c. 3 seconds for 2 GB have been reported.2狗拿耗子2、chunk 与 block K9F1208 是 64M 的 Nand Flash, 一个 chunk 包含 512byte 的 data area, 16byte 的 spare area, 与 32 个 chunk 构成了一个 block。

关于一篇yaffs2很好的文章

关于一篇yaffs2很好的文章

装置为硬碟及快闪记忆体(FlashMemory),虽然硬碟的容量相当大,但是其执行速度相当的慢、体积大且不耐震,较不适用于需要效率、体积及耐震考量的EmbeddedSystem,因为FlashMemory速度快,体积小及耐震的特性,大部份的EmbeddedSystem皆使用FlashMemory做为其内部储存装置。

如市面上最常见到的行动电话、PDA (PersonalDigitalAssistant)内部储存装置等或是数位相机所使用的记忆卡,皆使用FlashMemory。

因此该怎么操作或更有效率的使用FlashMemory,都是我们所要去关注的。

二、动机FlashMemory目前分为两种:NORFlashMemory及NANDFlashMemory,尤于NANDFlashMemory有较快的EraseTime、SmallSize及成本较低的特性下,使得NAND更适用于EmbeddedSystem。

FlashMemory是一储存装置,若要使用此储存装置,亦须要在FlashMemory上使用FileSystem。

在一般的BlockDevice(e.g.Disk)上使用的FileSystem,如:NTFS、FAT32和ext2等等,都可用于FlashMemory上,但是这些FileSystem并非专为Flash 所设计的,所以无针对Flash的特性去操作,因些需要透用FTL(FlashTranslationLayer)将其做转换的动作,如下图所示图一使用非专为Flash所设计的FileSystem(Flash-SpecificFileSystem),则需要透过FTL做转换,才能存取FlashMemory,但使用FTL会多了一个转换的过程,会浪费转换的时间,对于相当要求效率的EmbeddedSystem来说,不太适用,因此则有专为FlashMemory所设计(Flash-SpecificFileSystem)的FileSystem,如:JFFS、JFFS2和YAFFS等等。

yaffs第二篇——yaffs中的核心结构体

yaffs第二篇——yaffs中的核心结构体

一个比较大的工程,最最核心的往往是数据结构体的定义,这是我最近一段时间啃yaffs啃出来的体会,一个复杂的函数往往是因为里面包含了各类结构体,结构体成员函数之间的不断转换,因此想要理解好一个大型的软件,一定要深刻的理解它的核心结构体。

话说有一天和trio一起吃饭,trio老师谈到他看代码的习惯,说往往是先不看.c 文件,先把头文件仔细读一遍,这点真是深刻啊!我的理解核心数据就像整个代码的经络一样,别看这个程序有多少多少万行代码,它本质上就是在对这些结构体进行操作。

废话少说,我们来看一下yaffs的核心结构体。

Y affs的主要的结构体在yaffs_guts.h这个文件中,核心的接头体有:struct yaffs_DeviceStructstruct yaffs_ObjectStructStruct yaffs_ObjectHeader//Struct yaffs_blockinfoStruct yaffs_spareStruct yaffs_tags//Struct yaffs_chunkcache还有一个比较重要的结构体在yaffs_fs.h这个文件中Struct yaffsfs_Handle当然还有其他很多结构体,这里先把主要的列在这儿,我准备从物理上和逻辑上因此可以这么来说实际和nandflash的硬件相关的结构体有三个,其他的结构体都是只是为了维护yaffs的组织目录而在内存中形成的。

所以,yaffs的整个目录是可以通过遍历整个yaffs的结构,读取spare区和object headler来得到yaffs中的所有逻辑结构。

这部分工作是在yaffs_mount这个函数来实现的,这个我们以后会继续讲到。

下面我们来详细讲解每个结构体:**************************NO 1************************************* struct yaffs_DeviceStruct{//一下是nandflash的属性,起始地址,结束地址,页大小,是否使用硬件ecc,缓冲的数量等int nBytesPerChu nk; // Should be a power of 2 >= 512int nChunksPerBlock; // does not need to be a power of 2int startBlock; // Start block we're allowed to useint endBlock; // End block we're allowed to useint nReservedBlocks; // We want this tuneable so that we can reduce// reserved blocks on NOR and RAM.int useNANDECC; // Flag to decide whether or not to use NANDECC int nShortOpCaches; // If <= 0, then short op caching is disabled, else// the number of short op caches (don't use too many).void *genericDevice; // Pointer to device context// On an mtd this holds the mtd pointer.// 以下是nandflash的操作函数,这些是直接和硬件相关,需要我们根据不同的处理器进行特定的处理,包括读,写,擦除,初始化int (*writeChunkToNAND)(struct yaffs_DeviceStruct *dev,int chunkInNAND, const __u8 *data, yaffs_Spare *spare);int (*readChunkFromNAND)(struct yaffs_DeviceStruct *dev,int chunkInNAND, __u8 *data, yaffs_Spare *spare);int (*eraseBlockInNAND)(struct yaffs_DeviceStruct *dev,int blockInNAND);int (*initialiseNAND)(struct yaffs_DeviceStruct *dev);// Runtime parameters. Set up by Y AFFS.int internalStartBlock; // Internal version of startBlockint internalEndBlock; // End block we're allowed to useint blockOffset;int chunkOffset;__u16 chunkGroupBits; // 0 for devices <= 32MB. else log2(nchunks) - 16__u16 chunkGroupSize; // == 2^^chunkGroupBitsint isMounted;//以下是记录整个nandflash所有块信息的部分,在系统初始化的时候会为nandflash所有的块分配一个yaffs_blockinfo的信息结构体,它的首地址就是Blockinfoyaffs_BlockInfo *blockInfo;//chunkbits 和chunkBitmapStride是两个很有意思的东西,正是它们组成了整个nandflash的位图架构,对于一块有32页的nandflash,这里的chunkBitmapStride是4,而chunkbits是8位的,这样刚好4*8=32,也就是每一个位对应了nandflash中一个page,当然在系统挂载初始化的时候会为每一个块都分配,也就是说在首地址是chunkbits中的每一个位都对应了nandflash的一页,当然一个地址对应8页。

  1. 1、下载文档前请自行甄别文档内容的完整性,平台不提供额外的编辑、内容补充、找答案等附加服务。
  2. 2、"仅部分预览"的文档,不可在线预览部分如存在完整性等问题,可反馈申请退款(可完整预览的文档不适用该条件!)。
  3. 3、如文档侵犯您的权益,请联系客服反馈,我们会尽快为您处理(人工客服工作时间:9:00-18:30)。
4.说明 因为 yaffs2 貌似还在持续更新中,所以本文所列代码可能和读者手中的代码不完全一致。 另外,本文读者应熟悉 C 语言,熟悉 NAND Flash 的基本概念(如 block 和 page)。 Ok,步入正题。首先分析存储空间的分配。
5.NAND Flash 存储空间分配和释放 我们知道,NAND Flash 的基本擦除单位是 Block,而基本写入单位是 page。yaffs2 在分配 存储空间的时候是以 page 为单位的,不过在 yaffs2 中把基本 存储单位称为 chunk,和 page 是一样的大小,在大多数情况下和 page 是一个意思。在下文中我们使用 chunk 这个 词,以保持和 yaffs2 的源代 码一致。 我们先看存储空间的分配(在 yaffs_guts.c 中。这个文件也是 yaffs2 文件系统的核心部分):
[yaffs_AllocateChunk() => yaffs_FindBlockForAllocation()] static int yaffs_FindBlockForAllocation(yaffs_Device * dev) { int i; yaffs_BlockInfo *bi; if (dev->nErasedBlocks < 1) { /* Hoosterman we've got a problem. * Can't get space to gc */ T(YAFFS_TRACE_ERROR, (TSTR("yaffs tragedy: no more eraased blocks" TENDSTR))); return -1; } dev->nErasedBlocks 记录着器件内所有可供分配的 block 的数量。如果该值小于 1,那显 然是有问题了。不但正常的分配请求无法完成,就连垃圾收集都办不到了。 for (i = dev->internalStartBlock; i <= dev->internalEndBlock; i++) { dev->allocationBlockFinder++; if (dev->allocationBlockFinder < dev->internalStartBlock || dev->allocationBlockFinder > dev->internalEndBlock) { dev->allocationBlockFinder = dev->internalStartBlock; internalStartBlock 和 internalEndBlock 分别是 yaffs2 使用的 block 的起始序号和结束 序号。也就是说 yaffs2 文件系统不一定要占据整个 Flash,可以只占用其中的一部分。 dev->allocationBlockFinder 记录着上次分配的块的序号。如果已经分配到系统尾部,就 从头重新开始搜索可用块。 bi = yaffs_GetBlockInfo(dev, dev->allocationBlockFinder); if (bi->blockState == YAFFS_BLOCK_STATE_EMPTY) { bi->blockState = YAFFS_BLOCK_STATE_ALLOCATING; dev->sequenceNumber++;
bi->sequenceNumber = dev->sequenceNumber; dev->nErasedBlocks--; T(YAFFS_TRACE_ALLOCATE, (TSTR("Allocated block %d, seq %d, %d left" TENDSTR), dev->allocationBlockFinder, dev->sequenceNumber, dev->nErasedBlocks)); return dev->allocationBlockFinder; } yaffs_GetBlockInfo 函数获取指向 block 信息结构的指针,该函数比较简单,就不详细介 绍了。yaffs_BlockInfo 结构中的 blockState 成员描述该 block 的状态,比如空,满,已 损坏,当前分配中,等等。因为是要分配空闲块,所以块状态必须是 YAFFS_BLOCK_STATE_EMPTY,如果不是,就继续测试下一个 block。找到以后将 block 状 态修改为 YAFFS_BLOCK_STATE_ALLOCATING,表示当前正从该 block 中分配存储空间。正 常情况下,系统中只会有一个 block 处于该状 态。另外还要更新统计量 ErasedBlocks 和 sequenceNumber。这个 sequenceNumber 记录着各 block 被分配出去的先后 顺序,以后在 垃圾收集的时候会以此作为判断该 block 是否适合回收的依据。 现在让我们返回到函数 yaffs_AllocateChunk 中。yaffs_CheckSpaceForAllocation()函数 检查 Flash 上是否有足够的可用空间,通过检查后,就从当前供分配的 block 上切下一个 chunk: if (dev->allocationBlock >= 0) { bi = yaffs_GetBlockInfo(dev, dev->allocationBlock); retVal = (dev->allocationBlock * dev->nChunksPerBlock) + dev->allocationPage; bi->pagesInUse++; yaffs_SetChunkBit(dev, dev->allocationBlock, dev->allocationPage); dev->allocationPage++; dev->nFreeChunks--; /* If the block is full set the state to full */ if (dev->allocationPage >= dev->nChunksPerBlock) { bi->blockState = YAFFS_BLOCK_STATE_FULL; dev->allocationBlock = -1; } if(blockUsedPtr) *blockUsedPtr = bi; return retVal; } dev->allocationPage 记录着上次分配的 chunk 在 block 中的序号,每分配一次加 1。从这 里我们可以看出,系统在分配 chunk 的时候是从 block 的开头到结尾按序分配的,直到一 个 block 内的所有 chunk 全部分配完毕为止。retVal 是该 chunk 在整个 device 内的总序 号。PagesInUse 记录着该 block 中已分配使用的 page 的数量。
if (bi->blockState == YAFFS_BLOCK_STATE_ALLOCATING || bi->blockState == YAFFS_BLOCK_STATE_FULL || bi->blockState == YAFFS_BLOCK_STATE_NEEDS_SCANNING || bi->blockState == YAFFS_BLOCK_STATE_COLLECTING) { dev->nFreeChunks++; yaffs_ClearChunkBit(dev, block, page); bi->pagesInUse--; if (bi->pagesInUse == 0 && !bi->hasShrinkHeader && bi->blockState != YAFFS_BLOCK_STATE_ALLOCATING && bi->blockState != YAFFS_BLOCK_STATE_NEEDS_SCANNING) { yaffs_BlockBecameDirty(dev, block); } } else { /* T(("Bad news deleting chunk %d\n",chunkId)); */ } 首先要判断一下该 block 上是否确实存在着可释放的 chunk。block 不能为空,不能是坏块。
系统在设备描述结构 yaffs_Device 中维护着一张位图,该位图的每一位都代表着 Flash 上的一个 chunk 的状态。yaffs_SetChunkBit()将刚分配得到的 chunk 在位图中的对应位置 1,表明该块已被使用。更新一些统计量后,就可以返回了。
看过 chunk 分配以后,我们再来 chunk 的释放。和 chunk 分配不同的是,chunk 的 释放在大多数情况下并不释lock 擦除,所以物理介质的释放要留到垃圾收集或一个 block 上的所有 page 全部 变成空闲的时候才进行。 根据应用场合的不同,chunk 的释放方式并不唯一,分别由 yaffs_DeleteChunk 函数和 yaffs_SoftDeleteChunk 函数完 成。我们先看 yaffs_DeleteChunk:
chunk 的总数),还用这个结构维护着一组 NAND 操作函数(如读、写、删除)的指针。 整个结构体比较大,我 们会按情景的不同分别分析。useReserve 表示是否使用保留空间。 yaffs2 文件系统并不会将所有的存储空间全部用于存储文件系统数据,而要空出 部分 block 用于垃圾收集时使用。一般情况下这个参数都是 0,只有在垃圾收集时需要分配存 储空间的情况下将该参数置 1。yaffs_BlockInfo 是描述 block 属性的结构,主要由一些统 计变量组成,比如该 block 内还剩多少空闲 page 等。我们同样在具体情景中再分析这个结 构中的字段含义。 函数首先判断 dev->allocationBlock 的值是否小于 0。yaffs_Device 结构内的 allocationBlock 字段用于 记录当前从中分配 chunk(page)的那个 block 的序号。当一 个 block 内的所有 page 全部分配完毕时,就将这个字段置为-1,下次进入该函 数时就会 重新挑选空闲的 block。这里我们假定需要重新挑选空闲 block,因此进入 yaffs_FindBlockForAllocation 函数:
相关文档
最新文档