掉电安全文件系统littlefs移植

协变苔藓
• 阅读 144

前言

通过查看oneOS中对littlefs的移植工作,发现,littlefs源码本身,有用的就4个:

  • lfs.c
  • lfs.h
  • lfs_util.c
  • lfs_util.h

剩下的就是适配层:

  • dfs_lfs.c
  • lfs_config.h(和lfs_util.h差不多)
  • lfs_crc.c(和lfs_util.c差不多)

然后再对比其源码,发现,littlefs的源码完全没有更改,更改的只有是适配层,因此,接下来重点看看适配层到底改了什么!

适配层更改

先看lfs_crc.c:

他和lfs_util.c几乎一样,唯一区别在于:

如果没有定义宏LFS_CONFIG,那么将使用lfs_util.c中的lfs_crc接口;

如果定义了宏LFS_CONFIG,那么将使用lfs_crc.c中的lfs_crc接口。

oneOS在sconscript中是定义了该宏的:

CPPDEFINES = ['LFS_CONFIG=lfs_config.h']

另外该宏在lfs_util.h中有被用到作为一个判断:

  • 用户可以通过定义一个头文件来包含自己的配置来覆盖 lfs_util.h,通过定义 LFS_CONFIG 为一个头文件来包含(-DLFS_CONFIG=lfs_config.h)。
  • 如果使用了 LFS_CONFIG,那么默认的lfs_util.h将不会被输出,必须由配置文件提供。建议复制 lfs_util.h 并根据需要修改。
#ifdef LFS_CONFIG
#define LFS_STRINGIZE(x) LFS_STRINGIZE2(x)
#define LFS_STRINGIZE2(x) #x
#include LFS_STRINGIZE(LFS_CONFIG)
#else
 ... ...
#endif

可见,是在lfs_util.h文件中,直接include lfs_config.h

再看lfs_config.h

同样,他就是lfs_util.h改过来的,并没有太大区别。主要看点在于:

  • 如果没有定义LFS_ASSERT&&LFS_NO_ASSERTutil.h用的是assert.h里面的函数assert,而config用的是oneOS自带的os_assert
  • 如果没有定义LFS_NO_MALLOC,说明lfsmalloc,这时候util.h用的是stdlib.h里面的函数mallocfree,而config用的是oneOS自带的os_mallocos_free

适配dfs_lfs.c

最重要的适配层vfs_lfs.c,我把她单独拎出来,作为最高的敬意。

其实她的逻辑很清晰,最开始就是基本的配置,然后是littlefs需要用到的底层函数的适配,这两个都是对*struct* lfs_config结构体成员的赋值,最后则是对接vfs层的接口适配。

基本配置
#ifndef RT_DEF_LFS_DRIVERS
    #define RT_DEF_LFS_DRIVERS 1
#endif

#if (RT_DEF_LFS_DRIVERS < 1)
    #error "#define RT_DEF_LFS_DRIVERS must > 0"
#endif

#ifndef LFS_READ_SIZE
    #define LFS_READ_SIZE 256
#endif

#ifndef LFS_PROG_SIZE
    #define LFS_PROG_SIZE 256
#endif

#ifndef LFS_BLOCK_SIZE
    #define LFS_BLOCK_SIZE 4096
#endif

#ifndef LFS_CACHE_SIZE
    #define LFS_CACHE_SIZE LFS_PROG_SIZE
#endif

#ifndef LFS_BLOCK_CYCLES
    #define LFS_BLOCK_CYCLES (-1)
#endif

#ifndef LFS_LOOKAHEAD_MAX
    #define LFS_LOOKAHEAD_MAX 128
