# 虚拟文件系统 ## 基本概念 VFS(Virtual File Systemï¼‰æ˜¯æ–‡ä»¶ç³»ç»Ÿçš„è™šæ‹Ÿå±‚ï¼Œå®ƒä¸æ˜¯ä¸€ä¸ªå®žé™…的文件系统,而是一个异构文件系统之上的软件粘åˆå±‚,为用户æä¾›ç»Ÿä¸€çš„ç±»Unix文件æ“作接å£ã€‚由于ä¸åŒç±»åž‹çš„æ–‡ä»¶ç³»ç»ŸæŽ¥å£ä¸ç»Ÿä¸€ï¼Œè‹¥ç³»ç»Ÿä¸æœ‰å¤šä¸ªæ–‡ä»¶ç³»ç»Ÿç±»åž‹ï¼Œè®¿é—®ä¸åŒçš„æ–‡ä»¶ç³»ç»Ÿå°±éœ€è¦ä½¿ç”¨ä¸åŒçš„éžæ ‡å‡†æŽ¥å£ã€‚è€Œé€šè¿‡åœ¨ç³»ç»Ÿä¸æ·»åŠ VFS层,æä¾›ç»Ÿä¸€çš„æŠ½è±¡æŽ¥å£ï¼Œå±è”½äº†åº•层异构类型的文件系统的差异,使得访问文件系统的系统调用ä¸ç”¨å…³å¿ƒåº•层的å˜å‚¨ä»‹è´¨å’Œæ–‡ä»¶ç³»ç»Ÿç±»åž‹ï¼Œæé«˜å¼€å‘效率。 OpenHarmonyå†…æ ¸ä¸ï¼ŒVFS框架是通过在内å˜ä¸çš„æ ‘结构æ¥å®žçŽ°çš„ï¼Œæ ‘çš„æ¯ä¸ªç»“点都是一个Vnode结构体,父å结点的关系以PathCache结构体ä¿å˜ã€‚VFS最主è¦çš„两个功能是: - 查找节点。 - ç»Ÿä¸€è°ƒç”¨ï¼ˆæ ‡å‡†ï¼‰ã€‚ ## è¿è¡Œæœºåˆ¶ 当å‰ï¼ŒVFS层主è¦é€šè¿‡å‡½æ•°æŒ‡é’ˆï¼Œå®žçް坹ä¸åŒæ–‡ä»¶ç³»ç»Ÿç±»åž‹è°ƒç”¨ä¸åŒæŽ¥å£å®žçŽ°æ ‡å‡†æŽ¥å£åŠŸèƒ½ï¼›é€šè¿‡Vnode与PathCache机制,æå‡è·¯å¾„æœç´¢ä»¥åŠæ–‡ä»¶è®¿é—®çš„æ€§èƒ½ï¼›é€šè¿‡æŒ‚载点管ç†è¿›è¡Œåˆ†åŒºç®¡ç†ï¼›é€šè¿‡FD管ç†è¿›è¡Œè¿›ç¨‹é—´FD隔离ç‰ã€‚下é¢å°†å¯¹è¿™äº›æœºåˆ¶è¿›è¡Œç®€è¦è¯´æ˜Žã€‚ 1. 文件系统æ“作函数指针:VFS层通过函数指针的形å¼ï¼Œå°†ç»Ÿä¸€è°ƒç”¨æŒ‰ç…§ä¸åŒçš„æ–‡ä»¶ç³»ç»Ÿç±»åž‹ï¼Œåˆ†å‘到ä¸åŒæ–‡ä»¶ç³»ç»Ÿä¸è¿›è¡Œåº•层æ“ä½œã€‚å„æ–‡ä»¶ç³»ç»Ÿçš„å„自实现一套Vnodeæ“ä½œã€æŒ‚载点æ“ä½œä»¥åŠæ–‡ä»¶æ“作接å£ï¼Œå¹¶ä»¥å‡½æ•°æŒ‡é’ˆç»“构体的形å¼å˜å‚¨äºŽå¯¹åº”Vnodeã€æŒ‚载点ã€File结构体ä¸ï¼Œå®žçްVFS层对下访问。 2. Vnode:Vnode是具体文件或目录在VFS层的抽象å°è£…,它å±è”½äº†ä¸åŒæ–‡ä»¶ç³»ç»Ÿçš„差异,实现资æºçš„统一管ç†ã€‚VnodeèŠ‚ç‚¹ä¸»è¦æœ‰ä»¥ä¸‹å‡ ç§ç±»åž‹ï¼š - 挂载点:挂载具体文件系统,如/ã€/storage - 设备节点:/dev目录下的节点,对应于一个设备,如/dev/mmcblk0 - 文件/目录节点:对应于具体文件系统ä¸çš„æ–‡ä»¶/目录,如/bin/init Vnode通过哈希以åŠLRU机制进行管ç†ã€‚当系统å¯åЍåŽï¼Œå¯¹æ–‡ä»¶æˆ–ç›®å½•çš„è®¿é—®ä¼šä¼˜å…ˆä»Žå“ˆå¸Œé“¾è¡¨ä¸æŸ¥æ‰¾Vnode缓å˜ï¼Œè‹¥ç¼“å˜æ²¡æœ‰å‘½ä¸ï¼Œåˆ™å¹¶ä»Žå¯¹åº”æ–‡ä»¶ç³»ç»Ÿä¸æœç´¢ç›®æ ‡æ–‡ä»¶æˆ–目录,创建并缓å˜å¯¹åº”çš„Vnode。当Vnodeç¼“å˜æ•°é‡è¾¾åˆ°ä¸Šé™æ—¶ï¼Œå°†æ·˜æ±°é•¿æ—¶é—´æœªè®¿é—®çš„Vnodeï¼Œå…¶ä¸æŒ‚载点Vnode与设备节点Vnodeä¸å‚与淘汰。当å‰ç³»ç»Ÿä¸Vnodeçš„è§„æ ¼é»˜è®¤ä¸º512ï¼Œè¯¥è§„æ ¼å¯ä»¥é€šè¿‡LOSCFG_MAX_VNODE_SIZE进行é…置。Vnodeæ•°é‡è¿‡å¤§ï¼Œä¼šé€ æˆè¾ƒå¤§çš„内å˜å 用;Vnodeæ•°é‡è¿‡å°‘ï¼Œåˆ™ä¼šé€ æˆæœç´¢æ€§èƒ½ä¸‹é™ã€‚下图展示了Vnode的创建æµç¨‹ã€‚ **图1** Vnode创建æµç¨‹  1. PathCache:PathCache是路径缓å˜ï¼Œå®ƒé€šè¿‡å“ˆå¸Œè¡¨å˜å‚¨ï¼Œåˆ©ç”¨çˆ¶èŠ‚ç‚¹Vnode的地å€å’Œå节点的文件å,å¯ä»¥ä»ŽPathCacheä¸å¿«é€ŸæŸ¥æ‰¾åˆ°å节点对应的Vnode。下图展示了文件/目录的查找æµç¨‹ã€‚ **图2** 文件查找æµç¨‹  1. PageCache:PageCacheæ˜¯å†…æ ¸ä¸æ–‡ä»¶çš„缓å˜ã€‚当å‰PageCache仅支æŒç¼“å˜äºŒè¿›åˆ¶æ–‡ä»¶ï¼Œåœ¨åˆæ¬¡è®¿é—®æ–‡ä»¶æ—¶é€šè¿‡mmapæ˜ å°„åˆ°å†…å˜ä¸ï¼Œä¸‹æ¬¡å†è®¿é—®æ—¶ï¼Œç›´æŽ¥ä»ŽPageCacheä¸è¯»å–,å¯ä»¥æå‡å¯¹åŒä¸€ä¸ªæ–‡ä»¶çš„读写速度。å¦å¤–基于PageCacheå¯å®žçŽ°ä»¥æ–‡ä»¶ä¸ºåŸºåº•çš„è¿›ç¨‹é—´é€šä¿¡ã€‚ 2. fd管ç†ï¼šFd(File Descriptor)是æè¿°ä¸€ä¸ªæ‰“开的文件/目录的æè¿°ç¬¦ã€‚当å‰OpenHarmonyå†…æ ¸ä¸ï¼Œfdæ€»è§„æ ¼ä¸º896,分为三ç§ç±»åž‹ï¼š - 普通文件æè¿°ç¬¦ï¼Œç³»ç»Ÿæ€»è§„æ ¼ä¸º512。 - Socketæè¿°ç¬¦ï¼Œç³»ç»Ÿæ€»è§„æ ¼ä¸º128。 - 消æ¯é˜Ÿåˆ—æè¿°ç¬¦ï¼Œç³»ç»Ÿæ€»è§„æ ¼ä¸º256。 当å‰OpenHarmonyå†…æ ¸ä¸ï¼Œå¯¹ä¸åŒè¿›ç¨‹ä¸çš„fd进行隔离,å³è¿›ç¨‹åªèƒ½è®¿é—®æœ¬è¿›ç¨‹çš„fd,所有进程的fdæ˜ å°„åˆ°å…¨å±€fd表ä¸è¿›è¡Œç»Ÿä¸€åˆ†é…管ç†ã€‚进程的文件æè¿°ç¬¦æœ€å¤šæœ‰256个。 3. 挂载点管ç†ï¼šå½“å‰OpenHarmonyå†…æ ¸ä¸ï¼Œå¯¹ç³»ç»Ÿä¸æ‰€æœ‰æŒ‚载点通过链表进行统一管ç†ã€‚挂载点结构体ä¸ï¼Œè®°å½•了该挂载分区内的所有Vnode。当分区å¸è½½æ—¶ï¼Œä¼šé‡Šæ”¾åˆ†åŒºå†…的所有Vnode。 ## 开呿Œ‡å¯¼ ### 接å£è¯´æ˜Ž 当剿–‡ä»¶ç³»ç»Ÿæ”¯æŒçš„æŽ¥å£å¦‚ä¸‹è¡¨æ‰€ç¤ºï¼Œè¡¨æ ¼ä¸çš„“×â€ä»£è¡¨å¯¹åº”æ–‡ä»¶ç³»ç»Ÿä¸æ”¯æŒè¯¥æŽ¥å£ã€‚ **表1** 文件æ“作 | 接å£**åç§°** | 功能 | FAT | JFFS2 | NFS | TMPFS | PROCFS | | -------- | -------- | -------- | -------- | -------- | -------- | -------- | | open | 打开文件 | √ | √ | √ | √ | √ | | read/pread/readv/preadv | è¯»å–æ–‡ä»¶ | √ | √ | √ | √ | √ | | write/pwrite/writev/pwritev | 写入文件 | √ | √ | √ | √ | √ | | lseek | 设置文件åç§» | √ | √ | √ | √ | × | | close | 关闿–‡ä»¶ | √ | √ | √ | √ | √ | | unlink | åˆ é™¤æ–‡ä»¶ | √ | √ | √ | √ | × | | fstat | æŸ¥è¯¢æ–‡ä»¶ä¿¡æ¯ | √ | √ | √ | √ | √ | | fallocate | 预分é…å¤§å° | √ | × | × | × | × | | truncate | æ–‡ä»¶æˆªæ– | √ | √ | × | √ | × | | link | 创建硬链接 | × | √ | × | × | × | | symlink | 创建软链接 | √ | √ | × | × | × | | readlink | 读å–软链接 | √ | √ | × | × | × | | dup | å¤åˆ¶æ–‡ä»¶å¥æŸ„ | √ | √ | √ | √ | √ | | fsync | 文件内容刷入设备 | √ | × | × | × | × | | ioctl | 设备控制 | × | × | × | √ | × | | fcntl | 文件控制æ“作 | √ | √ | √ | √ | √ | | mkdir | 创建目录 | √ | √ | √ | √ | × | | opendir | 打开目录 | √ | √ | √ | √ | √ | | readdir | 读å–目录 | √ | √ | √ | √ | √ | | closedir | å…³é—目录 | √ | √ | √ | √ | √ | | telldir | 获å–目录åç§» | √ | √ | √ | √ | √ | | seekdir | 设置目录åç§» | √ | √ | √ | √ | √ | | rewinddir | é‡ç½®ç›®å½•åç§» | √ | √ | √ | √ | × | | scandir | 读å–ç›®å½•æ•°æ® | √ | √ | √ | √ | √ | | rmdir | åˆ é™¤ç›®å½• | √ | √ | √ | √ | × | | chdir | 切æ¢å½“å‰è·¯å¾„ | √ | √ | √ | √ | √ | | getcwd | 获å–当å‰è·¯å¾„ | √ | √ | √ | √ | √ | | realpath | 相对/ç»å¯¹è·¯å¾„è½¬æ¢ | √ | √ | √ | √ | √ | | rename | 文件/目录é‡å‘½å | √ | √ | √ | √ | × | | chmod | 修改文件/目录属性 | √ | √ | × | × | × | | chown | 修改文件/目录所有者 | √ | √ | × | × | × | | stat/lstat | 查询文件/ç›®å½•ä¿¡æ¯ | √ | √ | √ | √ | √ | | access | 查询文件/目录访问æƒé™ | √ | √ | √ | √ | √ | | mount | 挂载分区 | √ | √ | √ | √ | √ | | umount | å¸è½½åˆ†åŒº | √ | √ | √ | √ | × | | statfs | æŸ¥è¯¢æŒ‚è½½åˆ†åŒºä¿¡æ¯ | √ | √ | √ | √ | √ | | format | æ ¼å¼åŒ–分区 | √ | × | × | × | × | | sync | 分区内容刷入设备 | √ | × | × | × | × | **表2** 目录æ“作 | 接å£**åç§°** | 功能 | FAT | JFFS2 | NFS | TMPFS | PROCFS | | -------- | -------- | -------- | -------- | -------- | -------- | -------- | | mkdir | 创建目录 | √ | √ | √ | √ | × | | opendir | 打开目录 | √ | √ | √ | √ | √ | | readdir | 读å–目录 | √ | √ | √ | √ | √ | | closedir | å…³é—目录 | √ | √ | √ | √ | √ | | telldir | 获å–目录åç§» | √ | √ | √ | √ | √ | | seekdir | 设置目录åç§» | √ | √ | √ | √ | √ | | rewinddir | é‡ç½®ç›®å½•åç§» | √ | √ | √ | √ | × | | scandir | 读å–ç›®å½•æ•°æ® | √ | √ | √ | √ | √ | | rmdir | åˆ é™¤ç›®å½• | √ | √ | √ | √ | × | | chdir | 切æ¢å½“å‰è·¯å¾„ | √ | √ | √ | √ | √ | | getcwd | 获å–当å‰è·¯å¾„ | √ | √ | √ | √ | √ | | realpath | 相对/ç»å¯¹è·¯å¾„è½¬æ¢ | √ | √ | √ | √ | √ | | rename | 文件/目录é‡å‘½å | √ | √ | √ | √ | × | | chmod | 修改文件/目录属性 | √ | √ | × | × | × | | chown | 修改文件/目录所有者 | √ | √ | × | × | × | | stat/lstat | 查询文件/ç›®å½•ä¿¡æ¯ | √ | √ | √ | √ | √ | | access | 查询文件/目录访问æƒé™ | √ | √ | √ | √ | √ | | mount | 挂载分区 | √ | √ | √ | √ | √ | | umount | å¸è½½åˆ†åŒº | √ | √ | √ | √ | × | | statfs | æŸ¥è¯¢æŒ‚è½½åˆ†åŒºä¿¡æ¯ | √ | √ | √ | √ | √ | | format | æ ¼å¼åŒ–分区 | √ | × | × | × | × | | sync | 分区内容刷入设备 | √ | × | × | × | × | **表3** 分区æ“作 | 接å£**åç§°** | 功能 | FAT | JFFS2 | NFS | TMPFS | PROCFS | | -------- | -------- | -------- | -------- | -------- | -------- | -------- | | mount | 挂载分区 | √ | √ | √ | √ | √ | | umount | å¸è½½åˆ†åŒº | √ | √ | √ | √ | × | | statfs | æŸ¥è¯¢æŒ‚è½½åˆ†åŒºä¿¡æ¯ | √ | √ | √ | √ | √ | | format | æ ¼å¼åŒ–分区 | √ | × | × | × | × | | sync | 分区内容刷入设备 | √ | × | × | × | × | ### 开呿µç¨‹ 文件系统的主è¦å¼€å‘æµç¨‹åŒ…括挂载/å¸è½½åˆ†åŒºï¼Œä»¥åŠç³»åˆ—目录/文件æ“作。 ### 编程实例 代ç 实现如下: ``` #include <stdio.h> #include <string.h> #include "sys/stat.h" #include "fcntl.h" #include "unistd.h" #define LOS_OK 0 #define LOS_NOK -1 int main(void) { int ret; int fd = -1; ssize_t len; off_t off; char mntName[20] = "/storage"; char devName[20] = "/dev/mmcblk0p0"; char dirName[20] = "/storage/test"; char fileName[20] = "/storage/test/file.txt"; char writeBuf[20] = "Hello OpenHarmony!"; char readBuf[20] = {0}; /* 创建目录“/storage†*/ ret = mkdir(mntName, 0777); if (ret != LOS_OK) { printf("mkdir failed.\n"); return LOS_NOK; } /* 挂载设备“/dev/mmcblk0p0â€åˆ°â€œ/storage†*/ ret = mount(devName, mntName, "vfat", 0, 0); if (ret != LOS_OK) { printf("mount failed.\n"); return LOS_NOK; } /* 创建目录“/storage/test†*/ ret = mkdir(dirName, 0777); if (ret != LOS_OK) { printf("mkdir failed.\n"); return LOS_NOK; } /* 创建å¯è¯»å†™æ–‡ä»¶â€œ/storage/test/file.txt†*/ fd = open(fileName, O_RDWR | O_CREAT, 0777); if (fd < 0) { printf("open file failed.\n"); return LOS_NOK; } /* å°†writeBufä¸çš„内容写入文件 */ len = write(fd, writeBuf, strlen(writeBuf)); if (len != strlen(writeBuf)) { printf("write file failed.\n"); return LOS_NOK; } /* 将文件内容刷入å˜å‚¨è®¾å¤‡ä¸ */ ret = fsync(fd); if (ret != LOS_OK) { printf("fsync failed.\n"); return LOS_NOK; } /* 将读写指针å移至文件头 */ off = lseek(fd, 0, SEEK_SET); if (off != 0) { printf("lseek failed.\n"); return LOS_NOK; } /* 将文件内容读出至readBufä¸ï¼Œè¯»å–长度为readBufå¤§å° */ len = read(fd, readBuf, sizeof(readBuf)); if (len != strlen(readBuf)) { printf("read file failed.\n"); return LOS_NOK; } printf("%s\n", readBuf); /* 关闿–‡ä»¶ */ ret = close(fd); if (ret != LOS_OK) { printf("close failed.\n"); return LOS_NOK; } /* åˆ é™¤æ–‡ä»¶â€œ/storage/test/file.txt†*/ ret = unlink(fileName); if (ret != LOS_OK) { printf("unlink failed.\n"); return LOS_NOK; } /* åˆ é™¤ç›®å½•â€œ/storage/test†*/ ret = rmdir(dirName); if (ret != LOS_OK) { printf("rmdir failed.\n"); return LOS_NOK; } /* å¸è½½åˆ†åŒºâ€œ/storage†*/ ret = umount(mntName); if (ret != LOS_OK) { printf("umount failed.\n"); return LOS_NOK; } /* åˆ é™¤ç›®å½•â€œ/storage†*/ ret = rmdir(mntName); if (ret != LOS_OK) { printf("rmdir failed.\n"); return LOS_NOK; } return LOS_OK; } ``` **结果验è¯** 编译è¿è¡Œå¾—到的结果为: ``` Hello OpenHarmony! ```