那曲檬骨新材料有限公司

0
  • 聊天消息
  • 系統消息
  • 評論與回復
登錄后你可以
  • 下載海量資料
  • 學習在線課程
  • 觀看技術視頻
  • 寫文章/發帖/加入社區
會員中心
創作中心

完善資料讓更多小伙伴認識你,還能領取20積分哦,立即完善>

3天內不再提示

鴻蒙輕內核源碼分析:虛擬文件系統 VFS

王程 ? 來源: jf_75796907 ? 作者: jf_75796907 ? 2024-02-18 14:50 ? 次閱讀

VFS(Virtual File System)是文件系統的虛擬層,它不是一個實際的文件系統,而是一個異構文件系統之上的軟件粘合層,為用戶提供統一的類 Unix 文件操作接口。由于不同類型的文件系統接口不統一,若系統中有多個文件系統類型,訪問不同的文件系統就需要使用不同的非標準接口。而通過在系統中添加 VFS 層,提供統一的抽象接口,屏蔽了底層異構類型的文件系統的差異,使得訪問文件系統的系統調用不用關心底層的存儲介質和文件系統類型,提高開發效率。本文先介紹下 VFS 的結構體和全局變量,然后詳細分析下 VFS 文件操作接口。文中所涉及的源碼,均可以在開源站點 https://gitee.com/openharmony/kernel_liteos_m 獲取。

1、VFS 結構體定義

在文件 componentsfsvfsfs_operations.h 中定義了 VFS 虛擬文件系統操作涉及的結構體。⑴處的 struct MountOps 結構體封裝了掛載相關的操作,包含掛載、卸載和文件系統統計操作。⑵處的 struct FsMap 結構體映射文件系統類型及其對應的掛載操作和文件系統操作,支持的文件類型包含 “fat” 和 “littlefs” 兩種,通過這個結構體可以獲取對應文件類型的掛載操作及文件系統操作接口。⑶處的 struct FileOps 封裝文件系統的操作接口,包含文件操作、目錄操作,統計等相應的接口。

⑴  struct MountOps {
        int (*Mount)(const char *source, const char *target, const char *filesystemtype, unsigned long mountflags,
            const void *data);
        int (*Umount)(const char* target);
        int (*Umount2)(const char* target, int flag);
        int (*Statfs)(const char *path, struct statfs *buf);
    };

⑵  struct FsMap {
        const char *fileSystemtype;
        const struct MountOps *fsMops;
        const struct FileOps *fsFops;
    };

⑶  struct FileOps {
        int (*Open)(const char *path, int openFlag, ...);
        int (*Close)(int fd);
        int (*Unlink)(const char *fileName);
        int (*Rmdir)(const char *dirName);
        int (*Mkdir)(const char *dirName, mode_t mode);
        struct dirent *(*Readdir)(DIR *dir);
        DIR *(*Opendir)(const char *dirName);
        int (*Closedir)(DIR *dir);
        int (*Read)(int fd, void *buf, size_t len);
        int (*Write)(int fd, const void *buf, size_t len);
        off_t (*Seek)(int fd, off_t offset, int whence);
        int (*Getattr)(const char *path, struct stat *buf);
        int (*Rename)(const char *oldName, const char *newName);
        int (*Fsync)(int fd);
        int (*Fstat)(int fd, struct stat *buf);
        int (*Stat)(const char *path, struct stat *buf);
        int (*Ftruncate)(int fd, off_t length);
    };

2、VFS 重要的內部全局變量

