鸿蒙轻内核M核源码分析系列二一 02 文件系统LittleFS

往期知识点记录:

1、LFS文件系统结构体介绍

会分2部分来介绍结构体部分,先介绍LittleFS文件系统的结构体,然后介绍LiteOS-M内核中提供的和LittleFS相关的一些结构体。

1.1 LittleFS的枚举结构体

在openharmony/third_party/littlefs/lfs.h头文件中定义LittleFS的枚举、结构体,我们先简单了解下,后文会使用到的。

枚举lfs_type定义文件类型,了解下普通文件LFS_TYPE_REG和目录LFS_TYPE_DIR即可。枚举lfs_open_flags定义文件系统的打开标签属性信息,需要熟悉常用的只读LFS_O_RDONLY、只写LFS_O_WRONLY、读写LFS_O_RDWR等等。

// File types
enum lfs_type {
    // file types
    LFS_TYPE_REG            = 0x001,
    LFS_TYPE_DIR            = 0x002,

    // internally used types
    LFS_TYPE_SPLICE         = 0x400,
    LFS_TYPE_NAME           = 0x000,
    LFS_TYPE_STRUCT         = 0x200,
    LFS_TYPE_USERATTR       = 0x300,
    LFS_TYPE_FROM           = 0x100,
    LFS_TYPE_TAIL           = 0x600,
    LFS_TYPE_GLOBALS        = 0x700,
    LFS_TYPE_CRC            = 0x500,

    // internally used type specializations
    LFS_TYPE_CREATE         = 0x401,
    LFS_TYPE_DELETE         = 0x4ff,
    LFS_TYPE_SUPERBLOCK     = 0x0ff,
    LFS_TYPE_DIRSTRUCT      = 0x200,
    LFS_TYPE_CTZSTRUCT      = 0x202,
    LFS_TYPE_INLINESTRUCT   = 0x201,
    LFS_TYPE_SOFTTAIL       = 0x600,
    LFS_TYPE_HARDTAIL       = 0x601,
    LFS_TYPE_MOVESTATE      = 0x7ff,

    // internal chip sources
    LFS_FROM_NOOP           = 0x000,
    LFS_FROM_MOVE           = 0x101,
    LFS_FROM_USERATTRS      = 0x102,
};

// File open flags
enum lfs_open_flags {
    // open flags
    LFS_O_RDONLY = 1,         // Open a file as read only
#ifndef LFS_READONLY
    LFS_O_WRONLY = 2,         // Open a file as write only
    LFS_O_RDWR   = 3,         // Open a file as read and write
    LFS_O_CREAT  = 0x0100,    // Create a file if it does not exist
    LFS_O_EXCL   = 0x0200,    // Fail if a file already exists
    LFS_O_TRUNC  = 0x0400,    // Truncate the existing file to zero size
    LFS_O_APPEND = 0x0800,    // Move to end of file on every write
#endif

    // internally used flags
#ifndef LFS_READONLY
    LFS_F_DIRTY   = 0x010000, // File does not match storage
    LFS_F_WRITING = 0x020000, // File has been written since last flush
#endif
    LFS_F_READING = 0x040000, // File has been read since last flush
#ifndef LFS_READONLY
    LFS_F_ERRED   = 0x080000, // An error occurred during write
#endif
    LFS_F_INLINE  = 0x100000, // Currently inlined in directory entry
};

结构体lfs_t是littlefs文件系统类型结构体,lfs文件系统操作接口的第一个参数一般为这个结构体。成员变量struct lfs_config *cfg下文会涉及,其他成员变量可以暂不了解。

// The littlefs filesystem type
typedef struct lfs {
    lfs_cache_t rcache;
    lfs_cache_t pcache;

    lfs_block_t root[2];
    struct lfs_mlist {
        struct lfs_mlist *next;
        uint16_t id;
        uint8_t type;
        lfs_mdir_t m;
    } *mlist;
    uint32_t seed;

    lfs_gstate_t gstate;
    lfs_gstate_t gdisk;
    lfs_gstate_t gdelta;

    struct lfs_free {
        lfs_block_t off;
        lfs_block_t size;
        lfs_block_t i;
        lfs_block_t ack;
        uint32_t *buffer;
    } free;

    const struct lfs_config *cfg;
    lfs_size_t name_max;
    lfs_size_t file_max;
    lfs_size_t attr_max;

#ifdef LFS_MIGRATE
    struct lfs1 *lfs1;
#endif
} lfs_t;

