【鸿蒙南向开发】LiteOS-M小型系统内核——LittleFS

199 篇文章 0 订阅
198 篇文章 0 订阅

LittleFS

基本概念

LittleFS主要用在微控制器和flash上,是一种嵌入式文件系统,具有如下3个特点:

  1. 掉电恢复

    在写入时即使复位或者掉电也可以恢复到上一个正确的状态。

  2. 擦写均衡

    有效延长flash的使用寿命。

  3. 有限的RAM/ROM

    节省ROM和RAM空间。

运行机制

最经典的掉电保护方法有两种,一种是使用日志,一种是通过COW方式。lfs结合了两种方法,并优化了两种方案的缺点,提供了一套掉电保护策略

日志方式

image.png

具体步骤为:

  1. 写入数据之前,先在日志区存储开始标志,记录要写入的数据位置和大小;
  2. 待写入的数据写入日志区;
  3. 待写入的数据写入数据区;
  4. 写入完成之后,在日志区记录结束标志。

模拟掉电场景:

  1. 步骤1完成,步骤2没有完成;重启之后,保持原来的数据,日志无效;
  2. 步骤1,2完成了,步骤3没有完成,尝试把步骤2的数据写入到数据区;
  3. 步骤1,2,3完成了,步骤4没有完成,同样尝试把步骤2的数据写入到数据区;

Cow机制

image.png

具体步骤为:

  1. 想更新节点F的数据,先申请一个新的节点,把F的旧数据拷贝过去,然后更新新的数据;
  2. 把父节点的指针指向新的节点,去掉旧节点的指针。

模拟掉电场景:

步骤1完成了,步骤2没有完成,则使用旧的数据,新的节点变成孤儿节点。

lfs掉电保护

fs结合了日志方式和COW机制两种方式进行掉电保护,并且优化了两种方案。

前面谈过文件系统三要素,超级块,inode,以及数据。对应lfs来说,他把超级块以及inode通过日志的方式存储,两种采用统一的存储结构,后文称两者为元数据;普通数据则采用cow的方式存储,采用czt逆序链表的方式。

image.png

元数据的存储
image.png

元数据(对应root,dir)采用双block的方式存储,互为备份,每个block都有一个revision序号,值越大,表示block的数据越新,每个block默认可以存储最多0xff个文件的数据,如果超过这个值,则需要compact(压缩)。

Compact是干什么呢? 即当数据的大小大于某个值的时候,把数据整合,剔除同一个id的旧的数据,然后写入到备份block里面。

普通数据的存储

Lfs的数据采用链表的方式逆向管理。
image.png

  1. 采用逆向的指针,这样常规的追加数据,不需要额外的开销来重新建立所有的索引;
  2. 每个偶数block有多个指针,指向更远的数据,这样可以在检索的时候加快速度。

开发指导

移植LittleFS到新硬件设备上,需要申明lfs_config:

const struct lfs_config cfg = {
    // block device operations
    .read  = user_provided_block_device_read,
    .prog  = user_provided_block_device_prog,
    .erase = user_provided_block_device_erase,
    .sync  = user_provided_block_device_sync,

    // block device configuration
    .read_size = 16,
    .prog_size = 16,
    .block_size = 4096,
    .block_count = 128,
    .cache_size = 16,
    .lookahead_size = 16,
    .block_cycles = 500,
};

其中.read,.prog,.erase,.sync分别对应该硬件平台上的底层的读写\擦除\同步等接口。

read_size 每次读取的字节数,可以比物理读单元大以改善性能,这个数值决定了读缓存的大小,但值太大会带来更多的内存消耗。

prog_size 每次写入的字节数,可以比物理写单元大以改善性能,这个数值决定了写缓存的大小,必须是read_size的整数倍,但值太大会带来更多的内存消耗。

block_size 每个擦除块的字节数,可以比物理擦除单元大,但此数值应尽可能小因为每个文件至少会占用一个块。必须是prog_size的整数倍。

block_count 可以被擦除的块数量,这取决于块设备的容量及擦除块的大小。

示例代码

代码实现如下:

int main(void) {
    // mount the filesystem
    int err = lfs_mount(&lfs, &cfg);

    // reformat if we can't mount the filesystem
    // this should only happen on the first boot
    if (err) {
        lfs_format(&lfs, &cfg);
        lfs_mount(&lfs, &cfg);
    }

    // read current count
    uint32_t boot_count = 0;
    lfs_file_open(&lfs, &file, "boot_count", LFS_O_RDWR | LFS_O_CREAT);
    lfs_file_read(&lfs, &file, &boot_count, sizeof(boot_count));

    // update boot count
    boot_count += 1;
    lfs_file_rewind(&lfs, &file);
    lfs_file_write(&lfs, &file, &boot_count, sizeof(boot_count));

    // remember the storage is not updated until the file is closed successfully
    lfs_file_close(&lfs, &file);

    // release any resources we were using
    lfs_unmount(&lfs);

    // print the boot count
    printf("boot_count: %d\n", boot_count);
}

写在最后

●如果你觉得这篇内容对你还蛮有帮助,我想邀请你帮我三个小忙:
●点赞,转发,有你们的 『点赞和评论』,才是我创造的动力。
●关注小编,同时可以期待后续文章ing🚀,不定期分享原创知识。
●更多鸿蒙最新技术知识点,请移步前往小编:https://gitee.com/

在这里插入图片描述

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值