在文件 componentsfsvfslos_fs.c 中有 2 個全局變量比較重要,⑴處定義的數組 g_fsmap 維護文件系統類型映射信息,數組大小為 2,支持 “fat” 和 “littlefs” 文件類型。⑵處的變量 g_fs 根據掛載的文件類型指向數組 g_fsmap 中的 FsMap 類型元素。⑶處的函數 InitMountInfo () 會給數組 g_fsmap 進行初始化賦值。第 0 個元素維護的 “fat” 文件類型的文件系統映射信息,第 1 個元素維護的 “littlefs” 文件類型的文件系統映射信息。涉及到的掛載操作、文件系統操作變量 g_fatfsMnt、g_fatfsFops、g_lfsMnt、g_lfsFops 在對應的文件系統文件中定義。⑷處的函數 MountFindfs () 用于根據文件類型從數組中獲取文件映射信息。

⑴  static struct FsMap g_fsmap[MAX_FILESYSTEM_LEN] = {0};
⑵  static struct FsMap *g_fs = NULL;

⑶  static void InitMountInfo(void)
    {
    #if (LOSCFG_SUPPORT_FATFS == 1)
        extern struct MountOps g_fatfsMnt;
        extern struct FileOps g_fatfsFops;
        g_fsmap[0].fileSystemtype = strdup("fat");
        g_fsmap[0].fsMops = &g_fatfsMnt;
        g_fsmap[0].fsFops = &g_fatfsFops;
    #endif
    #if (LOSCFG_SUPPORT_LITTLEFS == 1)
        extern struct MountOps g_lfsMnt;
        extern struct FileOps g_lfsFops;
        g_fsmap[1].fileSystemtype = strdup("littlefs");
        g_fsmap[1].fsMops = &g_lfsMnt;
        g_fsmap[1].fsFops = &g_lfsFops;
    #endif
    }

⑷  static struct FsMap *MountFindfs(const char *fileSystemtype)
    {
        struct FsMap *m = NULL;

        for (int i = 0; i < MAX_FILESYSTEM_LEN; i++) {
            m = &(g_fsmap[i]);
            if (m-?>fileSystemtype && strcmp(fileSystemtype, m->fileSystemtype) == 0) {
                return m;
            }
        }

        return NULL;
    }

3、VFS 相關的操作接口

在之前的系列文章《鴻蒙輕內核 M 核源碼分析系列十九 Musl LibC》中介紹了相關的接口,那些接口會調用 VFS 文件系統中操作接口。對每個接口的用途用法不再描述,快速記錄下各個操作接口。

3.1 掛載卸載操作?

掛載卸載操作包含 LOS_FsMount、LOS_FsUmount、LOS_FsUmount2 等 3 個操作。⑴處在掛載文件系統之前,需要初始化文件系統映射信息,只會操作一次。⑵處根據文件系統類型獲取對應的文件類型映射信息。從這里,可以獲知,LiteOS-M 內核只能同時支持一個文件系統,不能只支持 fat 又支持 littlefs。⑶處對應對應的文件系統掛載接口實現掛載操作。其他兩個函數同樣比較簡單,自行閱讀代碼即可。

int LOS_FsMount(const char *source, const char *target,
                    const char *filesystemtype, unsigned long mountflags,
                    const void *data)
    {
        static int initFlag = 0;

⑴      if (initFlag == 0) {
            InitMountInfo();
            initFlag = 1;
        }

⑵      g_fs = MountFindfs(filesystemtype);
        if (g_fs == NULL) {
            errno = ENODEV;
            return FS_FAILURE;
        }

        if (g_fs->fsMops == NULL || g_fs->fsMops->Mount == NULL) {
            errno = ENOSYS;
            return FS_FAILURE;
        }

⑶      return g_fs->fsMops->Mount(source, target, filesystemtype, mountflags, data);
    }

    int LOS_FsUmount(const char *target)
    {
        if (g_fs == NULL) {
            errno = ENODEV;
            return FS_FAILURE;
        }
        if (g_fs->fsMops == NULL || g_fs->fsMops->Umount == NULL) {
            errno = ENOSYS;
            return FS_FAILURE;
        }
        return g_fs->fsMops->Umount(target);
    }

    int LOS_FsUmount2(const char *target, int flag)
    {
        if (g_fs == NULL) {
            errno = ENODEV;
            return FS_FAILURE;
        }
        if (g_fs->fsMops == NULL || g_fs->fsMops->Umount2 == NULL) {
            errno = ENOSYS;
            return FS_FAILURE;
        }
        return g_fs->fsMops->Umount2(target, flag);
    }

