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
VnodeTypeToStr(enum VnodeType type)43 static 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
VnodeListProcess(struct SeqBuf * buf,LIST_HEAD * list)67 static 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
PathCacheListProcess(struct SeqBuf * buf)83 static 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
PageCacheEntryProcess(struct SeqBuf * buf,struct page_mapping * mapping)102 static 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
PageCacheMapProcess(struct SeqBuf * buf)120 static 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
FsCacheInfoFill(struct SeqBuf * buf,void * arg)137 static 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
FsCacheClear(struct ProcFile * pf,const char * buffer,size_t buflen,loff_t * ppos)181 static 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 }
203 static const struct ProcFileOperations FS_CACHE_PROC_FOPS = {
204 .read = FsCacheInfoFill,
205 .write = FsCacheClear,
206 };
207
ProcFsCacheInit(void)208 void ProcFsCacheInit(void)
209 {
210 struct ProcDirEntry *pde = CreateProcEntry("fs_cache", 0, 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
ProcFsCacheInit(void)219 void ProcFsCacheInit(void)
220 {
221 /* do nothing in release version */
222 }
223 #endif
224