文章详情

  • 游戏榜单
  • 软件榜单
关闭导航
热搜榜
热门下载
热门标签
php爱好者> php文档>Yaffs basic and Spec

Yaffs basic and Spec

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

2009.3.23

所有资料来自 yaffs.net 的文档,  属于read notes类别.
第一句: 根据开发者建议, <64M的NAND分区用Jffs2区别不大,越大的分区用YAFFS越有优势. 如果只有小分区和NOR,Jffs是个不错的选择.

Yaffs, yet another flash file system(一个falsh 文件系统,让人不由自主想起强大的yacc). 号称专门为NAND falsh缔造的文件系统, 支持多个OS, 对linux来说,是个out tree的一个文件系统.

Charles Manning的文章提到当初尝试在改造jeffs2以适应NAND flash的过程中意识到一个专门支持NAND fash的文件系统的必要性. (下图为原文copy,2002年资料, 最近8G scandisk II 淘宝和鼎好售价150人民币左右..). jeffs对NOR的

NOR (typical, varies a lot)

NAND

Density

Up to 32MB chips

Currently 256MB and growing.

Cost per MB

$1-$2

25c

Access

Random

Page oriented with spare area on each page. Sequential access within a page.

Programmability

Can modify a single bit.

Very limited re-programming.

Read speed

50-100nS

10uS page "seek" + 50nS per byte

Program time

5uS per byte

200uS per page

Erasure time

1s per 64kB block

2ms per 16kB block

Reliability

Relatively immune to corruption. No bad blocks.

Needs error correction. Bad blocks marked when shipped.


很多特性都没有必要, 比如GC,  NOR因为擦写速度极慢,对垃圾收集要求颇高, NAND则快得多, YAFFS为NAND高度优化GC算法, 另外NAND总是有坏块存在的, ECC当然少不了, 并且作为NAND文件系统, 增强稳定性也是迫在眉睫, yaffs是log-structured的文件系统, 断电恢复能力好.

Yaffs 从一开始设计就采取了把YAFFS从OS分离出来的做法,是的YAFFS容易调试和移植.
  • yaffs_guts: 完全可以移植的文件系统算法.

  • yaffs_fs.c: 对linux VFS的接口.可以替换成模拟的接口以便在user space调试 yaffs_guts.c

  • nand interface: yaffs_guts 和 NAND memory 访问(linux MTD或者RAM emulation)的封装层.

  • Portability functions: OS服务的封装层, 如内存分配等...


YAFFS 占用RAM空间少,特性丰富(symbol link之类...),配置灵活支持众多规格的容量配置和ECC方式.

YAFFS NAND Model

YAFFS 采用NAND模型如下:

  • NAND flash 采用blocks组织, 每个block大小相同,是最小的擦写单位.
  • chunk 是最小的分配单位, YAFFS1 固定为512-byte(NAND page, 512data+16byte spare area) YAFFS2  chunk 可以更大,比如在2k page的设备上,一个chunk一般是一个2k的page,即2kb数据 + 64-bytes  spare.
  • 所有访问都是page (chunk) 对齐的.
  •  programming a NAND flash的时候只有0bit有意义, 1比特代表不关心.比如byte已经是1010了,那么编程 1001 的结果就是一个与操作, 成为1000, 这和NOR不同.

YAFFS 采用blockID和chunkID进行编号:
chunkId = block_id  * YAFFS_CHUNKS_PER_BLOCK + chunk Offset in this block.

YAFFS 以变量yaffs_Spare为标准组织spare信息,比如特别注意bad block marker的位置等事项.YAFFS规定空(0xFF filled) block 是空闲或者被擦除的, 所以, 格式化一个分区,相当于擦除所有非坏块.

