littlefs系列:Technical Specification

1、quick notes

  • littlefs是block-based文件系统。flash被划分成多个相同大小的block
  • block pointer是32bits,0xFFFFFFFF表示空指针
  • 除了逻辑block size(通常是erase block size),littlefs还有program block size和read block size,后面两个block size主要是用于flash 读写时的对齐
  • littlefs采用little-endian order

 

2、Directories/Metadata pairs

metadata pair是littlefs的基石,提供了原子更新的能力。superblock也是存储在metadata pair中。metadata pair存储在两个block中,一个block在另一个block erase的时候提供备份。同一个metadata pair中的两个block并不要求是连续的,可以分散在不同的位置,通过指针链接。

每一个metadata block类似于一个可以追加的log,包含多个commit。commit可以按照顺序追加到metadata block中而不需要erase操作。同时,后续的commit可以取代旧的commit,只有最新的commit才被认为是有效的。

 

每个metadata block包含一个32-bit的revision count,后面跟着多个commit。每个commit包含一个或多个entry,每个commit的最后是32-bit的CRC。entry不一定是word-aligned。但是每个commit都是program block size对齐的,因此commit与commit之间可能存在padding。

metadata block的主要域:

1)revision count:32bit长。每擦除一次就增加1,如果两个metadata block都包含有效的数据,则使用最新的revision count所在的block。

2)CRC:32bit长。使用0x04c11db7多项式,初始值为0xFFFFFFFF。

3)entry:每个entry以32-bit的tag开始,后面跟着可变长度的数据。

metadata block支持前向和后向的迭代。为了减少重复空间,相邻entry的tag通过XOR连接起来,初始值是0xffffffff。

 

每个entry中还包含一个valid bit用于指示当前entry和commit有效。

下图是包含4个entry的block。

  .---------------------------------------.
.-|  revision count   |      tag ~A       |        \
| |-------------------+-------------------|        |
| |                 data A                |        |
| |                                       |        |
| |-------------------+-------------------|        |
| |      tag AxB      |       data B      | <--.   |
| |-------------------+                   |    |   |
| |                                       |    |   +-- 1st commit
| |         +-------------------+---------|    |   |
| |         |      tag BxC      |         | <-.|   |
| |---------+-------------------+         |   ||   |
| |                 data C                |   ||   |
| |                                       |   ||   |
| |-------------------+-------------------|   ||   |
| |     tag CxCRC     |        CRC        |   ||   /
| |-------------------+-------------------|   ||
| |     tag CRCxA'    |      data A'      |   ||   \
| |-------------------+                   |   ||   |
| |                                       |   ||   |
| |              +-------------------+----|   ||   +-- 2nd commit
| |              |     tag CRCxA'    |    |   ||   |
| |--------------+-------------------+----|   ||   |
| | CRC          |        padding         |   ||   /
| |--------------+----+-------------------|   ||
| |     tag CRCxA''   |      data A''     | <---.  \
| |-------------------+                   |   |||  |
| |                                       |   |||  |
| |         +-------------------+---------|   |||  |
| |         |     tag A''xD     |         | < |||  |
| |---------+-------------------+         |  ||||  +-- 3rd commit
| |                data D                 |  ||||  |
| |                             +---------|  ||||  |
| |                             |   tag Dx|  ||||  |
| |---------+-------------------+---------|  ||||  |
| |CRC      |        CRC        |         |  ||||  /
| |---------+-------------------+         |  ||||
| |           unwritten storage           |  ||||  more commits
| |                                       |  ||||       |
| |                                       |  ||||       v
| |                                       |  ||||
| |                                       |  ||||
| '---------------------------------------'  ||||
'---------------------------------------'    |||'- most recent A
                                             ||'-- most recent B
                                             |'--- most recent C
                                             '---- most recent D

从上图中可以看出,第一个entry的tag是本entry的原始tag和0xFFFFFFFF进行XOR计算的结果。每个commit的最后一个entry是CRC,包含前一个entry的tag与CRC进行XOR计算的结果,例如1st commit中的entry C之后有tag CxCRC。

 

