开始文件系统注解,mount mtd flash 注解

    百万汉字注解 + 百篇博客分析 => 挖透鸿蒙内核源码
    国内:https://weharmony.gitee.io
    国外:https://weharmony.github.io
上级 9ae5bab5
......@@ -202,6 +202,8 @@ static int fatfs_sync(unsigned long mountflags, FATFS *fs)
#endif
return 0;
}
//哈希值比较函数,返回int
//typedef int VfsHashCmp(struct Vnode *vnode, void *arg);
int fatfs_hash_cmp(struct Vnode *vp, void *arg)
{
DIR_FILE *dfp_target = (DIR_FILE *)arg;
......@@ -211,7 +213,7 @@ int fatfs_hash_cmp(struct Vnode *vp, void *arg)
dfp_target->f_dir.dptr != dfp->f_dir.dptr ||
dfp_target->fno.sclst != dfp->fno.sclst;
}
//生成hash值的过程
static DWORD fatfs_hash(QWORD sect, DWORD dptr, DWORD sclst)
{
DWORD hash = FNV1_32_INIT;
......@@ -236,7 +238,7 @@ static mode_t fatfs_get_mode(BYTE attribute, mode_t fs_mode)
}
return fs_mode;
}
// fat文件系统对 Lookup 接口的实现
int fatfs_lookup(struct Vnode *parent, const char *path, int len, struct Vnode **vpp)
{
struct Vnode *vp = NULL;
......
......@@ -38,26 +38,30 @@
#include <limits.h>
struct MountOps;
struct Mount {
LIST_ENTRY mountList; /* mount list */
const struct MountOps *ops; /* operations of mount */
struct Vnode *vnodeBeCovered; /* vnode we mounted on */
struct Vnode *vnodeCovered; /* syncer vnode */
LIST_HEAD vnodeList; /* list of vnodes */
int vnodeSize; /* size of vnode list */
LIST_HEAD activeVnodeList; /* list of active vnodes */
int activeVnodeSize; /* szie of active vnodes list */
void *data; /* private data */
uint32_t hashseed; /* Random seed for vfshash */
unsigned long mountFlags; /* Flags for mount */
char pathName[PATH_MAX]; /* path name of mount point */
/* 将一个设备(通常是存储设备)挂接到一个已存在的目录上,操作系统将所有的设备都看作文件,
* 它将整个计算机的资源都整合成一个大的文件目录。我们要访问存储设备中的文件,必须将文件所在的分区挂载到一个已存在的目录上,
* 然后通过访问这个目录来访问存储设备。挂载就是把设备放在一个目录下,让系统知道怎么管理这个设备里的文件,
* 了解这个存储设备的可读写特性之类的过程。
*/
struct Mount {//装载
LIST_ENTRY mountList; /* mount list */ //通过本节点将Mount挂到全局Mount链表上
const struct MountOps *ops; /* operations of mount */ //装载操作函数
struct Vnode *vnodeBeCovered; /* vnode we mounted on */ //设备装载点
struct Vnode *vnodeCovered; /* syncer vnode */ //暂时不知作何用途
LIST_HEAD vnodeList; /* list of vnodes */ //链表表头
int vnodeSize; /* size of vnode list */ //节点数量
LIST_HEAD activeVnodeList; /* list of active vnodes */ //激活的节点链表
int activeVnodeSize; /* szie of active vnodes list *///激活的节点数量
void *data; /* private data */ //私有数据
uint32_t hashseed; /* Random seed for vfs hash */ //vfs 哈希随机种子
unsigned long mountFlags; /* Flags for mount */ //装载标签
char pathName[PATH_MAX]; /* path name of mount point */ //装载点路径名称
};
//装载操作
struct MountOps {
int (*Mount)(struct Mount *mount, struct Vnode *vnode, const void *data);
int (*Unmount)(struct Mount *mount, struct Vnode **blkdriver);
int (*Statfs)(struct Mount *mount, struct statfs *sbp);
int (*Mount)(struct Mount *mount, struct Vnode *vnode, const void *data);//装载
int (*Unmount)(struct Mount *mount, struct Vnode **blkdriver);//卸载
int (*Statfs)(struct Mount *mount, struct statfs *sbp);//状态
};
struct Mount* MountAlloc(struct Vnode* vnode, struct MountOps* mop);
......
......@@ -35,8 +35,8 @@
#include "fs/mount.h"
#include "fs/vnode.h"
struct PathCache {
struct Vnode *parentVnode; /* vnode points to the cache */
struct PathCache {//路径缓存
struct Vnode *parentVnode; /* vnode points to the cache */
struct Vnode *childVnode; /* vnode the cache points to */
LIST_ENTRY parentEntry; /* list entry for cache list in the parent vnode */
LIST_ENTRY childEntry; /* list entry for cache list in the child vnode */
......
......@@ -92,12 +92,12 @@ struct Vnode {
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 hashEntry; /* list entry for bucket in hash table */ //通过它挂入哈希表 g_vnodeHashEntrys[i], i:[0,g_vnodeHashMask]
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);//查询
......@@ -119,7 +119,11 @@ struct VnodeOps {
int (*Truncate64)(struct Vnode *vnode, off64_t len);//缩减或扩展大小
int (*Fscheck)(struct Vnode *vnode, struct fs_dirent_s *dir);//检查功能
};
/*哈希比较指针函数,使用方法,例如:
* int VfsHashGet(const struct Mount *mount, uint32_t hash, struct Vnode **vnode, VfsHashCmp *fn, void *arg)
* VfsHashCmp *fn 等同于 int *fn, 此时 fn是个指针,指向了一个函数地址
* fn(vnode,arg)就是调用这个函数,返回一个int类型的值
*/
typedef int VfsHashCmp(struct Vnode *vnode, void *arg);
int VnodesInit(void);
......
......@@ -32,28 +32,46 @@
#define __MTD_DEV_H__
#include "los_typedef.h"
/************************************************
MTD,Memory Technology Device即内存技术设备
Linux系统中采用MTD来管理不同类型的Flash芯片,包括NandFlash和NorFlash
NAND型和NOR型Flash在进行写入和擦除时都需要MTD(Memory Technology Drivers,MTD已集成在Flash芯片内部,
它是对Flash进行操作的接口),这是它们的共同特点;但在NOR型Flash上运行代码不需要任何的软件支持,
而在NAND型Flash上进行同样操作时,通常需要驱动程序,即内存技术驱动程序MTD。
#define MTD_NORFLASH 3
#define MTD_NANDFLASH 4
NOR型Flash采用的SRAM接口,提供足够的地址引脚来寻址,可以很容易的存取其片内的每一个字节;
NAND型Flash使用复杂的I/O口来串行的存取数据,各个产品或厂商的方法可能各不相同,通常是采用8个I/O引脚
来传送控制、地址、数据信息。
NAND型Flash具有较高的单元密度,容量可以做得比较大,加之其生产过程更为简单,价格较低;NOR型Flash占据了容量
为1~16MB闪存市场的大部分,而NAND型Flash只是用在8~128MB的产品中,这也说明NOR主要用在代码存储介质中,
NAND适合数据存储。
************************************************/
#define MTD_NORFLASH 3 //存储空间一般比较小,但它可以不用初始化,可以在其内部运行程序,一般在其存储一些初始化内存的固件代码;
#define MTD_NANDFLASH 4
#define MTD_DATAFLASH 6
#define MTD_MLCNANDFLASH 8
struct MtdNorDev {
unsigned long blockSize;
unsigned long blockStart;
unsigned long blockEnd;
/*********************************************
扇区是对硬盘而言,而块是对文件系统而言
文件系统不是一个扇区一个扇区的来读数据,一个扇区512个字节,太慢了,所以有了block(块)的概念,
文件系统是一个块一个块的读取的,block才是文件存取的最小单位。
*********************************************/
struct MtdNorDev {//一个block是4K,即:文件系统中1个块是由连续的8个扇区组成
unsigned long blockSize; //块大小,不用猜也知道,是4K,和内存的页等同,如此方便置换
unsigned long blockStart; //开始块索引
unsigned long blockEnd; //结束块索引
};
struct MtdDev {
struct MtdDev {//flash描述符
VOID *priv;
UINT32 type;
UINT64 size;
UINT32 eraseSize;
UINT32 eraseSize;//4K, 跟PAGE_CACHE_SIZE对应
int (*erase)(struct MtdDev *mtd, UINT64 start, UINT64 len, UINT64 *failAddr);
int (*read)(struct MtdDev *mtd, UINT64 start, UINT64 len, const char *buf);
int (*write)(struct MtdDev *mtd, UINT64 start, UINT64 len, const char *buf);
int (*erase)(struct MtdDev *mtd, UINT64 start, UINT64 len, UINT64 *failAddr);//擦除flash操作
int (*read)(struct MtdDev *mtd, UINT64 start, UINT64 len, const char *buf);//读操作
int (*write)(struct MtdDev *mtd, UINT64 start, UINT64 len, const char *buf);//写操作
};
#endif /* __MTD_DEV_H__ */
......@@ -47,36 +47,83 @@ extern "C" {
#endif /* __cplusplus */
#endif /* __cplusplus */
#define SPIBLK_NAME "/dev/spinorblk"
#define SPICHR_NAME "/dev/spinorchr"
#define NANDBLK_NAME "/dev/nandblk"
#define NANDCHR_NAME "/dev/nandchr"
typedef struct mtd_node {
UINT32 start_block;
UINT32 end_block;
UINT32 patitionnum;
CHAR *blockdriver_name;
CHAR *chardriver_name;
CHAR *mountpoint_name;
VOID *mtd_info; /* Driver used by a partition */
LOS_DL_LIST node_info;
LosMux lock;
UINT32 user_num;
/***************************************************************
* flash按照内部存储结构不同,分为两种:nor flash和nand flash
* Nor FLASH使用方便,易于连接,可以在芯片上直接运行代码,稳定性出色,传输速率高,
在小容量时有很高的性价比,这使其很适合应于嵌入式系统中作为 FLASH ROM。
Nor Flash架构提供足够的地址线来映射整个存储器范围。
* NandFLASH强调更高的性能,更低的成本,更小的体积,更长的使用寿命。
这使Nand FLASH很擅于存储纯资料或数据等,在嵌入式系统中用来支持文件系统。
缺点包括较慢的读取熟读和I/O映射类型或间接接口
* 在通信方式上Nor Flash 分为两种类型:CFI Flash和 SPI Flash。即采用的通信协议不同.
SPI Flash(serial peripheral interface)串行外围设备接口,是一种常见的时钟同步串行通信接口。
有4线(时钟,两个数据线,片选线)或者3线(时钟,两个数据线)通信接口,由于它有两个数据线能实现全双工通信,
读写速度上较快。拥有独立的数据总线和地址总线,能快速随机读取,允许系统直接从Flash中读取代码执行;
可以单字节或单字编程,但不能单字节擦除,必须以Sector为单位或对整片执行擦除操作,在对存储器进行重新编程之前需要对Sector
或整片进行预编程和擦除操作。
CFI Flash
英文全称是common flash interface,也就是公共闪存接口,是由存储芯片工业界定义的一种获取闪存芯片物理参数
和结构参数的操作规程和标准。CFI有许多关于闪存芯片的规定,有利于嵌入式对FLASH的编程。现在的很多NOR FLASH 都支持CFI,
但并不是所有的都支持。
CFI接口,相对于串口的SPI来说,也被称为parallel接口,并行接口;另外,CFI接口是JEDEC定义的,
所以,有的又成CFI接口为JEDEC接口。所以,可以简单理解为:对于Nor Flash来说,
CFI接口=JEDEC接口=Parallel接口 = 并行接口
特点在于支持的容量更大,读写速度更快。
缺点由于拥有独立的数据线和地址总线,会浪费电路电子设计上的更多资源。
***************************************************************/
#define SPIBLK_NAME "/dev/spinorblk" //nor spi flash 块设备
#define SPICHR_NAME "/dev/spinorchr" //nor spi flash 字符设备
#define NANDBLK_NAME "/dev/nandblk" //nand flash 块设备
#define NANDCHR_NAME "/dev/nandchr" //nand flash 字符设备
/***************************************************************
https://blog.csdn.net/lwj103862095/article/details/21545791
MTD,Memory Technology Device即内存技术设备,在Linux内核中,引入MTD层为
NOR FLASH和NAND FLASH设备提供统一接口。MTD将文件系统与底层FLASH存储器进行了隔离。
字符设备和块设备的区别在于前者只能被顺序读写,后者可以随机访问;同时,两者读写数据的基本单元不同。
字符设备,以字节为基本单位,在Linux中,字符设备实现的比较简单,不需要缓冲区即可直接读写,
内核例程和用户态API一一对应,用户层的Read函数直接对应了内核中的Read例程,这种映射关系由字符设备的
file_operations维护。
块设备,则以块为单位接受输入和返回输出。对这种设备的读写是按块进行的,其接口相对于字符设备复杂,
read、write API没有直接到块设备层,而是直接到文件系统层,然后再由文件系统层发起读写请求。
同时,由于块设备的IO性能与CPU相比很差,因此,块设备的数据流往往会引入文件系统的Cache机制。
MTD设备既非块设备也不是字符设备,但可以同时提供字符设备和块设备接口来操作它。
MTD设备通常可分为四层
这四层从上到下依次是:设备节点、MTD设备层、MTD原始设备层和硬件驱动层。
***************************************************************/
typedef struct mtd_node {//通过mknod在/dev子目录下建立MTD块设备节点(主设备号为31)和MTD字符设备节点(主设备号为90)
UINT32 start_block; //开始块索引
UINT32 end_block; //结束块索引
UINT32 patitionnum; //分区编号
CHAR *blockdriver_name; //块设备驱动名称
CHAR *chardriver_name; //字符设备驱动名称
CHAR *mountpoint_name; //挂载点名称
VOID *mtd_info; /* Driver used by a partition *///分区使用的驱动程序
LOS_DL_LIST node_info;//双循环节点,挂在首个分区节点上
LosMux lock; //每个分区都有自己的互斥量
UINT32 user_num; //使用数量
} mtd_partition;
typedef struct par_param {
mtd_partition *partition_head;
struct MtdDev *flash_mtd;
const struct block_operations *flash_ops;
const struct file_operations_vfs *char_ops;
CHAR *blockname;
CHAR *charname;
UINT32 block_size;
typedef struct par_param {//分区参数描述符,一个分区既可支持按块访问也可以支持按字符访问,只要有驱动程序就可
mtd_partition *partition_head; //首个分区,其他分区都挂在.node_info节点上
struct MtdDev *flash_mtd; //flash设备描述符,属于硬件驱动层
const struct block_operations *flash_ops; //块设备的操作方法
const struct file_operations_vfs *char_ops; //字符设备的操作方法
CHAR *blockname; //块设备名称
CHAR *charname; //字符设备名称
UINT32 block_size; //块单位(4K),对文件系统而言是按块读取数据,方便和内存页置换
} partition_param;
#define CONFIG_MTD_PATTITION_NUM 20
#define CONFIG_MTD_PATTITION_NUM 20 //分区数量的上限
#define ALIGN_ASSIGN(len, startAddr, startBlk, endBlk, blkSize) do { \
(len) = (((len) + ((blkSize) - 1)) & ~((blkSize) - 1)); \
......
......@@ -46,10 +46,10 @@ extern void lsfd(void);
extern void set_sd_sync_fn(int (*sync_fn)(int));
extern struct Vnode *files_get_openfile(int fd);
#define READ_OP 4
#define WRITE_OP 2
#define EXEC_OP 1
//访问模式
#define READ_OP 4 //读操作
#define WRITE_OP 2 //写操作
#define EXEC_OP 1 //运行操作
#define UGO_NUMS 3
#define MODE_IXUGO 0111
#define USER_MODE_SHIFT 6
......
......@@ -38,40 +38,46 @@
#include "stdlib.h"
#endif
static LIST_HEAD *g_mountList = NULL;
static LIST_HEAD *g_mountList = NULL;//装载链表,上面挂的是系统所有的装载设备
/* 在内核MountAlloc只被VnodeDevInit调用,但真实情况下它还将被系统调用 mount()调用
* int mount(const char *source, const char *target,
const char *filesystemtype, unsigned long mountflags,
const void *data)
mount见于..\code-2.0-canary\third_party\NuttX\fs\mount\fs_mount.c
vnodeBeCovered: /dev/mmcblk0
*/
struct Mount* MountAlloc(struct Vnode* vnodeBeCovered, struct MountOps* fsop)
{
struct Mount* mnt = (struct Mount*)zalloc(sizeof(struct Mount));
struct Mount* mnt = (struct Mount*)zalloc(sizeof(struct Mount));//申请一个mount结构体内存,小内存分配用 zalloc
if (mnt == NULL) {
PRINT_ERR("MountAlloc failed no memory!\n");
return NULL;
}
LOS_ListInit(&mnt->activeVnodeList);
LOS_ListInit(&mnt->vnodeList);
LOS_ListInit(&mnt->activeVnodeList);//初始化激活索引节点链表
LOS_ListInit(&mnt->vnodeList);//初始化索引节点链表
mnt->vnodeBeCovered = vnodeBeCovered;
vnodeBeCovered->newMount = mnt;
#ifdef LOSCFG_DRIVERS_RANDOM
HiRandomHwInit();
(VOID)HiRandomHwGetInteger(&mnt->hashseed);
HiRandomHwDeinit();
mnt->vnodeBeCovered = vnodeBeCovered;//设备将装载到vnodeBeCovered节点上
vnodeBeCovered->newMount = mnt;//该节点不再是虚拟节点,而作为 设备结点
#ifdef LOSCFG_DRIVERS_RANDOM //随机值 驱动模块
HiRandomHwInit();//随机值初始化
(VOID)HiRandomHwGetInteger(&mnt->hashseed);//用于生成哈希种子
HiRandomHwDeinit();//随机值反初始化
#else
mnt->hashseed = (uint32_t)random();
mnt->hashseed = (uint32_t)random(); //随机生成哈子种子
#endif
return mnt;
}
//获取装载链表
LIST_HEAD* GetMountList()
{
if (g_mountList == NULL) {
g_mountList = zalloc(sizeof(LIST_HEAD));
g_mountList = zalloc(sizeof(LIST_HEAD));//分配内存, 小内存分配用 zalloc
if (g_mountList == NULL) {
PRINT_ERR("init mount list failed, no memory.");
return NULL;
}
LOS_ListInit(g_mountList);
LOS_ListInit(g_mountList);//初始化全局链表
}
return g_mountList;
}
......@@ -47,9 +47,10 @@
#define DRIVER_NAME_ADD_SIZE 3
pthread_mutex_t g_mtdPartitionLock = PTHREAD_MUTEX_INITIALIZER;
//通常在NorFlash上会选取jffs及jffs2文件系统
static VOID YaffsLockInit(VOID) __attribute__((weakref("yaffsfs_OSInitialisation")));
static VOID YaffsLockDeinit(VOID) __attribute__((weakref("yaffsfs_OsDestroy")));
static INT32 Jffs2LockInit(VOID) __attribute__((weakref("Jffs2MutexCreate")));
static INT32 Jffs2LockInit(VOID) __attribute__((weakref("Jffs2MutexCreate")));//弱引用 Jffs2MutexCreate
static VOID Jffs2LockDeinit(VOID) __attribute__((weakref("Jffs2MutexDelete")));
partition_param *g_nandPartParam = NULL;
......@@ -57,7 +58,7 @@ partition_param *g_spinorPartParam = NULL;
mtd_partition *g_spinorPartitionHead = NULL;
mtd_partition *g_nandPartitionHead = NULL;
#define RWE_RW_RW 0755
#define RWE_RW_RW 0755 //文件读/写/执权限,chmod 755
partition_param *GetNandPartParam(VOID)
{
......@@ -83,8 +84,8 @@ static VOID MtdNandParamAssign(partition_param *nandParam, const struct MtdDev *
* you can change the NANDBLK_NAME or NANDCHR_NAME to NULL.
*/
nandParam->flash_mtd = (struct MtdDev *)nandMtd;
nandParam->flash_ops = GetDevNandOps();
nandParam->char_ops = GetMtdCharFops();
nandParam->flash_ops = GetDevNandOps(); //获取块设备操作方法
nandParam->char_ops = GetMtdCharFops(); //获取字符设备操作方法
nandParam->blockname = NANDBLK_NAME;
nandParam->charname = NANDCHR_NAME;
nandParam->partition_head = g_nandPartitionHead;
......@@ -146,7 +147,7 @@ static VOID MtdNorParamAssign(partition_param *spinorParam, const struct MtdDev
spinorParam->charname = NULL;
#endif
spinorParam->partition_head = g_spinorPartitionHead;
spinorParam->block_size = spinorMtd->eraseSize;
spinorParam->block_size = spinorMtd->eraseSize;//4K, 读/写/擦除 的最小单位
}
static VOID MtdDeinitSpinorParam(VOID)
......@@ -261,7 +262,7 @@ static INT32 AddParamCheck(UINT32 startAddr,
return ENOERR;
}
//注册块设备,此函数之后设备将支持VFS访问
static INT32 BlockDriverRegisterOperate(mtd_partition *newNode,
const partition_param *param,
UINT32 partitionNum)
......@@ -283,7 +284,7 @@ static INT32 BlockDriverRegisterOperate(mtd_partition *newNode,
newNode->blockdriver_name = NULL;
return -ENAMETOOLONG;
}
//在伪文件系统中注册块驱动程序,生成设备结点 inode
ret = register_blockdriver(newNode->blockdriver_name, param->flash_ops,
RWE_RW_RW, newNode);
if (ret) {
......@@ -297,7 +298,7 @@ static INT32 BlockDriverRegisterOperate(mtd_partition *newNode,
}
return ENOERR;
}
//注册字符设备,此函数之后设备将支持VFS访问
static INT32 CharDriverRegisterOperate(mtd_partition *newNode,
const partition_param *param,
UINT32 partitionNum)
......@@ -332,7 +333,7 @@ static INT32 CharDriverRegisterOperate(mtd_partition *newNode,
}
return ENOERR;
}
//注销块设备
static INT32 BlockDriverUnregister(mtd_partition *node)
{
INT32 ret;
......@@ -348,7 +349,7 @@ static INT32 BlockDriverUnregister(mtd_partition *node)
}
return ENOERR;
}
//注销字符设备
static INT32 CharDriverUnregister(mtd_partition *node)
{
INT32 ret;
......
......@@ -57,6 +57,7 @@
* https://weharmony.gitee.io/openharmony/zh-cn/device-dev/kernel/VFS.html
*/
//只能调用一次,多次调用将会造成文件系统异常。
void los_vfs_init(void)
{
uint retval;
......@@ -65,25 +66,25 @@ void los_vfs_init(void)
return;
}
#ifdef LOSCFG_FS_FAT_DISK
#ifdef LOSCFG_FS_FAT_DISK //两个自旋锁
spin_lock_init(&g_diskSpinlock);
spin_lock_init(&g_diskFatBlockSpinlock);
#endif
files_initialize();
files_initlist(&tg_filelist);
retval = VnodesInit();
retval = VnodesInit();//虚拟节点初始化
if (retval != LOS_OK) {
PRINT_ERR("los_vfs_init VnodeInit failed error %d\n", retval);
return;
}
retval = PathCacheInit();
retval = PathCacheInit();//路径缓存初始化
if (retval != LOS_OK) {
PRINT_ERR("los_vfs_init PathCacheInit failed error %d\n", retval);
return;
}
retval = VnodeHashInit();
retval = VnodeHashInit();//哈希列表初始化
if (retval != LOS_OK) {
PRINT_ERR("los_vfs_init VnodeHashInit failed error %d\n", retval);
return;
......
......@@ -241,18 +241,18 @@ static char *vfs_normalize_fullpath(const char *directory, const char *filename,
return fullpath;
}
//通过目录和文件名找(绝对)路径
int vfs_normalize_path(const char *directory, const char *filename, char **pathname)
{
char *fullpath = NULL;
int namelen;
#ifdef VFS_USING_WORKDIR
#ifdef VFS_USING_WORKDIR //使能当前工作目录
UINTPTR lock_flags;
LosProcessCB *curr = OsCurrProcessGet();
BOOL dir_flags = (directory == NULL) ? TRUE : FALSE;
LosProcessCB *curr = OsCurrProcessGet(); //获取当前进程
BOOL dir_flags = (directory == NULL) ? TRUE : FALSE;//是否为目录
#endif
namelen = vfs_normalize_path_parame_check(filename, pathname);
namelen = vfs_normalize_path_parame_check(filename, pathname);//参数检查
if (namelen < 0) {
return namelen;
}
......@@ -260,8 +260,8 @@ int vfs_normalize_path(const char *directory, const char *filename, char **pathn
#ifdef VFS_USING_WORKDIR
if (directory == NULL)
{
spin_lock_irqsave(&curr->files->workdir_lock, lock_flags);
directory = curr->files->workdir;
spin_lock_irqsave(&curr->files->workdir_lock, lock_flags);//对工作目录加锁
directory = curr->files->workdir;//获取工作目录 ,pwd
}
#else
if ((directory == NULL) && (filename[0] != '/')) {
......@@ -277,17 +277,17 @@ int vfs_normalize_path(const char *directory, const char *filename, char **pathn
#ifdef VFS_USING_WORKDIR
if (dir_flags == TRUE)
{
spin_unlock_irqrestore(&curr->files->workdir_lock, lock_flags);
spin_unlock_irqrestore(&curr->files->workdir_lock, lock_flags);//对工作目录解锁
}
#endif
return -ENAMETOOLONG;
}
fullpath = vfs_normalize_fullpath(directory, filename, pathname, namelen);
fullpath = vfs_normalize_fullpath(directory, filename, pathname, namelen);//获取整个路径(绝对)
#ifdef VFS_USING_WORKDIR
if (dir_flags == TRUE)
{
spin_unlock_irqrestore(&curr->files->workdir_lock, lock_flags);
spin_unlock_irqrestore(&curr->files->workdir_lock, lock_flags);//对工作目录解锁
}
#endif
if (fullpath == NULL) {
......@@ -313,7 +313,7 @@ int vfs_normalize_pathat(int dirfd, const char *filename, char **pathname)
char *fullpath = NULL;
int ret = 0;
ret = get_path_from_fd(dirfd, &relativeoldpath);
ret = get_path_from_fd(dirfd, &relativeoldpath);//通过FD找到路径
if (ret < 0) {
return ret;
}
......
......@@ -279,16 +279,16 @@ static char *NextName(char *pos, uint8_t *len)
*len = pos - name;
return name;
}
//处理前的准备
static int PreProcess(const char *originPath, struct Vnode **startVnode, char **path)
{
int ret;
char *absolutePath = NULL;
//通过相对路径找到绝对路径
ret = vfs_normalize_path(NULL, originPath, &absolutePath);
if (ret == LOS_OK) {
*startVnode = g_rootVnode;
*path = absolutePath;
if (ret == LOS_OK) {//成功
*startVnode = g_rootVnode;//根节点为开始节点
*path = absolutePath;//返回绝对路径
}
return ret;
......@@ -324,7 +324,7 @@ static int ProcessVirtualVnode(struct Vnode *parent, uint32_t flags, struct Vnod
}
return ret;
}
//一级一级向下找
static int Step(char **currentDir, struct Vnode **currentVnode, uint32_t flags)
{
int ret;
......@@ -373,21 +373,21 @@ STEP_FINISH:
return ret;
}
//查找节点
int VnodeLookup(const char *path, struct Vnode **result, uint32_t flags)
{
struct Vnode *startVnode = NULL;
char *normalizedPath = NULL;
int ret = PreProcess(path, &startVnode, &normalizedPath);
int ret = PreProcess(path, &startVnode, &normalizedPath);//找到根节点和绝对路径
if (ret != LOS_OK) {
PRINT_ERR("[VFS]lookup failed, invalid path=%s err = %d\n", path, ret);
goto OUT_FREE_PATH;
}
if (normalizedPath[0] == '/' && normalizedPath[1] == '\0') {
*result = g_rootVnode;
if (normalizedPath[0] == '/' && normalizedPath[1] == '\0') {//如果是根节点
*result = g_rootVnode;//啥也不说了,还找啥呀,直接返回根节点
free(normalizedPath);
return LOS_OK;
}
......@@ -395,11 +395,11 @@ int VnodeLookup(const char *path, struct Vnode **result, uint32_t flags)
char *currentDir = normalizedPath;
struct Vnode *currentVnode = startVnode;
while (currentDir && *currentDir != '\0') {
ret = Step(&currentDir, &currentVnode, flags);
if (*currentDir == '\0') {
while (currentDir && *currentDir != '\0') {//循环一直找到结尾
ret = Step(&currentDir, &currentVnode, flags);//一级一级向下找
if (*currentDir == '\0') {//找到最后了,返回目标节点或父虚拟节点
// return target or parent vnode as result
*result = currentVnode;
*result = currentVnode;//找到了
} else if (VfsVnodePermissionCheck(currentVnode, EXEC_OP)) {
ret = -EACCES;
goto OUT_FREE_PATH;
......@@ -517,23 +517,23 @@ int VnodeClosedir(struct Vnode *vnode, struct fs_dirent_s *dir)
(void)dir;
return LOS_OK;
}
//创建节点
int VnodeCreate(struct Vnode *parent, const char *name, int mode, struct Vnode **vnode)
{
int ret;
struct Vnode *newVnode = NULL;
ret = VnodeAlloc(NULL, &newVnode);
ret = VnodeAlloc(NULL, &newVnode);//分配一个节点
if (ret != 0) {
return -ENOMEM;
}
newVnode->type = VNODE_TYPE_CHR;
newVnode->vop = parent->vop;
newVnode->fop = parent->fop;
newVnode->data = NULL;
newVnode->parent = parent;
newVnode->originMount = parent->originMount;
newVnode->type = VNODE_TYPE_CHR;//字符设备
newVnode->vop = parent->vop;//继承父节点 vop
newVnode->fop = parent->fop;//继承父节点 fop
newVnode->data = NULL; //默认值
newVnode->parent = parent; //指定父节点
newVnode->originMount = parent->originMount; //挂载点
newVnode->uid = parent->uid;
newVnode->gid = parent->gid;
newVnode->mode = mode;
......@@ -541,21 +541,21 @@ int VnodeCreate(struct Vnode *parent, const char *name, int mode, struct Vnode *
*vnode = newVnode;
return 0;
}
//设备初始化,设备结点:/dev目录下,对应一个设备,如/dev/mmcblk0
int VnodeDevInit()
{
struct Vnode *devNode = NULL;
struct Mount *devMount = NULL;
int retval = VnodeLookup("/dev", &devNode, V_CREATE | V_CACHE | V_DUMMY);
int retval = VnodeLookup("/dev", &devNode, V_CREATE | V_CACHE | V_DUMMY);//通过名称找到索引节点
if (retval != LOS_OK) {
PRINT_ERR("VnodeDevInit failed error %d\n", retval);
return retval;
}
devNode->mode = DEV_VNODE_MODE | S_IFDIR;
devNode->type = VNODE_TYPE_DIR;
devNode->mode = DEV_VNODE_MODE | S_IFDIR; // 40755(chmod 755)
devNode->type = VNODE_TYPE_DIR; //设备根节点目录
devMount = MountAlloc(devNode, NULL);
devMount = MountAlloc(devNode, NULL);//分配一个mount节点
if (devMount == NULL) {
PRINT_ERR("VnodeDevInit failed mount point alloc failed.\n");
return -ENOMEM;
......@@ -610,7 +610,7 @@ int VnodeDevLookup(struct Vnode *parentVnode, const char *path, int len, struct
/* dev node must in pathCache. */
return -ENOENT;
}
//虚拟设备 默认节点操作
static struct VnodeOps g_devfsOps = {
.Lookup = VnodeDevLookup,
.Getattr = VnodeGetattr,
......
......@@ -33,17 +33,17 @@
#define VNODE_HASH_BUCKETS 128
//用哈希表只有一个目的,就是加快对索引节点对象的搜索
LIST_HEAD g_vnodeHashEntrys[VNODE_HASH_BUCKETS];//哈希桶链表组
uint32_t g_vnodeHashMask = VNODE_HASH_BUCKETS - 1; //哈希掩码
uint32_t g_vnodeHashSize = VNODE_HASH_BUCKETS; //哈希大小
LIST_HEAD g_vnodeHashEntrys[VNODE_HASH_BUCKETS];
uint32_t g_vnodeHashMask = VNODE_HASH_BUCKETS - 1;
uint32_t g_vnodeHashSize = VNODE_HASH_BUCKETS;
static LosMux g_vnodeHashMux;
static LosMux g_vnodeHashMux;//哈希表互斥量
//索引节点哈希表初始化
int VnodeHashInit(void)
{
int ret;
for (int i = 0; i < g_vnodeHashSize; i++) {
for (int i = 0; i < g_vnodeHashSize; i++) {//遍历初始化 128个双向链表
LOS_ListInit(&g_vnodeHashEntrys[i]);
}
......@@ -55,36 +55,36 @@ int VnodeHashInit(void)
return LOS_OK;
}
//打印全部 hash 表
void VnodeHashDump(void)
{
PRINTK("-------->VnodeHashDump in\n");
(void)LOS_MuxLock(&g_vnodeHashMux, LOS_WAIT_FOREVER);
(void)LOS_MuxLock(&g_vnodeHashMux, LOS_WAIT_FOREVER);//拿锁方式,永等
for (int i = 0; i < g_vnodeHashSize; i++) {
LIST_HEAD *nhead = &g_vnodeHashEntrys[i];
struct Vnode *node = NULL;
LOS_DL_LIST_FOR_EACH_ENTRY(node, nhead, struct Vnode, hashEntry) {
PRINTK(" vnode dump: col %d item %p\n", i, node);
LOS_DL_LIST_FOR_EACH_ENTRY(node, nhead, struct Vnode, hashEntry) {//循环打印链表
PRINTK(" vnode dump: col %d item %p\n", i, node);//类似矩阵
}
}
(void)LOS_MuxUnlock(&g_vnodeHashMux);
PRINTK("-------->VnodeHashDump out\n");
}
//通过节点获取哈希索引值
uint32_t VfsHashIndex(struct Vnode *vnode)
{
if (vnode == NULL) {
return -EINVAL;
}
return (vnode->hash + vnode->originMount->hashseed);
return (vnode->hash + vnode->originMount->hashseed);//用于定位在哈希表的下标
}
//通过哈希值和装载设备哈希种子获取哈希表索引
static LOS_DL_LIST *VfsHashBucket(const struct Mount *mp, uint32_t hash)
{
return (&g_vnodeHashEntrys[(hash + mp->hashseed) & g_vnodeHashMask]);
return (&g_vnodeHashEntrys[(hash + mp->hashseed) & g_vnodeHashMask]);//g_vnodeHashMask确保始终范围在[0~g_vnodeHashMask]之间
}
//通过哈希值获取节点信息
int VfsHashGet(const struct Mount *mount, uint32_t hash, struct Vnode **vnode, VfsHashCmp *fn, void *arg)
{
struct Vnode *curVnode = NULL;
......@@ -93,34 +93,34 @@ int VfsHashGet(const struct Mount *mount, uint32_t hash, struct Vnode **vnode, V
return -EINVAL;
}
(void)LOS_MuxLock(&g_vnodeHashMux, LOS_WAIT_FOREVER);
LOS_DL_LIST *list = VfsHashBucket(mount, hash);
LOS_DL_LIST_FOR_EACH_ENTRY(curVnode, list, struct Vnode, hashEntry) {
if (curVnode->hash != hash) {
(void)LOS_MuxLock(&g_vnodeHashMux, LOS_WAIT_FOREVER);//先上锁
LOS_DL_LIST *list = VfsHashBucket(mount, hash);//获取哈希表对应的链表项
LOS_DL_LIST_FOR_EACH_ENTRY(curVnode, list, struct Vnode, hashEntry) {//遍历链表
if (curVnode->hash != hash) {//对比哈希值找
continue;
}
if (curVnode->originMount != mount) {
if (curVnode->originMount != mount) {//对比原始mount值必须一致
continue;
}
if (fn != NULL && fn(curVnode, arg)) {
if (fn != NULL && fn(curVnode, arg)) {//哈希值比较函数,fn由具体的文件系统提供.
continue;
}
(void)LOS_MuxUnlock(&g_vnodeHashMux);
*vnode = curVnode;
*vnode = curVnode;//找到对应索引节点
return LOS_OK;
}
(void)LOS_MuxUnlock(&g_vnodeHashMux);
*vnode = NULL;
return LOS_NOK;
}
//从哈希链表中摘除索引节点
void VfsHashRemove(struct Vnode *vnode)
{
if (vnode == NULL) {
return;
}
(void)LOS_MuxLock(&g_vnodeHashMux, LOS_WAIT_FOREVER);
LOS_ListDelete(&vnode->hashEntry);
LOS_ListDelete(&vnode->hashEntry);//直接把自己摘掉就行了
(void)LOS_MuxUnlock(&g_vnodeHashMux);
}
//插入哈希表
......@@ -130,8 +130,8 @@ int VfsHashInsert(struct Vnode *vnode, uint32_t hash)
return -EINVAL;
}
(void)LOS_MuxLock(&g_vnodeHashMux, LOS_WAIT_FOREVER);
vnode->hash = hash;
LOS_ListHeadInsert(VfsHashBucket(vnode->originMount, hash), &vnode->hashEntry);
vnode->hash = hash;//设置节点哈希值
LOS_ListHeadInsert(VfsHashBucket(vnode->originMount, hash), &vnode->hashEntry);//通过节点hashEntry 挂入哈希表对于索引链表中
(void)LOS_MuxUnlock(&g_vnodeHashMux);
return LOS_OK;
}
git add -A
git commit -m ' 开始文件系统注解,从 vnode 开始 ...
git commit -m ' 开始文件系统注解,mount mtd flash 注解
百万汉字注解 + 百篇博客分析 => 挖透鸿蒙内核源码
国内: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.
先完成此消息的编辑!
想要评论请 注册