|
楼主 |
发表于 2010-2-11 09:18:10
|
显示全部楼层
作者:斑点
Emai:byeyear@hotmail.com
7.文件系统对象
在yaffs2中,不管是文件还是目录或者是链接,在内存都用一个结构体yaffs_ObjectStruct来描述。我们先简要介绍一下这个结构体中的几个关键字段,然后再来看代码。在后文中提到“文件”或“文件对象”,若不加特别说明,都指广义的“文件”,既可以是文件,也可以是目录。
__u8 deleted:1; /* This should only apply to unlinked files. */
__u8 softDeleted:1; /* it has also been soft deleted */
__u8 unlinked:1; /* An unlinked file. The file should be in the unlinked directory.*/
这三个字段用于描述该文件对象在删除过程中所处的阶段。在删除文件时,首先要将文件从原目录移至一个特殊的系统目录/unlinked,以此拒绝应用程序对该文件的访问,此时将unlinked置1;然后判断该文件长度是否为0,如果为0,该文件就可以直接删除,此时将deleted置1;如果不为0,就将deleted和softDelted都置1,表明该文件数据所占据的chunk还没有释放,要留待后继处理。
struct yaffs_ObjectStruct *parent;
看名字就知道,该指针指向上层目录。
int chunkId;
每个文件在flash上都有一个文件头,存储着该文件的大小、所有者、创建修改时间等信息。chunkId就是该文件头在flash上的chunk序号。
__u32 objectId; /* the object id value */
每一个文件系统对象都被赋予一个唯一的编号,作为对象标识,也用于将该对象挂入一个散列表,加快对象的搜索速度。
yaffs_ObjectType variantType;
yaffs_ObjectVariant variant;
前者表示该对象的类型,是目录、普通文件还是链接文件。后者是一个联合体,根据对象类型的不同有不同的解释。
其余的成员变量,我们在后面结合函数一起分析。
下面我们来看相关的函数。先看一个简单的:
static yaffs_Object *yaffs_CreateFakeDirectory(yaffs_Device * dev, int number,
__u32 mode)
所谓Fake Directory,就是仅存在于内存中,用于管理目的的目录对象,比如我们上面提到的unlinked目录。这种类型的目录有一些特别的地方,如禁止改名、禁止删除等。由于对象仅存在于内存中,因此不涉及对硬件的操作,所以函数体很简单。首先通过yaffs_CreateNewObject获得一个新对象,然后对其中的一些字段初始化。先把字段初始化看一下,顺便再介绍一些字段:
renameAllowed表示是否允许改名,对于fake对象为0;
unlinkAllowed表示是否允许删除,对于fake对象同样为0;
yst_mode就是linux中的访问权限位;
chunkId是对象头所在chunk,由于fake对象不占flash存储空间,所以置0。
回过头来看yaffs_CreateNewObject:
[yaffs_CreateFakeDirectory --> yaffs_CreateNewObject]
yaffs_Object *yaffs_CreateNewObject(yaffs_Device * dev, int number,
yaffs_ObjectType type)
{
yaffs_Object *theObject;
if (number < 0) {
number = yaffs_CreateNewObjectNumber(dev);
}
theObject = yaffs_AllocateEmptyObject(dev);
前面说过,每个yaffs_Object都有一个唯一的序列号,这个序号既可以在创建对象的时候由上层函数指定,也可以由系统分配。如果 number < 0,那就表示由系统分配。序列号分配函数是 yaffs_CreateNewObjectNumber。我们就不深入到这个函数内部了,只说明一下该函数做了些什么:
系统为了方便根据对象id找到对象本身,将每个对象都通过指针hashLink挂入了一个散列表,散列函数是number % 256,所以这个散列表有256个表项。yaffs_CreateNewObjectNumber函数每次搜索10个表项,从中选取挂接链表长度最短的那一项,再根据表索引试图计算出一个和该索引上挂接对象的id号不重复的id。
分配到了id号和空闲对象后,再根据对象类型的不同作不同的处理。我们主要关心两种情况,就是对象类型分别为文件和目录的时候:
case YAFFS_OBJECT_TYPE_FILE:
theObject->variant.fileVariant.fileSize = 0;
theObject->variant.fileVariant.scannedFileSize = 0;
theObject->variant.fileVariant.shrinkSize = 0xFFFFFFFF; /* max __u32 */
theObject->variant.fileVariant.topLevel = 0;
theObject->variant.fileVariant.top = yaffs_GetTnode(dev);
break;
case YAFFS_OBJECT_TYPE_DIRECTORY:
INIT_LIST_HEAD(&theObject->variant.directoryVariant.children);
break;
fileSize很好理解;topLevel就是映射树层高,新建的文件层高为0。还要预先分配一组Tnode供该对象使用。 scannedFileSize和shrinkSize用于yaffs2初始化时的flash扫描阶段,这里先跳过。如果该对象是目录,那么所做的工作只是初始化子对象(就是该目录下的文件或子目录)双向链表指针,前后指针都指向链表头自身。
看过Fake对象创建,我们再看看普通对象的创建。按对象类型的不同,有四个函数分别用于创建普通文件、目录、设备文件、符号链接和硬链接,它们分别是:
yaffs_MknodFile;
yaffs_MknodDirectory;
yaffs_MknodSpecial;
yaffs_MknodSymLink;
yaffs_Link
这四个函数最终都调用yaffs_MknodObject来完成创建对象的工作,只是调用参数不一样。
static yaffs_Object *yaffs_MknodObject(yaffs_ObjectType type,
yaffs_Object * parent,
const YCHAR * name,
__u32 mode,
__u32 uid,
__u32 gid,
yaffs_Object * equivalentObject,
const YCHAR * aliasString, __u32 rdev)
函数参数中,前面几个都很好理解,分别是对象类型,上级目录对象,文件名,访问权限,文件所属user id和group id; equivalentObject是创建硬链接时的原始文件对象;aliasString是symLink名称;rdev是设备文件的设备号。
函数首先检查在父目录中是否已存在同名文件,然后同样调用yaffs_CreateNewObject创建新对象。参数-1表示由系统自行选择对象id。
if (in) {
in->chunkId = -1;
in->valid = 1;
in->variantType = type;
in->yst_mode = mode;
in->yst_atime = in->yst_mtime = in->yst_ctime = Y_CURRENT_TIME;
in->yst_rdev = rdev;
in->yst_uid = uid;
in->yst_gid = gid;
in->nDataChunks = 0;
yaffs_SetObjectName(in, name);
in->dirty = 1;
yaffs_AddObjectToDirectory(parent, in);
in->myDev = parent->myDev;
这里列出的代码省略了和wince相关的条件编译部分。chunkId是对象头所在chunk,现在还没有将对象写入flash,所以置为-1;该新对象暂时还没有数据,所以nDataChunks是0。in->dirty = 1表示该新对象信息还没有写入flash。然后通过yaffs_AddObjectToDirectory将新对象挂入父对象的子对象链表。接下来根据对象类型作不同处理:
switch (type) {
case YAFFS_OBJECT_TYPE_SYMLINK:
in->variant.symLinkVariant.alias =
yaffs_CloneString(aliasString);
break;
case YAFFS_OBJECT_TYPE_HARDLINK:
in->variant.hardLinkVariant.equivalentObject =
equivalentObject;
in->variant.hardLinkVariant.equivalentObjectId =
equivalentObject->objectId;
list_add(&in->hardLinks, &equivalentObject->hardLinks);
break;
case YAFFS_OBJECT_TYPE_FILE:
case YAFFS_OBJECT_TYPE_DIRECTORY:
case YAFFS_OBJECT_TYPE_SPECIAL:
case YAFFS_OBJECT_TYPE_UNKNOWN:
/* do nothing */
break;
}
对于最常用的文件对象和目录对象不做任何处理;如果是hardlink,就将新对象挂入原对象的 hardLinks链表。从这里我们可以看出,yaffs2在内存中是以链表的形式处理hardlink的。在将hardlink存储到flash上的时候,则是通过objectId将两者关联起来。Hardlink本身占用一个chunk存储对象头。
最后,通过yaffs_UpdateObjectHeader将新对象头写入flash。 |
|