YAFFS的模块化设计,给YAFFS移植到其他OS以及调试带来很多便利, 大小端兼容, 多种CPU体系结构支持, 一个被称作YDI, YAFFS Direct Interface的东西是YAFFS可移植性的基础, YDI一般作为一个OS特定的模块来实现,包括:
  • Application Interface: 实现open, write..
  • RTOS Integration Interface  yaffsfs_SetError, yaffsfs_Lock/Unlock,yaffsfs_CurrentTime, 以及初始化, 另外内存分配见ydirectenv.h.
  • NAND Configuration and Access Interface: 访问NAND的接口.

使用前必须调用   yaffs_StartUp();然后mount分区如 yaffs_mount("/boot")之类. NAND的配置需要多说点:
yaffs必须有一个mount point(从根目录开始)和一个yaffs_Device 结构. yaffs_Device 一般代表一个分区, 可以是整个设备或者一部分,注意不能使用block0. yaffs_Device中下列结构必须配置好:

nBytesPerChunk: chunk的size,一般是page大小, YAFFS1 固定为512.
nChunksPerBlock: erasable block 的chunk数目(nand必须以blcok为擦写单位).
nReservedBlocks: 典型值为2, 5,为GC和block failure预留.
startBlock: 起始block,不能用0..
endBlock: Last block in this yaffs_Device.
useNANDECC: 非零值代表采用硬件ECC(或者MTD?).
nShortOpCaches: 一般用10-20, 0则会禁用cache.
genericDevice: 随意使用, 每个必须不同, (典型的,可以用mtd设备指针吧.)


Using YAFFS with NOR flash

在NOR上使用yaffs,需要模拟NAND的行为.假定NOR flash的擦写单元是128kB 的block:
每个chunk定义为512bytes数据加上16 bytes spare area,总共 528 bytes.
每个block则包含(128*1024)/528 = 248 chunks (还有几个byte浪费了)

则配置如下:
#define NOR_BASE xxxxx // Base address for NOR device
#define NOR_BLOCK_SIZE (128*1024)
#define NOR_PAGE_DATA_SIZE 512
#define NOR_PAGE_SPARE_SIZE 16
#define NOR_PAGE_WHOLE_SIZE (512+16)
#define NOR_CHUNKS_PER_BLOCK (NOR_BLOCK_SIZE/NOR_PAGE_WHOLE_SIZE)

#define chunkToAddr(c) (NOR_BASE + \
                        NOR_BLOCK_SIZE * ((c)/NOR_CHUNKS_PER_BLOCK) + \
                        NOR_PAGE_SIZE * ((c)%NOR_CHUNKS_PER_BLOCK))

对应的读写函数则如下:
int nor_writeChunkToNAND(struct yaffs_DeviceStruct *dev,int chunkInNAND, const __u8 *data, yaffs_Spare *spare);
{
    // Remember, we're dealing with NAND programming semantics, so we need to read back
    // and AND in the pattern for NOR. Don't have to do this for NAND.

    __u8 buffer[NOR_PAGE_DATA_SIZE];
    int i;
    __u8 * norAddr;

    if(data)
    {
        norAddr = chunkToAddr(chunkInNAND);
        memcpy(buffer, norAddr,NOR_PAGE_DATA_SIZE);
        for(i = 0; i < NOR_PAGE_DATA_SIZE; i++)
              buffer[i] &= data[i];
        write_nor(norAddr,buffer,NOR_PAGE_DATA_SIZE);
    }

    if(spare)
    {
        norAddr = chunkToAddr(chunkInNAND) + NOR_PAGE_DATA_SIZE;
        memcpy(buffer, norAddr,NOR_PAGE_SPARE_SIZE);
        for(i = 0; i < NOR_PAGE_SPARE_SIZE; i++)
              buffer[i] &= spare[i];
        write_nor(norAddr,buffer,NOR_PAGE_SPARE_SIZE);
    }

     return YAFFS_OK;
}


int nor_eraseBlockInNAND(struct yaffs_DeviceStruct *dev,int blockInNAND);
{
 ....__u8 *norAddr = NOR_BASE + NOR_BLOCK_SIZE * blockInNAND;
     erase_nor(norAddr);

     return YAFFS_OK;
}

