文件系统的重要作用就是对文件或者文件夹的数据进行相应的管理,无论是文件数据还是文件夹里面的内容数据在文件系统看来就是一个个元数据(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的话 由系统进行回收。
} else if (tags.chunkId > 0) {
/* chunkId > 0 so it is a data chunk... */
首先要找到数据所在的Inode结构,如果没有的话就进行创建
in = yaffs_FindOrCreateObjectByNumber(dev, tags.objectId,AFFS_OBJECT_TYPE_FILE);
然后就将这个data块放到文件结构里面中区。
if (in) {
if (!yaffs_PutChunkIntoFile(in, tags.chunkId, chunk, 1))
alloc_failed = 1;
}
else {
最后,就是如果page所用的chunkIDs是0的话,他就是一个objectHeader,就存放一个文件结构的page,然后我们就根据结构进行一个object 的创建,
/* chunkId == 0, so it is an ObjectHeader.
找到文件的父目录
* Thus, we read in the object header and make the object
parent = yaffs_FindOrCreateObjectByNumber(dev, oh->parentObjectId, YAFFS_OBJECT_TYPE_DIRECTORY);
然后就是加到文件夹中区。
yaffs_AddObjectToDirectory(parent, in);
}
不管是一个文件数据,还是一个文件结构,他们加到相应的结构表之后,就可以建立一个文件系统的结构了。它们是如何被加入进去的呢,文件系统又是怎样对数据进行相应的组织的呢。下面看看如何进行的组织。
(1)查找或者创建文件结构
in = yaffs_FindOrCreateObjectByNumber(dev,tags.objectId,YAFFS_OBJECT_TYPE_FILE);
由于在tag里面保存有文件的一个inode编号,就是objectId,文件系统通过这个ID对文件结构数据进行管理。
if (number > 0)
theObject = yaffs_FindObjectByNumber(dev, number);
if (!theObject)
theObject = yaffs_CreateNewObject(dev, number, type);
return theObject;
如果没有找到相应的object 的话就进行创建,下面先看看查找的过程,
yaffs_Object *yaffs_FindObjectByNumber(yaffs_Device *dev, __u32 number)
{
原来是先进性一个hash 操作,根据number 进行hash表操作之后,然后就是逐个对于表中的数据进行挨个的查找。
int bucket = yaffs_HashFunction(number);
struct ylist_head *i;
yaffs_Object *in;
ylist_for_each(i, &dev->objectBucket[bucket].list) {
/* Look if it is in the list */
if (i) {
in = ylist_entry(i, yaffs_Object, hashLink);
if (in->objectId == number) {
/* Don't tell the VFS about this one if it is defered free */
if (in->deferedFree)
return NULL;
return in;
}
}
}
return NULL;
}
这样我们就对OBJECT在文件系统的组织形式就有个认识了 他是有一个HASH 表,然后HASH表中有个链表,保存了objectID
其中每个object 都有一个下面的结构
typedef struct {
__u32 fileSize;
__u32 scannedFileSize;
__u32 shrinkSize;
int topLevel;
yaffs_Tnode *top;
} yaffs_FileStructure;
其中上面黄色的部分就是文件的数据的表。
(2)给文件增加文件数据
static int yaffs_PutChunkIntoFile(yaffs_Object *in, int chunkInInode,int chunkInNAND, int inScan)
这个就是将data数据增加到上面的tnode 结构中区,关于tnode 的维护,在CLF上面有个帖子介绍的比较详细,在这里就不做具体的介绍了。
(3) 父目录的关系维护
yaffs_AddObjectToDirectory(parent, in);
/* Now add it */
ylist_add(&obj->siblings,&directory>variant.directoryVariant.children);
还是链表,就是object 的结构有个
typedef struct {
struct ylist_head children; /* list of child links */
struct ylist_head dirty; /* Entry for list of dirty directories */
} yaffs_DirectoryStructure;
这样就可以在父目录进行目录的阅历,还有父目录的查找。
经过了这些过程之后,文件的结构,文件夹的结构,文件之间的关系,就完全的建立了。建立了这些之后,文件系统就可以进行文件增加,遍历的操作了。由于yaffs相对来说简单,只是使用了简单的链表,而没有像其他的文件系统那样使用比较复杂的RBTree或者B-Tree等。文件的操作就是链表的操作。
这里只是对文件系统的结构进行了分析,由于yaffs2 是基于nand 的,对于平衡损耗的算法,还有垃圾的回收,特有的checkpoint 没有详细的分析。
阅读(2325) | 评论(0) | 转发(0) |