#endif
lfs底层函数适配
static void _lfs_load_config(struct lfs_config* lfs_cfg, struct rt_mtd_nor_device* mtd_nor)
{
    uint64_t mtd_size;

    lfs_cfg->context = (void*)mtd_nor;

    lfs_cfg->read_size = LFS_READ_SIZE;
    lfs_cfg->prog_size = LFS_PROG_SIZE;

    lfs_cfg->block_size = mtd_nor->block_size;
    if (lfs_cfg->block_size < LFS_BLOCK_SIZE)
    {
        lfs_cfg->block_size = LFS_BLOCK_SIZE;
    }

    lfs_cfg->cache_size = LFS_CACHE_SIZE;
    lfs_cfg->block_cycles = LFS_BLOCK_CYCLES;

    mtd_size = mtd_nor->block_end - mtd_nor->block_start;
    mtd_size *= mtd_nor->block_size;
    lfs_cfg->block_count = mtd_size / lfs_cfg->block_size;

    lfs_cfg->lookahead_size = 32 * ((lfs_cfg->block_count + 31) / 32);
    if (lfs_cfg->lookahead_size > LFS_LOOKAHEAD_MAX)
    {
        lfs_cfg->lookahead_size = LFS_LOOKAHEAD_MAX;
    }
#ifdef LFS_THREADSAFE
    lfs_cfg->lock = _lfs_lock;        //如果定义了线程安全,则使用mutex互斥锁
    lfs_cfg->unlock = _lfs_unlock;
#endif
    lfs_cfg->read = _lfs_flash_read;  //littlefs用到的底层函数read
    lfs_cfg->prog = _lfs_flash_prog;  //littlefs用到的底层函数write
    lfs_cfg->erase = _lfs_flash_erase;//littlefs用到的底层函数erase 直接返回OK
    lfs_cfg->sync = _lfs_flash_sync;  //littlefs用到的底层函数sync  直接返回OK
}
vfs对接层

主要是为了对接vfs层,让vfs的接口可以直接使用底层littfs函数。

static int _lfs_result_to_dfs(int result)  //错误码转换
static int _vfs_lfs_mount(struct vfs_filesystem* vfs, unsigned long rwflag, const void* data)  //挂载
static int _vfs_lfs_unmount(struct vfs_filesystem* vfs) //卸载
static int _vfs_lfs_open(struct vfs_file* file)         //打开文件
... ...
static int _vfs_lfs_getdents(struct vfs_file* file, struct dirent* dirp, uint32_t count) //获得目录

适配总结

由此可见,适配lfs最重要的几步:

  • 如果定义了LFS_CONFIG,要自己做好配置
  • 基本的配置要做好,底层函数要适配,归结起来就是:struct lfs_config中的结构体成员要初始化好
  • vfs对接层要做好,这是每一个底层文件系统到vfs层必须要做的

oneos-lfs对照

    part_info->dev_info.dev    = (void *)dev;

    part_info->config.context = &part_info->dev_info;
    part_info->config.read    = g_lfs_dev_ops.read;
    part_info->config.prog    = g_lfs_dev_ops.prog;
    part_info->config.erase   = g_lfs_dev_ops.erase;
    part_info->config.sync    = g_lfs_dev_ops.sync;
#ifdef LFS_THREADSAFE
    part_info->config.lock    = g_lfs_dev_ops.lock;
    part_info->config.unlock  = g_lfs_dev_ops.unlock;
#endif

    part_info->config.read_size    = geometry.block_size;//最小读字节数,试了下不能乱改,sector
    part_info->config.prog_size    = geometry.block_size;//最小写字节数,试了下不能乱改,sector
    part_info->config.block_size   = geometry.block_size;//硬件块大小,试了下不能乱改,blocksize
    part_info->config.block_count  = geometry.capacity / geometry.block_size;//不用手动配
    part_info->config.block_cycles = -1;                //禁用块级磨损均衡
    part_info->config.cache_size    = geometry.block_size; //块缓存的大小,该值必须是读取和编程大小的倍数,并且是块大小的因数,就是要和block_size一样就好!!!

    part_info->config.lookahead_size= LFS_LOOKAHEAD_SIZE; //块分配时的预测深度(分配块时每次步进多少个块),这个数值必须为8的整数倍,这个可以改!!!
    
    part_info->config.read_buffer      = OS_NULL; //lfs_init中会分配!
    part_info->config.prog_buffer      = OS_NULL; //lfs_init中会分配!
    part_info->config.lookahead_buffer = OS_NULL; //lfs_init中会分配!
