From 05769288f21a17fcb4faa2de8d915ab65b8d4d62 Mon Sep 17 00:00:00 2001 From: kuangyufei Date: Sat, 26 Dec 2020 12:55:14 +0800 Subject: [PATCH] =?UTF-8?q?=E6=B3=A8=E8=A7=A3=E5=86=99=E6=97=B6=E5=A4=8D?= =?UTF-8?q?=E5=88=B6(Copy=20On=20Write)=E6=8A=80=E6=9C=AF=E5=9C=A8?= =?UTF-8?q?=E9=B8=BF=E8=92=99=E5=86=85=E6=A0=B8=E7=9A=84=E5=AE=9E=E7=8E=B0?= =?UTF-8?q?=20=E6=90=9C=E7=B4=A2=20@note=5Fpic=20=E6=96=B9=E4=BE=BF?= =?UTF-8?q?=E7=90=86=E8=A7=A3=E7=94=BB=E7=9A=84=E5=AD=97=E7=AC=A6=E5=9B=BE?= =?UTF-8?q?=20=E6=90=9C=E7=B4=A2=20@note=5Fwhy=20=E5=B0=9A=E6=9C=AA?= =?UTF-8?q?=E7=9C=8B=E6=98=8E=E7=99=BD=E7=9A=84=E5=9C=B0=E6=96=B9=EF=BC=8C?= =?UTF-8?q?=E5=A6=82=E6=9E=9C=E6=82=A8=E7=9C=8B=E6=98=8E=E7=99=BD=E4=BA=86?= =?UTF-8?q?=EF=BC=8C=E8=AF=B7=E5=91=8A=E7=9F=A5=E5=AE=8C=E5=96=84=20?= =?UTF-8?q?=E6=90=9C=E7=B4=A2=20@note=5Fthinking=20=E4=B8=80=E7=82=B9?= =?UTF-8?q?=E6=80=9D=E8=80=83=E5=92=8C=E5=90=90=E6=A7=BD=E7=9A=84=E5=9C=B0?= =?UTF-8?q?=E6=96=B9=20=E6=90=9C=E7=B4=A2=20@note=5F#if0=20=E7=94=B1?= =?UTF-8?q?=E7=AC=AC=E4=B8=89=E6=96=B9=E9=A1=B9=E7=9B=AE=E6=8F=90=E4=BE=9B?= =?UTF-8?q?=E4=B8=8D=E7=94=B1=E5=86=85=E6=A0=B8=E6=BA=90=E7=A0=81=E4=B8=AD?= =?UTF-8?q?=E5=AE=9A=E4=B9=89=E7=9A=84=E6=9E=81=E4=B8=BA=E9=87=8D=E8=A6=81?= =?UTF-8?q?=E7=9A=84=E7=BB=93=E6=9E=84=E4=BD=93=EF=BC=8C=E4=B8=BA=E6=96=B9?= =?UTF-8?q?=E4=BE=BF=E7=90=86=E8=A7=A3=E8=80=8C=E6=B7=BB=E5=8A=A0=E7=9A=84?= =?UTF-8?q?=20=E6=90=9C=E7=B4=A2=20@note=5Fgood=20=E7=BB=99=E6=BA=90?= =?UTF-8?q?=E7=A0=81=E7=82=B9=E8=B5=9E?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- fs/vfs/operation/fs_file_mapping.c | 80 ++++++++++++----------- kernel/base/include/los_vm_filemap.h | 25 ++++---- kernel/base/include/los_vm_map.h | 6 +- kernel/base/vm/los_vm_fault.c | 4 +- kernel/base/vm/los_vm_filemap.c | 94 +++++++++++++++------------- kernel/base/vm/los_vm_scan.c | 4 +- zzz/doc/note_fs.h | 35 +++++++++++ zzz/doc/note_ipc.h | 10 +-- zzz/git/push.sh | 12 ++-- 9 files changed, 156 insertions(+), 114 deletions(-) create mode 100644 zzz/doc/note_fs.h diff --git a/fs/vfs/operation/fs_file_mapping.c b/fs/vfs/operation/fs_file_mapping.c index 17c9773f..c12722ad 100644 --- a/fs/vfs/operation/fs_file_mapping.c +++ b/fs/vfs/operation/fs_file_mapping.c @@ -41,44 +41,47 @@ #if 0 //@note_#if0 定义见于 ..\third_party\NuttX\include\nuttx\fs\fs.h typedef volatile INT32 Atomic; -struct page_mapping { - LOS_DL_LIST page_list; /* all pages */ - SPIN_LOCK_S list_lock; /* lock protecting it */ - LosMux mux_lock; /* mutex lock * / - unsigned long nrpages; /* number of total pages */ - unsigned long flags; - Atomic ref; /* reference counting */ - struct file *host; /* owner of this mapping */ +//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 *///文件全路径来标识唯一性 }; -/* map: full_path(owner) <-> mapping * / -struct file_map { - LOS_DL_LIST head; //挂入文件链表的节点 - LosMux lock; /* lock to protect this mapping * / - struct page_mapping mapping; //映射内容区 - char *owner; /* owner: full path of file * / -}; - -struct 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 */ - void *f_dir; /* DIR struct for iterate the directory if open a directory */ + 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 -static struct file_map g_file_mapping = {0}; +static struct file_map g_file_mapping = {0};//用于挂载所有文件的file_map /************************************************************************************************** 初始化文件映射模块, - file_map: 每个需映射到内存的文件必须创建一个 file_map,都挂到全部g_file_mapping链表上 + file_map: 每个需映射到内存的文件必须创建一个 file_map,都挂到全局g_file_mapping链表上 page_mapping: 记录的是<文件,文件页>的关系,一个文件在操作过程中被映射成了多少个页, file:是文件系统管理层面的概念 **************************************************************************************************/ @@ -132,8 +135,8 @@ void add_mapping(struct file *filep, const char *fullpath) mapping = find_mapping_nolock(fullpath);//是否已有文件映射 if (mapping) {//有映射过的情况 LOS_AtomicInc(&mapping->ref);//引用自增 - filep->f_mapping = mapping;//赋值 - mapping->host = filep; + filep->f_mapping = mapping;//记录文件自己在内存的身份 + mapping->host = filep; //记录page_mapping的老板 (VOID)LOS_MuxUnlock(&g_file_mapping.lock);//释放锁 return;//收工 } @@ -227,7 +230,12 @@ void clear_file_mapping_nolock(const struct page_mapping *mapping) i++; } } -//删除一个映射 + +/****************************************************************************** + 删除一个文件映射,需要有个三个地方删除才算断开了文件和内存的联系. + + 1. 进程文件 +******************************************************************************/ int remove_mapping_nolock(const char *fullpath, const struct file *ex_filp) { int fd; @@ -276,11 +284,11 @@ int remove_mapping_nolock(const char *fullpath, const struct file *ex_filp) } (VOID)LOS_MuxDestroy(&mapping->mux_lock); - clear_file_mapping_nolock(mapping);//清除自己 - OsFileCacheRemove(mapping);//从缓存中删除自己 + clear_file_mapping_nolock(mapping);//清除进程对page_mapping的映射 + OsFileCacheRemove(mapping);//从页高速缓存中删除文件页 fmap = LOS_DL_LIST_ENTRY(mapping, - struct file_map, mapping);//找到自己的inode - LOS_ListDelete(&fmap->head);//从链表中摘除自己 + struct file_map, mapping);//通过page_mapping找到fmap + LOS_ListDelete(&fmap->head);//从g_file_mapping链表上摘掉自己 LOS_MemFree(m_aucSysMem0, fmap); out: diff --git a/kernel/base/include/los_vm_filemap.h b/kernel/base/include/los_vm_filemap.h index cee33f9e..c64e6bc5 100644 --- a/kernel/base/include/los_vm_filemap.h +++ b/kernel/base/include/los_vm_filemap.h @@ -64,23 +64,24 @@ extern "C" { #if 0 //@note_#if0 //page_mapping描述的是一个文件在内存中被映射了多少页,<文件,文件页的关系> /* file mapped in VMM pages */ -struct page_mapping { +struct page_mapping {//记录文件页和文件关系的结构体,叫文件页映射 LOS_DL_LIST page_list; /* all pages */ //链表上挂的是属于该文件的所有FilePage,这些页的内容都来源同一个文件 - SPIN_LOCK_S list_lock; /* lock protecting it */ - LosMux mux_lock; /* mutex lock */ // - unsigned long nrpages; /* number of total pages */ - unsigned long flags; - Atomic ref; /* reference counting */ + 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 { - LOS_DL_LIST head; +/* 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; - char *owner; /* owner: full path of file */ + struct page_mapping mapping; //每个文件都有唯一的page_mapping标识其在内存的身份 + char *owner; /* owner: full path of file *///文件全路径来标识唯一性 }; + #endif //文件页结构体 @@ -89,7 +90,7 @@ typedef struct FilePage { LOS_DL_LIST lru; //lru节点, 结合 LosVmPhysSeg: LOS_DL_LIST lruList[VM_NR_LRU_LISTS] 理解 LOS_DL_LIST i_mmap; /* list of mappings */ //链表记录文件页被哪些进程映射 MapInfo.node挂上来 UINT32 n_maps; /* num of mapping */ //记录被进程映射的次数 - struct VmPhysSeg *physSeg; /* physical memory that file page belongs to */ //物理内存是唯一的 + struct VmPhysSeg *physSeg; /* physical memory that file page belongs to */ //物理段:物理页框 = 1:N struct VmPage *vmPage; //物理页框 struct page_mapping *mapping; //此结构由文件系统提供,用于描述装入点 见于 ..\third_party\NuttX\include\nuttx\fs\fs.h VM_OFFSET_T pgoff; //页标,文件被切成一页一页读到内存 diff --git a/kernel/base/include/los_vm_map.h b/kernel/base/include/los_vm_map.h index 29170854..532be4cd 100644 --- a/kernel/base/include/los_vm_map.h +++ b/kernel/base/include/los_vm_map.h @@ -95,11 +95,11 @@ typedef struct VmFault { VADDR_T *pageKVaddr; /* KVaddr of pagefault's vm page's paddr */ //page cache中的虚拟地址 } LosVmPgFault; //虚拟内存文件操作函数指针,上层开发可理解为 class 里的方法,注意是对线性区的操作 -struct VmFileOps {// 文件操作 +struct VmFileOps {// 文件操作 见于g_commVmOps void (*open)(struct VmMapRegion *region); //打开 void (*close)(struct VmMapRegion *region);//关闭 - int (*fault)(struct VmMapRegion *region, LosVmPgFault *pageFault);//缺页 - void (*remove)(struct VmMapRegion *region, LosArchMmu *archMmu, VM_OFFSET_T offset);//删除 + int (*fault)(struct VmMapRegion *region, LosVmPgFault *pageFault);//缺页,OsVmmFileFault + void (*remove)(struct VmMapRegion *region, LosArchMmu *archMmu, VM_OFFSET_T offset);//删除 OsVmmFileRemove }; struct VmMapRegion {//线性区描述符,内核通过线性区管理虚拟地址,而线性地址就是虚拟地址 diff --git a/kernel/base/vm/los_vm_fault.c b/kernel/base/vm/los_vm_fault.c index 9f77c7ea..68c185de 100644 --- a/kernel/base/vm/los_vm_fault.c +++ b/kernel/base/vm/los_vm_fault.c @@ -147,7 +147,7 @@ STATIC STATUS_T OsDoReadFault(LosVmMapRegion *region, LosVmPgFault *vmPgFault)// return LOS_ERRNO_VM_NO_MEMORY; } -/* numap a page when cow happend only */ +/* numap a page when cow happend only *///仅当写时拷贝发生时取消页面映射 STATIC LosVmPage *OsCowUnmapOrg(LosArchMmu *archMmu, LosVmMapRegion *region, LosVmPgFault *vmf) { UINT32 intSave; @@ -404,7 +404,7 @@ STATUS_T OsVmPageFaultHandler(VADDR_T vaddr, UINT32 flags, ExcContext *frame) vmPgFault.vaddr = vaddr;//虚拟地址 vmPgFault.pgoff = ((vaddr - region->range.base) >> PAGE_SHIFT) + region->pgOff;//计算出文件读取位置 vmPgFault.flags = flags; - vmPgFault.pageKVaddr = NULL;//没有物理地址 + vmPgFault.pageKVaddr = NULL;//缺失页初始化没有物理地址 status = OsDoFileFault(region, &vmPgFault, flags);//缺页处理 if (status) { diff --git a/kernel/base/vm/los_vm_filemap.c b/kernel/base/vm/los_vm_filemap.c index ac0c8751..211e1095 100644 --- a/kernel/base/vm/los_vm_filemap.c +++ b/kernel/base/vm/los_vm_filemap.c @@ -171,7 +171,9 @@ STATIC LosFilePage *OsPagecacheGetPageAndFill(struct file *filp, VM_OFFSET_T pgO return page; } -//从文件filp中读 size 数据到buf中 +/****************************************************************************** + 从文件filp中读 size 数据到buf中 +******************************************************************************/ ssize_t OsMappingRead(struct file *filp, char *buf, size_t size) { INT32 ret; @@ -212,7 +214,7 @@ ssize_t OsMappingRead(struct file *filp, char *buf, size_t size) readSize = MIN2((PAGE_SIZE - offInPage), readLeft); - (VOID)memcpy_s((VOID *)buf, readLeft, (char *)kvaddr + offInPage, readSize); + (VOID)memcpy_s((VOID *)buf, readLeft, (char *)kvaddr + offInPage, readSize);//将文件页的数据拷贝到buf buf += readSize; readLeft -= readSize; readTotal += readSize; @@ -227,69 +229,71 @@ ssize_t OsMappingRead(struct file *filp, char *buf, size_t size) return readTotal; } - +/****************************************************************************** + 向页高速缓存中写入数据 +******************************************************************************/ ssize_t OsMappingWrite(struct file *filp, const char *buf, size_t size) { VADDR_T kvaddr; UINT32 intSave; INT32 writeSize = 0; size_t writeLeft = size; - VM_OFFSET_T pos = file_seek(filp, 0, SEEK_CUR); - VM_OFFSET_T pgOff = pos >> PAGE_SHIFT; - INT32 offInPage = pos % PAGE_SIZE; + VM_OFFSET_T pos = file_seek(filp, 0, SEEK_CUR);//获得要从文件那个位置写入 + VM_OFFSET_T pgOff = pos >> PAGE_SHIFT; //计算出文件页的序号 + INT32 offInPage = pos % PAGE_SIZE; //计算出文件页内偏移量 LosFilePage *page = NULL; - struct page_mapping *mapping = filp->f_mapping; + struct page_mapping *mapping = filp->f_mapping;//得到文件页映射 INT32 nPages = (ROUNDUP(pos + size, PAGE_SIZE) - ROUNDDOWN(pos, PAGE_SIZE)) >> PAGE_SHIFT; LOS_SpinLockSave(&mapping->list_lock, &intSave); - for (INT32 i = 0; i < nPages; i++, pgOff++) { - page = OsFindGetEntry(mapping, pgOff); - if (page) { - kvaddr = (VADDR_T)(UINTPTR)OsVmPageToVaddr(page->vmPage); - OsSetPageLocked(page->vmPage); - OsPageRefIncLocked(page); - } else { - page = OsPageCacheAlloc(mapping, pgOff); + for (INT32 i = 0; i < nPages; i++, pgOff++) {//遍历pgOff,pgOff表示页序号 + page = OsFindGetEntry(mapping, pgOff);//通过页序号拿到页高速缓存中的文件页 + if (page) {//页高速缓存中有该页 + kvaddr = (VADDR_T)(UINTPTR)OsVmPageToVaddr(page->vmPage);//通过文件页获得虚拟地址(即数据写入地址) + OsSetPageLocked(page->vmPage);//写操作要上锁 + OsPageRefIncLocked(page);//因为页可能被其他进程所引用,所以也要上锁 + } else {//页高速缓存中没有该页 + page = OsPageCacheAlloc(mapping, pgOff);//分配一个文件页 if (page == NULL) { VM_ERR("Failed to alloc a page frame"); break; } - kvaddr = (VADDR_T)(UINTPTR)OsVmPageToVaddr(page->vmPage); - OsAddToPageacheLru(page, mapping, pgOff); - OsSetPageLocked(page->vmPage); + kvaddr = (VADDR_T)(UINTPTR)OsVmPageToVaddr(page->vmPage);//通过文件页获得虚拟地址(即数据写入地址) + OsAddToPageacheLru(page, mapping, pgOff);//将页加入页高速缓存中 + OsSetPageLocked(page->vmPage);//写操作要上锁,因为是新页,所以不要 OsPageRefIncLocked } + //准备工作做好了,才是写入页高速缓存,注意这里只是写缓存,而不是写最终的文件 + writeSize = MIN2((PAGE_SIZE - offInPage), writeLeft);//计算出要写入的大小 - writeSize = MIN2((PAGE_SIZE - offInPage), writeLeft); + (VOID)memcpy_s((char *)(UINTPTR)kvaddr + offInPage, writeLeft, buf, writeSize);//将内容拷贝到页高速缓存 + buf += writeSize; //计算出剩余未写完buf位置 + writeLeft -= writeSize; //计算出剩余大小 - (VOID)memcpy_s((char *)(UINTPTR)kvaddr + offInPage, writeLeft, buf, writeSize); - buf += writeSize; - writeLeft -= writeSize; + OsMarkPageDirty(page, NULL, offInPage, writeSize);//标记文件页为脏页,从offInPage位置开始脏的. + //注意这里只是做标记,内核并不会马上将数据写入磁盘文件,而是在缺页时写入磁盘,就是著名的 写时拷贝技术. + offInPage = 0;//脏位置复位 - OsMarkPageDirty(page, NULL, offInPage, writeSize); - - offInPage = 0; - - OsCleanPageLocked(page->vmPage); + OsCleanPageLocked(page->vmPage);//释放文件页锁 } LOS_SpinUnlockRestore(&mapping->list_lock, intSave); - file_seek(filp, pos + size - writeLeft, SEEK_SET); + file_seek(filp, pos + size - writeLeft, SEEK_SET);//最后文件要seek到指定的位置 return (size - writeLeft); } - +//解除文件页和进程的映射关系 STATIC VOID OsPageCacheUnmap(LosFilePage *fpage, LosArchMmu *archMmu, VADDR_T vaddr) { UINT32 intSave; LosMapInfo *info = NULL; LOS_SpinLockSave(&fpage->physSeg->lruLock, &intSave); - info = OsGetMapInfo(fpage, archMmu, vaddr); + info = OsGetMapInfo(fpage, archMmu, vaddr);//获取文件页在进程的映射信息 if (info == NULL) { VM_ERR("OsPageCacheUnmap get map info fail!"); } else { - OsUnmapPageLocked(fpage, info); + OsUnmapPageLocked(fpage, info);//解除进程和文件页映射关系 } if (!(OsIsPageMapped(fpage) && ((fpage->flags & VM_MAP_REGION_FLAG_PERM_EXECUTE) || OsIsPageDirty(fpage->vmPage)))) { @@ -397,13 +401,13 @@ STATIC INT32 OsFlushDirtyPage(LosFilePage *fpage) size_t len; char *buff = NULL; VM_OFFSET_T oldPos; - struct file *file = fpage->mapping->host;//struct file *host; /* owner of this mapping */ 此映射的所有者 + struct file *file = fpage->mapping->host;/* owner of this mapping */ //此映射属于哪个文件,注意是1:1的关系. if ((file == NULL) || (file->f_inode == NULL)) {//nuttx file 文件描述符 VM_ERR("page cache file error"); return LOS_NOK; } - oldPos = file_seek(file, 0, SEEK_CUR);//定位到当前位置 + oldPos = file_seek(file, 0, SEEK_CUR);////先记录老位置,因为写完页数据后要seek回老位置 buff = (char *)OsVmPageToVaddr(fpage->vmPage);//获取页面的虚拟地址 file_seek(file, (((UINT32)fpage->pgoff << PAGE_SHIFT) + fpage->dirtyOff), SEEK_SET);//移到页面脏数据位置,注意不是整个页面都脏了,可能只脏了一部分 len = fpage->dirtyEnd - fpage->dirtyOff;//计算出脏数据长度 @@ -413,7 +417,7 @@ STATIC INT32 OsFlushDirtyPage(LosFilePage *fpage) (VOID)file_seek(file, oldPos, SEEK_SET);//移回老位置 return LOS_OK; } - //i_mops: Operations on a mountpoint 可前往 nuttx 查看 fat_operations.writepage为null + // if (file->f_inode && file->f_inode->u.i_mops->writepage) {//如果mount驱动程序提供了写页的实现 ret = file->f_inode->u.i_mops->writepage(file, (buff + fpage->dirtyOff), len);//使用mount接口回写数据 } else { @@ -424,7 +428,7 @@ STATIC INT32 OsFlushDirtyPage(LosFilePage *fpage) } ret = (ret <= 0) ? LOS_NOK : LOS_OK; OsCleanPageDirty(fpage->vmPage);//撕掉脏页标签,还清白之身,哈哈,臣妾又干净了. - (VOID)file_seek(file, oldPos, SEEK_SET);//写完了脏数据,切回到老位置,一定要回到老位置,因为回写脏数据是内核的行为,而不是用户的行为 + (VOID)file_seek(file, oldPos, SEEK_SET);//不管是否写正常,一定要切回到原来位置,很重要!!! 写页是内核的操作,不是用户的操作行为 return ret; } @@ -528,7 +532,7 @@ INT32 OsVmmFileFault(LosVmMapRegion *region, LosVmPgFault *vmf) /* get or create a new cache node */ LOS_SpinLockSave(&mapping->list_lock, &intSave); fpage = OsFindGetEntry(mapping, vmf->pgoff);//获取文件页 - if (fpage != NULL) {//找到了,该页已经在页高速缓存中 + if (fpage != NULL) {//找到了,说明该页已经在页高速缓存中 OsPageRefIncLocked(fpage); } else {//真的缺页了,页高速缓存中没找到 fpage = OsPageCacheAlloc(mapping, vmf->pgoff);//分配一个文件页,将数据初始化好,包括vmpage(物理页框) @@ -537,36 +541,36 @@ INT32 OsVmmFileFault(LosVmMapRegion *region, LosVmPgFault *vmf) LOS_SpinUnlockRestore(&mapping->list_lock, intSave); return LOS_NOK; } - newCache = true; + newCache = true;//分配了新文件页 } OsSetPageLocked(fpage->vmPage);//对vmpage上锁 LOS_SpinUnlockRestore(&mapping->list_lock, intSave); - kvaddr = OsVmPageToVaddr(fpage->vmPage);//获取该页框在内核空间的虚拟地址 + kvaddr = OsVmPageToVaddr(fpage->vmPage);//获取该页框在内核空间的虚拟地址,因为 page cache本身就是在内核空间, /* read file to new page cache */ if (newCache) {//新cache - oldPos = file_seek(file, 0, SEEK_CUR);//相对当前位置偏移,记录偏移后的位置 NUTTX - file_seek(file, fpage->pgoff << PAGE_SHIFT, SEEK_SET);// 相对开始位置偏移 + oldPos = file_seek(file, 0, SEEK_CUR);//先记录老位置,因为读完页数据后要seek回老位置 + file_seek(file, fpage->pgoff << PAGE_SHIFT, SEEK_SET);//定位到要开始读的位置,从fpage->pgoff << PAGE_SHIFT 文件位置开始读. if (file->f_inode && file->f_inode->u.i_mops->readpage) {//见于 NUTTX fat_operations.readpage = NULL ret = file->f_inode->u.i_mops->readpage(file, (char *)kvaddr, PAGE_SIZE);//从文件中读取一页数据到kvaddr } else { - ret = file_read(file, kvaddr, PAGE_SIZE);//将4K数据读到虚拟地址,磁盘数据进入物理页框 fpage->pgoff << PAGE_SHIFT 处 + ret = file_read(file, kvaddr, PAGE_SIZE);//将磁盘4K数据读到物理页框的kvaddr地址中,真正写到了fpage->vmPage->physAddr中. } - file_seek(file, oldPos, SEEK_SET);//再切回原来位置,一定要切回,很重要!!! 因为缺页是内核的操作,不是用户逻辑行为 + file_seek(file, oldPos, SEEK_SET);//不管是否读写正常,一定要切回到原来位置,很重要!!! 因为缺页->读页是内核的操作,不是用户的操作行为 if (ret == 0) { VM_ERR("Failed to read from file!"); OsReleaseFpage(mapping, fpage); return LOS_NOK; } LOS_SpinLockSave(&mapping->list_lock, &intSave); - OsAddToPageacheLru(fpage, mapping, vmf->pgoff);//将fpage加入 pageCache 和 LruCache + OsAddToPageacheLru(fpage, mapping, vmf->pgoff);//将fpage挂入pageCache 和 LruCache LOS_SpinUnlockRestore(&mapping->list_lock, intSave); } LOS_SpinLockSave(&mapping->list_lock, &intSave); /* cow fault case no need to save mapinfo */ if (!((vmf->flags & VM_MAP_PF_FLAG_WRITE) && !(region->regionFlags & VM_MAP_REGION_FLAG_SHARED))) { - OsAddMapInfo(fpage, ®ion->space->archMmu, (vaddr_t)vmf->vaddr);//既不共享,也不可写 就不用回写磁盘啦 + OsAddMapInfo(fpage, ®ion->space->archMmu, (vaddr_t)vmf->vaddr);//添加<虚拟地址,文件页>的映射关系,如此进程以后就能通过虚拟地址操作文件页了. fpage->flags = region->regionFlags; } @@ -575,7 +579,7 @@ INT32 OsVmmFileFault(LosVmMapRegion *region, LosVmPgFault *vmf) OsMarkPageDirty(fpage, region, 0, 0);//标记为脏页,要回写磁盘,内核会在适当的时候回写磁盘 } - vmf->pageKVaddr = kvaddr;//将文件页的虚拟地址带给缺陷页 + vmf->pageKVaddr = kvaddr;//缺陷页记录文件页的虚拟地址 LOS_SpinUnlockRestore(&mapping->list_lock, intSave); return LOS_OK; } diff --git a/kernel/base/vm/los_vm_scan.c b/kernel/base/vm/los_vm_scan.c index 60b6d692..59af7fd1 100644 --- a/kernel/base/vm/los_vm_scan.c +++ b/kernel/base/vm/los_vm_scan.c @@ -197,7 +197,7 @@ VOID OsPageRefDecNoLock(LosFilePage *fpage) page = fpage->vmPage; isOrgActive = OsIsPageActive(page); - if (!OsIsPageReferenced(page) && OsIsPageActive(page)) { + if (!OsIsPageReferenced(page) && OsIsPageActive(page)) {//[ref:0,act:1]的情况 OsCleanPageActive(page); OsSetPageReferenced(page); } else if (OsIsPageReferenced(page)) { @@ -208,7 +208,7 @@ VOID OsPageRefDecNoLock(LosFilePage *fpage) OsMoveToInactiveList(fpage); } } -//缩小未活动页链表 +//缩小活动页链表 VOID OsShrinkActiveList(LosVmPhysSeg *physSeg, int nScan) { LosFilePage *fpage = NULL; diff --git a/zzz/doc/note_fs.h b/zzz/doc/note_fs.h new file mode 100644 index 00000000..6c06822e --- /dev/null +++ b/zzz/doc/note_fs.h @@ -0,0 +1,35 @@ +#ifndef _NOTE_FS_H +#define _NOTE_FS_H + +#if 0 +共享内存写保持同步 +文件页下标不变,写的内容大于4k时,产生缺页继续写page cache , +脏页,凭文件页下标+脏页偏移量写回磁盘 +#endif + + + + + + + + + + + + + + + + + + + + + + + + + + +#endif diff --git a/zzz/doc/note_ipc.h b/zzz/doc/note_ipc.h index 309cd5ca..544ff803 100644 --- a/zzz/doc/note_ipc.h +++ b/zzz/doc/note_ipc.h @@ -1,11 +1,8 @@ #ifndef _NOTE_IPC_H #define _NOTE_IPC_H - -/**************************************************************** +#if 0 信号量是为了解决task的资源同步问题,有多少资源就设多大的资源最大值 - - 信号量机制: 以一个停车场的运作为例。假设停车场只有三个车位,一开始三个车位都是空的。这时如果同时来了五辆车, @@ -20,11 +17,8 @@ 当前资源计数器决定不会大于最大资源计数 最大资源计数,表示可以控件的最大资源数量 当前资源计数,表示当前可用资源的数量 +#endif - -****************************************************************/ - -/* */ /****************************************************************************** ******************************************************************************/ diff --git a/zzz/git/push.sh b/zzz/git/push.sh index eb196e8c..1d7f7ce2 100644 --- a/zzz/git/push.sh +++ b/zzz/git/push.sh @@ -1,10 +1,10 @@ git add -A -git commit -m '注解1.对缺页中断的处理 2.物理地址的管理 -搜索 @note_pic 可以查看全部字符图 -搜索 @note_why 是注者尚未看明白的地方,如果您看明白了,请告诉注者完善 -搜索 @note_thinking 是注者的思考和吐槽的地方 -搜索 @note_#if0 是由第三方项目提供不由内核源码中定义的极为重要的结构体,为方便理解而添加的。 -搜索 @note_good 是注者给源码点赞的地方 +git commit -m '注解写时复制(Copy On Write)技术在鸿蒙内核的实现 +搜索 @note_pic 方便理解画的字符图 +搜索 @note_why 尚未看明白的地方,如果您看明白了,请告知完善 +搜索 @note_thinking 一点思考和吐槽的地方 +搜索 @note_#if0 由第三方项目提供不由内核源码中定义的极为重要的结构体,为方便理解而添加的 +搜索 @note_good 给源码点赞 ' git push origin master -- GitLab