3、metadata tag

在littlefs中,32-bit的tag代表了所有的metadata类型,包含file entry, directory, global state和CRC。

 

32-bit的tag格式如上图。32-bit的tag是按照big-endian存储的。这也是littlefs中唯一按照big-endian存储的数据结构。主要是因为valid bit必须是commit的第一个bit,按照big-endian存储会简化代码。0x00000000和0xffffffff都是非法的tag。metadata tag各个域的详细解释如下:

1)valid bit(1-bit):指示tag是否valid

2)type3(11-bits):tag的类型。11bit又分为3bit的type1,又叫abstract type和8bit的chunk。0x000是非法的type

3)type1(3-bit):又叫abstract type

4)chunk(8-bits)和前面的abstract type组合表示多种不同的含义。type1+chunk+id组成一个唯一的id。

5)id(10-bits):metadata block中的每个文件都有一个唯一的id用于连接文件和tag。0x3ff用来表示不和文件关联的tag,比如目录和global metadata

6)length(10-bits):data的长度,0x3ff表示这个tag被删除

 

4、metadata type

1)0x401 LFS_TYPE_CREATE

创建新文件时会使用这个id。但是inline file不需要这个tag。创建所做的全部工作就是移动使用此ID的任何文件。从这个意义上说,创建类似于插入虚构的文件数组中。

 

2)0x4ff LFS_TYPE_DELETE

删除文件时使用此id。和create相反,此标记将移至与该id相邻的任何文件,类似于从虚构的文件数组中删除。

3)0x0xx LFS_TYPE_NAME

使用此id关联文件名和文件类型。chunk域表格8-bit的文件类型。

name tag的域如下图:

 

a)file type(8-bits):文件类型

b)file name:文件名,ASCII字符串。

 

4)0x001 LFS_TYPE_REG

初始化id+name为普通文件。

 

5)0x002 LFS_TYPE_DIR

初始化id+name为目录。littlefs中目录是通过metadata pair链表的形式存储的,每个pair都包含任意数量的文件,文件按照字母顺序排列。一个指向目录的指针存储在tag结构中。

 

6)0x0ff LFS_TYPE_SUPERBLOCK

初始化id为superblock。super block存储右格式化的配置信息和文件系统识别信息。superblock entry是存储在block0和block1上的一个metadata pairs,并且最后一个通过metadata pair会重复一次作为根目录。

 

superblock entry的内容存储在type为superblock的name tag和inline tag里。name tag包含『littlefs』字符串,而inline tag包含版本和配置信息。name tag和inline tag的示意图如下:

 

各域的定义:

a)magic string(8-bytes):『littlefs』字符串

b)version(32-bits):高16 bit为主版本号,低16 bit为次版本号

c)block size(32-bits):logical block size

d)block count(32-bits):number of blocks

e)name max(32-bits):文件名的最大长度

f)file max(32-bits):文件的最大长度

g)attr max(32-bits):文件属性的最大长度

superblock必须是metadata pair的第一个entry(id 0),也必须是第一个写入到block的entry。这意味着superblock可以通过地址偏移的方式直接读取。

 

7)0x2xx LFS_TYPE_STRUCT

通过id来关联数据结构。数据结构的具体布局取决于数据结构的type(存储在chunk域)。

 

8)0x200 LFS_TYPE_DIRSTRUCT

目录数据结构。littlefs中目录是通过metadata pair链表的形式存储的,每个pair都包含任意数量的文件,文件按照字母顺序排列。

 

目录结构tag只包含指向本目录的第一个metadata pair的指针。目录的大小只能通过遍历获取。指向本目录另一个metadata pair的指针存储在tail tag中。目录tag的布局如下:

 

a)metadata pair(8-bytes):指向本目录的第一个metadata pair。

9)0x201 LFS_TYPE_INLINESTRUCT