3.2 文件目錄操作?

VFS 封裝的文件目錄操作接口包含 LOS_Open、LOS_Close、LOS_Read、LOS_Write、LOS_Opendir、LOS_Readdir、LOS_Closedir 等等。對具體的文件類型的文件目錄操作接口進行封裝,代碼比較簡單,自行閱讀即可,部分代碼片段如下。

......

int LOS_Unlink(const char *path)
{
    if (g_fs == NULL) {
        errno = ENODEV;
        return FS_FAILURE;
    }
    if (g_fs->fsFops == NULL || g_fs->fsFops->Unlink == NULL) {
        errno = ENOSYS;
        return FS_FAILURE;
    }
    return g_fs->fsFops->Unlink(path);
}

int LOS_Fstat(int fd, struct stat *buf)
{
    if (g_fs == NULL) {
        errno = ENODEV;
        return FS_FAILURE;
    }
    if (g_fs->fsFops == NULL || g_fs->fsFops->Fstat == NULL) {
        errno = ENOSYS;
        return FS_FAILURE;
    }
    return g_fs->fsFops->Fstat(fd, buf);
}

......

int LOS_Mkdir(const char *path, mode_t mode)
{
    if (g_fs == NULL) {
        errno = ENODEV;
        return FS_FAILURE;
    }
    if (g_fs->fsFops == NULL || g_fs->fsFops->Mkdir == NULL) {
        errno = ENOSYS;
        return FS_FAILURE;
    }
    return g_fs->fsFops->Mkdir(path, mode);
}

DIR *LOS_Opendir(const char *dirName)
{
    if (g_fs == NULL) {
        errno = ENODEV;
        return NULL;
    }
    if (g_fs->fsFops == NULL || g_fs->fsFops->Opendir == NULL) {
        errno = ENOSYS;
        return NULL;
    }
    return g_fs->fsFops->Opendir(dirName);
}
......

3.3 隨機數文件?

文件 /dev/random 可以用于產生隨機數。在開啟宏 LOSCFG_RANDOM_DEV 時,LiteOS-M 支持隨機數文件。從⑴處可知隨機數依賴文件~/openharmony/base/security/huks/interfaces/innerkits/huks_lite/hks_client.h 和 hks_tmp_client.c,這些文件用來產生隨機數。⑵處定義的 RANDOM_DEV_FD 和 RANDOM_DEV_PATH 分別是隨機數文件的文件描述符和隨機數文件路徑。

#ifdef LOSCFG_RANDOM_DEV
⑴  #include "hks_client.h"
⑵  #define RANDOM_DEV_FD  CONFIG_NFILE_DESCRIPTORS + CONFIG_NSOCKET_DESCRIPTORS
    #define RANDOM_DEV_PATH  "/dev/random"
    #endif

3.3.1 隨機 LOS_Open 和 LOS_Close

該函數打開一個文件,獲取文件描述符用于進一步操作。⑴處表示對于隨機數文件,打開的標簽選項只能支持指定的這些,否則會返回錯誤碼。⑵處獲取標準路徑,如果獲取失敗,返回錯誤碼。⑶處比較獲取的標準路徑是否為 RANDOM_DEV_PATH,在確認是隨機數路徑時,⑷處開始判斷。如果訪問模式為只讀,返回錯誤,如果打開選項標簽是目錄,返回錯誤。如果不是上述錯誤情形,返回隨機數文件描述符。⑸處如果獲取的標準路徑為 “/” 或 “/dev”,則根據不同的選項,返回不同的錯誤碼。