结构体lfs_file_t、lfs_dir_t分别是littlefs的文件和目录类型结构体,暂不需要关心成员变量细节,知道结构体的用途即可。

// littlefs directory type
typedef struct lfs_dir {
    struct lfs_dir *next;
    uint16_t id;
    uint8_t type;
    lfs_mdir_t m;

    lfs_off_t pos;
    lfs_block_t head[2];
} lfs_dir_t;

// littlefs file type
typedef struct lfs_file {
    struct lfs_file *next;
    uint16_t id;
    uint8_t type;
    lfs_mdir_t m;

    struct lfs_ctz {
        lfs_block_t head;
        lfs_size_t size;
    } ctz;

    uint32_t flags;
    lfs_off_t pos;
    lfs_block_t block;
    lfs_off_t off;
    lfs_cache_t cache;

    const struct lfs_file_config *cfg;
} lfs_file_t;

结构体lfs_config用于提供初始化littlefs文件系统的一些配置。其中.read,.prog,.erase,.sync分别对应该硬件平台上的底层的读写\擦除\同步等接口。

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

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

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

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

    // Configuration provided during initialization of the littlefs
    struct lfs_config {
    // Opaque user provided context that can be used to pass
    // information to the block device operations
    void *context;

      int (*read)(const struct lfs_config *c, lfs_block_t block,
              lfs_off_t off, void *buffer, lfs_size_t size);
      int (*prog)(const struct lfs_config *c, lfs_block_t block,
              lfs_off_t off, const void *buffer, lfs_size_t size);
      int (*erase)(const struct lfs_config *c, lfs_block_t block);
      int (*sync)(const struct lfs_config *c);
    

    #ifdef LFS_THREADSAFE
    int (*lock)(const struct lfs_config *c);
    int (*unlock)(const struct lfs_config *c);
    #endif

      lfs_size_t read_size;
      lfs_size_t prog_size;
      lfs_size_t block_size;
      lfs_size_t block_count;
    
      int32_t block_cycles;
      lfs_size_t cache_size;
      lfs_size_t lookahead_size;
      void *read_buffer;
      void *prog_buffer;
      void *lookahead_buffer;
      lfs_size_t name_max;
      lfs_size_t file_max;
      lfs_size_t attr_max;
      lfs_size_t metadata_max;
    

    };

结构体lfs_info用于维护文件信息,包含文件类型,大小和文件名信息。

// File info structure
struct lfs_info {
    // Type of the file, either LFS_TYPE_REG or LFS_TYPE_DIR
    uint8_t type;

    // Size of the file, only valid for REG files. Limited to 32-bits.
    lfs_size_t size;

    // Name of the file stored as a null-terminated string. Limited to
    // LFS_NAME_MAX+1, which can be changed by redefining LFS_NAME_MAX to
    // reduce RAM. LFS_NAME_MAX is stored in superblock and must be
    // respected by other littlefs drivers.
    char name[LFS_NAME_MAX+1];
};

1.2 LiteOS-M LittleFS的结构体

我们来看下在文件components\fs\littlefs\lfs_api.h里定义的几个结构体。结构体LittleFsHandleStruct维护文件相关的信息,该结构体的成员包含是否使用,文件路径和lfs文件系统类型结构体lfs_t *lfsHandle和文件类型结构体lfs_file_t file。类似的,结构体FileDirInfo维护目录相关的信息,该结构体成员包含包含是否使用,目录名称和lfs文件系统类型结构体lfs_t *lfsHandle和目录类型结构体lfs_dir_t dir。另外一个结构体FileOpInfo维护文件操作信息。

typedef struct {
    uint8_t useFlag;
    const char *pathName;
    lfs_t *lfsHandle;
    lfs_file_t file;
} LittleFsHandleStruct;

struct FileOpInfo {
    uint8_t useFlag;
    const struct FileOps *fsVops;
    char *dirName;
    lfs_t lfsInfo;
};

