# 鴻蒙內(nèi)核M核源碼分析系列二一 01 虛擬文件系統(tǒng)VFS

      網(wǎng)友投稿 637 2025-03-31

      鴻蒙輕內(nèi)核M核源碼分析系列二一 01 虛擬文件系統(tǒng)VFS

      # 鴻蒙輕內(nèi)核M核源碼分析系列二一 01 虛擬文件系統(tǒng)VFS

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

      1、VFS結構體定義

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

      ⑴ 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重要的內(nèi)部全局變量

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

      ⑴ 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相關的操作接口

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

      3.1 掛載卸載操作

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

      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 隨機數(shù)文件

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

      #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

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

      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 ...... }

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

      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

      隨機數(shù)文件讀寫使用LOS_Read和LOS_Write接口。讀取時,⑴處先對傳入?yún)?shù)進行校驗,如果讀取字節(jié)數(shù)為0,則返回0;如果讀取的緩存地址為空,返回-1;如果讀的字節(jié)大于1024,則使用1024。⑵處調(diào)用hks_generate_random()產(chǎn)生隨機數(shù)。由于隨機數(shù)文件是只讀的,如果嘗試寫入會返回-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 ...... }

      小結

      本文介紹了VFS的結構體和全局變量,分析了下VFS文件操作接口,對于隨機數(shù)文件也進行了分析。時間倉促和能力關系,如有失誤,歡迎指正。感謝閱讀,如有任何問題、建議,都可以博客下留言給我,謝謝。

      參考資料

      HarmonyOS Device>文檔指南>基礎能力-虛擬文件系統(tǒng)

      IoT 虛擬化 輕量級操作系統(tǒng) LiteOS

      版權聲明:本文內(nèi)容由網(wǎng)絡用戶投稿,版權歸原作者所有,本站不擁有其著作權,亦不承擔相應法律責任。如果您發(fā)現(xiàn)本站中有涉嫌抄襲或描述失實的內(nèi)容,請聯(lián)系我們jiasou666@gmail.com 處理,核實后本網(wǎng)站將在24小時內(nèi)刪除侵權內(nèi)容。

      版權聲明:本文內(nèi)容由網(wǎng)絡用戶投稿,版權歸原作者所有,本站不擁有其著作權,亦不承擔相應法律責任。如果您發(fā)現(xiàn)本站中有涉嫌抄襲或描述失實的內(nèi)容,請聯(lián)系我們jiasou666@gmail.com 處理,核實后本網(wǎng)站將在24小時內(nèi)刪除侵權內(nèi)容。

      上一篇:如何查詢一整年制作多少個表格
      下一篇:怎么添加自己想要的水印內(nèi)容(如何自行添加水印)
      相關文章
      亚洲欧洲无码一区二区三区| 亚洲人成在线精品| 亚洲日韩亚洲另类激情文学| 亚洲国产成人精品无码区在线秒播| 亚洲av无码av制服另类专区| 亚洲精品美女久久777777| 亚洲综合色婷婷七月丁香| 中文亚洲AV片在线观看不卡| 久久久久亚洲AV无码专区桃色| 亚洲国产香蕉人人爽成AV片久久| 亚洲第一区在线观看| 亚洲精品成人区在线观看| 亚洲中文字幕丝袜制服一区| 国产av无码专区亚洲国产精品| 亚洲男人av香蕉爽爽爽爽| 国产专区一va亚洲v天堂| 国产亚洲成归v人片在线观看| 国产偷国产偷亚洲高清日韩| 国产成人A亚洲精V品无码| 亚洲精品无码久久一线| 久久香蕉国产线看观看亚洲片| 亚洲国产精久久久久久久| 在线电影你懂的亚洲| 亚洲AV色吊丝无码| 亚洲熟妇无码一区二区三区导航| 亚洲精品成a人在线观看夫| WWW亚洲色大成网络.COM| 亚洲精品亚洲人成在线观看下载| 亚洲女人被黑人巨大进入| 亚洲真人无码永久在线| 亚洲av网址在线观看| 亚洲综合激情视频| 国产亚洲精品VA片在线播放| 亚洲AV无码AV日韩AV网站| 国产亚洲精品2021自在线| 在线观看亚洲av每日更新| 亚洲欧洲日韩不卡| 亚洲AV无码国产精品色| 亚洲AV无码专区在线观看成人 | 亚洲白色白色永久观看| 亚洲第一成人在线|