int LOS_Open(const char *path, int oflag, ...)
{
#ifdef LOSCFG_RANDOM_DEV
    unsigned flags = O_RDONLY | O_WRONLY | O_RDWR | O_APPEND | O_CREAT | O_LARGEFILE | O_TRUNC | O_EXCL | O_DIRECTORY;
⑴  if ((unsigned)oflag & ~flags) {
        errno = EINVAL;
        return FS_FAILURE;
    }

    size_t pathLen = strlen(path) + 1;
    char *canonicalPath = (char *)malloc(pathLen);
    if (!canonicalPath) {
        errno = ENOMEM;
        return FS_FAILURE;
    }
⑵  if (GetCanonicalPath(NULL, path, canonicalPath, pathLen) == 0) {
        FREE_AND_SET_NULL(canonicalPath);
        errno = ENOMEM;
        return FS_FAILURE;
    }

⑶  if (strcmp(canonicalPath, RANDOM_DEV_PATH) == 0) {
        FREE_AND_SET_NULL(canonicalPath);
⑷      if ((O_ACCMODE & (unsigned)oflag) != O_RDONLY) {
            errno = EPERM;
            return FS_FAILURE;
        }
        if ((unsigned)oflag & O_DIRECTORY) {
            errno = ENOTDIR;
            return FS_FAILURE;
        }
        return RANDOM_DEV_FD;
    }
⑸  if (strcmp(canonicalPath, "/") == 0 || strcmp(canonicalPath, "/dev") == 0) {
        FREE_AND_SET_NULL(canonicalPath);
        if ((unsigned)oflag & O_DIRECTORY) {
            errno = EPERM;
            return FS_FAILURE;
        }
        errno = EISDIR;
        return FS_FAILURE;
    }
    FREE_AND_SET_NULL(canonicalPath);
#endif
......
}

對于隨機數文件,關閉時,直接返回成功,不需要額外操作。代碼片段如下:

int LOS_Close(int fd)
{
#ifdef LOSCFG_RANDOM_DEV
    if (fd == RANDOM_DEV_FD) {
        return FS_SUCCESS;
    }
#endif
......
}

3.3.2 隨機 LOS_Read 和 LOS_Write

隨機數文件讀寫使用 LOS_Read 和 LOS_Write 接口。讀取時,⑴處先對傳入參數進行校驗,如果讀取字節數為 0,則返回 0;如果讀取的緩存地址為空,返回 - 1;如果讀的字節大于 1024,則使用 1024。⑵處調用 hks_generate_random () 產生隨機數。由于隨機數文件是只讀的,如果嘗試寫入會返回 - 1 錯誤碼。

ssize_t LOS_Read(int fd, void *buf, size_t nbyte)
{
#ifdef LOSCFG_RANDOM_DEV
    if (fd == RANDOM_DEV_FD) {
⑴      if (nbyte == 0) {
            return FS_SUCCESS;
        }
        if (buf == NULL) {
            errno = EINVAL;
            return FS_FAILURE;
        }
        if (nbyte > 1024) { /* 1024, max random_size */
            nbyte = 1024; /* hks_generate_random: random_size must <= 1024 */
        }
        struct hks_blob key = {HKS_BLOB_TYPE_RAW, (uint8_t *)buf, nbyte};
⑵      if (hks_generate_random(&key) != 0) {
            errno = EIO;
            return FS_FAILURE;
        }
        return (ssize_t)nbyte;
    }
#endif
......
}

ssize_t LOS_Write(int fd, const void *buf, size_t nbyte)
{
#ifdef LOSCFG_RANDOM_DEV
    if (fd == RANDOM_DEV_FD) {
        errno = EBADF; /* "/dev/random" is readonly */
        return FS_FAILURE;
    }
#endif
......
}


審核編輯 黃宇

