• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (c) 2013-2019 Huawei Technologies Co., Ltd. All rights reserved.
3  * Copyright (c) 2020-2021 Huawei Device Co., Ltd. All rights reserved.
4  *
5  * Redistribution and use in source and binary forms, with or without modification,
6  * are permitted provided that the following conditions are met:
7  *
8  * 1. Redistributions of source code must retain the above copyright notice, this list of
9  *    conditions and the following disclaimer.
10  *
11  * 2. Redistributions in binary form must reproduce the above copyright notice, this list
12  *    of conditions and the following disclaimer in the documentation and/or other materials
13  *    provided with the distribution.
14  *
15  * 3. Neither the name of the copyright holder nor the names of its contributors may be used
16  *    to endorse or promote products derived from this software without specific prior written
17  *    permission.
18  *
19  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
20  * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
21  * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
22  * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR
23  * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
24  * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
25  * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
26  * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
27  * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
28  * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
29  * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
30  */
31 
32 #ifdef LOSCFG_FS_VFS
33 
34 #include "fs/file.h"
35 #include "los_vm_filemap.h"
36 
37 #ifdef LOSCFG_KERNEL_VM
38 
39 /* unmap a lru page by map record info caller need lru lock */
OsUnmapPageLocked(LosFilePage * page,LosMapInfo * info)40 VOID OsUnmapPageLocked(LosFilePage *page, LosMapInfo *info)
41 {
42     if (page == NULL || info == NULL) {
43         VM_ERR("UnmapPage error input null!");
44         return;
45     }
46     page->n_maps--;
47     LOS_ListDelete(&info->node);
48     LOS_AtomicDec(&page->vmPage->refCounts);
49     LOS_ArchMmuUnmap(info->archMmu, info->vaddr, 1);
50     LOS_MemFree(m_aucSysMem0, info);
51 }
52 
OsUnmapAllLocked(LosFilePage * page)53 VOID OsUnmapAllLocked(LosFilePage *page)
54 {
55     LosMapInfo *info = NULL;
56     LosMapInfo *next = NULL;
57     LOS_DL_LIST *immap = &page->i_mmap;
58 
59     LOS_DL_LIST_FOR_EACH_ENTRY_SAFE(info, next, immap, LosMapInfo, node) {
60         OsUnmapPageLocked(page, info);
61     }
62 }
63 
64 /* add a new lru node to lru list, lruType can be file or anon */
OsLruCacheAdd(LosFilePage * fpage,enum OsLruList lruType)65 VOID OsLruCacheAdd(LosFilePage *fpage, enum OsLruList lruType)
66 {
67     UINT32 intSave;
68     LosVmPhysSeg *physSeg = fpage->physSeg;
69     LosVmPage *page = fpage->vmPage;
70 
71     LOS_SpinLockSave(&physSeg->lruLock, &intSave);
72     OsSetPageActive(page);
73     OsCleanPageReferenced(page);
74     physSeg->lruSize[lruType]++;
75     LOS_ListTailInsert(&physSeg->lruList[lruType], &fpage->lru);
76 
77     LOS_SpinUnlockRestore(&physSeg->lruLock, intSave);
78 }
79 
80 /* delete a lru node, caller need hold lru_lock */
OsLruCacheDel(LosFilePage * fpage)81 VOID OsLruCacheDel(LosFilePage *fpage)
82 {
83     LosVmPhysSeg *physSeg = fpage->physSeg;
84     int type = OsIsPageActive(fpage->vmPage) ? VM_LRU_ACTIVE_FILE : VM_LRU_INACTIVE_FILE;
85 
86     physSeg->lruSize[type]--;
87     LOS_ListDelete(&fpage->lru);
88 }
89 
OsInactiveListIsLow(LosVmPhysSeg * physSeg)90 BOOL OsInactiveListIsLow(LosVmPhysSeg *physSeg)
91 {
92     return (physSeg->lruSize[VM_LRU_ACTIVE_FILE] >
93             physSeg->lruSize[VM_LRU_INACTIVE_FILE]) ? TRUE : FALSE;
94 }
95 
96 /* move a page from inactive list to active list  head */
OsMoveToActiveList(LosFilePage * fpage)97 STATIC INLINE VOID OsMoveToActiveList(LosFilePage *fpage)
98 {
99     LosVmPhysSeg *physSeg = fpage->physSeg;
100 
101     physSeg->lruSize[VM_LRU_ACTIVE_FILE]++;
102     physSeg->lruSize[VM_LRU_INACTIVE_FILE]--;
103     LOS_ListDelete(&fpage->lru);
104     LOS_ListTailInsert(&physSeg->lruList[VM_LRU_ACTIVE_FILE], &fpage->lru);
105 }
106 
107 /* move a page from active list to inactive list  head */
OsMoveToInactiveList(LosFilePage * fpage)108 STATIC INLINE VOID OsMoveToInactiveList(LosFilePage *fpage)
109 {
110     LosVmPhysSeg *physSeg = fpage->physSeg;
111 
112     physSeg->lruSize[VM_LRU_ACTIVE_FILE]--;
113     physSeg->lruSize[VM_LRU_INACTIVE_FILE]++;
114     LOS_ListDelete(&fpage->lru);
115     LOS_ListTailInsert(&physSeg->lruList[VM_LRU_INACTIVE_FILE], &fpage->lru);
116 }
117 
118 /* move a page to the most active pos in lru list(active head) */
OsMoveToActiveHead(LosFilePage * fpage)119 STATIC INLINE VOID OsMoveToActiveHead(LosFilePage *fpage)
120 {
121     LosVmPhysSeg *physSeg = fpage->physSeg;
122     LOS_ListDelete(&fpage->lru);
123     LOS_ListTailInsert(&physSeg->lruList[VM_LRU_ACTIVE_FILE], &fpage->lru);
124 }
125 
126 /* move a page to the most active pos in lru list(inactive head) */
OsMoveToInactiveHead(LosFilePage * fpage)127 STATIC INLINE VOID OsMoveToInactiveHead(LosFilePage *fpage)
128 {
129     LosVmPhysSeg *physSeg = fpage->physSeg;
130     LOS_ListDelete(&fpage->lru);
131     LOS_ListTailInsert(&physSeg->lruList[VM_LRU_INACTIVE_FILE], &fpage->lru);
132 }
133 
134 /* page referced add: (call by page cache get)
135 ----------inactive----------|----------active------------
136 [ref:0,act:0], [ref:1,act:0]|[ref:0,act:1], [ref:1,act:1]
137 ref:0, act:0 --> ref:1, act:0
138 ref:1, act:0 --> ref:0, act:1
139 ref:0, act:1 --> ref:1, act:1
140 */
OsPageRefIncLocked(LosFilePage * fpage)141 VOID OsPageRefIncLocked(LosFilePage *fpage)
142 {
143     BOOL isOrgActive;
144     UINT32 intSave;
145     LosVmPage *page = NULL;
146 
147     if (fpage == NULL) {
148         return;
149     }
150 
151     LOS_SpinLockSave(&fpage->physSeg->lruLock, &intSave);
152 
153     page = fpage->vmPage;
154     isOrgActive = OsIsPageActive(page);
155 
156     if (OsIsPageReferenced(page) && !OsIsPageActive(page)) {
157         OsCleanPageReferenced(page);
158         OsSetPageActive(page);
159     } else if (!OsIsPageReferenced(page)) {
160         OsSetPageReferenced(page);
161     }
162 
163     if (!isOrgActive && OsIsPageActive(page)) {
164         /* move inactive to active */
165         OsMoveToActiveList(fpage);
166     /* no change, move head */
167     } else {
168         if (OsIsPageActive(page)) {
169             OsMoveToActiveHead(fpage);
170         } else {
171             OsMoveToInactiveHead(fpage);
172         }
173     }
174 
175     LOS_SpinUnlockRestore(&fpage->physSeg->lruLock, intSave);
176 }
177 
178 /* page referced dec: (call by shrinker)
179 ----------inactive----------|----------active------------
180 [ref:0,act:0], [ref:1,act:0]|[ref:0,act:1], [ref:1,act:1]
181 ref:1, act:1 --> ref:0, act:1
182 ref:0, act:1 --> ref:1, act:0
183 ref:1, act:0 --> ref:0, act:0
184 */
OsPageRefDecNoLock(LosFilePage * fpage)185 VOID OsPageRefDecNoLock(LosFilePage *fpage)
186 {
187     BOOL isOrgActive;
188     LosVmPage *page = NULL;
189 
190     if (fpage == NULL) {
191         return;
192     }
193 
194     page = fpage->vmPage;
195     isOrgActive = OsIsPageActive(page);
196 
197     if (!OsIsPageReferenced(page) && OsIsPageActive(page)) {
198         OsCleanPageActive(page);
199         OsSetPageReferenced(page);
200     } else if (OsIsPageReferenced(page)) {
201         OsCleanPageReferenced(page);
202     }
203 
204     if (isOrgActive && !OsIsPageActive(page)) {
205         OsMoveToInactiveList(fpage);
206     }
207 }
208 
OsShrinkActiveList(LosVmPhysSeg * physSeg,int nScan)209 VOID OsShrinkActiveList(LosVmPhysSeg *physSeg, int nScan)
210 {
211     LosFilePage *fpage = NULL;
212     LosFilePage *fnext = NULL;
213     LOS_DL_LIST *activeFile = &physSeg->lruList[VM_LRU_ACTIVE_FILE];
214 
215     LOS_DL_LIST_FOR_EACH_ENTRY_SAFE(fpage, fnext, activeFile, LosFilePage, lru) {
216         if (LOS_SpinTrylock(&fpage->mapping->list_lock) != LOS_OK) {
217             continue;
218         }
219 
220         /* happened when caller hold cache lock and try reclaim this page */
221         if (OsIsPageLocked(fpage->vmPage)) {
222             LOS_SpinUnlock(&fpage->mapping->list_lock);
223             continue;
224         }
225 
226         if (OsIsPageMapped(fpage) && (fpage->flags & VM_MAP_REGION_FLAG_PERM_EXECUTE)) {
227             LOS_SpinUnlock(&fpage->mapping->list_lock);
228             continue;
229         }
230 
231         OsPageRefDecNoLock(fpage);
232 
233         LOS_SpinUnlock(&fpage->mapping->list_lock);
234 
235         if (--nScan <= 0) {
236             break;
237         }
238     }
239 }
240 
OsShrinkInactiveList(LosVmPhysSeg * physSeg,int nScan,LOS_DL_LIST * list)241 int OsShrinkInactiveList(LosVmPhysSeg *physSeg, int nScan, LOS_DL_LIST *list)
242 {
243     UINT32 nrReclaimed = 0;
244     LosVmPage *page = NULL;
245     SPIN_LOCK_S *flock = NULL;
246     LosFilePage *fpage = NULL;
247     LosFilePage *fnext = NULL;
248     LosFilePage *ftemp = NULL;
249     LOS_DL_LIST *inactive_file = &physSeg->lruList[VM_LRU_INACTIVE_FILE];
250 
251     LOS_DL_LIST_FOR_EACH_ENTRY_SAFE(fpage, fnext, inactive_file, LosFilePage, lru) {
252         flock = &fpage->mapping->list_lock;
253 
254         if (LOS_SpinTrylock(flock) != LOS_OK) {
255             continue;
256         }
257 
258         page = fpage->vmPage;
259         if (OsIsPageLocked(page)) {
260             LOS_SpinUnlock(flock);
261             continue;
262         }
263 
264         if (OsIsPageMapped(fpage) && (OsIsPageDirty(page) || (fpage->flags & VM_MAP_REGION_FLAG_PERM_EXECUTE))) {
265             LOS_SpinUnlock(flock);
266             continue;
267         }
268 
269         if (OsIsPageDirty(page)) {
270             ftemp = OsDumpDirtyPage(fpage);
271             if (ftemp != NULL) {
272                 LOS_ListTailInsert(list, &ftemp->node);
273             }
274         }
275 
276         OsDeletePageCacheLru(fpage);
277         LOS_SpinUnlock(flock);
278         nrReclaimed++;
279 
280         if (--nScan <= 0) {
281             break;
282         }
283     }
284 
285     return nrReclaimed;
286 }
287 
288 #ifdef LOSCFG_FS_VFS
OsTryShrinkMemory(size_t nPage)289 int OsTryShrinkMemory(size_t nPage)
290 {
291     UINT32 intSave;
292     size_t totalPages;
293     size_t nReclaimed = 0;
294     LosVmPhysSeg *physSeg = NULL;
295     UINT32 index;
296     LOS_DL_LIST_HEAD(dirtyList);
297     LosFilePage *fpage = NULL;
298     LosFilePage *fnext = NULL;
299 
300     if (nPage == 0) {
301         nPage = VM_FILEMAP_MIN_SCAN;
302     }
303 
304     if (nPage > VM_FILEMAP_MAX_SCAN) {
305         nPage = VM_FILEMAP_MAX_SCAN;
306     }
307 
308     for (index = 0; index < g_vmPhysSegNum; index++) {
309         physSeg = &g_vmPhysSeg[index];
310         LOS_SpinLockSave(&physSeg->lruLock, &intSave);
311         totalPages = physSeg->lruSize[VM_LRU_ACTIVE_FILE] + physSeg->lruSize[VM_LRU_INACTIVE_FILE];
312         if (totalPages < VM_FILEMAP_MIN_SCAN) {
313             LOS_SpinUnlockRestore(&physSeg->lruLock, intSave);
314             continue;
315         }
316 
317         if (OsInactiveListIsLow(physSeg)) {
318             OsShrinkActiveList(physSeg, (nPage < VM_FILEMAP_MIN_SCAN) ? VM_FILEMAP_MIN_SCAN : nPage);
319         }
320 
321         nReclaimed += OsShrinkInactiveList(physSeg, nPage, &dirtyList);
322         LOS_SpinUnlockRestore(&physSeg->lruLock, intSave);
323 
324         if (nReclaimed >= nPage) {
325             break;
326         }
327     }
328 
329     LOS_DL_LIST_FOR_EACH_ENTRY_SAFE(fpage, fnext, &dirtyList, LosFilePage, node) {
330         OsDoFlushDirtyPage(fpage);
331     }
332 
333     return nReclaimed;
334 }
335 #else
OsTryShrinkMemory(size_t nPage)336 int OsTryShrinkMemory(size_t nPage)
337 {
338     return 0;
339 }
340 #endif
341 #endif
342 
343 #endif
344