OpenHarmony - 小型系统内核(LiteOS-A)(五)
OpenHarmony - 小型系统内核(LiteOS-A)(五)
六、文件系统
虚拟文件系统
基本概念
VFS(Virtual File System)是文件系统的虚拟层,它不是一个实际的文件系统,而是一个异构文件系统之上的软件粘合层,为用户提供统一的类Unix文件操作接口。由于不同类型的文件系统接口不统一,若系统中有多个文件系统类型,访问不同的文件系统就需要使用不同的非标准接口。而通过在系统中添加VFS层,提供统一的抽象接口,屏蔽了底层异构类型的文件系统的差异,使得访问文件系统的系统调用不用关心底层的存储介质和文件系统类型,提高开发效率。
OpenHarmony内核中,VFS框架是通过在内存中的树结构来实现的,树的每个结点都是一个Vnode结构体,父子结点的关系以PathCache结构体保存。VFS最主要的两个功能是:
-
查找节点。
-
统一调用(标准)。
运行机制
当前,VFS层主要通过函数指针,实现对不同文件系统类型调用不同接口实现标准接口功能;通过Vnode与PathCache机制,提升路径搜索以及文件访问的性能;通过挂载点管理进行分区管理;通过FD管理进行进程间FD隔离等。下面将对这些机制进行简要说明。
-
文件系统操作函数指针:VFS层通过函数指针的形式,将统一调用按照不同的文件系统类型,分发到不同文件系统中进行底层操作。各文件系统的各自实现一套Vnode操作、挂载点操作以及文件操作接口,并以函数指针结构体的形式存储于对应Vnode、挂载点、File结构体中,实现VFS层对下访问。
-
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创建流程

-
PathCache:PathCache是路径缓存,它通过哈希表存储,利用父节点Vnode的地址和子节点的文件名,可以从PathCache中快速查找到子节点对应的Vnode。下图展示了文件/目录的查找流程。
图2 文件查找流程