聲明:本文內容及配圖由入駐作者撰寫或者入駐合作網站授權轉載。文章觀點僅代表作者本人,不代表電子發燒友網立場。文章及其配圖僅供工程師學習之用,如有內容侵權或者其他違規問題,請聯系本站處理。 舉報投訴
  • 文件系統
    +關注

    關注

    0

    文章

    287

    瀏覽量

    19941
  • 源碼
    +關注

    關注

    8

    文章

    652

    瀏覽量

    29396
  • vfs
    vfs
    +關注

    關注

    0

    文章

    14

    瀏覽量

    5270
  • 鴻蒙
    +關注

    關注

    57

    文章

    2392

    瀏覽量

    42986
收藏 人收藏

    評論

    相關推薦

    關于更新openharmony文件系統時遇到的問題

    用的固件,文件系統內核是之前的,之前版本用起來沒問題。但是 用下面三個的時候 固件可以正常燒錄,也按照文檔里面加載了環境變量,但是燒錄內核文件系統(都是U盤更新的)的時候出現了
    發表于 12-30 11:55

    華納云:VFS在提升文件系統性能方面的具體實踐

    VFS(Virtual File System)通過提供統一的接口和抽象層,使得操作系統能夠以高效的方式管理和訪問不同的文件系統。以下是一些VFS在提升
    的頭像 發表于 11-27 15:59 ?226次閱讀

    Jtti:Linux中虛擬文件系統和容器化的關系

    在Linux中,虛擬文件系統VFS)和容器化技術之間有密切的關系。容器化是指通過使用容器來運行應用程序,而容器本質上是在宿主機上運行的獨立進程,它們通常共享宿主機的操作系統內核和部分
    的頭像 發表于 11-27 15:38 ?183次閱讀

    虛擬化數據恢復—UFS2文件系統數據恢復案例

    虛擬化數據恢復環境: SAN環境下通過iSCSI實現FreeNAS,FreeNAS采用的UFS2文件系統。物理存儲架構在一臺服務器上,另外兩臺服務器上安裝ESXi虛擬系統。整個存儲
    的頭像 發表于 11-11 11:02 ?207次閱讀

    嵌入式學習-飛凌嵌入式ElfBoard ELF 1板卡-應用編程示例控制LED燈之sysfs文件系統

    文件系統,被稱為虛擬文件系統。它對系統設備進行管理,產生一個包含所有系統硬件層次的視圖,同時將內核信息以
    發表于 10-21 09:52

    飛凌嵌入式ElfBoard ELF 1板卡-應用編程示例控制LED燈之sysfs文件系統

    個基于內存的文件系統,被稱為虛擬文件系統。它對系統設備進行管理,產生一個包含所有系統硬件層次的視圖,同時將內核信息以
    發表于 10-18 09:31

    Linux根文件系統的掛載過程

    Linux根文件系統(rootfs)是Linux系統中所有其他文件系統和目錄的起點,它是內核啟動時掛載的第一個文件系統
    的頭像 發表于 10-05 16:50 ?492次閱讀

    【開源鴻蒙】使用QEMU運行OpenHarmony系統

    本文將會介紹如何從源碼安裝QEMU 6.2.0,以及如何使用QEMU運行OpenHarmony系統。通過本文,你將會對QEMU和OpenHarmony
    的頭像 發表于 09-14 08:51 ?714次閱讀
    【開源<b class='flag-5'>鴻蒙</b>】使用QEMU運行OpenHarmony<b class='flag-5'>輕</b>量<b class='flag-5'>系統</b>

    Linux中的proc介紹

    /proc 是一種偽文件系統(也即虛擬文件系統),存儲的是當前內核運行狀態的一系列特殊文件,用戶可以通過這些文件查看有關
    的頭像 發表于 08-14 18:14 ?486次閱讀
    Linux中的proc介紹

    如何修改buildroot和debian文件系統

    本文檔主要介紹在沒有編譯環境的情況下,如何修改buildroot和debian文件系統方法,如在buildroot文件系統中添加文件、修改目錄等文件操作,在debian
    的頭像 發表于 07-22 17:46 ?533次閱讀
    如何修改buildroot和debian<b class='flag-5'>文件系統</b>

    開源鴻蒙 編譯OpenHarmony系統QEMU RISC-V版本

    本文將介紹如何為QEMU RISC-V虛擬平臺構建OpenHarmony系統。得益于QEMU的CPU指令集模擬執行能力,該方法可以在沒有開發板的情況下調試和運行OpenHarmony系統
    的頭像 發表于 07-15 10:36 ?1148次閱讀
    開源<b class='flag-5'>鴻蒙</b> 編譯OpenHarmony<b class='flag-5'>輕</b>量<b class='flag-5'>系統</b>QEMU RISC-V版本

    linux--sysfs文件系統

    sysfs文件系統 sysfs,全稱為System Filesystem,是一個由Linux內核實現的虛擬文件系統。它扮演著一個橋梁的角色,將內核中的設備和驅動程序信息以
    的頭像 發表于 07-08 11:37 ?989次閱讀
    linux--sysfs<b class='flag-5'>文件系統</b>

    虛擬機數據恢復—EXT4文件系統下KVM虛擬機數據恢復案例

    發行版本中。KVM使用Linux自身的調度器進行管理。 本案例中的服務器操作系統為Linux,文件系統為EXT4。操作系統上的部署的幾臺KVM虛擬機被刪除,每臺KVM
    的頭像 發表于 04-17 14:22 ?406次閱讀
    <b class='flag-5'>虛擬</b>機數據恢復—EXT4<b class='flag-5'>文件系統</b>下KVM<b class='flag-5'>虛擬</b>機數據恢復案例

    Linux系統如何擴展文件系統

    當數據盤沒有創建分區,只在設備上創建了文件系統。或者格式化了硬盤,就直接mount上系統使用。
    的頭像 發表于 02-21 09:53 ?870次閱讀

    鴻蒙內核源碼分析:Newlib C

    使用 Musl C 庫的時候,內核提供了基于 LOS_XXX 適配實現 pthread、mqeue、fs、semaphore、time 等模塊的 posix 接口(//kernel/liteos_m
    的頭像 發表于 02-18 15:41 ?784次閱讀
    <b class='flag-5'>鴻蒙</b><b class='flag-5'>輕</b><b class='flag-5'>內核</b><b class='flag-5'>源碼</b><b class='flag-5'>分析</b>:Newlib C
    澳门百家乐官网游戏说明书| 网络百家乐官网破解器| 广东百家乐主论坛| 网上百家乐官网导航| 波克城市棋牌中心| 百家乐黄金城游戏大厅| 可以玩百家乐官网的博彩网站| 大发888亚洲游戏在线| 百家乐娱乐城备用网址| 百家乐官网游戏厅| 汝南县| 大发888主页优惠| 广州百家乐牌具公司| 188金宝博| 老虎机定位器| 百家乐园sun811.com| 明珠百家乐官网的玩法技巧和规则| 永利高百家乐官网现金网| 新浪棋牌竞技风暴| 威尼斯人娱乐城003| 百家乐庄闲必胜规| 百家乐统计| 职业百家乐官网的玩法技巧和规则 | 百家乐增值公式| 仕達屋百家乐官网的玩法技巧和规则 | 真人百家乐对决| 百家乐娱乐城棋牌| 大中华百家乐官网的玩法技巧和规则| 真人百家乐官网澳门娱乐城| 百家乐官网庄闲作千| 渭南市| 娱乐城注册送金| 儋州市| 大发888怎么打不开| 威尼斯人娱乐场 送2688元礼金领取lrm64 | 克东县| 云鼎百家乐官网注册| 斗六市| 大发888资讯网007| 威尼斯人娱乐城网络博彩| 大发888官方hgx2dafa888gwd|