开始文件系统注解,file mapping 注解

    百万汉字注解 + 百篇博客分析 => 挖透鸿蒙内核源码
    国内:https://weharmony.gitee.io
    国外:https://weharmony.github.io
上级 5c000a49
......@@ -56,7 +56,6 @@
#include <sys/stat.h>
#include <sys/types.h>
struct VnodeOps fatfs_vops; /* forward define */
struct file_operations_vfs fatfs_fops;
......@@ -71,7 +70,7 @@ struct file_operations_vfs fatfs_fops;
#define FTIME_DATE_OFFSET 16 /* date offset in dword */
#define SEC_MULTIPLIER 2
#define YEAR_OFFSET 80 /* Year start from 1980 in FATFS, while start from 1900 in struct tm */
// 结果转化 fat 转 vfs
int fatfs_2_vfs(int result)
{
int status = ENOERR;
......@@ -452,7 +451,7 @@ ERROR_FREE:
ERROR_EXIT:
return -ret;
}
//打开 fat 格式文件
int fatfs_open(struct file *filep)
{
struct Vnode *vp = filep->f_vnode;
......
......@@ -48,7 +48,20 @@
extern "C" {
#endif /* __cplusplus */
#endif /* __cplusplus */
/***************************************************
FAT文件系统是File Allocation Table(文件配置表)的简称,FAT文件系统有FAT12、FAT16、FAT32。
FAT文件系统将硬盘分为MBR区、DBR区、FAT区、DIR区、DATA区等5个区域。
FAT文件系统支持多种介质,特别在可移动存储介质(U盘、SD卡、移动硬盘等)上广泛使用。
可以使嵌入式设备和Windows、Linux等桌面系统保持很好的兼容性,方便用户管理操作文件。
OpenHarmony内核的FAT文件系统具有代码量和资源占用小、可裁切、支持多种物理介质等特性,
并且与Windows、Linux等系统保持兼容,支持多设备、多分区识别等功能。
OpenHarmony内核支持硬盘多分区,可以在主分区以及逻辑分区上创建FAT文件系统。
同时OpenHarmony内核也可以识别出硬盘上其他类型的文件系统。
***************************************************/
#define MAX_LFNAME_LENGTH 256
#define LABEL_LEN 12
#define FAT_RESERVED_NUM 2
......
......@@ -71,6 +71,13 @@ CFI Flash
CFI接口=JEDEC接口=Parallel接口 = 并行接口
特点在于支持的容量更大,读写速度更快。
缺点由于拥有独立的数据线和地址总线,会浪费电路电子设计上的更多资源。
SPI Flash : 每次传输一个bit位的数据,传输速度慢,但是价格便宜,任意地址读数据,擦除按扇区进行
CFI Flash : 每次传输一个字节 ,速度快,任意地址读数据,擦除按扇区进行
Nand Flash:芯片操作是以“块”为基本单位.NAND闪存的块比较小,一般是8KB,然后每块又分成页,
页大小一般是512字节.要修改NandFlash芯片中一个字节,必须重写整个数据块,读和写都是按照扇区进行的。
参考:https://blog.csdn.net/zhejfl/article/details/78544796
***************************************************************/
#define SPIBLK_NAME "/dev/spinorblk" //nor spi flash 块设备
......@@ -80,8 +87,6 @@ CFI 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存储器进行了隔离。
......@@ -98,8 +103,8 @@ read、write API没有直接到块设备层,而是直接到文件系统层,
MTD设备既非块设备也不是字符设备,但可以同时提供字符设备和块设备接口来操作它。
MTD设备通常可分为四层
这四层从上到下依次是:设备节点、MTD设备层、MTD原始设备层和硬件驱动层。
参考: https://blog.csdn.net/lwj103862095/article/details/21545791
***************************************************************/
typedef struct mtd_node {//通过mknod在/dev子目录下建立MTD块设备节点(主设备号为31)和MTD字符设备节点(主设备号为90)
UINT32 start_block; //开始块索引
UINT32 end_block; //结束块索引
......@@ -113,7 +118,7 @@ typedef struct mtd_node {//通过mknod在/dev子目录下建立MTD块设备节
UINT32 user_num; //使用数量
} mtd_partition;
typedef struct par_param {//分区参数描述符,一个分区既可支持按块访问也可以支持按字符访问,只要有驱动程序就
typedef struct par_param {//分区参数描述符,一个分区既可支持按块访问也可以支持按字符访问,只要有驱动程序就阔以
mtd_partition *partition_head; //首个分区,其他分区都挂在.node_info节点上
struct MtdDev *flash_mtd; //flash设备描述符,属于硬件驱动层
const struct block_operations *flash_ops; //块设备的操作方法
......
......@@ -48,15 +48,28 @@
pthread_mutex_t g_mtdPartitionLock = PTHREAD_MUTEX_INITIALIZER;
//通常在NorFlash上会选取jffs及jffs2文件系统
/*
* GCC使用__attribute__关键字来描述函数,变量和数据类型的属性,用于编译器对源代码的优化
* 对外部目标文件的符号引用在目标文件被最终链接成可执行文件时,它们须要被正确决议,如果没有找到该符号的定义,
链接器就会报符号未定义错误,这种被称为强引用(Strong Reference)。
* 与之相对应还有一种弱引用(Weak Reference),在处理弱引用时,如果该符号有定义,则链接器将该符号的引用决议;
如果该符号未被定义,则链接器对于该引用不报错。
* 链接器处理强引用和弱引用的过程几乎一样,只是对于未定义的弱引用,链接器不认为它是一个错误。一般对于未定义的弱引用,
链接器默认其为0,或者是一个特殊的值,以便于程序代码能够识别。
* 在GCC中,我们可以通过使用"__attribute__((weakref("..."))"这个扩展关键字来声明对一个外部函数的引用为弱引用,
参考: https://www.cnblogs.com/pengdonglin137/p/3615345.html
*/
static VOID YaffsLockInit(VOID) __attribute__((weakref("yaffsfs_OSInitialisation")));
static VOID YaffsLockDeinit(VOID) __attribute__((weakref("yaffsfs_OsDestroy")));
static INT32 Jffs2LockInit(VOID) __attribute__((weakref("Jffs2MutexCreate")));//弱引用 Jffs2MutexCreate
static VOID Jffs2LockDeinit(VOID) __attribute__((weakref("Jffs2MutexDelete")));
partition_param *g_nandPartParam = NULL;
partition_param *g_spinorPartParam = NULL;
mtd_partition *g_spinorPartitionHead = NULL;
mtd_partition *g_nandPartitionHead = NULL;
partition_param *g_nandPartParam = NULL; //nand flash 分区参数
partition_param *g_spinorPartParam = NULL; //nor flash 分区参数
mtd_partition *g_spinorPartitionHead = NULL; //spi nor flash 首个分区
mtd_partition *g_nandPartitionHead = NULL; //nand flash 首个分区
#define RWE_RW_RW 0755 //文件读/写/执权限,chmod 755
......@@ -75,10 +88,10 @@ mtd_partition *GetSpinorPartitionHead(VOID)
return g_spinorPartitionHead;
}
//nand flash 参数初始化,本函数只会被调用一次
static VOID MtdNandParamAssign(partition_param *nandParam, const struct MtdDev *nandMtd)
{
LOS_ListInit(&g_nandPartitionHead->node_info);
LOS_ListInit(&g_nandPartitionHead->node_info);//初始化全局链表
/*
* If the user do not want to use block mtd or char mtd ,
* you can change the NANDBLK_NAME or NANDCHR_NAME to NULL.
......@@ -86,19 +99,19 @@ static VOID MtdNandParamAssign(partition_param *nandParam, const struct MtdDev *
nandParam->flash_mtd = (struct MtdDev *)nandMtd;
nandParam->flash_ops = GetDevNandOps(); //获取块设备操作方法
nandParam->char_ops = GetMtdCharFops(); //获取字符设备操作方法
nandParam->blockname = NANDBLK_NAME;
nandParam->charname = NANDCHR_NAME;
nandParam->partition_head = g_nandPartitionHead;
nandParam->block_size = nandMtd->eraseSize;
nandParam->blockname = NANDBLK_NAME; // /dev/nandblk
nandParam->charname = NANDCHR_NAME; // /dev/nandchr
nandParam->partition_head = g_nandPartitionHead;//头分区节点
nandParam->block_size = nandMtd->eraseSize;//4K
}
//反初始化
static VOID MtdDeinitNandParam(VOID)
{
if (YaffsLockDeinit != NULL) {
YaffsLockDeinit();
}
}
//nand flash 初始化
static partition_param *MtdInitNandParam(partition_param *nandParam)
{
struct MtdDev *nandMtd = GetMtd("nand");
......@@ -107,7 +120,7 @@ static partition_param *MtdInitNandParam(partition_param *nandParam)
}
if (nandParam == NULL) {
if (YaffsLockInit != NULL) {
YaffsLockInit();
YaffsLockInit(); //加锁
}
nandParam = (partition_param *)zalloc(sizeof(partition_param));
if (nandParam == NULL) {
......@@ -126,10 +139,10 @@ static partition_param *MtdInitNandParam(partition_param *nandParam)
return nandParam;
}
//nor flash 初始化
static VOID MtdNorParamAssign(partition_param *spinorParam, const struct MtdDev *spinorMtd)
{
LOS_ListInit(&g_spinorPartitionHead->node_info);
LOS_ListInit(&g_spinorPartitionHead->node_info);//初始化全局链表
/*
* If the user do not want to use block mtd or char mtd ,
* you can change the SPIBLK_NAME or SPICHR_NAME to NULL.
......@@ -156,7 +169,7 @@ static VOID MtdDeinitSpinorParam(VOID)
Jffs2LockDeinit();
}
}
//spi nor flash 参数初始化
static partition_param *MtdInitSpinorParam(partition_param *spinorParam)
{
#ifndef LOSCFG_PLATFORM_QEMU_ARM_VIRT_CA7
......
......@@ -40,22 +40,69 @@
#ifdef LOSCFG_KERNEL_VM
static struct file_map g_file_mapping = {0};
static struct file_map g_file_mapping = {0};//用于挂载所有文件的file_map
#if 0 //@note_#if0
定义见于 ..\third_party\NuttX\include\nuttx\fs\fs.h
typedef volatile INT32 Atomic;
//page_mapping描述的是一个文件在内存中被映射了多少页,<文件,文件页的关系>
/* file mapped in VMM pages */
struct page_mapping {//记录文件页和文件关系的结构体,叫文件页映射
LOS_DL_LIST page_list; /* all pages */ //链表上挂的是属于该文件的所有FilePage,这些页的内容都来源同一个文件
SPIN_LOCK_S list_lock; /* lock protecting it */ //操作page_list的自旋锁
LosMux mux_lock; /* mutex lock */ // //操作page_mapping的互斥量
unsigned long nrpages; /* number of total pages */ //page_list的节点数量
unsigned long flags; //@note_why 全量代码中也没查到源码中对其操作
Atomic ref; /* reference counting */ //引用次数(自增/自减),对应add_mapping/dec_mapping
struct file *host; /* owner of this mapping *///属于哪个文件的映射
};
/* map: full_path(owner) <-> mapping */ //叫文件映射
struct file_map { //为在内核层面文件在内存的身份证,每个需映射到内存的文件必须创建一个file_map,都挂到全局g_file_mapping链表上
LOS_DL_LIST head; //链表节点,用于挂到g_file_mapping上
LosMux lock; /* lock to protect this mapping */
struct page_mapping mapping; //每个文件都有唯一的page_mapping标识其在内存的身份
char *owner; /* owner: full path of file *///文件全路径来标识唯一性
};
struct file //文件系统最重要的两个结构体之一,另一个是inode
{
unsigned int f_magicnum; /* file magic number */ //文件魔法数字
int f_oflags; /* Open mode flags */ //打开模式标签
FAR struct inode *f_inode; /* Driver interface */ //设备驱动程序
loff_t f_pos; /* File position */ //文件的位置
unsigned long f_refcount; /* reference count */ //被引用的数量,一个文件可被多个进程打开
char *f_path; /* File fullpath */ //全路径
void *f_priv; /* Per file driver private data */ //文件私有数据
const char *f_relpath; /* realpath */ //真实路径
struct page_mapping *f_mapping; /* mapping file to memory */ //与内存的映射 page-cache
void *f_dir; /* DIR struct for iterate the directory if open a directory */ //所在目录
};
#endif
/**************************************************************************************************
初始化文件映射模块,
file_map: 每个需映射到内存的文件必须创建一个 file_map,都挂到全局g_file_mapping链表上
page_mapping: 记录的是<文件,文件页>的关系,一个文件在操作过程中被映射成了多少个页,
file:是文件系统管理层面的概念
**************************************************************************************************/
uint init_file_mapping()
{
uint ret;
LOS_ListInit(&g_file_mapping.head);
LOS_ListInit(&g_file_mapping.head);//初始化全局文件映射节点,所有文件的映射都将g_file_mapping.head挂在链表上
ret = LOS_MuxInit(&g_file_mapping.lock, NULL);
ret = LOS_MuxInit(&g_file_mapping.lock, NULL);;//初始化文件映射互斥锁
if (ret != LOS_OK) {
PRINT_ERR("Create mutex for file map of page cache failed, (ret=%u)\n", ret);
}
return ret;
}
//清除文件映射
static void clear_file_mapping(const struct page_mapping *mapping)
{
unsigned int i = 3; /* file start fd */
......@@ -69,7 +116,7 @@ static void clear_file_mapping(const struct page_mapping *mapping)
i++;
}
}
//以无锁的方式通过文件名查找文件映射并返回
static struct page_mapping *find_mapping_nolock(const char *fullpath)
{
char *map_name = NULL;
......@@ -85,7 +132,11 @@ static struct page_mapping *find_mapping_nolock(const char *fullpath)
return NULL;
}
/**************************************************************************************************
增加一个文件映射,这个函数被do_open()函数调用,每打开一次文件就会调用一次
注意不同的进程打开同一个文件,拿到的file是不一样的。
https://blog.csdn.net/cywosp/article/details/38965239
**************************************************************************************************/
void add_mapping(struct file *filep, const char *fullpath)
{
int path_len;
......@@ -97,12 +148,12 @@ void add_mapping(struct file *filep, const char *fullpath)
return;
}
(VOID)LOS_MuxLock(&g_file_mapping.lock, LOS_WAIT_FOREVER);
mapping = find_mapping_nolock(fullpath);
(VOID)LOS_MuxLock(&g_file_mapping.lock, LOS_WAIT_FOREVER);//操作临界区,先拿锁
mapping = find_mapping_nolock(fullpath);//是否已有文件映射
if (mapping) {
LOS_AtomicInc(&mapping->ref);
filep->f_mapping = mapping;
mapping->host = filep;
LOS_AtomicInc(&mapping->ref);//引用自增
filep->f_mapping = mapping;//记录page_mapping的老板
mapping->host = filep;//释放锁
goto out;
}
......@@ -119,23 +170,29 @@ void add_mapping(struct file *filep, const char *fullpath)
fmap->name_len = path_len;
(void)strcpy_s(fmap->owner, path_len + 1, fullpath);
LOS_ListInit(&fmap->mapping.page_list);
LOS_SpinInit(&fmap->mapping.list_lock);
retval = LOS_MuxInit(&fmap->mapping.mux_lock, NULL);
LOS_ListInit(&fmap->mapping.page_list);//初始化文件映射的页表链表,上面将会挂这个文件映射的所有虚拟内存页
LOS_SpinInit(&fmap->mapping.list_lock);//初始化文件映射的自旋锁
retval = LOS_MuxInit(&fmap->mapping.mux_lock, NULL);//初始化文件映射的互斥锁
if (retval != LOS_OK) {
PRINT_ERR("%s %d, Create mutex for mapping.mux_lock failed, status: %d\n", __FUNCTION__, __LINE__, retval);
goto out;
}
LOS_ListTailInsert(&g_file_mapping.head, &fmap->head);
LOS_ListTailInsert(&g_file_mapping.head, &fmap->head);//将文件映射结点挂入全局链表
filep->f_mapping = &fmap->mapping;
filep->f_mapping->host = filep;
filep->f_mapping = &fmap->mapping;//<file,file_map>之间互绑
filep->f_mapping->host = filep;//<file,file_map>之间互绑,从此相亲相爱一家人
out:
(VOID)LOS_MuxUnlock(&g_file_mapping.lock);
}
/******************************************************************************
删除一个文件映射,需要有个三个地方删除才算断开了文件和内存的联系.
以无锁的方式删除映射
******************************************************************************/
int remove_mapping_nolock(struct page_mapping *mapping)
{
struct file_map *fmap = NULL;
......@@ -157,7 +214,7 @@ int remove_mapping_nolock(struct page_mapping *mapping)
return OK;
}
//无锁方式引用递减,删除或关闭文件时 由 files_close_internal调用
void dec_mapping_nolock(struct page_mapping *mapping)
{
if (mapping == NULL) {
......@@ -177,7 +234,7 @@ void dec_mapping_nolock(struct page_mapping *mapping)
(VOID)LOS_MuxUnlock(&g_file_mapping.lock);
}
//已有锁的方式删除文件映射
int remove_mapping(const char *fullpath)
{
int ret;
......@@ -203,7 +260,7 @@ int remove_mapping(const char *fullpath)
(void)sem_post(&f_list->fl_sem);
return OK;
}
//重命名映射
void rename_mapping(const char *src_path, const char *dst_path)
{
int ret;
......@@ -246,7 +303,7 @@ void rename_mapping(const char *src_path, const char *dst_path)
out:
(VOID)LOS_MuxUnlock(&g_file_mapping.lock);
}
//更新文件路径
int update_file_path(const char *old_path, const char *new_path)
{
struct filelist *f_list = NULL;
......
......@@ -42,7 +42,7 @@
#include "unistd.h"
#include "fs/vfs_util.h"
#include "fs/vnode.h"
/*
/********************************************************
* VFS是Virtual File System(虚拟文件系统)的缩写,它不是一个实际的文件系统,而是一个异构文件系统之上的软件粘合层,
* 为用户提供统一的类Unix文件操作接口。
......@@ -56,9 +56,8 @@
* 统一调用(标准)。
* https://weharmony.gitee.io/openharmony/zh-cn/device-dev/kernel/VFS.html
*/
//只能调用一次,多次调用将会造成文件系统异常。
void los_vfs_init(void)
********************************************************/
void los_vfs_init(void)//只能调用一次,多次调用将会造成文件系统异常
{
uint retval;
static bool g_vfs_init = false;
......@@ -90,14 +89,14 @@ void los_vfs_init(void)
return;
}
retval = VnodeDevInit();
retval = VnodeDevInit();//设备节点初始化
if (retval != LOS_OK) {
PRINT_ERR("los_vfs_init VnodeDevInit failed error %d\n", retval);
return;
}
#ifdef LOSCFG_KERNEL_VM
retval = init_file_mapping();
retval = init_file_mapping();//初始化文件映射
if (retval != LOS_OK) {
PRINT_ERR("Page cache file map init failed\n");
return;
......
此差异已折叠。
git add -A
git commit -m ' 开始文件系统注解,mount mtd flash 注解
git commit -m ' 开始文件系统注解,file mapping 注解
百万汉字注解 + 百篇博客分析 => 挖透鸿蒙内核源码
国内: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.
先完成此消息的编辑!
想要评论请 注册