点赞
收藏
评论区
推荐文章
Wesley13 Wesley13
3年前
MySQL部分从库上面因为大量的临时表tmp_table造成慢查询
背景描述Time:20190124T00:08:14.70572408:00User@Host:@Id:Schema:sentrymetaLast_errno:0Killed:0Query_time:0.315758Lock_
美凌格栋栋酱 美凌格栋栋酱
6个月前
Oracle 分组与拼接字符串同时使用
SELECTT.,ROWNUMIDFROM(SELECTT.EMPLID,T.NAME,T.BU,T.REALDEPART,T.FORMATDATE,SUM(T.S0)S0,MAX(UPDATETIME)CREATETIME,LISTAGG(TOCHAR(
Stella981 Stella981
3年前
Kerberos无约束委派的攻击和防御
 0x00前言简介当ActiveDirectory首次与Windows2000Server一起发布时,Microsoft就提供了一种简单的机制来支持用户通过Kerberos对Web服务器进行身份验证并需要授权用户更新后端数据库服务器上的记录的方案。这通常被称为Kerberosdoublehopissue(双跃点问题),
Wesley13 Wesley13
3年前
FLV文件格式
1.        FLV文件对齐方式FLV文件以大端对齐方式存放多字节整型。如存放数字无符号16位的数字300(0x012C),那么在FLV文件中存放的顺序是:|0x01|0x2C|。如果是无符号32位数字300(0x0000012C),那么在FLV文件中的存放顺序是:|0x00|0x00|0x00|0x01|0x2C。2.  
Wesley13 Wesley13
3年前
mysql设置时区
mysql设置时区mysql\_query("SETtime\_zone'8:00'")ordie('时区设置失败,请联系管理员!');中国在东8区所以加8方法二:selectcount(user\_id)asdevice,CONVERT\_TZ(FROM\_UNIXTIME(reg\_time),'08:00','0
Wesley13 Wesley13
3年前
NEO从源码分析看UTXO交易
_0x00前言_社区大佬:“交易是操作区块链的唯一方式。”_0x01交易类型_在NEO中,几乎除了共识之外的所有的对区块链的操作都是一种“交易”,甚至在“交易”面前,合约都只是一个小弟。交易类型的定义在Core中的TransactionType中:源码位置:neo/Core/TransactionType
Easter79 Easter79
3年前
SpringBoot整合Redis乱码原因及解决方案
问题描述:springboot使用springdataredis存储数据时乱码rediskey/value出现\\xAC\\xED\\x00\\x05t\\x00\\x05问题分析:查看RedisTemplate类!(https://oscimg.oschina.net/oscnet/0a85565fa
Wesley13 Wesley13
3年前
.Net Micro Framework移植基础(包编译通过)
借斯巴达之际,今天在QQ群1600838直播MF移植环境的准备工作,大家可随时询问移植相关问题!如果对MF移植之前的东西有疑问,请看论坛置顶帖.NetMicroFramework导航总贴(新手必看)(https://www.oschina.net/action/GoToLink?urlhttp%3A%2F%2Fwww.newlifex.c
Stella981 Stella981
3年前
Linux应急响应(二):捕捉短连接
0x00前言​短连接(shortconnnection)是相对于长连接而言的概念,指的是在数据传送过程中,只在需要发送数据时,才去建立一个连接,数据发送完成后,则断开此连接,即每次连接只完成一项业务的发送。在系统维护中,一般很难去察觉,需要借助网络安全设备或者抓包分析,才能够去发现。0x01应急场景​
Wesley13 Wesley13
3年前
ISO27001信息安全管理体系
0x00前言初入甲方,刚开始接触的应该就是ISO27001信息安全管理体系,你拿到的应该就是一整套安全管理类的文档。在甲方,稍微有点规模的公司很注重制度和流程,岗位职责分工明细,那么这些安全管理制度,就是你所能掌控的游戏规则,几个人的信息安全部生存之道。0x01ISO27001简介ISO/IEC27001信息安全管理体系
Java服务总在半夜挂,背后的真相竟然是... | 京东云技术团队
最近有用户反馈测试环境Java服务总在凌晨00:00左右挂掉,用户反馈Java服务没有定时任务,也没有流量突增的情况,Jvm配置也合理,莫名其妙就挂了