inline结构。inline结构主要用于存储小文件。文件直接存储在metadata pair中。文件的数据存储在tag的data字段中。

 

a)inline data:直接存储在metadata pair的文件数据。

10)0x202 LFS_TYPE_CTZSTRUCT

CTZ skip-list结构。CTZ skip-list结构用来存储大文件。文件存储在反向的skip-list中,一个指针指向skip-list的head。通过skip-list head和文件size信息就足够读取文件了。skip-list的示意图:

 

对于skip-list可以简单描述如下:

 

一个block中指针的最大数量由文件的最大长度和block size确定。对于32 bits的文件长度,最小的block size是104 bytes。

CTZ tag的示意图如下:

 

a)file head(32 bits):指向位于skip-list的head的block

b)file size(32 bits):文件大小

 

11)0x3xx LFS_TYPE_USERATTR

用户属性结构。

 

user_attr各域:

a)attr type(8-bits):user attribute类型

b)attr data:user attribute数据

 

12)0x6xx LFS_TYPE_TAIL

metadata pair的tail指针。tail指针用来把所有的metadata pairs连接成链表。chunk域包含tail指针的类型。tail指针分为hardtail和softtail。

hardtail:下一个metadata pair属于当前目录

softtail:下一个metadata pair不属于当前目录,只是为了方便文件系统的遍历

 

通常,metadata pair列表包含所有的metadata pair。但是有些操作导致out of sync,比如掉电,这是『global state』中的sync标志置位。当sync标志置位时:

a)metadata pair链表可能包含孤儿目录

b)metadata pair链表中可能包含和bad block关联的metadata pair,而这个bad block已经被替换了

一旦发现sync被置位,线索链表必须进行校验,如果littlefs是只读的则可以不用。

tail tag 的布局:

 

各域:

a)tail type(8-bits):tail指针的类型

b)metadata pair(8-bytes):指向下一个metadata pair

13)0x600 LFS_TYPE_SOFTTAIL

softtail类型的tail结构,说明下一个metadata pair不属于当前目录,只有在文件系统遍历时才会使用。

14)0x601 LFS_TYPE_HARDTAIL

hardtail类型的tail结构,说明下一个metadata pair属于当前目录。在littlefs中,目录是按照字母顺序排列的,因此下一个metadata pair中包含的文件名只能比当前的要大。

15)0x7xx LFS_TYPE_GSTATE

『global state』结构。

 

『global state』的大小和格式依赖于type,type存储在chunk域。目前只支持MOVE STATE.

16)0x7ff LFS_TYPE_MOVESTATE

提供『global state』中的move state相关的delta结构。move state主要存储可能会导致文件系统out of sync的操作信息。比如在metadata pairs之间移动文件或者对metadata pair链表本身的操作。

对于move操作,move state包含tag+源metadata pair信息。如果tag不为0,说明在move的过程中可能发生可掉电或者复位,而文件存在于两个不同的位置。对于这种情况,源文件应该被删除。

对于metadata pair链表本身的操作,单独的sync标志用来指示修改,如果sync被置位,线索链表需要校验,

move state tag的布局:

 

各域:

a)sync bit(1-bit):指示metadata pair线索链表处于in-sync。如果sync被置位,则链表在使用前需要校验

b)move type(11-bits):move的类型。0x000表示没有任何move,0x4ff表示源文件需要删除,其他的值均非法

c)move id(10-bits):需要move的file id

d)metadata pair(8-bytes):指向含有move的metadata pair

 

17)0x5xx LFS_TYPE_CRC

crc tag。crc表示了commit的结束,同时也提供校验信息。

data字段的前32-bit包含crc32的值。crc32计算时使用的多项式是0x04c11db7,初值是0xffffffff。对于第一个commit,计算crc时会包含revision count。

crc tag的布局:

 

a)valid state(1-bit):指出下一个tag的valid bit的值。这样可以确保metadata block中未写入的区域会被识别为无效区域。

b)crc(32-bits)

c)padding:program size对齐

  • 1
    点赞
  • 8
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值