int nor_initialiseNAND(struct yaffs_DeviceStruct *dev)
{
    // Set up chip selects etc.
}

YAFFS Debugging


YAFFS可以在运行时 通过proc来开启debug,相关的debug Flag见下表. 编译的时候配置debug通过 yaffs_fs.c 中的变量yaffs_traceMask.

name C #define bitmask value
error YAFFS_TRACE_ERROR 0x00000001
os YAFFS_TRACE_OS 0x00000002
allocate YAFFS_TRACE_ALLOCATE 0x00000004
scan YAFFS_TRACE_SCAN 0x00000008
bad_blocks YAFFS_TRACE_BAD_BLOCKS 0x00000010
erase YAFFS_TRACE_ERASE 0x00000020
gc YAFFS_TRACE_GC 0x00000040
write YAFFS_TRACE_WRITE 0x00000080
tracing YAFFS_TRACE_TRACING 0x00000100
deletion YAFFS_TRACE_DELETION 0x00000200
buffers YAFFS_TRACE_BUFFERS 0x00000400
nandaccess YAFFS_TRACE_NANDACCESS 0x00000800
gc_detail YAFFS_TRACE_GC_DETAIL 0x00001000
scan_debug YAFFS_TRACE_SCAN_DEBUG 0x00002000
mtd YAFFS_TRACE_MTD 0x00004000
always YAFFS_TRACE_ALWAYS 0x40000000
bug YAFFS_TRACE_BUG 0x80000000

运行时开启debug通过proc文件系统, 看几个例子, 很简单:

echo +os-write > /proc/yaffs

echo =none-os+write > /proc/yaffs

echo 0xf00001 > /proc/yaffs

echo all > /proc/yaffs


*always选项显示当打开的trace选项(未验证)


YAFFS Spec 摘要


   Jffs是基于journaling的flash file system, 对NOR提供了很好的支持, 由于有journaling, 稳定性也很好. 但是JFFS2虽然改进了但是128M的NAND flash还是要消耗约4M的RAM!! 另一方面JFFS需要在启动的时候扫描Flash来查找Journling河简历文件系统结构, 对于需要ECC的NAND来说128M扫描约需要28秒!!

   设计宗旨:

  • NAND-flash friendly.

  • Robustness through journaling strategies.

  • 减少RAM开销和启动时间.

  • 趋于使用在非移动性性质的flash上,不怕不兼容的话SM(smart media)卡也能用(SM现在还是FAT兼容性更好)


YAFFS 采用和SmartMedia类似的flash物理抽象,原因如下:

  • 一些结构是定死的: bad block markers 就是由NAND制造商决定的.

  • 可以重用代码.

  • 如果能用,不要修改.


文件数据存储于固定大小的chunks内, chunks大小等同于page. 每个page用一个file id和一个chunkID标记.这些标记存储在flahs的"spare data". 文件数据重写时,采取的做法是把新的数据写入新页,采用相同的chunkID和file ID.老的数据被标记为"discarded".


文件头存储在独立page,并有特殊标记,可以与数据区分开. 页面还有一个2 bit的的序列码,用于在断电,crash的时候区分哪个page是discarded的.


一个只含有discarded page的block显然是GC的理想候选. 当block内还有有效数据的情况下可以吧有效数据复制出去从而是的这个block可以被GC.


每个文件有一个列表,包含此文件的 __u16类型的page addresses.在128M的NAND上共有218 pages,故而 __u16可以有效的索引一个包含4个pages的group. 这样处理的结果是每512kb大概2byte的RAM开销. 128M NAND需要512kB 的 RAM.


启动的时候仍然需要扫描NAND, 但是只要spare 就行了, 速度相对很快, 128M NAND大概3秒. 进一步加速措施可以吧NAND进行分区,关键数据优先mount.


通过增大chunk size到1024或者2k可以进一步提高速度,同时利用率就会下降.



