当前位置: 首页 > 科技观察

Littlefs原理解析-磨损均衡(六)

时间:2023-03-20 16:21:01 科技观察

了解更多开源请访问:开源基础软件社区https://ost.51cto.com前言littlefs原理分析5篇,包括:littlefs提交机制的整体存储结构fetch操作目录操作文件读写操作,块分配算法也会介绍。littlefs有以下几种防止磨损的措施:写入时进行坏块检测和写入恢复。均匀分配块:由块分配算法实现。定期重新分配元数据所在的块。1、写入过程中的坏块检测和写入恢复在littlefs中,写入文件、目录元数据等时,会调用函数lfs_bd_flush,最终将数据写入磁盘。lfs_bd_flush函数写完后,会将写入内存的数据与磁盘上的数据进行比较。如果数据不一致,则可能是坏块。方法如下:写入时通过回读磁盘数据进行校验,检测坏块。检测到坏块后,清除坏块,重新分配块,然后重写。lfs_bd_flush函数检查数据是否一致的分析如下://缓存中的数据回写磁盘时,检测坏块lfs_bd_flush(lfs_t*lfs,|lfs_cache_t*pcache,lfs_cache_t*rcache,布尔验证)|...||//调用lfs_bd_cmp比较磁盘上的数据和写入的数据是否一致|//如果它们不同,你可能遇到了坏块|->if(validate){|lfs_bd_cmp(lfs,|NULL,rcache,diff,|pcache->block,pcache->off,pcache->buffer,diff);|}||->...比如往文件写数据,在函数lfs_file_flush中,当检测到坏块时,会重新分配块,然后进行Write操作:lfs_file_flush(lfs_t*lfs,lfs_file_t*file)|->...||->while(true){|//调用lfs_bd_flush写入数据,比较数据是否写入正确|interr=lfs_bd_flush(lfs,&file->cache,&lfs->rcache,true);|如果(错误){|//如果检测到坏块则跳转重定位|如果(错误==LFS_ERR_CORRUPT){|转到搬迁;|}|返回错误;|}|打破;||搬迁:|//重新定位块并再次写入|LFS_DEBUG("坏块在0x%"PRIx32,file->block);|err=lfs_file_relocate(lfs,文件);|如果(错误){|返回错误;|}|}2。块分配(一)lookaheadbufferlittlefs使用lookaheadbuffer来管理和分配块。前瞻缓冲区是一个固定大小的位图,它记录有关区域中块分配的信息。lookaheadbuffer的例子如下,假设总共有64个block,lookaheadbuffer的大小为8,lookaheadbuffer对应的block分别分配了文件A、D和目录B、C:相关的前瞻缓冲区的数据结构如下:structlfs_free{lfs_block_toff;//lookaheadlfs_block_tsize中所有block的整体偏移量;//lookahead中的块总数lfs_block_ti;//lookahead_size中的索引表示当前块lfs_block_tack;//所有剩余的空闲块Numberuint32_t*buffer;//lookahead的位图块管理缓冲区}free;(2)查找已分配块先行缓冲区只记录了一个区域的块分配信息,当需要知道其他区域的块分配情况时,可以通过扫描文件系统来查找已分配的块。如果先行缓冲区中没有空闲块,则需要移动先行缓冲区以寻找文件系统中的其他空闲块。扫描查找已分配块的过程如下:将先行缓冲区位置移动一个lookahead_size,并将先行缓冲区清零。从超级块开始遍历文件系统中的所有目录和文件,以遍历所有已分配的块。如果block位于lookaheadbuffer管理的区域,则将lookaheadbuffer中的相应位设置为1。lookaheadbuffer只使用固定大小的位图来存储分配块的信息,这是一个trade-off在littlefs.虽然比较费时,但是有效的节省了RAM空间资源。代码分析如下:lfs_alloc(lfs_t*lfs,lfs_block_t*block)|...||//当先行缓冲区中没有空闲块时,需要扫描||//1.移动前瞻缓冲区|->lfs->free.off=(lfs->free.off+lfs->free.size)|%lfs->cfg->block_count;|lfs->free.size=lfs_min(8*lfs->cfg->lookahead_size,lfs->free.ack);|lfs->free.i=0;||//2.将先行缓冲区清除为0|->memset(lfs->free.buffer,0,lfs->cfg->lookahead_size);||//3.遍历文件系统进行扫描搜索|->lfs_fs_rawtraverse(lfs,lfs_alloc_lookahead,lfs,true);||->...其中,lfs_fs_rawtraverse函数会从superblock开始遍历整个文件系统,对于整个文件系统中所有分配的块调用回调函数lfs_alloc_lookahead。lfs_alloc_lookahead函数分析如下://lfs_fs_rawtraverse函数传递给lfs_alloc_lookahead函数的参数//是lfs结构体指针p和块号blocklfs_alloc_lookahead(void*p,lfs_block_tblock)|->lfs_t*lfs=(lfs_t*)p;||//获取块号相对于先行缓冲区的偏移量|->lfs_block_toff=((block-lfs->free.off)|+lfs->cfg->block_count)%lfs->cfg->block_count;||//如果块在前瞻缓冲区管理的范围内,|//设置位图的相应位,表示该块已经分配|->if(offfree.size){|lfs->free.buffer[off/32]|=1U<<(off%32);|}|返回0;(3)块分配算法块分配算法过程总结:首先尝试从lookaheadbuffer中寻找下一个空闲块,如果没有,将lookaheadbuffer位置移动lookahead_size,执行上一节中的扫描和搜索文件系统过程,然后尝试从先行缓冲区中找到下一个空闲块,并循环进行。以下为几次分配和扫描的示例:boot...lookahead:fsblocks:fffff9fffffffffeffffffffffff0000scanning...lookahead:fffff9fffsblocks:fffff9fffffffffeffffffffffff0000alloc=21lookahead:fffffdfffsblocks:fffffdfffffffffeffffffffffff0000alloc=22lookahead:fffffffffsblocks:fffffffffffffffeffffffffffff0000scanning...lookahead:fffffffefsblocks:fffffffffffffffeffffffffffff0000alloc=63lookahead:fffffffffsblocks:ffffffffffffffffffffffffffff0000scanning...lookahead:fffffffffsblocks:ffffffffffffffffffffffffffff0000scanning...lookahead:fffffffffsblocks:ffffffffffffffffffffffffffff0000scanning...lookahead:ffff0000fsblocks:ffffffffffffffffffffffffffff0000alloc=112lookahead:ffff8000fsblocks:ffffffffffffffffffffffffffffffff8000(4)均匀分配法介绍完块分配算法,现在回头介绍块分配算法中与磨损均衡相关的策略littlefs使用一个简单的策略实现均匀分配:使用lookaheadbufferlinearBlocksare以这样一种方式分配,即在运行期间在循环磁盘中均匀地分配块。每次挂载文件系统时,lookaheadbuffer都会移动一个随机偏移量,这样在多次运行时,只要随机偏移量是统一的,整体分配也是统一的。相关函数分析:lfs_mount(lfs_t*lfs,conststructlfs_config*cfg)|->lfs_rawmount(lfs_t*lfs,conststructlfs_config*cfg)|->...||//1.计算随机数|->lfs_dir_fetchmatch(...)|->...||//使用crc计算随机数|->lfs->seed=lfs_crc(lfs->seed,&crc,sizeof(crc));||->...||//2.随机偏移前瞻缓冲区|->lfs->free.off=lfs->seed%lfs->cfg->block_count;3.元数据的周期性重新分配会在块中周期性的进行littlefs元数据对应块的重新分配,防止元数据块的磨损。由于元数据提交过程中空间不足,每次执行压缩或拆分操作时,修订计数也??会更新。当revisioncount是block_cycles的整数倍时,metadata对应的block会被重新分配。其中,block_cycles为用户配置的值。相关函数分析:lfs_dir_compact(lfs_t*lfs,|lfs_mdir_t*dir,conststructlfs_mattr*attrs,intattrcount,|lfs_mdir_t*source,uint16_tbegin,uint16_tend)|->...||//revisioncount为block_cycles的整数倍时,重新分配元数据对应的block|->if(lfs->cfg->block_cycles>0&&|(dir->rev%((lfs->cfg->block_cycles+1)|1)==0)){|...||//我们写得太多了,该搬家了|累了=真;|转到搬迁;|}||->...||relocate:|->...Summary本篇介绍了littlefs中磨损均衡相关的策略和block分配算法,littlefs文件系统原理分析系列文章到此结束。小编也希望通过对littlefs文件系统的认真分析,让相关读者对OpenHarmonyLiteOS-A内核的文件系统原理有更深入的了解,而littlefs文件系统不仅仅用在OpenHarmony系统上,它也是一种被广泛使用的小型文件系统,相信掌握它的原理对嵌入式开发者会有很大的帮助。了解更多开源知识,请访问:开源基础软件社区https://ost.51cto.com。