typedef struct {
    uint8_t useFlag;
    char *dirName;
    lfs_t *lfsHandle;
    lfs_dir_t dir;
} FileDirInfo;

2、LiteOS-M LittleFS的重要全局变量及操作

了解下文件components\fs\littlefs\lfs_api.c定义的常用全局变量。⑴处的g_lfsDir数组维护目录信息,默认支持的目录数目为LFS_MAX_OPEN_DIRS,等于10。⑵处的g_fsOp数组维护针对每个挂载点的文件操作信息,默认挂载点数目LOSCFG_LFS_MAX_MOUNT_SIZE为3个。⑶处的g_handle数组维护文件信息,默认支持文件的数量LITTLE_FS_MAX_OPEN_FILES为100个。⑷处开始的struct dirent g_nameValue是目录项结构体变量,用于函数LfsReaddir();pthread_mutex_t g_FslocalMutex是互斥锁变量;g_littlefsMntName是挂载点名称数组。⑸处开始的挂载操作变量g_lfsMnt、文件操作操作全局变量g_lfsFops在虚拟文件系统中被使用。

⑴  FileDirInfo g_lfsDir[LFS_MAX_OPEN_DIRS] = {0};

⑵  struct FileOpInfo g_fsOp[LOSCFG_LFS_MAX_MOUNT_SIZE] = {0};
⑶  static LittleFsHandleStruct g_handle[LITTLE_FS_MAX_OPEN_FILES] = {0};
⑷  struct dirent g_nameValue;
    static pthread_mutex_t g_FslocalMutex = PTHREAD_MUTEX_INITIALIZER;
    static const char *g_littlefsMntName[LOSCFG_LFS_MAX_MOUNT_SIZE] = {"/a", "/b", "/c"};
    ......
⑸  const struct MountOps g_lfsMnt = {
        .Mount = LfsMount,
        .Umount = LfsUmount,
    };

    const struct FileOps g_lfsFops = {
        .Mkdir = LfsMkdir,
        .Unlink = LfsUnlink,
        .Rmdir = LfsRmdir,
        .Opendir = LfsOpendir,
        .Readdir = LfsReaddir,
        .Closedir = LfsClosedir,
        .Open = LfsOpen,
        .Close = LfsClose,
        .Write = LfsWrite,
        .Read = LfsRead,
        .Seek = LfsSeek,
        .Rename = LfsRename,
        .Getattr = LfsStat,
        .Fsync = LfsFsync,
        .Fstat = LfsFstat,
    };

下文继续介绍下和这些变量相关的内部操作接口。

2.1 目录信息数组操作

GetFreeDir()设置目录信息数组元素信息。参数dirName为目录名称。遍历目录信息数组,遍历到第一个未使用的元素标记其为已使用状态,设置目录名称,返回目录信息元素指针地址。如果遍历失败,返回NULL。函数FreeDirInfo()为函数GetFreeDir()的反向操作,根据目录名称设置对应的数组元素为未使用状态,并把GetFreeDir设置为NULL。

函数CheckDirIsOpen()用于检测目录是否已经打开。如果目录信息数组中记录着对应的目录信息,则标志着该目录已经打开。

FileDirInfo *GetFreeDir(const char *dirName)
{
    pthread_mutex_lock(&g_FslocalMutex);
    for (int i = 0; i < LFS_MAX_OPEN_DIRS; i++) {
        if (g_lfsDir[i].useFlag == 0) {
            g_lfsDir[i].useFlag = 1;
            g_lfsDir[i].dirName = strdup(dirName);
            pthread_mutex_unlock(&g_FslocalMutex);
            return &(g_lfsDir[i]);
        }
    }
    pthread_mutex_unlock(&g_FslocalMutex);
    return NULL;
}

void FreeDirInfo(const char *dirName)
{
    pthread_mutex_lock(&g_FslocalMutex);
    for (int i = 0; i < LFS_MAX_OPEN_DIRS; i++) {
        if (g_lfsDir[i].useFlag == 1 && strcmp(g_lfsDir[i].dirName, dirName) == 0) {
            g_lfsDir[i].useFlag = 0;
            if (g_lfsDir[i].dirName) {
                free(g_lfsDir[i].dirName);
                g_lfsDir[i].dirName = NULL;
            }
            pthread_mutex_unlock(&g_FslocalMutex);
        }
    }
    pthread_mutex_unlock(&g_FslocalMutex);
}