Spare area details (per page)

Byte #                SmartMedia usage                              YAFFS usage

0..511

Data

Data. either file data or file header depending on tags

512..515

Reserved

Tags

516

Data status byte. Not used in SM code from Samsung

Data status byte. If more than 4 bits are zero, then this page is discarded.

517

Block status byte

Block status byte

518..519

Block address

Tags

520..522

ECC on second 256 bytes part of data

ECC on second 256 bytes of data

523..524

Block address

Tags

525..527

ECC on first 256 bytes part of data

ECC on first 256 bytes part of data



block status :block是否损坏.

data status : page是否有效, 如果0bit不足4个,代表有效, 否则代表discarded.

YAFFS tags:使用方式见下表

Number of bits               Usage

18

18-bit file id. ie. Limit of 218 (over 260000) files. File id 0 is not valid and indicates a deleted page. File Id 0x3FFFF i is also not valid. 就是Inode了.

2

2-bit serial number.

20

20-bit page id within file. Limit of 220 pages per file. ie. over 500MB file max size. Page id 0 means the file header for this file.

10

10-bit counter of the number of bytes used in the page.

12

12-bit ECC on tags.

2

Unused. Keep as 1.

64

Total


serial number: 一个有效页面被copy到新page的时候, 此序列号增加1, 比如覆写和GC. 

byte counter :在page中保留长度可以减少对文件头page的根新频度, 在open的时候无须更新文件头,在close的时候更新即可.



File "headers" 有两种:

  • 真正的文件头,( the mode, ower id, group id, length,...)

  • 一个hard link(s)

  • 目录也是一个文件, 有inode和hard link(s), 没有数据

RAM data details

Block 管理就是track block的状态, 多少个page在使用用中, 有问题的block, 是否是合适被GC的block等.

一个文件需要一个索引结构来保存属于这个文件的pages, 一些tree算法非常适合这些操作, 查找速度和内存开销都比较理想.

Page allocation and garbage collection

Pages分配策略是在一个block内是顺序的, 所有pages都被使用后选取下一个clean的block. 至少2到3个block预留给GC使用. 如果clean的blocks 不够, 就选择一个合适的dirty block (比如只有discarded pages), 擦除其数据,变成clean的block. 总之会选择最合适的block(比如discarded pages最多的).

GC 通过把有效pages写入新的pages来释放一个block. 同时,通过在一组block内进行随机选择也很好,可以避免不同block的损耗差异. 相对NOR, NAND 擦除和写的速度较快, 可以通过on-demand的方式进行, 亦可通过taklet.

相对于JFFSx, GC算法相当简单, 这得益于使用fixed-size pages 而不是journaling nodes.

Flash writing

YAFFS 在一个page擦除前,仅在新page分配的时候写入数据和spare数据, 在it gets stomped on(没看出来是什么时候)的时候再写一次spare, 这个符合很多NAND芯片的限制.

Wear levelling

没有明显的损耗平衡算法, 而是依赖于两个策略:

  • Reserving some blocks to cater for failure. You need to do this anyway with NAND. The main purpose behind wear levelling is to prevent some blocks getting more wear and failing. Since we expect, and handle, failure this is no longer as important.

  • The infrequent random block selection should prevent low-wear blocks getting "stuck".


Bootloading

boot loader 不能直接从NAND读取文件,因为NDND的坏块可能性很高,但是YAFFS很简单,boot loaderis应该很容易处理.

Conclusion

YAFFS 简单, 专业NAND, 启动快, 内存开销小, 拥有日志, YAFFS同时也借鉴了不少JFFS的代码.


相关阅读 更多 +
排行榜 更多 +
房间毁灭模拟器最新版

房间毁灭模拟器最新版

休闲益智 下载
街头追逐者最新版

街头追逐者最新版

休闲益智 下载
弓箭手2内置作弊菜单

弓箭手2内置作弊菜单

休闲益智 下载