49#define UNUSED(x) (VOID)(x)
52#ifdef LOSCFG_DEBUG_VERSION
55#define TRACE_TRY_CACHE() do { g_totalPageCacheTry++; } while (0)
56#define TRACE_HIT_CACHE() do { g_totalPageCacheHit++; } while (0)
66#define TRACE_TRY_CACHE()
67#define TRACE_HIT_CACHE()
69#ifdef LOSCFG_KERNEL_VM
88 if (fpage->
pgoff > pgoff) {
133 VM_ERR(
"OsAddMapInfo alloc memory failed!");
149 LOS_DL_LIST_FOR_EACH_ENTRY(info, immap,
LosMapInfo, node) {
150 if ((info->
archMmu == archMmu) && (info->
vaddr == vaddr) && (info->
page == page)) {
174 VM_ERR(
"OsPageCacheUnmap get map info failed!");
191 struct Vnode *vnode = NULL;
205 if (status != LOS_OK) {
215 if ((fpage == NULL) || (fpage->
vmPage != mapPage)) {
235 if (region != NULL) {
241 if ((off + len) > fpage->
dirtyEnd) {
245 if (off < fpage->dirtyOff) {
256 struct stat buf_stat;
258 if (stat(vnode->
filePath, &buf_stat) != OK) {
259 VM_ERR(
"FlushDirtyPage get file size failed. (filePath=%s)", vnode->
filePath);
263 fileSize = buf_stat.st_size;
265 dirtyEnd = dirtyBegin + PAGE_SIZE;
267 if (dirtyBegin >= fileSize) {
271 if (dirtyEnd >= fileSize) {
272 return fileSize - dirtyBegin;
285 VM_ERR(
"page cache vnode error");
301 VM_ERR(
"WritePage error ret %d", ret);
305 ret = (ret <= 0) ? LOS_NOK : LOS_OK;
315 if (newFPage == NULL) {
316 VM_ERR(
"Failed to allocate for temp page!");
391 bool newCache =
false;
392 struct Vnode *vnode = NULL;
397 VM_ERR(
"Input param is NULL");
414 VM_ERR(
"Failed to alloc a page frame");
427 VM_ERR(
"Failed to read from file!");
438 if (!((vmf->
flags & VM_MAP_PF_FLAG_WRITE) && !(region->
regionFlags & VM_MAP_REGION_FLAG_SHARED))) {
444 if ((vmf->
flags & VM_MAP_PF_FLAG_WRITE) && (region->
regionFlags & VM_MAP_REGION_FLAG_SHARED)) {
461 if (mapping == NULL) {
477 LOS_DL_LIST_FOR_EACH_ENTRY_SAFE(fpage, ftemp, &dirtyList,
LosFilePage, node) {
512 LOS_DL_LIST_FOR_EACH_ENTRY_SAFE(fpage, fnext, &dirtyList,
LosFilePage, node) {
538 struct Vnode *vnode = NULL;
540 return LOS_ERRNO_VM_MAP_FAILED;
543 vnode = filep->f_vnode;
547 if (filep->ops != NULL && filep->ops->mmap != NULL) {
553 int ret = filep->ops->mmap(filep, region);
556 return LOS_ERRNO_VM_MAP_FAILED;
559 VM_ERR(
"mmap file type unknown");
561 return LOS_ERRNO_VM_MAP_FAILED;
576 if (fpage->
pgoff == pgoff) {
580 if (fpage->
pgoff > pgoff) {
602 if (vmPage == NULL) {
603 VM_ERR(
"alloc vm page failed");
608 if ((physSeg == NULL) || (kvaddr == NULL)) {
610 VM_ERR(
"alloc vm page failed!");
617 VM_ERR(
"Failed to allocate for page!");
632 fpage->
pgoff = pgoff;
633 (VOID)memset_s(kvaddr, PAGE_SIZE, 0, PAGE_SIZE);
STATIC INLINE VOID LOS_AtomicDec(Atomic *v)
Atomic auto-decrement. | 对32bit原子数据做减1
LITE_OS_SEC_ALW_INLINE STATIC INLINE VOID LOS_ListInit(LOS_DL_LIST *list)
LITE_OS_SEC_ALW_INLINE STATIC INLINE VOID LOS_ListTailInsert(LOS_DL_LIST *list, LOS_DL_LIST *node)
Insert a node to the tail of a doubly linked list.
LITE_OS_SEC_ALW_INLINE STATIC INLINE VOID LOS_ListDelete(LOS_DL_LIST *node)
LITE_OS_SEC_ALW_INLINE STATIC INLINE VOID LOS_ListAdd(LOS_DL_LIST *list, LOS_DL_LIST *node)
Insert a new node to a doubly linked list.
VOID * LOS_MemAlloc(VOID *pool, UINT32 size)
从指定内存池中申请size长度的内存,注意这可不是从内核堆空间中申请内存
UINT32 LOS_MemFree(VOID *pool, VOID *ptr)
释放从指定动态内存中申请的内存
UINT8 * m_aucSysMem0
异常交互动态内存池地址的起始地址,当不支持异常交互特性时,m_aucSysMem0等于m_aucSysMem1。
STATUS_T LOS_ArchMmuUnmap(LosArchMmu *archMmu, VADDR_T vaddr, size_t count)
LOS_ArchMmuUnmap 解除进程空间虚拟地址区间与物理地址区间的映射关系
STATUS_T LOS_ArchMmuQuery(const LosArchMmu *archMmu, VADDR_T vaddr, PADDR_T *paddr, UINT32 *flags)
LOS_ArchMmuQuery 获取进程空间虚拟地址对应的物理地址以及映射属性。 本函数是内核高频函数,通过MMU查询虚拟地址是否映射过,带走映射的物理地址和权限
VOID LOS_SpinUnlockRestore(SPIN_LOCK_S *lock, UINT32 intSave)
VOID LOS_SpinLockSave(SPIN_LOCK_S *lock, UINT32 *intSave)
unsigned long VM_OFFSET_T
VOID OsDeletePageCacheLru(LosFilePage *page)
删除页高速缓存和LRU,对应 OsAddToPageacheLru
LosMapInfo * OsGetMapInfo(LosFilePage *page, LosArchMmu *archMmu, VADDR_T vaddr)
通过虚拟地址获取文件页映射信息,archMmu每个进程都有属于自己的mmu
VOID OsVmmFileRemove(LosVmMapRegion *region, LosArchMmu *archMmu, VM_OFFSET_T pgoff)
删除文件
VOID OsFileCacheFlush(struct page_mapping *mapping)
文件缓存冲洗,把所有fpage冲洗一边,把脏页洗到dirtyList中,配合OsFileCacheRemove理解
VOID OsAddToPageacheLru(LosFilePage *page, struct page_mapping *mapping, VM_OFFSET_T pgoff)
将页面加到活动文件页LRU链表上
INT32 OsVmmFileFault(LosVmMapRegion *region, LosVmPgFault *vmf)
LosFilePage * OsDumpDirtyPage(LosFilePage *oldFPage)
备份脏页,老脏页撕掉脏页标签
VOID OsAddMapInfo(LosFilePage *page, LosArchMmu *archMmu, VADDR_T vaddr)
INT32 OsVfsFileMmap(struct file *filep, LosVmMapRegion *region)
STATIC VOID OsReleaseFpage(struct page_mapping *mapping, LosFilePage *fpage)
STATIC UINT32 GetDirtySize(LosFilePage *fpage, struct Vnode *vnode)
VOID OsPageCacheDel(LosFilePage *fpage)
从页高速缓存上删除页
VOID OsDoFlushDirtyPage(LosFilePage *fpage)
冲洗脏页数据,将脏页数据回写磁盘
static int g_totalPageCacheTry
STATIC INT32 OsFlushDirtyPage(LosFilePage *fpage)
冲洗脏页,回写磁盘
LosFilePage * OsPageCacheAlloc(struct page_mapping *mapping, VM_OFFSET_T pgoff)
static int g_totalPageCacheHit
VOID OsMarkPageDirty(LosFilePage *fpage, LosVmMapRegion *region, INT32 off, INT32 len)
标记page为脏页 进程修改了高速缓存里的数据时,该页就被内核标记为脏页
STATIC VOID OsPageCacheAdd(LosFilePage *page, struct page_mapping *mapping, VM_OFFSET_T pgoff)
VOID ResetPageCacheHitInfo(int *try, int *hit)
VOID OsDelMapInfo(LosVmMapRegion *region, LosVmPgFault *vmf, BOOL cleanDirty)
删除映射信息
LosVmFileOps g_commVmOps
虚拟内存文件操作实现类
VOID OsFileCacheRemove(struct page_mapping *mapping)
LosFilePage * OsFindGetEntry(struct page_mapping *mapping, VM_OFFSET_T pgoff)
STATIC VOID OsPageCacheUnmap(LosFilePage *fpage, LosArchMmu *archMmu, VADDR_T vaddr)
STATUS_T OsNamedMMap(struct file *filep, LosVmMapRegion *region)
VOID OsPageRefDecNoLock(LosFilePage *page)
VOID OsPageRefIncLocked(LosFilePage *page)
VOID OsLruCacheAdd(LosFilePage *fpage, enum OsLruList lruType)
STATIC INLINE VOID OsCleanPageDirty(LosVmPage *page)
给页面撕掉数据被修改的标签
STATIC INLINE VOID OsCleanPageLocked(LosVmPage *page)
给页面撕掉被锁的标签
STATIC INLINE VOID OsSetPageDirty(LosVmPage *page)
给页面贴上数据被修改的标签
VOID OsUnmapAllLocked(LosFilePage *page)
解除文件页在所有进程的映射
VOID OsLruCacheDel(LosFilePage *fpage)
STATIC INLINE BOOL OsIsPageMapped(LosFilePage *page)
文件页是否映射过了
STATIC INLINE BOOL OsIsPageDirty(LosVmPage *page)
页面是否为脏页,所谓脏页就是页内数据是否被更新过,只有脏页才会有写时拷贝
struct FilePage LosFilePage
文件页结构体
VOID OsUnmapPageLocked(LosFilePage *page, LosMapInfo *info)
STATIC INLINE VOID OsSetPageLocked(LosVmPage *page)
给页面贴上被锁的标签
LOS_DL_LIST_HEAD(g_vmSpaceList)
初始化全局虚拟空间节点,所有虚拟空间都挂到此节点上.
STATIC INLINE VOID LOS_SetRegionTypeFile(LosVmMapRegion *region)
设置线性区为文件映射
BOOL LOS_IsRegionFileValid(LosVmMapRegion *region)
映射类型为文件的线性区是否有效
STATIC INLINE VOID LOS_SetRegionTypeDev(LosVmMapRegion *region)
设为设备映射线性区
LosVmPage * LOS_VmPageGet(PADDR_T paddr)
通过物理地址获取页框
@ VM_LRU_ACTIVE_FILE
活动文件页(磁盘)
VOID LOS_PhysPageFree(LosVmPage *page)
释放一个物理页框
struct VmPhysSeg * OsVmPhysSegGet(LosVmPage *page)
获取物理页框所在段
LosVmPage * LOS_PhysPageAlloc(VOID)
申请一个物理页
VOID * OsVmPageToVaddr(LosVmPage *page)
通过page获取内核空间的虚拟地址 参考OsArchMmuInit #define SYS_MEM_BASE DDR_MEM_ADDR /* physical memory base 物理地址的起始...
内存管理单元(英语:memory management unit,缩写为MMU),有时称作分页内存管理单元(英语:paged memory management unit,缩写为PMMU)。
LOS_DL_LIST lru
lru节点, 结合 LosVmPhysSeg: LOS_DL_LIST lruList[VM_NR_LRU_LISTS] 理解
struct VmPage * vmPage
物理页框
struct VmPhysSeg * physSeg
VM_OFFSET_T pgoff
页标,文件被切成一页一页读到内存
struct page_mapping * mapping
此结构由文件系统提供,用于描述装入点 见于 ..\third_party\NuttX\fs\fs.h
LOS_DL_LIST node
节点,节点挂到page_mapping.page_list上,链表以 pgoff 从小到大方式排序.
虚拟地址和文件页的映射信息,在一个进程使用文件页之前,需要提前做好文件页在此内存空间的映射关系,如此通过虚拟内存就可以对文件页读写操作.
LosFilePage * page
文件页中只记录物理地址,是不会变的.但它是需要被多个进程访问,和映射的.
VADDR_T vaddr
虚拟地址.每个进程访问同一个文件页的虚拟地址都是不一样的
LosArchMmu * archMmu
mmu完成vaddr和page->vmPage->physAddr物理地址的映射
LOS_DL_LIST node
节点,挂到page->i_mmap链表上.链表上记录要操作文件页的进程对这个page的映射信息
虚拟内存文件操作函数指针,上层开发可理解为 class 里的方法,注意是对线性区的操作 , 文件操作 见于g_commVmOps
void(* open)(struct VmMapRegion *region)
打开
struct VmMapRegion::@4::VmRegionFile rf
union VmMapRegion::@4 unTypeData
LosVmSpace * space
所属虚拟空间,虚拟空间由多个线性区组成
物理页框描述符 虚拟内存体现的是程序对内存资源的需求,而物理内存是对该请求的供应。 伙伴算法的思想是:把内存中连续的空闲页框空间看成是空闲页框块,并按照它们的大小(连续页框的数目)分组
SPIN_LOCK_S lruLock
用于置换的自旋锁,用于操作lruList
vnode并不包含文件名,因为 vnode和文件名是 1:N 的关系
struct page_mapping mapping
ssize_t(* WritePage)(struct Vnode *vnode, char *buffer, off_t pos, size_t buflen)
ssize_t(* ReadPage)(struct Vnode *vnode, char *buffer, off_t pos)
int VnodeHold(void)
拿锁,封装互斥量