1/* 2 * Copyright (c) 2021-2022 Huawei Device Co., Ltd. All rights reserved. 3 * 4 * Redistribution and use in source and binary forms, with or without modification, 5 * are permitted provided that the following conditions are met: 6 * 7 * 1. Redistributions of source code must retain the above copyright notice, this list of 8 * conditions and the following disclaimer. 9 * 10 * 2. Redistributions in binary form must reproduce the above copyright notice, this list 11 * of conditions and the following disclaimer in the documentation and/or other materials 12 * provided with the distribution. 13 * 14 * 3. Neither the name of the copyright holder nor the names of its contributors may be used 15 * to endorse or promote products derived from this software without specific prior written 16 * permission. 17 * 18 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 19 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, 20 * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 21 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR 22 * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, 23 * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, 24 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; 25 * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, 26 * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR 27 * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF 28 * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 29 */ 30 31#include "internal.h" 32#include "proc_fs.h" 33#include "vnode.h" 34#include "path_cache.h" 35#include "los_vm_filemap.h" 36 37#ifdef LOSCFG_DEBUG_VERSION 38 39#define CLEAR_ALL_CACHE "clear all" 40#define CLEAR_PATH_CACHE "clear pathcache" 41#define CLEAR_PAGE_CACHE "clear pagecache" 42 43static char* VnodeTypeToStr(enum VnodeType type) 44{ 45 switch (type) { 46 case VNODE_TYPE_UNKNOWN: 47 return "UKN"; 48 case VNODE_TYPE_REG: 49 return "REG"; 50 case VNODE_TYPE_DIR: 51 return "DIR"; 52 case VNODE_TYPE_BLK: 53 return "BLK"; 54 case VNODE_TYPE_CHR: 55 return "CHR"; 56 case VNODE_TYPE_BCHR: 57 return "BCH"; 58 case VNODE_TYPE_FIFO: 59 return "FIF"; 60 case VNODE_TYPE_LNK: 61 return "LNK"; 62 default: 63 return "BAD"; 64 } 65} 66 67static int VnodeListProcess(struct SeqBuf *buf, LIST_HEAD* list) 68{ 69 int count = 0; 70 struct Vnode *item = NULL; 71 struct Vnode *nextItem = NULL; 72 73 LOS_DL_LIST_FOR_EACH_ENTRY_SAFE(item, nextItem, list, struct Vnode, actFreeEntry) { 74 LosBufPrintf(buf, "%-10p %-10p %-10p %10p 0x%08x %-3d %-4s %-3d %-3d %-8o\t%s\n", 75 item, item->parent, item->data, item->vop, item->hash, item->useCount, 76 VnodeTypeToStr(item->type), item->gid, item->uid, item->mode, item->filePath); 77 count++; 78 } 79 80 return count; 81} 82 83static int PathCacheListProcess(struct SeqBuf *buf) 84{ 85 int count = 0; 86 LIST_HEAD* bucketList = GetPathCacheList(); 87 88 for (int i = 0; i < LOSCFG_MAX_PATH_CACHE_SIZE; i++) { 89 struct PathCache *pc = NULL; 90 LIST_HEAD *list = &bucketList[i]; 91 92 LOS_DL_LIST_FOR_EACH_ENTRY(pc, list, struct PathCache, hashEntry) { 93 LosBufPrintf(buf, "%-3d %-10p %-11p %-10p %-9d %s\n", i, pc, 94 pc->parentVnode, pc->childVnode, pc->hit, pc->name); 95 count++; 96 } 97 } 98 99 return count; 100} 101 102static int PageCacheEntryProcess(struct SeqBuf *buf, struct page_mapping *mapping) 103{ 104 int total = 0; 105 LosFilePage *fpage = NULL; 106 107 if (mapping->nrpages == 0) { 108 LosBufPrintf(buf, "null]\n"); 109 return total; 110 } 111 112 LOS_DL_LIST_FOR_EACH_ENTRY(fpage, &mapping->page_list, LosFilePage, node) { 113 LosBufPrintf(buf, "%d,", fpage->pgoff); 114 total++; 115 } 116 LosBufPrintf(buf, "]\n"); 117 return total; 118} 119 120static int PageCacheMapProcess(struct SeqBuf *buf) 121{ 122 LIST_HEAD *vnodeList = GetVnodeActiveList(); 123 struct page_mapping *mapping = NULL; 124 struct Vnode *vnode = NULL; 125 int total = 0; 126 127 VnodeHold(); 128 LOS_DL_LIST_FOR_EACH_ENTRY(vnode, vnodeList, struct Vnode, actFreeEntry) { 129 mapping = &vnode->mapping; 130 LosBufPrintf(buf, "%p, %s:[", vnode, vnode->filePath); 131 total += PageCacheEntryProcess(buf, mapping); 132 } 133 VnodeDrop(); 134 return total; 135} 136 137static int FsCacheInfoFill(struct SeqBuf *buf, void *arg) 138{ 139 int vnodeFree; 140 int vnodeActive; 141 int vnodeVirtual; 142 int vnodeTotal; 143 144 int pathCacheTotal; 145 int pathCacheTotalTry = 0; 146 int pathCacheTotalHit = 0; 147 148 int pageCacheTotal; 149 int pageCacheTotalTry = 0; 150 int pageCacheTotalHit = 0; 151 152 ResetPathCacheHitInfo(&pathCacheTotalHit, &pathCacheTotalTry); 153 ResetPageCacheHitInfo(&pageCacheTotalTry, &pageCacheTotalHit); 154 155 VnodeHold(); 156 LosBufPrintf(buf, "\n=================================================================\n"); 157 LosBufPrintf(buf, 158 "VnodeAddr ParentAddr DataAddr VnodeOps Hash Ref Type Gid Uid Mode\n"); 159 vnodeVirtual = VnodeListProcess(buf, GetVnodeVirtualList()); 160 vnodeFree = VnodeListProcess(buf, GetVnodeFreeList()); 161 vnodeActive = VnodeListProcess(buf, GetVnodeActiveList()); 162 vnodeTotal = vnodeVirtual + vnodeFree + vnodeActive; 163 164 LosBufPrintf(buf, "\n=================================================================\n"); 165 LosBufPrintf(buf, "No. CacheAddr ParentAddr ChildAddr HitCount Name\n"); 166 pathCacheTotal = PathCacheListProcess(buf); 167 168 LosBufPrintf(buf, "\n=================================================================\n"); 169 pageCacheTotal = PageCacheMapProcess(buf); 170 171 LosBufPrintf(buf, "\n=================================================================\n"); 172 LosBufPrintf(buf, "PathCache Total:%d Try:%d Hit:%d\n", 173 pathCacheTotal, pathCacheTotalTry, pathCacheTotalHit); 174 LosBufPrintf(buf, "Vnode Total:%d Free:%d Virtual:%d Active:%d\n", 175 vnodeTotal, vnodeFree, vnodeVirtual, vnodeActive); 176 LosBufPrintf(buf, "PageCache total:%d Try:%d Hit:%d\n", pageCacheTotal, pageCacheTotalTry, pageCacheTotalHit); 177 VnodeDrop(); 178 return 0; 179} 180 181static int FsCacheClear(struct ProcFile *pf, const char *buffer, size_t buflen, loff_t *ppos) 182{ 183 if (buffer == NULL || buflen < sizeof(CLEAR_ALL_CACHE)) { 184 return -EINVAL; 185 } 186 int vnodeCount = 0; 187 int pageCount = 0; 188 189 if (!strcmp(buffer, CLEAR_ALL_CACHE)) { 190 vnodeCount = VnodeClearCache(); 191 pageCount = OsTryShrinkMemory(VM_FILEMAP_MAX_SCAN); 192 } else if (!strcmp(buffer, CLEAR_PAGE_CACHE)) { 193 pageCount = OsTryShrinkMemory(VM_FILEMAP_MAX_SCAN); 194 } else if (!strcmp(buffer, CLEAR_PATH_CACHE)) { 195 vnodeCount = VnodeClearCache(); 196 } else { 197 return -EINVAL; 198 } 199 200 PRINTK("%d vnodes and related pathcaches cleared\n%d pages cleared\n", vnodeCount, pageCount); 201 return buflen; 202} 203static const struct ProcFileOperations FS_CACHE_PROC_FOPS = { 204 .read = FsCacheInfoFill, 205 .write = FsCacheClear, 206}; 207 208void ProcFsCacheInit(void) 209{ 210 struct ProcDirEntry *pde = CreateProcEntry("fs_cache", 0400, NULL); 211 if (pde == NULL) { 212 PRINT_ERR("create fs_cache error!\n"); 213 return; 214 } 215 216 pde->procFileOps = &FS_CACHE_PROC_FOPS; 217} 218#else 219void ProcFsCacheInit(void) 220{ 221 /* do nothing in release version */ 222} 223#endif 224