BOOL CheckDirIsOpen(const char *dirName)
{
    pthread_mutex_lock(&g_FslocalMutex);
    for (int i = 0; i < LFS_MAX_OPEN_DIRS; i++) {
        if (g_lfsDir[i].useFlag == 1) {
            if (strcmp(g_lfsDir[i].dirName, dirName) == 0) {
                pthread_mutex_unlock(&g_FslocalMutex);
                return TRUE;
            }
        }
    }
    pthread_mutex_unlock(&g_FslocalMutex);
    return FALSE;
}

经常有很多小伙伴抱怨说:不知道学习鸿蒙开发哪些技术?不知道需要重点掌握哪些鸿蒙应用开发知识点?

为了能够帮助到大家能够有规划的学习,这里特别整理了一套纯血版鸿蒙(HarmonyOS Next)全栈开发技术的学习路线,包含了鸿蒙开发必掌握的核心知识要点,内容有(ArkTS、ArkUI开发组件、Stage模型、多端部署、分布式应用开发、WebGL、元服务、OpenHarmony多媒体技术、Napi组件、OpenHarmony内核、OpenHarmony驱动开发、系统定制移植等等)鸿蒙(HarmonyOS NEXT)技术知识点。

《鸿蒙 (Harmony OS)开发学习手册》(共计892页):https://gitcode.com/HarmonyOS_MN/733GH/overview

如何快速入门?

1.基本概念

2.构建第一个ArkTS应用

3.......

开发基础知识:

1.应用基础知识

2.配置文件

3.应用数据管理

4.应用安全管理

5.应用隐私保护

6.三方应用调用管控机制

7.资源分类与访问

8.学习ArkTS语言

9.......

基于ArkTS 开发

1.Ability开发

2.UI开发

3.公共事件与通知

4.窗口管理

5.媒体

6.安全

7.网络与链接

8.电话服务

9.数据管理

10.后台任务(Background Task)管理

11.设备管理

12.设备使用信息统计

13.DFX

14.国际化开发

15.折叠屏系列

16.......

鸿蒙开发面试真题(含参考答案):https://gitcode.com/HarmonyOS_MN/733GH/overview

OpenHarmony 开发环境搭建

《OpenHarmony源码解析》 :https://gitcode.com/HarmonyOS_MN/733GH/overview

  • 搭建开发环境
  • Windows 开发环境的搭建
  • Ubuntu 开发环境搭建
  • Linux 与 Windows 之间的文件共享
  • ......
  • 系统架构分析
  • 构建子系统
  • 启动流程
  • 子系统
  • 分布式任务调度子系统
  • 分布式通信子系统
  • 驱动子系统
  • ......

OpenHarmony 设备开发学习手册 :https://gitcode.com/HarmonyOS_MN/733GH/overview


相关推荐
Damon小智3 小时前
HarmonyOS NEXT 技术实践-基于基础视觉服务的多目标识别
华为·harmonyos
匹马夕阳6 小时前
华为笔记本之糟糕的体验
华为·笔记本电脑
egekm_sefg6 小时前
华为、华三交换机纯Web下如何创关键VLANIF、操作STP参数
网络·华为
袁震17 小时前
Android-Glide缓存机制
android·缓存·移动开发·glide
岳不谢19 小时前
华为DHCP高级配置学习笔记
网络·笔记·网络协议·学习·华为
爱笑的眼睛1121 小时前
uniapp 极速上手鸿蒙开发
华为·uni-app·harmonyos
K.P21 小时前
鸿蒙元服务从0到上架【第三篇】(第二招有捷径)
华为·harmonyos·鸿蒙系统
K.P1 天前
鸿蒙元服务从0到上架【第二篇】
华为·harmonyos·鸿蒙系统
敲代码的小强1 天前
Flutter项目兼容鸿蒙Next系统
flutter·华为·harmonyos
程序猿会指北1 天前
纯血鸿蒙APP实战开发——Text实现部分文本高亮和超链接样式
移动开发·harmonyos·arkts·openharmony·arkui·组件化·鸿蒙开发