文章详情

  • 游戏榜单
  • 软件榜单
关闭导航
热搜榜
热门下载
热门标签
php爱好者> php文档>YAFFS Development Notes (read notes)

YAFFS Development Notes (read notes)

时间:2009-04-03  来源:hylpro

2009.3.26

YAFFS Development Notes


Yaffs可以编译成内核模块,开发过程可以用RAM模拟NAND, 或者编译成应用程序测试yaffs_guts.YAFFS对MTD的接口叫 yaffs, 到RAM的接口叫yaffsram. 编译使用步骤如下:

  1. 修改Makefile把KERNELDIR改成你的内核目录.

  2.  make clean; make

  3. 加载模块sudo /sbin/insmod yaffs.o .

  4. 创建安装点 mkdir /mnt/y

  5. 安装模拟版本:mount -t yaffsram none /mnt/y

  6. 安装MTD版本:mount -t yaffs /dev/mtd0 /mnt/y


YAFFS Data structures

都在yaffs_guts.h, 主要结构:

  • yaffs_Object: 代表文件,目录,符号连接或者hardlink. yaffs_Objects 包含对应的NAND内数据yaffs_ObjectHeader. 其中和目录相关部分如下:

    • parent : 父yaffs_Object

    • siblings: 同目录的yaffs_Object

    • children: 仅对目录有效, 指向本目录的children链表头.
  • yaffs_Tnode: 用以搜索一个文件内的chunkID, 类似ext2. Tnodes 固定为32 bytes; Level 0(tree的最底层) 是16个2-byte 的索引, 其他level是8个4-byte的指针指向其他tnodes.

  • yaffs_Device: 基本是VFS superblock. 存储用于访问NAND的MTD数据以及MTD函数指针.


Tnodes , Objects 会批量分配然后存储于有一个free list以便高效率重用. 下图是YAFFs在文件系统所处地位.



yaffs_Object

struct yaffs_ObjectStruct

{

     __u8 fake:1; // A fake object has no presence on NAND.

     __u8 renameAllowed:1; // Are we allowed to rename it?

     __u8 unlinkAllowed:1; // Are we allowed to unlink it?

     __u8 dirty:1; // the object needs to be written to flash

     __u8 valid:1; // When the file system is being loaded up, this object might be created before

                     the data  is available (ie. file data records appear before the header).

     __u8 serial; // serial number of chunk in NAND. Store here so we don't have to read back the

                     old one to update.

     __u16 sum; // sum of the name to speed searching

     struct yaffs_DeviceStruct *myDev; // The device I'm on

     struct list_head hashLink; // list of objects in this hash bucket


     struct list_head hardLinks; // all the equivalent hard linked objects live on this list


     // directory structure stuff

     struct yaffs_ObjectStruct *parent; //my parent directory

     struct list_head siblings; // siblings in a directory also used for linking up the free list


     // Where's my data in NAND?

     int chunkId; // where it lives

     __u32 objectId; // the object id value

     __u32 st_mode; // protection

     __u32 st_uid; // user ID of owner

     __u32 st_gid; // group ID of owner

     __u32 st_atime; // time of last access

     __u32 st_mtime; // time of last modification

     __u32 st_ctime; // time of last change


     yaffs_ObjectType variantType;

     yaffs_ObjectVariant variant;

};



fake, renameAllowed, unlinkAllowed 是处理"fake"类型的objects 使用的: fake的是指不在NAND上实际存在的obj, YAFFS只有root 和lost+found 是这种fake类型, 都不能重命名或者unlinked.


有四个变种yaffs_Object:

Files : 文件大小和tnode tree.

Directories: 一个children obj的列表.

Symlinks: 指向一个路径字符串.

Hardlinks: hold information to identify the equivalent object.


File structure (tnodes)

一个分层索引,用于track所有属于此文件的chunkID. (图遗失,但不难理解..)


  • .... 最底层的tnode包含16个 __u16s 的page id(chunkID)..

  • .... 否则就是8 指向底层tnodes的32bit指针.


文件创建时, 只有一个最低层的tnode, 随着文件扩张, 超过一个tnode容量时,就分配另一个tnode,同时一个internal node 也加入进来指向这两个tnodes. 遍历tnode树也很简单: 每个中间层的tnode使用3bit的page id索引(page id为文件内偏移). 最低层, 即level 0, 用4bits.  比如找文件偏移为page 0x235的chunkID: 0x235 就是0000001000110101, 分割: 000.000.100.011.0101, 参考下表:

Level                           Bits                                Selected value

 

3 or more if they exist

>= 10

Zero

2

9 to 7

100 binary = 4

1

6 to 4

011 binary = 3

0

3 to 0

0101 binary = 5


 

tnode 的消耗量: 16M的文件系统约要: 16M/512/16=2000个level 0,和一些内部tnode. 至少64k了.


NAND data

数据是存在NAND的"chunks"内. yaffs(不是yaffs2)采用512byte+16byte spare大小的chunk. Chunks 数据类型有:

  • yaffs_ObjectHeader: 对应一种yaffs_Object在NAND内的映像.

  • 文件数据

16 byte spare area包含:

  • 8 bytes of tags,

  • 6 bytes of ECC data

  • 1 byte block status (used to identify damaged blocks)

  • 1 byte data status (currently unused).

 

typedef struct

{

     unsigned chunkId:20; //chunk number in file, 0代表是yaffs_ObjectHeader,非零是文件数据

     unsigned serialNumber:2; //serial number for chunk

     unsigned byteCount:10; //number of bytes of data used in this chunk,仅对数据有效

     unsigned objectId:18; //the object id that this chunk belongs to.

     unsigned ecc:12; //ECC on tags

     unsigned unusedStuff:2; //unused

} yaffs_Tags;


非零chunkID代表是文件数据, ID是其在文件内的以chunk为单位的偏移. offset 0的chunkID 是1.参考yaffs_guts.c -> yaffs_Scan.


当一个chunk内数据要被替换时, (如,文件信息改变,或者文件数据被覆盖), 采用写一个新chunk的方式,写完新的chunk才会删除老的.这样照顾到断电/crash.为了区分同时存在两个相同chunkID的情况,需要serialNumber.




yaffs_ObjectHeader

typedef struct

{

     yaffs_ObjectType type; //file,directory,hardlink or symlink


     // Apply to everything

     int parentObjectId;

     __u16 sum; // checksum of name, speed up name lookup

     char name[YAFFS_MAX_NAME_LENGTH + 1];


     // Thes following apply to directories, files, symlinks - not hard links

     __u32 st_mode; // protection

     __u32 st_uid; // user ID of owner

     __u32 st_gid; // group ID of owner

     __u32 st_atime; // time of last access

     __u32 st_mtime; // time of last modification

     __u32 st_ctime; // time of last change

     // File size applies to files only

     int fileSize;

     // Equivalent object id applies to hard links only.

     int equivalentObjectId;

     // alias only applies to symlinks

     char alias[YAFFS_MAX_ALIAS_LENGTH + 1]; /*长度有点小*/

} yaffs_ObjectHeader;


每个NAND内的yaffs_Object都对应存储一个yaffs_ObjectHeader.


equivalentObjectId : 用于hardlinks.  hardlink 使用这个域指定链接到的objectID. 这和linux有所不同,比如ext2是用dir entry来制作hard link的, 而yaffs用他自己的inode来hard link.





NAND Interface

所有访问 NAND 的操作都是通过yaffs_Device内的四个函数指针实现的.此时的 chunk 就是一个 page.

  • 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);

当data 或者 spare 指针为NULL是, 对应RW被忽略.

NAND的相关知识:

  • NAND 不能随机访问. 必须以page为单位读写. (比512 byte的磁道大得多了)

  • 每个NAND page 有512 bytes 数据和16 byte 的"spare". 一个block有32个pages, spare内存有tag以确定其中存储的数据类型.

  • NAND 写操作只能把1 改变成0. 比如数据是10110011, 你写11011010,则你得到的结果是这两个值的与.: 10010010. 只有擦除才能重新得到1. 

  • 在擦除block前,只能向一个page些入有限次. yaffs只写2次: 分配和丢弃(discarded).

  • ECC 用于校正单bit错误, YAFFS 使用自己的ECC, MTD应该关闭ECC.

  • YAFFS开发时期, linux的MTD接口并非非常兼容于yaffs, 所以采用mtd group. (mtd interface 不支持以page为单位的读写).



mkyaffs

mkyaffs 的操作就是擦除所有非坏块. YAFFS 定义擦除的块就是free的.



相关阅读 更多 +
排行榜 更多 +
暗夜格斗手游

暗夜格斗手游

棋牌卡牌 下载
魔渊之刃手游

魔渊之刃手游

角色扮演 下载
像素火影次世代手游版

像素火影次世代手游版

体育竞技 下载