• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (c) 2023-2023 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 #ifdef LOSCFG_KERNEL_PLIMITS
32 #include "los_base.h"
33 #include "los_process_pri.h"
34 #include "hal_timer.h"
35 #include "los_plimits.h"
36 
37 typedef struct PlimiteOperations {
38     VOID (*LimiterInit)(UINTPTR);
39     VOID *(*LimiterAlloc)(VOID);
40     VOID (*LimiterFree)(UINTPTR);
41     VOID (*LimiterCopy)(UINTPTR, UINTPTR);
42     BOOL (*LimiterAddProcessCheck)(UINTPTR, UINTPTR);
43     VOID (*LimiterAddProcess)(UINTPTR, UINTPTR);
44     VOID (*LimiterDelProcess)(UINTPTR, UINTPTR);
45     BOOL (*LimiterMigrateCheck)(UINTPTR, UINTPTR);
46     VOID (*LimiterMigrate)(UINTPTR, UINTPTR, UINTPTR);
47 } PlimiteOperations;
48 
49 static PlimiteOperations g_limiteOps[PROCESS_LIMITER_COUNT] = {
50     [PROCESS_LIMITER_ID_PIDS] = {
51         .LimiterInit = PidLimiterInit,
52         .LimiterAlloc = PidLimiterAlloc,
53         .LimiterFree = PidLimterFree,
54         .LimiterCopy = PidLimiterCopy,
55         .LimiterAddProcessCheck = OsPidLimitAddProcessCheck,
56         .LimiterAddProcess = OsPidLimitAddProcess,
57         .LimiterDelProcess = OsPidLimitDelProcess,
58         .LimiterMigrateCheck = PidLimitMigrateCheck,
59         .LimiterMigrate = NULL,
60     },
61 #ifdef LOSCFG_KERNEL_MEM_PLIMIT
62     [PROCESS_LIMITER_ID_MEM] = {
63         .LimiterInit = OsMemLimiterInit,
64         .LimiterAlloc = OsMemLimiterAlloc,
65         .LimiterFree = OsMemLimiterFree,
66         .LimiterCopy = OsMemLimiterCopy,
67         .LimiterAddProcessCheck = OsMemLimitAddProcessCheck,
68         .LimiterAddProcess = OsMemLimitAddProcess,
69         .LimiterDelProcess = OsMemLimitDelProcess,
70         .LimiterMigrateCheck = MemLimiteMigrateCheck,
71         .LimiterMigrate = OsMemLimiterMigrate,
72     },
73 #endif
74 #ifdef LOSCFG_KERNEL_SCHED_PLIMIT
75     [PROCESS_LIMITER_ID_SCHED] = {
76         .LimiterInit = OsSchedLimitInit,
77         .LimiterAlloc = OsSchedLimitAlloc,
78         .LimiterFree = OsSchedLimitFree,
79         .LimiterCopy = OsSchedLimitCopy,
80         .LimiterAddProcessCheck = NULL,
81         .LimiterAddProcess = NULL,
82         .LimiterDelProcess = NULL,
83         .LimiterMigrateCheck = NULL,
84         .LimiterMigrate = NULL,
85     },
86 #endif
87 #ifdef LOSCFG_KERNEL_DEV_PLIMIT
88     [PROCESS_LIMITER_ID_DEV] = {
89         .LimiterInit = OsDevLimitInit,
90         .LimiterAlloc = OsDevLimitAlloc,
91         .LimiterFree = OsDevLimitFree,
92         .LimiterCopy = OsDevLimitCopy,
93         .LimiterAddProcessCheck = NULL,
94         .LimiterAddProcess = NULL,
95         .LimiterDelProcess = NULL,
96         .LimiterMigrateCheck = NULL,
97         .LimiterMigrate = NULL,
98     },
99 #endif
100 #ifdef LOSCFG_KERNEL_IPC_PLIMIT
101     [PROCESS_LIMITER_ID_IPC] = {
102         .LimiterInit = OsIPCLimitInit,
103         .LimiterAlloc = OsIPCLimitAlloc,
104         .LimiterFree = OsIPCLimitFree,
105         .LimiterCopy = OsIPCLimitCopy,
106         .LimiterAddProcessCheck = OsIPCLimitAddProcessCheck,
107         .LimiterAddProcess = OsIPCLimitAddProcess,
108         .LimiterDelProcess = OsIPCLimitDelProcess,
109         .LimiterMigrateCheck = OsIPCLimiteMigrateCheck,
110         .LimiterMigrate = OsIPCLimitMigrate,
111     },
112 #endif
113 };
114 
115 STATIC ProcLimiterSet *g_rootPLimite = NULL;
116 
OsRootPLimitsGet(VOID)117 ProcLimiterSet *OsRootPLimitsGet(VOID)
118 {
119     return g_rootPLimite;
120 }
121 
OsProcLimiterSetInit(VOID)122 UINT32 OsProcLimiterSetInit(VOID)
123 {
124     g_rootPLimite = (ProcLimiterSet *)LOS_MemAlloc(m_aucSysMem1, sizeof(ProcLimiterSet));
125     if (g_rootPLimite == NULL) {
126         return ENOMEM;
127     }
128     (VOID)memset_s(g_rootPLimite, sizeof(ProcLimiterSet), 0, sizeof(ProcLimiterSet));
129 
130     LOS_ListInit(&g_rootPLimite->childList);
131     LOS_ListInit(&g_rootPLimite->processList);
132 
133     ProcLimiterSet *procLimiterSet = g_rootPLimite;
134     for (INT32 plimiteID = 0; plimiteID < PROCESS_LIMITER_COUNT; ++plimiteID) {
135         procLimiterSet->limitsList[plimiteID] = (UINTPTR)g_limiteOps[plimiteID].LimiterAlloc();
136         if (procLimiterSet->limitsList[plimiteID] == (UINTPTR)NULL) {
137             OsPLimitsFree(procLimiterSet);
138             return ENOMEM;
139         }
140 
141         if (g_limiteOps[plimiteID].LimiterInit != NULL) {
142             g_limiteOps[plimiteID].LimiterInit(procLimiterSet->limitsList[plimiteID]);
143         }
144     }
145     return LOS_OK;
146 }
147 
PLimitsDeleteProcess(LosProcessCB * processCB)148 STATIC VOID PLimitsDeleteProcess(LosProcessCB *processCB)
149 {
150     if ((processCB == NULL) || (processCB->plimits == NULL)) {
151         return;
152     }
153 
154     ProcLimiterSet *plimits = processCB->plimits;
155     for (UINT32 limitsID = 0; limitsID < PROCESS_LIMITER_COUNT; limitsID++) {
156         if (g_limiteOps[limitsID].LimiterDelProcess == NULL) {
157             continue;
158         }
159         g_limiteOps[limitsID].LimiterDelProcess(plimits->limitsList[limitsID], (UINTPTR)processCB);
160     }
161     plimits->pidCount--;
162     LOS_ListDelete(&processCB->plimitsList);
163     processCB->plimits = NULL;
164     return;
165 }
166 
PLimitsAddProcess(ProcLimiterSet * plimits,LosProcessCB * processCB)167 STATIC UINT32 PLimitsAddProcess(ProcLimiterSet *plimits, LosProcessCB *processCB)
168 {
169     UINT32 limitsID;
170     if (plimits == NULL) {
171         plimits = g_rootPLimite;
172     }
173 
174     if (processCB->plimits == g_rootPLimite) {
175         return EPERM;
176     }
177 
178     if (processCB->plimits == plimits) {
179         return LOS_OK;
180     }
181 
182     for (limitsID = 0; limitsID < PROCESS_LIMITER_COUNT; limitsID++) {
183         if (g_limiteOps[limitsID].LimiterAddProcessCheck == NULL) {
184             continue;
185         }
186 
187         if (!g_limiteOps[limitsID].LimiterAddProcessCheck(plimits->limitsList[limitsID], (UINTPTR)processCB)) {
188             return EACCES;
189         }
190     }
191 
192     PLimitsDeleteProcess(processCB);
193 
194     for (limitsID = 0; limitsID < PROCESS_LIMITER_COUNT; limitsID++) {
195         if (g_limiteOps[limitsID].LimiterAddProcess == NULL) {
196             continue;
197         }
198         g_limiteOps[limitsID].LimiterAddProcess(plimits->limitsList[limitsID], (UINTPTR)processCB);
199     }
200 
201     LOS_ListTailInsert(&plimits->processList, &processCB->plimitsList);
202     plimits->pidCount++;
203     processCB->plimits = plimits;
204     return LOS_OK;
205 }
206 
OsPLimitsAddProcess(ProcLimiterSet * plimits,LosProcessCB * processCB)207 UINT32 OsPLimitsAddProcess(ProcLimiterSet *plimits, LosProcessCB *processCB)
208 {
209     UINT32 intSave;
210     SCHEDULER_LOCK(intSave);
211     UINT32 ret = PLimitsAddProcess(plimits, processCB);
212     SCHEDULER_UNLOCK(intSave);
213     return ret;
214 }
215 
OsPLimitsAddPid(ProcLimiterSet * plimits,UINT32 pid)216 UINT32 OsPLimitsAddPid(ProcLimiterSet *plimits, UINT32 pid)
217 {
218     UINT32 intSave, ret;
219     if ((plimits == NULL) || OS_PID_CHECK_INVALID(pid) || (pid == 0)) {
220         return EINVAL;
221     }
222 
223     if (plimits == g_rootPLimite) {
224         return EPERM;
225     }
226 
227     SCHEDULER_LOCK(intSave);
228     LosProcessCB *processCB = OS_PCB_FROM_PID((unsigned int)pid);
229     if (OsProcessIsInactive(processCB)) {
230         SCHEDULER_UNLOCK(intSave);
231         return EINVAL;
232     }
233 
234     ret = PLimitsAddProcess(plimits, processCB);
235     SCHEDULER_UNLOCK(intSave);
236     return ret;
237 }
238 
OsPLimitsDeleteProcess(LosProcessCB * processCB)239 VOID OsPLimitsDeleteProcess(LosProcessCB *processCB)
240 {
241     UINT32 intSave;
242     SCHEDULER_LOCK(intSave);
243     PLimitsDeleteProcess(processCB);
244     SCHEDULER_UNLOCK(intSave);
245 }
246 
OsPLimitsPidsGet(const ProcLimiterSet * plimits,UINT32 * pids,UINT32 size)247 UINT32 OsPLimitsPidsGet(const ProcLimiterSet *plimits, UINT32 *pids, UINT32 size)
248 {
249     UINT32 intSave;
250     LosProcessCB *processCB = NULL;
251     UINT32 minSize = LOS_GetSystemProcessMaximum() * sizeof(UINT32);
252     if ((plimits == NULL) || (pids == NULL) || (size < minSize)) {
253         return EINVAL;
254     }
255 
256     SCHEDULER_LOCK(intSave);
257     LOS_DL_LIST *listHead = (LOS_DL_LIST *)&plimits->processList;
258     if (LOS_ListEmpty(listHead)) {
259         SCHEDULER_UNLOCK(intSave);
260         return EINVAL;
261     }
262 
263     LOS_DL_LIST_FOR_EACH_ENTRY(processCB, listHead, LosProcessCB, plimitsList) {
264         pids[OsGetPid(processCB)] = 1;
265     }
266     SCHEDULER_UNLOCK(intSave);
267     return LOS_OK;
268 }
269 
PLimitsProcessMerge(ProcLimiterSet * currPLimits,ProcLimiterSet * parentPLimits)270 STATIC VOID PLimitsProcessMerge(ProcLimiterSet *currPLimits, ProcLimiterSet *parentPLimits)
271 {
272     LOS_DL_LIST *head = &currPLimits->processList;
273     while (!LOS_ListEmpty(head)) {
274         LosProcessCB *processCB = LOS_DL_LIST_ENTRY(head->pstNext, LosProcessCB, plimitsList);
275         PLimitsDeleteProcess(processCB);
276         PLimitsAddProcess(parentPLimits, processCB);
277     }
278     LOS_ListDelete(&currPLimits->childList);
279     currPLimits->parent = NULL;
280     return;
281 }
282 
PLimitsMigrateCheck(ProcLimiterSet * currPLimits,ProcLimiterSet * parentPLimits)283 STATIC UINT32 PLimitsMigrateCheck(ProcLimiterSet *currPLimits, ProcLimiterSet *parentPLimits)
284 {
285     for (UINT32 limiteID = 0; limiteID < PROCESS_LIMITER_COUNT; limiteID++) {
286         UINTPTR currLimit = currPLimits->limitsList[limiteID];
287         UINTPTR parentLimit = parentPLimits->limitsList[limiteID];
288         if (g_limiteOps[limiteID].LimiterMigrateCheck == NULL) {
289             continue;
290         }
291 
292         if (!g_limiteOps[limiteID].LimiterMigrateCheck(currLimit, parentLimit)) {
293             return EPERM;
294         }
295     }
296     return LOS_OK;
297 }
298 
OsPLimitsFree(ProcLimiterSet * currPLimits)299 UINT32 OsPLimitsFree(ProcLimiterSet *currPLimits)
300 {
301     UINT32 intSave, ret;
302     if (currPLimits == NULL) {
303         return EINVAL;
304     }
305 
306     SCHEDULER_LOCK(intSave);
307     ProcLimiterSet *parentPLimits = currPLimits->parent;
308     ret = PLimitsMigrateCheck(currPLimits, parentPLimits);
309     if (ret != LOS_OK) {
310         SCHEDULER_UNLOCK(intSave);
311         return ret;
312     }
313 
314     PLimitsProcessMerge(currPLimits, parentPLimits);
315     SCHEDULER_UNLOCK(intSave);
316 
317     for (INT32 limiteID = 0; limiteID < PROCESS_LIMITER_COUNT; ++limiteID) {
318         UINTPTR procLimiter = currPLimits->limitsList[limiteID];
319         if (g_limiteOps[limiteID].LimiterFree != NULL) {
320             g_limiteOps[limiteID].LimiterFree(procLimiter);
321         }
322     }
323     (VOID)LOS_MemFree(m_aucSysMem1, currPLimits);
324     return LOS_OK;
325 }
326 
OsPLimitsCreate(ProcLimiterSet * parentPLimits)327 ProcLimiterSet *OsPLimitsCreate(ProcLimiterSet *parentPLimits)
328 {
329     UINT32 intSave;
330 
331     ProcLimiterSet *newPLimits = (ProcLimiterSet *)LOS_MemAlloc(m_aucSysMem1, sizeof(ProcLimiterSet));
332     if (newPLimits == NULL) {
333         return NULL;
334     }
335     (VOID)memset_s(newPLimits, sizeof(ProcLimiterSet), 0, sizeof(ProcLimiterSet));
336     LOS_ListInit(&newPLimits->childList);
337     LOS_ListInit(&newPLimits->processList);
338 
339     SCHEDULER_LOCK(intSave);
340     newPLimits->parent = parentPLimits;
341     newPLimits->level = parentPLimits->level + 1;
342     newPLimits->mask = parentPLimits->mask;
343 
344     for (INT32 plimiteID = 0; plimiteID < PROCESS_LIMITER_COUNT; ++plimiteID) {
345         newPLimits->limitsList[plimiteID] = (UINTPTR)g_limiteOps[plimiteID].LimiterAlloc();
346         if (newPLimits->limitsList[plimiteID] == (UINTPTR)NULL) {
347             SCHEDULER_UNLOCK(intSave);
348             OsPLimitsFree(newPLimits);
349             return NULL;
350         }
351 
352         if (g_limiteOps[plimiteID].LimiterCopy != NULL) {
353             g_limiteOps[plimiteID].LimiterCopy(newPLimits->limitsList[plimiteID],
354                                                parentPLimits->limitsList[plimiteID]);
355         }
356     }
357     LOS_ListTailInsert(&g_rootPLimite->childList, &newPLimits->childList);
358 
359     (VOID)PLimitsDeleteProcess(OsCurrProcessGet());
360     (VOID)PLimitsAddProcess(newPLimits, OsCurrProcessGet());
361     SCHEDULER_UNLOCK(intSave);
362     return newPLimits;
363 }
364 
365 #ifdef LOSCFG_KERNEL_MEM_PLIMIT
OsPLimitsMemUsageGet(ProcLimiterSet * plimits,UINT64 * usage,UINT32 size)366 UINT32 OsPLimitsMemUsageGet(ProcLimiterSet *plimits, UINT64 *usage, UINT32 size)
367 {
368     UINT32 intSave;
369     LosProcessCB *processCB = NULL;
370     UINT32 minSize = LOS_GetSystemProcessMaximum() * sizeof(UINT64) + sizeof(ProcMemLimiter);
371     ProcMemLimiter *memLimit = (ProcMemLimiter *)usage;
372     UINT64 *memSuage = (UINT64 *)((UINTPTR)usage + sizeof(ProcMemLimiter));
373     if ((plimits == NULL) || (usage == NULL) || (size < minSize)) {
374         return EINVAL;
375     }
376 
377     SCHEDULER_LOCK(intSave);
378     (VOID)memcpy_s(memLimit, sizeof(ProcMemLimiter),
379                    (VOID *)plimits->limitsList[PROCESS_LIMITER_ID_MEM], sizeof(ProcMemLimiter));
380     LOS_DL_LIST *listHead = (LOS_DL_LIST *)&plimits->processList;
381     if (LOS_ListEmpty(listHead)) {
382         SCHEDULER_UNLOCK(intSave);
383         return EINVAL;
384     }
385 
386     LOS_DL_LIST_FOR_EACH_ENTRY(processCB, listHead, LosProcessCB, plimitsList) {
387         memSuage[OsGetPid(processCB)] = processCB->limitStat.memUsed;
388     }
389     SCHEDULER_UNLOCK(intSave);
390     return LOS_OK;
391 }
392 #endif
393 
394 #ifdef LOSCFG_KERNEL_IPC_PLIMIT
OsPLimitsIPCStatGet(ProcLimiterSet * plimits,ProcIPCLimit * ipc,UINT32 size)395 UINT32 OsPLimitsIPCStatGet(ProcLimiterSet *plimits, ProcIPCLimit *ipc, UINT32 size)
396 {
397     UINT32 intSave;
398     if ((plimits == NULL) || (ipc == NULL) || (size != sizeof(ProcIPCLimit))) {
399         return EINVAL;
400     }
401 
402     SCHEDULER_LOCK(intSave);
403     (VOID)memcpy_s(ipc, sizeof(ProcIPCLimit),
404                    (VOID *)plimits->limitsList[PROCESS_LIMITER_ID_IPC], sizeof(ProcIPCLimit));
405     SCHEDULER_UNLOCK(intSave);
406     return LOS_OK;
407 }
408 #endif
409 
410 #ifdef LOSCFG_KERNEL_SCHED_PLIMIT
OsPLimitsSchedUsageGet(ProcLimiterSet * plimits,UINT64 * usage,UINT32 size)411 UINT32 OsPLimitsSchedUsageGet(ProcLimiterSet *plimits, UINT64 *usage, UINT32 size)
412 {
413     UINT32 intSave;
414     LosProcessCB *processCB = NULL;
415     UINT32 minSize = LOS_GetSystemProcessMaximum() * sizeof(UINT64);
416     if ((plimits == NULL) || (usage == NULL) || (size < minSize)) {
417         return EINVAL;
418     }
419 
420     SCHEDULER_LOCK(intSave);
421     LOS_DL_LIST *listHead = (LOS_DL_LIST *)&plimits->processList;
422     if (LOS_ListEmpty(listHead)) {
423         SCHEDULER_UNLOCK(intSave);
424         return EINVAL;
425     }
426 
427     LOS_DL_LIST_FOR_EACH_ENTRY(processCB, listHead, LosProcessCB, plimitsList) {
428         usage[OsGetPid(processCB)] = processCB->limitStat.allRuntime;
429     }
430     SCHEDULER_UNLOCK(intSave);
431     return LOS_OK;
432 }
433 #endif
434 #endif
435