-
PageCache:PageCache是内核中文件的缓存。当前PageCache仅支持缓存二进制文件,在初次访问文件时通过mmap映射到内存中,下次再访问时,直接从PageCache中读取,可以提升对同一个文件的读写速度。另外基于PageCache可实现以文件为基底的进程间通信。
-
fd管理:Fd(File Descriptor)是描述一个打开的文件/目录的描述符。当前OpenHarmony内核中,fd总规格为896,分为三种类型:
- 普通文件描述符,系统总规格为512。
- Socket描述符,系统总规格为128。
- 消息队列描述符,系统总规格为256。
当前OpenHarmony内核中,对不同进程中的fd进行隔离,即进程只能访问本进程的fd,所有进程的fd映射到全局fd表中进行统一分配管理。进程的文件描述符最多有256个。
-
挂载点管理:当前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 -1int 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!
相关文章:
OpenHarmony - 小型系统内核(LiteOS-A)(五)
OpenHarmony - 小型系统内核(LiteOS-A)(五) 六、文件系统 虚拟文件系统 基本概念 VFS(Virtual File System)是文件系统的虚拟层,它不是一个实际的文件系统,而是一个异构文件系统之…...
PyTorch进阶学习笔记[长期更新]
第一章 PyTorch简介和安装 PyTorch是一个很强大的深度学习库,在学术中使用占比很大。 我这里是Mac系统的安装,相比起教程中的win/linux安装感觉还是简单不少(之前就已经安好啦),有需要指导的小伙伴可以评论。 第二章…...
proteus8.17 环境配置
Proteus介绍 Proteus 8.17 是一款功能强大的电子设计自动化(EDA)软件,广泛应用于电子电路设计、仿真和分析。以下是其主要特点和新功能: ### 主要功能 - **电路仿真**:支持数字和模拟电路的仿真,包括静态…...
Microsoft SQL Server Management 一键删除数据库所有外键
DECLARE ESQL VARCHAR(1000); DECLARE FCursor CURSOR --定义游标 FOR (SELECT ALTER TABLE O.name DROP CONSTRAINT F.name; AS CommandSQL from SYS.FOREIGN_KEYS F JOIN SYS.ALL_OBJECTS O ON F.PARENT_OBJECT_ID O.OBJECT_ID WHERE O.TYPE U AND F.TYPE …...
【JAVAFX】自定义FXML 文件存放的位置以及使用
情况 1:FXML 文件与调用类在同一个包中(推荐) 假设类 MainApp 的包是 com.example,且 FXML 文件放在 resources/com/example 下: 项目根目录 ├── src │ └── sample │ └── Main.java ├── src/s…...
Oracle 如何停止正在运行的 Job
Oracle 如何停止正在运行的 Job 先了解是dbms_job 还是 dbms_scheduler,再确定操作命令。 一 使用 DBMS_JOB 包停止作业(适用于旧版 Job) 1.1 查看正在运行的 Job SELECT job, what, this_date, this_sec, failures, broken FROM user_j…...
高级语言调用C接口(四)结构体(2)-Python
这个专栏好久没有更新了,主要是坑开的有点大,也不知道怎么填,涉及到的开发语言比较多,写起来比较累,需要看的人其实并不多,只能说,慢慢填吧,中间肯定还会插很多别的东西,…...
Java对接Dify API接口完整指南
Java对接Dify API接口完整指南 一、Dify API简介 Dify是一款AI应用开发平台,提供多种自然语言处理能力。通过调用Dify开放API,开发者可以快速集成智能对话、文本生成等功能到自己的Java应用中。 二、准备工作 获取API密钥 登录Dify平台控制台在「API密…...
极狐GitLab GEO 功能介绍
极狐GitLab 是 GitLab 在中国的发行版,关于中文参考文档和资料有: 极狐GitLab 中文文档极狐GitLab 中文论坛极狐GitLab 官网 Geo (PREMIUM SELF) Geo 是广泛分布的开发团队的解决方案,可作为灾难恢复策略的一部分提供热备份。Geo 不是 开箱…...
Nginx-前言
nginx是什么? 轻量级,开源免费的web服务器软件,服务器安装nginx,服务器则成为web服务器 nginx的稳定版版本号: 偶数版本 nginx的相关目录: /etc/nginx/nginx.conf nginx的主配置文件 /etc/nginx/ngi…...
LFI to RCE
LFI不止可以来读取文件,还能用来RCE 在多道CTF题目中都有LFItoRCE的非预期解,下面总结一下LFI的利用姿势 1. /proc/self/environ 利用 条件:目标能读取 /proc/self/environ,并且网页中存在LFI点 利用方式: 修改请…...
云原生(Cloud Native)的详解、开发流程及同类软件对比
以下是云原生(Cloud Native)的详解、开发流程及同类软件对比: 一、云原生核心概念 定义: 云原生(Cloud Native)是基于云环境设计和运行应用程序的方法论,强调利用云平台的弹性、分布式和自动化…...
全局唯一标识符(UID)生成策略
目录 一、UUID 二、雪花算法 三、时间戳 随机数 四、利用数据库的自增字段 五、 基于 Redis 的原子操作 总结 在信息系统中,生成唯一ID是非常常见的需求,尤其是在分布式系统或高并发场景下。以下是几种常见的生成唯一ID的算法或方式: …...
学习笔记:减速机工作原理
学习笔记:减速机工作原理 一、减速机图片二、减速比概念三、减速机的速比与扭矩之间的关系四、题外内容--电机扭矩 一、减速机图片 二、减速比概念 即减速装置的传动比,是传动比的一种,是指减速机构中,驱动轴与被驱动轴瞬时输入速…...
《UE5_C++多人TPS完整教程》学习笔记36 ——《P37 拾取组件(Pickup Widget)》
本文为B站系列教学视频 《UE5_C多人TPS完整教程》 —— 《P37 拾取组件(Pickup Widget)》 的学习笔记,该系列教学视频为计算机工程师、程序员、游戏开发者、作家(Engineer, Programmer, Game Developer, Author) Steph…...
《空间复杂度(C语言)》
文章目录 前言一、什么是空间复杂度?通俗理解: 二、空间复杂度的数学定义三、常见空间复杂度举例(含C语言代码)🔹 O(1):常数空间🔹 O(n):线性空间🔹 O(n^2):平…...
Kaggle-Store Sales-(回归+多表合并+xgboost模型)
Store Sales 题意: 给出很多商店,给出商店的类型,某时某刻卖了多少销售额。 给出了油价表,假期表,进货表。 让你求出测试集合中每个商店的销售额是多少。 数据处理: 1.由于是多表,所以要先把其他表与tr…...
在 Tailwind CSS 中优雅地隐藏滚动条
在开发中,我们经常需要隐藏滚动条但保持滚动功能,这在构建现代化的用户界面时很常见。 本文将介绍两种在 Tailwind CSS 项目中实现这一目标的方法,方便同学们记录和查阅。 方法一:使用 tailwind-scrollbar-hide 插件 这是一种更…...
智能合约安全审计平台——以太坊虚拟机安全沙箱
目录 以太坊虚拟机安全沙箱 —— 理论、设计与实战1. 引言2. 理论背景与安全原理2.1 以太坊虚拟机(EVM)概述2.2 安全沙箱的基本概念2.3 安全证明与形式化验证3. 系统架构与模块设计3.1 模块功能说明3.2 模块之间的数据流与安全性4. 安全性与密码学考量4.1 密码学保障在沙箱中…...
std::unordered_map(C++)
std::unordered_map 1. 概述2. 内部实现3. 性能特征4. 常用 API5. 使用示例6. 自定义哈希与相等比较7. 注意事项与优化8. 使用建议9. emplace和insert异同相同点不同点例子对比何时优先使用哪种? 1. 概述 定义:std::unordered_map<Key, T, Hash, KeyE…...
【MCP教程】Claude Desktop 如何连接部署在远程的remote mcp server服务器(remote host)
前言 最近MCP特别火热,笔者自己也根据官方文档尝试了下。 官方文档给的Demo是在本地部署一个weather.py,然后用本地的Claude Desktop去访问该mcp服务器,从而完成工具的调用: 但是,问题来了,Claude Deskto…...
Android Input——输入事件回调完成(十四)
前面几篇文章介绍了事件回调的相关流程,以及回调事件处理函数的相关内容,最后我们再来看一下事件处理完后,如何通知 InputDispatcher 去回调 Callback。 一、客户端回调 在 Android 的事件分发机制中,当客户端(即应用层)完成事件处理后,最终会调用 ViewRootImpl 的 fin…...
数据通信学习笔记之OSPF配置命令
华为 [huawei]ospf 10 router-id 1.1.1.1 //创建ospf进程,本地有效area 1 // 进入区域1network 192.168.1.0 0.0.0.255 // 宣告网段,使用反掩码stub // 配置为stub区域stub no-summary // 配置为Totally Stub 完全末节区域。在ABR上配置࿰…...
Python -yield 在python 中什么意思
在 Python 中,yield 是一个关键字,用于定义生成器函数(generator function)。它的作用是将一个普通函数转变为可迭代的生成器,具有惰性计算的特性。以下是关键要点: 核心概念 生成器函数: 当函数…...
多个路由器互通(静态路由)无单臂路由(简单版)
多个路由器互通(静态路由)无单臂路由(简单版) 开启端口并配ip地址 维护1 Router>en Router#conf t Router(config)#int g0/0 Router(config-if)#no shutdown Router(config-if)#ip address 192.168.10.254 255.255.255.0 Ro…...
OpenCV 图形API(38)图像滤波-----Sobel 算子操作函数Sobel()
操作系统:ubuntu22.04 OpenCV版本:OpenCV4.9 IDE:Visual Studio Code 编程语言:C11 算法描述 cv::gapi::Sobel 函数是 OpenCV 的 G-API 模块中用于执行 Sobel 算子操作的一个函数,主要用于图像的边缘检测。Sobel 算子通过计算图…...
3DS 转 STL 全攻略:传统工具与迪威模型网在线转换深度解析
在 3D 建模与 3D 打印的技术领域中,常常会遇到需要将不同格式的文件进行转换的情况。其中,把 3DS 文件转换为 STL 格式是较为常见的操作。3DS 文件作为一种旧版 Autodesk 3D Studio 使用的 3D 图像格式,存储着丰富的信息,包括网格…...
windows系统安装驱动、cuda和cudnn
一、首先在自己的电脑里安装了nvidia的独立显卡 显卡的查找方式: CtrlShiftEsc打开任务管理器,点击性能,点击GPU 0查看显卡型号,如下图所示: 只要电脑中有nvidia的独立显卡,就可以暗转显卡驱动、cuda和cu…...
嵌入式开发--STM32软件和硬件CRC的使用--续篇
本文是《嵌入式开发–STM32软件和硬件CRC的使用》的续篇,又踩到一个坑,发出来让大家避一下坑。 按照G0系列的设置,得出错误的结果 前文对应的是STM32G0系列,今天在用STM32G4系列时,按照前文的设置,用硬件…...
2.深入剖析 Rust+Axum 类型安全路由系统
摘要 详细解读 RustAxum 路由系统的关键设计原理,涵盖基于 Rust 类型系统的路由匹配机制、动态路径参数与正则表达式验证以及嵌套路由与模块化组织等多种特性。 一、引言 在现代 Web 开发中,路由系统是构建 Web 应用的核心组件之一,它负责…...
