From 231cb6be27380948bc48136ae2e02c28450f47a8 Mon Sep 17 00:00:00 2001 From: mucor Date: Mon, 21 Jun 2021 16:11:06 +0800 Subject: [PATCH] feat: add /proc/fs_cache to display cache info add /proc/fs_cache to display vnode, path cache, page cache. also change some bad virable name close: #I3WWBD Signed-off-by: mucor --- fs/proc/include/internal.h | 2 + fs/proc/os_adapt/fs_cache_proc.c | 192 +++++++++++++++++++++++++++ fs/proc/os_adapt/proc_init.c | 1 + fs/vfs/include/path_cache.h | 7 + fs/vfs/include/vnode.h | 3 + fs/vfs/path_cache.c | 72 ++++++---- fs/vfs/vnode.c | 31 +++-- kernel/base/include/los_vm_filemap.h | 3 + kernel/base/vm/los_vm_filemap.c | 20 +++ 9 files changed, 299 insertions(+), 32 deletions(-) create mode 100644 fs/proc/os_adapt/fs_cache_proc.c diff --git a/fs/proc/include/internal.h b/fs/proc/include/internal.h index 886ab3ce..03df8ec9 100644 --- a/fs/proc/include/internal.h +++ b/fs/proc/include/internal.h @@ -63,6 +63,8 @@ extern void ProcMountsInit(void); extern void ProcUptimeInit(void); +extern void ProcFsCacheInit(void); + #ifdef __cplusplus #if __cplusplus } diff --git a/fs/proc/os_adapt/fs_cache_proc.c b/fs/proc/os_adapt/fs_cache_proc.c new file mode 100644 index 00000000..b026704b --- /dev/null +++ b/fs/proc/os_adapt/fs_cache_proc.c @@ -0,0 +1,192 @@ +/* + * Copyright (c) 2021-2021 Huawei Device Co., Ltd. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, + * are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, this list of + * conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, this list + * of conditions and the following disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * 3. Neither the name of the copyright holder nor the names of its contributors may be used + * to endorse or promote products derived from this software without specific prior written + * permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, + * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; + * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, + * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR + * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF + * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include "internal.h" +#include "proc_fs.h" +#include "vnode.h" +#include "path_cache.h" +#include "los_vm_filemap.h" + +#ifdef LOSCFG_DEBUG_VERSION +static char* VnodeTypeToStr(enum VnodeType type) { + switch (type) { + case VNODE_TYPE_UNKNOWN: + return "UKN"; + case VNODE_TYPE_REG: + return "REG"; + case VNODE_TYPE_DIR: + return "DIR"; + case VNODE_TYPE_BLK: + return "BLK"; + case VNODE_TYPE_CHR: + return "CHR"; + case VNODE_TYPE_BCHR: + return "BCH"; + case VNODE_TYPE_FIFO: + return "FIF"; + case VNODE_TYPE_LNK: + return "LNK"; + default: + return "BAD"; + } +} + +static int VnodeListProcess(struct SeqBuf *buf, LIST_HEAD* list) +{ + int count = 0; + struct Vnode *item = NULL; + struct Vnode *nextItem = NULL; + + LOS_DL_LIST_FOR_EACH_ENTRY_SAFE(item, nextItem, list, struct Vnode, actFreeEntry) { + LosBufPrintf(buf, "%-10p %-10p %-10p %10p 0x%08x %-3d %-4s %-3d %-3d %o\n", + item, item->parent, item->data, item->vop, item->hash, item->useCount, + VnodeTypeToStr(item->type), item->gid, item->uid, item->mode); + count++; + } + + return count; +} + +static int PathCacheListProcess(struct SeqBuf *buf) +{ + int count = 0; + LIST_HEAD* bucketList = GetPathCacheList(); + + for (int i = 0; i < LOSCFG_MAX_PATH_CACHE_SIZE; i++) { + struct PathCache *pc = NULL; + LIST_HEAD *list = &bucketList[i]; + + LOS_DL_LIST_FOR_EACH_ENTRY(pc, list, struct PathCache, hashEntry) { + LosBufPrintf(buf, "%-3d %-10p %-11p %-10p %-9d %s\n", i, pc, + pc->parentVnode, pc->childVnode, pc->hit, pc->name); + count++; + } + } + + return count; +} + +static void PageCacheEntryProcess(struct SeqBuf *buf, struct page_mapping *mapping) +{ + LosFilePage *fpage = NULL; + + if (mapping == NULL) { + LosBufPrintf(buf, "null]\n"); + return; + } + + LOS_DL_LIST_FOR_EACH_ENTRY(fpage, &mapping->page_list, LosFilePage, node) { + LosBufPrintf(buf, "%d,", fpage->pgoff); + } + LosBufPrintf(buf, "]\n"); + return; +} + +static void PageCacheMapProcess(struct SeqBuf *buf) +{ + struct filelist *flist = &tg_filelist; + struct file *filep = NULL; + + (void)sem_wait(&flist->fl_sem); + for (int i = 3; i < CONFIG_NFILE_DESCRIPTORS; i++) { + if (!get_bit(i)) { + continue; + } + filep = &flist->fl_files[i]; + if (filep == NULL) { + continue; + } + LosBufPrintf(buf, "[%d]%s:[", i, filep->f_path); + PageCacheEntryProcess(buf, filep->f_mapping); + } + (void)sem_post(&flist->fl_sem); +} + +static int FsCacheInfoFill(struct SeqBuf *buf, void *arg) +{ + int vnodeFree= 0; + int vnodeActive= 0; + int vnodeVirtual= 0; + int vnodeTotal = 0; + + int pathCacheTotal = 0; + int pathCacheTotalTry = 0; + int pathCacheTotalHit = 0; + + int pageCacheTotalTry = 0; + int pageCacheTotalHit = 0; + + ResetPathCacheHitInfo(&pathCacheTotalHit, &pathCacheTotalTry); + ResetPageCacheHitInfo(&pageCacheTotalTry, &pageCacheTotalHit); + + VnodeHold(); + LosBufPrintf(buf, "\n=================================================================\n"); + LosBufPrintf(buf, "VnodeAddr ParentAddr DataAddr VnodeOps Hash Ref Type Gid Uid Mode\n"); + vnodeVirtual = VnodeListProcess(buf, GetVnodeVirtualList()); + vnodeFree = VnodeListProcess(buf, GetVnodeFreeList()); + vnodeActive = VnodeListProcess(buf, GetVnodeActiveList()); + vnodeTotal = vnodeVirtual + vnodeFree + vnodeActive; + + LosBufPrintf(buf, "\n=================================================================\n"); + LosBufPrintf(buf, "No. CacheAddr ParentAddr ChildAddr HitCount Name\n"); + pathCacheTotal = PathCacheListProcess(buf); + + LosBufPrintf(buf, "\n=================================================================\n"); + PageCacheMapProcess(buf); + LosBufPrintf(buf, "\n=================================================================\n"); + LosBufPrintf(buf, "PathCache Total:%d Try:%d Hit:%d\n", + pathCacheTotal, pathCacheTotalTry, pathCacheTotalHit); + LosBufPrintf(buf, "Vnode Total:%d Free:%d Virtual:%d Active:%d\n", + vnodeTotal, vnodeFree, vnodeVirtual, vnodeActive); + LosBufPrintf(buf, "PageCache Try:%d Hit:%d\n", pageCacheTotalTry, pageCacheTotalHit); + VnodeDrop(); + return 0; +} + +static const struct ProcFileOperations FS_CACHE_PROC_FOPS = { + .read = FsCacheInfoFill, +}; + +void ProcFsCacheInit(void) +{ + struct ProcDirEntry *pde = CreateProcEntry("fs_cache", 0, NULL); + if (pde == NULL) { + PRINT_ERR("create fs_cache error!\n"); + return; + } + + pde->procFileOps = &FS_CACHE_PROC_FOPS; +} +#else +void ProcFsCacheInit(void) +{ + /* do nothing in release version */ +} +#endif diff --git a/fs/proc/os_adapt/proc_init.c b/fs/proc/os_adapt/proc_init.c index a8616ca8..ef111c7c 100644 --- a/fs/proc/os_adapt/proc_init.c +++ b/fs/proc/os_adapt/proc_init.c @@ -64,6 +64,7 @@ void ProcFsInit(void) ProcProcessInit(); ProcUptimeInit(); ProcKernelTraceInit(); + ProcFsCacheInit(); } LOS_MODULE_INIT(ProcFsInit, LOS_INIT_LEVEL_KMOD_EXTENDED); diff --git a/fs/vfs/include/path_cache.h b/fs/vfs/include/path_cache.h index 1b8e861d..2515ea28 100644 --- a/fs/vfs/include/path_cache.h +++ b/fs/vfs/include/path_cache.h @@ -42,6 +42,9 @@ struct PathCache { LIST_ENTRY childEntry; /* list entry for cache list in the child vnode */ LIST_ENTRY hashEntry; /* list entry for buckets in the hash table */ uint8_t nameLen; /* length of path component */ +#ifdef LOSCFG_DEBUG_VERSION + int hit; /* cache hit count*/ +#endif char name[0]; /* path component name */ }; @@ -52,5 +55,9 @@ int PathCacheLookup(struct Vnode *parent, const char *name, int len, struct Vnod void VnodePathCacheFree(struct Vnode *vnode); void PathCacheMemoryDump(void); void PathCacheDump(void); +LIST_HEAD* GetPathCacheList(void); +#ifdef LOSCFG_DEBUG_VERSION +void ResetPathCacheHitInfo(int *hit, int *try); +#endif #endif /* _PATH_CACHE_H */ diff --git a/fs/vfs/include/vnode.h b/fs/vfs/include/vnode.h index b138416f..ba13e8b9 100644 --- a/fs/vfs/include/vnode.h +++ b/fs/vfs/include/vnode.h @@ -176,5 +176,8 @@ void VnodeMemoryDump(void); mode_t GetUmask(void); int VfsPermissionCheck(uint fuid, uint fgid, mode_t fileMode, int accMode); int VfsVnodePermissionCheck(const struct Vnode *node, int accMode); +LIST_HEAD* GetVnodeFreeList(void); +LIST_HEAD* GetVnodeActiveList(void); +LIST_HEAD* GetVnodeVirtualList(void); #endif /* !_VNODE_H_ */ diff --git a/fs/vfs/path_cache.c b/fs/vfs/path_cache.c index 01543c50..ef80df6a 100644 --- a/fs/vfs/path_cache.c +++ b/fs/vfs/path_cache.c @@ -37,6 +37,23 @@ #define PATH_CACHE_HASH_MASK (LOSCFG_MAX_PATH_CACHE_SIZE - 1) LIST_HEAD g_pathCacheHashEntrys[LOSCFG_MAX_PATH_CACHE_SIZE]; +#ifdef LOSCFG_DEBUG_VERSION +static int g_totalPathCacheHit = 0; +static int g_totalPathCacheTry = 0; +#define TRACE_TRY_CACHE() do { g_totalPathCacheTry++; } while (0) +#define TRACE_HIT_CACHE(pc) do { pc->hit++; g_totalPathCacheHit++; } while (0) + +void ResetPathCacheHitInfo(int *hit, int *try) +{ + *hit = g_totalPathCacheHit; + *try = g_totalPathCacheTry; + g_totalPathCacheHit = 0; + g_totalPathCacheTry = 0; +} +#else +#define TRACE_TRY_CACHE() +#define TRACE_HIT_CACHE(pc) +#endif int PathCacheInit(void) { @@ -50,12 +67,12 @@ void PathCacheDump(void) { PRINTK("-------->pathCache dump in\n"); for (int i = 0; i < LOSCFG_MAX_PATH_CACHE_SIZE; i++) { - struct PathCache *nc = NULL; + struct PathCache *pc = NULL; LIST_HEAD *nhead = &g_pathCacheHashEntrys[i]; - LOS_DL_LIST_FOR_EACH_ENTRY(nc, nhead, struct PathCache, hashEntry) { + LOS_DL_LIST_FOR_EACH_ENTRY(pc, nhead, struct PathCache, hashEntry) { PRINTK(" pathCache dump hash %d item %s %p %p %d\n", i, - nc->name, nc->parentVnode, nc->childVnode, nc->nameLen); + pc->name, pc->parentVnode, pc->childVnode, pc->nameLen); } } PRINTK("-------->pathCache dump out\n"); @@ -94,7 +111,7 @@ static void PathCacheInsert(struct Vnode *parent, struct PathCache *cache, const struct PathCache *PathCacheAlloc(struct Vnode *parent, struct Vnode *vnode, const char *name, uint8_t len) { - struct PathCache *nc = NULL; + struct PathCache *pc = NULL; size_t pathCacheSize; int ret; @@ -103,53 +120,55 @@ struct PathCache *PathCacheAlloc(struct Vnode *parent, struct Vnode *vnode, cons } pathCacheSize = sizeof(struct PathCache) + len + 1; - nc = (struct PathCache*)zalloc(pathCacheSize); - if (nc == NULL) { + pc = (struct PathCache*)zalloc(pathCacheSize); + if (pc == NULL) { PRINT_ERR("pathCache alloc failed, no memory!\n"); return NULL; } - ret = strncpy_s(nc->name, len + 1, name, len); + ret = strncpy_s(pc->name, len + 1, name, len); if (ret != LOS_OK) { return NULL; } - nc->parentVnode = parent; - nc->nameLen = len; - nc->childVnode = vnode; + pc->parentVnode = parent; + pc->nameLen = len; + pc->childVnode = vnode; - LOS_ListAdd((&(parent->childPathCaches)), (&(nc->childEntry))); - LOS_ListAdd((&(vnode->parentPathCaches)), (&(nc->parentEntry))); + LOS_ListAdd((&(parent->childPathCaches)), (&(pc->childEntry))); + LOS_ListAdd((&(vnode->parentPathCaches)), (&(pc->parentEntry))); - PathCacheInsert(parent, nc, name, len); + PathCacheInsert(parent, pc, name, len); - return nc; + return pc; } -int PathCacheFree(struct PathCache *nc) +int PathCacheFree(struct PathCache *pc) { - if (nc == NULL) { + if (pc == NULL) { PRINT_ERR("pathCache free: invalid pathCache\n"); return -ENOENT; } - LOS_ListDelete(&nc->hashEntry); - LOS_ListDelete(&nc->parentEntry); - LOS_ListDelete(&nc->childEntry); - free(nc); + LOS_ListDelete(&pc->hashEntry); + LOS_ListDelete(&pc->parentEntry); + LOS_ListDelete(&pc->childEntry); + free(pc); return LOS_OK; } int PathCacheLookup(struct Vnode *parent, const char *name, int len, struct Vnode **vnode) { - struct PathCache *nc = NULL; + struct PathCache *pc = NULL; int hash = NameHash(name, len, parent) & PATH_CACHE_HASH_MASK; LIST_HEAD *dhead = &g_pathCacheHashEntrys[hash]; - LOS_DL_LIST_FOR_EACH_ENTRY(nc, dhead, struct PathCache, hashEntry) { - if (nc->parentVnode == parent && nc->nameLen == len && !strncmp(nc->name, name, len)) { - *vnode = nc->childVnode; + TRACE_TRY_CACHE(); + LOS_DL_LIST_FOR_EACH_ENTRY(pc, dhead, struct PathCache, hashEntry) { + if (pc->parentVnode == parent && pc->nameLen == len && !strncmp(pc->name, name, len)) { + *vnode = pc->childVnode; + TRACE_HIT_CACHE(pc); return LOS_OK; } } @@ -184,3 +203,8 @@ void VnodePathCacheFree(struct Vnode *vnode) FreeParentPathCache(vnode); FreeChildPathCache(vnode); } + +LIST_HEAD* GetPathCacheList() +{ + return g_pathCacheHashEntrys; +} diff --git a/fs/vfs/vnode.c b/fs/vfs/vnode.c index c66bdec5..95bf120b 100644 --- a/fs/vfs/vnode.c +++ b/fs/vfs/vnode.c @@ -35,7 +35,7 @@ LIST_HEAD g_vnodeFreeList; /* free vnodes list */ LIST_HEAD g_vnodeVirtualList; /* dev vnodes list */ -LIST_HEAD g_vnodeCurrList; /* inuse vnodes list */ +LIST_HEAD g_vnodeActiveList; /* inuse vnodes list */ static int g_freeVnodeSize = 0; /* system free vnodes size */ static int g_totalVnodeSize = 0; /* total vnode size */ @@ -57,7 +57,7 @@ int VnodesInit(void) LOS_ListInit(&g_vnodeFreeList); LOS_ListInit(&g_vnodeVirtualList); - LOS_ListInit(&g_vnodeCurrList); + LOS_ListInit(&g_vnodeActiveList); retval = VnodeAlloc(NULL, &g_rootVnode); if (retval != LOS_OK) { PRINT_ERR("VnodeInit failed error %d\n", retval); @@ -94,7 +94,7 @@ struct Vnode *VnodeReclaimLru(void) struct Vnode *nextItem = NULL; int releaseCount = 0; - LOS_DL_LIST_FOR_EACH_ENTRY_SAFE(item, nextItem, &g_vnodeCurrList, struct Vnode, actFreeEntry) { + LOS_DL_LIST_FOR_EACH_ENTRY_SAFE(item, nextItem, &g_vnodeActiveList, struct Vnode, actFreeEntry) { if ((item->useCount > 0) || (item->flag & VNODE_FLAG_MOUNT_ORIGIN) || (item->flag & VNODE_FLAG_MOUNT_NEW)) { @@ -152,7 +152,7 @@ int VnodeAlloc(struct VnodeOps *vop, struct Vnode **newVnode) LOS_ListAdd(&g_vnodeVirtualList, &(vnode->actFreeEntry)); vnode->vop = &g_devfsOps; } else { - LOS_ListTailInsert(&g_vnodeCurrList, &(vnode->actFreeEntry)); + LOS_ListTailInsert(&g_vnodeActiveList, &(vnode->actFreeEntry)); vnode->vop = vop; } VnodeDrop(); @@ -204,7 +204,7 @@ int VnodeFreeAll(const struct Mount *mount) struct Vnode *nextVnode = NULL; int ret; - LOS_DL_LIST_FOR_EACH_ENTRY_SAFE(vnode, nextVnode, &g_vnodeCurrList, struct Vnode, actFreeEntry) { + LOS_DL_LIST_FOR_EACH_ENTRY_SAFE(vnode, nextVnode, &g_vnodeActiveList, struct Vnode, actFreeEntry) { if ((vnode->originMount == mount) && !(vnode->flag & VNODE_FLAG_MOUNT_NEW)) { ret = VnodeFree(vnode); if (ret != LOS_OK) { @@ -220,7 +220,7 @@ BOOL VnodeInUseIter(const struct Mount *mount) { struct Vnode *vnode = NULL; - LOS_DL_LIST_FOR_EACH_ENTRY(vnode, &g_vnodeCurrList, struct Vnode, actFreeEntry) { + LOS_DL_LIST_FOR_EACH_ENTRY(vnode, &g_vnodeActiveList, struct Vnode, actFreeEntry) { if (vnode->originMount == mount) { if ((vnode->useCount > 0) || (vnode->flag & VNODE_FLAG_MOUNT_ORIGIN)) { return TRUE; @@ -294,7 +294,7 @@ static void RefreshLRU(struct Vnode *vnode) return; } LOS_ListDelete(&(vnode->actFreeEntry)); - LOS_ListTailInsert(&g_vnodeCurrList, &(vnode->actFreeEntry)); + LOS_ListTailInsert(&g_vnodeActiveList, &(vnode->actFreeEntry)); } static int ProcessVirtualVnode(struct Vnode *parent, uint32_t flags, struct Vnode **vnode) @@ -612,7 +612,7 @@ void VnodeMemoryDump(void) struct Vnode *nextItem = NULL; int vnodeCount = 0; - LOS_DL_LIST_FOR_EACH_ENTRY_SAFE(item, nextItem, &g_vnodeCurrList, struct Vnode, actFreeEntry) { + LOS_DL_LIST_FOR_EACH_ENTRY_SAFE(item, nextItem, &g_vnodeActiveList, struct Vnode, actFreeEntry) { if ((item->useCount > 0) || (item->flag & VNODE_FLAG_MOUNT_ORIGIN) || (item->flag & VNODE_FLAG_MOUNT_NEW)) { @@ -625,3 +625,18 @@ void VnodeMemoryDump(void) PRINTK("Vnode number = %d\n", vnodeCount); PRINTK("Vnode memory size = %d(B)\n", vnodeCount * sizeof(struct Vnode)); } + +LIST_HEAD* GetVnodeFreeList() +{ + return &g_vnodeFreeList; +} + +LIST_HEAD* GetVnodeVirtualList() +{ + return &g_vnodeVirtualList; +} + +LIST_HEAD* GetVnodeActiveList() +{ + return &g_vnodeActiveList; +} diff --git a/kernel/base/include/los_vm_filemap.h b/kernel/base/include/los_vm_filemap.h index 70047b20..17120118 100644 --- a/kernel/base/include/los_vm_filemap.h +++ b/kernel/base/include/los_vm_filemap.h @@ -206,6 +206,9 @@ VOID OsMarkPageDirty(LosFilePage *fpage, LosVmMapRegion *region, int off, int le typedef struct ProcessCB LosProcessCB; VOID OsVmmFileRegionFree(struct file *filep, LosProcessCB *processCB); +#ifdef LOSCFG_DEBUG_VERSION +VOID ResetPageCacheHitInfo(int *try, int *hit); +#endif #ifdef __cplusplus #if __cplusplus } diff --git a/kernel/base/vm/los_vm_filemap.c b/kernel/base/vm/los_vm_filemap.c index e63ee4c5..9a6ec2ce 100644 --- a/kernel/base/vm/los_vm_filemap.c +++ b/kernel/base/vm/los_vm_filemap.c @@ -47,6 +47,24 @@ #define UNUSED(x) (VOID)x #endif +#ifdef LOSCFG_DEBUG_VERSION +static int g_totalPageCacheTry = 0; +static int g_totalPageCacheHit = 0; +#define TRACE_TRY_CACHE() do { g_totalPageCacheTry++; } while (0) +#define TRACE_HIT_CACHE() do { g_totalPageCacheHit++; } while (0) + +VOID ResetPageCacheHitInfo(int *try, int *hit) +{ + *try = g_totalPageCacheTry; + *hit = g_totalPageCacheHit; + g_totalPageCacheHit = 0; + g_totalPageCacheTry = 0; +} +#else +#define TRACE_TRY_CACHE() +#define TRACE_HIT_CACHE() +#endif + #ifdef LOSCFG_KERNEL_VM STATIC VOID OsPageCacheAdd(LosFilePage *page, struct page_mapping *mapping, VM_OFFSET_T pgoff) @@ -365,7 +383,9 @@ INT32 OsVmmFileFault(LosVmMapRegion *region, LosVmPgFault *vmf) /* get or create a new cache node */ LOS_SpinLockSave(&mapping->list_lock, &intSave); fpage = OsFindGetEntry(mapping, vmf->pgoff); + TRACE_TRY_CACHE(); if (fpage != NULL) { + TRACE_HIT_CACHE(); OsPageRefIncLocked(fpage); } else { fpage = OsPageCacheAlloc(mapping, vmf->pgoff);