开始文件系统注解,从 vnode 开始 ...

    百万汉字注解 + 百篇博客分析 => 挖透鸿蒙内核源码
    国内:https://weharmony.gitee.io
    国外:https://weharmony.github.io
上级 cc1f411f
......@@ -33,8 +33,8 @@
#include "los_list.h"
typedef LOS_DL_LIST LIST_HEAD;
typedef LOS_DL_LIST LIST_ENTRY;
typedef LOS_DL_LIST LIST_HEAD; //这是要向 linux学习吗? : )
typedef LOS_DL_LIST LIST_ENTRY;
#define FNV1_32_INIT ((uint32_t) 33554467UL)
#define FNV1_64_INIT ((uint64_t) 0xcbf29ce484222325ULL)
......
......@@ -40,65 +40,84 @@
#define VNODE_FLAG_MOUNT_NEW 1
#define VNODE_FLAG_MOUNT_ORIGIN 2
#define DEV_PATH_LEN 5
/*
Linux 链接分两种,一种被称为硬链接(Hard Link),另一种被称为符号链接(Symbolic Link)。默认情况下,ln 命令产生硬链接。
硬连接
硬连接指通过索引节点来进行连接。在 Linux 的文件系统中,保存在磁盘分区中的文件不管是什么类型都给它分配一个编号,
称为索引节点号(Inode Index)。在 Linux 中,多个文件名指向同一索引节点是存在的。比如:A 是 B 的硬链接(A 和 B 都是文件名),
则 A 的目录项中的 inode 节点号与 B 的目录项中的 inode 节点号相同,即一个 inode 节点对应两个不同的文件名,两个文件名指向同一个文件,
A 和 B 对文件系统来说是完全平等的。删除其中任何一个都不会影响另外一个的访问。
硬连接的作用是允许一个文件拥有多个有效路径名,这样用户就可以建立硬连接到重要文件,以防止“误删”的功能。其原因如上所述,
因为对应该目录的索引节点有一个以上的连接。只删除一个连接并不影响索引节点本身和其它的连接,只有当最后一个连接被删除后,
文件的数据块及目录的连接才会被释放。也就是说,文件真正删除的条件是与之相关的所有硬连接文件均被删除。
软连接
另外一种连接称之为符号连接(Symbolic Link),也叫软连接。软链接文件有类似于 Windows 的快捷方式。
它实际上是一个特殊的文件。在符号连接中,文件实际上是一个文本文件,其中包含的有另一文件的位置信息。
比如:A 是 B 的软链接(A 和 B 都是文件名),A 的目录项中的 inode 节点号与 B 的目录项中的 inode 节点号不相同,
A 和 B 指向的是两个不同的 inode,继而指向两块不同的数据块。但是 A 的数据块中存放的只是 B 的路径名(可以根据这个找到 B 的目录项)。
A 和 B 之间是“主从”关系,如果 B 被删除了,A 仍然存在(因为两个是不同的文件),但指向的是一个无效的链接。
*/
/*
* Vnode types. VNODE_TYPE_UNKNOWN means no type.
*/
enum VnodeType {
VNODE_TYPE_UNKNOWN, /* unknown type */
VNODE_TYPE_REG, /* regular fle */
VNODE_TYPE_DIR, /* directory */
VNODE_TYPE_BLK, /* block device */
VNODE_TYPE_CHR, /* char device */
VNODE_TYPE_BCHR, /* block char mix device */
VNODE_TYPE_FIFO, /* pipe */
VNODE_TYPE_LNK, /* link */
enum VnodeType {//节点类型
VNODE_TYPE_UNKNOWN, /* unknown type */ //未知类型
VNODE_TYPE_REG, /* regular file */ //正则文件(普通文件)
VNODE_TYPE_DIR, /* directory */ //目录
VNODE_TYPE_BLK, /* block device */ //块设备
VNODE_TYPE_CHR, /* char device */ //字符设备
VNODE_TYPE_BCHR, /* block char mix device *///块和字符设备混合
VNODE_TYPE_FIFO, /* pipe */ //管道文件
VNODE_TYPE_LNK, /* link */ //链接,这里的链接指的是上层硬链接概念
};
struct fs_dirent_s;
struct VnodeOps;
struct IATTR;
//linux下有多种权限控制的机制,常见的有:DAC(Discretionary Access Control)自主式权限控制和MAC(Mandatory Access Control)强制访问控制。
//linux 下使用 inode 中文意思是索引节点(index node),从概念层面鸿蒙 Vnode是对标 inode
struct Vnode {
enum VnodeType type; /* vnode type */
int useCount; /* ref count of users */
uint32_t hash; /* vnode hash */
uint uid; /* uid for dac */
uint gid; /* gid for dac */
mode_t mode; /* mode for dac */
LIST_HEAD parentPathCaches; /* pathCaches point to parents */
LIST_HEAD childPathCaches; /* pathCaches point to children */
struct Vnode *parent; /* parent vnode */
struct VnodeOps *vop; /* vnode operations */
struct file_operations_vfs *fop; /* file operations */
void *data; /* private data */
uint32_t flag; /* vnode flag */
LIST_ENTRY hashEntry; /* list entry for bucket in hash table */
LIST_ENTRY actFreeEntry; /* vnode active/free list entry */
struct Mount *originMount; /* fs info about this vnode */
struct Mount *newMount; /* fs info about who mount on this vnode */
enum VnodeType type; /* vnode type */ //节点类型
int useCount; /* ref count of users *///节点引用数,即有多少文件名指向这个vnode
uint32_t hash; /* vnode hash */ //节点哈希值
uint uid; /* uid for dac */ //DAC用户ID
uint gid; /* gid for dac */ //DAC用户组ID
mode_t mode; /* mode for dac */ //DAC的模式
LIST_HEAD parentPathCaches; /* pathCaches point to parents */ //指向父级路径缓存,上面的都是当了爸爸节点
LIST_HEAD childPathCaches; /* pathCaches point to children */ //指向子级路径缓存,上面都是当了别人儿子的节点
struct Vnode *parent; /* parent vnode */ //父节点
struct VnodeOps *vop; /* vnode operations */ //节点虚拟操作
struct file_operations_vfs *fop; /* file operations */ //虚拟 <--> 真实的文件系统操作
void *data; /* private data */ //私有数据
uint32_t flag; /* vnode flag */ //节点标签
LIST_ENTRY hashEntry; /* list entry for bucket in hash table */ //挂入哈希表 g_vnodeHashEntrys
LIST_ENTRY actFreeEntry; /* vnode active/free list entry */ //通过本节点挂到空闲链表和使用链表上
struct Mount *originMount; /* fs info about this vnode */ //关于这个节点的挂载信息
struct Mount *newMount; /* fs info about who mount on this vnode */ //挂载在这个节点上的文件系统
};
//
struct VnodeOps {
int (*Create)(struct Vnode *parent, const char *name, int mode, struct Vnode **vnode);
int (*Lookup)(struct Vnode *parent, const char *name, int len, struct Vnode **vnode);
int (*Open)(struct Vnode *vnode, int fd, int mode, int flags);
int (*Close)(struct Vnode *vnode);
int (*Reclaim)(struct Vnode *vnode);
int (*Unlink)(struct Vnode *parent, struct Vnode *vnode, char *fileName);
int (*Rmdir)(struct Vnode *parent, struct Vnode *vnode, char *dirName);
int (*Mkdir)(struct Vnode *parent, const char *dirName, mode_t mode, struct Vnode **vnode);
int (*Readdir)(struct Vnode *vnode, struct fs_dirent_s *dir);
int (*Opendir)(struct Vnode *vnode, struct fs_dirent_s *dir);
int (*Rewinddir)(struct Vnode *vnode, struct fs_dirent_s *dir);
int (*Closedir)(struct Vnode *vnode, struct fs_dirent_s *dir);
int (*Getattr)(struct Vnode *vnode, struct stat *st);
int (*Setattr)(struct Vnode *vnode, struct stat *st);
int (*Chattr)(struct Vnode *vnode, struct IATTR *attr);
int (*Rename)(struct Vnode *src, struct Vnode *dstParent, const char *srcName, const char *dstName);
int (*Truncate)(struct Vnode *vnode, off_t len);
int (*Truncate64)(struct Vnode *vnode, off64_t len);
int (*Fscheck)(struct Vnode *vnode, struct fs_dirent_s *dir);
int (*Create)(struct Vnode *parent, const char *name, int mode, struct Vnode **vnode);//创建
int (*Lookup)(struct Vnode *parent, const char *name, int len, struct Vnode **vnode);//查询
int (*Open)(struct Vnode *vnode, int fd, int mode, int flags);//打开
int (*Close)(struct Vnode *vnode);//关闭
int (*Reclaim)(struct Vnode *vnode);//回收
int (*Unlink)(struct Vnode *parent, struct Vnode *vnode, char *fileName);//取消链接
int (*Rmdir)(struct Vnode *parent, struct Vnode *vnode, char *dirName);//删除目录
int (*Mkdir)(struct Vnode *parent, const char *dirName, mode_t mode, struct Vnode **vnode);//创建目录
int (*Readdir)(struct Vnode *vnode, struct fs_dirent_s *dir);//读目录
int (*Opendir)(struct Vnode *vnode, struct fs_dirent_s *dir);//打开目录
int (*Rewinddir)(struct Vnode *vnode, struct fs_dirent_s *dir);//定位目录函数
int (*Closedir)(struct Vnode *vnode, struct fs_dirent_s *dir);//关闭目录
int (*Getattr)(struct Vnode *vnode, struct stat *st);//获取节点属性
int (*Setattr)(struct Vnode *vnode, struct stat *st);//设置节点属性
int (*Chattr)(struct Vnode *vnode, struct IATTR *attr);//改变节点属性(change attr)
int (*Rename)(struct Vnode *src, struct Vnode *dstParent, const char *srcName, const char *dstName);//重命名
int (*Truncate)(struct Vnode *vnode, off_t len);//缩减或扩展大小
int (*Truncate64)(struct Vnode *vnode, off64_t len);//缩减或扩展大小
int (*Fscheck)(struct Vnode *vnode, struct fs_dirent_s *dir);//检查功能
};
typedef int VfsHashCmp(struct Vnode *vnode, void *arg);
......
......@@ -42,7 +42,21 @@
#include "unistd.h"
#include "fs/vfs_util.h"
#include "fs/vnode.h"
/*
* VFS是Virtual File System(虚拟文件系统)的缩写,它不是一个实际的文件系统,而是一个异构文件系统之上的软件粘合层,
* 为用户提供统一的类Unix文件操作接口。
* 由于不同类型的文件系统接口不统一,若系统中有多个文件系统类型,访问不同的文件系统就需要使用不同的非标准接口。
* 而通过在系统中添加VFS层,提供统一的抽象接口,屏蔽了底层异构类型的文件系统的差异,使得访问文件系统的系统调用不用
* 关心底层的存储介质和文件系统类型,提高开发效率。
* OpenHarmony内核中,VFS框架是通过在内存中的树结构来实现的,树的每个结点都是一个inode结构体。
* 设备注册和文件系统挂载后会根据路径在树中生成相应的结点。VFS最主要是两个功能:
* 查找节点。
* 统一调用(标准)。
* https://weharmony.gitee.io/openharmony/zh-cn/device-dev/kernel/VFS.html
*/
void los_vfs_init(void)
{
uint retval;
......
......@@ -37,7 +37,7 @@
#define PATH_CACHE_HASH_MASK (LOSCFG_MAX_PATH_CACHE_SIZE - 1)
LIST_HEAD g_pathCacheHashEntrys[LOSCFG_MAX_PATH_CACHE_SIZE];
//路径缓存初始化
int PathCacheInit(void)
{
for (int i = 0; i < LOSCFG_MAX_PATH_CACHE_SIZE; i++) {
......@@ -198,7 +198,7 @@ static void FreeParentPathCache(struct Vnode *vnode)
PathCacheFree(item);
}
}
//和长辈,晚辈告别,从此不再是父亲和孩子.
void VnodePathCacheFree(struct Vnode *vnode)
{
if (vnode == NULL) {
......
......@@ -34,42 +34,60 @@
#include "fs/dirent_fs.h"
#include "fs_other.h"
LIST_HEAD g_vnodeFreeList; /* free vnodes list */
LIST_HEAD g_vnodeVirtualList; /* dev vnodes list */
LIST_HEAD g_vnodeCurrList; /* inuse vnodes list */
static int g_freeVnodeSize = 0; /* system free vnodes size */
static int g_totalVnodeSize = 0; /* total vnode size */
static LosMux g_vnodeMux;
static struct Vnode *g_rootVnode = NULL;
static struct VnodeOps g_devfsOps;
#define ENTRY_TO_VNODE(ptr) LOS_DL_LIST_ENTRY(ptr, struct Vnode, actFreeEntry)
#define VNODE_LRU_COUNT 10
#define DEV_VNODE_MODE 0755
LIST_HEAD g_vnodeFreeList; /* free vnodes list */ //空闲节点链表
LIST_HEAD g_vnodeVirtualList; /* dev vnodes list */ //虚拟设备节点链表,暂无实际的文件系统
LIST_HEAD g_vnodeCurrList; /* inuse vnodes list */ //非虚拟设备的节点链表,有实际的文件系统(如:FAT)
static int g_freeVnodeSize = 0; /* system free vnodes size */ //剩余节点数量
static int g_totalVnodeSize = 0; /* total vnode size */ //总节点数量
static LosMux g_vnodeMux; //操作链表互斥量
static struct Vnode *g_rootVnode = NULL;//根节点
static struct VnodeOps g_devfsOps;//节点操作
#define ENTRY_TO_VNODE(ptr) LOS_DL_LIST_ENTRY(ptr, struct Vnode, actFreeEntry) //通过局部(actFreeEntry)找到整体(Vnode)
#define VNODE_LRU_COUNT 10 //最多回收数量
#define DEV_VNODE_MODE 0755 //0755可不是深圳的意思哈,而是节点的权限,对照以下注释理解
/*
#ifndef S_IRUSR
#define S_ISUID 04000
#define S_ISGID 02000
#define S_ISVTX 01000
#define S_IRUSR 0400
#define S_IWUSR 0200
#define S_IXUSR 0100
#define S_IRWXU 0700
#define S_IRGRP 0040
#define S_IWGRP 0020
#define S_IXGRP 0010
#define S_IRWXG 0070
#define S_IROTH 0004
#define S_IWOTH 0002
#define S_IXOTH 0001
#define S_IRWXO 0007
#endif
*/
int VnodesInit(void)
{
int retval = LOS_MuxInit(&g_vnodeMux, NULL);
int retval = LOS_MuxInit(&g_vnodeMux, NULL);//初始化操作vnode链表的互斥量
if (retval != LOS_OK) {
PRINT_ERR("Create mutex for vnode fail, status: %d", retval);
return retval;
}
LOS_ListInit(&g_vnodeFreeList);
LOS_ListInit(&g_vnodeVirtualList);
LOS_ListInit(&g_vnodeCurrList);
retval = VnodeAlloc(NULL, &g_rootVnode);
LOS_ListInit(&g_vnodeFreeList); //初始化空闲的节点链表
LOS_ListInit(&g_vnodeVirtualList); //初始化虚拟设备节点链表
LOS_ListInit(&g_vnodeCurrList); //初始化当前(已在使用)的节点链表
retval = VnodeAlloc(NULL, &g_rootVnode);//分配根节点
if (retval != LOS_OK) {
PRINT_ERR("VnodeInit failed error %d\n", retval);
return retval;
}
g_rootVnode->mode = S_IRWXU | S_IRWXG | S_IRWXO | S_IFDIR;
g_rootVnode->type = VNODE_TYPE_DIR;
g_rootVnode->mode = S_IRWXU | S_IRWXG | S_IRWXO | S_IFDIR;// 40777 (chmod 777)
g_rootVnode->type = VNODE_TYPE_DIR;//节点类型为目录
return LOS_OK;
}
//获取空闲节点链表,分配的节点从空闲链表里出
static struct Vnode *GetFromFreeList(void)
{
if (g_freeVnodeSize <= 0) {
......@@ -84,44 +102,44 @@ static struct Vnode *GetFromFreeList(void)
}
vnode = ENTRY_TO_VNODE(LOS_DL_LIST_FIRST(&g_vnodeFreeList));
LOS_ListDelete(&vnode->actFreeEntry);
LOS_ListDelete(&vnode->actFreeEntry);//从空闲链表上摘出去.
g_freeVnodeSize--;
return vnode;
}
//节点批量回收, LRU是Least Recently Used的缩写,即最近最少使用,
struct Vnode *VnodeReclaimLru(void)
{
struct Vnode *item = NULL;
struct Vnode *nextItem = NULL;
int releaseCount = 0;
//遍历链表
LOS_DL_LIST_FOR_EACH_ENTRY_SAFE(item, nextItem, &g_vnodeCurrList, struct Vnode, actFreeEntry) {
if ((item->useCount > 0) ||
(item->flag & VNODE_FLAG_MOUNT_ORIGIN) ||
(item->flag & VNODE_FLAG_MOUNT_NEW)) {
if ((item->useCount > 0) || //还有链接数
(item->flag & VNODE_FLAG_MOUNT_ORIGIN) || //原来是个mount节点
(item->flag & VNODE_FLAG_MOUNT_NEW)) { //是个新mount节点
continue;
}
if (VnodeFree(item) == LOS_OK) {
if (VnodeFree(item) == LOS_OK) {//正式回收,其实就是将自己从链表上摘出去,再挂到空闲链表上.
releaseCount++;
}
if (releaseCount >= VNODE_LRU_COUNT) {
if (releaseCount >= VNODE_LRU_COUNT) {//一次最多回收量
break;
}
}
if (releaseCount == 0) {
if (releaseCount == 0) {//回收失败
PRINT_ERR("VnodeAlloc failed, vnode size hit max but can't reclaim anymore!\n");
return NULL;
}
item = GetFromFreeList();
item = GetFromFreeList();//获取一个空闲节点
if (item == NULL) {
PRINT_ERR("VnodeAlloc failed, reclaim and get from free list failed!\n");
}
return item;
}
//申请分配一个 vnode 节点
int VnodeAlloc(struct VnodeOps *vop, struct Vnode **newVnode)
{
struct Vnode* vnode = NULL;
......@@ -133,26 +151,26 @@ int VnodeAlloc(struct VnodeOps *vop, struct Vnode **newVnode)
g_totalVnodeSize++;
}
if (vnode == NULL) {
vnode = VnodeReclaimLru();
if (vnode == NULL) {//没有分配到节点
vnode = VnodeReclaimLru();//执行回收算法,释放节点
}
if (vnode == NULL) {
if (vnode == NULL) {//回收也没有可用节点
*newVnode = NULL;
VnodeDrop();
return -ENOMEM;
return -ENOMEM;//分配失败,返回
}
vnode->type = VNODE_TYPE_UNKNOWN;
LOS_ListInit((&(vnode->parentPathCaches)));
LOS_ListInit((&(vnode->childPathCaches)));
LOS_ListInit((&(vnode->hashEntry)));
LOS_ListInit((&(vnode->actFreeEntry)));
vnode->type = VNODE_TYPE_UNKNOWN; //节点默认类型,未知
LOS_ListInit((&(vnode->parentPathCaches)));//后续可能要当爸爸,做好准备
LOS_ListInit((&(vnode->childPathCaches)));//后续可能要当儿子,做好准备
LOS_ListInit((&(vnode->hashEntry))); //用它挂到全局哈希表上
LOS_ListInit((&(vnode->actFreeEntry))); //用它挂到全局正使用节点链表上
if (vop == NULL) {
LOS_ListAdd(&g_vnodeVirtualList, &(vnode->actFreeEntry));
if (vop == NULL) {//
LOS_ListAdd(&g_vnodeVirtualList, &(vnode->actFreeEntry));//挂到虚拟设备
vnode->vop = &g_devfsOps;
} else {
} else {//如果已有指定的文件系统(FAT),直接绑定
LOS_ListTailInsert(&g_vnodeCurrList, &(vnode->actFreeEntry));
vnode->vop = vop;
}
......@@ -162,32 +180,32 @@ int VnodeAlloc(struct VnodeOps *vop, struct Vnode **newVnode)
return LOS_OK;
}
//是否 vnode 节点
int VnodeFree(struct Vnode *vnode)
{
if (vnode == NULL) {
return LOS_OK;
}
VnodeHold();
if (vnode->useCount > 0) {
VnodeHold();//拿互斥锁
if (vnode->useCount > 0) {//还有引用数,或者叫链接数.这里的链接数指的是还有硬链接没删除的情况
VnodeDrop();
return -EBUSY;
return -EBUSY;//返回设备或资源忙着呢.
}
VnodePathCacheFree(vnode);
LOS_ListDelete(&(vnode->hashEntry));
LOS_ListDelete(&vnode->actFreeEntry);
VnodePathCacheFree(vnode);//节点和父亲,孩子告别
LOS_ListDelete(&(vnode->hashEntry));//将自己从当前哈希链表上摘出来,此时vnode通过hashEntry挂在 g_vnodeHashEntrys
LOS_ListDelete(&vnode->actFreeEntry);//将自己从当前链表摘出来,此时vnode通过actFreeEntry挂在 g_vnodeCurrList
if (vnode->vop->Reclaim) {
vnode->vop->Reclaim(vnode);
}
memset_s(vnode, sizeof(struct Vnode), 0, sizeof(struct Vnode));
LOS_ListAdd(&g_vnodeFreeList, &vnode->actFreeEntry);
LOS_ListAdd(&g_vnodeFreeList, &vnode->actFreeEntry);//通过 actFreeEntry链表节点挂到 空闲链表上.
g_freeVnodeSize++;
VnodeDrop();
VnodeDrop();//释放互斥锁
return LOS_OK;
}
......
......@@ -123,7 +123,7 @@ void VfsHashRemove(struct Vnode *vnode)
LOS_ListDelete(&vnode->hashEntry);
(void)LOS_MuxUnlock(&g_vnodeHashMux);
}
//插入哈希表
int VfsHashInsert(struct Vnode *vnode, uint32_t hash)
{
if (vnode == NULL) {
......
git add -A
git commit -m ' 2021/6/08 同步官方 -- 本次官方对编译构建,任务,信号模块有较大的改动.
git commit -m ' 开始文件系统注解,从 vnode 开始 ...
百万汉字注解 + 百篇博客分析 => 挖透鸿蒙内核源码
国内:https://weharmony.gitee.io
国外:https://weharmony.github.io
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册